Plotting time with flot, json series - javascript

JSON data is not being plotted?
Javascript:
var datasets = JSON.parse(xmlhttp.responseText);
alert(JSON.stringify(datasets[0]));
var plotarea = $("#placeholder");
$.plot(plotarea, [[datasets[0].points]], {
xaxis: {
mode: "time",
min: (new Date(2013, 11, 1)).getTime(),
max: (new Date()).getTime()
}
});
Outputs:
{"name":"Test.txt","points":[[1389313796000,2],[1389314796000,4]]}
Rendered graph:

You've got one too many sets of [ ] on the data argument in your plot call. Should be:
$.plot(plotarea, [datasets[0].points], {
Fiddle here.
Even with that fixed though, your "plot" is just a vertical line on the right grid border.

Related

how to plot multiple time series in chartjs where each time series has different times

I have two time series for example:
s1:
2017-01-06 18:39:30 100
2017-01-07 18:39:28 101
and
s2:
2017-01-07 18:00:00 90
2017-01-08 18:00:00 105
I want to plot these in a Chartjs chart, however it seems that Chartjs only takes one x-axis array (or label in Chartjs terminology).
So my question is what is the best way to plot both of these?
My approach was to write a function (in python, although the language doesn't really matter for this part) that iterates through both time series and creates 3 new arrays which is in the format apparently Chartjs needs based off the 1st example here: https://www.sitepoint.com/introduction-chart-js-2-0-six-examples/
The algorithm (in sudo code) goes like:
# inputs are initial time series s1 and s2
y1 = [] # to hold new s1 data values
y2 = [] # to hold new s2 data values
x = [] # to hold times
# iterate through longest series s1 or s2
if s1[idx].time > s2[idx].time
x.append(s1[idx].time)
y1.append(s1[idx].data)
# y2 appends the linear interpolation of
# of closest y2 points
if (s1[idx].time < s2[idx].time)
x.append(s2[idx].time)
# opposite of above. ie. swap y1<->y2, s1->s2
else # they have the same time
x.append(s1[idx].time)
y1.append(s1[idx].data)
y2.append(s2[idx].data)
There are a couple other conditional checks for when data runs out of the shorter series but that is the main logic. After which I have 3 arrays that I can now add to chart js via one time/label array/x-axis and two data arrays. However this seems WAY more complicated than it should be considering how common I assume this use case is. Any help or advice is greatly appreciated.
In ChartJS, label is a Category Cartesian Axis. Since you mentioned linear interpolation in your code, I assume the strings like 2017-01-06 18:39:30 are not categories, they represent the numeric values of the x-axis. So we need to inform ChartJS that the strings in the x axis are actually time. We do this in the scale options.
var s1 = {
label: 's1',
borderColor: 'blue',
data: [
{ x: '2017-01-06 18:39:30', y: 100 },
{ x: '2017-01-07 18:39:28', y: 101 },
]
};
var s2 = {
label: 's2',
borderColor: 'red',
data: [
{ x: '2017-01-07 18:00:00', y: 90 },
{ x: '2017-01-08 18:00:00', y: 105 },
]
};
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: { datasets: [s1, s2] },
options: {
scales: {
xAxes: [{
type: 'time'
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<canvas id="myChart"></canvas>
You can find more information in Chart.js documentation.
You can have data of the form [{x:"value", y:"value"}] when your graph is of type scatter.
So to make your graph work, do this.
var canvas = document.getElementById("graph");
var s1 = [{x:"2017-01-06 18:39:30",y:"100"},{x:"2017-01-07 18:39:28",y:"101"}];
var s2 = [{x:"2017-01-07 18:00:00",y:"90"},{x:"2017-01-08 18:00:00",y:"105"}];
var graphParams = {
type:"scatter",
data:{
datasets: [{
label:"Series 1",
data:s1,
borderColor:"red",
backgroundColor:"transparent",
},
{
label:"Series 2",
data:s2,
borderColor:"blue",
backgroundColor:"transparent",
}],
},
options:{
maintainAspectRatio:false,
responsive:false,
scales:{
xAxes:[{
type:"time",
distribution: "series",
}],
}
}
}
ctx = new Chart(canvas, graphParams);
<canvas id="graph" height="500" width="700"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.1/Chart.bundle.min.js"></script>

Dojo charting. X-axis labels not sequential order

I have a chart where the X-axis pulls data from a cell in an SQL table. The source data cell for the SQL table is formatted as DATE. The SQL cell is formatted DATETIME. When the data is exported to a .csv the cell format is again DATE and a chart built in the .csv has the X-axis in sequential date order. When the same data is viewed in a chart on our GIS the X-axis dates are out of order making the plotted data impossible to decipher. Here is the code for the chart. Any assistance would be greatly appreciated. Thanks.
function makeChart(featureset) {
dojo.empty("chartDiv");
var dlg = dijit.byId('chartDialog');
// When resources are loaded and the DOM is ready....
dojo.ready(function () {
var data = featureset._jsonData.items;
var store = new dojo.data.ItemFileWriteStore({
data: {
identifier: "TestID",
label: "Parameter",
items: data
}
});
chart = new dojox.charting.DataChart("chartDiv", {
comparative: true
//scroll:stretchToFit
});
chart.setStore(store, { Parameter: '*' }, "Result");
//chart.addAxis("x", {title: "Sample#", titleOrientation: "away", majorLabels:true, minorTicks:true, minorLabels:true,
if (data.length > 2) {
chart.addAxis("x", {
title: "Collection Date",
titleOrientation: "away",
majorTicks: false,
majorLabels: true,
majorTickStep: 5,
minorTicks: false,
from: 0, to: (data.length + 0.5),
labelFunc: function (n) {
// I am assuming that your timestamp needs to be multiplied by 1000.
//var date = new Date(parseInt(data[n].CollectionDate) * 1000);
var date = data[n].CollectionDate;
return date;
}
});
}
chart.addAxis("y", { vertical: true });
var c = dojo.connect(chart, "onData", function () {
dojo.disconnect(c);
if (dijit.byId("chartlegend")) {
dijit.byId("chartlegend").destroy();
dojo.create("div", { id: "chartlegend" }, "chLegHd");
chlegend = new dojox.charting.widget.Legend({ chart: chart }, "chartlegend");
}
else {
chlegend = new dojox.charting.widget.Legend({ chart: chart }, "chartlegend");
chlegend.startup();
}
});
});
dlg.show();
}
I changed the source cell from datatype "datetime" to "date" and that made no difference in how the chart displays. It should show sequential dates i.e. 6/14/2015 7/01/2015 8/13/2015
but it is displaying thusly 8/13/2015 7/01/2015 6/14/2015
I am not very sure I understood your question very clearly. You want to display the date in sequential order retrieved from the DB. Here is what you can do:
You can create the labels array by the data base data retrieved.
var dBDateArray= ["array of dates from the DB in sequential order"];
var labelsArray = [];
for (var i = 0; i < dBDateArray.length; i++,) {
var obj = {};
obj.value = i;
obj.text = dbDateArray[i].name;
labelsArray.push(obj);
}
Set the labels in x Axis to this.labelsArray
this.chart1.addAxis("x", {
title: "Collection Date",
titleOrientation: "away",
labels:labelsArray
})

jQuery Flot line chart with month,year in x-axis

I'm trying to generate a graph with month,year in x-axis. Please check below for ex:
The data for the graph is obtained via ajax. Please check below for sample json:
{"total":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,475],[2013,11,0],[2013,12,0],[2014,1,367],[2014,2,0],[2014,3,0]],"critical":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,0],[2013,11,0],[2013,12,0],[2014,1,1],[2014,2,0],[2014,3,0]],"high":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,20],[2013,11,0],[2013,12,0],[2014,1,20],[2014,2,0],[2014,3,0]],"medium":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,24],[2013,11,0],[2013,12,0],[2014,1,135],[2014,2,0],[2014,3,0]],"low":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,42],[2013,11,0],[2013,12,0],[2014,1,26],[2014,2,0],[2014,3,0]]}
In the above example [2013,4,0] should translate to x-axis: Apr 2013, y-axis: 0.
Can you please let me know how i can achieve this?
Thanks.
Here's how I'd do it:
// your JSON
obj = {"total":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,475],[2013,11,0],[2013,12,0],[2014,1,367],[2014,2,0],[2014,3,0]],"critical":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,0],[2013,11,0],[2013,12,0],[2014,1,1],[2014,2,0],[2014,3,0]],"high":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,20],[2013,11,0],[2013,12,0],[2014,1,20],[2014,2,0],[2014,3,0]],"medium":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,24],[2013,11,0],[2013,12,0],[2014,1,135],[2014,2,0],[2014,3,0]],"low":[[2013,4,0],[2013,5,0],[2013,6,0],[2013,7,0],[2013,8,0],[2013,9,0],[2013,10,42],[2013,11,0],[2013,12,0],[2014,1,26],[2014,2,0],[2014,3,0]]};
// reformat into the format flot likes
seriesData = [];
for (var prop in obj) {
// push in the series, the "property" is the label
// use $.map to produce an array of [date, y-value]
// the new Date(i[0],i[1]-1).getTime(),
// will give you the epoch time for the first day of that month/year
seriesData.push({label: prop, data:$.map(obj[prop], function(i,j){
return [[new Date(i[0],i[1]-1).getTime(), i[2]]];
})});
}
// plot it!
$.plot("#placeholder", seriesData, {
xaxis: { mode: "time", timeformat: "%b %Y" }
});
Fiddle here.
Edit: It was changed j by i[2] in order to display the data correctly plotted.
In the options:
xaxis: {mode: "time", timeformat: "%b %m"}
Using the time plugin.
The data has to be converted to timestamps as explained in the link. As you have 0 in the day, maybe something like:
tstamp = new Date(dat[0]*1000*3600*24*30*12+dat[1]*1000*3600*24*30)

Limit labels number on Chart.js line chart

I want to display all of the points on my chart from the data I get, but I don't want to display all the labels for them, because then the chart is not very readable. I was looking for it in the docs, but couldn't find any parameter that would limit this.
I don't want to take only three labels for example, because then the chart is also limited to three points. Is it possible?
I have something like that right now:
If I could just leave every third-fourth label, it would be great. But I found absolutely nothing about labels options.
Try adding the options.scales.xAxes.ticks.maxTicksLimit option:
xAxes: [{
type: 'time',
ticks: {
autoSkip: true,
maxTicksLimit: 20
}
}]
For concreteness, let's say your original list of labels looks like:
["0", "1", "2", "3", "4", "5", "6", "7", "8"]
If you only want to display every 4th label, filter your list of labels so that every 4th label is filled in, and all others are the empty string (e.g. ["0", "", "", "", "4", "", "", "", "8"]).
For anyone looking to achieve this on Chart JS V2 the following will work:
var options = {
scales: {
xAxes: [{
afterTickToLabelConversion: function(data){
var xLabels = data.ticks;
xLabels.forEach(function (labels, i) {
if (i % 2 == 1){
xLabels[i] = '';
}
});
}
}]
}
}
Then pass the options variable as usual into a:
myLineChart = new Chart(ctx, {
type: 'line',
data: data,
options: options
});`
UPDATE:
I'v updated my fork with the latest pull (as of Jan 27, 2014) from NNick's Chart.js master branch.
https://github.com/hay-wire/Chart.js/tree/showXLabels
ORIGINAL ANSWER:
For those still facing this issue, I forked Chart.js a while back to solve the same problem. You can check it out on:
https://github.com/hay-wire/Chart.js/tree/skip-xlabels => Older branch! Check showXLabels branch for latest pull.
How to use:
Applicable to bar chart and line chart.
User can now pass a { showXLabels: 10 } to display only 10 labels (actual displayed labels count might be a bit different depending on the number of total labels present on x axis, but it will still remain close to 10 however)
Helps a lot when there is a very large amount of data. Earlier, the graph used to look devastated due to x axis labels drawn over each other in the cramped space. With showXLabels, user now has the control to reduce the number of labels to whatever number of labels fit good into the space available to him.
See the attached images for a comparison.
Without showXLabels option:
With { showXLabels: 10 } passed into option:
Here's some discussion on it:
https://github.com/nnnick/Chart.js/pull/521#issuecomment-60469304
For Chart.js 3.3.2, you can use #Nikita Ag's approach with a few changes. You can check the documentation. Put ticks in xAxis in scales. Example:
...
options: {
scales: {
xAxis: {
ticks: {
maxTicksLimit: 10
}
}
}
}
...
for axis rotation
use this:
scales: {
xAxes: [
{
// aqui controlas la cantidad de elementos en el eje horizontal con autoSkip
ticks: {
autoSkip: true,
maxRotation: 0,
minRotation: 0
}
}
]
}
In Chart.js 3.2.0:
options: {
scales: {
x: {
ticks: {
maxTicksLimit: 10
}
}
}
}
According to the chart.js github issue #12. Current solutions include:
Use 2.0 alpha (not production)
Hide x-axis at all when it becames too crowd (cannot accept at all)
manually control label skip of x-axis (not in responsive page)
However, after a few minutes, I thinks there's a better solution.
The following snippet will hide labels automatically. By modify xLabels with empty string before invoke draw() and restore them after then. Even more, re-rotating x labels can be applied as there's more space after hiding.
var axisFixedDrawFn = function() {
var self = this
var widthPerXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / self.xLabels.length
var xLabelPerFontSize = self.fontSize / widthPerXLabel
var xLabelStep = Math.ceil(xLabelPerFontSize)
var xLabelRotationOld = null
var xLabelsOld = null
if (xLabelStep > 1) {
var widthPerSkipedXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / (self.xLabels.length / xLabelStep)
xLabelRotationOld = self.xLabelRotation
xLabelsOld = clone(self.xLabels)
self.xLabelRotation = Math.asin(self.fontSize / widthPerSkipedXLabel) / Math.PI * 180
for (var i = 0; i < self.xLabels.length; ++i) {
if (i % xLabelStep != 0) {
self.xLabels[i] = ''
}
}
}
Chart.Scale.prototype.draw.apply(self, arguments);
if (xLabelRotationOld != null) {
self.xLabelRotation = xLabelRotationOld
}
if (xLabelsOld != null) {
self.xLabels = xLabelsOld
}
};
Chart.types.Bar.extend({
name : "AxisFixedBar",
initialize : function(data) {
Chart.types.Bar.prototype.initialize.apply(this, arguments);
this.scale.draw = axisFixedDrawFn;
}
});
Chart.types.Line.extend({
name : "AxisFixedLine",
initialize : function(data) {
Chart.types.Line.prototype.initialize.apply(this, arguments);
this.scale.draw = axisFixedDrawFn;
}
});
Please notice that clone is an external dependency.
i had a similar type of issue, and was given a nice solution to my specific issue show label in tooltip but not in x axis for chartjs line chart. See if this helps you
you can limit at as
scales: {
x: {
ticks: {
// For a category axis, the val is the index so the lookup via getLabelForValue is needed
callback: function(val, index) {
// Hide the label of every 2nd dataset
return index % 5 === 0 ? this.getLabelForValue(val) : '';
},
}
}
}
this will skip 4 labels and set the 5th one only.
you can use the following code:
xAxes: [{
ticks: {
autoSkip: true,
maxRotation: 90
}
}]
You may well not need anything with this new built-in feature.
A built-in label auto-skip feature detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally. https://www.chartjs.org/docs/latest/axes/
To set a custom number of ticks regardless of your chartsjs version:
yAxes: [{
ticks: {
stepSize: Math.round((Math.max.apply(Math, myListOfyValues) / 10)/5)*5,
beginAtZero: true,
precision: 0
}
}]
10 = the number of ticks
5 = rounds tick values to the nearest 5. All your y values will have the same step size.
Similar will work for xAxes too.
This answer works like a charm.
If you are wondering about the clone function, try this one:
var clone = function(el){ return el.slice(0); }
In the Chart.js file, you should find (on line 884 for me)
var Line = function(...
...
function drawScale(){
...
ctx.fillText(data.labels[i], 0,0);
...
If you just wrap that one line call to fillText with if ( i % config.xFreq === 0){ ... }
and then in chart.Line.defaults add something line xFreq : 1 you should be able to start using xFreq in your options when you call new Chart(ctx).Line(data, options).
Mind you this is pretty hacky.

Highcharts - show every other x-axis category

I have Highcharts set up to display a graph with a bunch of xAxis categories. This is all working fine, but I would like to be able to skip some of the xAxis categories, so not everything one is shown. You can see an example of this working within Campaign Monitor's reporting section (screenshot: http://screencast.com/t/Y2FjNzQ4Y).
Any idea how I can achieve this same layout?
It seems like the xAxis:labels:step value is what should be used to accomplish this:
xAxis: {
categories: ['JAN', 'FEB', 'MAR', 'APR', 'MAY'],
labels:{
step: 2 // this will show every second label
}
},
Step Axis Labels
Super late, but I figure this can help someone out.
xAxis: {
categories: categoriesname,
labels: {
style: {
color: '#000',
font: '9px Trebuchet MS, Verdana, sans-serif'
}
},
**tickInterval: TickInterval,**// SET THIS
tickPixelInterval: 80,
tickmarkPlacement: 'on'
},
You can set the xAxis type as 'datetime' then set the pointInterval and PointStart in the plotoptions.
Code example:
var chart;
$(document).ready(function () {
chart = new Highcharts.Chart({
"xAxis": {
"type": "datetime"
"plotOptions": {
"line": {
"pointInterval": 86400000,
"pointStart": 1282408923000
}
},
});
});
The figures you see for pointInterval and Start are in millisecionds which you can generate using getTime() The interval in your case would be 86400000ms which is one day. The library displays appropriate intervals based on your data interval.
here is my ugly solution :)
I'm using array as queue. http://javascript.about.com/library/blqueue.htm
if you fill point datas to the queue, you can to set datas for your chart series.
var myQueue = new Array();
var myPoint = [x, y]; myQueue.push(myPoint);
chart.series[0].setData(myQueue);
my X axis is not a datetime, it's an integer
first
var x = 0;
x value should be always increment when you need a new point.
http://dl.dropbox.com/u/3482121/picture/highcharts/PM/Screenshot.png

Categories

Resources