nvd3.js cumulativeLine Chart translate axis not working (interactive scope issue?) - javascript

I'm trying to make a custom chart starting with the Cumulative Line Chart http://nvd3.org/ghpages/cumulativeLine.html
I'd like to display data with origin being top left so I swapped the y range, and now the x axis is on top and I need to translate it to the bottom.
I'm trying to use the common d3js transform attribute
.attr('transform', 'translate(0,' + height+ ')');
as suggested here but it does not seem to be working!
I located this section in the cumulativeLineChart model (around line 350)
g.select('.nv-x.nv-axis')
// .attr('transform', 'translate(0,' + y.range()[0] + ')');
.attr('transform', 'translate(0,' + 300 + ')'); // my testing alteration
d3.transition(g.select('.nv-x.nv-axis'))
.call(xAxis);
Y axis can't be translated either. I think it has something to do with the indexLine and the way the scope can be adjusted, but I may be completely off. In fact, I want to get rid of the interactive indexLine feature altogether...
Am I even modifying the right part of the NVD3 code?!
Any help would be GREATLY appreciated. I've spent hours and hours trying to get the whole thing work (occasionally running back and forth between nvd3 and d3), and I am stuck. Thanks!

Related

Unable to refresh svg chart on Data Change

I have a heatmap designed on d3js. I have added two filters for sorting the data. When I'm changing the filters I see the updated data in the console and the chart refreshes. But after each refresh, the earlier visualized chart still remains.
I have tried .remove() and .exit from d3. These didn't seem to work.
Here's the link for my code in codesandbox: https://codesandbox.io/s/5x6qkjw6kp
Quick Answer
The way you have your code setup, you are calling the whole heatmap creation function every time a filter changes, so you're reading data, axes, everything again. Based on that, you could easily clear all elements on the chart and have them recreated from scratch, rather than using the true enter, exit, update pattern, by putting this line before you define your chart.
d3.select(".chart").selectAll("*").remove();
So your code will now look like
//Setting chart width and adjusting for margins
d3.select(".chart").selectAll("*").remove();
const chart = d3
.select(".chart")
.attr("width", width + margins.right + margins.left)
.attr("height", height + margins.top + margins.bottom)
.append("g")
.attr(
"transform",
"translate(" + margins.left + "," + margins.top + ")"
);
Enter Exit Update
This section has been heavily edited, but looking through the code, quite a lot of changes would have to be made to adapt it to make it use Enter/Exit/Update type processes. Think about putting the main creation steps at the start of the chart creation outside of the function, as these only need to run once at load (titles, axes, things like that). Clicking new elements would then not recreate the whole chart, but just alter the dataset used to create the rect objects.
This works by removing all elements which are children of the main chart group before the chart is recreated.
Hope that makes sense, let me know if anything is unclear and I'll tidy it up!

Scale / Redraw d3.js gridlines on zoom / drag

I just started using d3.js yesterday and i have some trouble getting my stuff done.
For now I created a chart with two y axes, each showing some values and an x axis showing dates.
On click on the values on the y axes, I display the corresponding horizontal grid lines.
My problem is, that when zooming in or out, or dragging, the gridlines (horizontal and vertical) don't scale correctly with the axes values, they just don't move at all.
I searched a lot this afternoon and found some examples how to do it, but none of them seem to work with the code i already have.
I presume, that the logic should be added to the zoom behavior but i'm not sure
// x axis gridlines
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// add the X gridlines
let xGrid = svg.append("g")
.attr('class', 'grid')
.attr("id", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
//zoom behavior
function zoomed() {
.. some behavior ..
//redraw gridlines here?
.. some behavior ..
}
Please see this fiddle for the whole thing.
I called the second y axis (right) zAxis even if it's not a z axis.
Help would really be greatly appreciated.
The axes are working when you zoom. That's because, in the function zoomed() you are updating the scales.
So in order to make the grids zoom, you just need to update its scales too. Put this code inside the function zoomed() and it should work.
xGrid.call(
d3.axisBottom(x)
.scale(d3.event.transform.rescaleX(x))
.ticks(5)
.tickSize(-height)
.tickFormat("")
)
Now you just need to replicate this scale update to all other grids. Sorry that I couldn't give you a complete answer, but I don't have much time right now.
Now, in my opinion, you should not have the function make_gridlines() because it is really simple, and when you're working on lots of updates on different places it confuses me.
So, instead of calling make_gridlines() you call d3.axisBottom(x).ticks(5).
(Note that I'm new to d3 and js, so I'm recommending this based on my little experience and knowledge)

How to fix the d3 object?

I tried http://bl.ocks.org/godds/ec089a2cf3e06a2cd5fc
However, I found when I used the brush, the main part of the stacked bar is out of boundary. How to fix it?
I think here is the reason:
some bars should not be shown in the main part but they are still in the scope of svg
Thank you for your help!
These types of zoom literally are just geometric zooms, all the bars are still being drawn, it's just that the vast majority are off-screen, some are within the chart limits and a few lie in the axis gap in-between which are the ones that look awkward.
Make a svg clip, and add it to the right 'g' element to get rid of this effect:
svg.append("defs").append("clipPath")
.attr("id", "myclip")
.append ("rect")
.attr({x: 0, width: width, y: margin.top, height: height});
... and later on in the code
// draw the bars
main.append("g")
.attr("clip-path", "url(#myclip)")
.attr("class", "bars")

Updating D3.js graph on mouseover event

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.

How do I modify ticks and format labels on D3 axes?

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.

Categories

Resources