Background
I was trying to show the average traffic with respect to the hours DYNAMICALLY using highchart. That is to say I want it show the traffic repeatedly like this, when the time comes to 23:00 next I want it back to 0:00.
I am doing this by setting 24 categories ['0:00', '1:00'...,'23:00'], and adding points when the data is updated by ajax, say every 1 second.
var chart = new Highcharts.Chart({
...//some options
xAxis: {
categories:['0:00','1:00','2:00',...,'23:00']
},
load: function() {setInterval(updateData,1000)}
series: [] //empty series here, adding dynamically by ajax
})
the updateData is defined as a function
function updateData(){
var data = $.ajax(...)// get the data
var series = chart.series[0];
if(series.data.length < 24){ //when data.length is < 24 add directly
chart.series[0].addPoint(data,true,false);
}else{
chart.series[0].addPoint(data,true,true);//set the 3rd option to true to remove the first data point, actually here this data is equal to the first one since this is a circle, when it comes to 24:00 it is actually 0:00, and I should update the xAxis.
//code updating the axis categories to [1:00, 2:00...23:00,0:00]
xAxis.setCategories(categories);
}
}
the x-axis turns out to be [2:00, 3:00, ...23:00, 0:00, 24], That is to say the point that I add this time does NOT correspond to the categories[24]:0:00, It is actually corresponding to the categories[25] which is not exist, so it is set to 24 in default.
A solution (quick and dirty)
do not ring shift the categories but push a new circle to it,like:
categories.push("time");//time is 0:00-23:00
xAxis.setCategories(categories);
but this will make the categories larger and larger..which is bad.
How can I fix this.
Another solution(also with some problems)
By using datetime as the type of x-axis, there is another problem. My data format is as follws
time count
8:00 23
9:00 56
... ...
and I can construct Points like [time, count], the question is I have time only. Even if I construct data by manually adding a date like
time = (new Date("2012-11-17 "+time)).getTime()
seems feasible. But when it got through 24 hours, the spline comes back to the left of the chart since the x-axis value here is equal to the first one.
BTW: how can I make the x-axis show only the time, the image above showed date at the left side, and the time interval is automatically display how to make it display all?
Thank You for your attention!!!
I followed your advice #Ruchit Rami and revised my code:
/*update part*/
var time = series.points.length > 0 ? series.points[series.points.length-1].category+3600 : 0;
//from 1970-1-1 0:00 And **add 1 hour everytime**
if (series.data.length < 24) {
series.addPoint([time, sum],true,false);
} else {
series.addPoint([time, sum],true,true);
}
/*chart part*/
xAxis: {
type: 'datetime',
dateTimeLabelFormat: {
second: '%H:%M',
minute: '%H:%M',
hour: '%H:%M',
day: '%H:%M',
week: '%H:%M',
month: '%H:%M',
year: '%H:%M'
}
tickInterval: 3600
}
The result
The date label format seems not affected though I specify it
And the time is not correct. Why? Thanks!
still didnt displayed right
To display only time on the X-axis you can use dateTimeLabelFormats property of xaxis and you can use tickInterval for setting tick interval on xaxis.
//Sets tickInterval to 24 * 3600 * 1000 if display is by day
tickInterval : 24 * 3600 * 1000,
dateTimeLabelFormats : {
hour : '%H:%M',
day : "%H:%M"
}
Now, for the issue of chart redraw from the first point, you will need to increase the date of the xaxis point. I am unable to come up with any elegant solution but you can check for time "0:00" while adding new points dynamically and before adding that point increase its date part by one compared to last point in the series.You can find the last point of the series by series.points[series.points.length-1]. Hope i haven't missed anything.
Now, this may not be what you are looking for but I am making some assumptions about what you want to show:
Data by hour for one "day" 0000-2300
Do not care to show the date just the time
Data fluctuates across "days" for a given time
I have created an example here of the chart iterating through 4 "days" of data. I did this by creating an empty data series first to draw the chart, then on load of the chart I iterate through an array of data sets every 1.5 seconds. It then loops back over to the beginning. I have it updating a DIV with what the "day" is. Please let me know if I have missed some condition you need.
Here is the looping code:
var data1 = [5, 8, 2, 5, 7, 4, 1, 2, 30, 20, 50, 30, 150, 130, 70, 50, 20, 47, 32, 18, 20, 15, 16, 8];
var data2 = [9, 15, 3, 4, 1, 1, 0, 0, 60, 75, 112, 190, 267, 365, 258, 164, 168, 190, 47, 16, 20, 18, 5, 8];
var data3 = [15, 18, 12, 5, 7, 4, 1, 2, 130, 20, 150, 130, 150, 130, 70, 50, 20, 47, 32, 18, 20, 15, 16, 8];
var data4 = [19, 15, 13, 4, 11, 11, 0, 0, 60, 175, 112, 190, 267, 365, 258, 164, 168, 190, 47, 16, 20, 18, 15, 18];
var dataSet = [data1, data2, data3, data4];
var dataIter = 0;
$(function() {
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
events: {
load: function() {
var series = this.series[0];
setInterval(function() {
if (dataIter >= dataSet.length) dataIter = 0;
series.setData(dataSet[dataIter], true);
$("#dayLabel").text("Day - " +dataIter.toString());
dataIter += 1;
}, 1500);
}
}
},
xAxis: {
categories: ['0000', '0100', '0200', '0300', '0400', '0500', '0600', '0700', '0800', '0900', '1000', '1100', '1200', '1300', '1400', '1500', '1600', '1700', '1800', '1900', '2000', '2100', '2200', '2300'],
labels: {
rotation: 90
}
},
yAxis: {
min: 0,
max: 500
},
series: [{
data: []}]
});
});
Related
I have this chart
<script src="http://code.highcharts.com/highcharts.js"></script>
<div id="container" style="height: 300px"></div>
var seriesOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'];
/**
* Create the chart when all data is loaded
* #returns {undefined}
*/
function createChart() {
Highcharts.stockChart('container', {
plotOptions: {
series: {
gapSize: 5 * 24 * 3600 * 1000,
gapUnit: 'relative'
}
},
rangeSelector: {
selected: 5
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent',
showInNavigator: true
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
series: seriesOptions
});
}
$.each(names, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/' + name.toLowerCase() + '-c.json', function (data) {
if (i==0) {
var first = [], last = [];
first.push.apply(first, data.slice(0,1)[0]);
last.push.apply(first, data.slice(0,1)[0]);
first[0] = first[0] - 1900 * 24 * 3600 * 1000;
last[0] = last[0] - 130 * 24 * 3600 * 1000;
data = [];
data.push(first);
data.push(last);
}
seriesOptions[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter += 1;
if (seriesCounter === names.length) {
createChart();
}
});
});
and as you can see there are three stocks shown. If you hover the chart with the mouse and go to the beginning you'll notice MSFT stock which has only 2 points and that's intentional. After MSFT there should be about 6 year gap, however on the chart it's shown in a few pixels.
How can I configure stockChart to show real gaps? In other words, I want to see the gap of 6 years so from 2005 till 2011 there will be empty space proportional to the whole chart?
The discussion in the comment section of the first answer reveals that OP wants to hide no-data periods only in some cases.
The solution here might be to set ordinal to false (as #ewolden) suggested and use breaks instead:
xAxis: {
breaks: [{
breakSize: 24 * 3600 * 1000,
from: Date.UTC(2017, 0, 6),
to: Date.UTC(2017, 0, 9)
}],
ordinal: false
},
series: [{
data: [
[Date.UTC(2017, 0, 2), 6],
[Date.UTC(2017, 0, 3), 7],
[Date.UTC(2017, 0, 4), 3],
[Date.UTC(2017, 0, 5), 4],
[Date.UTC(2017, 0, 6), 1],
[Date.UTC(2017, 0, 9), 8],
[Date.UTC(2017, 0, 10), 9],
[Date.UTC(2017, 6, 1), 4],
[Date.UTC(2017, 6, 2), 5]
]
Example: http://jsfiddle.net/BlackLabel/ocg0dujg/
In the above demo I was able to hide the weekend (7 and 8 Jan) and maintain the space between January and July.
API reference: https://api.highcharts.com/highstock/xAxis.breaks
What you are after is ordinal.
In an ordinal axis, the points are equally spaced in the chart regardless of the actual time or x distance between them. This means that missing data for nights or weekends will not take up space in the chart.
Setting ordinal to false, like this, will give you the gap you are after:
xAxis: {
type: 'datetime',
ordinal: false,
},
There are some other issues with your code, if you look in console, you are getting error 15 which states that highcharts requires data to be sorted. You get this because of how you add the series data to your MSFT series. You add both the x and the y to a single 1D array, which means highcharts tries to plot both your x and y values on the x axis.
I did a workaround that gives it the right format in this fiddle: http://jsfiddle.net/2cps91ka/91/
I need to create a chart with fixed values xaxis although it contains no data to graph like this:
Is importante the min value for yaxis must be (0) but show 1 grid line
(The color does not matter, and I need to show minute by minute interval, eg 18:50, 18:51, 18: 52, 18:53 ... 10 Total ticks)
as it should be the format xaxis?
as it should enter data values?
You can use showEmpty parameter of your xAxis and yAxis to show them without any data. You can also add min and max values for calculating the extremes of your axes.
If you want to have an interval of your ticks equal to 1 min you can set it using tickInterval: http://api.highcharts.com/highcharts/xAxis.tickInterval
Here you can find code that may help you:
$('#container').highcharts({
xAxis: {
type: 'datetime',
min: Date.UTC(2016, 01, 01, 01),
showEmpty: true,
max: Date.UTC(2016, 01, 01, 01, 30),
tickInterval: 1000 * 60, // one minute
},
yAxis: {
min: 0,
max: 10,
showEmpty: true
},
series: [{
}]
});
And here you can find live example how it can work: http://jsfiddle.net/wys1duhq/1/
I'm trying out Highcharts and I have a situation where I have negative values and positive values within one bucket on the x-axis. The total for the stacked values is not accurately represented on the y-axis and the y-axis stackLabel.
For instance, in this JSFiddle, the Oranges have -30, 20 and 40. The total is showing 60; not 30.
Here's a snippet of the Highcharts object showing the data:
series: [{
name: 'John',
data: [50, -30, 40, 70, 20]
}, {
name: 'Jane',
data: [20, 20, 30, -20, 10]
}, {
name: 'Joe',
data: [30, 40, 40, -20, 50]
}]
In the highcharts stackLabel sum values from negative and positive values separately. Take look at your exampel and you will notice that you have stacklabel -30 and 60, separaterly calculated.
You can solve this by using the yAxis.stackLabels.formatter property as below:
yAxis: {
stackLabels: {
enabled: true,
align: 'center',
formatter: function() {
var sum = 0;
var series = this.axis.series;
for (var i in series) {
if (series[i].visible && series[i].options.stacking == 'normal')
sum += series[i].yData[this.x];
}
if(this.total > 0 ) {
return Highcharts.numberFormat(sum,1);
} else {
return '';
}
}
}
}
From this answer.
Highcharts does a great job figuring out appropriate tick intervals.
However, I have a "duration" series (in ms), which I format e.g. like "3y 6M" or "1d 3h" or "3h 30min" for display. Because Highcharts is optimizing the tick intervals for the ms value (e.g. 10,000,000ms), I end up with awkward values such as [ 2h 46min 40s, 5h 33min 20s, 8h 20min ] rather than [ 3h, 6h, 9h ].
Can I get Highcharts to prefer multiples of certain values (e.g. 1000, 60 * 1000, 60 * 60 * 1000 etc)? I'd rather not have to calculate the exact tick interval myself (depends on chart size etc).
I think you should consider using datetime axis for yAxis. For example: http://jsfiddle.net/jRGvs/
yAxis: {
type: 'datetime'
},
series: [{
type: 'column',
name: 'Column',
data: [Date.UTC(1970, 0, 1, 2, 30),
Date.UTC(1970, 0, 1, 1, 45),
Date.UTC(1970, 0, 1, 4, 10),
Date.UTC(1970, 0, 1, 3, 30)]
}]
you can go with label > formatter for yAxis,
here you can write a routine which will handle the text/value to be displayed beside the grid line. but the thing is you cannot override the tick interval from here.
In my chart, I try to display end of month performances over one year (at 31 Jan, 29 Fev, ..., 31 Dec). X-axis is defined as follow:
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
month: '%b %Y'
}
}
}
The issue is that the scale automatically adjust to the appropriate unit (Months) and display the first day of the Month. As a result, my first element (at 31 Jan) is displayed above "Feb 2012" (same issue for other elements).
I was wondering if I could rather display the end of month day on my x-axis. Any idea?
Thanks,
Example
You can define a custom xAxis.tickPositioner with the positions at which the tick should appear as follows
xAxis: {
type: 'datetime',
tickPositioner: function() {
var ticks = [
Date.UTC(2012, 0, 31),
Date.UTC(2012, 2, 31),
Date.UTC(2012, 4, 31),
Date.UTC(2012, 6, 31),
Date.UTC(2012, 8, 30),
Date.UTC(2012, 10, 30)];
//dates.info defines what to show in labels
//apparently dateTimeLabelFormats is always ignored when specifying tickPosistioner
ticks.info = {
unitName: "month", //unitName: "day",
higherRanks: {} // Omitting this would break things
};
return ticks;
}
}
Customize tick positions | Highchart & Highstock # jsFiddle