highcharts - exported png in horizontal bar charts - highcharts

I have a horizontal bar chart with negative and positive values,
I noticed that gridlines have a slight offset to the left (maybe they get rounded?). Here is an image that illustrates my problem:
I tried to reproduce it in fiddle, but got slightly different result (please export png to see the image). It's hard to notice but negative bars don't start from zero.
So I am curios to know what is the root cause of the problem and potential fix you may suggest.
Thanks in advance!
Highcharts.chart('container', {
chart: {
type: 'bar',
styledMode: true,
events: {
load: function(){
const chart = this;
const gridLines = chart.yAxis[0].gridGroup.element.querySelectorAll('path');
console.log(gridLines);
const yTicks = chart.yAxis[0].ticks;
for(let tick of Object.keys(yTicks)){
if(yTicks[tick].pos === 0) {
const zeroGridLine = yTicks[tick].gridLine.element;
zeroGridLine.classList.replace('highcharts-grid-line','zero-line');
if(chart.seriesGroup) chart.seriesGroup.element.appendChild(zeroGridLine)
break;
}
}
}
}
},
title: {
text: 'title'
},
xAxis: {
categories: ['Medical care',
'Shelter',
'Personal services',
'Education',
'Furnishings',
'Communication',
'Recreation',
'Fuels and utilities',
'Apparel',
'Transportation',],
lineWidth: 1,
labels: {
align: 'left',
reserveSpace: true,
step: 1,
x:-5,
/* max: 9.5,
min: -0.5, */
style: {
whiteSpace: 'wrap',
textOverflow: 'visible'
}
}
},
yAxis: {
tickWidth: 1
},
series: [{
name: 'April 2020',
data: [
4.81, 2.62, 2.53, 2.15, 1.31, 1.12, 0.94, -0.35, -3, -8]
}, {
name: 'Jan 2020',
data: [4.48, 3.32, 2.11, 2.17, 0.66, 0.93, 1.41, 0.57, -1.26, 2.87]
}]
})
#import 'https://code.highcharts.com/css/highcharts.css';
#container {
min-width: 300px;
max-width: 300px;
height: 300px;
margin: 1em auto;
}
.highcharts-xaxis-labels {
font-size: 15px;
}
.zero-line {
stroke: black;
stroke-width: 1;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="height: 400px"></div>

I think that it is a bug. I reported it on the Highcharts Github issue channel where you can follow this thread or add your own opinion about this behaviour. The core developers will respond you.
https://github.com/highcharts/highcharts/issues/14302

Related

highcharts - custom legend width

I have a simple line chart with a legend aligned to the right. Legend width is set based on the legend item content, if the content doesn't exceed 25% of the width of the chart, it stays as it is. But if it exceeds - 25% is applied. The code for this is here.
The problem is that I am facing a situation when legend text has long string without white spaces in between - like PricewaterhouseCooper, the text gets cutoff - which is expected result based on the code. However I wanted to eliminate this scenario and let it exceed 25% if there is a string which width is wider than 25%. Do you have suggestion how better approach this problem?
Thanks!
My suggestion is using custom legend HTML to use custom styling for it. Highchart can be very strong at custom style for your chart.
I created this Fiddle for an example of it.
In my example, I used "min-width" and "max-width" based on percent of your container width. Also different "font-family" can cause a different results.
<script src="https://code.highcharts.com/highcharts.js"></script>
<style>#import 'https://code.highcharts.com/css/highcharts.css';
#container {
min-width: 300px;
max-width: 500px;
height: 300px;
margin: 1em auto;
}
</style>
<div id="container"></div>
<script>
Highcharts.chart('container', {
chart: {
styledMode: true,
events: {
load: function() {
var chart = this,
legend = chart.legend,
legendMaxWidth =
Highcharts.relativeLength(legend.options.maxWidth, 1) * chart.chartWidth;
/*if (legend.legendWidth > legendMaxWidth) {
legend.update({
width: legend.options.maxWidth
});
}*/
}
}
},
legend: {
align: 'right',
layout: 'proximate',
maxWidth: '25%',
width: '25%',
/* use custom html */
useHTML: true,
labelFormatter: function () {
return '<span title="' + this.name + '" style="max-width:110px;min-width:75px;display:block;word-wrap: break-word;white-space: normal;letter-spacing: 0.5px;">' + this.name + '</span>';
}
},
series: [{
name: 'PricewaterhouseCoopers',
data: [1, 4, 3, 5],
},{
name: 'Pricewaterhouse Coopers copy',
data: [2, 1, 0, 3],
},
{
name: 'Deloitteverylongtexthere',
data: [3, 5, 3, 1],
}
]
});
</script>

How to style Highchart data table and make it responsive?

I'm trying to export my highchart to a table below it. In their documentation about Highchart Table, I only found this with this example
I'm trying to style the table with colored thead, but there's no thead tag in Highcharts' table. This doesn't work too
// draw category labels
chart.xAxis[0].categories.forEach(function (name, i) {
renderer.text(
name,
cellLeft + cellPadding,
tableTop + (i + 2) * rowHeight - cellPadding
)
.css({
fontWeight: 'bold',
backgroundColor: '#aaa'
})
.add();
});
Things I'm trying to do:
1. Color the thead
2. Append the average temperature below the chart
3. Erase the empty border stroke above the Month column
4. Make the table responsive
I can't seem to find any Highchart table documentation. Any help is welcomed. Thank you
This css worked for me and it is responsive!
I got the css from this demo.
I just cut and paste it into my css file and DONE.
.highcharts-data-table table {
border-collapse: collapse;
border-spacing: 0;
background: white;
min-width: 100%;
margin-top: 10px;
font-family: sans-serif;
font-size: 0.9em;
}
.highcharts-data-table td, .highcharts-data-table th, .highcharts-data-table caption {
border: 1px solid silver;
padding: 0.5em;
}
.highcharts-data-table tr:nth-child(even), .highcharts-data-table thead tr {
background: #f8f8f8;
}
.highcharts-data-table tr:hover {
background: #eff;
}
.highcharts-data-table caption {
border-bottom: none;
font-size: 1.1em;
font-weight: bold;
}
I think it would be easier for you to use the table generated by the export-data.js module.
It can be called like this, if you want to always show it:
chart: {
events: {
load: function() {
this.viewData()
}
},
...
}
Then you can style that table like a normal html table, e.g:
.highcharts-data-table thead {
background-color: #aaa;
}
To find the average you can calculate that based on the values on the html table and call it after the viewData function has been called, see example.
function getAverages(rowVals) {
let averages = ''
rowVals.forEach(function(arr, i) {
if (i != 0)
averages += '<td>' + (arr.reduce(function(a, b) {
return a + b;
}) / arr.length).toFixed(1) + '</td>'
});
return averages
}
function addHtmlTableAverage() {
var table = $('.highcharts-data-table table')[0],
avgVal, sumVal = 0,
rowCount = table.rows.length - 1,
rowVals = [
[]
]; // minus the header
for (var i = 1; i < table.rows.length; i++) {
for (let j = 1; j < table.rows[i].cells.length; j++) {
if (rowVals[j]) {
rowVals[j].push(parseFloat(table.rows[i].cells[j].innerHTML))
} else {
rowVals.push([parseFloat(table.rows[i].cells[j].innerHTML)])
}
}
}
$('.highcharts-data-table table > tbody:last')
.append('<tr class="averages"><td><b>Avg</b></td>' +
getAverages(rowVals) +
"</tr>")
}
/**
* Create the chart
*/
window.chart = Highcharts.chart('container', {
chart: {
events: {
load: function() {
this.viewData()
addHtmlTableAverage()
}
},
borderWidth: 2,
width: 600,
height: 300
},
title: {
text: 'Average monthly temperatures'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
yAxis: {
title: {
text: 'Temperature (°C)'
}
},
series: [{
name: 'Tokyo',
data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
}, {
name: 'New York',
data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
}, {
name: 'Berlin',
data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
}, {
name: 'London',
data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
}]
});
#container {
margin-top: 20px;
}
.highcharts-data-table thead {
background-color: #aaa;
}
.averages td {
background-color: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<div id="container"></div>
Working example: http://jsfiddle.net/ewolden/6gh05usq/2/
Every item you want to add to the table you need to generate. For example thead background: http://jsfiddle.net/BlackLabel/0behnswa/
Snippet:
// Apply thead background:
renderer.rect(
cellLeft,
tableTop + cellPadding,
colWidth,
rowHeight
)
.attr({
fill: 'rgba(150, 150, 150, 0.5)'
})
.add()
In short, you need to play around with code to modify it the way you wan to.
For example, remove parts of code that are responsible to generate empty cell: http://jsfiddle.net/BlackLabel/0behnswa/2/
The big part is "responsive" table. This is SVG, that means you need to write all responsive options. On top, you can find options to configure:
// user options
var tableTop = 310,
colWidth = 100,
tableLeft = 20,
rowHeight = 20,
cellPadding = 2.5,
...
Those are fixed numbers, you need to calculate them.

How to place ranking like top 10 and put x axis labels on right of horizontal bar chart?

Current Chart
xAxis: {
categories: ['Africa', 'America', 'Asia', 'Europe', 'Oceania'],
title: {
text: null
},
labels: {
x : 25,
align: 'left'
}
},
My Script in here
http://jsfiddle.net/puff0211/dtcLn8sm/14/
Desired Chart
Does anyone know to accomplish this?
Thank you!
One of the solutions here is to slightly change the position of both axes via left property (it's not documented but it works) and create additional labels using SVG Renderer. chart.events.load is a good place for it because when it launches ticks values and positions are already computed - we can use them to create additional labels:
load: function() {
var ticks = this.xAxis[0].ticks,
renderer = this.renderer;
for (var prop in ticks) {
var t = ticks[prop];
if (t.label) {
var coords = t.label.xy,
label = renderer.text(t.pos + 1, coords.x - additionLabelsOffset, coords.y).add();
}
}
}
(...)
xAxis: {
left: axesOffset
(...)
},
yAxis: {
left: axesOffset
(...)
}
Live demo: http://jsfiddle.net/kkulig/cq2otgr1/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text
My solution is simple.
Let chart margin keep width with left lable.(api use chart.margin)
Allow X Axis can display 2 lable. (api use useHTML and formatter )
Code:
chart: {
type: 'bar',
margin: [ 0, 0, 70, 70]
},
{...},
xAxis: {
labels: {
x : 0,
align: 'left',
useHTML: true,
formatter: function() {
return '<div style="position: relative; top: 0px; right: 50px"> No. '+ (this.pos + 1) +'</div>\
<div style="position: absolute; top: 0px; left: 20px"><b>'+ this.value +'</div>';
}
}
Live demo: http://jsfiddle.net/puff0211/pv84nLub/
API Reference:
https://api.highcharts.com/highcharts/chart.margin
https://api.highcharts.com/highcharts/xAxis.labels.useHTML
https://api.highcharts.com/highcharts/xAxis.labels.formatter

Highcharts. Explicit colour for one point in HeatMap

I have got a heat map with this colours:
colorAxis: {
min: 0,
max: 1,
minColor: '#a50022',
maxColor: '#007340',
gridLineColor: '#000000',
stops: [
[0, '#a50022'],
[0.5, '#fffbbc'],
[1, '#007340']
],
},
It works good, but now, I would like to define a color for some cases when I dont receive a value (between 0 and 1) but a string, so I can receive a "WARNING" and I would like to give it the colour red. For that I have tried to do this:
dataClasses: [{
name: "WARNING",
color: '#a50022',
},
],
And when I create the series:
myData.push([column, row , "WARNING"]);
This doesnt work, it is shown in black. I have also tried:
myData.push({y:[column, row ,"WARNING"],name:"WARNING"});
And everything crashes with this, no data shown.
In this case, I will only receive strings, no values, so I could delete the stops, min, max and that stuff. So I would just need a "heat map" where I could define the colours for each string value.
I believe this is now a setting you can specify in API http://api.highcharts.com/highmaps/plotOptions.heatmap.nullColor
nullColor: Color
The color to apply to null points.
Change:
myData.push({y:[column, row ,"WARNING"],name:"WARNING"});
To:
myData.push({x: column, y:row, name:"WARNING", color: 'red'});
Even you can set the color of a point in heatmap explicitly after generating it.
you can check out the below link.
Demo, Explicit select and color change HeatMap
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<title>Highcharts Demo</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/heatmap.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="height: 400px; min-width: 310px; max-width: 800px; margin: 0 auto"></div>
<button id="getselectedpoints"> Select Point</button>
<button id="changeColor"> Change color</button>
<script type='text/javascript'>//<![CDATA[
var heatMapData=[];
heatMapData.push({x: 1, y:1, name:"well_data1", color: 'red'});
heatMapData.push({x: 4, y:5, name:"well_data2", color: 'green'});
heatMapData.push({x: 6, y:10, name:"well_data3", color: 'blue'});
heatMapData.push({x: 9, y:5, name:"well_data4", color: 'yellow'});
var selfSelectedInHeatMap=false;
var heatMapChart = Highcharts.chart('container', {
chart: {
type: 'heatmap',
marginTop: 40,
marginBottom: 80,
plotBorderWidth: 1
},
title: {
text: 'HEAT MAP'
},
xAxis: {
min:1,
categories: [0,1,2,3,4,5,6,7,8,9,10,11],
gridLineWidth:1
},
yAxis: {
min:1,
categories: ['','a','b','c','d','e','f','g','h','i','j','m','n','o'],
gridLineWidth:1
},
legend: {
align: 'right',
layout: 'vertical',
margin: 0,
verticalAlign: 'top',
enabled:false
},
plotOptions: {
series: {
point: {
events: {
select: function () {
selfSelectedInHeatMap = true;
alert("selected "+this.name + ' (' + this.series.yAxis.categories[this.y] +', ' +this.series.xAxis.categories[this.x] +')')
doHeatMapSelectionWork(this.name);
}
}
}
}
},
tooltip: {
formatter: function () {
return '<b>' + this.point.name + '</b> (' + this.series.yAxis.categories[this.point.y] +', ' +this.series.xAxis.categories[this.point.x] +')';
}
},
series: [{
name: 'Wells Data',
allowPointSelect: true,
cursor: 'pointer',
states: {
hover: {
color: '#a4edba'
},
select: {
borderColor: 'black',
borderWidth:5
}
},
borderWidth: 1,
data: heatMapData,
dataLabels: {
enabled: false
}
}]
});
function doHeatMapSelectionWork(name)
{
if(!selfSelectedInHeatMap)
{
var dataPoints = heatMapChart.series[0].data;
for(var i=0;i<dataPoints.length;i++)
{
if(dataPoints[i].name == name)
{
dataPoints[i].select();
break;
}
}
}
selfSelectedInHeatMap=false;
}
function changeColorForHeatMap(name)
{
var dataPoints = heatMapChart.series[0].data;
for(var i=0;i<dataPoints.length;i++)
{
if(dataPoints[i].name == name)
{
dataPoints[i].update({
color: 'pink'
});
break;
}
}
}
$('#getselectedpoints').click(function () {
doHeatMapSelectionWork('well_data1');
});
$('#changeColor').click(function () {
changeColorForHeatMap('well_data2');
});
//]]>
</script>
</body>
</html>

highchart threshold color with live updating series

I'm trying to apply the new threshold/negativeColor features of Highcharts v3.0.2 to essentially the 'spline updating each second' example.
During the animation of the chart updating, I'm seeing weird artifacts in the series line - it looks like it's animating to a different set of control points.. and then it snaps back to the correct configuration when the animation (of the new data point coming in) is done.
Commenting out the threshold/negativeColor features makes this visual artifact go away.
Am I seeing a bug?
UPDATE: I'm posting the following code as an example, which is the stock highcharts demo (my local jquery is v1.10.2) with the threshold/color/negativeColor lines (first lines under series) added by me. This code seemingly misbehaves.
<html>
<head>
<script src="js/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script>
$(function () {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
threshold: 0.5,
color: '#FF0000',
negativeColor: '#00FF00',
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
}]
});
});
});
</script>
</head>
<body>
<div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>
</body>
</html>
Indeed it looks like a bug, reported here. At this moment you can only disable animations.

Resources