D3 multiple pie chart labels - javascript
I am relatively new to D3 working with a very large data set and trying to create a very large array of pie charts. However I cannot figure out how to place tittles at the very top of each pie chart.
My data that I am using is currently in a csv format like this and the fruits would be the labels I want for the pie charts
[apple,90,36,2]
[pear,36,36,3]
[grape,19,13,0]
I have pasted my code bellow with the data that works for it included bellow. Also I would ultimately like to be able to zoom into the data and look at it from a zoomed out feature like this:
http://mbostock.github.io/d3/talk/20111116/pack-hierarchy.html
If anybody has an idea to effectively convey this it would be greatly appreciated.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Multiple Pie Charts</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.4.5"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js?2.4.5"></script>
<style type="text/css">
body {
text-align: center;
}
</style>
</head>
<body>
<script type="text/javascript">
var data = [
[90,36,2],
[36,36,3],
[19,13,0],
]
var m = 10,
r = 100,
z = d3.scale.category20c();
var svg = d3.select("body").selectAll("svg")
.data(data)
.enter().append("svg:svg")
.attr("width", (r + m) * 2)
.attr("height", (r + m) * 2)
.append("svg:g")
.attr("transform", "translate(" + (r + m) + "," + (r + m) + ")");
svg.selectAll("path")
.data(d3.layout.pie())
.enter().append("svg:path")
.attr("d", d3.svg.arc()
.innerRadius(r / 2)
.outerRadius(r))
.style("fill", function(d, i) { return z(i); });
</script>
</body>
</html>
You could use dc.js, it simplifies making d3 charts and retains the flexibility. On the homepage of that project they have a link to annotated source so you can see how to use it.
If you have a large data set I would use something like that because it uses crossfilter to reduce your data elements to only those that need to be displayed, resulting in much better performance.
Sorry I didn't directly answer your title question but suggested a different way of doing this, but I have never had to do that because I use dc.js which makes all this much simpler.
Figured it out
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
svg {
padding: 10px 0 0 10px;
}
.arc {
stroke: #fff;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var radius = 74,
padding = 10;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#2B8429"]);
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 30);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
d3.csv("data1.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "fruit"; }));
data.forEach(function(d) {
d.ages = color.domain().map(function(name) {
return {name: name, population: +d[name]};
});
});
var legend = d3.select("body").append("svg")
.attr("class", "legend")
.attr("width", radius * 2)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d; });
var svg = d3.select("body").selectAll(".pie")
.data(data)
.enter().append("svg")
.attr("class", "pie")
.attr("width", radius * 2)
.attr("height", radius * 2)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
svg.selectAll(".arc")
.data(function(d) { return pie(d.ages); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); });
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.fruit; });
});
</script>
Related
How to create left axis with variable tick interval in tick values and has same distance between tick value
I am creating left axis and the current output is like this. . The problem is there is a gap between tick values but i want uniform gap between two tick values as here. Here is the Code example. svg.append("g") .attr("class", "axisLeft") .call(d3.axisLeft(y1).tickValues(y1TickValues).tickSizeOuter(0).tickFormat(d3.format("d"))) .selectAll('text') .style('text-anchor', 'end');
What you're asking for is impossible. The reason is simple: a linear scale is a continuous scale. That is, it deals with a continuous (non-discrete) quantitative variable. The only way for you to guarantee that the distance between the ticks is rigorously the same is using an ordinal scale, but those scales deal with qualitative (categorical) variables. Not what you want. However, there is a hack: using a log scale. In this case, since your domain crosses zero, well use a symlog scale (avoiding the log of zero, which in math is not a real number), available on D3 v5 (not v4, the version you're using). By using a symlog scale with constant(100)... var y1 = d3.scaleSymlog() .constant(100) .domain([0,2000]).range([height,0]); ... we get something similar (but not exactly like) to what you asked: Here is the updated code: (function(window){ var graphData = [1699, 725, 1149, 868, 304, 1844, 745, 1846, 1423, 1739, 823, 1404, 226, 1603, 389, 517, 1452, 1842, 930, 547, 1072, 828, 733, 632]; var timeArr = []; for (var i=0;i<24;i++) { timeArr.push(i); } function trans(key){ return key; } drawEditGraph(); function drawEditGraph() { var dataGraph = { timeArr:timeArr, graphData:graphData}; function make_x_gridlines() { return d3.axisBottom(x).tickSize(height).tickValues(xTicks) .ticks(10) } var margin = {top: 35, right: 50, bottom: 30, left: 50}, width = $(window).width() - margin.left - margin.right, height = $(window).height() - margin.top - margin.bottom; var svgHeight = height + 40; var x = d3.scaleLinear().range([0, width]); var tickValues= [0,4,8,12,16,20,24]; var y1TickValues = [20,50,75,100,150,200,300,400,500,750,1000,1500,2000] x.domain([0,23]); var y1 = d3.scaleSymlog() .constant(100) .domain([0,2000]).range([height,0]); var xTicks = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23] var valueline2 = d3.line() .x(function(d) { return x(d.date); }) .y(function(d) { return y1(d.open); }); var svg = d3.select("#graphDiv").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", svgHeight + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var data = []; for (var i=0;i<dataGraph.timeArr.length;i++){ var obj = {}; obj.date = dataGraph.timeArr[i]; obj.open = dataGraph.graphData[i]; data.push(obj) } svg.append("g") .attr("class", "grid") .attr("transform", "translate(0,"+(height)+")") .call(make_x_gridlines() .tickSize(-width) .tickSizeOuter(0) .tickFormat("") ) svg.append("path") .data([data]) .attr("class", "line") .attr("d", valueline2); // Add the X Axis svg.append("g") .attr("class", "axisBottom") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x).tickValues(xTicks).tickFormat(function(d,i){ if (d<10) return "0"+d; return d; })); // Add the Y Axis svg.append("g") .attr("class", "axisLeft") .call(d3.axisLeft(y1).tickValues(y1TickValues).tickSizeOuter(0).tickFormat(d3.format("d"))) .selectAll('text') .style('text-anchor', 'end'); //Add title svg.append("text") .attr("text-anchor", "center") .attr("x", (width/2) - 25) .attr("y", height + 35 ) .attr("fill", "#8E8E8E") .attr("font-size", "12") .text(trans("Time")); // Y0 axis label: svg.append("text") .attr("text-anchor", "end") .attr("transform", "rotate(0)") .attr("y", -23) .attr("x", 5) .attr("font-size", "12") .attr("fill", "#725100") .text(trans("Colour")); svg.append("text") .attr("text-anchor", "end") .attr("transform", "rotate(0)") .attr("y", -8) .attr("x", 5) .attr("font-size", "12") .attr("fill", "#725100") .text("("+trans("K") + ")"); } }(window)); .line { fill: none; stroke: #FFC841 ; stroke-width: 2px; } .axisSteelBlue text{ fill: #FFC841; } .axisRed text{ fill: #5BCBD4; } .grid line { stroke: lightgrey; stroke-opacity: 0.7; shape-rendering: crispEdges; } <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="description" content="Graph Demo"> <meta name="viewport" content="width=device-width"> <title>Graph Demo</title> <script src="https://code.jquery.com/jquery-2.1.4.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"></script> </head> <body> <div id="graphDiv"> </div> </body> </html>
Error: <rect> attribute y: Expected length, "NaN"
I am trying to follow this example here for a D3 stacked chart. I've tested it locally and it works fine. I have adapted the code to match my csv dataset, but unfortunately I get issues with the calculation of y and height attributes: Error: attribute y: Expected length, "NaN". Error: attribute height: Expected length, "NaN". Here is my adapted source code: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Enterprise Elements Analysis - In/Out of Scope</title> <script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script> <style type="text/css"> svg { font: 10px sans-serif; shape-rendering: crispEdges; } .axis path, .axis line { fill: none; stroke: #000; } path.domain { stroke: none; } .y .tick line { stroke: #ddd; } </style> </head> <body> <script type="text/javascript"> // Our D3 code will go here var ratData = []; d3.csv("./etcounts.csv", function(d) { return { type: d.type, in_scope: +d.in_scope, out_scope: +d.out_scope }; }, function(error, rows) { data = rows; console.log(data); createVisualization(); }); function createVisualization() { // Setup svg using with margins var margin = {bottom: 75, left: 15, right: 85}; var w = 200 - margin.left - margin.right; var h = 175 - margin.bottom; // get length of Array var arrayLength = data.length; // length of dataset var x_axisLength = 100; // length of x-axis in our layout var y_axisLength = 100; // length of y-axis in our layout var svg = d3.select("body") .append("svg") .attr("width", w + margin.left + margin.right) .attr("height", h + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + ",10)"); // set up the properties for stack var stack = d3.stack() .keys(["In Scope", "Out Scope"]) .order(d3.stackOrderDescending) .offset(d3.stackOffsetNone); // transpose your data using stack var series = stack(data); // view the stack console.log(series); // setup the Y scale var yScale = d3.scaleLinear() .domain([0, d3.max(series, function(d) { return d3.max(d, function(d) { return d[1]; }); })]) .range([h, 0]); // Set some colors into an array var colors = ["#dfd6d6", "#d85f41"]; // choose colors // Create groups for each series, rect elements for each segment var groups = svg.selectAll("g.type") .data(series) .enter().append("g") .attr("class", "type") .style("fill", function(d, i) { return colors[i]; // color the rectangles }); // Create the rectangles var rect = groups.selectAll("rect") .data(function(d) { return d; }) .enter() .append("rect") .attr("x", function(d,i) { return i * (x_axisLength/arrayLength) + 30; // Set x coordinate of rectangle to index of data value (i) *25 }) .attr("y", function(d) { return yScale(d[1]); // set base of rectangle }) .attr("height", function(d) { return yScale(d[0]) - yScale(d[1]); // set height of rectangle }) .attr("width", (x_axisLength/arrayLength) - 1) // set width of rectangle .on("mouseover", function() { tooltip.style("display", null); // hide tooltip }) .on("mousemove", function(d) { var xPosition = d3.mouse(this)[0] - 15; var yPosition = d3.mouse(this)[1] - 25; tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")"); tooltip.select("text").text(d.data.city + ": " + (d[1] - d[0])); // populate tooltip }) .on("mouseout", function() { tooltip.style("display", "none"); }); // Draw legend var legend = svg.selectAll(".legend") .data(colors) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(" + i * 50 + ", 110)"; }); legend.append("rect") .attr("x", w - 70) .attr("width", 18) .attr("height", 18) .style("fill", function(d, i) {return colors.slice().reverse()[i];}); legend.append("text") .attr("x", w - 49) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "start") .text(function(d, i) { switch (i) { case 0: return "In"; case 1: return "Out"; } }); // Prep the tooltip bits, initial display is hidden var tooltip = svg.append("g") .attr("class", "tooltip") .style("display", "none"); tooltip.append("text") .attr("x", 15) .attr("dy", "1.2em") .style("text-anchor", "middle") .attr("font-size", "12px"); // Create y-axis svg.append("line") .attr("x1", 30) .attr("y1", 0) .attr("x2", 30) .attr("y2", 100) .attr("stroke-width", 2) .attr("stroke", "black"); // y-axis label svg.append("text") .attr("class", "y label") .attr("text-anchor", "middle") .text("Elements") .attr("transform", "translate(20, 50) rotate(-90)") .attr("font-size", "14px") .attr("font-family", "'Open Sans', sans-serif"); // Create x-axis svg.append("line") .attr("x1", 30) .attr("y1", 100) .attr("x2", 130) .attr("y2", 100) .attr("stroke-width", 2) .attr("stroke", "black"); } </script> </body> </html> My Dataset (etcounts.csv) is here: type,in_scope,out_scope ERKRS,1,1 KKBER,6,5 KOKRS,1,31 BUKRS,78,143 VKORG,23,13 BWKEY,51,6 EKORG,5,6 WERKS,51,65 LGORT,9,180 SPART,9,3 VTWEG,2,0 PERSA,47,73 Unfortunately my D3/JS skills are not quite up to par, but I would appreciate any help. Thanks - John
Instead of var stack = d3.stack() .keys(["In Scope", "Out Scope"]) <-- there is no key as such .order(d3.stackOrderDescending) .offset(d3.stackOffsetNone); it should have been: var stack = d3.stack() .keys(["in_scope", "out_scope"]) .order(d3.stackOrderDescending) .offset(d3.stackOffsetNone); Reason: there is no keys in your CSV "In Scope", "Out Scope" It should have been "in_scope", "out_scope" EDIT For tool tip : tooltip.select("text").text(d.data.city + ": " + (d[1] - d[0])); should have been tooltip.select("text").text(d.data.type + ": " + (d[1] - d[0])); Reason: There is no data.city in your CSV. working code here
Animate position of svg rect on transition
Edit: here is an example Fiddle: https://jsfiddle.net/3c9dtLyh/6/ I have a layout that I am attempting to animate to compare the arrangement on two different dates. What I would like to accomplish is a transition where items whose x,y position is different on the second date smoothly fly to the new position. I have attempted to do this using an updateData function set to trigger onclick. The layout looks like this: I do not neccesarily expect this approach to work because how would the transition know which (x,y) pairs correspond to the correct item name in the new arrangement. What am I missing about how these transitions work and how could I improve my approach? Here is the code I am using. It's a relatively simple sequence of appending and svg element, drawing the rectangles, then (failing) to update their position on click. <!DOCTYPE html> <meta charset="utf-8"> <style> body { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .dot { stroke: #000; } </style> <body> <div id = "chart"> </div> <div id = "select_params"> <input name="updateButton" type="button" value="Update" onclick="updateData()" /> </div> </body> <!-- load js libraries --> <script src="https://d3js.org/d3.v4.min.js"></script> <!-- uses v4 of d3 --> <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script> <!-- need to use this older version for tipsy --> <script type="text/javascript" src="jquery.tipsy.js"></script> <!-- load from locally hosted source code --> <!-- build the visualization --> <script type='text/javascript'> var item_width = 40, item_height = 60; var margin = {top: 20, right: 50, bottom: 75, left: 40}, width = 700 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.scaleLinear() .range([0, width]); var y = d3.scaleLinear() .range([height, 0]); var color = d3.scaleOrdinal(d3.schemeCategory10); var svg = d3.select("#chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.csv("http://localhost:8080/udacity_test_vis_1/combined_item_pos.csv", function(data) { // cast string to numeric data.forEach(function(d) { d.x_pos = +d.x_pos; d.y_pos = +d.y_pos; d.sales = +d.sales; }); console.log(data); var x_offset = 5, y_offset = 5; x.domain(d3.extent(data, function(d) { return d.x_pos; })); // set the x domain y.domain(d3.extent(data, function(d) { return d.y_pos; })); // set the y domain svg.selectAll("g") .data(data) .enter() .append("rect") .filter(function(d){ return d.date == '1-20-2017'}) .attr("class", "dot") .attr("width", item_width) .attr("height", item_height) .attr("x", function(d) { return x(d.x_pos) + x_offset; }) // x position of dots .attr("y", function(d) { return y(d.y_pos) + y_offset; }) // y position of dots .attr("rx", 5) .attr("ry", 5) .style("fill", "#1f5fc6") // color factor variable .style("fill-opacity", 0.5); svg.selectAll("g") .data(data) .enter() .append("text") .filter(function(d){ return d.date == '1-20-2017'}) .attr("x", function(d) { return x(d.x_pos) + item_width/2 + x_offset; }) .attr("y", function(d) { return y(d.y_pos) + item_height/2 + y_offset; }) .attr("font-size", 10) .attr("text-anchor", "middle") .attr("fill", "black") .text(function(d){ return d.item_name}); }); function updateData() { // grab the data again d3.csv("http://localhost:8080/udacity_test_vis_1/combined_item_pos.csv", function(data) { // cast string to numeric data.forEach(function(d) { d.x_pos = +d.x_pos; d.y_pos = +d.y_pos; d.sales = +d.sales; }); var svg = d3.select("#chart").transition(); svg.selectAll("g") .data(data) .enter() .append("rect") .filter(function(d){ return d.date == '2-10-2017'}) .attr("class", "dot") .attr("width", item_width) .attr("height", item_height) .attr("x", function(d) { return x(d.x_pos) + x_offset; }) // x position of dots .attr("y", function(d) { return y(d.y_pos) + y_offset; }) // y position of dots .attr("rx", 5) .attr("ry", 5) .style("fill", "#1f5fc6") // color factor variable .style("fill-opacity", 0.5); svg.selectAll("g") .data(data) .enter() .append("text") .filter(function(d){ return d.date == '2-10-2017'}) .attr("x", function(d) { return x(d.x_pos) + item_width/2 + x_offset; }) .attr("y", function(d) { return y(d.y_pos) + item_height/2 + y_offset; }) .attr("font-size", 10) .attr("text-anchor", "middle") .attr("fill", "black") .text(function(d){ return d.item_name}); }); } </script> Here is my data: ,x_pos,y_pos,item_name,sales,date 0,1,1,S8221,2022,1-20-2017 1,2,1,NLC11,518,1-20-2017 2,3,1,35UUY,1614,1-20-2017 3,4,1,PPTNV,1059,1-20-2017 4,5,1,G0CWS,2183,1-20-2017 5,6,1,3JHUA,2513,1-20-2017 6,7,1,4HXGA,2251,1-20-2017 7,8,1,RYM9K,2330,1-20-2017 8,9,1,T8PUB,1476,1-20-2017 9,10,1,PLULW,1225,1-20-2017 10,1,2,YJ6S0,2403,1-20-2017 11,2,2,E9RGD,1361,1-20-2017 12,3,2,E2SW4,1131,1-20-2017 13,4,2,BZPGX,698,1-20-2017 14,5,2,0K682,1855,1-20-2017 15,6,2,D8UZW,2371,1-20-2017 16,7,2,USKY7,1851,1-20-2017 17,8,2,D0L0Y,1767,1-20-2017 18,9,2,P1AGP,1025,1-20-2017 19,10,2,9LT7O,1380,1-20-2017 20,1,3,1J184,1108,1-20-2017 21,2,3,RJDEG,2106,1-20-2017 22,3,3,LTSLR,1980,1-20-2017 23,4,3,ET3DF,2700,1-20-2017 24,5,3,42W1W,2194,1-20-2017 25,6,3,5QTJN,958,1-20-2017 26,7,3,O8XKY,2381,1-20-2017 27,8,3,LS9NW,516,1-20-2017 28,9,3,0MPZ7,2198,1-20-2017 29,10,3,R4E3J,2494,1-20-2017 30,1,4,WFPPY,2349,1-20-2017 31,2,4,MT2DB,2525,1-20-2017 32,3,4,6DRYS,600,1-20-2017 33,4,4,NVV0S,1556,1-20-2017 34,5,4,ODGZ2,912,1-20-2017 35,6,4,E3NLS,931,1-20-2017 36,7,4,9FFZ7,722,1-20-2017 37,8,4,UKZGF,2170,1-20-2017 38,9,4,XXORI,896,1-20-2017 39,10,4,QYU9Q,1104,1-20-2017 40,1,5,4KQPU,1562,1-20-2017 41,2,5,S3AYK,2298,1-20-2017 42,3,5,5W3CE,2580,1-20-2017 43,4,5,T0S7H,1677,1-20-2017 44,5,5,02SJG,1972,1-20-2017 45,6,5,GBMNZ,1845,1-20-2017 46,7,5,2Y7KH,982,1-20-2017 47,8,5,3WMOL,1952,1-20-2017 48,9,5,93KLU,2240,1-20-2017 49,10,5,K80OQ,2467,1-20-2017 50,1,6,2SIJS,1788,1-20-2017 51,2,6,5ZJ7V,2277,1-20-2017 52,3,6,HTL99,873,1-20-2017 53,4,6,C06QP,2185,1-20-2017 54,5,6,2S1YI,580,1-20-2017 55,6,6,IQ0L8,2395,1-20-2017 56,7,6,PEE2Y,2299,1-20-2017 57,8,6,6DEWK,2019,1-20-2017 58,9,6,9FY5B,1517,1-20-2017 59,10,6,NZQ54,2624,1-20-2017 60,1,7,C4SVV,1823,1-20-2017 61,2,7,Q4C4I,2339,1-20-2017 62,3,7,996OQ,1621,1-20-2017 63,4,7,PISK6,895,1-20-2017 64,5,7,KOKHE,1315,1-20-2017 65,6,7,6P4FT,1467,1-20-2017 66,7,7,3FY75,2085,1-20-2017 67,8,7,9YCNB,992,1-20-2017 68,9,7,NXXK1,2080,1-20-2017 69,10,7,4RDHV,2031,1-20-2017 0,6,1,9FFZ7,592,2-10-2017 1,1,6,E2SW4,622,2-10-2017 2,6,7,PLULW,1699,2-10-2017 3,8,3,ET3DF,784,2-10-2017 4,9,4,KOKHE,1092,2-10-2017 5,2,6,5ZJ7V,1691,2-10-2017 6,4,5,9FY5B,630,2-10-2017 7,9,4,G0CWS,1523,2-10-2017 8,9,2,PISK6,1778,2-10-2017 9,6,4,35UUY,2107,2-10-2017 10,3,5,5QTJN,1751,2-10-2017 11,6,6,NLC11,526,2-10-2017 12,8,2,C06QP,2308,2-10-2017 13,8,3,XXORI,1453,2-10-2017 14,5,1,E9RGD,1864,2-10-2017 15,7,2,HTL99,1222,2-10-2017 16,3,3,PEE2Y,2050,2-10-2017 17,9,7,GBMNZ,1941,2-10-2017 18,3,1,T8PUB,1440,2-10-2017 19,5,1,3WMOL,2692,2-10-2017 20,7,7,S3AYK,523,2-10-2017 21,1,5,BZPGX,2245,2-10-2017 22,2,1,S8221,2241,2-10-2017 23,9,7,IQ0L8,566,2-10-2017 24,8,5,D8UZW,1769,2-10-2017 25,3,1,RYM9K,1044,2-10-2017 26,4,6,4HXGA,2650,2-10-2017 27,2,2,WFPPY,2203,2-10-2017 28,2,4,93KLU,2289,2-10-2017 29,7,3,P1AGP,1084,2-10-2017 30,4,3,3JHUA,1364,2-10-2017 31,1,4,9LT7O,1198,2-10-2017 32,4,6,4RDHV,771,2-10-2017 33,10,7,T0S7H,873,2-10-2017 34,3,6,NXXK1,2391,2-10-2017 35,8,2,2SIJS,811,2-10-2017 36,8,4,LTSLR,1670,2-10-2017 37,6,7,02SJG,1880,2-10-2017 38,9,3,0MPZ7,2090,2-10-2017 39,2,6,E3NLS,2350,2-10-2017 40,7,6,QYU9Q,1092,2-10-2017 41,6,3,0K682,894,2-10-2017 42,1,5,LS9NW,1928,2-10-2017 43,7,7,NVV0S,951,2-10-2017 44,9,4,996OQ,670,2-10-2017 45,7,6,USKY7,706,2-10-2017 46,10,4,Q4C4I,2270,2-10-2017 47,4,2,UKZGF,1691,2-10-2017 48,10,3,RJDEG,597,2-10-2017 49,10,2,1J184,1921,2-10-2017 50,2,3,5W3CE,2604,2-10-2017 51,5,5,3FY75,1260,2-10-2017 52,1,1,6DEWK,2491,2-10-2017 53,7,5,9YCNB,1743,2-10-2017 54,4,7,6DRYS,2450,2-10-2017 55,5,2,MT2DB,1292,2-10-2017 56,8,5,C4SVV,1395,2-10-2017 57,3,7,ODGZ2,2685,2-10-2017 58,10,4,2S1YI,2617,2-10-2017 59,1,2,YJ6S0,1611,2-10-2017 60,6,3,2Y7KH,2188,2-10-2017 61,5,4,4KQPU,1413,2-10-2017 62,10,1,D0L0Y,2291,2-10-2017 63,5,1,NZQ54,1405,2-10-2017 64,5,2,6P4FT,1885,2-10-2017 65,3,1,PPTNV,1442,2-10-2017 66,1,5,K80OQ,2140,2-10-2017 67,4,5,42W1W,1697,2-10-2017 68,2,7,O8XKY,1007,2-10-2017 69,10,6,R4E3J,887,2-10-2017
So, I took a few minutes to completely refactor your code into proper d3 style. This aims to demonstrate a couple things: The proper use of the enter, update, exit pattern. Removed cut / paste duplicate code. The proper way to use g to group elements and position them together. How to add the transitions. Here is the code running. Commented code: <!DOCTYPE html> <meta charset="utf-8"> <style> body { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .dot { stroke: #000; } </style> <body> <div id="chart"> </div> <div id="select_params"> <input name="updateButton" type="button" value="Update" onclick="updateData()" /> </div> </body> <!-- load js libraries --> <script src="https://d3js.org/d3.v4.min.js"></script> <!-- uses v4 of d3 --> <!-- build the visualization --> <script type='text/javascript'> var item_width = 40, item_height = 60; var margin = { top: 20, right: 50, bottom: 75, left: 40 }, width = 700 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.scaleLinear() .range([0, width]); var y = d3.scaleLinear() .range([height, 0]); var color = d3.scaleOrdinal(d3.schemeCategory10); var svg = d3.select("#chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // a single function to draw function draw(data, someDate) { data.forEach(function(d) { d.x_pos = +d.x_pos; d.y_pos = +d.y_pos; d.sales = +d.sales; }); // pre-filter data data = data.filter(function(d) { return d.date === someDate }); var x_offset = 5, y_offset = 5; x.domain(d3.extent(data, function(d) { return d.x_pos; })); // set the x domain y.domain(d3.extent(data, function(d) { return d.y_pos; })); // set the y domain // create an update selection with a key function var g_sel = svg.selectAll("g") .data(data, function(d) { return d.item_name; }); // get rid of those leaving the update g_sel.exit().remove(); // our entering g var g_ent = g_sel.enter() .append("g"); // add our rects to our g g_ent.append("rect") .attr("class", "dot") .attr("width", item_width) .attr("height", item_height) .attr("rx", 5) .attr("ry", 5) .style("fill", "#1f5fc6") // color factor variable .style("fill-opacity", 0.5); // add our text to our g g_ent.append("text") .attr("font-size", 10) .attr("text-anchor", "middle") .attr("fill", "black") .attr("dx", item_width / 2) .attr("dy", item_height / 2) .text(function(d) { return d.item_name }); // UPDATE + ENTER selection g_sel = g_ent.merge(g_sel); // move them into position with transition g_sel .transition() .attr("transform", function(d) { return "translate(" + (x(d.x_pos) + x_offset) + "," + (y(d.y_pos) + y_offset) + ")"; }); } d3.csv("test.csv", function(data) { draw(data, '1-20-2017'); }); function updateData() { d3.csv("test.csv", function(data) { draw(data, '2-10-2017'); }); } </script>
Heres my attempt: https://jsfiddle.net/guanzo/3c9dtLyh/10/ There are multiple data points that share the same position, which is why some rectangles are overlapping. I made a lot of changes to your code that resulted in less repetition. Your data contains duplicate item_names with different dates/positions, but in your visualization you seem to want to only show items at a single date. Therefore, you only need to pass d3 data for a certain date, versus passing d3 ALL the data and then filtering. Your code: svg.selectAll("g") .data(data) .enter() .append("rect") .filter(function(d){ return d.date == '1-20-2017'}) My code: var firstDateData = data.filter(d=>d.date == '1-20-2017'); var groups = svg.selectAll("g") .data(firstDateData, d=> d.item_name) The difference between these 2 is that in my example, D3 is only aware of a single set of item_names on date 1-20-2017. Therefore when i update the date with item_names on date 2-10-2017, D3 will automatically move all updated rectangles to their new position. How? Here is where your question comes into play: I do not neccesarily expect this approach to work because how would the transition know which (x,y) pairs correspond to the correct item name in the new arrangement This is because i associated each rectangle with an item_name. D3s data function can take an optional 2nd parameter that specifies HOW the data is bound to the rectangles. This is called the key function. svg.selectAll("g").data(firstDateData, d=> d.item_name) In this case, i told d3 that each group (rectangles and their text) is bound to item_name. Therefore, the next time i pass data to D3, it tries to match existing elements (that are associated with an item_name) to the data (which contains item_names). If in my new data, i pass an item_name that corresponds to an existing element, and the data contains a new x and y position, D3 will move to element to that new position. Note that even though i'm talking about rectangles, i bound data to the g element, which contains the rectangle and the text. Feel free to ask any questions, i made a lot of changes that i didn't discuss.
D3 two donut charts on top of one another, different data sets. Javascript/HTML
What I'm trying to do is make two charts display in the same field, one to show the time spent working vs. the time spent idling, and the other chart to show whether the machine is currently working or idling. I want the chart that shows the machine idling to be smaller than the first and fit inside it. I've been able to make both charts but I am unable to combine them in the way that I want them to. [what I have right now] [what I'd like to do] Here is my code: <!DOCTYPE html> <html lang="en"> <div id="chart-center-jc1" align="center"></div> <!--this line control location of the SVG chart--> <script src="d3/d3.v3.min.js"></script> <script> var radius = 80, padding = 10; var radius2 = 25, padding = 10; var color = d3.scale.ordinal() .range([ "#fc0303", "#21d525", "#d0cece", "#a05d56", "#d0743c", "#ff8c00"]); var arc = d3.svg.arc() .outerRadius(radius) .innerRadius(radius - 30); var arc2 = d3.svg.arc() .outerRadius(radius2) .innerRadius(radius2 - 25); var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.population; }); var pie2 = d3.layout.pie() .sort(null) .value(function(d) { return d.population; }); d3.csv("M1 Summary.csv", function(error, data) { if (error) throw error; color.domain(d3.keys(data[0]).filter(function(key) { return key !=="Machine"; })); data.forEach(function(d) { d.ages = color.domain().map(function(name) { return {name: name, population: +d[name]}; }); }); var legend = d3.select("#chart-center-jc1").append("svg") .attr("class", "legend") .attr("width", radius * 2) .attr("height", radius * 2) .selectAll("g") .data(color.domain().slice().reverse()) .enter().append("g") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", 24) .attr("y", 9) .attr("dy", ".35em") .text(function(d) { return d; }); var svg = d3.select("#chart-center-jc1").selectAll(".pie") .data(data) .enter().append("svg") .attr("class", "pie2") .attr("width", radius * 2) .attr("height", radius * 3) .append("g") .attr("transform", "translate(" + radius + "," + radius + ")"); svg.selectAll(".arc") .data(function(d) { return pie(d.ages); }) .enter().append("path") .attr("class", "arc") .attr("d", arc) .style("fill", function(d) { return color(d.data.name); }); svg.selectAll(".arc2") .data(function(d) { return pie2(d.ages); }) .enter().append("path") .attr("class", "arc2") .attr("d", arc2) .style("fill", function(d) { return color(d.data.name); }); });
The key is to append one svg onto another: var svg = d3.select("#chart-center-jc1").append("svg") .attr("width", radius * 2) .attr("height", radius * 3) .attr("class","outerPie") .append("g") .attr("transform", "translate(" + radius + "," + radius + ")"); var svg2 = d3.select(".outerPie").append("svg") .attr("width", radius * 2) .attr("height", radius * 3) .attr("class","innerPie") .append("g") .attr("transform", "translate(" + radius + "," + radius + ")"); Note that both svgs have the same height, width, and translate. This is because they are on top of one another, and you want to position the second in the center of the first. See fiddle for complete solution.
How to add tooltips in a D3 donut chart
I would like to add tooltips in a D3 donut chart. How can this be done? I would also like to add the percentages for each of the sections in pie chart. This is my code: <!DOCTYPE html> <meta charset="utf-8"> <style> body { font: 14px sans-serif; } svg { padding: 10px 0 0 10px; } .arc { stroke: #000; } .arc:hover{ stroke: yellow; } .pie:hover { fill: orangered ; } </style> <body> <div class = "InfoVis"></div> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> <script> var tooltip = d3.select("body") .append("div") .style("position", "absolute") .style("z-index", "10") .style("visibility", "hidden") .text("a simple tooltip"); var radius = 144, padding = 20; var color = d3.scale.ordinal() .range(["#00ffff", "#00ff00", "#ffbf00", "#fe2ec8", "#bdbdbd", "#3104b4", "#5882fa"]); var arc = d3.svg.arc() .outerRadius(radius) .innerRadius(radius - 40); var pie = d3.layout.pie() .sort(null) .value(function(d) { return d.nutrifacts; }); d3.csv("data.csv", function(error, data) { color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Cereal"; })); data.forEach(function(d) { d.nutri = color.domain().map(function(name) { return {name: name, nutrifacts: +d[name]}; }); }); var legend = d3.select("body").append("svg") .attr("class", "legend") .attr("width", radius * 2) .attr("height", radius * 2) .selectAll("g") .data(color.domain().slice().reverse()) .enter().append("g") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", 24) .attr("y", 9) .attr("dy", ".55em") .text(function(d) { return d; }); var svg = d3.select("body").selectAll(".pie") .data(data) .enter().append("svg") .attr("class", "pie") .attr("width", radius * 2) .attr("height", radius * 2) .append("g") .attr("transform", "translate(" + radius + "," + radius + ")"); svg.selectAll(".arc") .data(function(d) { return pie(d.nutri); }) .enter().append("path") .attr("class", "arc") .attr("d", arc) .style("fill", function(d) { return color(d.data.name); }); svg.append("text") .attr("dy", ".35em") .style("text-anchor", "middle") .text(function(d) { return d.Cereal; }); }); </script> Please help me in adding a tooltip to this code and, if possible, add color to the tooltip.
I got idea of your question, but you don't give data.csv file. So I took my own data for drawing donut chart with tooltip. But your are using predefined tooltip, which is given by D3. var data = [{"age":"1-5","population":2000}, {"age":"6-10","population":1000}, {"age":"11-15","population":3000}, {"age":"16-20","population":1200}, {"age":"21-25","population":900},{"age":"26-30","population":1500}, {"age":"31-35","population":600},{"age":"36-40","population":1200}, {"age":"41-45","population":900}]; var margin = {top:40,left:40,right:40,bottom:40}; width = 650; height = 650; radius = Math.min(width-100,height-100)/2; var color = d3.scale.ordinal() .range(["#e53517","#6b486b","#ffbb78","#7ab51d","#6b486b", "#e53517","#7ab51d","#ff7f0e","#ffc400"]); var arc = d3.svg.arc() .outerRadius(radius -130) .innerRadius(radius - 10); var arcOver = d3.svg.arc() .outerRadius(radius +50) .innerRadius(0); var svg = d3.select("#svgContent").append("svg") .attr("width",width) .attr("height",height) .append("g") .attr("transform","translate("+width/2+","+height/2+")"); div = d3.select("body") .append("div") .attr("class", "tooltip"); var pie = d3.layout.pie() .sort(null) .value(function(d){return d.population;}); var g = svg.selectAll(".arc") .data(pie(data)) .enter() .append("g") .attr("class","arc") .on("mousemove",function(d){ var mouseVal = d3.mouse(this); div.style("display","none"); div .html("age:"+d.data.age+"</br>"+"population:"+d.data.population) .style("left", (d3.event.pageX+12) + "px") .style("top", (d3.event.pageY-10) + "px") .style("opacity", 1) .style("display","block"); }) .on("mouseout",function(){div.html(" ").style("display","none");}) .on("click",function(d){ if(d3.select(this).attr("transform") == null){ d3.select(this).attr("transform","translate(42,0)"); }else{ d3.select(this).attr("transform",null); } }); g.append("path") .attr("d",arc) .style("fill",function(d){return color(d.data.age);}); svg.selectAll("text").data(pie(data)).enter() .append("text") .attr("class","label1") .attr("transform", function(d) { var dist=radius+15; var winkel=(d.startAngle+d.endAngle)/2; var x=dist*Math.sin(winkel)-4; var y=-dist*Math.cos(winkel)-4; return "translate(" + x + "," + y + ")"; }) .attr("dy", "0.35em") .attr("text-anchor", "middle") .text(function(d){ return d.value; }); For more clarity, see this link. This is animated screenshot of this code in action: