d3.js adding legend to multiline series chart
Here is a fixed & refactored version of your code.
var legend = svg.selectAll('g')
.data(cities)
.enter()
.append('g')
.attr('class', 'legend');
legend.append('rect')
.attr('x', width - 20)
.attr('y', function(d, i){ return i * 20;})
.attr('width', 10)
.attr('height', 10)
.style('fill', function(d) {
return color(d.name);
});
legend.append('text')
.attr('x', width - 8)
.attr('y', function(d, i){ return (i * 20) + 9;})
.text(function(d){ return d.name; });
You need to use enter()
, but enter()
and exit()
methods cannot be used with datum()
. Quoting from the d3 wiki
selection.datum([value])
Gets or sets the bound data for each selected element. Unlike the selection.data method, this method does not compute a join (and thus does not compute enter and exit selections).
CQM
Updated on July 19, 2022Comments
-
CQM almost 2 years
How would one add a legend to the multiline series chart? I tried but am not getting any legend to display.
The block here:
has a flaw when the various series converge to the same point, like zero. All the labels will be overlayed on each other. Instead of going for these labels, a traditional legend would be useful.
I tried adding this
var legend = svg.append("g") .attr("class", "legend") .attr("height", 100) .attr("width", 100) .attr('transform', 'translate(-20,50)'); legend.selectAll('rect') .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) .append("rect") .attr("x", width) .attr("y", function(d, i){ return i * 20;}) .attr("width", 10) .attr("height", 10) .style("fill", function(d) { return color.domain(d3.keys(d[0]).filter(function(key) { return key !== "day"; })); }); legend.selectAll('text') .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) .append("text") .attr("x", width) .attr("y", function(d, i){ return i * 20 + 9;}) .text(function(d) { return d.name; });
to the end of the code, the key names (d.name) match how my data is formatted, but it does not display. At one point it showed all black boxes to the right of the graph so that means I am close but I am missing something important
any insight appreciated
-
CQM over 11 yearshm, I find some discrepancies with that logic, in the example graph
city
variable in some places start off with.append("text")
then.datum(...)
with noenter()
after that, but just attribute modifying. Also, when I did addenter()
my console said object has noenter()
and gave an error -
Alex_B over 11 yearsI could be wrong but i think the confusion comes from the fact (if i am reading this correctly) .datum() adds/changes the value to an existing element in your selection. In your code where you state "legend.selectAll('rect')" none exist and to create the initial join you would need to use ".data(data).enter()" to create new "rect" elements.
-
Alex_B over 11 yearshere's a good answer to the question about .data and .datum stackoverflow.com/questions/13181194/…
-
theUser about 10 yearsI addded a dot and your code worked for me. var legend = svg.selectAll('.g')