Highcharts Stock Chart - Custom X axis date times format - highcharts

I'm wondering if it's possible to define a custom ordering or format for the xAxis in stock highcharts. My dataset has a date time which would be used for the xAxis however my client has specified that it should show in the middle T-0 on the xAxis. Rest of them from the left side should be like -3m -2m -1m and from the right side +1m +2m +3m(In case of year timeframe).
Example for 1 year timeframe
I have tried using formatter function on xAxis labels. However I can not figure out how to get the middle tick first and then start chaging labels to the left and to the right from that middle position tick.

If the formatting, amount and interval of the labels is static, you can use variables from outside of the chart.
For example:
const labels = [];
let labelIndex = 0;
for (let i = -6; i < 7; i++) {
labels.push(i);
}
Highcharts.stockChart('container', {
xAxis: {
...,
labels: {
formatter: function() {
labelIndex++;
if (this.isFirst) {
labelIndex = 0;
}
const label = labels[labelIndex];
if (label < 0) {
return label + 'm';
} else if (label === 0) {
return 'T-' + label;
}
return '+' + label + 'm';
}
}
},
...
});
Live demo: http://jsfiddle.net/BlackLabel/L7uy29kw/
API Reference: https://api.highcharts.com/highstock/xAxis

Related

Highchart - Boxplot - Extra category shown with no data

When I'm drawing BOX Plot chart with Highchart like this : JSFiddle
chart: {
type: 'boxplot',
}
where category 2 "Merchant 2" is shown on x-axis even though we don't have data for it.
How can we avoid rendering categories on x-axis when they don't have data in box plot ?
Thank you
There's no built in mechanism in Highcharts that'll filter out and hide "unused" categories.
Workaround:
breaks functionality allows to hide regions on axes. Here's an algorithm that finds the categories that don't have any points above them and applies breaks:
render: function() {
if (redrawEnabled) {
redrawEnabled = false;
var emptyCategories = [],
series = this.series,
xAxis = this.xAxis[0],
categories = xAxis.categories.slice(),
categoryFlags = new Array(categories.length).fill(false), // indicates if any point has a value for category with the given index
breaks = [],
correspondingPoint;
// find out which categories are 'used'
for (var i = 0; i < categories.length; i++) {
for (var ii = 0; ii < series.length; ii++) {
if (!series[ii].visible) {
continue;
}
correspondingPoint = series[ii].data.find((point) => point.x === i);
if (correspondingPoint) {
categoryFlags[i] = true;
break;
}
}
}
// create and apply breaks
categoryFlags.forEach(function(flag, index) {
if (!flag) {
breaks.push({
from: index - 0.5,
to: index + 0.5
});
}
});
//console.log(breaks)
xAxis.update({
breaks: breaks
});
}
redrawEnabled = true;
}
Live demo: http://jsfiddle.net/BlackLabel/fubwdm4x/
The key to understand how this solution works is that the categories are basically just information how to format axis' labels and position ticks. The tickInterval is always 1 and ticks are moved -0.5 to the left. So if you have categories like this: ['Category 1', 'Category 2', 'Category 3'] the positions of ticks are: -0.5, 0.5, 1.5 and 2.5.
API reference: https://api.highcharts.com/highcharts/yAxis.breaks

Highcharts : Set an y offset to the series

Situation : Chart with some analogic-series and some digital-series (0-1).
The problem is with the digital series. I would like to make sure that the series do not overlap like the image 1.
My idea is to set an "y-offset" on the digital-series, to have a result like the image 2.
This is a part of the y Axis configuration of the digital series. All the digital-series is related to a single y Axis (with id digital).
id : "digital",
min: 0,
max : 1,
ceiling:1,
floor : 0,
tickInterval: 1
Image 1.
Image 2.
In the documentation i can't find anything that can help me. And this is not my case.
UPDATE
Example on JSFIDDLE. Look (yes it's impossible currently) at the digital series with green color.
If you add a function in the load event, you can change the value of y in a way that makes it look offset. Like this:
chart: {
events: {
load: function() {
var series = this.series;
for (var i = 0; i < series.length; i++) {
if (series[i].yAxis.userOptions.id == "digital") {
for (var j = 0; j < series[i].data.length; j++) {
if (series[i].data[j].y == 1) {
series[i].data[j].y = 1 + 0.1 * i;
} else {
series[i].data[j].y = 0
}
}
this.update(series, true, false);
}
}
}
}
}
This sets the new y value equal to 0.1 * the series index.
Working example: https://jsfiddle.net/u2pzrhgk/27/

Highcharts bar chart with varied bar widths?

I want to make stacked bar chart where each portion has a width that encodes one value (say "Change" in the data below) and a height that encodes another value ("Share")
In some ways this is like a histogram with different bin sizes. There are a few "histogram" questions but none seem to address this. Plot Histograms in Highcharts
So given data like this:
Category Share Price Change
Apples 14.35 0.1314192423
Horseradish 46.168 0.1761474117
Figs 2.871 0.018874249
Tomatoes 13.954 0.0106121298
Mangoes 7.264 0.1217297011
Raisins 5.738 0.0206787136
Eggplant 6.31 0.0110160732
Other produce 3.344 0.0945377722
I can make a stacked bar that captures the "share" column in widths:
And another that captures the "change" column in heights:
And I can use an image editor to combine those into this histogram-like beast:
Which really captures that horseradish is a huge deal. So my question is, can I do that within Highcharts?
You can realise that by using snippet.
(function (H) {
var seriesTypes = H.seriesTypes,
each = H.each,
extendClass = H.extendClass,
defaultPlotOptions = H.getOptions().plotOptions,
merge = H.merge;
defaultPlotOptions.marimekko = merge(defaultPlotOptions.column, {
pointPadding: 0,
groupPadding: 0
});
seriesTypes.marimekko = extendClass(seriesTypes.column, {
type: 'marimekko',
pointArrayMap: ['y', 'z'],
parallelArrays: ['x', 'y', 'z'],
processData: function () {
var series = this;
this.totalZ = 0;
this.relZ = [];
seriesTypes.column.prototype.processData.call(this);
each(this.zData, function (z, i) {
series.relZ[i] = series.totalZ;
series.totalZ += z;
});
},
translate: function () {
var series = this,
totalZ = series.totalZ,
xAxis = series.xAxis;
seriesTypes.column.prototype.translate.call(this);
// Distort the points to reflect z dimension
each(this.points, function (point, i) {
var shapeArgs = point.shapeArgs,
relZ = series.relZ[i];
shapeArgs.x *= (relZ / totalZ) / (shapeArgs.x / xAxis.len);
shapeArgs.width *= (point.z / totalZ) / (series.pointRange / series.xAxis.max);
});
}
});
}(Highcharts));
Example: http://jsfiddle.net/highcharts/75oucp3b/

Pie chart legend shows empty values

Using dot net highcharts and the label formatter to only display certain items in the legend, it displays values that have been returned as ''.
.SetLegend(new Legend { Enabled = true, LabelFormatter = "function() { if (this.y >= 5) { return this.name; } else { return ''; } }" })
You can disable default legend and create your own as HTML. Then you can control which point should be or not displayed.
Example: http://jsfiddle.net/N3KAC/1/
$legend = $('#customLegend');
$.each(chart.series[0].data, function (j, data) {
$legend.append('<div class="item"><div class="symbol" style="background-color:'+data.color+'"></div><div class="serieName" id="">' + data.name + '</div></div>');
});
$('#customLegend .item').click(function(){
var inx = $(this).index(),
point = chart.series[0].data[inx];
if(point.visible)
point.setVisible(false);
else
point.setVisible(true);
});
The formatter only formats the text that gets displayed - it does not determine whether or not there is a legend entry for a series.
What you need is the showInLegend property, and you will need to run your check on the series object, not on the legend.
Reference:
http://api.highcharts.com/highcharts#plotOptions.series.showInLegend

Highcharts label format with tickPositioner in a datetime x Axis

In my chart ,I try to display only 5 ticks in a datetime axis, I use the tickPositioner function and set only 5 ticks ,this work perfect but the data labels loss it's format and show only numbers.
I use the formatter function but i need a grouping labels for the zoom.
It's little hacky, but you need also calculate information about labels and add them, for example: http://jsfiddle.net/AVhaL/
tickPositioner: function (min, max) {
var ticks = this.getLinearTickPositions(this.tickInterval, min, max),
tLen = ticks.length;
ticks.info = {
unitName: "week",
higherRanks: {},
totalRange: ticks[tLen - 1] - ticks[0]
};
return ticks;
}
So according to totalRange, you need to pass unitName - it's information which format should be taken from dateTimeLabelFormats.
You only need format label, after put ticks.
Options.xAxis.tickPositioner = function () {
const ticks = this.series[0].xData;
let result = [];
for (let index = 0; index < ticks.length; index++) {
result.push(ticks[index]);
}
return result;
};
and format xAxis
labels: {
format: "{value:%b-%Y}",
align: "center"
}
to tooltips
tooltip: {
valueSuffix: "",
valuePrefix: "",
xDateFormat: "%B - %Y",
valueDecimals: 0
},

Resources