I want to enforce that the axis of my bubble chart to starts at 0. In any other chart type I would set
yAxis: {
min:0
}
But this can cause bubbles with an y value near zero to be clipped.
All I could come up with so far is to add an invisible dummy series to force the axis to start at 0.
See http://jsfiddle.net/kzoon/jd3c9/ for my problem and workaround.
Has anyone a better solution to this problem?
How about using tick positioner? It allows you to programmatically set tick positions. Take a look into the docs: http://api.highcharts.com/highcharts#yAxis.tickPositioner
Sample function can work like this:
Find axis min and max values
If min is greater than 0, use 0 as min:
Add ticks every "20" unless we achieve max value
Here you can find the code:
yAxis: {
tickPositioner: function () {
var positions = [],
min = Math.floor(this.min / 10) * 10,
max = Math.ceil(this.max / 10) * 10,
step = 20,
tick;
if (min > 0)
min = 0;
tick = min;
while (tick < max + step) {
positions.push(tick);
tick += step;
}
return positions;
}
},
and working demo on jsfiddle: http://jsfiddle.net/2ABFW/
You can use startWithTick: http://jsfiddle.net/jd3c9/8/
yAxis: {
startWithTick: true
}
Now your y-axis will display the next tick under 0 (-20 in this case) and no bubble will be clipped.
Related
I have created a line chart in Google Sheets using data pulled from an API. The data changes every hour, so the min and max values of the data to chart also changes.
I would like to know if there is a script that can lookup up min and max from a column of data and use those values to dynamically set min/max for the Y axis.
Currently the only way I can see to change Y axis min max is manually in the chart editor, but the inputs only accept numbers, not formulas, so the min max is rigid.
// Only applies to first y axis
// Only applies to charts on active spreadsheet
// Allows for multiple series
// Takes approx 3 seconds per 10 charts to run
// Change Sheet1 for your sheet name
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1')
var config = {
// y-axis max is this factor higher than your chart's max value
// For example if your max value is 100 and scaleUpBuffer is 0.1,
// the y-axis max value will be set to 100 * (1 + 0.1) = 110
scaleUpBuffer: 0.0001,
// y-axis min is this factor lower than your chart's min value
scaleDownBuffer: 0.0001,
// If / when google fix goes through,
// set this to true and run fixCharts() to get default scaling back
// This sets min and max y axis values to null (the default)
restoreDefault: false,
}
function fixCharts() {
var minMaxY1;
sheet.getCharts().forEach(function (chart) {
minMaxY1 = config.restoreDefault ? [null, null] : getChartMinMaxY(chart, config);
updatedChart = chart
.modify()
.setOption('vAxes', {0: {viewWindow: {min: minMaxY1[0], max: minMaxY1[1]}}})
.build();
sheet.updateChart(updatedChart);
})
}
function getChartMinMaxY(chart, config) {
var chartRangeArray,
y1 = [];
chart.getRanges().forEach(function(chartRange) {
chartRangeArray = chartRange.getValues();
chartRangeArray.forEach(function(row) {
for (var i=1;i<row.length;i++) {
// loops all series, assumes all on 1st y axis
if (typeof row[i] == 'number') {
// ignores blanks, headers, junk strings etc.
y1.push(row[i]);
}
}
});
});
return [
Math.min.apply(null, y1) * (1 - config.scaleDownBuffer),
Math.max.apply(null, y1) * (1 + config.scaleUpBuffer)
];
}
I am trying to create a reference line that runs through the origin and passes from negative to positive. See an example of what i am trying to achieve - see the threshold line. This threshold line must run through all three x, y coordinates (-1,-45,000), (0.0), (1, 45,000).
enter image description here
Below is my work so far.
http://jsfiddle.net/catio6/rhf6yre5/1/
I've looked at this for reference but have had had no luck after several hours of attempts of replicating this with all three x, y coordinates (-1,-45,000), (0.0), (1, 45,000): http://jsfiddle.net/phpdeveloperrahul/XvjfL/
$(function () {
$('#container').highcharts({
xAxis: {
categories: ['Jan', 'Feb', 'Mar']
},
series: [{
data: [29.9, 71.5, 256]
}]
}, function(chart) { // on complete
console.log("chart = ");
console.log(chart);
//chart.renderer.path(['M', 0, 0, 'L', 100, 100, 200, 50, 300, 100])
chart.renderer.path(['M', 75, 223.5,'L', 259, 47])//M 75 223.5 L 593 223.5
.attr({
'stroke-width': 2,
stroke: 'red'
})
.add();
});
});
So Highcharts doesn't have, as far as I know, a way to define a line that goes from/to infinity.
One idea I had to solve this issue for you is dynamically calculate the values for the line series based on your data. The idea is simple: Given the maximum values for X and Y you want to plot, we just need to limit the axis to a certain value that makes sense and calculate the values for the asymptote series in order to make it seems infinite. My algorithm looks like this:
// Get all your other data in a well formated way
let yourData = [
{x: 0.57, y: 72484},
{x: 0.57, y: 10000}
];
// Find which are the maximum x and y values
let maxX = yourData.reduce((max, v) => max > v.x ? max : v.x, -999999999);
let maxY = yourData.reduce((max, v) => max > v.y ? max : v.y, -999999999);
// Now you will limit you X and Y axis to a value that makes sense due the maximum values
// Here I will limit it to 10K above or lower on Y and 2 above or lower on X
let maxXAxis = maxX + 2;
let minXAxis = - (maxX + 2);
let maxYAxis = maxY + 10000;
let minYAxis = -(maxY + 10000);
// Now you need to calculate the values for the Willingness to pay series
let fn = (x) => 45000 * x; // This is the function that defines the Willingness to pay line
// Calculate the series values
let willingnessSeries = [];
for(let i = Math.floor(minXAxis); i <= Math.ceil(maxXAxis); i++) {
willingnessSeries.push([i, fn(i)]);
}
Here is a working fiddle: http://jsfiddle.net/n5xg1970/
I tested with several values for your data and all of them seem to be working ok.
Hope it helps
Regards
To preface, I am using the extended logarithm functions for negative and small numbers here:
/**
* Custom Axis extension to allow emulation of negative values on a
logarithmic
* Y axis. Note that the scale is not mathematically correct, as a true
* logarithmic axis never reaches or crosses zero.
*/
(function (H) {
// Pass error messages
H.Axis.prototype.allowNegativeLog = true;
// Override conversions
H.Axis.prototype.log2lin = function (num) {
var isNegative = num < 0,
adjustedNum = Math.abs(num),
result;
if (adjustedNum < 10) {
console.log('adjustedNum: ', adjustedNum);
adjustedNum += (10 - adjustedNum) / 10;
}
result = Math.log(adjustedNum) / Math.LN10;
if (adjustedNum < 10) console.log('result: ', result);
return isNegative ? -result : result;
};
H.Axis.prototype.lin2log = function (num) {
var isNegative = num < 0,
absNum = Math.abs(num),
result = Math.pow(10, absNum);
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}(Highcharts));
So if I have a y-axis with a dataMin of 0.22 and a dataMax of 2.34 using a log scale, the only ticks I get back are [0,1] designating 0 and 10, the bottom and top of the chart, with no tick marks in between.
1) Is there a way I can specify how many ticks I want in a log chart (tickAmount: 5 would not work)?
2) Is there a way I can tighten the range over which ticks fall? (like in this case, it sets the axis with data values between 0 and 10 even though my data series only falls between 0.22 and 2.34).
Thanks!
1.
tickPositions and tickPositioner options allow you to control where exactly the ticks will fall.
2.
You can try adjusting the tickInterval option: http://jsfiddle.net/BlackLabel/8v3xuyot/
yAxis: {
type: 'logarithmic',
tickInterval: 0.2
}
API references:
https://api.highcharts.com/highcharts/yAxis.tickInterval
https://api.highcharts.com/highcharts/yAxis.tickPositioner
https://api.highcharts.com/highcharts/yAxis.tickPositions
We are comparing multiple series using logarithmic scale. Most of the time the chart looks fine and scales correctly to min/max of the data. In the example below the top series is cut off. The only thing that changes is the data. If we change the time period to any of the other options, it will re-scale correctly, going back to 1Y has the same problem. Is there a way to resolve this issue?
The second question I have is about the logic of the grid lines/labels when in log scale. Shouldn't by default the steps be based on Log(10) for example [0.10%, 1%, 10%, 100%, 1000%]? Is there a config option to set this? In the example below the default [0.10, 0.20, 0.40, 1.00] doesn't make much sense.
This is what the labels/ticks should always look like: jsfiddle.net/TeTMw/1
EDIT:
Here is the highcharts code that looks like is causing this bug. Would be great if you could help fix this issue.
// Second case: We need intermediary ticks. For example
// 1, 2, 4, 6, 8, 10, 20, 40 etc.
} else if (interval >= 0.08) {
var roundedMin = mathFloor(min),
intermediate,
i,
j,
len,
pos,
lastPos,
break2;
if (interval > 0.3) {
intermediate = [1, 2, 4];
} else if (interval > 0.15) { // 0.2 equals five minor ticks per 1, 10, 100 etc
intermediate = [1, 2, 4, 6, 8];
} else { // 0.1 equals ten minor ticks per 1, 10, 100 etc
intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
}
for (i = roundedMin; i < max + 1 && !break2; i++) {
len = intermediate.length;
for (j = 0; j < len && !break2; j++) {
pos = log2lin(lin2log(i) * intermediate[j]);
if (pos > min && lastPos <= max) {
positions.push(lastPos);
}
if (lastPos > max) {
break2 = true;
}
lastPos = pos;
}
}
There's a known issue that log axes may be cut off in Highcharts 1.3.0. This will be fixed with 1.3.1, released later this week. See https://github.com/highslide-software/highcharts.com/issues/1666 .
For the Y axis tick interval, see http://api.highcharts.com/highcharts#yAxis.tickInterval. By default, the tickInterval is null, so the layout of the ticks is determined by tickPixelInterval. In your specific chart for example, if we skipped 0.20 and 0.40, the ticks would become too widespread for the default tickPixelInterval of 72.
the above graph shows the congestion between x and y coordinates how can that be avoided?
You can also add an offset to the labels of either xAxis or yAxis with
xAxis: {
labels: {
x: 5,
y: 5
}
}
This will move the label 5 points relative to the axis.
Increase the scale on the X axis by for example formatting x axis data to a Date without time information?