How to remove a paticular legend in D3 - d3.js

svgData = svg.select('g.data').selectAll('g.datum').data data, (d)-> d.key
newData = svgData.enter()
.append 'g'
.classed 'datum', true
legends = newData.append 'g'
.classed 'legend-entry', true
.attr 'opacity', 1
.on 'click', hidden.toggle
legends.append 'circle'
.attr 'r', 2
.attr 'cx', 1
.attr 'stroke-width', 1
.attr 'fill', (d)-> scales.color(d.key)
.attr 'stroke', (d)-> scales.color(d.key)
legends.append 'text'
.attr 'x', 5
.attr 'y', 2.5
.attr 'font-size', 7
.text (d)-> d.key
legends = svg.selectAll('g.legend-entry') #separate selection to get both old and new for positioning <br/>
Here svgData is the old data which is appearing on the legend and newData is data which I'm going to append to the legend. Before appending the newData I want to remove a few legends. The data which I want to remove from legends is stored in a variable say removeLegend. I want to remove all these legends before append data from newdata. Any Help would be appreciated. Thanks

Where are the parentheses?
You just need to follow the selection binding schedule: update, enter and exit.
update: binding data and comparing
enter: if there are more data than legend items create new items
exit: if there are less data than legend items, then remove the old items(this is exactly you want).
This is the Mike Bostock's tutorial in detail.

Related

d3.selectAll get the style fill value of map's path

I am trying to get the colour from the path but it gives me initially assigned colour. Initially, I filled the whole path with yellow colour(see below code):
# Line 566:
india.selectAll("path")
.data(fixed)
.enter().append("path")
.attr("d", path)
.style("fill", "#ffffd9")
but using the following code I assigned them diff. colour based on value:
# Line 620:
india.selectAll("path").transition().duration(1000)
.style("fill", function (d) {
// log("=======>",d, d.confirmed);
return colormap(d.properties.confirmed); });
This is what I have tried:
# Line 642:
rects = india.selectAll('path');
// clear previous selection
// rects.style({'stroke': 'none', 'stroke-width': '1px'});
// loop and hightlight matches
rects.each(function(){
var r = d3.select(this);
log("-----======--------", r._groups[0][0]);
log("!!!!!!!!!:",r._groups[0][0].style.cssText);
log("-->==>",r._groups[0][0].path);
log("#####:", r.style('fill'), hexToRGB('#fdedec'));
log("######:", (r.style('fill')===hexToRGB('#fdedec')));
// if (r.style('fill') === self.style('fill')){
// r.style({'stroke': 'red', 'stroke-width': '2px'});
});
But it gives me initially assigned colour(yellow), not the changed ones(shades of red). How to do it?
Code + demo:
https://plnkr.co/edit/4tsSOBuNhi418Pt5?open=lib%2Fscript.js

Heatmap and sparklines

I created an heatmap using this example and this data:
NAME,YEAR,M1,M2
A,2000,20,5
B,2000,30,1
C,2000,,10
D,2000,,88
E,2000,,21
F,2000,84,3
G,2000,,64
A,2001,44,48
B,2001,15,51
C,2001,20,5
D,2001,95,2
E,2001,82,9
F,2001,,77
G,2001,3,80
A,2002,8,99
B,2002,92,52
C,2002,62,
D,2002,41,
E,2002,66,
F,2002,21,21
G,2002,62,4
A,2003,2,5
B,2003,89,78
C,2003,9,
D,2003,7,9
E,2003,2,45
F,2003,92,58
G,2003,2,14
A,2004,2,55
B,2004,89,58
C,2004,9,55
D,2004,7,59
E,2004,2,70
F,2004,92,
G,2004,2,
Now I would like to add to the right of the heatmap a sparkline for each row, so there must be a sparkline associated with A, to B, etc.
And I wish they were positioned right next to each other.
To make the sparklines I saw this example.
This is the result: PLUNKER.
As you can see, I can't get the data correctly from the data.csv file to create the sparklines. Also I don't know how to place them in the correct position.
I tried this way but without success.
var sparkSvg = d3.select("#container-sparkline")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.data(dataNest)
.enter()
.append("path")
.attr("class", "sparkline-path")
.attr("d", function(d) {
console.log("i");
console.log(d);
});
Also I'm not sure using two div is the correct way to put a chart near another chart.
Anyone would know how to help me?
Approach:
I've created a sparkline for every name in data set with values on x axis as a year and y as a m2 value from data set. For the demo purposes I've hardcoded number of years to 5 so x axis have only 5 values, but that can be computed with some additional script based on input data.
I've also added tome padding for sparkline container so they're aligned with the heatmap
Code:
As you can see in the plunker I've introduced a function to group data by name, so for each name we have an array with objects:
var groupBy = function(array, key) {
return array.reduce(function(a, v) {
(a[v[key]] = a[v[key]] || []).push(v);
return a;
}, {});
};
// data grouped by name
var groupedData = groupBy(data, 'name');
Since we assumed for demo purposes that X axis has fixed number of values we need to find max value for Y axis to properly scale charts. To do that I reduce array of values to get only m2 values and find a max number whthin that array:
var maxYvalue = Math.max(...data.map(function(d){return Number(d.m2)}));
Now we can create scales for the sparklines
var x = d3.scaleLinear().domain([0, 4]).range([0, 60]);
var y = d3.scaleLinear().domain([0, maxYvalue]).range([2, itemSize-2 ]);
I'm assuming that chart have width of 60px and height of itemSize, I also introduce 2px of vertical padding so its easier to read those sparklines being on next to each-other.
Now we can define d3.line(as you already did in your plunker) which we'll use fro rendering sparklines .
var line = d3.line()
.x(function(d, i) { return x(i); })
.y(function(d) { return y(d); })
And last step is to render sparklines inside "#container-sparkline" container. To do that we can iterate over every array in groupedData and render sparkline for each name:
// for each name render sparkline
Object.keys(groupedData).forEach(function(key){
const sparkData = groupedData[key].map(function(datum){
return Number(datum['m2']);
})
var sparkSvg = d3.select("#container-sparkline")
.append("svg")
.attr("width", "100%")
.attr("height", itemSize-1)
.append("path")
.attr("class", "sparkline-path")
.attr("d", line(sparkData));
})
I've also slightly changed styles for #container-sparkline and added borders for sparkline svg's. I hope this is what you've asked for.
Here you can find your plunker with my changes
http://plnkr.co/edit/9vUFI76Ghieq4yZID5B7?p=preview

dc.js Can a Pie Legend be recentered after filtering

I would like to be able to recenter a Pie charts legend after it has been filtered. Slices/Legends will removed when filtering because we remove empty bins. I added a pretransition listener to chart2, but that seems to be to late because the legend y value is the previous value and not current.
.on('pretransition', chart => buildLegend (chart))
If Male is selected on the Gender Pie chart I want the 4 legend items on the Job Pie chart to be re-centered. Any suggestions?
You can see a jsFiddle example.
A little more digging around showed me how to reference and update SVG elements.
function recenterLegend(chart) {
chart.selectAll('g.dc-legend')
.attr('transform', function(d) {
let legendY = (300 - (chart.group().all().length * 16)) / 2;
let translate = 'translate(220,' + legendY + ')';
return translate ;
});
}
Here is the updated jsfiddle.

D3 stacked bar chart: unique bar for each row (stack only one row)

I'm quite new to D3 and I'm trying to make a stacked bar chart (or column chart) with unique bars for each row (each observation) in the dataset.
The problem I have encountered is: if there's more than one row with the same value used for the y axes (in my case, in data.csv, in the column "seq", "3" and "4" appear twice), then all data with the same name (from different rows) will be stacked together like this:
data.csv
seq,Idle Time,Answer Time
2,95,4
1,0,3
3,22,3
4,0,4
6,43,3
5,0,2
8,30,1
7,0,3
4,20,5
3,0,8
But what I'm trying to do is to make one bar for each row, despite the identical values of d.seq (so that there will be two bars for d.seq=3 and d.seq=4)
The full code I am working on now is here
Any suggestions will be appreciated, thanks!
You can plot based on the index of your data array, rather than on the "seq" value. The index will be unique. http://plnkr.co/edit/vtsfWSB7etegM9VfI6mM?p=preview
I've just updated two lines
line 86:
y.domain(data.map(function(d, i) { return i; }));
line 112:
.attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; });
If you still want the y-tick label to show the value in "seq", have a look here where you can find out more about axes and how to apply custom labels:
https://github.com/mbostock/d3/wiki/SVG-Axes
EDIT
http://plnkr.co/edit/6sNaLwiSSm7aU66qzIOK?p=preview
You need to move the yAxis definition within the d3.csv success function, and then reference the data array like so to label the axis how you would like:
var yAxis = d3.svg.axis()
.scale(y)
.tickFormat(function(i) {return data[i].seq; })
.orient("left");

d3.js bar chart with pos & neg bars (win/loss) for each record

I want to make a bar chart in d3.js that has both positive and negative bars for each item or row, like this:
it's somewhat like the google finance "Sector Summary" chart (http://google.com/finance)
Can anyone point me to a d3.js example of this kind of chart? I am aware of the "bar chart with negative values" example here: http://bl.ocks.org/mbostock/2368837
If there is a relatively easy way to explain how to modify that example to accomplish what I want, that could work too.
Thanks!
Here is what I could do:
The basis is to have two values per item. To simplify things we can say that all values have to be positive, the first one will be displayed on the right, the second one on the left.
From the example you provided, we will just plot the second value we add:
data = [
{name: "A",value: 1,value2: 2},
...
]
We will also fix the domain (you can write a function to do it nicely afterwards):
x.domain([-10,10])
Finally, we will draw the second bars (on the left):
svg.selectAll(".bar2")
.data(data)
.enter().append("rect")
.attr("class", "bar2")
.attr("x", function (d) {
return x(Math.min(0, -d.value2));
})
.attr("y", function (d) {
return y(d.name);
})
.attr("width", function (d) {
return Math.abs(x(-d.value2) - x(0));
})
.attr("height", y.rangeBand());
This code is just copy paste from the example where I replaced d.value by -d.value1 and .bar by .bar2 for the class.
You will also have to modify the x-axis format for having "75, 50, 25, 0, 25, 50, 75".
jsFiddle: http://jsfiddle.net/chrisJamesC/vgZ6E/

Resources