[英]Javascript d3 pie chart doesn't pull data from JSON file with list of dictionaries
I have a .json file with data, and I'd like to make a d3 donut (pie) chart from it.我有一个包含数据的 .json 文件,我想从中制作一个 d3 甜甜圈(饼图)图。 I'm not especially fluent in javascript, and every example I can find either pulls from inline json data or the json file is structured differently than mine (mine is a list of dictionaries; theirs are often single dictionaries).
我对 javascript 不是特别流利,我能找到的每个例子要么是从内联 json 数据中提取的,要么是 json 文件的结构与我的不同(我的是一个字典列表;他们的通常是单个字典)。 I've been troubleshooting for a few days, and somehow can't land on anything that actually works.
我已经进行了几天的故障排除,但不知何故无法解决任何实际有效的问题。 Any thoughts/tips?
任何想法/提示?
The example at https://www.d3-graph-gallery.com/graph/donut_label.html uses inline json data to render a donut chart with labels. https://www.d3-graph-gallery.com/graph/donut_label.html 上的示例使用内联 json 数据来呈现带有标签的圆环图。 I've attempted to modify it that code by:
我试图通过以下方式修改它的代码:
/data/all-facet-digitized.json looks like: /data/all-facet-digitized.json 看起来像:
[
{
"count": "55433",
"facet": "true"
},
{
"count": "373977",
"facet": "false"
}
]
Code in the of my html file looks like:我的 html 文件中的代码如下所示:
<div id="chart"></div> <!-- div containing the donut chart -->
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var width = 450
height = 450
margin = 40
// The radius of the pieplot is half the width or half the height (smallest one) minus margin.
var radius = Math.min(width, height) / 2 - margin
// append the svg object to the div called 'chart'
var svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Parse the Data
d3.json("/data/all-facet-digitized.json", function(data) {
// set the color scale
var color = d3.scaleOrdinal()
.domain(["true","false"])
.range(d3.schemeDark2);
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {return d.count; })
var data_ready = pie(d3.entries(data))
// The arc generator
var arc = d3.arc()
.innerRadius(radius * 0.5) // This is the size of the donut hole
.outerRadius(radius * 0.8)
// Another arc that won't be drawn. Just for labels positioning
var outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9)
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d){ return(color(d.facet)) })
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 0.7)
// Add the polylines between chart and labels:
svg
.selectAll('allPolylines')
.data(data_ready)
.enter()
.append('polyline')
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr('points', function(d) {
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
return [posA, posB, posC]
})
// Add the polylines between chart and labels:
svg
.selectAll('allLabels')
.data(data_ready)
.enter()
.append('text')
.text( function(d) { console.log(d.facet) ; return d.facet} )
.attr('transform', function(d) {
var pos = outerArc.centroid(d);
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1);
return 'translate(' + pos + ')';
})
.style('text-anchor', function(d) {
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
return (midangle < Math.PI ? 'start' : 'end')
})
})
</script>
My result renders as an empty space:我的结果呈现为一个空白空间:
<div id="chart">
<svg width="450" height="450">
<g transform="translate(225,225)"></g>
</svg>
</div>
The schemeDark2
doens't exist in d3 v4. schemeDark2
在 d3 v4 中不存在。 I've replaced it with schemeCategory10
:我已经用
schemeCategory10
替换了它:
var color = d3.scaleOrdinal()
.domain(["true","false"])
.range(d3.schemeCategory10);
Since you have an array of objects, you don't need d3.entries
.由于您有一组对象,因此不需要
d3.entries
。 That takes an object and converts it to an array where each key is an item of the array.这需要一个对象并将其转换为一个数组,其中每个键都是数组的一个项目。 But since you already have an array here, you can put it directly in
pie()
:但是因为这里已经有一个数组,你可以直接把它放在
pie()
:
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {return d.count; })
var data_ready = pie(data)
Now that you've got the data, you can access it on any of the functions: try putting console.log(data_ready)
to see what's available.现在您已经获得了数据,您可以在任何函数上访问它:尝试放入
console.log(data_ready)
以查看可用的内容。 You'll see that the data is bound for each object as the .data
property.您将看到数据作为
.data
属性绑定到每个对象。 pie()
takes an array and puts it in a format that's convenient to make pie charts with. pie()
接受一个数组并将其放入便于制作饼图的格式中。
Say we want to access the facet property: we would access that as item.data.facet
.假设我们要访问 facet 属性:我们将其作为
item.data.facet
访问。 So in your functions, to access, you can do:因此,在您的功能中,要访问,您可以执行以下操作:
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d){ return(color(d.data.facet)) })
<head></head> <div id="chart"></div> <!-- div containing the donut chart --> <script src="//d3js.org/d3.v4.min.js"></script> <script> // set the dimensions and margins of the graph var width = 450 height = 450 margin = 40 // The radius of the pieplot is half the width or half the height (smallest one) minus margin. var radius = Math.min(width, height) / 2 - margin // append the svg object to the div called 'chart' var svg = d3.select("#chart") .append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // Parse the Data var data = [ { "count": "55433", "facet": "true" }, { "count": "373977", "facet": "false" } ] // set the color scale var color = d3.scaleOrdinal() .domain(["true","false"]) .range(d3.schemeCategory10); // Compute the position of each group on the pie: var pie = d3.pie() .sort(null) // Do not sort group by size .value(function(d) {return d.count; }) var data_ready = pie(data) console.log('data_r', data_ready) // The arc generator var arc = d3.arc() .innerRadius(radius * 0.5) // This is the size of the donut hole .outerRadius(radius * 0.8) // Another arc that won't be drawn. Just for labels positioning var outerArc = d3.arc() .innerRadius(radius * 0.9) .outerRadius(radius * 0.9) // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function. svg .selectAll('allSlices') .data(data_ready) .enter() .append('path') .attr('d', arc) .attr('fill', function(d){ return(color(d.data.facet)) }) .attr("stroke", "white") .style("stroke-width", "2px") .style("opacity", 0.7) // Add the polylines between chart and labels: svg .selectAll('allPolylines') .data(data_ready) .enter() .append('polyline') .attr("stroke", "black") .style("fill", "none") .attr("stroke-width", 1) .attr('points', function(d) { var posA = arc.centroid(d) // line insertion in the slice var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that var posC = outerArc.centroid(d); // Label position = almost the same as posB var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left return [posA, posB, posC] }) // Add the polylines between chart and labels: svg .selectAll('allLabels') .data(data_ready) .enter() .append('text') .text( function(d) { return d.data.facet} ) .attr('transform', function(d) { var pos = outerArc.centroid(d); var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1); return 'translate(' + pos + ')'; }) .style('text-anchor', function(d) { var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 return (midangle < Math.PI ? 'start' : 'end') }) </script>
Ok, the issues here is that you've completely missed how data_ready
is structured after converting the JSON response.好的,这里的问题是您完全错过了转换 JSON 响应后
data_ready
的结构。 You might want to add console.log(data_ready)
just after you set data_ready
and inspect it in the console for better understanding of the following fixes.您可能希望在设置
data_ready
后添加console.log(data_ready)
并在控制台中检查它以更好地理解以下修复。
First a color fix:首先是颜色修复:
.attr('fill', function(d){ return(color(d.data.value.facet)) })
Then a data fix:然后是数据修复:
.value(function(d) {return d.value.count; })
And lastly a label fix:最后是标签修复:
.text( function(d) { console.log(d.data.key) ; return d.data.value.facet } )
Your script should look like this:您的脚本应如下所示:
// set the dimensions and margins of the graph
var width = 450
height = 450
margin = 40
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = Math.min(width, height) / 2 - margin
// append the svg object to the div called 'my_dataviz'
var svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.json("/data/all-facet-digitized.json", function(data) {
// set the color scale
var color = d3.scaleOrdinal()
.domain(["true","false"])
.range(d3.schemeDark2);
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {return d.value.count; })
var data_ready = pie(d3.entries(data))
// The arc generator
var arc = d3.arc()
.innerRadius(radius * 0.5) // This is the size of the donut hole
.outerRadius(radius * 0.8)
// Another arc that won't be drawn. Just for labels positioning
var outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9)
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d){ return(color(d.data.value.facet)) })
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 0.7)
// Add the polylines between chart and labels:
svg
.selectAll('allPolylines')
.data(data_ready)
.enter()
.append('polyline')
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr('points', function(d) {
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
return [posA, posB, posC]
})
// Add the polylines between chart and labels:
svg
.selectAll('allLabels')
.data(data_ready)
.enter()
.append('text')
.text( function(d) { console.log(d.data.key) ; return d.data.value.facet } )
.attr('transform', function(d) {
var pos = outerArc.centroid(d);
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1);
return 'translate(' + pos + ')';
})
.style('text-anchor', function(d) {
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
return (midangle < Math.PI ? 'start' : 'end')
})
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.