I've got a legend, with colored rectangles...
I'd like to replace the rectangles with symbols (i.e., circle, cross, diamond, square). I can't figure out how to do that.
I've been using variations of .attr("d", d3.svg.symbol().type('circle'). For instance, I tried:
legendRect
.attr("d", d3.svg.symbol().type(function (d) { return d[2] })
and I tried:
legendRect.append("svg:path")
.attr("d", d3.svg.symbol().type((d: any) => { return d[2] }))
d[2] is "supposed to be" pulling from legendData, as shown in the below code example...like it does with d[1] for the fill.
But I don't ever see anything change.
Here's the code I'm using for the legend, without the symbol stuff, below. What am I doing wrong and how can I change the rectangles to symbols? Where do I need to add what?
var legendData = [["OA", "yellow", "circle"], ["OI", "blue", "cross"], ["RARC", "green", "diamond"], ["CAPE", "red", "square"], ["Other", "black", "triangleDown"]];
var legend = this.svg.append("g")
.attr("class", "legend")
.attr("height", 0)
.attr("width", 0)
.attr('transform', 'translate(-20,250)');
var legendRect = legend.selectAll('rect').data(legendData);
legendRect.enter()
.append("rect")
.attr("x", width - 65)
.attr("width", 10)
.attr("height", 10)
;
legendRect
.attr("y", function (d, i) {
return i * 20;
})
.style("fill", function (d) {
return d[1];
})
var legendText = legend.selectAll('text').data(legendData);
legendText.enter()
.append("text")
.attr("x", width - 52);
legendText
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d[0];
});
Here's how I would code it. Notice, that I data-bind to a wrapper g element and then place the symbol and text into it for each legend item. You can then position the g instead of positioning the text and "symbol" separately. This also removes the need for double-binding the data.
var legendData = [["OA", "yellow", "circle"], ["OI", "blue", "cross"], ["RARC", "green", "diamond"], ["CAPE", "red", "square"], ["Other", "black", "triangleDown"]];
var svg = d3.select('body').append('svg').attr('width', 500).attr('height', 500);
var legend = svg.append('g')
.attr("class", "legend")
.attr("height", 0)
.attr("width", 0)
.attr('transform', 'translate(20,20)');
var legendRect = legend
.selectAll('g')
.data(legendData);
var legendRectE = legendRect.enter()
.append("g")
.attr("transform", function(d,i){
return 'translate(0, ' + (i * 20) + ')';
});
legendRectE
.append('path')
.attr("d", d3.svg.symbol().type((d) => { return d[2] }))
.style("fill", function (d) {
return d[1];
});
legendRectE
.append("text")
.attr("x", 10)
.attr("y", 5)
.text(function (d) {
return d[0];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
This is a implementation which uses symbols for your legend. You can use the symbols like the following:
svg.selectAll('.symbol')
.data(legendData)
.enter()
.append('path')
.attr('transform', function(d, i) {
return 'translate(' + (20) + ',' + ((i * 20) + 10) + ')';
})
.attr('d', d3.symbol().type(function(d, i) {
if (d[2] === "circle") {
return d3.symbolCircle;
} else if (d[2] === "cross") {
return d3.symbolCross;
} else if (d[2] === "diamond") {
return d3.symbolDiamond;
} else if (d[2] === "square") {
return d3.symbolSquare;
} else {
return d3.symbolTriangle;
}
})
.size(100))
.style("fill", function(d) {
return d[1];
});
Then you can set your legend labels like the following:
svg.selectAll('.label')
.data(legendData)
.enter()
.append('text')
.attr("x", "40")
.attr("y", function(d, i){ return ((i * 20)+15);})
.text(function(d) {
return d[0];
});
Check fiddle here - https://jsfiddle.net/zoxckLe3/
P.S. - Above solution uses d3 v4. To achieve the same in v3, use the following line .attr('d', d3.svg.symbol().type(function(d){return d[2];})) instead of the part where I match d[2] to the symbol name.
For adding image icons, you can use below code.
legend.append("**image**")
.attr("x", 890)
.attr("y", 70)
.attr("width", 20)
.attr("height", 18)
.attr("xlink:href",function (d) {
**return "../assets/images/dev/"+d+".png";**
})
This works for me..
I am trying to visualize a dataset to see major players in the pangolin trade. I want each country to be part of a categorical scale on the y-axis, and the x-axis is the date, and I want each trade instance to be represented as a circle, with x being the date it happened, y being the position for that particular country, and r being the number of instances accumulated so far (represented in my data as r). Basically my data is from 2010 to 2016, and includes the country name where pangolins are either imported to or exported from, the count (accumulated trade instances up until this date), and the date (yyyy-mm-dd).
Below is part of my data, which I store in the variable trade:
[{"date":"2010-10-22","country":"Thailand","rank":4,"count":1},{"date":"2010-10-28","country":"Malaysia","rank":2,"count":1},{"date":"2010-11-8","country":"Thailand","rank":4,"count":2},{"date":"2010-11-18","country":"Nepal","rank":7,"count":1},{"date":"2010-11-22","country":"China","rank":5,"count":1},{"date":"2010-11-22","country":"China","rank":5,"count":2},{"date":"2010-11-27","country":"India","rank":1,"count":1},{"date":"2010-11-28","country":"India","rank":1,"count":2},{"date":"2010-11-28","country":"India","rank":1,"count":3},{"date":"2010-11-30","country":"India","rank":1,"count":4},{"date":"2010-12-17","country":"Malaysia","rank":2,"count":2},{"date":"2010-12-22","country":"Vietnam","rank":3,"count":1},{"date":"2011-01-3","country":"Nepal","rank":7,"count":2},{"date":"2011-02-12","country":"Myanmar","rank":8,"count":1},{"date":"2011-02-25","country":"Malaysia","rank":2,"count":3},{"date":"2011-02-26","country":"Malaysia","rank":2,"count":4},{"date":"2011-03-2","country":"South Africa","rank":18,"count":1},{"date":"2011-03-2","country":"Rwanda","rank":35,"count":1},{"date":"2011-03-2","country":"Mozambique","rank":22,"count":1},{"date":"2011-03-2","country":"Kenya","rank":12,"count":1},{"date":"2011-03-3","country":"China","rank":5,"count":3},{"date":"2011-02-21","country":"Vietnam","rank":3,"count":2},{"date":"2011-03-24","country":"Malaysia","rank":2,"count":5},{"date":"2011-04-4","country":"Malaysia","rank":2,"count":6},{"date":"2011-03-25","country":"India","rank":1,"count":5},{"date":"2011-03-26","country":"Malaysia","rank":2,"count":7},{"date":"2011-04-2","country":"Nepal","rank":7,"count":3},{"date":"2011-04-20","country":"Thailand","rank":4,"count":3},{"date":"2011-05-11","country":"China","rank":5,"count":4},{"date":"2011-05-11","country":"China","rank":5,"count":5},{"date":"2011-05-26","country":"Indonesia","rank":6,"count":1},{"date":"2011-05-26","country":"India","rank":1,"count":6},{"date":"2011-05-29","country":"Indonesia","rank":6,"count":2},{"date":"2011-06-6","country":"India","rank":1,"count":7},{"date":"2011-06-7","country":"Mozambique","rank":22,"count":2},{"date":"2011-06-5","country":"India","rank":1,"count":8},{"date":"2011-06-12","country":"Malaysia","rank":2,"count":8},{"date":"2011-06-13","country":"Singapore","rank":21,"count":1},{"date":"2011-06-14","country":"Malaysia","rank":2,"count":9},{"date":"2011-06-17","country":"India","rank":1,"count":9},{"date":"2011-06-19","country":"India","rank":1,"count":10},{"date":"2011-06-26","country":"Thailand","rank":4,"count":4},{"date":"2011-06-30","country":"India","rank":1,"count":11},{"date":"2011-07-4","country":"Malaysia","rank":2,"count":10},{"date":"2011-07-5","country":"Zimbabwe","rank":14,"count":1},{"date":"2011-07-12","country":"Indonesia","rank":6,"count":3},{"date":"2011-07-18","country":"Indonesia","rank":6,"count":4},{"date":"2011-07-27","country":"Nepal","rank":7,"count":4},{"date":"2011-08-16","country":"Nepal","rank":7,"count":5},{"date":"2011-08-19","country":"Namibia","rank":33,"count":1},{"date":"2011-08-23","country":"India","rank":1,"count":12},{"date":"2010-09-17","country":"Myanmar","rank":8,"count":2},{"date":"2011-09-1","country":"Zimbabwe","rank":14,"count":2},{"date":"2011-09-13","country":"Indonesia","rank":6,"count":5},{"date":"2011-09-13","country":"Malaysia","rank":2,"count":11},{"date":"2011-09-13","country":"Myanmar","rank":8,"count":3},{"date":"2011-09-21","country":"Malaysia","rank":2,"count":12},{"date":"2011-09-26","country":"Thailand","rank":4,"count":5},{"date":"2011-09-30","country":"Indonesia","rank":6,"count":6},{"date":"2011-10-1","country":"Sri Lanka","rank":19,"count":1},{"date":"2011-10-6","country":"India","rank":1,"count":13},{"date":"2011-10-7","country":"India","rank":1,"count":14},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":7},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":8},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":9},{"date":"2011-10-22","country":"India","rank":1,"count":15},{"date":"2011-10-24","country":"India","rank":1,"count":16},{"date":"2011-11-28","country":"United States","rank":32,"count":1},{"date":"2011-12-15","country":"Vietnam","rank":3,"count":3},{"date":"2011-12-27","country":"Thailand","rank":4,"count":6},{"date":"2012-01-4","country":"Philippines","rank":15,"count":1},{"date":"2012-01-5","country":"Kenya","rank":12,"count":2},{"date":"2012-01-6","country":"Philippines","rank":15,"count":2},{"date":"2012-01-17","country":"Philippines","rank":15,"count":3},{"date":"2012-01-24","country":"China","rank":5,"count":6},{"date":"2012-02-22","country":"Malaysia","rank":2,"count":13},{"date":"2012-03-1","country":"Malaysia","rank":2,"count":14},{"date":"2012-03-19","country":"Pakistan","rank":11,"count":1},{"date":"2012-03-21","country":"Malaysia","rank":2,"count":15},{"date":"2012-03-23","country":"Vietnam","rank":3,"count":4},{"date":"2012-04-27","country":"Vietnam","rank":3,"count":5},{"date":"2012-04-23","country":"Belgium","rank":31,"count":1},{"date":"2012-06-7","country":"Thailand","rank":4,"count":7},{"date":"2012-06-7","country":"Thailand","rank":4,"count":8}];
and here is my code:
var margin = {left:120, top:20, right:0, bottom:50};
var width = 1000;
var height = 800;
var data=trade;
var tradeByCountry = d3.nest()
.key(function(d) { return d.country; })
.entries(trade);
console.log(tradeByCountry);
tradeByCountry.forEach(function(country){
country['number']=country.values.length;
console.log(country);
});
var country_colors = ["#393b79","#5254a3", '#6b6ecf', '#9c9ede', '#637939', '#8ca252','#b5cf6b','#cedb9c',
'#8c6d31','#bd9e39','#e7ba52','#e7cb94','#843c39','#ad494a','#d6616b','#e7969c','#7b4173','#a55194',
'#ce6dbd','#de9ed6', '#9467bd', '#c5b0d5','#3182bd', '#6baed6','#17becf','#9edae5','#e6550d','#fd8d3c','#fdae6b',
'#31a354','#74c476','#a1d99b','#d62728','#ff9896','#7f7f7f','#c7c7c7'];
var colors = d3.scale.ordinal()
.domain(d3.range(tradeByCountry.length))
.range(country_colors);
tradeByCountry.sort(function(x, y){
return d3.descending(x.number, y.number);
})
var countriesArray = [];
tradeByCountry.forEach(function(country){
countriesArray.push(country.key);
});
console.log(countriesArray);
var x = d3.time.scale()
.rangeRound([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var timeFormat = d3.time.format("%Y-%m-%d");
x.domain([timeFormat.parse('2010-10-22'),timeFormat.parse('2016-12-30')]);
y.domain(countriesArray);
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)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("date");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "translate(35,-25)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("countries");
svg.selectAll(".dot")
.data(tradeByCountry)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 7)
.attr("cx", function(d) { return 0; })
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("fill", function(d,i) { return colors(i); });
svg.selectAll("text.labels")
.data(tradeByCountry)
.enter()
.append("text")
.text(function(d) {return d.key})
.attr("x", 0)
.attr("y", function(d,i) { return (height/tradeByCountry.length)*i; })
.attr("transform", "translate(-120,5)")
.attr("fill",function(d,i) { return colors(i); });
svg.selectAll('.line')
.data(tradeByCountry)
.enter().append('line')
.attr("x1", 0) // x position of the first end of the line
.attr("y1",function(d,i) { return (height/tradeByCountry.length)*i; })
.attr("x2", width) // x position of the second end of the line
.attr("y2", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("stroke",function(d,i) { return colors(i); })
.attr("id", function(d){return d.key});
//PROBLEM HERE!!!!!!!!!!!
var g = svg
.selectAll("g")
.data(tradeByCountry)
.enter().append("g")
.selectAll(".dot")
.data(function(d) {return d.values;})
.enter().append("circle")
.attr("id", function(d){ return d.count;})
.attr("r", function(d){return d.count;})
.attr("cx", function(d,i) { console.log (d.date);return (x(timeFormat.parse(d.date))); })
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("fill", function(d,i) { return colors(i); });
I am having trouble specifically at the very last part of my code, where I can't get all the circles to draw and not in the correct r, as I would like r to increase as the trade accumulates over time for a country, instead it seems that r is different according to country:
Two things, firstly in your example .selectAll("g") at the point you mark as having the error was picking up g elements in the axes, so the first few countries weren't getting their data displayed. This doesn't appear to be the case in your screenshot but it was happening given the code you posted, so I just qualified those gs with the .country class.
The second thing, and what was causing your specific problem was this line:
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
I'm guessing you thought the index variable i here was still tied to the tradeByCountry array, which it would have been after selectAll("g.country").data(tradebyCountry) but at this point we've now made a nested selection .selectAll(".dot") on d.values for each country's data so i is now indexing those list of values. So that line of code above will take the values for each country and separate them all vertically, always starting from the top row - when in fact you want them on the same line, just separated by country.
What you wanted (I = India, M = Malaysia, T = Thailand)
I--- I0 I1 I2
M--- M0M1 M2
T--- T0 T1 T2
What you were getting
I--- I0 M0 T0
M--- M1 I1 T1
T--- I2 T2 M2
This was also hidden by the fact .attr("fill") also had the same mistake so the colours on each row were consistent (I've used d.rank instead to fix it).
Solution 1: To make sure the values stay on the same correct line use i before you do the nested selection so it still refers to the countries like this, which will offset each g element by the correct amount:
.attr("transform", function(d,i) {
return "translate(0,"+(height/tradeByCountry.length)*i+")";
})
and simply set cy to be zero for everything you add to this g element and they'll all be in a straight line (and on the right line)
Full code at the PROBLEM HERE! stage:
var g = svg
.selectAll("g.country")
.data(tradeByCountry)
.enter().append("g")
.attr("class", "country")
.attr("transform", function(d,i) {
return "translate(0,"+(height/tradeByCountry.length)*i+")";
})
.selectAll(".dot")
.data(function(d) {return d.values;})
.enter().append("circle")
.attr("class", "dot")
.attr("id", function(d){ return d.country+"_"+d.date+"_"+d.count;})
.attr("r", function(d){ return d.count;})
.attr("cx", function(d,i) { console.log (d.date);return (x(timeFormat.parse(d.date))); })
.attr("cy", function(d,i) { return 0; })
.style("fill", function(d,i) { return colors(d.rank); });
http://jsfiddle.net/d4typ567/1/
Solution 2: It's also the case that d3 maintains a parent index variable for nested selections (usually denoted ii) that can be passed into most d3 .attr and .style functions, so you could do .attr("cy", function(d,i, ii) { return (height/tradeByCountry.length)*ii; }) instead, but offsetting the g element is only 1 operation whereas this is done for every circle. Remember to do the same for the color (fill) function.
I'm having a go at my first line chart in d3.js and would like to draw the path between the data points gradually, but also display each data point as a solid circle.
I have already got this working, but what I would really like to try and do is show each circle appear as the line hits each data point.
Right now the data points appear first and then the line path is drawn between them as per this snippet of my code:
var path = g.append("svg:path")
.attr("d", line(data));
var totalLength = path.node().getTotalLength();
console.log(totalLength);
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
Working example - http://codepen.io/anon/pen/JYqPvZ
Is what I'm trying to achieve possible?
Thanks
You could write a custom tween function:
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
// custom tween
.tween("line", function() {
// set up an interp function
var interp = d3.interpolateNumber(totalLength, 0);
var self = d3.select(this);
// this is called on each animation frame
return function(t) {
// calculate offset and apply it
var offset = interp(t);
self.attr("stroke-dashoffset", offset);
// calculate current x position of line
var xPos = this.getPointAtLength(totalLength - offset).x;
// for each point see if we can "show" the circle
g.selectAll(".point").each(function(){
var point = d3.select(this);
if (xPos > (+point.attr('cx'))){
point.style('opacity',1);
}
})
};
});
Working code:
var data = [3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 7],
w = 600,
h = 400,
margin = 20,
y = d3.scale.linear().domain([0, d3.max(data)]).range([0 + margin, h - margin]),
x = d3.scale.linear().domain([0, data.length]).range([0 + margin, w - margin]);
var vis = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
var g = vis.append("svg:g")
.attr("transform", "translate(0, 400)");
var line = d3.svg.line()
//.interpolate("cardinal")
.x(function(d,i) { return x(i); })
.y(function(d) { return -1 * y(d); });
var path = g.append("svg:path")
.attr("d", line(data));
var totalLength = path.node().getTotalLength();
console.log(totalLength);
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.tween("line", function() {
var interp = d3.interpolateNumber(totalLength, 0);
var self = d3.select(this);
return function(t) {
var offset = interp(t);
self.attr("stroke-dashoffset", offset);
var xPos = this.getPointAtLength(totalLength - offset).x;
g.selectAll(".point").each(function(){
var point = d3.select(this);
if (xPos > (+point.attr('cx'))){
point.style('opacity',1);
}
})
};
});
g.append("svg:line")
.attr("x1", x(0))
.attr("y1", -1 * y(0))
.attr("x2", x(w))
.attr("y2", -1 * y(0))
g.append("svg:line")
.attr("x1", x(0))
.attr("y1", -1 * y(0))
.attr("x2", x(0))
.attr("y2", -1 * y(d3.max(data)));
g.selectAll(".xLabel")
.data(x.ticks(5))
.enter().append("svg:text")
.attr("class", "xLabel")
.text(String)
.attr("x", function(d) { return x(d) })
.attr("y", 0)
.attr("text-anchor", "middle")
g.selectAll(".yLabel")
.data(y.ticks(4))
.enter().append("svg:text")
.attr("class", "yLabel")
.text(String)
.attr("x", 0)
.attr("y", function(d) { return -1 * y(d) })
.attr("text-anchor", "right")
.attr("dy", 4)
g.selectAll(".xTicks")
.data(x.ticks(5))
.enter().append("svg:line")
.attr("class", "xTicks")
.attr("x1", function(d) { return x(d); })
.attr("y1", -1 * y(0))
.attr("x2", function(d) { return x(d); })
.attr("y2", -1 * y(-0.3))
g.selectAll(".yTicks")
.data(y.ticks(4))
.enter().append("svg:line")
.attr("class", "yTicks")
.attr("y1", function(d) { return -1 * y(d); })
.attr("x1", x(-0.3))
.attr("y2", function(d) { return -1 * y(d); })
.attr("x2", x(0))
var points = g.selectAll(".point")
.data(data)
.enter().append("svg:circle")
.attr("class","point")
.attr("stroke", "steelblue")
.attr("fill", function(d, i) { return "steelblue" })
.attr("cx", function(d, i) { return x(i); })
.attr("cy", function(d, i) { return -1 * y(d); })
.attr("r", function(d, i) { return 5 })
.style("opacity", 0)
.on('click', function(p){
console.log('clicked! - ' + p );
})
.on("mouseover", function(d) {
d3.select(this).attr("r", 8).style("fill", "red").attr("stroke", "red");
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 5).style("fill", "steelblue").attr("stroke", "steelblue");
});
var val = points.append('g');
val.selectAll('text')
.data(function(d,i){ return d.values})
.enter().append('text')
.attr("x", function(d, i) {
return x(i) + x.rangeBand() / 2;})
.attr("y", function(d, i) { return y(d.value) })
.attr('dy', -10)
.attr("text-anchor", "middle")
.text(function(d) { return d.value; })
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
line {
stroke: black;
}
text {
font-family: Arial;
font-size: 9pt;
}
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
I've been drawing a planetarium with planets and labels on it :
svg.append("circle").attr("r", 20).attr("cx", w/2)
.attr("cy", h/2).attr("class", "sun");
svg.append("text").attr("x", w/2)
.attr("y", h/2).attr("text-anchor", "middle").attr("fill", "grey").text("VICTOR HUGO");
var container = svg.append("g")
.attr("transform", "translate(" + w/2 + "," + h/2 + ")")
var orbit = container.selectAll(".orbit")
.data(dataset, key)
.enter()
.append("circle")
.attr("class", "orbit")
.attr("r", 0);
//function(d) {return (d.key * ((w/2)/151) + 20); });
var planets = container.selectAll(".planet")
.data(dataset, key)
.enter()
.append("circle")
.attr("class", "planet")
.attr("r", function(d) {return 5;})
.attr("cx", function(d) {return d.x; })
.attr("cy", function(d) {return d.y; })
.on("mouseover", function(d, i) {
stopTooltip = false
showTooltip(d);
});
d3.select("svg").on("click", function(d) {stopTooltip = true;});
var texts = container.selectAll(".text")
.data(dataset, key)
.enter()
.append("text")
.attr("class", "text")
.attr("dx", function(d) {return d.x;})
.attr("dy", ".35em")
.text(function(d) {return d.titre});
Then, I've been adding a legend and a click function, so that when you click on one or another of the legend subtitle, the dataset is updated (if you look at the tooltips, it is indeed updated).
////////////////////////Legend//////////////////////////////////
update = function(newDataset, key){
var newplanets = container.selectAll(".planet").data(newDataset, key);
newplanets.enter().append("circle");
newplanets.transition()
.duration(0)
.attr("r", function(d) {return 5;})
.attr("cx", function(d) {return d.x; })
.attr("cy", function(d) {return d.y; })
.on("mouseover", function(d, i) {
stopTooltip = false
showTooltip(d);
});
newplanets.exit().remove();
var newtexts = container.selectAll(".text").data(newDataset, key);
newtexts.enter().append("text");
newtexts.transition()
.duration(0)
.attr("class", "text")
.attr("dx", function(d) {return d.x;})
.attr("dy", ".35em")
.text(function(d) {return d.titre});
newtexts.exit().remove();
}
var legendRectSize = 7;
var legendSpacing = 20;
var VictorHugoClass = [
{ "VHClassName": '...Auteur (oeuvre)', "VHClass": r990o, "color": "#0000FF" },
{ "VHClassName": '...Auteur (expression)', "VHClass": r990e, "color": "#FBA10D" },
];
//Initiate container around Legend
var legendContainer = svg.append("g").attr("class","legendContainer")
.attr("transform", "translate(" + 30 + "," + (h - 90) + ")");
//Create title of Legend
var legendTitle = legendContainer.append('text')
.attr('x', 0)
.attr('y', legendRectSize - legendSpacing)
.attr("dy", "1em")
.attr('class', 'legendTitle')
.attr('transform', function() {
var height = legendRectSize + legendSpacing;
var offset = height * VictorHugoClass.length / 2;
var horz = -2 * legendRectSize;
var vert = -2.3 * height - offset;
return 'translate(' + horz + ',' + vert + ')';
})
.attr("fill", "black")
.text("Victor Hugo en tant que...")
.call(wrap, 200);
//Create container per circle/text pair
var legend = legendContainer
.selectAll('.legend')
.data(VictorHugoClass)
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * VictorHugoClass.length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
})
.on("click", function(d) {
update(d.VHClass, d.key);
});
//Append circles to Legend
legend.append('circle')
.attr('r', legendRectSize)
.attr('cx', 4)
.attr('cy', legendRectSize/2 - legendSpacing)
.attr("opacity", 1)
.style("fill", "white")
.style('stroke', function(d) {return d.color;});
//Append text to Legend
legend.append('text')
.attr('x', legendRectSize + legendSpacing/2)
.attr('y', legendRectSize - legendSpacing)
.attr("fill", "black")
.text(function(d) { return d.VHClassName; });
Nevertheless, the labels won't update with the planets, and some of the data of the former dataset are still remaining when the second dataset is loaded into the visualization. My Plunker is here for more details : http://plnkr.co/edit/UnhqCZhME7ymxdIbpcIj?p=preview
Thank you very much for your help in this...