NVD3.js x-axis multiChart labels aligned on multiple lines but not multiple bars

This question is about NVD3.js. x-axis multiChart labels are bound to rows but not columns

I am using NVD3.js multiChart to show several lines and several bars on a chart. Everything works fine, but the labels on the x axis are aligned only with line points, not with stripes. I want to correctly align the labels directly below the columns , as follows. But I get the following:

x-axis labels is not aligned to bars

As you can see, the x axis (example, 2014-February) is not aligned with the Bars .

1) How to align x axis labels to rows and rows at the same time ?

2) I need this solution for NVD3.js or how to integrate correctly.

I did jsFiddle: http://jsfiddle.net/n2hfN/28/

Thanks!

+6
source share
5 answers

The problem is that nv.models.multiChart uses linear scale for its x axis, and then when it draws the columns, it calls nv.models.multiBar , which uses ordinal scale with .rangeBands() .

You can track this mess through the source code:

First, consider multiChart.js

HERE is where the x-scale sets the linear scale.

HERE it calls the nv.models.multiBar model to create bars.

If we jump to look at multiBar.js

HERE it creates an ordinal scale, and HERE sets the scale range using .rangeBands()

As a result, the ordinal scale used to place the bars and the linear scale used for the axis of the chart are not aligned. Here, which two scales look on their own if they are plotted along the axis:

d3 ordinal vs linear scale

The solution would be to make the chart display line graphs and the x axis in terms of the ordinal scale used by the bars. This will work in your case, because the bars and lines use the same data for the x axis. It is very simple to do if you create your own schedule and do not rely on nvd3, as I showed in my answer to your previous question HERE . This is extremely difficult to do if you are trying to work in nvd3, and many others have tried and failed to disable the default scales used by nvd3 diagrams. See this issue on the nvd3 github page , which has been open since January 2013, for example.

I tried using several approaches to reuse the ordinal scale of the bars, but with little success. If you want to orient yourself and try to reinstall it yourself, I can tell you that from my experiments I came closer when I used chart.bars1.xScale().copy() to make a copy of the bar scale and set its range of domains and ranges . Unfortunately, since the width of the chart is calculated during rendering, and I cannot create a hook in the chart.update function, it is not possible to set the rangeBands correctly.

In short, if you cannot live with label offsets, you will probably need to copy your own chart without nvd3 or find another type of layout for your visualization.

+10
source

After playing the NVD3 v1.7.1 source code with a very useful guide offered by jshanley answer, I think I managed to find an answer (maybe more than a good solution).

  • What I did was align the labels on the x axis with the stripes and align the data points of the line with the stripes.

    1.1. To align the X axis label, I moved the x axis to the right so that the first label appears below the middle of the first bar. Then I moved the last label to the left so that it appears below the middle of the last bar. See the code here . The amount that needs to be shifted is calculated while drawing using .rangeBand() and stored in the rbcOffset variable (I had to change multiBar.js to make it work).

    1,2. A similar shift is required to align the data points of the line with the stripes. Fortunately, this part is simple, because scatter.js (which is used by the line chart) has the logical variable padData , which does what we want. So basically, I just set padData to true and the lines are shifted to align them with bars, see here .

  • In order to integrate correctly with NVD3 and do everything well, some additional changes are needed. I forked NVD3 on GitHub so you can see the complete solution. Of course, contributions are welcome.

+4
source

I am using the latest solution and it is being implemented. So you can specify

lines1.padData(true)

to align the lines.

+3
source

The same thing here, I used the last solution, it worked for me as well. Find the following line in the multiChart.js file

 if(dataLines1.length){ lines1.scatter.padData(true); // add this code to make the line in sync with the bar d3.transition(lines1Wrap).call(lines1); } 
0
source

I ran into the same problem and fixed it using the code below:

in lines 7832 and 7878 replace

 .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; }) 

with:

 var w = (x.rangeBand() / (stacked && !data[j].nonStackable ? 1 : data.length)); var sectionWidth = availableWidth/(bars.enter()[0].length - 1); if(bars.enter().length == 2) return 'translate(' + ((i-1)*w + i*w + (i*(sectionWidth - 2*w))) + ',0)'; else return 'translate(' + ((i-0.5)*w + i*(sectionWidth - w)) + ',0)'; 

The first case handles a case with several bars, and the second handles a case with one bar.

0
source

Source: https://habr.com/ru/post/971905/


All Articles