Highcharts columnrange date chart - javascript

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

Related

Highcharts get if data is currently beeing grouped with multiple series

I want to determine wether data grouping is currently beeing applied to a series or not after the user zooms in into the graph.
When there is only one series inside the graph it works just fine with the approach i found by using the hasGroupedData, which returns true if data is grouped and undefined if it's not.
chart.series[0].hasGroupedData
However, if there are more than one series inside the graph this always returns true once the data grouping has been applied once on the series so there is no way for me to know anymore if the data is beeing grouped or not.
The same behaviour is with the normal Highcharts chart as well as the Highstock stockchart, which I want to use.
I am out of ideas how else i could determine if the series is beeing grouped or not so any help would be appreciated.
Example code:
https://jsfiddle.net/Itsearnest/ho0a4zw9/
var chart = Highcharts.stockChart('container', {
chart: {
zoomType: "x"
},
navigator:{
enabled:false
},
yAxis:[{},{}],
xAxis:{
events:{
afterSetExtremes: (event) => {
var info = document.getElementById("info");
info.innerHTML = "";
chart.series.forEach((elem) =>{
info.innerHTML += ("Data grouped for " + elem.name +": " + elem.hasGroupedData) + "<br>";
});
}
}
},
series: [{
data: Array.from({length: 50000}, () => Math.floor(Math.random() * 500))
}]
});
document.getElementById("add").onclick = (event) => {
var base = Math.floor(Math.random()*1000);
chart.addSeries({
data: Array.from({length: 50000}, () => base + Math.floor(Math.random() * 500))
});
};
Edit.
It turns out it is a bug in Version 10.0.0. After downgrading to 9.1.2 it works as intended (https://github.com/highcharts/highcharts/issues/17141)

How do I display two datasets on a single chart with chartjs

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

Highcharts chart creation using d3.csv

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

Highcharts Plotoptions Series

I am currently using Highcharts in my website. In one of my charts (a Basic Column chart) I have multiple series, which I can click on the name displayed on the bottom to show/hide.
I can have a lot of series and I would like to limit the number of series to 3 at the same time. It means when it loads the graph, it shows only 3 series and the others are not shown. If I click on a 4th serie, one of the 3 originally present will disappear, so that the number of active serie always remain 3.
I've been looking for it and I found out I needed to do some modifications in the plotOptions.series field and I digged into the Highcharts API reference but didn't found what I wanted. My first attempt at the code would be something like this :
$('#container').highcharts({
plotOptions:{
series: {
var series = this.series;
var nb_of_visible_series = 0;
//Here i count the number of visible series
for(var i=0; i<series.length; i++) {
if(series[i].visible) {
nb_of_visible_series++:
}
}
//If too many series are visible I'll randomly
//hide as many series as necessary
if(nb_of_visible_series>3) {
var nb_of_series_to_hide = nb_of_visible_series-3;
while(nb_of_series_to_hide>0) {
var i=Math.floor(Math.random()*series.length);
if(series[i].visible) {
series[i].hide()
nb_of_series_to_hide--;
}
}
}
}
}
}
So this is the idea but I don't know where to put it for real (not directly in the plotOptions.series field just like this I guess ?). I can put it in plotOptions.series.events.legentItemClick but then it will not be taken into account at the loading of the chart.
I'm looking for some tracks and advices about my code (I'm a JS beginner) and thank you in Advance. And sorry about my poor english.
For sure code you have written wouldn't work. Options for Highcharts should be javascript object, not some thing mixed between variables, options etc.
1) To get displayed on init only three series preprocess data, something like this:
var series = [{ data: [..], name: 'name 1' ..} , { data: [..], name: 'name 2' ..} , ... , {data: [..], name: 'name n'}];
for (var i = 0, len = series.length; i < len; i++) {
series[i].visible = i < 3; //setup variable series.visible to show/hide on init load.
}
$('#container').highcharts({
series: series //pass variable with updated visible option
});
2) As you noticed you need to write your own function for legendItemClick which will check how many series is visible (loop through chart.series and count series.visible == true). Then hide/show specific series using series.hide() / series.show().

How to create line Hightchart from CSV where two columns of data are used as tooltip text?

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

Categories