I have a chart in NVD3 with a date on the X axis and a float on the Y axis.
It displays fine, but when I hover over the chart to make the tooltip pop up, it doesn't show it for the dataset I'm currently hovering over. Here's a GIF to make it more clear, hopefully:
This is the code I've used:
<script>
var data = function() {
return [
{
values: [
{x:"2018-09-08", y:19.98},{x:"2018-09-07", y:11.99},{x:"2018-09-06", y:9.98},{x:"2018-09-05", y:4.99},{x:"2018-09-03", y:9.98},{x:"2018-09-02", y:14.99}, ],
key: 'Turnover'
}
];
}
nv.addGraph(function() {
var chart = nv.models.lineChart()
.useInteractiveGuideline(true)
.xScale(d3.time.scale())
.x( function(d){return d3.time.format('%Y-%m-%d').parse(d.x);} );
;
chart.xAxis
.axisLabel('Date')
.tickFormat(function(d) {return d3.time.format("%Y-%m-%d")(new Date(d))});
;
chart.yAxis
.axisLabel('Sales')
.tickFormat(d3.format('.02f'))
;
chart.showLegend(false);
d3.select('#nvd3 svg')
.datum(data())
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
</script>
Edit 1: When I do not use the .useInteractiveGuideline(true) function, it does work and the tooltip is presented on the correct set of data. However, I do want to use this function. So any help here?
Looking at the examples of the NVD3 site they work with a Linear Scale for time axis.
Converting the code to this too shows the requested behavior.
You have to set the tick positions yourself because the automatic ticks for a linear scale are not on dates
var data = function() {
return [
{
values: [
{x:"2018-09-02", y:14.99},
{x:"2018-09-03", y:9.98},
{x:"2018-09-05", y:5.99},
{x:"2018-09-06", y:9.98},
{x:"2018-09-07", y:11.99},
{x:"2018-09-08", y:19.98}
],
key: 'Turnover'
}
];
};
var formatDate = d3.time.format("%Y-%m-%d");
nv.addGraph(function () {
var chart = nv.models.lineChart()
.useInteractiveGuideline(true)
;
var mydata = data();
mydata[0].values.forEach(e => { e.x = Date.parse(e.x); });
chart.xAxis
.axisLabel('Date')
.tickFormat(function(d) {return formatDate(new Date(d))})
.tickValues(mydata[0].values.map( d => d.x ))
;
chart.yAxis
.axisLabel('Sales')
.tickFormat(d3.format('.02f'))
;
chart.showLegend(false);
d3.select('#nvd3 svg')
.datum(mydata)
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
Related
My chart has multiple Y-Axes that have different domains.
When I am dragging on the chart, only the last y-axis is being updated.
I added each y-axis like below;
addYAxis(data, tag) { // tag is for index for each y-axis e.g: 0, 1, 2
const yScale = d3.scale.linear()
.domain([0, this.innerHeight])
.range([this.innerHeight, 0]);
const yAxis = d3.svg.axis()
.scale(yScale)
.orient(tag ? 'right' : 'left')
.tickSize(tag ? this.innerWidth + 50 * (tag - 1) : -this.innerWidth);
const yAxisElement = this.g.append('g')
.attr('class', 'y axis')
.call(yAxis);
this.yAxisList.push({yScale, yAxis, yAxisElement});
}
Here is the zoom list for each axis.
this.zoom.push(d3.behavior.zoom()
.x(this.xScale)
.y(this.yAxisList[tag].yScale) // when I replace [tag] with [0], then only first axis is being updated.
.scaleExtent([.5, 10])
.scale(this.currentZoom)
.translate(this.currentPan)
.on('zoom', () => this.zoomed(tag))
.on('zoomend', () => {
setTimeout(() => { this.zooming = false; }, 10);
}));
this.g.call(this.zoom[tag]) // when I replace [tag] with [0], then only first axis is being updated.
.on('dblclick.zoom', null);
And update them like below;
updateYAxis() {
this.yAxisList.forEach(({yAxisElement, yAxis}) => yAxisElement.call(yAxis));
}
Structure of this chart:
How to update all Y-axes while dragging on the chart?
Here,
.on('zoom', () => this.zoomed(tag))
you only updated current zoom, but should update other zoom objects with the current zoom values as well.
.on('zoom', () => {
this.zoom.forEach((zoom, t) => {
zoom.scale(this.zoom[tag].scale());
zoom.translate(this.zoom[tag].translate());
this.zoomed(t);
});
})
I am new to Javascript and couldn't find error in my code.
I am using NVD3 charts here. It is a time series based chart with date and closing prices of a particular stock. Data ranges from 2005 till now.
Here is the code
var data= JSON.parse("Data.JSON")
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({top: 70, right: 70, bottom: 70, left: 70})
.useInteractiveGuideline(true)
.transitionDuration(100)
.showYAxis(true)
.showXAxis(true)
;
//Chart x-axis settings
chart.xAxis
.axisLabel('date')
.tickFormat(function(d) {return new Date((data.Date - (25567 + 1))*86400*1000);
chart.yAxis //Chart y-axis settings
.axisLabel('close')
.tickFormat(d3.scale.linear(data.Close));
d3.select('#Charts svg') //Selecting the <svg> element where i want to render the chart in.
.datum(data) //Populating the <svg> element with chart data...
.call(chart); //Finally, rendering the chart!
//Update the chart when window resizes.
})
;
//Data
{
"Date": [13089, 13094, 13095, 13096, 13097, 13098, 13101, 13103, 13104, 13105, 13108, 13109, 13110]
"Close": [ 2419.1, 2461.6, 2492.7, 2489.1, 2500.7, 2548.7, 2558.7, 2582.8, 2603.9, 2620.1, 2602.5, 2572.8]
}
The number of array elements in "Close" are less compared to "Date".
Here is a possible solution that you might be looking for:
nv.addGraph(function () {
var chart = nv.models.lineChart();
chart.xAxis.axisLabel('date')
.tickFormat(d3.format(''));
chart.yAxis.axisLabel('close')
.tickFormat(d3.format(''));
d3.select('#dateChart')
.datum(chartData())
.transition().duration(500)
.call(chart);
nv.utils.windowResize(function () {
d3.select('#dateChart').call(chart)
});
return chart;
});
function chartData() {
var myData = {
"Date": [13089, 13094, 13095, 13096, 13097, 13098, 13101, 13103, 13104, 13105, 13108, 13109, 13110],
"Close": [2419.1, 2461.6, 2492.7, 2489.1, 2500.7, 2548.7, 2558.7, 2582.8, 2603.9, 2620.1, 2602.5, 2572.8, 2588.8]
//The number of array elements in Close were less compared to Date. Hence added 2588.8 as the last element
};
var result = [];
for (var i = 0; i < myData.Date.length; i++) {
result.push({
x: myData.Date[i],
y: myData.Close[i]
});
}
return [{
values: result,
key: 'Date Chart',
color: '#ff7f0e'
}];
}
JS Fiddle: https://jsfiddle.net/m7oaxjue/3/
I am trying to customize the x-axis label for a line plot with NV D3 but all I get is the iteration from 0 - N
Here's my code
for(var i = 0;i< numberBins;i++){
valuesForD3.push({x:parseFloat(histogramObject['min']) + parseFloat(i * histogramObject['binWidth']),
y:histogramObject['values'][i]
});
}
chart = nv.models.lineChart()
.options({
margin: {left: 50, bottom: 40},
x: function(d,i) { return i},
showXAxis: true,
showYAxis: true,
transitionDuration: 100
});
d3.select('#chart1 svg')
.datum([{values:valuesForD3,key:'Score values',color:'#2222ff'}])
.call(chart);
Looking at their examples (where's the documentation!), you can customize the ticks like:
chart.xAxis
.tickFormat(function(d) {
return d.someTickLabel;
});
Here's a quick example.
I'm trying to get two lines to use two different scales.
When I try to toggle a plot, the grid lines disappear, instead of the plot.
Can you figure out what I'm doing wrong?
http://jsfiddle.net/3ZP3S/
var dataset1 = {
values : [],
key : "Math.cos",
type: "line",
color: '#2ca02c',
yAxis: 1
};
var dataset2 = {
values : [],
key : "sin",
type: "line",
color : "#ff7f0e",
yAxis: 2
};
for (var i = -3.14; i < 3.1415; i+= .01){
dataset1.values.push( { x: i , y : Math.cos(i) });
dataset2.values.push( { x: i , y : Math.sin(i) * 3 });
}
var data = [dataset1, dataset2];
nv.addGraph( function() {
var chart = nv.models.multiChart()
.margin({top: 30, right: 60, bottom: 50, left: 70})
.color(d3.scale.category10().range());
chart.xAxis
.tickFormat(d3.format(',.2f'));
chart.yAxis1
.tickFormat(d3.format(',.1f'));
chart.yAxis2
.tickFormat(d3.format(',.1f'));
d3.select('#chart svg')
.datum(data)
.transition().duration(500).call(chart);
return chart;
});
This was a bug with nvd3. I tried several "previous" versions of nvd3, and d3, and this always occurred.
We also decided to drop nvd3 and switch to C3.js, which seems to be "much" more mature in terms of stability...
I would like to change the XTick format of the small chart to also be a date. I have the following which is lifted from this example:
function chart(div)
{
var testdata = loadData();
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart();
chart.xAxis.tickFormat(function(d) {
var dx = testdata[0].values[d] && testdata[0].values[d].x || 0;
return d3.time.format('%x')(new Date(dx))
});
chart.yAxis
.tickFormat(d3.format(',.2f'));
chart.y2Axis
.tickFormat(d3.format(',.2f'));
d3.select(div + ' svg')
.datum(loadData())
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
}
But only the large chart's format changes to date.
There are two ways of fixing the ticks for the second x-axis.
The first way is by setting the tickFormat explicitly for the second axis as well. This design follows the traditional paradigm of setting one attribute at a time.
var xFormat = function(d) {
var dx = testdata[0].values[d] && testdata[0].values[d].x || 0;
return d3.time.format('%x')(new Date(dx));
};
chart.xAxis.tickFormat(xFormat);
chart.xAxis2.tickFormat(xFormat);
The second way, which would avoid code duplication, is setting both the axis together using a special function exposed by the chart API:
// This would set both the axis simultaneously
chart.xTickFormat(xFormat);
This function is present in the code (introduced here) for exactly this purpose. However, as the API is not very stable, it might be removed later.