D3.js path goes in different directions in V3 vs V4 - javascript
I'm attempting to make the same multi-line graph in D3 V3 and V4, but they behave differently for reasons I don't understand. What can I change in my V4 code that will make the paths connect in the correct order (according to the x axis instead of the y axis)?
Here's what V3 gives, taken from the jsfiddle I made for it:
...But here's V4:
Jsfiddle doesn't support V4 yet, so here's my code:
var margin = {top: 20, right: 40, bottom: 100, left: 100},
width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var line = d3.line()
.x(function(d) { return x(d.depth); })
.y(function(d) { return y(d.carat); });
var svg = d3.select("body")
.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("diamonds.csv", function(error, data) {
data.forEach(function(d) {
d.carat = +d.carat;
d.depth = +d.depth;
//d.cut = +d.cut;
})
data.sort(function(a,b) { return a.x - b.x; });
x.domain(d3.extent(data, function(d) { return d.depth; })).nice();
y.domain(d3.extent(data, function(d) { return d.carat; })).nice();
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 6)
.attr("x", 5)
.attr("dy", ".35em")
.attr("transform", "rotate(45)")
.style("text-anchor", "start")
var dataNest = d3.nest()
.key(function(d) {return d.cut;})
.entries(data);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price");
var color = d3.scaleOrdinal(d3.schemeCategory10);
dataNest.forEach(function(d) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key); })
.attr("d", line(d.values));
});
});
If you look at your code using D3 v3.x, you did this after loading the data:
data.forEach(function(d) {
d.x = +d.depth;
d.carat = +d.carat;
})
And using that property x for sorting:
data.sort(function(a,b) { return a.x - b.x; });
However, in your v4.x version, you did:
data.forEach(function(d) {
d.depth = +d.depth;
d.carat = +d.carat;
})
And used an nonexistent x for sorting (the problem with sorting alone was making the lines different from v3.x).
Solution: use depth for sorting:
data.sort(function(a,b) { return a.depth - b.depth; });
Here is your code using v4.x version:
var margin = {
top: 20,
right: 40,
bottom: 100,
left: 100
},
width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var line = d3.line()
.x(function(d) {
return x(d.depth);
})
.y(function(d) {
return y(d.carat);
});
var svg = d3.select("body")
.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 + ")");
var data = d3.csvParse(d3.select("pre#data").text());
data.forEach(function(d) {
d.carat = +d.carat;
d.depth = +d.depth;
//d.cut = +d.cut;
})
data.sort(function(a, b) {
return a.depth - b.depth;
});
x.domain(d3.extent(data, function(d) {
return d.depth;
})).nice();
y.domain(d3.extent(data, function(d) {
return d.carat;
})).nice();
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 6)
.attr("x", 5)
.attr("dy", ".35em")
.attr("transform", "rotate(45)")
.style("text-anchor", "start")
var dataNest = d3.nest()
.key(function(d) {
return d.cut;
})
.entries(data);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price");
var color = d3.scaleOrdinal(d3.schemeCategory10);
dataNest.forEach(function(d) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key);
})
.attr("d", line(d.values));
});
pre {
display:none;
}
path
{
fill: none;
stroke: #000;
}
.line {
fill: none;
// stroke: green;
// stroke-width: 3.5px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="data">
carat,cut,color,clarity,depth,table,price,x,y,z
0.41,Ideal,G,VS1,60.8,56,899,4.79,4.82,2.92
0.3,Ideal,F,VS1,62.1,55,612,4.31,4.35,2.69
1.25,Ideal,H,SI1,62.2,57,6661,6.86,6.9,4.28
0.41,Ideal,G,VS2,61.4,55,1061,4.8,4.75,2.93
0.53,Premium,E,VVS2,62.4,56,2331,5.19,5.17,3.23
1.14,Very Good,G,VS2,63.2,56,6435,6.67,6.63,4.2
0.51,Premium,G,SI1,62,59,1053,5.12,5.1,3.17
1.51,Good,H,VVS2,63.1,59,11826,7.26,7.28,4.59
1.31,Ideal,J,SI1,62.5,56,6337,6.95,7.04,4.37
0.33,Very Good,I,VVS1,61.7,61,608,4.43,4.45,2.74
0.42,Ideal,F,VS1,62.3,55,1103,4.79,4.77,2.98
1.01,Good,E,VS2,60.8,63,6250,6.44,6.46,3.92
1,Premium,F,SI1,62.7,59,5292,6.4,6.36,4
0.51,Ideal,G,VVS1,61.9,53,1919,5.14,5.2,3.2
0.34,Ideal,H,SI1,61.5,55,647,4.53,4.55,2.79
0.23,Premium,F,VVS2,61.3,59,445,3.94,3.99,2.43
0.3,Ideal,F,VS2,62.9,57,776,4.29,4.27,2.69
1.14,Premium,F,SI1,60.4,58,6320,6.82,6.79,4.11
0.33,Ideal,J,VVS1,62.1,54,509,4.45,4.47,2.77
0.41,Premium,H,SI1,60.9,60,683,4.79,4.83,2.93
2.01,Premium,J,SI2,62.8,58,12407,8.09,8,5.05
2.01,Very Good,I,SI1,60.3,59,15126,8.14,8.21,4.93
0.4,Very Good,D,VS2,62.8,58,993,4.66,4.71,2.94
1.09,Premium,D,SI1,61.6,58,5799,6.61,6.57,4.06
0.3,Ideal,F,VS1,61.5,55,612,4.31,4.34,2.66
0.77,Very Good,H,SI2,63.6,58,2129,5.77,5.81,3.68
0.38,Very Good,F,VS1,62.7,57,883,4.71,4.64,2.93
0.54,Premium,E,VS1,60.3,58,1939,5.26,5.32,3.19
0.93,Premium,F,SI1,58.8,60,4010,6.49,6.37,3.78
0.32,Ideal,H,VS1,61.1,56,561,4.44,4.46,2.72
0.78,Premium,F,SI2,62.8,56,2200,5.9,5.86,3.69
0.4,Ideal,E,VS1,61.2,55,1005,4.79,4.76,2.92
0.41,Ideal,D,VS2,62.4,55,1076,4.79,4.76,2.98
0.73,Very Good,E,SI1,61.6,59,2760,5.77,5.78,3.56
2.52,Very Good,G,SI2,63.2,58,17689,8.65,8.61,5.45
1.06,Ideal,D,VVS2,62,56,12053,6.53,6.57,4.06
0.8,Very Good,D,IF,63.3,57,6834,5.85,5.87,3.71
1.5,Premium,H,VS2,62.2,58,10291,7.27,7.36,4.55
2.17,Good,H,SI2,58.9,62,16036,8.48,8.52,5.01
1.58,Ideal,G,SI1,62.2,55,11927,7.44,7.5,4.65
2.03,Premium,H,VS2,62.1,56,18139,8.2,8.12,5.07
0.58,Very Good,D,SI2,62.9,56,1438,5.31,5.35,3.35
0.72,Very Good,D,VS2,62.1,59,3016,5.7,5.73,3.55
0.38,Ideal,D,VVS2,61.5,57,1200,4.63,4.67,2.86
0.5,Premium,E,VS2,61.3,60,1624,5.07,5.11,3.12
0.31,Ideal,F,VS2,61.1,56,640,4.35,4.39,2.67
1.41,Premium,D,SI2,61.1,56,6988,7.19,7.15,4.38
0.7,Good,I,VS1,63.2,55,2274,5.58,5.63,3.54
1.22,Ideal,F,SI2,62,57,4852,6.88,6.83,4.25
1.58,Ideal,H,VS2,61.4,56,12334,7.5,7.56,4.62
1.2,Ideal,G,VS1,62,55,9625,6.81,6.87,4.24
1.03,Premium,H,I1,61.1,60,3172,6.46,6.51,3.96
0.77,Very Good,H,VS1,62.8,58,2961,5.75,5.78,3.62
1.04,Ideal,I,VS2,61.5,57,5105,6.49,6.52,4
1,Good,H,SI1,63.7,60,4788,6.33,6.3,4.02
0.82,Very Good,G,IF,61.9,57,4844,5.96,6,3.7
0.71,Ideal,D,VS1,60.9,57,3518,5.74,5.76,3.5
1.21,Ideal,I,SI2,64.6,56,4879,6.67,6.62,4.29
0.4,Very Good,E,SI1,61.7,60,687,4.68,4.72,2.9
1.11,Premium,H,SI1,61.1,60,5433,6.68,6.62,4.06
1.5,Ideal,F,VS2,60.4,57,14071,7.41,7.43,4.48
1.48,Very Good,H,SI1,62.5,59,8815,7.16,7.23,4.5
0.28,Ideal,F,VVS2,61.5,57,787,4.19,4.24,2.59
0.64,Very Good,E,VS2,63.4,54,2114,5.52,5.49,3.49
1.68,Ideal,I,VS2,62.1,57,10800,7.6,7.54,4.7
0.93,Premium,G,SI2,61.7,60,3802,6.25,6.2,3.84
0.34,Very Good,E,SI1,62.9,56,596,4.45,4.48,2.81
1.57,Premium,G,VS1,59.9,56,14180,7.6,7.55,4.54
1.16,Premium,H,SI2,61.8,58,4872,6.81,6.75,4.19
0.3,Ideal,E,VVS2,61.4,57,1013,4.34,4.32,2.66
1.06,Very Good,F,SI1,63.4,58,5520,6.51,6.42,4.1
1.14,Ideal,H,SI1,61.6,56,7079,6.72,6.74,4.14
1,Premium,J,SI1,58.7,58,3920,6.55,6.51,3.83
2.01,Very Good,F,SI2,63.3,59,11925,7.98,7.89,5.02
1.37,Premium,G,VS1,58.3,60,10412,7.35,7.3,4.27
0.91,Premium,E,SI2,61.6,60,3846,6.14,6.1,3.77
1,Premium,G,VS2,63,58,6048,6.4,6.33,4.01
0.4,Good,G,SI1,63.4,58,655,4.66,4.71,2.97
1.39,Very Good,G,SI2,61.5,62,6628,7.09,7.16,4.38
0.31,Ideal,G,IF,62.7,57,924,4.31,4.34,2.71
1.5,Premium,H,VS2,62.4,59,11092,7.29,7.32,4.56
0.99,Very Good,F,SI1,62.5,58,5112,6.36,6.38,3.98
1.5,Very Good,I,VVS2,64,54,9618,7.19,7.27,4.63
1.04,Very Good,E,VVS2,62.4,58,8748,6.46,6.4,4.01
1.01,Premium,H,SI1,61.8,59,5204,6.38,6.33,3.93
0.71,Fair,D,SI1,55.5,62,2086,6,5.97,3.32
0.26,Ideal,G,VS1,62.1,55,478,4.09,4.12,2.55
0.92,Premium,E,SI1,61.7,57,4637,6.32,6.2,3.86
0.32,Ideal,E,VS2,61.8,54,768,4.43,4.4,2.73
0.54,Ideal,H,IF,61.5,54,1981,5.27,5.3,3.25
0.4,Ideal,G,IF,61.2,56,1199,4.74,4.77,2.91
1.28,Very Good,G,VVS2,59.5,56,11478,7.12,7.16,4.25
0.42,Premium,G,VS2,60.6,59,1087,4.85,4.78,2.92
1.04,Premium,H,VS2,60.4,59,5777,6.66,6.51,3.98
0.91,Premium,G,SI1,61.8,60,4045,6.18,6.21,3.83
0.33,Very Good,H,VS2,58.8,62,486,4.49,4.53,2.65
0.31,Ideal,E,VS1,61.3,54,664,4.37,4.4,2.69
0.61,Very Good,D,VS1,62.4,57,2096,5.44,5.46,3.4
0.3,Ideal,H,VVS2,61.6,55,605,4.3,4.34,2.66
1.57,Premium,J,VS1,61.3,59,8595,7.44,7.47,4.57
0.72,Very Good,J,VS1,62.3,57,2136,5.73,5.77,3.58
1.11,Premium,F,SI2,62.2,57,5284,6.67,6.61,4.13
0.4,Premium,D,SI2,61.7,58,855,4.74,4.69,2.91
0.7,Good,F,VVS1,63.3,56,3310,5.64,5.7,3.59
1,Premium,D,SI2,59.4,60,4626,6.56,6.48,3.87
0.61,Ideal,E,VVS2,62,54,3011,5.43,5.47,3.38
1,Premium,F,VS2,62.8,59,6328,6.35,6.32,3.98
1.05,Ideal,F,SI2,60.9,56,4591,6.56,6.64,4.02
1.01,Premium,I,SI1,61.6,58,3944,6.45,6.51,3.99
0.51,Ideal,F,VS2,63.2,57,1687,5.08,5.05,3.2
1.2,Premium,H,SI2,62.4,61,5040,6.81,6.78,4.24
1.52,Ideal,J,VS1,62.3,58,8608,7.32,7.35,4.57
0.51,Premium,F,VVS2,61.9,56,2310,5.17,5.13,3.19
0.5,Very Good,H,IF,61.4,61,1923,5.14,5.03,3.12
1.01,Premium,G,SI1,63,60,4118,6.34,6.3,3.98
0.8,Very Good,F,VS1,62.6,57,3720,5.9,5.98,3.72
2.01,Very Good,I,SI1,62.8,60,14811,7.99,8.04,5.03
1,Premium,E,SI1,61.6,59,5600,6.41,6.38,3.94
1,Good,J,VS1,58.1,64,3920,6.63,6.51,3.82
0.52,Premium,F,VS2,61.4,62,1605,5.19,5.16,3.18
1.3,Very Good,I,VS2,61.8,56,7087,6.98,7.04,4.33
2,Very Good,I,SI1,62.9,59.2,15081,7.95,8.08,5.05
0.31,Very Good,I,VS2,61.6,56,468,4.36,4.39,2.69
1.63,Very Good,I,SI1,62,54,9090,7.6,7.67,4.73
0.3,Premium,H,VVS2,62.1,52,776,4.31,4.29,2.67
1.1,Premium,G,VS2,62.8,58,6387,6.6,6.58,4.14
0.23,Very Good,F,VVS2,61,59,465,3.93,3.97,2.41
1.23,Premium,I,SI2,62.1,59,4773,6.83,6.79,4.23
1.02,Good,G,VS2,63.6,57,5816,6.38,6.41,4.07
0.71,Premium,F,VS1,59.2,58,2839,5.87,5.82,3.46
1.69,Ideal,H,I1,62,56,6757,7.66,7.61,4.73
1.6,Ideal,G,VS2,61.9,56,15000,7.53,7.47,4.64
0.32,Ideal,H,IF,61.9,54.2,783,4.38,4.42,2.72
0.73,Very Good,G,SI2,62.2,58,2057,5.71,5.77,3.57
0.32,Ideal,D,VS2,62.7,54,758,4.36,4.38,2.74
0.7,Ideal,E,VS2,61.1,59,3201,5.67,5.73,3.48
0.3,Ideal,H,VS1,62.1,54,526,4.32,4.35,2.69
0.9,Good,I,VS2,63.8,55,3303,6.07,6.16,3.9
0.52,Premium,H,SI2,60.9,61,975,5.15,5.1,3.12
0.97,Premium,F,SI1,62.7,59,4561,6.28,6.31,3.95
0.32,Very Good,H,SI1,62.6,55,461,4.37,4.38,2.74
0.54,Ideal,F,SI1,61.2,56,1307,5.23,5.29,3.22
1.21,Good,F,VS2,63.7,58,7911,6.67,6.71,4.26
1.51,Very Good,I,SI1,63.1,56,7891,7.28,7.33,4.61
1.01,Premium,F,VS2,58.9,58,6271,6.59,6.51,3.86
1.57,Very Good,J,VS2,62.6,59,7832,7.39,7.43,4.64
0.73,Premium,I,VS1,60.3,58,2371,5.83,5.87,3.53
1.2,Ideal,I,SI1,62.5,57,5107,6.77,6.71,4.21
3.04,Premium,I,SI2,59.3,60,18559,9.51,9.46,5.62
0.31,Very Good,G,VVS1,63.1,56,1046,4.35,4.33,2.74
0.5,Premium,E,I1,60.7,61,840,5.14,5.05,3.09
0.38,Ideal,I,VS1,62.4,54.4,703,4.62,4.66,2.9
1.12,Premium,G,VS2,60.7,53,6774,6.81,6.7,4.1
1.33,Premium,F,SI2,60.7,62,5288,7.12,7.07,4.31
1.11,Ideal,J,VS1,61.7,57,4854,6.67,6.72,4.13
0.71,Ideal,G,SI1,62.4,56,2386,5.74,5.71,3.57
1.03,Ideal,G,VS1,62.1,57,6558,6.44,6.47,4.01
0.32,Very Good,G,VVS1,61.4,55,772,4.41,4.45,2.72
1.55,Premium,D,VS2,61.5,58,16137,7.51,7.48,4.61
0.72,Premium,F,VS2,60.8,58,2530,5.78,5.74,3.5
0.31,Good,F,VS2,63.4,56,625,4.29,4.32,2.73
0.42,Ideal,G,IF,62,57,1310,4.82,4.8,2.98
2.1,Premium,H,SI2,60.4,59,16479,8.28,8.33,5.02
0.66,Ideal,H,VS2,61.4,56,2178,5.62,5.65,3.46
0.48,Premium,F,SI1,60.6,62,1110,5.06,5,3.05
0.91,Very Good,D,SI1,63,59,4429,6.11,6.15,3.86
0.5,Ideal,E,SI2,62.5,57,1154,5.04,5.07,3.16
0.57,Ideal,I,VS1,62.2,55,1448,5.28,5.33,3.3
1.09,Premium,F,SI1,60.9,59,5384,6.64,6.59,4.03
1,Premium,H,SI1,62.3,60,4788,6.38,6.34,3.96
0.4,Very Good,E,VS2,63,58,791,4.7,4.73,2.97
1.2,Ideal,I,SI1,60.1,56,5578,6.9,6.84,4.13
0.71,Premium,I,VS2,59.3,59,2300,5.89,5.81,3.47
0.34,Ideal,D,VS2,62,55,1033,4.48,4.45,2.77
1.25,Good,J,SI1,63.6,57,5110,6.86,6.81,4.35
0.41,Ideal,D,SI1,61.7,54,1015,4.79,4.78,2.95
0.51,Fair,D,SI2,66.5,58,1109,4.95,4.89,3.27
0.56,Ideal,E,SI1,62.7,57,1698,5.27,5.23,3.29
1.04,Ideal,G,VS1,61.5,57,7457,6.5,6.54,4.01
0.3,Ideal,I,SI1,61.9,57,422,4.29,4.31,2.66
0.5,Premium,F,VS2,61.7,60,1323,5.06,5.02,3.11
0.28,Very Good,G,VVS2,62.3,56,522,4.16,4.19,2.6
0.37,Very Good,E,VS1,62,56,925,4.59,4.63,2.86
0.8,Premium,F,SI2,58.5,62,2371,6.08,6.05,3.55
0.81,Very Good,F,SI2,62.7,58,2942,5.92,5.95,3.72
0.51,Ideal,E,VVS2,62.8,56,2211,5.13,5.15,3.23
0.98,Ideal,G,SI1,62.3,56,4665,6.37,6.34,3.96
1.51,Good,H,VS2,63.6,61,8904,7.08,7.03,4.49
0.5,Premium,D,SI1,60.3,58,1433,5.12,5.1,3.08
0.43,Ideal,F,VVS2,62.2,55,1250,4.85,4.83,3.01
0.7,Ideal,F,SI1,61.1,57,2516,5.75,5.71,3.5
0.3,Premium,E,SI1,61.8,60,675,4.28,4.23,2.63
0.7,Very Good,F,VS2,62.9,56,2400,5.66,5.73,3.58
0.92,Very Good,D,VS1,61.9,58,7544,6.19,6.24,3.85
2.57,Premium,J,SI1,63,58,18485,8.77,8.65,5.49
2.25,Ideal,I,SI2,60.7,56,11104,8.54,8.5,5.17
0.51,Ideal,G,VVS2,61.5,57,1875,5.13,5.18,3.17
1.05,Ideal,H,SI2,61.9,56,4504,6.49,6.56,4.04
0.3,Ideal,E,VS1,62.5,56,694,4.27,4.31,2.68
1.01,Premium,J,VS2,62.4,60,3296,6.45,6.35,3.99
</pre>
Related
Why does this D3 code not produce any output in Jupyter Notebook?
I followed this blog here and here's the code that I'm trying to run on my Jupyter Notebook - essentially a simple scatter plot from the iris dataset. from IPython.core.display import display, HTML from string import Template import pandas as pd import json, random HTML('<script src="./d3.min.js"></script>') filename = 'https://gist.githubusercontent.com/mbostock/3887118/raw/2e68ffbeb23fe4dadd9b0f6bca62e9def6ee9e17/data.tsv' iris = pd.read_csv(filename,sep="\t") iris_array_of_dicts = iris.to_dict(orient='records') css_text = ''' .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .dot { stroke: #000; } ''' js_text_template = Template(''' var margin = {top: 20, right: 20, bottom: 30, left: 40}, // **** width = 960 - margin.left - margin.right, **** // **** height = 500 - margin.top - margin.bottom; **** width = 720 - margin.left - margin.right, height = 375 - margin.top - margin.bottom; var x = d3.scale.linear() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.category10(); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); // **** var svg = d3.select("body").append("svg") **** var svg = d3.select("#$graphdiv").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.tsv("data.tsv", function(error, data) { **** // **** if (error) throw error; **** var data = $python_data ; data.forEach(function(d) { d.sepalLength = +d.sepalLength; d.sepalWidth = +d.sepalWidth; }); x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice(); y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice(); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Sepal Width (cm)"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Sepal Length (cm)") svg.selectAll(".dot") .data(data) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", function(d) { return x(d.sepalWidth); }) .attr("cy", function(d) { return y(d.sepalLength); }) .style("fill", function(d) { return color(d.species); }); var legend = svg.selectAll(".legend") .data(color.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d; }); // **** }); **** ''') html_template = Template(''' <style> $css_text </style> <div id="graph-div"></div> <script> $js_text </script> ''') js_text = js_text_template.substitute({'python_data': json.dumps(iris_array_of_dicts), 'graphdiv': 'graph-div'}) HTML(html_template.substitute({'css_text': css_text, 'js_text': js_text})) The code runs without errors but doesn't display any output. I've also tried to use the display functionality but that still produces no results. What am I doing wrong? My assumption is that since this is an old blog post, Jupyter has moved past supporting Javascript this way and I have to use cell and line magics now but I'm not sure as I'm new to Javascript.
I have just tried and figured out the problem. If you look at the console log, the browser do not interpret d3. To solve it add to your code. <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> You will now see your nice plot Here an exemple of update In [1]: from IPython.core.display import display, HTML from string import Template import pandas as pd import json, random HTML('<script src="./d3.min.js"></script>') filename = 'https://gist.githubusercontent.com/mbostock/3887118/raw/2e68ffbeb23fe4dadd9b0f6bca62e9def6ee9e17/data.tsv' iris = pd.read_csv(filename,sep="\t") iris_array_of_dicts = iris.to_dict(orient='records') css_text = ''' .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .dot { stroke: #000; } ''' js_text_template = Template(''' var margin = {top: 20, right: 20, bottom: 30, left: 40}, // **** width = 960 - margin.left - margin.right, **** // **** height = 500 - margin.top - margin.bottom; **** width = 720 - margin.left - margin.right, height = 375 - margin.top - margin.bottom; var x = d3.scale.linear() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.category10(); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); // **** var svg = d3.select("body").append("svg") **** var svg = d3.select("#$graphdiv").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.tsv("data.tsv", function(error, data) { **** // **** if (error) throw error; **** var data = $python_data ; data.forEach(function(d) { d.sepalLength = +d.sepalLength; d.sepalWidth = +d.sepalWidth; }); x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice(); y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice(); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Sepal Width (cm)"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Sepal Length (cm)") svg.selectAll(".dot") .data(data) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", function(d) { return x(d.sepalWidth); }) .attr("cy", function(d) { return y(d.sepalLength); }) .style("fill", function(d) { return color(d.species); }); var legend = svg.selectAll(".legend") .data(color.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d; }); // **** }); **** ''') html_template = Template(''' <style > $css_text </style> <div id="graph-div"></div> <script > $js_text </script> ''') js_text = js_text_template.substitute({'python_data': json.dumps(iris_array_of_dicts), 'graphdiv': 'graph-div'}) my_plot = html_template.substitute({'css_text': css_text, 'js_text': js_text}) d3_download = """ <script src="http://d3js.org/d3.v3.min.js" charset="utf-8" > </script>""" my_plot = d3_download + my_plot HTML(my_plot) Out [1]:
How to make d3-diagram visualization from json-array working?
I have a problem with a d3 visualization (bar chart) that doesn't work. Instead of loading the data from a CSV file like in the tutorials on the d3 page (https://bl.ocks.org/mbostock/3885304), I want it to load from a JSON-array. Though I'm not sure why it doesn't seem like it loads at all. Can be something when I added the time parse, or placed the x.domain(data.map(function(d) { return d.date; })); outside a CSV load data snippet. Thank you for your help! <script type="text/javascript"> var data = [{date:"1999-06-23" ,value:1},{date:"1999-06-24" ,value:2},{date:"1999-06-28" ,value:3},{date:"1999-06-29" ,value:4},{date:"1999-06-30" ,value:5}]; var parseDate = d3.timeParse("%Y-%m-%d"); data.forEach(function(d) { d.date = parseDate(d.date); d.value = +d.value; }); var xAxis = d3.axisBottom(x) .tickFormat(d3.timeFormat("%Y-%m-%d")); var yAxis = d3.axisLeft(y) .ticks(10); var svg = d3.select("#graph").append("svg") .attr("width", 956) .attr("height", 360) margin = {top: 50, right: 100, bottom: 50, left: 50}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom, g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05); var y = d3.scaleLinear().range([height, 0]); x.domain(data.map(function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.value; })]); g.selectAll("bar") .data(data) .enter().append("rect") .style("fill", "steelblue") .attr("x", function (d) { return x(d.date); }) .attr("y", function (d) { return y(d.value); }) .attr("width", x.bandwidth()) .attr("height", function(d) { return height - y(d.value); }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .selectAll("text") .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", "-.55em") .attr("transform", "rotate(-90)" ); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Value ($)"); </script> .axis { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script> <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css"> </head> <body> <script src="script.js"></script> </body> </html>
The list of the problems: Your reference to D3 is v3. However, your code uses v4. You are defining the axes generators before defining the scales. You are not translating the axes. Besides that, there is no such a thing as "JSON array". That's just an array. You probably meant hardcoded data Here is the working code: var data = [{ date: "1999-06-23", value: 1 }, { date: "1999-06-24", value: 2 }, { date: "1999-06-28", value: 3 }, { date: "1999-06-29", value: 4 }, { date: "1999-06-30", value: 5 }]; var parseDate = d3.timeParse("%Y-%m-%d"); data.forEach(function(d) { d.date = parseDate(d.date); d.value = +d.value; }); var svg = d3.select("body").append("svg") .attr("width", 956) .attr("height", 360); var margin = { top: 50, right: 100, bottom: 50, left: 50 }, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom; g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05); var y = d3.scaleLinear().range([height, 0]); x.domain(data.map(function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.value; })]); var xAxis = d3.axisBottom(x) .tickFormat(d3.timeFormat("%Y-%m-%d")); var yAxis = d3.axisLeft(y) .ticks(10); g.selectAll("bar") .data(data) .enter().append("rect") .style("fill", "steelblue") .attr("x", function(d) { return x(d.date); }) .attr("y", function(d) { return y(d.value); }) .attr("width", x.bandwidth()) .attr("height", function(d) { return height - y(d.value); }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(" + margin.left + "," + (height + margin.bottom) + ")") .call(xAxis) .selectAll("text") .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", "-.55em") .attr("transform", "rotate(-90)"); svg.append("g") .attr("class", "y axis") .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Value ($)"); <script src="https://d3js.org/d3.v4.min.js"></script>
How can I add a <g> element to my chart
I'm following a long Mike Bostocks' Let's make a Bar Chart tutorial and I'm stuck after I decided, that my bars need some text. As far as I understood it, rect cannot contain text elements, so I need to create a grouping and wrap both, text and rect in it. The problem is, that my code refuses to render the groupings (and the bars for that matter). In fact, it does not even execute the section to append a <g> element. If I throw in a console.log or alert into the callback it does never get called. Full code for reference below. The part in question is: var bar = chart.selectAll("g") .data(data) .enter().append("g") .attr("transform", function(d) { return "translate(" + x(d.letter) + "," + y(d.value) + ")"; }); Full code: var margin = { top: 20, right: 30, bottom: 30, left: 40 }, width = 960, height = 500; var x = d3.scaleBand() .rangeRound([0, width]); var y = d3.scaleLinear() .range([height, 0]); var xAxis = d3.axisBottom(x), yAxis = d3.axisLeft(y) .ticks(10, "%").tickPadding(11); var chart = d3.select(".chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.tsv("../data.tsv", type, function (err, data) { x.domain(data.map(function (d) { return d.letter; })); //set domain of scale, it is now known y.domain([0, d3.max(data, function (d) { return d.value; })]); //append the xAis chart.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + (height) + ")") .call(xAxis); chart.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Frequency"); var bar = chart.selectAll("g") .data(data) .enter().append("g") .attr("transform", function(d) { return "translate(" + x(d.letter) + "," + y(d.value) + ")"; }); bar.append("rect") .attr("height", function(d) { return height - y(d.value); }) .attr("width", x.bandwidth()); }); function type(d) { //coerce property to be number -> //find out what the difference between + and Number() is. d.value = +d.frequency; return d; } So, where did I go wrong and why?
You have two problems, the first one being a simple selection order and the second one being conceptual. The first problem is this: when you write var bar = chart.selectAll("g") for creating your groups, you're selecting groups that already exist in your SVG, which are the axes and an initial group added to the SVG. So, select something else, something that doesn't exist: var bar = chart.selectAll(".foo") Your second problem is conceptual: although you're correct about being impossible to append a text to a rect, you don't need g elements to achieve what you want. Just create a rect selection and a text selection, and append both to the SVG. But if you want to add the groups, this is what you have to do. First, in the data binding, select something that doesn't exist: var groups = chart.selectAll(".groups") .data(data) .enter() .append("g") .attr("transform", function(d) { return "translate(" + x(d.letter) + ",0)"; }); Translate only the x position of the groups, the y position of their elements will be set individually. Then, create the bars: var bar = groups.append("rect") .attr("y", function(d) { return y(d.value); }) .attr("width", x.bandwidth()) .attr("height", function(d) { return height - y(d.value); }); And finally your texts: var text = groups.append("text") .attr("y", function(d) { return y(d.value) - 6; }) .attr("x", x.bandwidth() / 2) .attr("text-anchor", "middle") .text(function(d) { return d.value }); This is a demo using your code and fake data: var data = d3.csvParse(d3.select("#csv").text()); data.forEach(function(d) { d.value = +d.value }); var margin = { top: 20, right: 30, bottom: 30, left: 40 }, width = 960, height = 500; var x = d3.scaleBand() .rangeRound([0, width]) .padding(0.3); var y = d3.scaleLinear() .range([height, 0]); var xAxis = d3.axisBottom(x), yAxis = d3.axisLeft(y) .ticks(10, "%").tickPadding(11); var chart = d3.select(".chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); x.domain(data.map(function(d) { return d.letter; })); //set domain of scale, it is now known y.domain([0, d3.max(data, function(d) { return d.value; })]); var groups = chart.selectAll(".groups") .data(data) .enter() .append("g") .attr("transform", function(d) { return "translate(" + x(d.letter) + ",0)"; }) var bar = groups.append("rect").attr("y", function(d) { return y(d.value); }) .attr("width", x.bandwidth()) .attr("height", function(d) { return height - y(d.value); }); var text = groups.append("text") .attr("y", function(d) { return y(d.value) - 6; }) .attr("x", x.bandwidth() / 2) .attr("text-anchor", "middle") .text(function(d) { return d.value }); //append the xAis chart.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + (height) + ")") .call(xAxis); chart.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Frequency"); pre { display: none; } rect { fill: teal; } <script src="https://d3js.org/d3.v4.min.js"></script> <svg class="chart"></svg> <pre id="csv">letter,value A,.08167 B,.01492 C,.02782 D,.04253 E,.12702 F,.02288 G,.02015</pre>
D3 - To add Data Labels to a simple bar chart
I know this is easy and I saw some examples in this forum as well as other websites as well, but I simple can't figure it out. I'm new in using D3 library to generate the charts. I'm trying to learn by creating bar chart. My question is how to add the Data Labels into the chart? Below is the codes I have. then I have my JS: var chartwidth = 800; var chartheight = 600; var data = [ {"Start_Dt":"Jan 15","UnitName":"Unit 1","ProgramName":"ProgramName 1","AttendCnt":159,"NewcomerCnt":10} , {"Start_Dt":"Jan 22","UnitName":"Unit 2","ProgramName":"ProgramName 2","AttendCnt":178,"NewcomerCnt":5} , {"Start_Dt":"Feb 14","UnitName":"Unit 2","ProgramName":"ProgramName 3","AttendCnt":240,"NewcomerCnt":46} , {"Start_Dt":"Feb 19","UnitName":"Unit 1","ProgramName":"ProgramName 4","AttendCnt":201,"NewcomerCnt":10} , {"Start_Dt":"Feb 26","UnitName":"Unit 2","ProgramName":"ProgramName 5","AttendCnt":177,"NewcomerCnt":7} , {"Start_Dt":"Mar 12","UnitName":"Unit N","ProgramName":"ProgramName N","AttendCnt":184,"NewcomerCnt":3} ]; var margin = {top: 20, right: 20, bottom: 300, left: 40}, width = chartwidth - margin.left - margin.right, height = chartheight - margin.top - margin.bottom; var formatPercent = d3.format(".0%"); var formatTime = d3.time.format("%e %B"); var x = d3.scale.ordinal() .rangeRoundBands([0, width], .1); var x2 = d3.scale.ordinal() .rangeBands([0, width], 0); var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); 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 + ")"); data.forEach(function(d) { d.AttendCnt = +d.AttendCnt; }); x.domain(data.map(function(d) { return d.Start_Dt + " " + d.ProgramName; })); y.domain([0, d3.max(data, function(d) { return d.AttendCnt; })]); //Create X Axis svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .selectAll("text") .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", ".15em") .attr("transform", "rotate(-65)" ) .append("text") .attr("y", 25) .attr("x",x.rangeBand()/2 ) .style("text-anchor", "middle") .style("font-size", "20px") .style("color", "black") .text(function(d,i) { return "xxx"; }); //Create Y Axis svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 0) .attr("dy", ".71em") .style("text-anchor", "end") .text("Attendance"); svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", function(d) { return x(d.Start_Dt + " " + d.ProgramName); }) .attr("width", x.rangeBand()) .attr("y", function(d) { return y(d.AttendCnt); }) .attr("height", function(d) { return height - y(d.AttendCnt); }); Before After How to modify the codes to get the result I wanted? Tks
i haven't tested the code but it could be something like this : svg.selectAll(".barText") .data(data) .enter().append("text") .attr("class", "barText") .attr("x", function(d) { return x(d.Start_Dt + " " + d.ProgramName); }) .attr("y", function(d) { return height - y(d.AttendCnt); }) .text(function(d) { return d.AttendCnt; }) ; Hope it helps
Error parsing with multiline graph in D3
I'm trying to create a multiline graph using D3, and I keep running across the same error Error: Problem parsing d="MNaN,450LNaN,0LNaN,450LNaN,450LNaN,0LNaN,0" Which seems to occur when I try to graph my line: city.append("path") .attr("class", "line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) { return color(d.name); }); I'm trying to graph a single line at the moment with the following data set: {"name":"application_active_users","values":[{"value":0,"end_time":"2013-06-14T11:00:00.000Z"},{"value":1,"end_time":"2013-06-15T11:00:00.000Z"},{"value":0,"end_time":"2013-06-16T11:00:00.000Z"},{"value":0,"end_time":"2013-06-17T11:00:00.000Z"},{"value":1,"end_time":"2013-06-18T11:00:00.000Z"},{"value":1,"end_time":"2013-06-19T11:00:00.000Z"}]} I'm assuming something is wrong with my datasource. Does anyone see an immediate issue with how my datasource is set up? Here is a portion of the D3 code. The entire code is here http://jsfiddle.net/hy4Hz/. var payload; var storedMetrics = []; var metricCount = 1; var graphData = []; var margin = { top: 20, right: 20, bottom: 30, left: 50 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; //var parseDate = d3.time.format("%Y-%m-%d").parse; //var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%SZ").parse; var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S").parse; var color = d3.scale.category10(); var x = d3.time.scale() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var line = d3.svg.line() .x(function (d) { return x(d.end_time); }) .y(function (d) { return y(d.value); }); var svg = d3.select("body").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 + ")"); x.domain(d3.extent( data, function (d) { return d.end_time; })); y.domain([ d3.min(metrics, function (c) { return d3.min(c.values, function (v) { return v.value; }); }), d3.max(metrics, function (c) { return d3.max(c.values, function (v) { return v.value; }); })]); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Temperature (ºF)"); var city = svg.selectAll(".city") .data(metrics) .enter().append("g") .attr("class", "city"); city.append("path") .attr("class", "line") .attr("d", function (d) { return line(d.values); }) .style("stroke", function (d) { return color(d.name); }); city.append("text") .datum(function (d) { return { name: d.name, value: d.values[d.values.length - 1] }; }) .attr("transform", function (d) { return "translate(" + x(d.value.end_time) + "," + y(d.value.value) + ")"; }) .attr("x", 3) .attr("dy", ".35em") .text(function (d) { return d.name; });
It looks like your x.domain() might not be set up correctly. The first argument to d3.extent should be data.values.