score:5
There is really no need to interpolate your values. You actually can modify the scale of most nvd3 charts, including multiBarCharts, although there is some extra work that needs to be done to make it work.
The basic thing you need to do is this:
var xScale = d3.time.scale();
chart.multibar.xScale(xScale);
Then that should just work! Except it doesn't, because the multiBarChart assumes that the xScale is d3.scale.ordinal()
. So you will need to fake being that type by setting xScale.rangeBands
and xScale.rangeBand
:
xScale.rangeBands = xScale.range;
xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * SOME_VALUE };
The problem now is getting SOME_VALUE. This needs to equal the width of an individual bar, which depends on two things: the width of the whole chart and the number of ticks there would be, including the zero values that are missing in the data.
Here's how nvd3 gets the available width internally:
var container = d3.select('#chart svg'),
availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
However, if the window resizes, you will need to refresh this value:
nv.utils.windowResize(function() {
availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
});
As for getting the number of ticks, this depends solely on your data. In your case, there will be 11 ticks: every year between 2001 and 2011. So we'll go with that. Therefore, the entire scale definition looks like this:
var container = d3.select('#chart svg'),
availableWidth,
numTicks = 11,
xScale = d3.time.scale();
function updateAvailableWidth() {
availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
}
updateAvailableWidth();
nv.utils.windowResize(updateAvailableWidth);
xScale.rangeBands = xScale.range;
xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * availableWidth / numTicks; };
chart.multibar.xScale(xScale);
Finally, you need to set your xDomain manually. If you did this with the ordinal scale it had before, it would fail, but with a linear time scale it will work excellently:
chart.xDomain([new Date().setFullYear('2001'), new Date().setFullYear('2011')]);
Putting it all together, here is your example code (pasteable into http://nvd3.org/livecode/#codemirrorNav):
nv.addGraph(function() {
var chart = nv.models.multiBarChart(),
container = d3.select('#chart svg'),
availableWidth,
numTicks = 11,
xScale = d3.time.scale();
function updateAvailableWidth() {
availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
}
updateAvailableWidth();
nv.utils.windowResize(updateAvailableWidth);
xScale.rangeBands = xScale.range;
xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * availableWidth / numTicks; };
chart.multibar.xScale(xScale);
chart.xDomain([new Date().setFullYear('2001'), new Date().setFullYear('2011')]);
chart.xAxis
.tickFormat(function(d){ return d3.time.format('%y')(new Date(d)); });
chart.yAxis
.tickFormat(d3.format(',f'));
chart.reduceXTicks(false);
chart.showControls(false);
var data = [{
'key': 'GB by year',
'values': [
{x: new Date().setFullYear('2001'), y: 0.12},
{x: new Date().setFullYear('2004'), y: 0.03},
{x: new Date().setFullYear('2005'), y: 0.53},
{x: new Date().setFullYear('2006'), y: 0.43},
{x: new Date().setFullYear('2007'), y: 5.5},
{x: new Date().setFullYear('2008'), y: 9.9},
{x: new Date().setFullYear('2009'), y: 26.85},
{x: new Date().setFullYear('2010'), y: 0.03},
{x: new Date().setFullYear('2011'), y: 0.12}
]
}];
container.datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
score:5
You can do this in 2 ways:
A) You either rewrite the axis component of nvd3 to use d3.time.scale() / make another axis component for this use case...
Or the easiest way:
B) You use the custom values for the axis. First of all you use the + operator ( +(date) ) to have the values in ms. There is a tickValues function in d3 that allows you to pass custom values for the ticks.. To force the X scale you have the forceX() method from the scatter (I assume you already know about this) and you write a simple function that takes custom values for ticks.... So if you force your scale to have values between Jan 1 2002 and Dec 31 2012 and then decide to have 4 ticks you can use either ticks directly or tickValues...
So it goes like this (add something similar to the multiBarChart.js file):
lines.forceX(minValue, maxValue) //where minValue and maxValue are the values
//converted to ms already after you did +(date)
//then you just rewrite the ticks - if you want a custom number of ticks you can do it like this
//numberOfTicks is a method I added to the axis component (axis.js) to give the number of ticks the user would like to have
//x.domain() now contains the forced values instead of the values you initially used..
var maxTicks = xAxis.numberOfTicks()-1, xMin = x.domain()[0], xMax = x.domain()[1],
xDiff = (xMax - xMin)/maxTicks, tickInterval = [];
tickInterval[0] = xMin;
for(i=1; i<maxTicks; i++){
var current = xMin + i*xDiff;
tickInterval[i] = current;
}
tickInterval[maxTicks] = xMax;
//tickInterval already contains the values you want to pass to the tickValues function
xAxis.tickValues(tickInterval);
Hope this helps... I know it's hack but it worked in my case :) And of course if you already formatted the date to be displayed as year you will get the values for the years when displaying the ticks :)
This is how I did it for lines. For multiBarChart you will need to add an extra step: you need to deal with the reduceTicks functionality (set it to false, delete that part of the code, do whatever you like with it...)
score:12
Based on the above answer, you can do this with numeric x values (not Date objects) as well as a forced X range and specified tickValues.... for certain types of charts.
Bar charts do not seem to have the capability, however nvd3.lineCharts do what you'd like. The multiBarChart model does not allow the use of the forceX function to be applied (right now, ever?).
A solution to your problem would be to fill in the 0's or to use a sequential chart type (e.g. lineChart)
nv.addGraph(function() {
var chart = nv.models.lineChart()
.forceX(2001,2011);
var tickMarks = [2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011]
chart.xAxis
.tickValues(tickMarks)
.tickFormat(function(d){ return d });
chart.yAxis
.tickFormat(d3.format(',f'));
var data = [{
'key': 'GB by year',
'values': [
{x: 2001, y: 0.12},
{x: 2004, y: 0.03},
{x: 2005, y: 0.53},
{x: 2006, y: 0.43},
{x: 2007, y: 5.5},
{x: 2008, y: 9.9},
{x: 2009, y: 26.85},
{x: 2010, y: 0.03},
{x: 2011, y: 0.12}
]
}];
d3.select('#chart svg')
.datum(data)
.transition().duration(500).call(chart);
nv.utils.windowResize(chart1.update);
return chart;
});
Source: stackoverflow.com
Related Query
- how to set the domain and scale on an axis on a nvd3.js multiBarChart
- How to set the domain and scale on an yaxis on a discreteBarChart nvd3.js
- How to set domain to avoid overlapping dots and axis in d3 plot?
- nvD3 - multiBarChart - How to start from 0 and how to change the shape of controls
- How do I prevent graph elements from reaching the axis of my graph in D3 and scale properly?
- How can I get the D3.js axis ticks and positions as an array?
- D3: Create a continuous color scale with many strings/inputs for the range and dynamically changing values of the domain
- D3js: How do I clear the zoom scale set by the d3.zoom event?
- D3: How do I set "click" event and "dbclick" event at the same time?
- How to set a nvd3 axis to use strings instead of numerical values ?
- With D3, how can I set attribute ("fill", "none") of axis path and line, but not text (without editing stylesheet)
- How to make the NVD3 discreteBarChart labels on the X axis to adapt to the width or to the number of labels?
- D3: How to remove tick marks at the top and bottom of Y axis
- How to modify axis labels in d3 for a stacked bar chart when the axis labels are mapped as part of the scale's domain
- How to get the boundaries of currently visible time scale (after panning and zooming)?
- how to draw nvd3 simple barchart with x and y axis in angularjs
- NVD3 how set y scale correctly?
- How to set the label for each vertical axis in a parallel coordinates visualization?
- D3 word-cloud: how to auto size the font so words will not run out , and to scale words to all the screen?
- How to remove the comma in D3 axis ticks and remove the last tick?
- D3.js how to get the position/offset of x and y axis
- How to set intersection point of x and y axis
- How to increase the space between axis and axis label?
- D3, Scale How to set the scale?
- Multiple NVD3 charts on page. How to simplify the javascript code and wrap function?
- How to get the minimum and maximum value between a given range in data set in d3.js
- How to have the same scale in both x and y
- How to scale an integer to date with range and domain
- How to make axis "smart" and "flexible" so that the starting/end points on axis are sensible in D3 V4?
- How to normalize data in d3 and plot the lines in the axis independent of other line ranges
More Query from same tag
- D3.js: Trying to build flat calendar
- Struggling to get a chart with modified JSON format
- Getting a bunch of `NaN` when trying to make multiline chart in D3
- D3 trim hierarchical data by depth?
- How to draw a JSON list in D3.js?
- CSS3 - Transform-origin not working on SVG element in d3.js
- D3 datamaps changing border width on mouseover
- How to add popup on D3.js visualization (tree nodes)
- How do I assign ticks to be equal to a different key value from the same object from the one on which the axis is based on in D3.js?
- d3js grouped bar chart, is this possible?
- Breaking D3 in separate HTML, JS and CSS files not working
- Background image not applying to one div on Chrome for Mac
- How to create a beeswarm plot with variable radius in d3js v5?
- using php output in the javascript variable gives Cannot read property 'forEach' of undefined error
- How to access the inner array resulting from d3.groups?
- how to highlight over lap beetween rectangles in d3 js
- How can i convert sunburst graph as a Directive to use with angularjs?
- Zoom for graph in D3
- Binding javascript (d3.js) to shiny
- NVD3 time formatting , line with focus chart
- How to loop through JSON file using jQuery
- Change the data used in a force layout
- Transitioning basis line to linear line shortens/hide part of the line
- Using D3 to make a colored force layout
- How to specify an "id" for a path in Nvd3
- Cannot Clear React D3 Component Error for BarChart: "Cannot read property 'map' of undefined"
- Zoom to bounding box of path on externally loaded svg using D3
- Dcjs cursor and tooltips
- D3.js WordCloud: Words overlap and have weird spacing & distribution
- call an ASP.net (not MVC) webmethod and get a json response, so I can then iterate through a list with foreach (of d3.js)?