I am working on the line graph using brush and context see this link for what I have so far. The brushing effect is only appearing on the scale and not the line graph. I am not able to figure out how to change brushed() function so that the brushing also appears for the line chart as well.
function brushed(){
console.log("brush called");
x.domain(brush.empty() ? x1.domain() : brush.extent());
focus.select(".line").attr("d", line);
focus.select(".x.axis").call(xAxis);
}
I needed to rewrite brushed function to following to update the line chart.
function brushed(){
console.log("brush called");
x.domain(brush.empty() ? x1.domain() : brush.extent());
**focus.selectAll(".line").attr("d", function(d) { return line(d.values); })**
focus.select(".x.axis").call(xAxis);
}
updated plnkr link
Related
I am using the d3 zoom behaviour and attempting to use a transition for both a translateTo and a scaleTo at the same time. If I make the calls to zoom without a transition everything works fine. If I use a transition for just one of the transforms it also works, but if I attempt to use a transition for both it fails (it appears to only apply the first transform). I have a JSFiddle with several combinations here: JSFiddle
Here's the code that isn't working as I expect
svg.transition()
.duration(750)
.call(zoom.scaleTo, 2)
.call(zoom.translateTo, 50, 50)
You can do like this:
svg.transition()
.duration(750)
.call(zoom.scaleTo, 2)
.transition() <--- this is missing.
.call(zoom.translateTo, 50, 50)
First zoom then translate.
working code here
EDIT
Performing zoom and translate both # same time you need to tween.
function twizzle(selection, duration) {
d3.select(selection).transition()
.duration(duration)
.tween("attr:transform", function() {
//interpolate from start to end state
var i = d3.interpolateString("scale(1)translate(0,0)", "scale(2)translate(50,50)");
return function(t) {
selection.attr("transform", i(t));
};
});
}
Now call the function like this:
d3.select('body')
.append('button')
.text('transition both - scale first')
.on('click', function() {
//on click call the function created above
group.call(twizzle, 750) <-- perform the scale and translate on the group not on the SVG.
})
working code here
I'm building a number of graphs using crossfilter and dc.js. Among others, there is a row chart and an histogram (a bar chart).
What I am trying to do is to create a tooltip on the row chart which will show the histogram.
Looking at this SO-question I saw an example using d3-tip. I have made an attempt in this jsfiddle. However, I cannot see how to embed a div in the tooltip.
Any suggestion? (If using plain d3 is better, I'm ok with that.)
Snippet of code is:
function draw_row(div_id){ ...; return row_chart; }
function draw_hist(div_id){ ...; return bar_chart; }
var rate_chart = draw_row('#rate').title(function(){return'';});
dc.renderAll();
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function () {
// What to put in here???
draw_hist('#distr').render();
return "<div id='distr'>Distribution<br></div>"
});
d3.selectAll("#rate g.row")
.call(tip)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
Fun project!
Yes, as you noticed, you're not going to be able to render the chart while you're in the .html() callback - that only returns static HTML, and I don't think you can give it an element instead.
So we'll have to find a place to render after the HTML has already been generated. Luckily, d3-tip doesn't try to handle mouse events or anything like that - the code which displays the tip is right there in the code you've posted:
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
So we can wrap tip.show in a function of our own, and then render the chart into the tip once it's on the screen.
We have to watch out because mouseover will fire every time the mouse moves, and we probably don't want to replace the tip-chart until we hover over another bar. So we'll remember the id of the last bar we hovered:
var last_tip = null;
d3.selectAll("#rate g.row")
.call(tip)
.on('mouseover', function(d) {
if(d.key !== last_tip) {
tip.show(d);
draw_hist('#distr').render();
last_tip = d.key;
}
})
.on('mouseout', function(d) {
last_tip = null;
tip.hide(d);
});
Finally, d3-tip needs to know the size of the tip content in order to render in the right place. (If it accidentally renders on top of the element, this can cause horrible flickering when the mouse goes over the tip, registering mouseout on the element.)
So we'll just hard-code that, since we're hard-coding the chart size anyway. 20 extra pixels to fit the title:
.html(function (d) {
return "<div id='distr' style='min-width:300px; min-height: 320px'>Distribution<br></div>"
});
Looks pretty cool with the default translucent black style from d3-tip:
Here's the fork of your fiddle: https://jsfiddle.net/gordonwoodhull/hkx7j3r5/10/
I have prepared a bubble chart , which you can zoom into using the brush in ther grey area below the scale.Here is the fiddle. The code below updates the graph . It is updating the ruler but not graph. Can any one point out why?
function brushmove(){
x_axis.domain(brush.empty() ? x_axis.domain() : brush.extent());
svg.select('.ruler').call(x_axis_ruler);
blue_circle.selectAll('circle').data(dataset)
.attr('cx', function (d, i) {
return x_axis(d.waiting_to_be_processed_time);
})
}
I dont know why but you should not be using the variable blue_circle to update the width .
Instead you should be replacing the code with this:
function brushmove(){
x_axis.domain(brush.empty() ? x_axis.domain() : brush.extent());
svg.select('.ruler').call(x_axis_ruler);
d3.select('.processing_circles').selectAll('circle').data(dataset).attr('cx', function (d, i) {
return x_axis(d.waiting_to_be_processed_time);})
}
I have left the reason for a more experienced user to checkout.
I could really use some guidance setting up a transition on my multiseries line chart. As an example of what I need, I've started with this great multiseries line chart: http://bl.ocks.org/mbostock/3884955. To that code, I've added an update() function that's called once using setInterval(). I've also created a new data set called data2.csv which is similar to data.tsv but has different values.
The update function should change the data that the line chart is displaying. Forget about making a nice smooth transition, I can't even get the data to update in the chart view. When I try using the update function, it looks like the new data is loaded properly into the javascript variables, but the lines on the chart don't change at all.
I've seen variations on this question asked a few times but haven't found an answer yet. Can anyone help me figure out how to transition this multi-series line chart to a new dataset (also multiseries)?
function update() {
d3.csv("data2.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
// format the date
data.forEach(function(d) {
d.date = parseDate(d.date);
});
// rearrange the data, same as in the original example code
var cities2 = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
// update the .city g's to the new dataset
var city2 = svg.selectAll(".city")
.data(cities2);
// redraw the lines with the new data???
city2.selectAll("path")
.attr("d", function(d) { return line(d.values); });
clearInterval(transitionInterval);
});
}
UPDATE: NikhilS's answer contains the key to the solution in the comment trail.
You should make sure you are following the enter + update process as outlined by Mike Bostock in his stuff on the General Update Pattern. It looks like you haven't invoked any kind of d3 transition. You also haven't specified an enter or exit for the update function, which will cause problems if you have new data coming in and/or old data going out. Try changing this:
var city2 = svg.selectAll(".city")
.data(cities2);
city2.selectAll("path")
.attr("d", function(d) { return line(d.values); });
to the following:
var city2 = svg.selectAll('.city')
.data(cities2);
var cityGroups = city2.enter().append('g')
.attr('class', 'city');
cityGroups.append('path')
.attr('class', 'line');
d3.transition().selectAll('.line')
.attr('d', function(d) { return line(d.values); });
city2.exit().remove();
I made a basic data re-join and update demo a while back, which you can view here.
use d3 Transition, you can make some sort of animation.
If you want to select a sub-interval of the data to plot the graph, no need manipulation on the data, just use a d3 brush and clip the graph
For a multi-series line graph with most of the line graph elements, you could refer to this example: http://mpf.vis.ywng.cloudbees.net/
I am using nvd3 to draw a simple line chart with data receiving via an ajax request. It is working perfectly with the first drawing request but not on redrawing. The chart redraws by calling the same drawing function but with different data + differen max/min values.
When redrawing the chart with new data the "hover circle" does not appear, whereas the tooltip does. Furthermore when clicking on the legend of the chart and force a redraw by that the hover appears again, but the values of the yAxis are changed to these of the first drawn chart.
So far I assume that when redrawing the chart still holds the old max/min values - but only concerning the "hover" effect. The general chart looks fine so far also on redraw - the problem just faces the hover and that's it.
Sounds pretty confusing, but hopefully you will get the point.
Some code:
d3.json(queryurl, function(data2){
nv.addGraph(function(jsonData) {
if(chart){
chart.remove();
}
chart = nv.models.lineChart()
.x(function(d) { return d[0] })
.y(function(d) { return d[1] })
.color(d3.scale.category10().range());
chart.xAxis
.tickFormat(function(d) {
return d3.time.format('%x')(new Date(d))
});
chart.yAxis
.scale()
.tickFormat(d3.format(''));
chart.lines.yDomain([maxmin.max,maxmin.min]);
d3.select('#chart1 #chartsvg')
.datum(data2)
.transition().duration(600)
.call(chart);
nv.utils.windowResize(chart.update);
});
});
return chart;}
Try using .empty() on the svg element before redrawing.
I've only just started with NVD3 and D3 myself, however am doing a similar thing. What worked for me is to separate the data update function with the chart creation function. Do note the caveat below though...
I have the following to create the graph:
initGraph = function(url) {
d3.json(url, function(data) {
nv.addGraph(function() {
chart = nv.models.multiBarChart();
d3.select('#chart svg').datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
});
};
And the following function to update it:
redrawGraph = function(url) {
d3.json(url, function(data) {
d3.select('#chart svg').datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
});
};
I don't know if this is the recommended solution as I'm still at the "hack until it works" stage. With this, all the functions of the chart work after invocation of redrawGraph() (including axes redraw and tooltips).
Caveat: this seems to occasionally result in miscalculated ticks on recalculation: