d3 graph duplicates on the DOM when data source changes - javascript

I am trying to create a line graph with D3. The data source will be updated on the user actions.
<svg class="line-chart"></svg>
DataSource.watch("pdg2", (data) => {
function drawChart(data) {
var svgWidth = 800, svgHeight = 400;
var margin = { top: 20, right: 20, bottom: 30, left: 50 };
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
var svg = d3.select('svg')
.attr("width", svgWidth)
.attr("height", svgHeight);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date)})
.y(function(d) { return y(d.value)})
x.domain(d3.extent(data, function(d) { return d.date }));
y.domain(d3.extent(data, function(d) { return d.value }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", -45)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("ALLOC_GAS_VOL_MMCF");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
}
drawChart(data);
});
When the data source changes, it duplicates the same graph on the previous one. I was wondering if there is a way to check axes before its pushed to the graph?
Thanks

Just add the line at start of function drawChart. It will remove all the elements inside svg.
d3.selectAll("svg > *").remove();
I have shown you where you need to write.
function drawChart(data) {
d3.selectAll("svg > *").remove();

Related

Problems with grouped bar chart

I am new to d3 and trying to make a grouped bar chart following this and this websites.
The following is my code for the scales
x0 = d3.scaleTime()
.domain([
d3.min(dataset, function(d) {return d.date;}),
d3.max(dataset, function(d) {return d.date;})
])
.range([0,w]);
x1 = d3.scaleOrdinal()
.domain([dataset.WorldPopulation, dataset.InternetUser]);
// .rangeRound([0, x0.bandwidth()]);
y = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {return d.WorldPopulation})])
.range([h,0]);
In the website above they use scaleOrdinal but I used scaleTime as x0. Therefore I'm not too sure if that works.
This is my code for the append(rect) for the bar chart
var date = svg.selectAll(".date")
.data(dataset)
.enter()
.append("g")
.attr("class", "g")
.attr("transform", function(d) {return "translate(" + x0(d.date) + ",0)";});
/* Add field1 bars */
date.selectAll(".bar.field1")
.data(d => [d])
.enter()
.append("rect")
.attr("class", "bar field1")
.style("fill","blue")
.attr("x", d => x0(d.WorldPopulation))
.attr("y", d => y(d.WorldPopulation))
.attr("width", x1.bandwidth())
.attr("height", d => {
return height - margin.top - margin.bottom - y(d.WorldPopulation)
});
/* Add field2 bars */
date.selectAll(".bar.field2")
.data(d => [d])
.enter()
.append("rect")
.attr("class", "bar field2")
.style("fill","red")
.attr("x", d => x0(d.InternetUser))
.attr("y", d => y(d.InternetUser))
.attr("width", x1.bandwidth())
.attr("height", d => {
return height - margin.top - margin.bottom - y(d.InternetUser)
});
And this is my csv file. Not too sure how to upload excel so I took a screenshot.
Any help provided will be appreciated. Feel free to request for any extra snippets of my code for clarification.
edit: After tweaking the code, no errors are shown but the svg is not produced either.
Using scaleBand for both x0 and x1, the following code works:
<script src="js/d3.v4.js"></script>
<script>
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scaleBand()
.rangeRound([0, width]).padding(.1);
var x1 = d3.scaleBand();
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(x0)
.tickSize(0);
var yAxis = d3.axisLeft()
.scale(y);
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("InternetUserStats.csv", function (error, data) {
var dates = data.map(function (d) { return d.date; });
var ymax = d3.max(data, function (d) { return Math.max(d.WorldPopulation, d.InternetUser); });
x0.domain(dates);
x1.domain(['WorldPopulations', 'InternetUsers']).rangeRound([0, x0.bandwidth()]);
y.domain([0, ymax]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var date = svg.selectAll(".g")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function (d) { return "translate(" + x0(d.date) + ",0)"; });
/* Add field1 bars */
date/*.selectAll(".bar.field1")
.data(data)
.enter()*/
.append("rect")
.attr("class", "bar field1")
.style("fill", "blue")
.attr("x", function (d) { return x1('WorldPopulations'); })
.attr("y", function (d) { return y(+d.WorldPopulation); })
.attr("width", x0.bandwidth() / 2)
.attr("height", function (d) {
return height /*- margin.top - margin.bottom*/ - y(d.WorldPopulation)
});
/* Add field2 bars */
date/*.selectAll(".bar.field1")
.data(data)
.enter()*/
.append("rect")
.attr("class", "bar field2")
.style("fill", "red")
.attr("x", function (d) { return x1('InternetUsers'); })
.attr("y", function (d) { return y(d.InternetUser); })
.attr("width", x0.bandwidth() / 2)
.attr("height", function (d) {
return height /*- margin.top - margin.bottom*/ - y(d.InternetUser)
});
});
</script>
EDIT: the following code adds a legend that is based on your comment and your second link:
//This code goes after field2 bars are added.
/* Legend */
var legend = svg.selectAll(".legend")
.data(['WorldPopulations', 'InternetUsers']) //Bind an array of the legend entries
.enter().append("g")
.attr("class", "legend")
.attr("font-family", "sans-serif")
.attr("font-size", 13)
.style("text-anchor", "end")
.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", function (d) {
// Return "blue" for "WorldPopulations" and "red" for "InternetUsers":
return ((d === "WorldPopulations") ? "blue" : "red");
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
//.style("text-anchor", "end") //Already applied to .legend
.text(function (d) { return d; });

Multiple simple graphs on one page d3.js

I am using d3.js and i am trying to display more than one graphs in the same page. Though the d3.js code is same.The one chart is from Measurements.csv and the other from m1.csv.
<!DOCTYPE html>
<svg width="1000" height="500"></svg>
<style> /* set the CSS */
.grid line {
stroke: aquamarine;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 1;
}
</style>
<style>
body {
background-color: SlateGrey;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var svg2 = d3.select("svg"),
margin = {top: 0, right: 0, bottom: 90, left: 50},
width = 950 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
g = svg2.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleLinear()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y)
.ticks(5)
}
var line = d3.line()
.x(function(d) { return x(d.frequency); })
.y(function(d) { return y(d.output); });
d3.csv("Measurements.csv", function(d) {
d.frequency = +d.frequency;
d.output = +d.output;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.frequency; }));
y.domain(d3.extent(data, function(d) { return d.output; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.attr("y", 10)
.attr("dx", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Mixer");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "aquamarine")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 4)
.attr("d", line);
// add the X gridlines
svg2.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
// add the Y gridlines
svg2.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
)
});
// set the dimensions and margins of the graph
var svg3 = d3.select("svg"),
margin = {top: 0, right: 0, bottom: 90, left: 50},
width = 950 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
g = svg2.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleLinear()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y)
.ticks(5)
}
var line = d3.line()
.x(function(d) { return x(d.frequency); })
.y(function(d) { return y(d.output); });
d3.csv("m1.csv", function(d) {
d.frequency = +d.frequency;
d.output = +d.output;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.frequency; }));
y.domain(d3.extent(data, function(d) { return d.output; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.attr("y", 10)
.attr("dx", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Mixer");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "aquamarine")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 4)
.attr("d", line);
// add the X gridlines
svg3.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
// add the Y gridlines
svg3.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
)
});
</script>
I found that have to use different variable name to hold svgs such as svg1, svg2.. etc..but the one chart is laying on the other.How to resolve this?here is the chart on the other!
Just changing this...
var svg = d3.select("svg")
... for this...
var svg2 = d3.select("svg")
... won't make any difference: the variable name is different, but the selection is the same: they are both selecting the same SVG.
Since you are not appending an SVG, but selecting an existing one, set two SVGs, each one with a unique ID....
<svg id="svg1" width="1000" height="500"></svg>
<svg id="svg2" width="1000" height="500"></svg>
... and select them accordingly:
var svg1 = d3.select("#svg1")
var svg2 = d3.select("#svg2")
PS: I'm addressing only the selection issue. For avoiding duplicated code (since you said that the code is the same), wrap the whole code in a function with two parameters: the ID of the selected SVG and the path of the CSV file. Then, you just need to call that function twice, with different arguments.

D3.js path goes in different directions in V3 vs V4

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>

D3: Add data value labels to multi line graph

I am using this multiline graph but so far have failed to generate data value labels on every tick (for every day).
<script>
var margin = {top: 30, right: 40, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%m-%y").parse;
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").ticks(7);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(7);
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sev3); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sev4); });
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 + ")");
// Get the data
d3.csv("data.tsv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.sev3 = +d.sev3;
d.sev4 = +d.sev4;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return Math.max(d.sev3, d.sev4); })]);
svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data));
svg.append("path") // Add the valueline2 path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[0].sev4) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Sev4");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[0].sev3) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Sev3");
});
</script>
Data.tsv
date,sev3,sev4
20-02-15,0,0
19-02-15,0,0
18-02-15,0,0
17-02-15,481,200
16-02-15,691,200
15-02-15,296,200
14-02-15,307,200
The code above gives this:
And THIS is what i am trying to accomplish
I understand that i must use .append("text") and position the text at about the same x,y coords as the data point and pull the value from the data to feed into the "text" but i am having difficulties in integrating that concept.
I suspect that the selection would occur with valueline.append ? I have looked at a HEAP of examples, i dont thing a linegraph with data value labels exists, if it does please point me to it :)
Any thoughts ?
Your text will not be visible, as it is located outside the boundaries of your svg: you added a group that is translated of margin.left, and the put your x at width+3, which means located at width+3+margin.left of the left border of your svg.
Try replacing your append text with something like:
svg.append("text")
.attr("transform", "translate(" + (width/2) + "," + y(data[0].sev4) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Sev4");
svg.append("text")
.attr("transform", "translate(" + (width/2) + "," + y(data[0].sev3) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Sev3");
I did not test it, so I cannot guarantee, but your code seems fine, that's the only thing I see.
Result of this add:
EDIT
After your clarifications, here is a plunk: http://plnkr.co/edit/lDlseqUQQXgoFwTK5Aop?p=preview
The part you will be interested in is:
svg.append('g')
.classed('labels-group', true)
.selectAll('text')
.data(data)
.enter()
.append('text')
.classed('label', true)
.attr({
'x': function(d, i) {
return x(d.date);
},
'y': function(d, i) {
return y(d.sev3);
}
})
.text(function(d, i) {
return d.sev3;
});
This will draw your labels. Is it the result you try to achieve?

Add text on top of bar in d3js chart -- no <text> elements added

I am creating a bar chart with d3.js from data stored in tsv file. I want to insert a text in each bar. How I can do?
I have tried even this solution, but doesn't work.
Here is the code of my function:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, 1);
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("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 + ")");
function visualize(file){
d3.tsv(file, function(error, data) {
data.forEach(function(d) {
d.weight = +d.weight;
});
x.domain(data.map(function(d) { return d.concept; }));
y.domain([0, d3.max(data, function(d) { return d.weight; })]);
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("weight");
svg.selectAll(".bar")
.data(data)
.enter().append("rect").style("fill", function (d){return d.color;})
.attr("class", "bar")
.attr("x", function(d) { return x(d.concept); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.weight); })
.attr("height", function(d) { return height - y(d.weight); });
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) {
return d.concept;
})
.attr("text-anchor", "middle")
.attr("x", x)
.attr("y",y)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
});
}
All my code with the files tsv are here: full code
AmeliaBR is right as usual, and I am only putting this answer because while I was working on it, I saw myself changing the code so that it really makes use of the Enter, Update, Exit selection paradigm. I have made quite a few changes in that regard. Here is the code, FWIW:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, 1);
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("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 + ")");
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("weight");
var g = svg.append("g");
function update(file){
d3.tsv(file, function(error, data) {
data.forEach(function(d) {
d.weight = +d.weight;
});
x.domain(data.map(function(d) { return d.concept; }));
y.domain([0, d3.max(data, function(d) { return d.weight; })]);
var bar = g.selectAll(".bar")
.data(data);
bar.enter()
.append("rect")
.attr("class","bar");
bar
.style("fill", function (d){return d.color;})
.attr("class", "bar")
.attr("x", function(d) { return x(d.concept); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.weight); })
.attr("height", function(d) { return height - y(d.weight); });
bar.exit().remove();
var text = g.selectAll(".text")
.data(data);
text.enter()
.append("text")
.attr("class","text");
text
.attr("text-anchor", "right")
.attr("x", function(d) { return x(d.concept); })
.attr("y", function(d) { return y(d.weight) + 22;})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.text(function(d) {
return d.concept;
});
text.exit().remove();
});
}
And you call it like by doing update("data16.tsv") and then update("data15.tsv").
When you draw an axis, it creates separate <text> elements for each label inside the axis group inside the SVG. So if you then try to select all the <text> elements in the SVG, you're going to select all your axis labels. If you have more axis labels than data for text elements, your enter() selection will be empty and nothing will happen.
To be sure you're only selecting the correct <text> elements, give your text labels a class to distinguish them from the axis labels. And then use that class to narrow-down your selector:
svg.selectAll("text.bar-label")
.data(data)
.enter()
.append("text")
.attr("class", "bar-label")

Categories

Resources