I have a chart which has attribute column.grouping set to false,
and I would like to show data labels only on highest columns.
Here is an example
dataLabels: {
enabled: true
}
I have tried to find solution for couple hours now, I would appreciate any help.
I think it would be the easiest to use point.dataLabels.enabled option. Just preprocess data before rendering the chart, to determine which points should display values, see: http://jsfiddle.net/9f1maj3x/
And code:
function enableLabels(d_1, d_2) {
// compare two data series and enable dataLabel for a higher column:
$.each(d_1, function (i, point) {
if (point > d_2[i]) {
d_1[i] = {
dataLabels: {
enabled: true
},
y: d_1[i]
}
} else {
d_2[i] = {
dataLabels: {
enabled: true
},
y: d_2[i]
}
}
});
return [d_1, d_2];
}
Data example:
var data = [
[150, 73, 20],
[140, 90, 40],
[103.6, 178.8, 198.5],
[203.6, 198.8, 208.5]
];
var leftColumns = enableLabels(data[0], data[1]),
rightColumns = enableLabels(data[2], data[3]);
And example in Highcharts:
series: [{
name: 'Employees',
color: 'rgba(165,170,217,1)',
data: leftColumns[0],
pointPadding: 0.3,
pointPlacement: -0.2
}, {
name: 'Employees Optimized',
color: 'rgba(126,86,134,.9)',
data: leftColumns[1],
pointPadding: 0.4,
pointPlacement: -0.2
}, {
name: 'Profit',
color: 'rgba(248,161,63,1)',
data: rightColumns[0],
tooltip: {
valuePrefix: '$',
valueSuffix: ' M'
},
pointPadding: 0.3,
pointPlacement: 0.2,
yAxis: 1
}, {
name: 'Profit Optimized',
color: 'rgba(186,60,61,.9)',
data: rightColumns[1],
tooltip: {
valuePrefix: '$',
valueSuffix: ' M'
},
pointPadding: 0.4,
pointPlacement: 0.2,
yAxis: 1
}]
you can use
chart.yAxis[0].max;
or
this.dataMax
to get maximum value. to compare , in formatter function compare both and retrun larger one.
You can write a formatter for the dataLabel that checks if it's the highest for that yAxis, here's the API documentation:
http://api.highcharts.com/highcharts#plotOptions.series.dataLabels.formatter
After comments: You can take the data out of the chart object and use a formatter to pick the largest one, fiddle: http://jsfiddle.net/7zc5peyf/1/
var em = [150, 73, 20];
var eo = [140, 90, 40];
data label code:
data: em,
dataLabels:{
enabled: true,
formatter: function(){
if(this.y > eo[this.point.index]){
return this.y;
}
}
}
Here is my solution:
$(function () {
var something = {
chart: {
type: 'column'
},
title: {
text: 'Efficiency Optimization by Branch'
},
xAxis: {
categories: [
'Seattle HQ',
'San Francisco',
'Tokyo']
},
yAxis: [{
min: 0,
title: {
text: 'Employees'
}
}, {
title: {
text: 'Profit (millions)'
},
opposite: true
}],
legend: {
shadow: false
},
tooltip: {
shared: true
},
plotOptions: {
column: {
grouping: false,
shadow: false,
borderWidth: 0
},
series: {
events: {
hide: function () {
console.log(this);
},
show: function () {
console.log(this);
},
legendItemClick: function () {
for (var i = 0; i < something.series.length; i++) {
if (something.series[i].name === this.name) {
something.series[i].visible = !this.visible;
}
}
console.log(this.name);
}
}
}
},
series: [{
name: 'Employees',
color: 'rgba(165,170,217,1)',
visible: true,
data: [150, 73, 20],
pointPadding: 0.3,
pointPlacement: -0.2,
dataLabels: {
enabled: true,
formatter: function () {
var index = something.xAxis.categories.indexOf(this.x);
if ((this.y > something.series[1].data[index]) || !something.series[1].visible) {
console.log(something.series.visible);
return this.y + '*';
}
return '';
}
}
}, {
name: 'Employees Optimized',
color: 'rgba(126,86,134,.9)',
visible: true,
data: [140, 90, 40],
pointPadding: 0.4,
pointPlacement: -0.2,
dataLabels: {
enabled: true,
formatter: function () {
var index = something.xAxis.categories.indexOf(this.x);
if ((this.y > something.series[0].data[index]) || !something.series[0].visible) {
console.log(something.series.visible);
return this.y + '*';
}
return '';
}
}
}, {
name: 'Profit',
color: 'rgba(248,161,63,1)',
visible: true,
data: [193.6, 128.8, 144.5],
tooltip: {
valuePrefix: '$',
valueSuffix: ' M'
},
pointPadding: 0.3,
pointPlacement: 0.2,
yAxis: 1,
dataLabels: {
enabled: true,
formatter: function () {
var index = something.xAxis.categories.indexOf(this.x);
if ((this.y > something.series[3].data[index]) || !something.series[3].visible) {
return this.y + '*';
}
return '';
}
}
}, {
name: 'Profit Optimized',
color: 'rgba(186,60,61,.9)',
visible: true,
data: [123.6, 198.8, 208.5],
tooltip: {
valuePrefix: '$',
valueSuffix: ' M'
},
pointPadding: 0.4,
pointPlacement: 0.2,
yAxis: 1,
dataLabels: {
enabled: true,
formatter: function () {
var index = something.xAxis.categories.indexOf(this.x);
if ((this.y > something.series[2].data[index]) || !something.series[2].visible) {
console.log(something.series.visible);
return this.y + '*';
}
return '';
}
}
}]
};
$('#container').highcharts(something);
});
http://jsfiddle.net/7zc5peyf/4/
Related
I need to display my x-axis label as a whole number with percentage without the decimal and a zero before it. I am already using allowDecimals: false but that's not helping it looks like. How can I fix this?
0.10% should render as 10% and etc.
https://jsfiddle.net/samwhite/p01xvw2z/
Highcharts.chart('container', {
chart: {
height: 550
},
title: {
text: 'GME: Absolute Daily Return vs. % of Outstanding Shares Hedged, January 2021',
align: 'left',
style: {
fontSize: '20px',
fontWeight: 'bold',
}
},
subtitle: {
text: 'Data source: OPERA and Bloomberg',
align: 'left'
},
credits: { enabled: false },
xAxis: {
title: { text: '% of Outstanding Shares Needed for Hedging' },
// labels: {
// formatter: function () {
// return this.value.toFixed(2) + '%'
// }
// },
labels: {
format: '{value:,.2f}%'
},
min: -0.01,
max: 0.6,
tickInterval: 0.1,
allowDecimals: false
},
yAxis: {
title: { text: 'Absolute % Change in Price' },
min: -0.01,
tickInterval: 0.5,
labels: {
formatter: function () {
return this.value.toFixed(1)
}
},
gridLineWidth: 0,
minorGridLineWidth: 0
},
legend: {
enabled: false
},
series: [{
type: 'line',
name: '',
color: "#f79646",
data: [[0, -.1489], [0.5, 0.7003]],
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
enableMouseTracking: false
}, {
type: 'scatter',
marker: {
symbol: 'circle',
fillColor: '#00429d',
radius: 3
},
name: 'Observations',
color: '#000',
data: [
[0.05, 0.08],
[0.05, 0.00],
[0.08, 0.05],
[0.08, 0.01],
[0.05, 0.02],
[0.13, 0.12],
[0.11, 0.00],
[0.35, 0.57],
[0.42, 0.27],
[0.38, 0.11],
[0.22, 0.10],
[0.21, 0.00],
[0.26, 0.09],
[0.48, 0.51],
[0.34, 0.18],
[0.44, 0.92],
[0.43, 1.34],
[0.34, 0.44],
[0.42, 0.67]
],
tooltip: {
valueDecimals: 2
}
}]
});
Something like this?
labels: {
formatter: function () {
return this.value * 100 + '%';
}
},
I am trying to split the data contained in a dict into multiple charts. Each chart has two series: column and marker. If represent all the data in a single chart, everything works fine, but if I try to split it, the columns and the marker don't get aligned for some reason
function setup_chart(chart_container){
return new Highcharts.chart(chart_container, {
chart: {
alignTicks: false,
type: 'columnrange',
inverted: true,
zoomType: 'y',
panning: true,
},
credits: {
enabled: false
},
title: {
text: null
},
xAxis: {
categories: [],
className: 'chart-axis-title',
title: {
align:'high'
},
offset: -10
},
navigation: {
buttonOptions: {
x: 5,
y: -12
}
},
yAxis:[{
minRange: 1,
max:null,
min:null,
allowDecimals: false,
title: {
text: 'Days'
},
labels:{
formatter:function(){
if(this.value !=0){
return this.value;
}
}
}
},{
tickPositions: [0, 100],
visible: false
}],
tooltip: {
},
exporting: {
scale: 3,
chartOptions: {
legend: {
enabled: true
}
}
},
legend: {
enabled: false
},
series: [{
yAxis: 1,
data:[]
},{
name: 'Days',
data: [],
stickyTracking: true
}]
});
}
I'm passing the data via jinja2 and populate the chart in the following way:
var options_data_cm = {{options|tojson|safe}}[k]['cms'];
var cm_groups = {{cm_group_dict}};
var cms_details = {};
for(var key in cm_groups){
cms_details[key] = {
"data":[],
"left":[],
"right":[],
"cols":[],
"categories":[]
}
}
for(var key in cms_details){
var crtChart = $('#'+key).highcharts();
crtChart.xAxis[0].update({title:{ text: ""+cm_groups[key] }});
crtChart.addSeries({
type: 'column',
yAxis: 1,
data: cms_details[key]['cols'],
zIndex: 1,
minPointLength: 10,
threshold: -0.1,
pointPadding: 0,
pointRange: 0,
groupPadding: 0,
showInLegend: false,
tooltip: {
pointFormat: false
},
states: {
hover: {
enabled: false
}
}
});
crtChart.addSeries({
name: "Study Days",
dataLabels: {
enabled: false,
padding: 10,
borderWidth: 0,
useHTML:false,
formatter:function(){
if(this.y != 0)
return this.y;
}
},
stickyTracking: false,
data: cms_details[key]['data'],
borderWidth: 0,
zIndex: 5,
maxPointWidth: 5,
tooltip:{
followPointer:true
},
point: {
events: {
click: function() {
if (url != "")
window.open(url,'_blank');
}
}
}
});
crtChart.addSeries({
type:'scatter',
stickyTracking:false,
tooltip:{snap:0},
data:cms_details[key]['left'],
zIndex: 1
});
crtChart.addSeries({
type:'scatter',
stickyTracking:false,
tooltip:{snap:0},
data:cms_details[key]['right'],
zIndex: 1
});
crtChart.xAxis[0].setCategories(cms_details[key]['categories']);
}
Here are two pictures, the first one is with assignment without breaking the data into multiple charts, the second one is an attempt to split it :
I've tried to inspect the content of the data and it seems OK in the sense that both have the same coordinates, however they are shifted.
EDIT:
Here's the link to the jsfiddle
I have managed to solve the issue by adding pointPlacement: 0.2 to the series which was displaced.
These code are written by javascript,and use hightChart StockChart below.
The program can draw chart by the datetime and report_value1 in the stockChart,and show report_value1 in the tooltip.
I want to add more values to show in the pointFormat of the tooltip.
How to add code to show the rpm value of the speed_data in the tooltip?
var speed_data = [];
for (var i = 0; i < _datalenght; i++) {
v = sData[i];
speed_data.push([
v.report_time * 1000,
v.report_value1,
v.rpm,
]);
}
fuelchart = new Highcharts.StockChart({
chart: {
renderTo: "speed_chart_div",
type: 'line',
zoomType: 'x',
marginRight: 10,
backgroundColor: null
},
rangeSelector: {
buttons: [{
type: 'minute',
count: 5,
text: '5min'
}, {
type: 'minute',
count: 30,
text: '30min'
}, {
type: 'hour',
count: 1,
text: '1hour'
}, {
type: 'hour',
count: 4,
text: '4hour'
}, {
type: 'hour',
count: 8,
text: '8hour'
}, {
type: 'all',
count: 1,
text: 'all'
}],
selected: 5,
inputEnabled: false
},
title: {
text: null
},
subtitle: {
text: '' // dummy text to reserve space for dynamic subtitle
},
scrollbar: {
barBackgroundColor: 'gray',
barBorderRadius: 7,
barBorderWidth: 0,
buttonBackgroundColor: 'gray',
buttonBorderWidth: 0,
buttonBorderRadius: 7,
trackBackgroundColor: 'none',
trackBorderWidth: 1,
trackBorderRadius: 8,
trackBorderColor: '#CCC'
},
xAxis: {
type: 'datetime',
ordinal: false
},
yAxis: {
title: {
text: JLANG.REPORT_SPEED
},
min: 0
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
plotOptions: {
line: {
lineWidth: 2,
states: {
hover: {
lineWidth: 3
}
}
}
},
series: [{
name: JLANG.REPORT_SPEED,
type: 'area',
color: '#357EC7',
lineWidth: 1,
data: speed_data,
tooltip: {
valueDecimals: 0,
useHTML: true,
headerFormat: '<span style="color: {series.color}; font-size:15px;"><b>{point.key}</b></span>',
pointFormat:
'<br/><div><span style="color: {series.color}; font-size:15px;">{series.name}: </span></div>' + '<div><span style="text-align: right; font-size:15px;"><b>{point.y} km/h</b></span></div>' +
'<br/><div><span style="color: {series.color}; font-size:15px;">rpm: </span></div>' + '<div><span style="text-align: right; font-size:15px;"><b>{???} </b></span></div>'
,
xDateFormat: '%H:%M:%S %d-%m-%Y'
},
gapSize: 0,
fillColor: {
linearGradient: {
x1: 0,
y1: 0,
x2: 0,
y2: 1
},
stops: [
[0, Highcharts.getOptions().colors[0]],
[1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
]
},
threshold: null
}],
credits: {
enabled: false
}
});
I try it succussfully.
usdeur = [[1187654400000,0.7429,1],[1187740800000,0.7383,2],[1187827200000,0.7369,3]];
propertyData = [];
//propertyData[1187654400000] = {"a":1,"b":2};
//propertyData[1187740800000] = {"a":3,"b":4};
//propertyData[1187827200000] = {"a":5,"b":6};
for (var i = 0; i < usdeur.length; i++) {
propertyData[usdeur[i][0]] = {"a":i,"b":i+1};
}
Highcharts.stockChart('container', {
xAxis: {
type: 'datetime',
ordinal: false
},
yAxis: {
title: {
text: "speed"
},
min: 0
},
legend: {
enabled: false
},
credits: {
enabled: false
},
tooltip: {
valueDecimals: 0,
useHTML: true,
xDateFormat: '%H:%M:%S %d-%m-%Y',
/* pointFormat:
'<br/><div><span style="color: {series.color}; font-size:15px;">{series.name}: </span></div>' +
'<div><span style="text-align: right; font-size:15px;"><b>{propertyData[point.x]}.{point.y} km/h</b></span></div>',
*/
formatter: function () {
var s = '<b>' + Highcharts.dateFormat('%A, %b %e, %Y', this.x) + '</b>';
$.each(this.points, function () {
s += '<br/>1 USD = ' + this.y + ' EUR<br/>' +
propertyData[this.x]["a"] + "<br/>" +
propertyData[this.x]["b"] ;
});
return s;
}
},
rangeSelector: {
selected: 1
},
series: [{
type: 'area',
name: 'USD to EUR',
data: usdeur
}]
});
Here is the code in concern: http://jsfiddle.net/e0qxfLtt/14/
$(function() {
var chartData = [50, 30, 4, 70, -10, -20, 20, 30];
var index = 1;
var chart1, chart2;
$('#b').click(function(){
var buttonB = document.getElementById('b');
buttonB.disabled = true;
if(index < chartData.length){
chart1.series[0].remove();
chart1.addSeries({data: [chartData[index - 1]]});
setTimeout(function(){chart1.series[0].setData([]);}, 1000);
setTimeout(function(){
chart2.series[0].addPoint([index, chartData[index - 1]]);;
index++;
}, 1000);
}
setTimeout(function(){buttonB.disabled = false;}, 3000);
})
chart1 = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'column'
},
title: {
text: ''
},
xAxis: {
title: {
text: ''
},
gridLineWidth: 1,
tickPixelInterval: 80,
categories: [''],
min:0,
max:0
},
yAxis: {
title: {
text: ''
},
min:-100,
max:100
},
plotOptions: {
series: {
animation: {
duration: 1000
}
}
},
credits: {
enabled: false
},
tooltip: {
formatter: function () {
return Highcharts.numberFormat(this.y, 2) + '%';
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
pointPlacement: 'on',
data: [],
pointWidth: 28
}]
});
chart2 = new Highcharts.Chart({
chart: {
renderTo: 'container1',
type: 'column'
},
title: {
text: ''
},
xAxis: {
title: {
text: ''
},
gridLineWidth: 1,
tickPixelInterval: 40,
min:0,
max:10
},
yAxis: {
title: {
text: ''
},
min:-100,
max:100
},
plotOptions: {
series: {
animation: {
duration: 1000
}
}
},
credits: {
enabled: false
},
tooltip: {
formatter: function () {
return Highcharts.numberFormat(this.y, 2) + '%';
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
pointPlacement: 'on',
data: []
}]
});
});
The bar charts are not animating at all. (I will do something about the color.)
I tried addSeries. However, I could only use it for the chart on the left, as for the chart on the right, only the last drawn bar should be newly drawn/animated.
When i have inconsistent data coming in (when for example the server that gathers the data is down) highcharts does not plot the X correctly.
It still plots like there is data on the X while there is not.
It should afcouse plot the correct hour when there actually is data.
Here is the fiddle: http://jsfiddle.net/ZVwFK/
Data variable is inconsistant!
Can someone show me how i can correct this error?
$(function () {
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline',
margin: [50,130,90,100]
},
title: {
text: 'Weather Today'
},
credits: {
enabled: false
},
subtitle: {
text: 'test'
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
day: '%H:%M'
},
tickInterval: 3600 * 1000,
labels: {
rotation: -45,
align: 'right',
style: {
fontSize: '10px',
fontFamily: 'Verdana, sans-serif'
}
}
},
yAxis: [{
title: {
text: 'Temperature C'
},
opposite: false,
minorGridLineWidth: 0
}, {
title: {
text: 'Humidity %'
},
minorGridLineWidth: 0,
opposite: true
}, {
opposite: true,
title: {
text: 'Air Pressure hPa',
minorGridLineWidth: 0,
},
}],
tooltip: {
formatter: function() {
if(this.series.name === 'Temperature')
{
return ''+ Highcharts.dateFormat('%H:%M',this.x) +': '+ this.y + ' C';
}
if(this.series.name === 'Humidity')
{
return ''+ Highcharts.dateFormat('%H:%M',this.x) +': '+ this.y + ' %';
}
if(this.series.name === 'Air Pressure')
{
return ''+ Highcharts.dateFormat('%H:%M',this.x) +': '+ this.y + ' hPa';
}
}
},
plotOptions: {
spline: {
lineWidth: 4,
states: {
hover: {
lineWidth: 3
}
},
marker: {
enabled: false,
states: {
hover: {
enabled: true,
symbol: 'circle',
radius: 3,
lineWidth: 1
}
}
}
}
},
series: [{
name: 'Temperature',
data: temp,
type: 'spline',
/* yAxis: 0, */
shadow: true,
showInLegend: true,
pointInterval: 60 * 1000,
/* pointStart: Date.UTC(2006, 0, 1),*/
dashStyle: 'solid',
marker: {
enabled: false
}
} , {
name: 'Humidity',
data: hum,
yAxis: 1,
shadow: false,
showInLegend: true,
pointInterval: 60 * 1000,
type: 'line',
dashStyle: 'dot',
marker: {
enabled: false
}
}, {
name: 'Air Pressure',
data: bar,
yAxis: 2,
shadow: false,
showInLegend: true,
pointInterval: 60 * 1000,
type: 'line',
dashStyle: 'shortdot',
marker: {
enabled: false
}
}],
navigation: {
menuItemStyle: {
fontSize: '6px'
}
}
});
});
});
There are two ways of specifying time data for Highcharts and I think you are using the wrong way for the problem. It's the second style you should use when having gaps in the data.
A compact array without gaps only containing the values for each time-point
data: [2, 5, 3, 6, 1]
Then you specify the time-point for the first measure together with the interval. eg:
pointStart: Date.UTC(2013,1,12), // start point in milliseconds
pointInterval: 3600 // interval in milliseconds
You cannot have different length between the time-points this way.
A two dimensional array with both time-points and measure
data: [[Date.UTC(2013,1,12), 2],
[Date.UTC(2013,1,12), 5],
[Date.UTC(2013,1,12), 3],
...]
This way of specifying the array can have gaps where there's no data.
See the reference here
and example here.