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.
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
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 am doing data visualizations with react, react-chartjs-2, and chart.js version 2.2.1. There is a possibly related answer to this question here (look for 17.06.16 update), but I'm not sure what Chart.pluginService.register is or whether it is compatible with React. So far it hasn't worked for me.
I am simply looking to place a label inside the doughnut that is the sum of all data subsets. I assume this is nested somewhere in the doughnut chart's options, but I haven't found it yet.
In react-chartjs-2 you can access the datasets through chart.config.data.datasets.
So for:
data = {
labels: [
'Red',
'Green',
'Yellow'
],
datasets: [{
data: [300, 50, 100],
...
Inside the draw callback in Chart.helpers.extend you can use:
var sum = 0;
for (var i = 0; i < this.chart.config.data.datasets[0].data.length; i++) {
sum += this.chart.config.data.datasets[0].data[i];
}
Here's an example Codepen: http://codepen.io/anon/pen/xqMQQB?editors=1010
I got an Kendo ui Bar Chart which is filled with an dynamic array.
One time its filled with 12 items and one time its filled with only 1 item.
Now the Bars automatically resizes, when only one item is in the array, the Bar is super big. I know, that there is no "max-width" or "width" property in the configuration.
Is there a workaround for my problem? I.E. dynamic calculation of the gap/space or whatever property? Or even with css or so?
Here is an simple fiddle
var dataset = [1,2,3,3,5,6,8];
var dataOnlyOne = [10]
//gap:0.2
// gap: function(){
return width/12*... // works not
}
Its been a while, and you probably moved on, but I was searching for something similar...
Your problem could be resolved using the below code, where the gap is calculated from the number of items in the data array:
$(function() {
var data = [1,2,3,3,5,6,8,2,3,3,5,6,8];
// var data = [10];
var gap = 8/data.length
$('#chart').kendoChart({
seriesDefaults: {
type: 'column',
stack: true,
},
series: [
{
name: 'dataset',
data: data, // dataOnlyOne
color: 'blue',
gap:gap
}
]
})
});
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'
}
});