I'm trying to assign categories to the Y Axis on a column chart. I've tried using categories but this causes a peculiar result with the columns not reaching the X Axis, and the values being incorrect
https://jsfiddle.net/fmgLa5h4/1/
I've tried various other properties to correct this but to no avail.
I've also tried using labels.formatter, which gets a slightly more desirable result but with the labels aligned to the ticks - again I've tried other ways to correct this without success
https://jsfiddle.net/fmgLa5h4/2/
You can try to mapping the data using data.seriesMapping and set your own dataLabels or categories, take a look at this example:
var categories = ['A', 'B', 'C', 'D', 'E'],
yAxisLabels = ['10', '20', '30', '40', '50'];
Highcharts.chart('container', {
data: {
csv: document.getElementById('data').innerHTML,
seriesMapping: [{
// x: 0, // X values are pulled from column 0 by default
// y: 1, // Y values are pulled from column 1 by default
label: 2 // Labels are pulled from column 2 and picked up in the dataLabels.format below
}]
},
chart: {
type: 'column'
},
title: {
text: 'Daily runs'
},
xAxis: {
minTickInterval: 24 * 36e5
},
yAxis: {
labels: {
formatter: function() {
return yAxisLabels[this.value] + ', ' + this.value || '';
},
},
tickInterval: 1,
max: categories.length - 1,
},
legend: {
enabled: false
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
format: '{point.label}'
},
}
}
});
For formatting data tables, yAxis.labels.formatter is a good option. It is possible that your data will need to be formatted before you map it.
Sample concept:
data = data.replace(/\r\n/g, '\n') // Unix
.replace(/\r/g, '\n') // Mac
.split('\n');
data.forEach(function(row, i){
if (i) {
row = row.split(',');
data[i] = row.concat([
categories.indexOf(row[1]),
categories.indexOf(row[3])
]).join(',');
}
});
data = data.join('\n');
Live demo:
https://jsfiddle.net/BlackLabel/g5svkrac/
API References:
https://api.highcharts.com/highcharts/yAxis.labels.formatter
https://api.highcharts.com/highcharts/data.seriesMapping
You meant to positioning the label, you can use yAxis.labels.y to position offset of all labels relative to the tick positions on the axis.
https://jsfiddle.net/BlackLabel/g5svkrac/1/
I have an API which returns JSON data like this:
[
{
"name":"Something",
"data":[
{
"x":1541096421,
"y":2
},{
"x":1541436378,
"y":4
},{
"x":1553621371,
"y":2
}
]
},{
"name":"Something else",
"data":[
{
"x":1541096421,
"y":2
},{
"x":1541436378,
"y":4
},{
"x":1553621371,
"y":2
}
]
}
]
The x axis represents date/time and the y axis is a score. It's plotted on a chart like this, using some formatting to convert the date from millisecond timestamp to a readable date format:
function renderChart(data) {
$('#chartContainer').highcharts({
chart: {
type: 'scatter',
zoomType: 'xy'
},
title: {
text: chartTitle()
},
xAxis: {
allowDecimals: false,
title: {
text: 'Date completed',
scalable: false
},
type: 'datetime',
labels: {
formatter: function () {
if (true) {
return Highcharts.dateFormat('%d-%b-%y', moment.unix(this.value));
}
else {
if (this.value > 0 && this.value < 24) {
return this.value;
}
else
return 0;
}
}
},
tickPixelInterval: 100
},
yAxis: {
title: {
text: 'Score'
}
},
plotOptions: {
scatter: {
marker: {
radius: 5
}
}
},
series: data,
exporting: {
buttons: {
contextButton: {
menuItems: Highcharts.getOptions().exporting.buttons.contextButton.menuItems.filter(item => item !== 'openInCloud')
}
}
// Tried adding this but it doesn't make any difference:
/*,
csv: {
dateFormat: '%d/%m/%Y'
}*/
},
tooltip: {
formatter: function () {
return 'Score of <b>' + this.y + '</b> posted on <b>' + Highcharts.dateFormat('%d-%b-%y', moment.unix(this.x)) + '</b>';
}
}
});
}
This works fine. However, when I click 'export to CSV' in the Highchart graph on the front-end it outputs a CSV file where the date is always showing as "18/01/1970". Obviously it's something to do with the fact that the API is returning a timestamp value, but I don't see how I can modify the format in the CSV similar to how it's done in the chart rendering code.
Can anyone advise how (preferably without modifying the data returned by the API) to get the CSV to output a correct date in day/month/year format?
Many thanks
It can be done easily by wrapping Highcharts.Chart.prototype.getDataRows method and map the data array which is used for export. Check demo and code posted below.
Code:
(function(H) {
H.wrap(H.Chart.prototype, 'getDataRows', function(proceed, multiLevelHeaders) {
var rows = proceed.call(this, multiLevelHeaders);
rows = rows.map(row => {
if (row.x) {
row[0] = Highcharts.dateFormat('%d-%b-%y', row.x * 1000);
}
return row;
});
return rows;
});
}(Highcharts));
Demo:
https://jsfiddle.net/BlackLabel/yafx8cb1/1/
Docs:
https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
As per #Core972's comment, the issue here is related to the timestamp in the API returning the date as seconds rather than milliseconds. I don't believe there is a way to manipulate the date format in the CSV export specifically so it will require a change to the API which returns the data.
Wojciech Chmiel's answer demonstrates how to override Highchart's output to re-format the date from a non-ideal source.
I've implemented a polar chart in which each series has 4 values corresponding to 4 categories. When I export the chart csv, the category column contains polar coordinates. I would like to replace these with the corresponding category name. How do I do this?
Adding the categories to each series, had no effect. I also tried adding a categories property to the xAxis, but it had not effect. An xAxis.label formatter successfully returns the category name for each data polar coordinate.
const options = {
chart: {
polar: true,
},
title: {
text: '',
},
tooltip: {
valueDecimals: 2,
headerFormat: '<br/>',
},
legend: {},
pane: {
startAngle: 0,
endAngle: 360,
},
xAxis: {
tickInterval: 45,
min: 0,
max: 360,
labels: {
// eslint-disable-next-line
formatter: function() {
switch (this.value) {
case 45:
return '<b>Experience</b>'
case 135:
return '<b>Frictionless</b>'
case 225:
return '<b>Low Price</b>'
case 315:
return '<b>Brand</b>'
default:
return ''
}
},
},
},
yAxis: {
min: 0,
max: 10,
labels: {
format: '{}',
},
},
plotOptions: {
series: {
pointStart: 45,
pointInterval: 90,
},
column: {
pointPadding: 0,
groupPadding: 0,
},
},
series: kahnSeries,
}
You need to use categories property, but without options like: pointInterval, pointStart, min and max:
xAxis: {
categories: ['Experience', 'Frictionless', 'Low Price', 'Brand']
},
Live demo: http://jsfiddle.net/BlackLabel/z8cm1p39/
API Reference: https://api.highcharts.com/highcharts/xAxis.categories
To avoid changing the chart's current display, I wrapped the getCSV function and replaced the CSV category values. If there was a simpler way, please share it.
{
(function (H) {
H.wrap(H.Chart.prototype, 'getCSV', function (
proceed,
useLocalDecimalPoint
) {
// Run the original proceed method
const result = proceed.apply(
this,
Array.prototype.slice.call(arguments, 1)
)
const itemDelimiter = ','
const lineDelimiter = '\n'
const rows = result.split(lineDelimiter)
let newResult = ''
let rowCategories = false
rows.forEach((row, rowIndex) => {
const columns = row.split(itemDelimiter)
if (rowIndex === 0 && columns[0] === '"Category"') {
rowCategories = true
}
if (rowIndex > 0 && rowCategories) {
let newRow = formatter(columns[0])
columns.forEach((column, columnIndex) => {
if (columnIndex > 0) {
newRow += itemDelimiter
newRow += column
}
})
newResult += newRow
} else {
newResult += row
}
if (rowIndex < rows.length - 1) {
newResult += lineDelimiter
}
}
)
return newResult
})
}(Highcharts))
}
I am plotting a chart with ‘y’ axis being numeric values and ‘x’ axis being date time values.
I was able to process a JSON object of 3000 items. However, because of our business rules, we also need to display the time: hours + minutes in the chart’s tooltips.
This changed everything!
Now the chart takes about 15 seconds to plot 2000 records. This is unacceptable.
I can see clearly that when I remove the time part of my Date object the charts works perfectly. It is just when added the hours and minutes that performance gets affected.
Trying different things I realized that your charts should support the amount of data I am using since it is not massive.
We love the charts but performance is key for us to continue using your products.
Can you help me with this issue?
Please check this fiddle so you can understand my problem. Feel free to remove the hours and minutes variables from the DateUtc creation:
https://jsfiddle.net/17a3jry9/7/
Thanks in advance!
var pointStart = new Date();
var data = [{"date":"2017-11-08","time":"1712","perc":10},{"date":"2017-11-08","time":"1608","perc":10},{"date":"2017-11-08","time":"1506","perc":10},{"date":"2017-11-08","time":"1408","perc":10},{"date":"2017-11-08","time":"1309","perc":10},{"date":"2017-11-08","time":"1207","perc":10},{"date":"2017-11-08","time":"1110","perc":10},{"date":"2017-11-08","time":"1003","perc":10},{"date":"2017-11-08","time":"0910","perc":10},{"date":"2017-11-08","time":"0810","perc":10},{"date":"2017-11-08","time":"0708","perc":10},{"date":"2017-11-09","time":"1710","perc":10},{"date":"2017-11-09","time":"1604","perc":10},{"date":"2017-11-09","time":"1510","perc":10},{"date":"2017-11-09","time":"1406","perc":10},{"date":"2017-11-09","time":"1310","perc":10},{"date":"2017-11-09","time":"1205","perc":10},{"date":"2017-11-09","time":"1107","perc":10},{"date":"2017-11-09","time":"1010","perc":10},{"date":"2017-11-09","time":"0912","perc":10},{"date":"2017-11-09","time":"0806","perc":10}{"date":"2018-10-25","time":"0709","perc":10},{"date":"2018-10-25","time":"1009","perc":10},{"date":"2018-10-25","time":"1208","perc":10},{"date":"2018-10-25","time":"1309","perc":10},{"date":"2018-10-25","time":"1410","perc":10},{"date":"2018-10-25","time":"1510","perc":10},{"date":"2018-10-25","time":"1702","perc":10},{"date":"2018-10-26","time":"1409","perc":10},{"date":"2018-10-26","time":"0710","perc":10},{"date":"2018-10-26","time":"1505","perc":10},{"date":"2018-10-26","time":"1704","perc":10},{"date":"2018-10-29","time":"0708","perc":10},{"date":"2018-10-29","time":"1007","perc":10},{"date":"2018-10-29","time":"1208","perc":10},{"date":"2018-10-29","time":"1406","perc":10},{"date":"2018-10-29","time":"1509","perc":10},{"date":"2018-10-29","time":"1610","perc":10},{"date":"2018-10-30","time":"0710","perc":10},{"date":"2018-10-30","time":"1010","perc":10},{"date":"2018-10-30","time":"1207","perc":10},{"date":"2018-10-30","time":"1409","perc":10},{"date":"2018-10-30","time":"1510","perc":10},{"date":"2018-10-30","time":"1709","perc":10},{"date":"2018-10-31","time":"0708","perc":10},{"date":"2018-10-31","time":"1009","perc":10},{"date":"2018-10-31","time":"1206","perc":10},{"date":"2018-10-31","time":"1409","perc":10},{"date":"2018-10-31","time":"1509","perc":10},{"date":"2018-10-31","time":"1708","perc":10},{"date":"2018-11-01","time":"0707","perc":10},{"date":"2018-11-01","time":"1007","perc":10},{"date":"2018-11-01","time":"1108","perc":10},{"date":"2018-11-01","time":"1250","perc":10},{"date":"2018-11-01","time":"1509","perc":10},{"date":"2018-11-01","time":"1407","perc":10},{"date":"2018-11-01","time":"1709","perc":10},{"date":"2018-11-02","time":"0708","perc":10},{"date":"2018-11-02","time":"1007","perc":10},{"date":"2018-11-02","time":"1108","perc":10},{"date":"2018-11-02","time":"1210","perc":10},{"date":"2018-11-02","time":"1407","perc":10},{"date":"2018-11-02","time":"1509","perc":10},{"date":"2018-11-02","time":"1608","perc":10},{"date":"2018-11-02","time":"1715","perc":10},{"date":"2018-11-05","time":"0707","perc":10},{"date":"2018-11-05","time":"1007","perc":10},{"date":"2018-11-05","time":"1209","perc":10},{"date":"2018-11-05","time":"1408","perc":10},{"date":"2018-11-05","time":"1509","perc":10},{"date":"2018-11-05","time":"1611","perc":10},{"date":"2018-11-05","time":"1715","perc":10},{"date":"2018-11-06","time":"0708","perc":10},{"date":"2018-11-06","time":"1007","perc":10},{"date":"2018-11-06","time":"1201","perc":10},{"date":"2018-11-06","time":"1410","perc":10},{"date":"2018-11-06","time":"1510","perc":10},{"date":"2018-11-06","time":"1709","perc":10},{"date":"2018-11-07","time":"0708","perc":10},{"date":"2018-11-07","time":"1007","perc":10},{"date":"2018-11-07","time":"1209","perc":10},{"date":"2018-11-07","time":"1307","perc":10},{"date":"2018-11-07","time":"1410","perc":10},{"date":"2018-11-07","time":"1506","perc":10},{"date":"2018-11-07","time":"1708","perc":10},{"date":"2018-11-08","time":"0707","perc":10},{"date":"2018-11-08","time":"1009","perc":10},{"date":"2018-11-08","time":"1207","perc":10},{"date":"2018-11-08","time":"1309","perc":10},{"date":"2018-11-08","time":"1412","perc":10},{"date":"2018-11-08","time":"1508","perc":10}];
var newSeries = data.map(function (key) {
var utilDate = new Date(key.date);
var hours = parseInt(key.time.slice(0, 2));
var minutes = parseInt(key.time.slice(2, 4));
return { x: Date.UTC(utilDate.getFullYear(), utilDate.getMonth(), utilDate.getDate(), hours, minutes), y: key.perc, key: key.id };
});
Highcharts.stockChart('container', {
xAxis: {
type: 'datetime',
title: {
text: 'Date'
}
},
yAxis: {
title: {
text: 'Util (%)'
},
min: 0
},
tooltip: {
headerFormat: '<b>{point.x: %A, %b %e, %I:%M %p}</b><br>'
//pointFormat: '{point.x:%e. %b}: {point.y:.2f} m'
},
colors: ['teal', 'red'],
// Define the data points. All series have a dummy year
// of 1970/71 in order to be compared on the same x axis. Note
// that in JavaScript, months start at 0 for January, 1 for February etc.
series: [{
name: "Util",
data: newSeries
}],
title: {
text: 'Util Movement'
},
subtitle: {
text: ""
},
plotOptions: {
series: {
cursor: 'pointer',
turboThreshold: 10000,
point: {
events: {
}
},
label: {
connectorAllowed: false
},
pointStart: pointStart.getFullYear()
}
},
responsive: {
rules: [{
condition: {
maxWidth: 200
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
});
Please take a look to the browser console, you have information there about error: Highcharts error #15: www.highcharts.com/errors/15.
This means that you have unsorted data, so you need to sort them:
newSeries.sort(function(a, b){
return a.x - b.x
});
Live demo: https://jsfiddle.net/BlackLabel/onq0Lurx/