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
Related
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>
I'm still fairly new to javascript and this has got me banging my head against the wall. I'm sure it's really simple but for some reason I cannot seem to get this working correctly. I have seen similar questions on stackoverflow but I can't make them work for me.
I am trying to plot an unknown number of datasets onto a Chartjs graph. I am able to get the data (using PHP it is output as data attributes on child elements of the canvas) and store them to a variable $rows.
var $rows = $('#graphCanvas').find('> div')
I then iterate through the rows and calculate the dataset.
var colors = [ '#2685CB', '#4AD95A', '#FEC81B', '#FD8D14', '#CE00E6', '#4B4AD3', '#FC3026', '#B8CCE3', '#6ADC88', '#FEE45F' ];
for (var i=0; i<$rows.length; i++) {
datasetdata[i] = {
label:"Test " + i,
data: getdata($rows[i]),
backgroundColor: colors[i],
hoverBackgroundColor: colors[i],
borderStyle: 'solid',
borderWidth: 2,
}
}
function getdata($rows) {
//returns raw data
}
This all works well however the problem starts when I try to use datasetdata
var graphContext = document.getElementById("graphCanvas").getContext("2d");
var graphData = {
labels: labels,
datasets: [datasetdata]
};
If I use it with an index it works fine: datasetdata[0]
If I knew for sure how many datasets there would be I could just add their indexes and it would be fine.
Any insight into what I'm doing wrong would be great
Problem:
You have an extra set of brackets surrounding the datasetdata variable.
Solution:
Remove the brackets and set the datasets to just datasetdata:
var graphData = {
labels: labels,
datasets: datasetdata
};
Explanation:
The datasets option accepts a parameter that is an array of dataset objects. The wanted structure looks as following:
datasets: [
{ dataset1 },
{ dataset2 }
]
In your code, you surrounded the datasetdata by a set of brackets:
var graphData = {
labels: labels,
datasets: [datasetdata]
};
By adding another set of brackets, you are basically setting datasets to an array which contains the datasetdata array. The code renders a result that looks as following:
datasets: [
[ { dataset1 }, { dataset2 } ]
]
If you add select the value of the array at a specific index, you are extracting a single dataset from the datasetdata array.
var graphData = {
labels: labels,
datasets: [datasetdata[0]]
};
Your structure is then an array with a single dataset inside it:
datasets: [
{ dataset1 }
]
This code won't throw and error, since the structure is valid, however, it will only display the first result.
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;}
This is in continued to my question here
I was having a lot of problems in creating highcharts basic charts using CSV data from my local filesystem without using a server/framework and just basic HTML/CSS/JS etc
So, finally, I got an idea to create a chart inside "d3.csv" function wherein we can add highchart functions insdie d3.csv ones
But, there seems to be something very silly wrong, I'm trying with a very basic code and table.
HTML code has only container div element,
Javascript
d3.csv("test.csv", function(data) {
data.forEach(function(d) {
name = d.name,
apples = +d.apples
});
console.log(data[2]);
dataset = data;
//display();
console.log(dataset[0]);
console.log(dataset[0].name);
function push(a)
{
var filter = [];
for (i=0; i<a.length ; i++)
{
filter.push(a[i].apples);
//console.log (filter);
}
return filter;
}
window.apples = push(dataset);
console.log(apples);
$(function () {
$('#container').highcharts({
chart: {
type : 'bar'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: [dataset[0].name, dataset[1].name]
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
data: apples
}
]
});
})
});
test.csv :
name,apples
John,8
Jane,3
My console is showing "apples" correctly as [8,3]. I'm getting an empty graph on screen with only axes shown and nothing inside and also, x axis and y axis elements are interchanged.
What am I doing wrong here? Is the global variable - apples, not being accessed inside highcharts fucntions?
UPDATE :
Found the answer, but only one number is showing up.
I have 2 more questions :
How do I show the whole series?
Is this a good method to draw highcharts or will I face many issues later?
Found the solution to this, myself, for a change.
Highcharts will expect function to be parsed in their format ( Highcharts error 14 in console)
Changed my function above to this,
for (i=0; i<a.length ; i++)
{
x = a[i].apples;
y = parseFloat(x)
filter.push(y);
}
return filter;
}
window.apples = push(dataset);
And the series part to this :
series: [{
data : [apples]
}
]
This is finally, giving me a graph with one bar (John, 8) now!!
The second number is still not being loaded, if someone wants to help with that, please comment below.
Update :
changed
data : [apples] -> data: apples (Correct format)
Credits : PawelFus
This is a multi-part question, so please forgive the length of the question.
I'm attempting to create a chart that will plot a patient's height, weight, and BMI as separate series for multiple dates. I want to pull the data in using CSV for testing purposes before migrating to a server. I'm attempting to get it to work similar to this FIDDLE, but haven't been successful so far.
Here's one version of my code with the data hard coded:
$(function () {
var options = {
chart: {
renderTo: 'container',
type: 'line'
},
title: {
text: 'Patient Measurements'
},
xAxis: {
categories: []
},
yAxis: {
title: {
text: 'Measurements'
}
},
series: []
};
var data = "ID,PATIENT_NAME,DATA_DATE,HEIGHT,WEIGHT,BMI\n" +
"1,\"Doe,John\",1/1/2013 00:00:00,65,185,30.78224852\n" +
"1,\"Doe,John\",1/2/2013 00:00:00,65,184,30.61585799\n" +
"1,\"Doe,John\",2/1/2013 00:00:00,65,181,30.11668639\n" +
"1,\"Doe,John\",2/2/2013 00:00:00,65,180,29.95029585\n"
// Split the lines
var lines = data.split('\n');
var first = lines.shift().split(',');
var series_holder = [];
for (var = i, i < first.length, i++) {
var s = {
data: []
};
series_holder.push(s);
}
$.each (lines, function(lineNo, line) {
var items = line.split(',');
$.each (items, function(itemNo, item){
// If itemNo is the row/column iteration object, then start at column 2
if (itemNo >= 2) {
// Subtract the column from the itemNo to get a zero-based series_holder
series_holder[itemNo - 2].data.push(parseFloat(item));
}
});
});
options.series = series_holder;
var chart = new Highcharts.Chart(options);
});
The example should plot three lines (one for height, weight, and BMI) with four data points apiece (for each date).
I know the data in my example is not formatted based on Highcharts recommendations, but I need to be able to grab the ID and PATIENT_NAME fields from the CSV and use them in the tooltip for the series, so that the ID and PATIENT_NAME will identify the patient regardless of the data point you hover over. I understand that I could just display this in a DIV or something on the page, but I wanted to be able to do this because I have ideas for other things I could display in the tooltip if I can figure out how to get this to work.
From reviewing Highcharts site, I believe that all I would need to do to implement my code for a CSV, would be to add the following code instead of var data = "..." in my code above:
$.get(inputData, function(data) {
// Check for data
if (data.value != "") {
alert("No data to retrieve!");
return(0);
}
I'm not very well-versed with Javascript, jQuery, or Highcharts, but I'm doing my best to learn quickly. I realize that there are likely a number of mistakes in my code (some intentional, like parseFloat for non-float data types, so I can learn how to handle/parse different data types), so I appreciate everyone's patience.
Thanks for your help.
I've been playing with this some more and, after doing a lot of debugging to determine how the data is handled, I came up with the following code. I thought this might be a simplified version that might better get my point across.
$(function () {
var options = {
chart: {
renderTo: 'container',
type: 'line'
},
title: {
text: 'Patient Measurements'
},
xAxis: {
categories: []
},
yAxis: {
title: {
text: 'Measurements'
}
},
series: []
};
var data = "ID;PATIENT_NAME;DATA_DATE;AVG_HEIGHT;AVG_WEIGHT;BMI;WEIGHT_STATUS\n"+"1;DOE,JOHN;2012-12-29 00:00:00;65;185;30.7822485207101;Obese\n"+"1;DOE,JOHN;2013-01-12 00:00:00;65;184;30.6158579881657;Obese\n"+"1;DOE,JOHN;2013-02-09 00:00:00;65;181;30.1166863905325;Obese\n";
// Split the lines
var lines = data.split('\n');
var first = lines.shift().split(';');
var series_holder = [];
$.each (lines, function(lineNo, line) {
var items = line.split(';');
$.each(items, function(itemNo, item) {
if (itemNo == 3) {
options.xAxis.categories.push(item);
}
else if (itemNo > 3 && itemNo < 7) {
series_holder[itemNo-4].data.push(parseFloat(item));
}
});
});
for (var i = 4; i < first.length - 1; i++) {
var s = {
data: []
};
s.name = first[i].replace(/AVG_/g,"");
series_holder.push(s);
}
var chart = new Highcharts.Chart(options);
});
The x-Axis should be the date values under DATE_DATE.
The series/lines should be the following:
Height
Weight
BMI
The data for the plot points is in column index 4 (AVG_HEIGHT) to 6 (BMI) after the header row.
Here's a sample Fiddle that I got to work that is similar to what I want to do...I just can't get it to work for my specific data.
I'll hold off on the tooltip and CSV portions of my question for now. I'd really like to get something of mine working so I know I'm on the right track.
This is not a complete answer but more a tip: Highcharts have a plugin (modules/data.src.js) that handle parsing of csv data that should get you started. It will automatically use the column names as series names, and it also tries to guess the types of the columns (datetime/number/category).
Have a look at the src on github, and the demo example at jsfiddle:
$('#container1').highcharts({
data: {
csv: document.getElementById('csv1').innerHTML
},
title: {
text: 'Categorized CSV data'
}
});