Dojo charting. X-axis labels not sequential order - javascript

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
})

Related

Mapping issue on Chart Js Bar Chart

I have a small problem in my Bar Chart. I am using Chart.js v 2.9.4. I have successfully made the chart. The data is also coming. But I have a small issue. let me explain that.
I have 2 datasets both are getting from the Database. The datasets are as follows:
The total number of calls received on a certain date e.g, (5 calls on 5th October, 7 Calls on 6th October, 3 call on 7th October etc)
The number of paid calls received on a certain date e.g (3 calls on 5th October, 2 Calls on 6th October )
I successfully gets the data in JSON format and put it on the bar chart. The code for this is as follows:
var data_s = response.call_data;
var data_b = response.bill_data;
var c_days = [];
var b_days = [];
var calls = [];
var b_calls = [];
for (var i in data_s) {
var date = data_s[i].dated // date of the call (Total Call)
var res = date.split("-");
var year = res[0];
var month = res[1];
var day = res[2];
var dm = day + "/" + month;
c_days.push(dm);
calls.push(data_s[i].calls); // Number of calls
}
for (var i in data_b) {
var date = data_b[i].b_dated; // Date of Paid Call
var res = date.split("-");
var year = res[0];
var month = res[1];
var day = res[2];
var dm = day + "/" + month;
b_days.push(dm);
b_calls.push(data_b[i].b_calls); // Number of paid calls
}
var c = c_days.concat(b_days);
var unique = c.filter(function(itm, i, c) {
return i == c.indexOf(itm);
});
var chartdata = {
labels: unique,
datasets: [{
label: 'Total Calls',
backgroundColor: '#007bff',
borderColor: '#007bff',
hoverBackgroundColor: '#007bff',
hoverBorderColor: '#666666',
responsive: true,
maintainAspectRatio: false,
datasetFill: false,
data: calls
},
{
label: 'Billed Calls',
backgroundColor: '#28a745',
borderColor: '#28a745',
hoverBackgroundColor: '#28a745',
hoverBorderColor: '#666666',
responsive: true,
maintainAspectRatio: false,
datasetFill: false,
data: b_calls
}
]
};
var graphTarget = $("#barChart");
var barGraph = new Chart(graphTarget, {
type: 'bar',
data: chartdata,
options: barChartOptions
});
The problem is that that on a single bar chart the data on the dates are mismanaged. Like for example the total number of calls received on 7th October can be 10 while the billed calls (paid calls) can be 0.
My SQL query which fetch data from the database only gives total number of calls on the date.
The bar chart is successfully plotted but the paid calls data get a bit miss managed as told earlier.
You can say it is not necessary that if we receive call on certain day it must be paid call. Like on 5th October we can have total of 15 calls and none of it can be billed or paid. So the bar chart populates total call correctly but on paid call it doesn't put zero but next day billed or paid call on that 5th October date.
You should define the x-axis as a time cartesian axis and provide the data as individual points, an array of objects, having a x (alternatively also t) and an y property each.
There's no need for complex data processing using for loops. The response can instead be converted and directly assigned to the data properties through the Array.map() method as follows.
var chartdata = {
// omit labels
datasets: [{
...
data: response.call_data.map(v => ({ x: v.dated, y: v.calls }))
},
{
...
data: response.bill_data.map(v => ({ x: v.b_dated, y: v.b_calls }))
}]
};
For further information, please take a look at this answer.
The different date/time formats from the mentioned answer obviously need to be adapted to the format of your data and the desired display.

How to make a chart with highcharts, load data from API

I am a new programmer and this is my first time using highcharts.
I have code like this using highstocks library too:
Highcharts.getJSON('https://gmlews.com/api/data', function(data) {
console.log(data);
var accelero_x = [],
timestamp = [];
for (var i = 0; i < data.length; i++) {
accelero_x.push(data[i].accelero_x);
timestamp.push(data[i].timestamp);
}
console.log(accelero_x);
console.log(timestamp);
// Create the chart
Highcharts.stockChart('container', {
rangeSelector: {
selected: 1
},
title: {
text: 'Accelero X'
},
series: [{
name: 'Accelero X',
data: accelero_x,
type: 'spline',
tooltip: {
valueDecimals: 2
}
}]
});
});
You can see the full running code on : https://jsfiddle.net/estri012/y1usoxd7/1/
The problem is how to make the x-axes based on my timestamp?
New problem after get the x-axes right is : in my api, some of the last data is in 19March. But on the chart the last data shows 18March not 19March. Actually there is no one single data on 18March in my API. You can check the api on the URL above. Meanwhile the other data before those are showing the right date on the chart.
This is the capture of the chart :
You need to convert your data to the format required by Highcharts, in your case - an array of arrays or an array of objcts ({ x, y }).
Highcharts.getJSON('https://gmlews.com/api/data', function(data) {
var seriesData = [];
for (var i = 0; i < data.length; i++) {
seriesData.push([
new Date(data[i].timestamp).getTime(),
data[i].accelero_x
]);
}
// Create the chart
...
});
Live demo: https://jsfiddle.net/BlackLabel/82vqcwsr/
API Reference: https://api.highcharts.com/highstock/series.line.data

Update Chart JS with date range selector

I am trying to update a chart depending on the dates and and shifts selected using ajax. My ajax call returns an array like this:
0
date "2017-11-20"
shift "Day Shift"
availability 100
1
date "2017-11-21"
shift "Day Shift"
availability 63.63636363636363
2
date "2017-11-22"
shift "Day Shift"
availability 63.63636363636363
3
date "2017-11-23"
shift "Day Shift"
availability 63.63636363636363
4
date "2017-11-24"
shift "Day Shift"
availability 14.285714285714285
5
date "2017-11-20"
shift "Night Shift"
availability 67.56756756756756
6
date "2017-11-21"
shift "Night Shift"
availability 67.56756756756756
7
date "2017-11-22"
shift "Night Shift"
availability 67.56756756756756
8
date "2017-11-23"
shift "Night Shift"
availability 67.56756756756756
my javascript looks like this:
// on change event
var request;
$('input').on('change', function(event) {
console.log('changed');
event.preventDefault();
// Abort any pending request
if (request) {
request.abort();
}
var rangeStart = moment($('#daterange').data('daterangepicker').startDate).unix();
var rangeEnd = moment($('#daterange').data('daterangepicker').endDate).unix();
var shift = 'all';
request = $.ajax({
url: "report_availability.php",
type: "post",
data: {
rangeStart: rangeStart,
rangeEnd: rangeEnd,
shift: shift
}
});
request.done(function (response, textStatus){
drawChart(response);
});
request.fail(function (textStatus, errorThrown){
// Log the error to the console
console.error(
"The following error occurred: "+
textStatus, errorThrown
);
});
request.always(function () {
console.log('request finished');
});
});
function drawChart(data) {
var dates = [];
var shift1Score = [];
var shift2Score = [];
for(var i in data) {
var found = jQuery.inArray(data[i].date, dates);
if (found < 0) {
dates.push(data[i].date);
}
if(data[i].shift == 'Day Shift' ) {
shift1Score.push(data[i].availability);
} else {
shift2Score.push(data[i].availability);
}
}
// Destroy the chart if it already exists
// NOT WORKING
if(myChart!=null){
myChart.destroy();
console.log('destroy');
}
var ctx = document.getElementById("myChart").getContext('2d');
ctx.canvas.height = 50;
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: dates,
datasets: [
{
label: "Day Shift",
backgroundColor: "#3e95cd",
data: shift1Score
}, {
label: "Night Shift",
backgroundColor: "#8e5ea2",
data: shift2Score
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
responsive: true,
maintainAspectRatio: false
}
});
}
I have 2 problems with this:
problem 1: The chart is not being destroyed so when I redraw it, it just redraws on top of the old chart which causes problems with the hover events. I have tried to use chart.update() to resolve this issue however this seems to just add to the original data instead of replacing it.
EDIT:- I have solved problem 1 by removing the canvas and then creating a new canvas:-
$('#myChart').remove();
$('#chartBar').append('<canvas id="myChart"></canvas>');
Problem 2: There is more than 2 shifts.. sometime upto 5 and I do not want to hard code all of these. I would like to draw each dataset depending on how many shifts are returned in the array, I am open to changing the array structure in php or javascript but just cannot seem to figure out the correct array structrue or how to build a dynamic dataset array for the chart.
the chart should output like this for 2 shifts:
Any help would be great thanks
I had the same problem that you have.
In order to update the graph i am using two functions:
Remove all datasets in current graph:
function removeDataset(chart) {
chart.data.datasets = [];
};
Add a new dataset to the graph:
function addDataset(chart, name, data, background, border, fill) {
var newDataset = {
label: name,
data: [],
backgroundColor: background,
borderColor: border,
fill: fill
};
for (var index = 0; index < data.length; ++index) {
newDataset.data.push(data[index]);
}
chart.data.datasets.push(newDataset);
};
So, when i have the ajax done, i use like this:
removeDataset(ctx1);
addDataset(ctx1, "Dataset Name", resp.dataset_data_json, "#007bff", "#007bff", true);
ctx1.update();
To declare the graph, i use:
var ctx1;
$(document).ready(function () {
var canvas1 = $("#canvas1")[0];
canvas1.height = "300";
ctx1 = new Chart(canvas1, config_ctx1);
});
I hope it helps.

Chart.js Bar Chart - grouping and mapping data

I am trying to use Chart.js Bar Chart to display a set of data.
My data is weekly based so to my method I send the year and week and get the data back in 3 columns; Product, Area and Amount.
What I want is to have to Products horizontaly and in each Product I want different bars for each Area and offcourse the Amount verticaly. (Bonus: If an Area nothing in that product it should not be shown in that particular Product)
The problem is that the number of Products and the number of Areas can vary from each week. And I can't seem to find a good way to loop through the data and create the datasets the way chart.js wants.
Also tried using Underscore.js to group it but the fact that the each Area doesn't always have an amount for a spesific product seems to be causing some issues.
So I guess you have to loop through the data and map that data to another predefined array for each Area so it can match this structure somehow??
Also open for other Chart plugins, but really liked how Chart.js animates the data. And if I get this working I can probably figgure out an update method for when you change week.
To get the labels i can f.ex do this:
$.ajax({
....
success: function (d) {
var a = _.groupBy(d.data, function (d) { return d.Product });
var labels = [];
$.each(a, function (i, value) {
labels.push(i);
});
}
});
With data in this format
var myJSONData = [
{
Product: 'P1',
Area: 'A1',
Value: 12
},
...
]
You can use this function to convert it into the format Chart.js requires
var data = {
labels: [],
datasets: []
}
var colors = ['Red','Blue','Green', ...] // add as many colors as there will be areas (maximum)
myJSONData.forEach(function (e) {
// create labels
var labelIndex = data.labels.indexOf(e.Product)
if (labelIndex === -1) {
labelIndex = data.labels.length;
data.labels.push(e.Product);
// dummy entries for each dataset for the label
data.datasets.forEach(function (dataset) {
dataset.data.push(0)
})
}
// get the area dataset
var area = data.datasets.filter(function(area){
return (area.label === e.Area);
})[0]
// otherwise create it
if (area === undefined) {
area = {
label: e.Area,
// create a dummy array with an entry for each of the existing labels
data: data.labels.map(function () {
return 0;
}),
fillColor: colors[data.datasets.length]
};
data.datasets.push(area)
}
// set the value
area.data[labelIndex] = e.Value;
})
and use that to display the chart.
Fiddle - http://jsfiddle.net/jt4Lqkn3/
(Bonus: If an Area nothing in that product it should not be shown in
that particular Product)
You can't change any configuration to do this - there will be a space left for each series.
However you might want to set the strokeColor to a transparent value (e.g. strokeColor: "rgba(0, 0, 0, 0)", just below the fillColor line) and set the barStrokeWidth option to 0, so that 0 values don't show up at all on the chart (otherwise there will be thin line shown)
new Chart(ctx).Bar(data, {
barStrokeWidth: 0,
});

Plotting time with flot, json series

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.

Categories

Resources