so recently I've been working on a web app that collects data from requests and I am trying to output the data into a graph based on frequency per hour/month etc.
So, I'm using Chart.js and have JSON data of dates and I'm trying to make a chart that shows the frequency of requests per hour, etc.
My data is just each request has a time stamp, so all I have is a bunch of time stamps in 2018-01-03 15:15:04 format. for example:
{'2018-01-03 15:15:04', '2018-01-04 06:32:45', '2018-01-04 23:32:45', '2018-02-23 01:24:32'}
except, I have hundreds of them. Just frequency per hour, month, etc is what I want.
Can anyone point me in the right direction? My two thoughts were this:
Just do the counting and parsing myself and come up with counts per hour and then just throw the data at the chart
Somehow use their built in functionality for time, which I am still a bit unclear about even after reading the docs.
thanks a ton, everyone!
Here's an example of what I would like:
Chart example
Also, http://www.chartjs.org/samples/latest/scales/time/financial.html
Going with #1 on your list is your best bet. I wrote an example of how you can achieve it pretty easily.
First find the frequency (I did it by month/year) and add it to a Map. I used a map because the .keys() and .values() functions for a Map are returned in insertion order. A regular object cannot guarantee order.
Then, Chart.js can display those values pretty easily using spread syntax to turn the .keys() and .values() iterators into arrays.
var a = ['2018-01-03 15:15:04', '2018-01-04 06:32:45', '2018-01-04 23:32:45', '2018-02-23 01:24:32', '2018-02-23 04:33:12', '2018-03-23 05:33:12', '2018-03-22 08:33:12', '2018-04-27 01:33:12'];
var freqMap = new Map();
a.forEach(function(time) {
var date = new Date(time);
var monthName = date.toLocaleString("en-us", {
month: "short"
});
var key = monthName + "-" + date.getFullYear();
var count = freqMap.get(key) || 0;
freqMap.set(key, ++count);
});
var ctx = document.getElementById("myChart").getContext('2d');
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: [...freqMap.keys()],
datasets: [{
label: 'Requests per month',
data: [...freqMap.values()]
}],
},
options: {
elements: {
line: {
tension: 0
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
Related
I am having problems displaying two datasets on a single graph. Technically both data points are being graphed but both values are being graphed on a single line. See graph attached down below.
So firstly parsing the values:
webSocket.onmessage = function(event){
var data = JSON.parse(event.data);
console.log(data.value);
console.log(data.value2);
var today = new Date();
var t = today.getHours()+ ":" + today.getMinutes() + ":" + today.getSeconds();
addData(t, data.value, data.value2)
}
this code works since the console logs both values. Next is adding the data to the end of the chart and this is where I suspect my mistake lies as I do not know how to "call" the different datasets:
function addData(label, data, data2){
dataPlot.data.labels.push(label);//x-values
dataPlot.data.datasets.forEach((dataset)=> {
dataset.data.push(data);
dataset.data.push(data2);
});
dataPlot.update();
}
Finally the code for the corresponding chart:
dataPlot = new Chart(document.getElementById("line-chart"),{
type: 'line',
data: {
datasets: [{
data: [],
label: "Thermocouple 1",
borderColor: "#3e95cd",
fill: true
},
{
data: [],
label: "Thermocouple 2",
borderColor: " #FF0000",
fill: true
}]
}
});
I think there might also be a mistake here as I do not know how to "declare" the two different datasets.
I am very new to javascript.
So as stated above the result is one line being graphed on a chart but with both values. Thus heating up one of the thermocouples result in a graph looking like a mountain range basically.Graph
To start, you don't need a foreach here otherwise you will push 4 data in the dataset while you are declaring 2 :
dataPlot.data.datasets.forEach((dataset)=> {
dataset.data.push(data);
dataset.data.push(data2);
});
Try one of those 2 options :
Doing things manually (without foreach):
dataPlot.data.datasets.push(data);
dataPlot.data.datasets.push(data2);
OR, create an array of data, and make the forEach on that array :
dataArray.forEach( (item) => {
dataPlot.data.datasets.push(item);
});
PS : for the second option, you need to make sure that dataArray.length == dataPlot.data.datasets.length
My goal is to make a chart that tracks user activity. I want it to plot when they first logged on, and when they last logged on.
The data I pass into this function (var refarray = [...data here...]) is in string format, meaning I need to parse the dates given to me from the database into a date format, or so I thought. Below you will see my attempt.
function hc_first_last_logon(selector, refarray){
var categories = [];
var Dat = [];
for(var i = 0; i<refarray.length; i++){ // store all user names and data
categories.push(refarray.name)
Dat.push([Date.parse(refarray.FirstLogon), Date.parse(refarray.LastLogon)])
}
//console.log(Dat) returns date time objects as expected
var def = {
chart: { type: 'columnrange', inverted: true },
legend: { enabled: false},
title:{ text: "First and Last Log-on"},
xAxis:{ categories: categories, title:{text: "User"}},
yAxis:{ type: 'datetime' },
series:[{name: "First and Last Log-on", data: Dat}]
};
var div = $('#' + selector);
console.log(div);
div.highcharts(def);
return def;}
My intent is for this chart to be versatile, allowing me to choose any number of different users, and get the chart when I click a refresh button on my html page (it queries the database and sends the data to this function).
I suspect that my issue has to do with the date variable, Dat, as it appears that the string and date variable types are not acceptable data inputs for highcharts.
Here's an included screen shot of the errors that I am getting in the returned code. The 10x2 matrix is pretty much all the same, so I'll only include one row. Error #17 corresponds to unacceptable data type, which confirms my suspicions.
Console Results
Any suggestions?
UPDATE: I included highcharts-more.js, and now got rid of the error mentioned above. The date ranges are still a bit off. Below is an image of what's going on now.
Current Chart Situation
Thanks to #Grzegorz BlachliĆski and his suggestions, I was able to find the issue and resolve it. Here's what went wrong:
1) I did not load highcharts-more.js Including this file resolved the Highcharts error 17.
2) Date needs to be in milliseconds from 1/1/1970. Easy fix putting the dates generated into (datevar).getTime().
3) I did not have a tooltip formatter. I copied one off the internet that got the job done, and it worked!
Here's the code for those interested:
function hc_first_last_logon(selector, refarray){
var categories = [];
var Dat = [];
for(var i = 0; i<refarray.length; i++){ // store all user names and data
categories.push(refarray.name)
Dat.push([Date.parse(refarray.FirstLogon).getTime(), Date.parse(refarray.LastLogon)].getTime())
}
//console.log(Dat) returns date time objects as expected
var def = {
chart: { type: 'columnrange', inverted: true },
legend: { enabled: false},
title:{ text: "First and Last Log-on"},
xAxis:{ categories: categories, title:{text: "User"}},
yAxis:{ type: 'datetime' },
tooltip: {
formatter: function() {
return new Date(this.point.low).toUTCString().substring(0, 22) + ' - ' + new Date(this.point.high).toUTCString().substring(0, 22)
}
},
series:[{name: "First and Last Log-on", data: Dat}]
};
var div = $('#' + selector);
console.log(div);
div.highcharts(def);
return def;}
I'm trying for days now to get Highstock working with an external CSV file. The issue was first that the imported file was sorted in "descending" order whereas Highcharts requires the data to be sorted in "ascending" order. Once I found a JSFiddle/Codepen close to my problem, I managed to display the data correctly.
Now the problem is that on the x-axis the dates are displayed as something like 00:00:00.500 whereas it should be looking like this 2016-03-11.
I have created a codepen since it may be easier for you to respond to it than copy/pasting here a lot of code: http://codepen.io/bauhausweb/pen/aNpbxg
Thanks for looking into my issue!
For your example, there seems to at least be the problem of 2016-03-11 simply being a string and not a timestamp in milliseconds, which causes it to chose the defaults of 0, 1, 2, ... as x-values instead.
Below I've provided an example of how you can use the data modules csv attribute to achieve a similar result, with the help of the complete function:
$(function () {
$.get("https://www.example.com/my.csv", function (csv) {
$('#container').highcharts('StockChart', {
data: {
complete: function(o) {
o.series[0].data.reverse();
},
csv: csv
}
});
});
});
Or look at this JSFiddle demonstration.
Try to do something like this:
$.each(lines, function (lineNo, line) {
if (lineNo > 0 && lineNo < 557) {
var items = line.split(',');
// var seriesname = String(items[0]); // this is the area name
var seriesname = "Gold"; // this is the area name
var price = parseFloat(items[1]);
var f_date = items[0];
var format = String(f_date.replace(/-/g,','));
var date_items = format.split(',');
var d = Date.UTC(date_items[0],date_items[1],date_items[2]);
console.log(d);
var date = d;
// this will be the id of the drilldown
// var shift_one_value = parseFloat(items[3]); // drilldown shift1 value
// var shift_two_value = parseFloat(items[4]); // drilldown shift2 value
series.data.push({
name: seriesname,
y: price,
x: date
});
}
});
The problem is the date it would be formated in UTC
Your code has a lot of oddities. Your xAxis is set to datetime which is good. With a point interval of one day - also good. But, if you look at your series.data you are sending in data formatted like:
{
name: "Gold",
x: "1233.6",
y: 1233.6
}
You are setting the y here:
var date = String(items[1]);
You should be using items[0]. Now, you also have to parse this string into javascript time. Something like this can work:
var arr = String(items[0]).split("-");
var date = Date.UTC(arr[0], arr[1], arr[2]);
However, now your chart throws error that date is not sorted. See updated pen here.
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
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.