How can I create Highcharts Arearange graph from CSV file? - csv

My CSV contents look like:
date,average,maximum,minimum
2017-01-01,0.02963,0.05595
2017-01-02,0.02929,0.05566
2017-01-03,0.02921,0.05579
2017-01-04,0.02920,0.05682
2017-01-05,0.02942,0.06489
2017-01-06,0.02971,0.07201
2017-01-07,0.02861,0.05390
2017-01-08,0.02820,0.05243
2017-01-09,0.02896,0.05203
2017-01-10,0.04215,0.24689
2017-01-11,0.02853,0.05130
2017-01-12,0.02777,0.05065
2017-01-13,0.02769,0.05022
2017-01-14,0.02723,0.04985
I want to produce a highcharts Multiple seriesgraph with arearange (using maximum and minimum) and line(average). But I am not be able to write the date as the x axis values.
So far, I tried with the following example: https://www.highcharts.com/demo/arearange-line
Here is my code:
<html>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
</head>
<body onload="test()">
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<script type="text/javascript">
function test()
{
var c=[];
var ranges = [];
var averages = [];
var current = [];
var reference = [];
$.get('data.csv', function(data)
{
var lines = data.split('\n');
for(i=1;i<lines.length; i++)
{
var items = lines[i].split(',');
c.push(items[1]);
ranges.push([items[0],items[2],items[3]]);
averages.push([items[0],items[1]]);
}
});
Highcharts.chart('container', {
title: {
text: 'July Data'
},
xAxis: {
categories: c
},
yAxis: {
title: {
text: 'Value'
}
},
tooltip: {
crosshairs: true,
shared: true,
valueSuffix: 'mm/day'
},
legend: {
},
series: [{
name: 'Average',
data: averages,
zIndex: 1,
marker: {
fillColor: 'white',
lineWidth: 2,
lineColor: Highcharts.getOptions().colors[0]
}
},
{
name: 'Climatology',
data: ranges,
type: 'arearange',
lineWidth: 0,
linkedTo: ':previous',
color: Highcharts.getOptions().colors[0],
fillOpacity: 0.3,
zIndex: 0,
marker: {
enabled: false
}
}]
});
};
</script>
</body>

As K. Rohde noticed, your data lacks one column (probably average) and all your y values should be numbers, not strings. Also, you do not have to use categories if x values are dates. Simply, change xAxis' type to 'datetime' and this way you do not have to create and fill additional category array (c).
<pre id="csv" style="display:none">date,average,maximum,minimum
2017-01-01,0.04,0.02963,0.05595
2017-01-02,0.04,0.02929,0.05566
2017-01-03,0.04,0.02921,0.05579
2017-01-04,0.04,0.02920,0.05682
2017-01-05,0.04,0.02942,0.06489
2017-01-06,0.04,0.02971,0.07201
2017-01-07,0.04,0.02861,0.05390
2017-01-08,0.04,0.02820,0.05243
2017-01-09,0.04,0.02896,0.05203
2017-01-10,0.1,0.04215,0.24689
2017-01-11,0.04,0.02853,0.05130
2017-01-12,0.04,0.02777,0.05065
2017-01-13,0.04,0.02769,0.05022
2017-01-14,0.04,0.02723,0.04985</pre>
API Reference:
http://api.highcharts.com/highcharts/xAxis.type
Example:
http://jsfiddle.net/ez1as425/ - corrected demo
http://jsfiddle.net/g6mojLdm/ - xAxis with datetime type

Your code has had some issues. You may look at the Fiddle here for a corrected version.
First off, your CSV data has 4 columns specified, but only three columns in the data. I added some mock average data for the demo.
Second, your Categories c were set to items[1], although items[0] contained your date values.
Finally, when parsing your CSV data, into chartable pieces, you need to convert the split values (being a string) to a Number.

Related

Show bar with zero value in ChartJs v2

I'm wondering is there any way to show in ChartJs (in bar chart) bars with zero value?
I mean something like this: https://jsfiddle.net/vrg5cnk5/16/, so the second bar would be just blue border on level zero.
I used already this code:
ticks: {
beginAtZero: true,
min: 0,
suggestedMin: 0
}
but I'm not surprised it didn't work.
Thanks in advance
Simply specify minBarLength in the dataset, with the minimum length in pixels the bars should have. See documentation.
Working Example:
var $chartCanvas = $('myCanvas');
var barChart = new Chart(myCanvas, {
type: 'bar',
data: {
labels: ['Accepted Answer', 'Top rated answer', 'This Answer'],
datasets:[{
data: [0, 3, 10],
minBarLength: 7, // This is the important line!
}]
},
options: {
title: {
display: true,
text: 'helpfulness of answers to this questions'
},
legend: {
display: false
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="myCanvas"></canvas>
After dig into the plugin system, if you using Chart.js >=2.5, you can write a plugin to achieve it. Here is an example to draw a line when data is zero.
Here is my code:
const zeroCompensation = {
renderZeroCompensation: function (chartInstance, d) {
// get postion info from _view
const view = d._view
const context = chartInstance.chart.ctx
// the view.x is the centeral point of the bar, so we need minus half width of the bar.
const startX = view.x - view.width / 2
// common canvas API, Check it out on MDN
context.beginPath();
// set line color, you can do more custom settings here.
context.strokeStyle = '#aaaaaa';
context.moveTo(startX, view.y);
// draw the line!
context.lineTo(startX + view.width, view.y);
// bam! you will see the lines.
context.stroke();
},
afterDatasetsDraw: function (chart, easing) {
// get data meta, we need the location info in _view property.
const meta = chart.getDatasetMeta(0)
// also you need get datasets to find which item is 0.
const dataSet = chart.config.data.datasets[0].data
meta.data.forEach((d, index) => {
// for the item which value is 0, reander a line.
if(dataSet[index] === 0) {
this.renderZeroCompensation(chart, d)
}
})
}
};
and here is how to add the plugin to Chart.js
var chart1 = new Chart(ctx, {
plugins: [zeroCompensation]
});
The offcial document is not clear about their plugin API, you may console.log to find what you want.
There is no way to configure chart.js to do this, but you could use a hack instead. Just set your value for the 0 bar to a really small number like 0.1.
data: [2, 0.1, 3, 1]
Here is an example forked from yours.
If you are using tooltips, then you would have to also add some logic so that the tooltip for that bar still displays a value of 0. You can do this using the label callback.
label: function(tooltipItem, data) {
var value = data.datasets[0].data[tooltipItem.index];
var label = data.labels[tooltipItem.index];
if (value === 0.1) {
value = 0;
}
return label + ': ' + value + ' %';
}
Here is an example putting it all together.
If you struggle with this, here's what I came up with. It is similar idea to Li Jinyao, but in addition, you would get click and hover events (tooltip) working for whole bar.
I value is close to 0 but negative, the bar will show on negative side of x axis - you can easily get rid of it if that's not what you want to do.
const zeroCompensation = {
id: 'zeroCompensation',
beforeDatasetsDraw: function(chart) {
const meta = chart.getDatasetMeta(0)
forEach(meta.data, d => {
const barHeight = d._view.base - d._view.y;
if(Math.abs(barHeight) < minBarHeight /* I used value 5 */) {
d._view.y = d._view.base - minBarHeight * (Math.sign(barHeight) || 1);
}
});
}};
and add it to plugins:
plugins: [zeroCompensation]
Keep in mind that this will work for values close to 0, not only 0. If you want it only for zeroes, you can change contents of if condition to:
chart.config.data.datasets[0].data[index] === 0
This is what Li Jinyao used in his answer.
Hope that helps.
Edit: I wanted to highlight that this solution works regardless of values spread. Answer marked as solution will not work as intended if there are some high values in data set - 0.1 will render same as 0 in that case.
Here is the simplest way to do this in V3 chart js
Chart.defaults.datasets.bar.minBarLength = 5;
2019 Update
This can be done easily as below.
var myChart = new Chart(ctx, {
...
options: {
...
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
);
You can find this in Chart.js documentation https://www.chartjs.org/docs/latest/
I just stumbled over this questions because I had a similar problem: The type of my Chart.js chart was 'horizontalBar' and for some datasets (where no zero values was present across the dataset) the horizontal bar did not start with 0 rather with the lowest value from the dataset.
I tried to figure out a solution and came up with following entry in the options object while creating the charts:
ticks: {
beginAtZero:true,
mirror:false,
suggestedMin: 0,
suggestedMax: 100
}
However that did not work as expected although all posts said it works that way.
After further investigation and reading of the Chart.js documentation I found the solution. The reason the further step did not work was following I found in the documentation:
However, any options specified on the x axis in a bar chart, are applied to the y axis in a horizontal bar chart.
So I just changed my options object to hold the proper configuration for the xAxes and it worked.
For those who are interested here is the the whole code I used for creating the horizontal bar chart with y-axis starting always at zero:
this.chart = new Chart(
ctx,
{
type: 'horizontalBar',
data: this.data.chartdata,
options: {
scales: {
xAxes: [{
stacked: false,
ticks: {
beginAtZero:true,
mirror:false,
suggestedMin: 0,
suggestedMax: 100
}
}],
yAxes: [{
stacked: true
}]
},
scaleBeginAtZero : true,
// important here to use () =>
// to keep the scope of this
onClick: (e) => {
var actChart : Chart = this.charts[trialId];
var element =
actChart.getElementAtEvent(e);
}
}
}
);

Displaying JSON data into a pie chart using chart.js

my first time using chart.js and am running into a small bug that I can't seem to work around it. Below is my code, however, its just displaying the labels but not rendering the pie chart itself.
Am following samples from the chart.js documentation here http://www.chartjs.org/docs/#doughnut-pie-chart-example-usage
Your help will be appreciated.
<canvas id="myChart" width="200" height="200"></canvas>
$(document).ready(function () {
/*
-> #47A508 = green (wins)
-> #ff6a00 = orange (losses)
-> #ffd800 = yellow (draws)
*/
var DataArray = [];
var ctx = document.getElementById("myChart");
$.ajax({
url: 'http://api.football-data.org/v1/competitions/426/leagueTable',
dataType: 'json',
type: 'GET',
}).done(function (result) {
$.each(result.standing, function () {
var name = "Manchester United FC";
if (this.teamName == name) {
DataArray.push([this.wins, this.losses, this.draws]);
}
});
var myChart = new Chart(ctx, {
type: 'pie',
data: {
label: 'Manchester United Current Form',
labels: [
"Wins",
"Losses",
"Draws"
],
datasets: [
{
data: DataArray,
backgroundColor: [
"#47A508",
"#ff6a00",
"#ffd800"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
},
options: { responsive: true }
});
});
}
maybe it is because of the jquery each, it fills DataArray async and the array is not ready, when you want to use it as chart data.
Change the $.each to a simple js for loop
for(var i = 0; i < result.standing; i++){
var name = "Manchester United FC";
var team = result.standing[i];
if (team.teamName == name) {
DataArray.push(team.wins, team.losses, team.draws);
}
}
try callbacks for you ajax or do the below (which is a dirty solution):
$.ajax({
url: 'http://api.football-data.org/v1/competitions/426/leagueTable',
dataType: 'json',
cache: false, //add this
async: false, //add this
type: 'GET',
Also
the result of your ajax could be returned using the below code instead of using an array.
jQuery.parseJSON(result);
The issue lies in your DataArray. The way it is implemented is is an array with a single entry. Which is another array itself.
[[<wins>, <losses>, <draws>]]
instead of
[<wins>, <losses>, <draws>]
That is because you instantiate an array and then push into it an array object.
To fix this try using the following function:
(...)
$.each(result.standing, function () {
var name = "Manchester United FC";
if (this.teamName == name) {
DataArray = ([this.wins, this.losses, this.draws]);
console.log("This team name");
}
});
(...)
I got this solved, well sadly, with no magic at all to brag about. There was nothing wrong with the code initially, however, it was a problem with the DOM rendering performance. Thank you #alwaysVBNET and #Aniko Litvanyi for your inputs as well.
This link helped me out, hopefully it does to someone out there.

Create an average line for Google Charts

I am learning to use Google Charts and I'm trying to get an average of all values and show a line on the chart to represent the average.
Below is an of how my chart looks but I need an average line for all the values.
thanks in advance for your attention.
<html>
<body style="font-family: Arial;border: 0 none;">
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard" style="width:1300px;overflow:scroll;">
<div id="chart" style="position: relative; width: 1300px; height: 300px;"></div>
<div id="control" style="position: relative; width: 1300px; height: 30px;"></div>
</div>
<script type="text/javascript">
google.charts.load('current', {
callback: function () {
var query = new google.visualization.Query('xxxxxxx');
query.setQuery('select A,B,C,D');
query.send(function (response) {
if (response.isError()) {
console.log('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control',
options: {
filterColumnIndex: 0,
ui: {
chartType: 'ScatterChart',
chartOptions: {
pointSize: 2,
chartArea: {width: '90%'},
hAxis: {format: 'dd/MM/yyyy'}
},
chartView: {
columns: [ 0, 1, 2]
}
}
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'SteppedAreaChart',
containerId: 'chart',
options: {
filterColumnIndex: 0,
pointSize: 2,
chartArea: {height: '80%', 'width': '90%'},
hAxis: {format: 'E dd/MMM','textStyle':{'fontSize': 11, 'color': 'black','bold':true},'minTextSpacing': 0, 'slantedText': false},
vAxis: {format: '0'},
legend: {position: 'top'},
bar: {groupWidth: '100%'},
isStacked: false
},
view: {
columns: [ 0, 1,2]
}
});
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'TableProxy',
options: {
page: 'enable',
pageSize: 1
},
view: {
columns: [0]
}
});
google.visualization.events.addListener(proxyTable, 'ready', function () {
var dt = proxyTable.getDataTable();
var groupedData = google.visualization.data.group(dt, [0], [{
column: 2,
type: 'number',
aggregation: google.visualization.data.avg
}]);
chart.setDataTable(groupedData);
chart.draw();
});
google.visualization.events.addListener(proxyTable, 'ready', function () {
var group = google.visualization.data.group(proxyTable.getDataTable(), [{
column: 0,
type: 'date',
modifier: function () {
return 1;
}
}], [{
column: 2,
type: 'number',
aggregation: google.visualization.data.avg
}]);
});
dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
dashboard.bind(control, chart);
dashboard.draw(response.getDataTable());
});
},
packages: ['controls', 'corechart', 'table'], 'language': 'pt-br'
});
</script>
</body>
</html>
It's possible to group by date (code bellow)...but the main difficult thing to do is how to use the controlType: 'ChartRangeFilter'. Anyone has any idea??
function floorDate(datetime) {
var newDate = new Date(datetime);
newDate.setHours(0);
newDate.setMinutes(0);
newDate.setSeconds(0);
return newDate;
}
var columnChart1 = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'chart3'
});
// columnChart1.draw();
// Create the dashboard.
new google.visualization.Dashboard(document.getElementById('dashboard')).
// Configure & bind the controls
bind(divPicker, [table, columnChart]).
// Draw the dashboard
draw(data);
google.visualization.events.addListener(divPicker, 'ready',
function(event) {
// group the data of the filtered table and set the result in the pie chart.
columnChart1.setDataTable(google.visualization.data.group(
// get the filtered results
table.getDataTable(), [{
'column': 0,
'modifier': floorDate,
'type': 'date'
}], [{
'column': 2,
'aggregation': google.visualization.data.sum,
'type': 'number'
}]
));
// redraw the pie chart to reflect changes
columnChart1.draw();
});
google.visualization.events.addListener(divPicker, 'statechange',
function(event) {
// group the data of the filtered table and set the result in the pie chart.
columnChart1.setDataTable(google.visualization.data.group(table.getDataTable(), [0], [{
'column': 2,
'aggregation': google.visualization.data.avg,
'type': 'number'
}]));
// redraw the pie chart to reflect changes
columnChart1.draw();
});
}
google.setOnLoadCallback(drawVisualization);
</script>
You should be able to make use of a trendline.
A trendline is a line superimposed on a chart revealing the overall direction of the data. Google Charts can automatically generate trendlines for Scatter Charts, Bar Charts, Column Charts, and Line Charts.
Guessing from the given code, you may want to add trendlines: { 0: {} } to the chartOptions for your control variable.
Putting your code into a jsFiddle or a Codepen would make it easier to debug and show you a valid solution to your particular problem.
I appreciate this is a little old, but my searching found this and wanted to help further.
Adding a trendline gives a data's trend (increasing, decreasing) and not really the average. I cannot claim this answer as mine, please see https://groups.google.com/forum/#!topic/google-chart-api/UOdUFszYSRc
As Tom suggests I actually use the combo chart and compute a second series, but as your charts are quite complex you may wish to use the API method, which his JSFiddle (found in the link above) shows working - thanks Tom.

Highchart Basicline

According to my own question
i have tried something, and my fiddle is link
But i want to be output as like below
i.e x axis contains monthly reports
my ajax code is
$.ajax({
url: "/echo/json/",
data: data,
type: "POST",
success: function(point) {
var chartSeriesData = [];
var chartCategory = [];
$.each(point, function(i, item) {
var series_name = item.resultDate;
var series_data = item.y;
var cagory = series_name;
var series = {
name: series_name,
data: item.y
};
chartSeriesData.push(series);
chartCategory.push(series_name);
});
var chartingOptions = {
chart: {
renderTo: 'container',
defaultSeriesType: 'spline'
},
xAxis: {
categories: chartCategory
},
series: chartSeriesData
};
chartingOptions = $.extend({}, jugalsLib.getBasicChartOptions(), chartingOptions);
chart = new Highcharts.Chart(chartingOptions);
}
});
Thanking you....
In your parser, you create many series, because you initialize series in points loop. So you should prepare series earlier than points loop. Then add points to correct serie (in this case first or second serie).

highcharts not refreshing chart when page refreshes

i have created a highchart and data i took it from csv file.The chart is working good and plotting fine.But my problem is when the page refreshes it is not taking the latest value from the csv file.It still displays the old chart.when i close the browser and re-open the chart works fine.Please help me how to reset/redraw with updated value from csv
Below is my code. This problem IE not in firefox
var options = {
chart: {
renderTo: 'container',
defaultSeriesType: 'line',
marginRight: 130,
marginBottom: 25
},
title: {
text: 'Support Trending P1,P2 & P3'
},
xAxis: {
categories: []
},
yAxis: {
showLastLabel:true,
tickInterval:5,
title: {
text: ""
}
},
series: []
};
$.get('../data/trending.txt', function(data) {
// Split the lines
var lines = data.split(';');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
// header line containes categories
if (lineNo == 0) {
$.each(items, function(itemNo, item) {
if (itemNo > 0) options.xAxis.categories.push(item);
});
}
// the rest of the lines contain data with their name in the first position
else {
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
series.data.push(parseFloat(item));
}
});
options.series.push(series);
}
});
var chart = new Highcharts.Chart(options);
});
});
Blockquote
It looks like your chart data is being cached, and not being refreshed by the browser. Without code, it's card to know how to fix it.
If you are using jquery $.ajax, there is an option
cache:false
Which may help. http://api.jquery.com/jQuery.ajax/