I'm trying to replicate this Focus+Context via Brushing example. I'm including the same layout, but with a scatterplot instead of a line/area plot.
I started working off this example I found which combines the area plot and a scatterplot. However, when I scrap the area plot, I lose the zoom/focus capability.
My last step (thus far unsuccessful) is to make the brush (small focus bar on the bottom) actually respond to the main panel (make it adjust/zoom in when smaller time periods are selected in the brush). The brush adjusts the axis as it should, but I just haven't been able to make the brush actually adjust/zoom the points on the main scatterplot. I'm not trying plot anything in the brush - there will be a lot of points, so keeping the brush with a grey background and no points is fine.
here's my fiddle: http://jsfiddle.net/fuqzp580/3/
Sidenote: I can't quite get the jsfiddle to work with the way I'm using d3.csv, so I coded up a slightly altered version with dummy data in lieu of using d3.csv. However, I included the d3.csv code (commented out), just in case that could be a cause for my problem.
I'm new to d3 so any pointers or ideas welcome!
Here's an updated fiddle with the dots zooming on the points in the main panel: http://jsfiddle.net/henbox/3uwg92f8/1/
You were very close, I just made 3 small changes:
Firstly, uncommented the code you already had in function brushed() for selecting the dots
Secondly, defined mydots globally (since you were only doing it inside initialize() and it needs to be used beyond this scope). Added this on line 55:
var mydots = focus.append("g");
And last (and most importantly), I changed the definition for xMap from
xMap = function(d) { return x2(d.time); }
to
xMap = function(d) { return x(d.time); }
When brushing, it's the x scale that gets updated, not the x2
Related
I have seen examples here and here were a brush is triggered in JavaScript. I want to understand the implementation of the first one.
Background
The first example bundles two D3 line charts in a single svg container; classes focus and context, respectively:
The context chart (marked in light blue, above) is the one containing the brush, which can be triggered by a mouse click:
When we look inside its group container, we find the designated brush parameters; under the extent class:
Question 1.
I don't understand what happens in the last two lines, in particular the last line:
function drawBrush(a, b) {
// define our brush extent
// note that x0 and x1 refer to the lower and upper bound of the brush extent
// while x2 refers to the scale for the second x-axis, for context or brush area.
// unfortunate variable naming :-/
var x0 = x2.invert(a*width)
var x1 = x2.invert(b*width)
console.log("x0", x0)
console.log("x1", x1)
brush.extent([x0, x1])
// now draw the brush to match our extent
// use transition to slow it down so we can see what is happening
// set transition duration to 0 to draw right away
brush(d3.select(".brush").transition().duration(500));
// now fire the brushstart, brushmove, and brushend events
// set transition the delay and duration to 0 to draw right away
brush.event(d3.select(".brush").transition().delay(10duration(500))
}
In brush(d3.select(".brush").transition().duration(500));, the current brush parameters are selected with a transition precondition; which is passed to brush, so it can draw the new brush according to the changed brush.extend values.
In brush.event(d3.select(".brush").transition().delay(10duration(500)), it seems that the previous line sets the parameters, after which brush.event executes with the new brush parameters. Can someone make sense of this? How do the brush events apply to this case?
Question 2.
I also don't see how exactly, this event action gets linked back to the focused chart. If find the mechanisms via callbacks quite cryptic:
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
This snippet seems crystal-clear: the brush is made and linked to the brush event listener. On a brush event, brushed will act as the event handler. Furthermore, the scale of context's x-axis x2 is passed to the brush, as it sits on the context chart.
But I'm not quite sure how brushed works:
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
Just to be sure, is it correct that a new axis is generated in focus.select(".x.axis").call(xAxis); with the brush parameters set in x.domain(brush.empty() ? x2.domain() : brush.extent());?
First, there is a typo in the last line. In the code it actually is:
brush.event(d3.select(".brush").transition().delay(1000).duration(500))
Back to your question, the confusion you're facing trying to understand what the brush events have to do with it is quite simple: you're reading the D3 v4 docs, while that code uses D3 v3.
This is brush.event in D3 v3:
brush.event(selection)
If selection is a selection, it dispatches a brush gesture to registered listeners as a three event sequence: brushstart, brush and brushend. This can be useful in triggering listeners after setting the brush extent programatically. (emphasis mine)
As you can clearly see, the first line changes the brush itself (the context), while the second one changes the big area chart (the focus).
I am using d3.js to generate a circle kind of graph. My graph has three layers background,midground and foreground. I have a function called call for foreground and midground layer.
I am able to generate the arc for values till .96 but if it goes beyond that .97, .98, .99 and 1.0 arc are getting collapsed.
midground.transition()
.duration(750)
.call(arcTween, 0. * τ);
foreground.transition()
.duration(750)
.call(arcTween, 0. * τ);
I am new to d3.js and svg kindly help with this. I have provided the jsfiddle link as well.
http://jsfiddle.net/Lxnymj28/1/
This setting is messing up the arc calculation:
.cornerRadius(outerRadius - innerRadius)
If you remove the cornerRadius, everything draws fine.
EDITS
Did some research, this was a bug in the library, fixed back in October, 2015. You are using way out of date software.
If you use the latest version of d3.js version 3, everything works fine.
New fiddle here.
Here I have the code for my scatterplot.
https://github.com/laran/eisenhower/blob/master/components/plot/scatterplot.js
This is what the plot looks like when it is initially rendered which is done by calling .setup() and then .update().
This is what the plot looks like after a point is added (data points changed and plot updated).
You'll notice that in addition to there being one more point on the second plot, while the new circle has a black outline, all of the circles that were already there have had their black outline removed.
My question is why do the black circle outlines disappear after update?
And, for bonus points:
After updating one of the data points and calling Application.Plotter.update(), the dots often don't update. Why don't the circles update after changing the data values and calling Application.Plotter.update()?
I have a feeling that there's something of in how I'm calling enter() or exit() on the plot. But I'm not familiar enough with d3 to really understand what I've done wrong.
Thanks!
I fixed the issue by calling .exit().remove() before calling .enter().append().
https://github.com/laran/eisenhower/commit/4a23906f17723449a5f1d4901279d32cbcf26870
I'm relatively new to d3 and am attempting to augment a radar diagram such that it rotates on click and the next axis points directly upwards.
The example in which I am working from is found here.
Problem
Currently, when the svg is clicked, I rotate the entire svg by a specified angle based on the number of axis there are in the graph. Since I am rotating the entire svg the labels that are appended to each axis will rotate also (as shown in the following image).
The text is currently unreadable and I want to achieve a solution which is more similar to the following image:
I would like each label to stay with their respective axis and also stay upright after the svg has been rotated, but I am finding it hard to achieve this.
JSFIDDLE
This JSFIDDLE is the stripped down code of the current implementation (I left out the numerous failed attempts) and the following code, which would be in the 'rotateOnClick' function is the closest I have came to a solution so far (I haven't used the index i variable so far but my intention was to swap the position of labels with each other when clicked).
g.selectAll(".legend")
.transition()
.duration(cfg.rotateDuration)
.attr("transform", function(d, i){
if (i<total) i++;
else i = 0;
return "rotate("+newAngle*-1+", "+(cfg.w/2)+",0 )"
})]
.ease(cfg.easeFunction);
I need to manipulate each label individually and stay aligned with its respective axis and also for it to work with a dynamic number of axis.
I greatly appreciate any help and insight.
I’m new to to d3 and have combined mbostock’s stacked bar graph example ( http://bl.ocks.org/mbostock/3886208 ) with a map to show data (canada.json)
I would like the graph to display an updated chart on the d3.mouseover event of the province:
http://gao8a.github.io/ (something like this)
Unfortunately, I was only able to get the axises to display. It's showing either multiple or the same axis overlapping:
(These will take ~ 3 seconds to load)
Multiple:
http://bl.ocks.org/GAO8A/566e238a72e5ebd1e2c1
Same Axis overlap
http://bl.ocks.org/GAO8A/64f94bb494c4a73f2bf6
I understand I probably need a ‘mouseout’ event to delete the previous but I’m not quite sure how to design that either.
Can anyone point out what I’m doing wrong and how I should be loading the data?
PS:
I was going to make a jsfiddle but can’t seem to get it to get it to work with my hosted canada.json data.
https://raw.githubusercontent.com/GAO8A/GAO8A.github.io/master/canada.json
Thanks
Your issue is that you keep adding the axes in the tooltip element. Unfortunately this creates the overlaps. What you could do is add the axes once, and the readjust their domain with the new values that correspond to the element being hovered.
So in essence if you could add the following lines:
var X_AXIS = tooltip.append("g").attr("class", "x axis x-axis").attr("transform", "translate(0," + height + ")");
X_AXIS.call(xAxis)
X_AXIS.append("text").attr("dy", "3em").attr("dx", "50em").style("text-anchor", "end").text("Month");
var Y_AXIS = tooltip.append("g").attr("class", "y axis y-axis")
Y_AXIS.call(yAxis)
Y_AXIS.append("text").attr("transform", "rotate(-90)").attr("dy", "-3em").attr("dx", "-8em").style("text-anchor", "end").text("Temperature (Celcius)");
just before adding your map, this would in a sense 'initialize' the axes.
So further, in your mouseover handler, you could add the following lines, just after you determine your x and y domains.
X_AXIS.call(xAxis)
Y_AXIS.call(yAxis)
or better still, to add some transition:
X_AXIS.transition().duration(400).call(xAxis)
Y_AXIS.transition().duration(400).call(yAxis)
This way, you don't keep adding axes, you just readjust the ones currently intialized.
Hope this helps.