I'm fairly sure if I can find an example showing what I'm trying to do, I can reverse engineer/reimplement it. Has anyone seen an example showing a smooth/animated transition between a linear and log scale in D3JS?
I have both scales working independently, but I have to reload the page to change the scale.
My Google skills have failed me!
Thanks so much.
Here's a proof of concept jsfiddle. You simply reselect the data points and redraw them with the new scale. For the axis labels, the transition is even simpler -- you just need to call the axis function again. Relevant excerpt below.
// change to log scale...
yScale = d3.scale.log().domain([1, 100]).range([dim-padding,padding]);
svg.selectAll("circle").data(data)
.transition().delay(1000).duration(1000)
.attr("cx", function(d) { return xScale(d); })
.attr("cy", function(d) { return yScale(d); });
svg.selectAll(".y")
.transition().delay(1000).duration(1000)
.call(yAxis.scale(yScale));
You might need to play around with how the labels are generated to make it look "nice", but in principle d3 will take care of the entire transition.
Related
I'm trying to teach myself D3 with examples from http://bl.ocks.org/mbostock.
I took the scatterchart and I'm trying to load various data depending on what menu-item is active.
Everything is working fine, but I got one problem I just can't solve.
The xAxis should update itself depending on the values from the data linked to the menu item.
I was searching the web for an answer, but couldn't find one that worked for me.
I think the problem (and solution) lies in this part of the code;
function updateChart() {
svg.selectAll('.dot')
.transition()
.duration(1000)
.attr('cx', function(d) {
return x(d.data[parameter]);
})
svg.select(".x.axis")
.call(xAxis);
}
I made this JSFiddle to make it more understandable.
Here's what's going on.
You successfully generated your xAxis with the correct x scale in the first go around, however
You didn't update your xAxis with the new domain of data
You were right in that you had to re-update your scales whenever you click on your labels.
I've done a couple of things:
Add a sourceData variable after you've coerced your numbers, for all your functions to reference
Add a updateXScale(data) function that will simply update your x scale's domain
Have it called every time you click a label. Not only will this fix your x scale, it will also enable the correct scaling of your x-coordinates for your .dot's.
Here's what it looks like all together. I've created a fiddle that has a working version of your example.
And here's your updateChart function for reference:
function updateChart() {
updateXScale(sourceData);
svg.selectAll('.dot')
.transition()
.duration(1000)
.attr('cx', function(d) {
return x(d.data[parameter]);
});
svg.select(".x.axis")
.call(xAxis);
}
I have a d3 visualisation on a web page that shows a collection of plot points on a chart.
It's all very simple really with just two axis and sometimes maybe 30 points to plot. As I render these plots I perform a transition on the r attributes of the SVG circles. The code that does this is:
g.append("svg:circle")
.attr("class", "plot-circle")
.attr("cx", xCo)
.attr("cy", yCo)
.attr("r", 0)
.transition()
.delay(function() { return delayInput * 100; })
.duration(plotExplosionDuration)
.ease(Math.sqrt)
.attr("r", 6);
All that occurs is that the circles are initially set to r=0 which means they aren't rendered at all. Then I start a transition on the appended circle to take this radius up to 6.
The problem is that it appears on some machines these transitions don't stop at r=6 and some plots end up being much bigger than the value set after the transition.
I simply cannot duplicate this on my main development machine (PC), my iPad nor my MacBook Pro which leads me to think it might be performance or machine load causing this?
has anyone got any ideas on how to ensure the transition stops at the defined final r value?
I have a zoomable map of the world with a single point on it (in reality there are multiple points from a separate resource but I have simplified it). The block is here.
When I try and zoom in it jumps to a certain scale and then usually doesn't allow any more zooming movements. I have experimented with various different values for the transition, scale and scaleExtent taken from this example and this one (with the latter being very close to what I want overall) but nothing has worked. It seems to get quite close to the actual size at height/6 for minimum zoom but still behaves badly.
I suspect the main problem is with scaleExtent. I actually want the minimum zoom to be the size of the map and so it isn't possible to pan around unless zoomed in.
The other problem is, as you can see in the bl.ock that the circle disappears when you zoom. I want the circle to maintain position and size (so it doesn't get bigger when I zoom).
Can any one help with
The zoom problem on the map, so the map minimum zoom is the actual size map and I can zoom in to about 6x that
Preventing the map from panning unless zoomed in
Maintaining the size and position of the circle on the map
I've put an example of what I think you're after on this bl.ock which is based on the first example you pointed to. It looks as though this line .scaleExtent([height, height*6]) is limiting the scale (well that the purpose of it) to something that was incompatible with your expectations and the initial scale you set, so when you zoom in past a certain level (in this case height) you get stick between height and height * 6.
If you set your minimum zoom and your initial zoom I think you'll get around some of your issues.
The issue with the dots was that they weren't referenced in the redraw function, so when you zoomed d3 / the browser didn't know what to do with them. In my example I've put the following snippet in to address this:
g.selectAll("circle")
.attr("cx", function (d,i) { return projection(d)[0]; })
.attr("cy", function (d,i) { return projection(d)[1]; })
.attr("r", "10px")
.style("fill", "red");
I'm trying to design a simulation of physical gravity with the D3 library, but I'm not having a lot of luck. The 'layout' API reference states that physical gravity can be implemented through a positive 'charge' parameter, but I'm unsure of how this would work.
What I'm attempting to implement at the moment is a single SVG element that contains multiple variably-weighted and -sized rects rising at different speeds eventually going out of the viewport -- their weights will define the velocity at which they rise. (Basically, I'm just trying to implement a global gravitational pull from beyond the top of the viewport.)
Is there a feasible way of doing this in accordance with the D3 force layout? I'm just looking for conceptual solutions, but examples and code snippets are appreciated as well.
Thanks in advance!
Here is couple ideas:
You can directly modify vertical position of node in tick event handler:
force.on("tick", function(e) {
nodes.forEach(function(o, i) {
o.y -= o.weight / 30;
});
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
You need to set force.gavity(0) for this approach.
Or you can use force.gravity: it pulls nodes towards layout center, you can specify svg transfromation to shift layout center above viewport
I see a strange flickering effect after a transition. It is unusual mainly because I do not set the opacity in any way (I want the color to remain the same). Any ideas why this happens?
To have an idea about how the code looks like, here is an example.
var theBars = this.vis.selectAll(".bar" + source.id).data(this.columns);
theBars.enter().insert("svg:rect")
//some attributes
.style("fill", sourceColor)
//some other attributes
theBars.transition()
//.duration(.01)
.attr("y", function(d) {
return this.settings.base - this.getStackedBarHeight(d, source.id);
}.bind(this))
.attr("height", function(d) {
return this.getBarHeight(d.counters[source.id]);
}.bind(this));
As it can be seen only one line sets the color.
I initially tought I made some mistakes at binding, but after checking some posts here and on Google Groups, I discovered that this flickering usually appears when you have transitions that also change the opacity of the object. Unfortunately I don't change any opacity, I just make a transition. This effect appears in all major browsers when executing that transition (theBars.transition).
I try to select a bar from a stacked bar and modify its height.
Best regards!
To fix this I added 2 things:
in the init phase - I added all the bars but with all counters set
on 0;
in the draw phase - I added this code:
var theBars = this.vis.selectAll("#bar_"+index+"_"+currentIndex);
this.settings.sources.each(function(pair) {
theBars
.style("fill", source.color)
.attr("height", this.getBarHeight(source.id)
.attr("y", this.settings.size.baseLine - this.getStackedBarHeight(counters, source.id))
}, this);
The flickering caused by the transitions is gone since we have no transition here. There are still situations in which we need to do a transition, for example when we have several bars with the same word, but there I resolved the flickering by doing it really quick (a .duration(.1) or even less).