I am learning how to use D3.js and I am trying to render multiple pie charts from JSON data that I fetched from an external API. The data that I am working with look like below
tickers = [{
"symbol": "GME",
"buy": 0,
"hold": 3,
"period": "2021-08-01",
"sell": 5,
"strongBuy": 0,
"strongSell": 2
}, {
"symbol": "AMD",
"buy": 21,
"hold": 16,
"period": "2021-08-01",
"sell": 1,
"strongBuy": 8,
"strongSell": 0
}]
I am trying to render a pie chart for each object in the array, but I cant seem to get the data flow correctly to my pie charts. I only want "Strong Sell", "Sell", "Hold", "Buy", and "Strong Buy" information on each pie chart.
I have tried the below codes, and attached screenshots showing the HTML and the pie charts
var margin = 20, width = 250, height = 250
var radius = Math.min(width, height) / 2 - margin
var new_data = tickers.map(function(d){
if (d){
var temp = {"Strong Sell": d.strongSell, "Sell": d.sell, "Hold": d.hold, "Buy": d.buy, "Strong Buy": d.strongBuy}
} else {
var temp = {"Strong Sell": 0, "Sell": 0, "Hold": 0, "Buy": 0, "Strong Buy": 0}
}
return temp
})
var color = d3.scaleOrdinal()
.domain(["Strong Sell", "Sell", "Hold", "Buy", "Strong Buy"])
.range(["#570e00", "#ff2a00", "#ffff00", "#00ff08", "#00570c"])
var pie = d3.pie()
.value(function(d) {return d.value; })
var data_ready = pie(d3.entries(new_data))
var recommendSvg = d3.selectAll(".company-recommend")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
recommendSvg
.selectAll('g')
.data(data_ready)
.enter()
.append('path')
.attr('d', d3.arc()
.innerRadius(0)
.outerRadius(radius)
)
.attr('fill', function(d){ return(color(d.data.key)) })
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7)
Any help or advice would be greatly appreciated!
Here's a complete example, which assumes that the "company-recommend" divs are already created.
I've modified your code so that you don't need to use d3.entries
. I put the data in that format from the start. In addition, I've updated recommendSvg
so that the data
array is bound to it. This means that each div is bound to one element in the data
array. When drawing the pie chart in each group, we then pass the data for that chart to the pie
generator and create one path for each slice.
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div class="company-container">
<div class="company-profile"></div>
<div class="company-recommend"></div>
</div>
<div class="company-container">
<div class="company-profile"></div>
<div class="company-recommend"></div>
</div>
<script>
const tickers = [
{
"symbol": "GME",
"buy": 0,
"hold": 3,
"period": "2021-08-01",
"sell": 5,
"strongBuy": 0,
"strongSell": 2
},
{
"symbol": "AMD",
"buy": 21,
"hold": 16,
"period": "2021-08-01",
"sell": 1,
"strongBuy": 8,
"strongSell": 0
}
];
const margin = 20;
const width = 250;
const height = 250;
const radius = Math.min(width, height) / 2 - margin;
const data = tickers.map(d => [
{ key: 'Strong Sell', value: d.strongSell },
{ key: 'Sell', value: d.sell },
{ key: 'Hold', value: d.hold },
{ key: 'Buy', value: d.buy },
{ key: 'Strong Buy', value: d.strongBuy },
]);
const color = d3.scaleOrdinal()
.domain(["Strong Sell", "Sell", "Hold", "Buy", "Strong Buy"])
.range(["#570e00", "#ff2a00", "#ffff00", "#00ff08", "#00570c"]);
const pie = d3.pie().value(d => d.value);
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius);
// bind our data to the divs. add a group to each div.
const recommendSvg = d3.selectAll('.company-recommend')
.data(data)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);
// draw the pie chart in each group
// by creating one path for each slice
recommendSvg.selectAll('path')
.data(d => pie(d))
.join('path')
.attr('d', arc)
.attr('fill', d => color(d.data.key))
.attr('stroke', 'black')
.attr('stroke-width', '2px')
.attr('opacity', 0.7);
</script>
</body>
</html>