I would like the graph to adjust itself according to 5 y axes for a chartsjs linear graph. As of now chartsjs adjusts the number of y axes after the data. I would like it to always be 5 and have the data adjust itself accordingly.
If we want to limit the minimum and maximum value for the y-axis then we can add the scales property to the options and set the yAxes property.
In the following example we are setting the minimum value for the y-axis to -10 and maximum value to 80 and we are also defining the stepSize of 10.
var options = {
scales: {
yAxes: [{
ticks: {
max: 80,
min: -10,
stepSize: 10
}
}]
},
};
I have a ton of data associated with time. I want to plot a, hopefully, simple line graph. A simplified example:
var data = [{ time: 13:30, size: 100 }, { time: 13:37, size: 500}, { time: 13: 42, size: 300 }
{ time: 13:51, size: 150 }, { time: 13:56, size: 175 }, { time: 15:59, size: 75 }
{ time: 16:11, size: 75 }, { time: 16:37, size: 125 }, { time: 15:27, size: 200 } [...]
{ time: 20:36, size: 500 }]
Many time values, and corresponding size values. Of course, I do not want to plot every single time value on this graph. Instead I want to take the lowest value, 13:30, then plot the time on the axes at 30 minute intervals (i.e. 13:30, 14:00, 14:30 ... 20:30) until I hit the latest time in my array of data. At the same time, I want to plot every size value. So, the graph will only display a tick for 13:30 and 14:00, but the values that correspond with 13.37, 13.42, 13.51, 13.56 will be plotted on the line.
How would I go about doing this?
My first attempt was something like this:
var graph = d3.select('.graph'),
WIDTH = 790,
HEIGHT = 250,
MARGINS = {
top: 20,
right: 20,
bottom: 20,
left: 50
}
xScale = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]),
yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([smallest, largest]),
xAxis = d3.svg.axis().scale(xScale),
yAxis = d3.svg.axis().scale(yScale).orient("left");
NB the "smallest" and "largest" variables are the smallest and largest size values in my data array, calculated elsewhere. Obviously this is wrong because this would plot every single time value on the axes (as explained above, I do not want this) and even if I did it errors and glitches horribly.
How would I go about achieving what I want to achieve?
Thx
-- Gaweyne
Solved it. d3.time.scale not d3.scale.linear()
xScale = d3.time.scale(range([MARGINS.left, WIDTH - MARGINS.right]).domain(new Date([//Earliest Date//]), new Date([//Latest Date//]))
My charts output dynamic data based on input filters. These can have 1 to 30 bars and they resize on screen resize/device. Just an example, currently where there's < 5 bars and the charts width is 1138px (max), then I have pretty big bars in width.
Q. How is this problem dealth with?
var options = {
xaxis: { ticks: ticks},
grid: { clickable: false, hoverable: true },
series: { stack: true, bars: {show: true,align: 'center',barWidth: 0.5,lineWidth: 2,fillColor: {colors: [{opacity: 0.9}, {opacity: 0.9}]}} },
legend: {container: ".widget-legend"}
};
Assuming you want to give your bars the same pixel width whether there are 1 or 30 bars, you can calculate the value for barWidth from the width of the chart (in x axis units and pixels, correcting for axes and margins) using cross-multiplication. A reasonable pixel width for up to 30 bars on 1100 pixels would be around 20 pixels per bar.
var chartWidthInPixels = 1100 * 0.95; // or $('#chart').width() * 0.95
var barWidthInPixels = 20; // or chartWidthInPixels / 50
var chartWidthInAxisUnits = (max(ticks) - min(ticks)) + 1; // this will be 1 for one bar
var barWidthInAxisUnits = barWidthInPixels * (chartWidthInAxisUnits / chartWidthInPixels);
For one bar with the above example values this gives around 0.019 for the barWidth. By variation of the constants in the formulas you can modify the calculation.
Note: Although this is a self-answered question, I am always curious about better approaches.
sin(x) and cos(x) for x in degrees.
Goal: I would like to adjust this initial plot and add a 2nd X axis to show both degrees and radians.
How do I set up jqPlot PlotOptions to add x and y labels, change scales, and add a second X axis?
I am using a JavaScript library that I wrote called html5csv [License: GPL] that support various data analysis operations and interfaces to jqPlot for plotting. It allows the specification of the jqPlot plotOptions object for each plot.
The (currently blank) plotOptions are on the first line of code. You may assume the plotOptions are correctly delivered to jqPlot by the subsequent code invoking CSV().jqplot() from the html5csv library.
html5csv + jqplot dual line graph without special axes
plotOptions = {};
CSV.begin('%F', {dim:[36,4],header:['deg','rad','sin','cos'],
func: function(i,j){
var deg = 10*(i);
var rad = deg*2*Math.PI/360.0;
if (j===0) return deg;
if (j===1) return rad;
if (j===2) return Math.sin(rad);
if (j===3) return Math.cos(rad);
}
}).
jqplot([['chart1',[['deg','sin'],['deg','cos']], plotOptions]]).
table('tab1',{header:1}).
go();
jsfiddle of single axes sine, cosine wave plot
This jqPlot documentation shows up to 2 X axes and 9 Y axes but when calling new Axis() I get Uncaught ReferenceError: Axis is not defined in the console. To fix this I tried adding more of the jqplot .js files to the script headers but it did not help.
jqplot Axis formatting options documentation shows all the options to configure axis labels, ticks, etc. for a particular axis if I could create one.
How do I proceed from here?
Don't call new Axis(); This is done for you internally in jqPlot.
Basically, if you declare the right keys in plotOptions, the Axis will be set up for you. But if the keys are missing or misnamed, it will obviously fail.
Here are the finished examples:
Part 1: Customized set of single axes
Output
jqplot PlotOptions Input
plotOptions = {
axes: {
xaxis: {
show: true,
label: 'deg',
min: 0,
max: 360,
tickInterval: 45
},
yaxis: {
show: true,
label: 'y',
min: -2.0,
max: 2.0
}
}
};
Note: You don't need to call new Axis, but you do need to name the object fields as shown.
plotOptions = {
axes: {
xaxis: {
show: true,
label: 'deg',
min: 0,
max: 360,
tickInterval: 45
},
yaxis: {
show: true,
label: 'y',
min: -2.0,
max: 2.0
}
}
};
CSV.begin('%F', {
dim: [36, 4],
header: ['deg', 'rad', 'sin', 'cos'],
func: function(i, j) {
var deg = 10 * (i);
var rad = deg * 2 * Math.PI / 360.0;
if (j === 0) return deg;
if (j === 1) return rad;
if (j === 2) return Math.sin(rad);
if (j === 3) return Math.cos(rad);
}
}).
jqplot([
['chart1', [
['deg', 'sin'],
['deg', 'cos']
], plotOptions]
]).
table('tab1', {
header: 1
}).
go();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/jquery.jqplot.css" />
<script src="https://cdn.rawgit.com/DrPaulBrewer/html5csv/7f39da16/html5csv.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/jquery.jqplot.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/plugins/jqplot.canvasAxisLabelRenderer.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/plugins/jqplot.canvasAxisTickRenderer.js"></script>
Part 2: Dual X axes, with degrees and radians scales
Output
jqPlot PlotOptions Input
plotOptions = {
axes: {
xaxis: {
show: true,
label: 'deg',
min: 0,
max: 360,
tickInterval: 45
},
x2axis: {
show: true,
label: 'rad',
min: 0,
max: 2 * Math.PI,
numberTicks: 9
},
yaxis: {
show: true,
label: 'y',
min: -2.0,
max: 2.0
}
}
};
plotOptions = {
axes: {
xaxis: {
show: true,
label: 'deg',
min: 0,
max: 360,
tickInterval: 45
},
x2axis: {
show: true,
label: 'rad',
min: 0,
max: 2 * Math.PI,
numberTicks: 9
},
yaxis: {
show: true,
label: 'y',
min: -2.0,
max: 2.0
}
}
};
CSV.begin('%F', {
dim: [36, 4],
header: ['deg', 'rad', 'sin', 'cos'],
func: function(i, j) {
var deg = 10 * (i);
var rad = deg * 2 * Math.PI / 360.0;
if (j === 0) return deg;
if (j === 1) return rad;
if (j === 2) return Math.sin(rad);
if (j === 3) return Math.cos(rad);
}
}).
jqplot([
['chart1', [
['deg', 'sin'],
['deg', 'cos']
], plotOptions]
]).
table('tab1', {
header: 1
}).
go();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/jquery.jqplot.css" />
<script src="https://cdn.rawgit.com/DrPaulBrewer/html5csv/7f39da16/html5csv.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/jquery.jqplot.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/plugins/jqplot.canvasAxisLabelRenderer.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.9/plugins/jqplot.canvasAxisTickRenderer.js"></script>
Notes: No need to call new Axis() here, either. Name the plotOptions keys properly and it works.
Plotting of data used the original single X coordinate using the 1st X axis.
Reference
From the jqPlot Axis docs:
Axes options are specified within an axes object at the top level of the plot options like so:
{
axes: {
xaxis: {min: 5},
yaxis: {min: 2, max: 8, numberTicks:4},
x2axis: {pad: 1.5},
y2axis: {ticks:[22, 44, 66, 88]}
}
}
There are 2 x axes, ‘xaxis’ and ‘x2axis’, and 9 yaxes, ‘yaxis’, ‘y2axis’. ‘y3axis’, ... Any or all of which may be specified.
Useful axis options excerpted from the documentation
Note: Additional options do exist. These are the most basic ones.
In a few of these I edited slightly for clarity.
show
true to display the axis on the graph.
label
Label for the axis
showLabel
true to show the axis label.
min
minimum value of the axis (in data units, not pixels).
max
maximum value of the axis (in data units, not pixels).
autoscale
true to Autoscale the axis min and max values to provide sensible tick spacing.
If axis min or max are set, autoscale will be turned off. The numberTicks, tickInterval and pad options do work with autoscale, although tickInterval has not been tested yet. padMin and padMax do nothing when autoscale is on.
ticks
1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis. If no label is specified, the value is formatted into an appropriate label.
numberTicks
Desired number of ticks. Default is to compute automatically.
tickInterval
number of units between ticks. Mutually exclusive with numberTicks.
showTicks
true to show the ticks (both marks and labels) or not. Will not override showMark and showLabel options if specified on the ticks themselves.
showTickMarks
true to show the tick marks (line crossing grid) or not. Overridden by showTicks and showMark option of tick itself.
syncTicks
true to try and synchronize tick spacing across multiple axes so that ticks and grid lines line up. This has an impact on autoscaling algorithm, however. In general, autoscaling an individual axis will work better if it does not have to sync ticks.
tickSpacing
A number giving approximate pixel spacing between ticks on graph. Used during autoscaling. This number will be an upper bound, actual spacing will be less.
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...