Highcharts: xAxis yearly labels centered between ticks - highcharts

I am drawing a line chart with monthly data points. However, I want the scale to display year strings only.
So far, so easy. However, as far as I can see, Highcharts will always draw the xAxis labels relative to the ticks... and I am required to display them centered between ticks.
Is there some simple way of doing this that I am missing, please...?

According to my understanding, the behavior you desire is: http://jsfiddle.net/msjaiswal/U45Sr/2/
Let me break down the solution :
1. Monthly Data Points
One data point corresponding to one month :
var data = [
[Date.UTC(2003,1),0.872],
[Date.UTC(2003,2),0.8714],
[Date.UTC(2003,3),0.8638],
[Date.UTC(2003,4),0.8567],
[Date.UTC(2003,5),0.8536],
[Date.UTC(2003,6),0.8564],
..
]
2. Scale to display only yearly ticks
Use chart options like this:
xAxis: {
minRange : 30 * 24 * 3600 * 1000, //
minTickInterval: 12* 30 * 24 * 3600 * 1000 // An year
},

There is no simple, out-of-the-box solution. You have to use events and reposition the labels accordingly. Here is a sample solution that also works when resizing the browser window (or otherwise forcing the chart to redraw), even when the tick count changes: http://jsfiddle.net/McNetic/eyyom2qg/3/
It works by attaching the same event handler to both the load and the redraw events:
$('#container').highcharts({
chart: {
events: {
load: fixLabels,
redraw: fixLabels
}
},
[...]
The handler itself looks like this:
var fixLabels = function() {
var labels = $('div.highcharts-xaxis-labels span', this.container).sort(function(a, b) {
return +parseInt($(a).css('left')) - +parseInt($(b).css('left'));
});
labels.css('margin-left',
(parseInt($(labels.get(1)).css('left')) - parseInt($(labels.get(0)).css('left'))) / 2
);
$(labels.get(this.xAxis[0].tickPositions.length - 1)).remove();
};
Basically, it works like this:
Get all existing labels (when redrawn, this includes newly added ones). 2. Sort by css property 'left' (they are not sorted this way after some redrawing)
Calculate offset between the first two labels (the offset is the same for all labels)
Set half of the offset as margin-left of all labels, effectively shifting them half the offset to the right.
Remove the rightmost label (moved outside of chart, by sometimes partly visible).

This can be done with a workaround by manually adjusting the label positioning via a callback (called on both load and redraw). Please see the fiddle linked to in my comment on this post: Highcharts - how can I center labels on a datetime x-axis?

There are several xAxis options which may help do what you want.
http://api.highcharts.com/highcharts#xAxis.labels
Take a look at 'align' which specifies whether the labels are to the left or right of the tick, and also 'x' which allows you to specify a x-offset for the label from the tick.

Have you tried to use tick placement ? http://api.highcharts.com/highcharts#xAxis.tickmarkPlacement

Related

Highcharts - Highstock: fixed width intervals with scrollbar

I need the points of my chart to have a fixed width (say, 100px each). If the needed space exceed the width of the chart, I just want to be able to scroll horizontally (with the scrollbar.enabled parameter set to true).
This is the basic setup, without setting the points width:
http://jsfiddle.net/wxxdne19/
If I set the column width like this:
http://jsfiddle.net/wxxdne19/1/
The tickPixelInterval parameter is ignored (as the documentation says, of course).
I tried a bunch of other things, but none of them worked, and I ran out of ideas. How can I do what I need?
Update
To clarify what I need, think of it as if I have a column chart, and I need to force all the columns to have a fixed width. Something like this:
http://jsfiddle.net/4rx4snjh/
But, instead of the columns overlapping each other, I'd like the scrollbar to do its job :-) Furthermore, I need it to work with any kind of series (lines, areas...), not just columns.
It seems that the solution here is to compute extremes manually and set them in load event:
load: function() {
var chart = this,
xAxis = this.xAxis[0],
visibleColumns = (xAxis.width - pointWidth) / pointWidth;
xAxis.setExtremes(pointStart, pointStart + pointInterval * visibleColumns);
}
Live demo: http://jsfiddle.net/kkulig/mpancrbc/
For some reason (bug probably) xAxis.min value must be initialized when the container width is a small value (in my example it's less that 400 px or so).
API reference: https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes

Highcharts synchronization with multiple yaxis

I have two charts that are synchronized. They have a margin left to make sure they are uniformly aligned. I have situations where I have multiple yAxis that can get turned on and they are on the right side opposed to the left. I attempted to use the same marginRight approach but when a second, third, or fourth axis gets added to the right it won't show up because there isn't enough room. So I am dealing with a dynamic amount of space over there on the right side. Highcharts handles the dynamic aspects when it's just one chart but I need my second chart to have the same margin even tho it doesn't have these additional yAxis. It's important that this time series data remains aligned in the two charts.
What is the approach to handle this?
UPDATE:
I created a simple jsFiddle here: http://jsfiddle.net/28hrffv7/
In my real-world example, I have showEmpty set to false and a series which is hidden by default.
{ opposite: true, title: { text: 'Random Text' }, showEmpty: false}
When they turn it own the series is rendered and the axis and title is added. This example shows that the first charts doesn't realize that the 3rd chart has 3 axis and as a result should have more marginleft
Update 2: Updated JS fiddle to show the more dynamic nature of the problem. When you toggle a series in the legend you can observe axes getting added and removed which is feature that is wanted. What is required is to keep all the charts synchronized in the width of the plotable area so they all line up correctly. http://jsfiddle.net/28hrffv7/3/
You could hard-code marginRight as well as marginLeft.
Demo #1: http://jsfiddle.net/28hrffv7/1/
Or check which marginRight is the highest and update all chart with the new setting. Relevant part of the code:
}, {
data: []
}]
}, function(chart){
if (chart.marginRight > topMarginRight) {
topMarginRight = chart.marginRight;
console.log(topMarginRight);
}
});
}); // end of the each function creating the charts
$.each(Highcharts.charts, function (i, chart) {
chart.margin[1] = topMarginRight;
chart.isDirtyBox = true;
chart.redraw(false);
})
Demo #2: http://jsfiddle.net/28hrffv7/4/ (for Highcharts < 5.0.0)
UPDATE:
With Highcharts 5+ the same is possible through a chart update.
$.each(Highcharts.charts, function (i, chart) {
chart.update({
chart: {
marginRight: topMarginRight
}
});
})
Demo #3: http://jsfiddle.net/28hrffv7/5/
In case of multiple series in each chart you could call a custom function for events like load, redraw, afterAnimate.
Demo #4: http://jsfiddle.net/acjaLxj1/1/

position ticks in par with data - highcharts

I have a 'datetime' chart which has one point per day. So my requirement is to have each date displayed on x-axis and value plotted for each date. So I have set the tickinterval as 1 day (24*3600*1000) as follows:
http://jsfiddle.net/vuf5e/1/
However, the x-axis seems to show only Aug28th and chart has two points on either side of it instead of showing one point for Aug27th and another one for Aug28th.
I tried using tickPositions and the chart appears as follows:
http://jsfiddle.net/vuf5e/2/
What is wrong here?
One of the numbers is wrong.
the second position in the tick is 137766608975 but then in the data is 1377666808975 which has a full digit more than the other.
You are in fact missing an 8 somewhere in the middle.
so basically the number on the second tick become smaller than the first one.
[...]
xAxis: {
type:'datetime' , tickPositions:[1377601929269, **137766608975**]
},
series:[{"yAxis":0,"name":"Device_INTERFACE_in_octets--.2","data":[[1377601929269,5.8583],[**1377666808975**,6.6278]]}]
});
});

How do I get x-axis to expand to take more of the chart width

As you can see from the attached image, my x-axis categories are getting bunched together in the middle. How can I configure highcharts to take up more of the x-axis? Note: The chart size is dynamic, it grows and shrinks based on the overall browser size and split-panels within the app. So explicit computation of the point-width is not an option (I expect highcharts to do the work for me).
Note: The picture is vertically cropped.
The chart options I'm using are:
highchart.setAnimation(false);
Legend legend = new Legend();
legend.setEnabled(false);
highchart.setLegend(legend);
highchart.getXAxis().setCategories(result.getAxisXCategories().toArray(new String[] {}));
highchart.setType(Series.Type.COLUMN);
ColumnPlotOptions options = new ColumnPlotOptions();
options.setStacking(Stacking.NORMAL);
options.setGroupPadding(0);
options.setAnimation(true);
highchart.setColumnPlotOptions(options);
In other words, legend is turned off and column plot options is set to zero group-padding.
UPDATE: Here is a JSFiddle showing the same issue
For others who run into the same issue, the solution is to set the pointRange option of the ColumnPlotOptions. In JSON this looks like:
"plotOptions": {
"column": {
"stacking": "normal",
pointRange: 1,
"groupPadding": 0
}
}
In GWT-Highcharts, you don't actually have a specific API for pointRange. Therefore set a generic option like this:
ColumnPlotOptions options = new ColumnPlotOptions();
options.setOption("pointRange", 1.0);
...
You can try to set pointWidth() http://api.highcharts.com/highcharts#plotOptions.column.pointWidth

Highcharts x-axis label

In chart, the x-axis labels are overlapping, when chart data is big.
I have used "step" property as follows :
xAxis: {
labels:{
step: (stepVal ? stepVal : 0),
},
}
I calculate the value of stepVal, depending upon data.
This resolves the issue of overlapping labels on x-axis.
But, when I zoom the chart, I want to see all the labels on x-axis.
How to get it?
In Highcharts 3.0 you can use
chart.xAxis[0].update({
labels: {
step: newValue
}
}
for updating step. Just setting new value in options for new chart won't work.
I believe what you are looking for is this..
http://api.highcharts.com/highcharts#chart.events.selection
You would need to change the xAxis labels steps in the event of a zoom action. You will need to determine how many labels you would want to show, based on how many labels are visible as a result of the zoom.

Resources