I have one long unixtime, value Array which is used to initiate a flot chart, and some buttons to change the scale, what I can't seem to be able to do is get Y-axis to scale with the change in X-scale.
Here is an example chart:
http://jsfiddle.net/U53vz/
var datarows = //Data Array Here
var options = { series: { lines: { show: true }, points: { show: true } },
grid: { hoverable: true,clickable: false, },
xaxis: { mode: "time", min: ((new Date().getTime()) - 30*24*60*60*1000), max: new Date().getTime(), }
};
function castPlot() {
window.PLOT = $.plot("#placeholder", [{ data: dataRows }], options
);
};
In the official example scaling is automatic and unspecified on the Y-axis:
http://www.flotcharts.org/flot/examples/axes-time/index.html
The only alternative I can think of is looping through the dataset and calculating new Y min/max on each button press. Unless I am breaking some very obvious default function.
When calculating y-scale, flot does not look at only the "viewable" data but the whole dataset. Since the data points are still present, the y min/max respects them. So your options are:
Subset the series data down to the desired range and let flot scale both x and y.
As you suggested, calculate your own min/max on the y axis.
If you plot get any more complicated than it is now (especially if you start setting up click/hover events on it), I would also recommend you switch to redrawing instead of reiniting your plot.
var opts = somePlot.getOptions();
opts.xaxes[0].min = newXMin;
opts.xaxes[0].max = newXMax;
opts.yaxes[0].min = newYMin;
opts.yaxes[0].max = newYMax;
somePlot.setupGrid();
somePlot.draw();
EDITS
Here's one possible solution.
Related
I am wondering if it is possible to set the value of a series to always be the top of the current chart, more or less like using plotBands or plotLines.
For example, I would love to have a series like: [1,1], [1,yAxis.top] ...
Is that possible?
Yo do not know what is an axis max until you set it or let the Highcharts calculate it. I assume that you do not want to set axis.max, so you need to wait until the Highcharts sets axis max and then add a max point dynamically. You can use a load event to achieve that.
chart: {
events: {
load: function () {
const axis = this.yAxis[0]
const max = axis.max
const series = this.series[0]
axis.update({ max })
series.addPoint(axis.max, true, false, false)
}
}
},
example http://jsfiddle.net/qb2tn7jh/
I have series with simple integer values. So there is no need to have float numbers as y-axis labels.
I use the axisLabelFormatter to convert y to integers. But the result is, that I have duplicated integer values on the y-axis.
How can I get a y-axis, which is labeled only with single integers at the correct place?
I would like to have the secondary y-axis with a different grid too
See also the example at https://jsfiddle.net/eM2Mg/9559/.
I have tried your example, modified it and I have got this result
I have modified your code the next way
var graph2 = new Dygraph(document.getElementById("graph2"), data, {
axes: {
y2: {
axisLabelFormatter: function(y) {
return texts[y] || parseInt(y);
},
drawGrid: true,
independentTicks: true,
pixelsPerLabel: 100,
gridLinePattern: [2,2]
}
},
legend: "always",
series: {
"State": {
axis: "y2",
strokeWidth: 2,
stepPlot: true,
}
},
strokeWidth: 2,
title: "my try to get what I want"
});
I have set the option drawGrid and independentLabels to true.
It is necessary to adjust the pixelsPerLabel to the size you think the 3 values auto, on, off are better shown.
And the grid patterLine to show a different grid for the right y axis.
You can also remove the drawGrid if you consider it look better without the grid.
I hope this could be a solution for you! Regards!
In this jsfiddle the chart has a nice zoom effect every time the visiblity of a series is toggled.
But when I add the UpperLimit series this effect is lost because that series has the lowest and highest x-values.
How can I make the chart zoom in on the series of my choice and keep other series from affecting zoom boundaries?
{
name: 'UpperLimit',
color: '#FF0000',
dashStyle: 'ShortDash',
showInLegend: false,
//affectsZoomBox: false, //No such thing :(
data: [
[1, 100],
[10, 100]
]
},
I don't think it is possible using configuration of the series. However, if you are willing to hack a bit it will be possible to exclude one or more series from the calculation of axis extremes:
chart.xAxis[0].oldGetSeriesExtremes = chart.xAxis[0].getSeriesExtremes;
chart.xAxis[0].getSeriesExtremes = function() {
var axis = this;
var originalSeries = axis.series;
var series = [];
for (var i = 0; i < originalSeries.length; i++) {
// Filter out the series you don't want to include in the calculation
if (originalSeries[i].name != 'UpperLimit') {
series.push(originalSeries[i]);
}
}
axis.series = series;
axis.oldGetSeriesExtremes();
axis.series = originalSeries;
}
The code shows how to overwrite the getSeriesExtremes function on the axis object. The method is replaced with a wrapper that removes the series that should be excluded, then calls the original function and then restores the original series to the axis.
This is clearly a hack. However, it works on my machine...
I want to use a chartjs linechart to visualize my data points. Chartjs seems to animate the graph by default, but it does not animate the values on the x-axis. The x-axis only move in discrete steps.
Is there any way to enable animation on the axis also?
Thanks!
As far as I am aware, ChartJS does not support x-axis animation out-of-the-box. So you'll have to hack it. There are several ways to possibly do this, but the following methods seems to work.
If You Want to Animate the Data On the X-Axis
When a chart is updated, the following steps occur: 1) The axes are drawn, and then 2) a draw() function is called to draw the data. There are different draw() functions for different chart types, and the function for line charts is Chart.controllers.line.prototype.draw. The draw() functions take one argument, which I will call animationFraction, that indicates how complete the animation is as a fraction. For instance, if an animation is 5% complete, animationFraction will be 0.05, and if an animation is 100% complete (i.e. if the chart is in its final form), animationFraction=1. The draw() function is called at each step of the animation to update the data display.
One hack to animate the x-axis then is to monkey-patch the line chart draw() function to translate the canvas in the horizontal dimension at every draw step:
var hShift = (1-animationFraction)*ctx.canvas.width;
hShift is the horizontal shift in pixels of the chart. As defined above, the data will sweep in from the right; if you want it to sweep in from the left, you can make the above negative. You then save the canvas context state, transform the canvas using hShift, draw the chart data, and then restore the canvas to its original state so that on the next animation frame the axes will be drawn in the correct spot:
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift, 0);
ctx.oldDraw.call(this, animationFraction);
ctx.restore();
In the above, this refers to the chart object, and oldDraw refers to the original line chart drawing function that was saved previously:
var oldDraw = Chart.controllers.line.prototype.draw;
You can additionally setup your new draw() function to read new animation options that allow you to set whether the x-axis and y-axis are animated:
var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
var animationConfig = this.chart.options.animation;
if (animationConfig.xAxis === true) {
var ctx = this.chart.chart.ctx;
var hShift = (1-animationFraction)*ctx.canvas.width;
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift,0);
if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
ctx.restore();
} else if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
}
You can then create a line chart with both axes animated with:
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});
See https://jsfiddle.net/16L8sk2p/ for a demo.
If You Want to Animate the X-Axis Limits
If you want to animate the x-axis limits--i.e. move the data, axis ticks, and tick labels, then you can use the following strategy. It's a bit quirky, so it might take some effort to work out the kinks for any given use-case, but I believe it should work generally. First, you'll need to convert the line plot to a scatter plot. Line charts have categorical x-axes that move in steps, so you can't set the axis limits to be between ticks, which is what you'll need to do to get the animation. So you'll need to use a line scatter plot instead, since scatter plots can have arbitrary axis limits. You can do this by numbering each data point, and assigning that number to the x-value for that data point. For instance, to generate a random dataset, you could do:
var DATA_POINT_NUM = 58;
var data = {
labels: [],
datasets: [
{
data: [],
},
]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
data.datasets[0].data.push({ x: i,
y: Math.random()*10
});
data.labels.push(String.fromCharCode(65+i));
}
You'll then need to write a function to convert between the assigned x-values of your data points, and the data point labels (i.e. the categories that will be on the charts x-axis):
function getXAxisLabel(value) {
try {
var xMin = lineChart.options.scales.xAxes[0].ticks.min;
} catch(e) {
var xMin = undefined;
}
if (xMin === value) {
return '';
} else {
return data.labels[value];
}
}
where lineChart is our Chart object, which will be defined below. Note that ChartJS draws the chart slightly differently if there's a label at x-axis's minimum value, so you'll need to write this function to return an empty string if the value==the minimum value of the x-axis. You can then define the Chart object:
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: false,
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
ticks: {
min: 0,
max: 10,
callback: getXAxisLabel, // function(value) { return data.labels[value]; },
autoSkip: false,
maxRotation: 0,
},
}]
}
}
});
ticks.callback is set to our getXAxisLabel function above. When ChartJS draws the x-axis, it will pass the x-values of the data points to the callback function and then use the resulting string as the value on the x-axis. In this way, we can draw a scatter chart like a line chart. I've also set autoSkip=false and maxRotation=0 to make sure the axis labels get drawn in a consistent way.
You can then animate the chart by adjusting the x-axis ticks.min and ticks.max values and calling the chart's .update() method. To illustrate this, the code below scans along the charts x-axis, showing ten data points at a time.
var xMin = 0; // Starting minimum value for the x-axis
var xLength = 10; // Length of the x-axis
var animationDuration = 5000; // Duration of animation in ms
// Calculate animation properties
var framesPerSec = 100;
var frameTime = 1000/framesPerSec;
var xStep = (DATA_POINT_NUM-xMin+xLength)/(animationDuration/1000*framesPerSec);
function nextFrame() {
var xMax = xMin+xLength;
if (xMax < DATA_POINT_NUM-1) {
if (xMax+xStep > DATA_POINT_NUM-1) {
xMax = DATA_POINT_NUM-1;
xMin = xMax-xLength;
}
lineChart.options.scales.xAxes[0].ticks.min = xMin;
lineChart.options.scales.xAxes[0].ticks.max = xMax;
lineChart.update();
setTimeout(nextFrame, frameTime);
xMin += 0.1;
}
}
nextFrame();
Putting it all together: https://jsfiddle.net/qLhojncy/
I am no expert in javascript but I found an example for Chartjs that, when inserted a new data point, updates the x-axis via animation as it seems, maybe it helps you: example.
Example source: sitepoint.com
I want to plot a graph with the following as the xaxis:
var xaxis = [31.1,31.2,31.3,31.4,31.5, 32.1,32.2,32.3,32.4,32.5];
notice how there is a skip between 31.5 and 32.1. However, when I plot my line graph, there is a large space between these two points. Here's my code:
$(document).ready(function(){
var cust1 = [[31.1,10],[31.2,15],[31.3,25],[31.4, 60],[31.5,95]];
var cust2 = [[31.1,0],[31.2,15],[31.3,30],[31.4, 50],[31.5,85]];
var data = [];
data.push(cust1);
data.push(cust2);
var xaxis = [31.1,31.2,31.3,31.4,31.5, 32.1,32.2,32.3,32.4,32.5];
var plot3 = $.jqplot('line-chart', data,
{
title:'Design Progress',
axes: {
xaxis: {
//renderer: $.jqplot.LineRenderer,
label: 'Work Weeks',
ticks: xaxis
},
yaxis: {
label: "Percent Complete",
max: 100,
min: 0
}
}
}
);
});
I think it's because I'm not specifying a renderer option in my xaxis options. However, I've tried to use $.jqplot.LineRenderer and $.jqplot.CategoryAxisRenderer without any luck (I even set my xaxis values as strings but that didn't work). Anybody know what's going on?
Here's a pic to further clarify:
Reason why it happens : jQuery flot library is building the graph with values that determined by your data.
When you provide such data, the plugin will set the axis values to be as same as the text and with the borders of the numbers you gave.
what you can do, is set the text to be different than the axis value.
You can easily do it by options.xaxis.ticks.push([value, "the text"]).
Pay attention that you are the one who is going to set which label will have which axis value, and this calls for setting the options parameter before calling the $plot