Highcharts - Issue with negative values when displaying multiple axes - javascript

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

Related

Override auto generated Y axis plot area values in Highcharts

I have certain requirement where I need to override the auto calculated values for Y axis in highcharts. For eg.
Here, the gridlines plot area is equally divided into 100. I wanted to override this so that the negative plot area should be at a max of let's say 50 and the positive ones can remain the same. Even if I try the max, min, softMax, softMin, ceiling and floor properties, the result is the same. I was thinking of using a secondary axis but then there is only one data in the series which would render the second one useless. I don't think using setExtremes() will be helpful either. I'm hoping to avoid modifying the library itself to add a certain option but it'll be helpful if such an option already exists in highcharts. Any suggestions?
Use tickPositions or tickPositioner property:
yAxis: {
tickPositions: [-50, 0, 100, 200, 300, 400]
}
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4883/
API Reference:
https://api.highcharts.com/highcharts/yAxis.tickPositions
https://api.highcharts.com/highcharts/yAxis.tickPositioner

Chartjs v2.5 - only show min and max on scale, absolute positioning on scale

I created a very simple line chart, for use on mobile devices. I find that when I include the scale, it takes up a lot of space on the side of the chart.
Instead, what I've seen accomplished on other mobile charts is only showing the minimum and the maximum value. A user can use the tooltip to find specifics.
Anyway, I'm hoping someone can show me how to create a scale such as the one here:
The two main takeaways of this scale:
Only the min and max values are shown
They are shown with absolute positioning approximately in the top left and bottom right corners.
My thought process was possibly using the scaleOverride, then just defining scaleSteps : 1 with a scaleStepWidth equal to the difference between the min and max of my data. Even if this is on the right track, I don't know how I would override the positioning of the scale to be absolute and not take space away from the line itself.
I've broken this answer down into the steps needed to get your chart to look like the provided image:
1. Only show max and min labels
First, use JavaScript max() and min() methods to determine the highest and lowest values in the data array:
var min = Math.min(...data);
var max = Math.max(...data);
Then, add the following options to the yAxes ticks configuration section:
Set the max and min values to the data array max and min values.
Set stepSize to the difference between the max and min value. This will ensure that it only shows the highest and lowest numbers in the labels.
2. Move labels to inside the right side of the chart
This can be done in two steps:
Add position: "right" to move the align the scale yAxes to the right side of the chart.
Set mirror: true in the ticks configuration to flip the labels over the yAxes, to get them to show inside the chart.
3. Format number with dollar sign and 2 decimal places
To format the numbers with a dollar sign and two decimal places, add a callback function to the ticks options:
callback: function(value) {
return '$' + value.toFixed(2);
}
See How To Format Scale Numbers in Chart.js v2 and Formatting a number with exactly two decimals in JavaScript for more information.
4. Change color or hide the yAxes grid line
Although your question is about changing the color of the grid line, based on the provided image, I am assuming you want to remove the yAxes line. To remove the grid line, set drawBorder to false in the grid line configuration settings.
If you do want to change the grid line color to white, color: "#fff" will work, you just need to make sure that you put that line in the gridLines config section like:
gridLines: {
color: "#fff"
}
5. Change label font formatting
This wasn't in your questions, but if you want to change to label font color and sizing, simply use the fontColor and fontSize tick config options.
Final yAxes code:
yAxes: [{
id: 'share_price',
type: 'linear',
position: "right",
gridLines: {
display: false,
drawBorder: false,
//color: "#fff"
},
ticks: {
stepSize: max - min,
min: min,
max: max,
mirror: true,
fontColor: "#fff",
fontSize: 18,
callback: function(value) {
return '$' + value.toFixed(2);
}
}
}]
JSFiddle Demo: https://jsfiddle.net/ujsg9w8r/5/

Highstock - how to shift the X axis

I have the following chart here:
what I'd like to do is shift the X axis so that the path only reaches the half of the width and the rest is blank (planning to put some plotlines there of some future events) - any ideas how to do it? Cheers :)
To achieve this you simply need to give your x axis a max property.
max: Number
The maximum value of the axis. If null, the max value is automatically calculated. If the endOnTick option is true, the max value might be rounded up.
– xAxis.max - Highstock API
They give a demo of this here: http://jsfiddle.net/gh/get/jquery/2/highcharts/highcharts/tree/master/samples/stock/xaxis/min-max/
In your case, if you're wanting your current data to end half way along the x axis, you need to set the max to the difference between where the data starts and where the data currently ends on top of the point the data currently ends.
As you haven't specified any code yourself, I'm going to use dummy values. If your x axis data starts at 5 and ends at 8, the difference between 5 and 8 is 3, so you need to add that to 8 to offset the chart:
xAxis: {
max: 11 // (8 - 5 + 8)
}

Set a minimal default range for a column chart in Highcharts

I'm using Highcharts for a column chart that has positive and negative percentage values.
I always want the y-axis of the chart to display at least the range between -50% and +30%, no matter what the values are. However, if a value is larger than 30% or small than -50% the range of the y-axis should adapt accordingly. if I use yAxis: {min: -50, max: 30} the range won't get bigger when I have larger values.
Is there a way to do this? Or do I have to update it programmatically once Highcharts has calculated the range?
Currently you have to do it yourself.
It can be accomplished by running a function to check the min/max and reset if needed.
Something like this (quick dirty example):
function setMinAxisExtremes(chart, axis, min, max) {
var ax = axis == 'y' ? chart.yAxis[0] : chart.xAxis[0];
var ext = ax.getExtremes();
min = ext.min > min ? min : ext.min;
max = ext.max < max ? max : ext.max;
ax.setExtremes(min,max);
}
Example:
http://jsfiddle.net/jlbriggs/szub0o3g/
(and as noted above, there is a feature request to have Highcharts do this with a built in property, which is sorely in need of votes, here: http://highcharts.uservoice.com/forums/55896-general/suggestions/1848953-extend-the-axis-max-property-to-act-like-css-mi )
You can prepare your own function to position ticks, it is tickPositioner

What the right way to graph negative numbers in Protovis?

For the simplest use case, a bar chart with values ranging from -10 to 10, how does one go about coding this cleanly using the Protovis JavaScript charting library?
By cleanly I mean centering the axis, showing x and y axis labels, and representing the column values of the chart where negative values fall below the y axis and positive values exceed the y axis.
Here's a working example: http://jsfiddle.net/nrabinowitz/yk5By/3/
The important parts of this are as follows:
Make an x-axis scale going from your min value to your max value (in your case, it would be pv.Scale.linear(-10,10).range(0,w); in my example, I calculate min and max based on the data).
Base the width of the bar on the absolute distance of the datum from 0:
.width(function(d) { return Math.abs(x(d) - x(0)); })
Then adjust the .left() property based on whether the datum is positive or negative:
.left(function(d) { return d > 0 ? x(0) : x(0) - this.width(); });
Because we're using a simple x-axis scale, the adding axis labels is super-easy:
vis.add(pv.Label)
.data(x.ticks()) // you could also use pv.range(min, max, 1) here
.left(x);

Categories