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);
}
Related
I have a bar chart that I want to be able to hover over the bars and display some data on the top of the chart as text.
I don't want to use tooltips and when I change my text to a normal string like "boom" it will display that on mouse entry. However, it wont display the data.
I have the mouseenter and the function it calls in the code below. Basically I need a way for the mousenter to tell the function what the data it. For some reason it wont do that.
Ive tried useing .text(d3.select(this).text(d.data)) in the function.
I have also tried getting rid of the function and having it all as one code. Also did not work
.on("mouseenter", flash("mode0Danceability"))
function flash(name) {
return function() {
svg.append("text").attr({id: "fish"})
.attr("class", "boom")
.attr("x", 45)
.attr("y", -33)
.text(svg.html(d.mode0Danceability))
.style("font", "20px sans-serif")
.style("fill", "steelblue");
};
}
Best method IS to create a tooltip, just give it no borders and append it as a text to a particular location not as a div.
I created two different SVGs. One contains a graph with data points, the other one contains three lines. The lines color are supposed to be dependent on the selected data point and I have not managed to get this done yet (more details below). The jsfiddle can be found here: jsfiddle.
What I would like to do is to change the color of the three lines when I mouseover the data points. I managed to change the color of all lines to the same color but would actually like to use the color that is associated to the respective data point but I don't know how I can pass the color data which are stored in myColors to the function where I set the lines' color.
The relevant code is shown below. I add a graph with datapoints to mySvg and when I mouseover the data points, I change their color to black and the color of the lines in the other SVG to green. However, instead of changing all lines' color to green, I would actually like to change their colors to the colors defined in myColors (see the above linked jsfiddle to find the data). How could I do this?
var circles = mySvg.selectAll("circle")
.data(lineData)
.enter()
.append("circle");
var circleAttributes = circles
.attr("cx", function (d) { return xScale(d.x); })
.attr("cy", function (d) { return yScale(d.y); })
.attr("r", 6)
.style("fill", 'red')
.on('mouseover', function(d){
d3.select(this).style("fill", 'black');
d3.select('#myLines').selectAll("line").attr("class","sweepline").style("stroke", 'green');
})
.on('mouseout', function(d){
d3.select(this).style("fill", 'red');
});
As with many d3 problems this one is easily solved using data binding. Your custom colors could be bound to the lines you append to the second SVG. Since your array myColors, consisting of the arrays of custom colors per line, has the same structure as your other arrays like names, x1Val, y1Val and so forth, it can be easily integrated in the data array coords used for binding information to your lines:
var coords = d3.zip(names, x1Val, y1Val, x2Val, y2Val, myColors);
This data per line can later on be used in the mouseover event handler for your circles setting the stroke style on the lines.
.on('mouseover', function(d,i) {
// ...
d3.select('#myLines')
.selectAll("line")
.style("stroke", function(d) {
return d[5][i].color;
});
})
The callback determines the color by
accessing the array of custom colors, which is at position 5 of the data array bound to the lines, hence d[5],
getting the ith object of this array of colors. The i is the index of this circle, which is passed as parameter to the event handler and made available to the stroke callback by a closure,
getting property .color from this object
Check the updated JSFiddle for a working example.
Furthermore, I have updated the mouseout handler to delete the previously set stroke style causing the lines to be reset to their default color set by class sweepline. This behaviour, at least to my eyes, seemed to be missing.
d3.select('#myLines')
.selectAll("line")
.style("stroke", null);
I'm working with this example, but am struggling to find how to format the x axes to prevent overlap. I believe some of the difficulties I'm experiencing are due to the brush for the zoom/pan option. I'm trying to move the August labels to the right so they don't overlap the y-axis. Additionally, the brush labels completely overlap each other and I'd like to fix that as well.
x-axis code
this.xAxisTop = d3.svg.axis().scale(this.xScale).orient("bottom");
this.xAxisBottom = d3.svg.axis().scale(this.xScale).orient("top");
brush code
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y",0)
.attr("height", contextHeight);
I've tried modifying the x-axis directly by selecting an x-axis and calling .ticks(5), but all it does is return a bunch of code related to the axis functions.
Please let me know if I should include more coherent explanations or examples, thanks!
For this problem we have to write custom tick format functions.
Same problem occurred while zooming is solved in below link.
http://stackoverflow.com/questions/20010864/d3-axis-labels-become-too-fine-grained-when-zoomed-in
Below link helps you in solving your problem directly
http://jsfiddle.net/BdGv5/3/
Three custom javascript functions helps you to change your axis format.
I'm working with this jsfiddle. I expect that when I click the WeekView button it should change the bar colors to reflect the same colors that are in my legend. But for some reason the colors are different.
I don't think
var layer = svg.selectAll(".layer")
.data(stack);
layer.enter()
.append("g")
.attr("class", "layer")
.style("fill", function (d, i) {
return color(i);
});
layer.exit()
.remove();
is being called when I switch to weekview, therefore its not replacing the old bars with the new ones its just reusing the bars from the previous views.
How can I get d3.js to replace the bars with the proper colors?
Indeed, the problem is in that part of the code: Demo
var layer = svg.selectAll(".layer")
.data(stack);
layer.enter()
.append("g")
.attr("class", "layer");
// Set the colors in the `update` cycle, not the `enter` cycle.
layer.style("fill", function (d, i) {
return color(i);
});
layer.exit()
.remove();
There is an interesting history of why this behaves this way. In earlier versions of D3, the enter and update set of elements were kept separate, just like update and exit events are still kept separate, i.e. operations you performed on the update set would not be performed on the exit set and vice-versa.
However, in version 2.0 of D3, it was decided that any element appended in the enter phase would also become a part of the update set. This was done because often the enter set of elements and the update set of elements needed to have the exact same operation performed on them (like in your case). To avoid this effect, you'll need to write the update phase before the enter phase.
Hence, in the enter cycle, elements should be appended and their initial attributes should should be set while their final values (which they should have in static state) should be set in the update cycle.
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.