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
Related
I am using the Highcharts synchronized charts to display three different variables. However, in order to render cleaner graphs, I'd like to display the x-axis (which is the same for all three graphs) only for the bottom graph.
For that, I presume, I need to cycle at the end of the generation process through the charts and suppress the first two x-axis, kind like
for (i = 0; i < (Highcharts.charts.length - 1); i = i + 1)
{
chart = Highcharts.charts[i];
chart.xAxis.labels.enabled = false;
}
Here is the default fiddle.
I don't succeed in getting this to work. Can anyone help me out on this?
You can set the xAxis.visible property depending on the chart index:
success: function (activity) {
activity = JSON.parse(activity);
activity.datasets.forEach(function (dataset, i) {
...
Highcharts.chart(chartDiv, {
xAxis: {
visible: i === 2,
...
},
...
});
});
}
Live demo: https://jsfiddle.net/BlackLabel/cmdb5at0/
API Reference: https://api.highcharts.com/highcharts/xAxis.visible
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 am making a diagram that should show states in a timeline like diagram. I figured that the best fit for it would be horizontal bar diagram, I added data like this:
series: [{
data: [?],
name: 'state1'
}, {
data: [?],
name: 'state2'
}, {
data: [?],
name: 'state3'
}, {
data: [?],
name: 'state1'
}, {
....
}, {
data: [?],
name: 'state1'
}]
Here's what I'v got:
The chart looks like what I need, but I need to somehow group legends, for example this case there should be only 3 legends: state1, state2, state3.
How can I achieve something like this?
I would suggest a different approach, using the column range series type.
This way you can do this with only three series, with a data point for each time slot, rather than a series for each time slot. This saves from having to manipulate the legend or fake other series level actions.
This is an example I did for an earlier question that demonstrates the method (with only two states):
http://jsfiddle.net/jlbriggs/o9ck2zLn/0/
can easily be adapted to use a datetime axis as well, which it seems you might be going for.
Basing on the answer of #StAlex, I would recommend a similar solution, but without the ECMAScript 5 specific forEach:
var legend = {};
for (var i = 0; i < series.length; i++) {
var bar = series[i];
if (!legend[bar.name]) {
legend[bar.name] = 0;
}
legend[bar.name] += bar.data;
}
I assumed that data is a number. If this is not so, add a comment.
var legends = {};
series.forEach(function(bar){
legends[bar.name] = bar.data;
});
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().
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'
}
});