Highcharts: Restricting nth label on a category axis - javascript

I have a category axis where categories are shown on the y-axis. The labels displayed are automatically chosen by highcharts from the categories array. The index of the category determines what label is shown on the axis. The index is calculated automatically by highcharts and it does a fairly good job with it. But sometimes the next index exceeds the length of the categories array and when this happens the index number is shown on the axis. This makes it look bad among the other labels.
Using steps
labels: {
step: <number>
}
helps prevent this issue but I prefer highcharts automatic calculation , is there anyway I can avoid showing the index which exceeds the length of the categories array?

I think this is caused by yAxis.endOnTick which is set to true by default: https://jsfiddle.net/ky40k1mk/3/ vs https://jsfiddle.net/ky40k1mk/2/
Of course, instead of removing last tick (so the chart will end in nowhere), we can replace last tick, using xAxis.tickPositioner, see demo: https://jsfiddle.net/ky40k1mk/4/ (or: https://jsfiddle.net/ky40k1mk/5/ )
And tickPositioner:
tickPositioner: function() {
var ticks = this.tickPositions,
last = ticks.length - 1;
if (ticks[last] > this.dataMax) {
ticks.splice(last, 1, this.dataMax); // replace last tick with current max
}
return ticks;
}

Related

Serial chart which starts from 0 if only positive values are present, but accepts negatives as well

So basically I need a serial chart, but if only positives are entered, no mattter what values they have, then the chart would always show 0 as a base value and if in case there are any negative values, then to display them as well.
If I use the "minimum" property for ValueAxis and set it to zero, this prevents the chart from displaying negatives, while the "baseValue" set to 0, doesn't force the chart to use 0 as a base at all times, but caluclates based on the values that are passed.
Here's an example:
http://jsfiddle.net/b3kyos6g/
"valueAxes": [{
"position": "left",
"title": "Visitors",
"baseValue": 0,
}],
Just change the negative value to a positive one (remove the -)
The documentation probably isn't clear on how baseValue works. baseValue is used to redefine the "zero line", meaning that area graph fills will go to that value, and columns start at that value. It has nothing to do with the scale or minimum/maximums of the axis.
To make the chart automatically start from zero if your values are all positive, you can write a mini-plugin using AmCharts.addInitHandler to check your data values and set the minimum as appropriate prior to the chart's initialization, like so:
// Mini plugin to force a zero minimum on the first value axis if all values
// are non-negative. Can be extended to support multiple value axes if needed.
AmCharts.addInitHandler(function(chart) {
//get all value fields if there are multiple graphs
var valueFields = chart.graphs.map(function(graph) {
return graph.valueField;
});
//find out if there are any negative values in the dataProvider for any graph.
var containsNegatives = chart.dataProvider.some(function(dataItem) {
return valueFields.some(function(valueField) {
return dataItem[valueField] < 0;
});
});
//only set the value axis minimum to 0 if there are no negatives.
if (!containsNegatives) {
chart.valueAxes[0].minimum = 0;
chart.validateData();
}
}, ['serial']);
Here's an updated fiddle that demonstrates this using two charts.

How do I dynamically set the scale of y-axis for c3 chart?

I'm making a c3 chart that has grouped data, and I'd like to have a y-axis grid line that shows a maximum value, that the grouped data combined should not exceed.
So, the y-axis grid line could be called "Maximum"
I know how to make the grid, but it doesn't always show because the grouped data might be way below the grid value. But I want the grid to always show.
I looked at padding for the y-axis, but it's uses pixels and is hard to get accurate.
Is there a away to just set the y-axis to show like 5 values greater than whatever the y-axis grid line is?
Unfortunately, C3 does not have a setting for "set Y axis to maximum of yvalue or largest data". However, let's assume you have added a grid line using a method like below. You can then set the y-axis padding and maximum value using the settings shown here:
grid: {
y: {
lines: [{ value: 20 }],
}
},
axis: {
y: {
padding: {top:5, bottom,0},
max: 20
}
}
In this case I have set the max value to be the same as the gridline value and used padding to create a small space above it. This will handle the case where your data is below the gridline. However, if your data exceeds the (gridline+padding) total then the chart won't grow to accommodate that data because the max setting is fixed. So, you will need to dynamically change this max value using javascript if your data is greater than the max value by finding the maximum value in your data and setting max above that if it exceeds your gridline value, something like this...
if(highValue > gridlineValue)
chart.axis.max(highValue);
else
chart.axis.max(gridlineValue);
I just noticed that your data never exceeds the gridline, so you can go with the first part of this answer. I've left the rest in here in case someone else wants a more dynamic solution. Note that you could also just use the max value without padding if you wanted to set it explicitly to a value higher than the gridline.
As of this writing, there actually is a way to reset the y-max to be dynamic, after setting it to specific max. You do so by setting max to undefined, like so: chart.axis.max(undefined);.
Here, have a working jsfiddle.

Highstock gapsize is causing line rendering issue

I'm using Highstock (v4.2.3) to present data in a StockChart with a number of different Y axes, all plotted against time on the X axis. The data has gaps in it, and I'd like to depict those gaps, but when I turn on gapSize (with any value other than zero), there's a weird quirk that causes line rendering issues--when using the navigator to zoom in on certain date ranges (not all), in some cases (whose pattern I've yet to discern) the chart fails to fully render the line across the entire x axis.
This annotated screenshot depicts the issue.
When I turn gapSize off (or explicitly set it to zero), this problem goes away. Note that the gaps themselves appear correctly on the chart (when navigating to a date range that doesn't present the line rendering issue).
plotOptions: {
series: {gapSize:2}
}
Any ideas?
jsFiddle with your issue:
http://jsfiddle.net/2N52H/109/
As you can read in our API:
http://api.highcharts.com/highstock#plotOptions.line.gapSize
A gap size of 5 means that if the distance between two points is
greater than five times that of the two closest points, the graph will
be broken
As far as I know data you have has random gaps so you will never know what is the distance between two closest points. For example if you will have data in every one hour, distance between two closest points will be 15 minutes and your gapSize will be set to 2, you will see only your closest points.
When you are using zoom sometimes your visible data closest distance is changing so the gaps are changing as well.
See this example:
http://jsfiddle.net/2N52H/111/
Maybe you can use xAxis.ordinal parameter to visualise your gaps:
http://api.highcharts.com/highstock#xAxis.ordinal
You can also change standard functionallity by using wrapper. Here you can read about it:
http://www.highcharts.com/docs/extending-highcharts/extending-highcharts
For example you can change gappedPath function:
(function(H) {
H.wrap(H.Series.prototype, 'gappedPath', function(proceed) {
var gapSize = this.options.gapSize,
xAxis = this.xAxis,
points = this.points.slice(),
i = points.length - 1;
if (gapSize && i > 0) { // #5008
// extension for ordinal breaks
while (i--) {
if (points[i + 1].x - points[i].x > gapSize) {
points.splice( // insert after this one
i + 1,
0, {
isNull: true
}
);
}
}
}
return this.getGraphPath(points);
})
}(Highcharts))
example:
http://jsfiddle.net/2N52H/113/
Kind regards.

Strange tooltip behavior with long series in highcharts

I'm using Highcharts for a project in which I have to display two series with about a thousand points each. The x-axis represents a date, and the y-axis a quantity. In addition, each point has an associated list of namesMy data is day-by-day without gaps, with a structure such as
var mydata = [ ...
{x: theDate, y: theValue, names: theNames},
... ]
where theNames is an array of strings. I can access these in the tooltip formatter through this.points.point.names, given that the range displayed on the chart is small enough. If I change the x-axes so that the start date and end date are more than roughly a year apart, then the tooltip is not rendered at all.
One of the possible avenues that I have tried but failed with so far is setting the turboThreshold limit to the length of the longest series plus 1. Setting this lets me at least display a graph when mydata.length > 1000 (the default value). However, this only displays the tooltip if the x-axis range is less than 261. Otherwise, the tooltip disappears entirely, as does the point.data object where I'm getting the name from.
I'm also not great at JavaScript, but I was wondering if there were a way to separate the names of the points from the array containing them (in my examples, myData1 and myData2) and somehow access those names from the tooltip function without going through the current point.
Here is the link to the jsFiddle demonstrating this issue.
All help is appreciated!
The problem is in dataGrouping, when disabled works fine: http://jsfiddle.net/34tfg/1/
DataGrouping is method in Highcharts to approximate points and display them when width of the chart is not enough, e.g. how to display 10 000points in a chart of width 1 000px -> 10 points in a one pixel..? And when dataGrouping is used, new points are created, so all your custom options like 'names' etc. are lost (at least not accessible).
Code:
plotOptions: {
line: {
dataGrouping: {
enabled: false
},
turboThreshold: 10000
}
},

Highcharts - Issue with negative values when displaying multiple axes

We're attempting to display two series of data on the same chart. The first series (ie: number of quotations) can only contain positive integers (and 0). The second series (ie: sales value) can contain both positive and negative float values (in case you're wondering, the negative values result from the issuing of credit notes).
As indicated on the attached image, the problem we're having is that when the second series contains negative values, the 0-point "base line" of the two series of data is no longer shared.
We've tried setting the "min" options of the Y axes to 0, but then we lose out the insight on negative values.
We've also tried setting the min of the first series to be equal to the minimum extreme of the second series, but unfortunately this doesn't scale the columns very nicely (since the values of each Y axis are on completely different scales, ie: 10s vs 1000s).
How can we configure the chart so that the 0-point "base line" is shared? In other words, how would we make the blue columns start at the same base line as the green 0 point?
Update
Linger's answer is a step in the right direction. Setting the min and tickinterval for both axes does the trick. However the values need to be determined dynamically based on variable data, which is where I am now stuck.
Any tips on how these min and tickinterval values can be determined before I generate the chart?
I've done some thinking about it in the mean time. The values associated with the left axis (blue / quotations) are always positive and start from zero. Thus it is the right axis (green / sales) that dictates the number of ticks to show below the zero point. Now since highcharts automatically determines the best scale for both blue and green, all I need to do is find a way to set the left axis' minimum value like so (excuse the pseudo-code):
var factor = right_axis.min / right_axis.tickinterval;
left_axis.min = factor * left.tickinterval;
Note: I have seen the reference API has a setExtremes() method under Axis, but this would require me to first initialise the chart, and then go back and update its left axis. I am hoping to do this before drawing the chart. Perhaps I'm overlooking something obvious?
Thanks.
You can control what you are asking for with a combination of tickInterval and min on the yaxis as demonstrated in this jsfiddle mock up.
EDIT
In your code while reading in the XML you will have to keep track of what the lowest value is and also the highest value on the sales side. Then decide how you want to display those values if they meet a certain value. After that use if statements to set the values. Here is a couple of examples.
Low less than -50 and greater -90
With High less than 400
Primary Axis: min: -2, tickInterval: 1,
Secondary Axis: min: -100, tickInterval: 50
Example
Low less than -50 and greater -90
With High greater than 400
Primary Axis: min: -1, tickInterval: 1,
Secondary Axis: min: min: -100, tickInterval: 100,
Example
To figure out what the min on the Primary Axis should be you simply divide the min on the Secondary Axis by its tickInterval. Then the tickInterval for the Primary Axis would always be 1.
You can also calculate second axis tick positions based on the max series value related to this axis and the first axis ticks positions to get the same amount of ticks and 0 line shared.
Using axis.update() method update tick positions in the second axis using property tickPositions.
Example with a load event. Notice, that when you add points dynamically you have to make those calculations and update tick positions each time your first axis ticks will change:
chart: {
type: 'column',
events: {
load: function() {
var chart = this,
yAxis = this.yAxis,
max = yAxis[1].dataMax,
positiveTicksAmount = 0,
negativeTicksAmount = 0,
tickPositions = [],
tickInterval,
min,
i;
yAxis[0].tickPositions.forEach(function(tick) {
if (tick > 0) {
positiveTicksAmount++;
} else if (tick < 0) {
negativeTicksAmount++;
}
});
tickInterval = max / positiveTicksAmount;
for (i = negativeTicksAmount; i > 0; i--) {
tickPositions.push(-tickInterval * i);
}
for (i = 0; i <= positiveTicksAmount; i++) {
tickPositions.push(
tickInterval * i
);
}
yAxis[1].update({
tickPositions: tickPositions
});
}
}
},
Jsfiddle examples:
https://jsfiddle.net/wchmiel/84q0sxrt/
http://jsfiddle.net/wchmiel/nuj7fagh/
Api reference:
https://api.highcharts.com/class-reference/Highcharts.Axis#update
https://api.highcharts.com/highcharts/yAxis.tickPositions

Categories