update data in an d3 area graph - javascript

I'm looking for how to dynamically change data in a D3 area graph, like in this example.
The only difference, is that i'm using an area graph, like in this code:
svg.append("path")
.datum(data)
.attr("class", "d3-area")
.attr("d", area)
.style('fill', color)
.transition() // begin animation
.duration(1000)
.attrTween('d', function() {
var interpolator = d3.interpolateArray(startData, data);
return function (t) {
return area(interpolator (t));
}
});

Related

Using General update pattern in line graph

I have a demo here
Its a line bar chart using D3 in an Angular app.
I want the chart to be responsive so when the page is resized the chart width will increase and the height will be stay the same.
I'm doing this by capturing the window resize and then calling the function that draws the chart.
This works for the axis but I cant get the line and points to redraw.
I think it's to do with the way I'm trying to us the update pattern
How can I use the update pattern to redraw this line graph
const that = this;
const valueline = d3.line()
.x(function (d, i) {
return that.x(d.date) + 0.5 * that.x.bandwidth();
})
.y(function (d) {
return that.y(d.value);
});
this.x.domain(data.map((d: any) => d.date));
this.y.domain(d3.extent(data, function (d) {
return d.value
}));
const thisLine = this.chart.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
const totalLength = thisLine.node().getTotalLength();
thisLine.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength);
thisLine.transition()
.duration(1500)
.attr("stroke-dashoffset", 0)
let circle = this.chart.selectAll("line-circle")
.data(data);
circle = circle
.enter()
.append("circle")
.attr("class", "line-circle")
.attr("r", 4)
.attr("cx", function (d) {
return that.x(d.date) + 0.5 * that.x.bandwidth();
})
.attr("cy", function (d) {
return that.y(d.value);
})
circle
.attr("r", 4)
.attr("cx", function (d) {
return that.x(d.date) + 0.5 * that.x.bandwidth();
})
.attr("cy", function (d) {
return that.y(d.value);
})
circle
.exit()
.remove()
You have problems in both circles' selection and the line selection.
The circles' selection:
You're selecting "line-circle". Instead of that, you have to select by class: ".line-circle";
You're reassigning the circle selection:
circle = circle.enter()//etc...
Don't do that, otherwise circle will point to the enter selection, not to the update selection anymore. Just do:
circle.enter()//etc...
The path:
You're appending a new path every time you call the function. Don't do that. Instead, select the existing path and change its d attribute, or append a new path if there is none. Both behaviours can be achieved with this code:
let thisLine = this.chart.selectAll(".line")
.data([data]);
thisLine = thisLine.enter()
.append("path")
.attr("class", "line")
.merge(thisLine)
.attr("d", valueline);
Here is your forked code: https://stackblitz.com/edit/basic-scatter-mt-vvdxqr?file=src/app/bar-chart.ts

d3 fill under interpolated line

In the following d3 line chart example, I would like to fill in the the area under the lines with fill color equivalent to line color and a transparency of 50%.
In addition to adding area to the CSS
.area {
fill: blue;
opacity: 0.5
}
adding the following to function updateGraph(data)
svg.append("path")
.data([data])
.attr("class", "area")
.attr("d", area);
and
var area = d3.svg.area()
.x(function(d) { return x(d.year); })
.y0(height)
.y1(function(d) { return y(d.value); });
what is needed for the filled in area to fit under the interpolated line and for fill color to be equivalent to line color?
Actually, you have to create a new selection before the lines' selection (named states), here named stateArea:
var stateArea = svg.selectAll(".area")
.data(result, function(d) {
return d.key
});
stateArea.enter().append("path")
.attr("class", "area");
stateArea.transition()
.style("fill", function(d, i) {
return d.color = color(d.key);
})
.style("opacity", 0.5)
.attr("id", function(d) {
return 'tagArea' + d.key.replace(/\s+/g, '');
})
.attr("d", function(d) {
return area(d.values)
});
stateArea.exit().remove();
Here is the updated bl.ocks: http://bl.ocks.org/anonymous/0c80f4f72247dcc8f590aa2d63d40da0
PS: I'm just appending the areas here, you'll have to refactor the code if you want that legend to the left changing the areas as well.

d3 doughpie/bubble chart combo with animation tweening

I have created this chart in static form - to exactly how it needs to be -- but I've lost animation and morphing along the way ---
1. -- how to animate the arcs
2. -- how to animate the bubbles
3. -- adding back the randomise button to test with 2 dummy data sets.
I need the arcs to tween like they did before -- http://jsfiddle.net/NYEaX/1452/
Latest fiddle.
http://jsfiddle.net/NYEaX/1506/
this is the old pie animations and worked very well
/* ------- ANIMATE PIE SLICES -------*/
var slice = doughpie.select(".slices").selectAll("path.slice")
.data(pie(data), key);
slice.enter()
.insert("path")
.style("fill", function(d) {
return color(d.data.label);
})
.style("transform", function(d, i){
//return "translate(0, 0)";
})
.attr("class", "slice");
slice
.transition().duration(1000)
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
})
slice.exit()
.remove();
/* ------- ANIMATE PIE SLICES -------*/
//this is the current pie arcs - but when I try and animate the pie in the same manner - it fails.
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.label);
});
arc
.outerRadius(radius - 10)
.innerRadius(0);

D3 Filter via selectAll after Transition

I try to build an interactive scatterplot. Therefore I am applying different colors to my data via dropdown like this:
function color_drop_update (select, checkbox) {
if (select == "gender") {
holder.selectAll(".dot").style("fill", colorf_gender);
holder.selectAll(".legend rect").style("fill", color_gender);
}
I can also change the plotted axes via radioboxes and a transition like this:
function transition(dimension) {
if (dimension == "pca") {
var xMap = xMap_pca;
var yMap = yMap_pca;
xScale.domain([d3.min(data, xValue_pca)-1, d3.max(data, xValue_pca)+1]);
yScale.domain([d3.min(data, yValue_pca)-1, d3.max(data, yValue_pca)+1]);
}
else if (dimension == "tsne") {
var xMap = xMap_tsne;
var yMap = yMap_tsne;
xScale.domain([d3.min(data, xValue_tsne)-1, d3.max(data, xValue_tsne)+1]);
yScale.domain([d3.min(data, yValue_tsne)-1, d3.max(data, yValue_tsne)+1]);
}
// Update old
circles.attr("class", "update")
.transition()
.duration(0)
.attr("cx", xMap)
.attr("cy", yMap);
//Update Axis
holder.select(".xaxis")
.transition()
.duration(0)
.call(xAxis);
holder.select(".yaxis")
.transition()
.duration(0)
.call(yAxis);
}
What is working fine:
Different filters and color information before transition
Different filters and color information are kept after the transition: first filter then transition (intended)
What is NOT working:
Choose axis and filter afterwards: first transition then filter!
Would really appreciate any hints and help!
Finally I got it:
it is important, that you mention the markers class even in the transition one again:
circles.attr("class", "update")
.transition()
.duration(0)
.attr("cx", xMap)
.attr("cy", yMap)
.attr("class", "dot");

d3.js doughnut chart :: Additional paths are rendered and not updated

I'm having problems rendering doughnut charts in d3. I have 2 doughnuts, that I'm creating side-by-side inside of a for each function::
data.forEach(function(d,i){...}
The charts render fine. When I go to update the chart, paths are redrawn. Not sure why this happening because I'm using .enter()
Any advise?
var singleDonutData = [1];
var donutSections=singleDonut.selectAll(".donutSections")
.data(singleDonutData)
.enter()
.append("g")
.attr("class","donutSections");
var pathGroup = svg.select("." + donutName).select(".donutSections").selectAll("path.arc")
.data(pie(d));
var path = pathGroup
.enter()
.append('path')
.style('fill', function(d){ //give arc a color in SVG Scale
return color(d.data.label);
})
.attr("d", arc)
.each(function(d) { this._current = d; }); // store the initial angles;
You need to add corresponding class name on the generated path, for example:
var pathGroup = svg.select("." + donutName).select(".donutSections").selectAll("path.arc")
.data(pie(d));
var path = pathGroup
.enter()
.append('path')
.style('fill', function(d){
return color(d.data.label);
})
.attr("class", "arc") // corresponding to selectAll("path.arc")
.attr("d", arc)
.each(function(d) { this._current = d; }); angles;
So that when you update the chart, d3 can correctly select these already rendered path.
After this update, you also need to add code to handle the update selection. Something like this:
pathGroup.transition().duration(1000)
.attrTween("d", function(d){
// some transition animation code here if you need it.
})

Categories

Resources