Restacking cumulative columns in Highcharts marimekko charts - javascript

I've got a basic variable width column chart (aka Marimekko) set up using Highcharts but am having trouble getting it to restack the columns properly to eliminate the data gap once a series has been removed or hidden.
JSFIDDLE DEMO <-- I've set up a demo of the issue here.
You'll notice clicking on a legend item removes the series from the chart, but it also removes all of the following data points in the array (i.e. clicking on series C removes series C, D, and E whereas it should redraw to A-B-D-E). Since the y-axis data is meant to display a cumulative sum of all series, these should re-shuffle as adjacent columns with no gaps. How can I get this to render properly?
THIS POST uses similar demo code and attempting to solve the same problem, however the answer is somewhat elusive and I am unable to get it working.
Thanks in advance!
$(function () {
var dataArray = [
{ name: 'A', x: 200, y: 120 },
{ name: 'B', x: 380, y: 101 },
{ name: 'C', x: 450, y: 84 },
{ name: 'D', x: 198, y: 75 },
{ name: 'E', x: 95, y: 55 }
];
function makeSeries(listOfData) {
var sumX = 0.0;
for (var i = 0; i < listOfData.length; i++) {
sumX += listOfData[i].x;
}
var allSeries = []
var x = 0.0;
for (var i = 0; i < listOfData.length; i++) {
var data = listOfData[i];
allSeries[i] = {
name: data.name,
data: [
[x, 0], [x, data.y],
{
x: x + data.x / 2.0,
y: data.y,
dataLabels: { enabled: false, format: data.x + ' x {y}' }
},
[x + data.x, data.y], [x + data.x, 0]
],
w: data.x,
h: data.y
};
x += data.x + 0;
}
return allSeries;
}
$('#container').highcharts({
chart: { type: 'area' },
xAxis: {
tickLength: 0,
labels: { enabled: true}
},
yAxis: {
title: { enabled: false}
},
plotOptions: {
series: {
events: {
legendItemClick: function () {
var pos = this.index;
var sname = this.name;
var chart = $('#container').highcharts();
while(chart.series.length > 0) {
chart.series[pos].remove(true);
}
dataArray[pos]= { name: sname, x: 0, y: 0 };
chart.series[0].setData(dataArray);
}
}
},
area: {
lineWidth: 0,
marker: {
enabled: false,
states: {
hover: { enabled: false }
}
}
}
},
series: makeSeries(dataArray)
});
});

Related

Plotline (vertical line) in highcharts scatter chart

https://jsfiddle.net/7zL0v5oq/
I would like to have a plotline at today's date. The list can get quite long and in that case it helps with having an oversight. I fear it doesn't work because it is a scatter chart but I don't know what the problem is. I've searched all over the place but everything leads to plotlines, which clearly doesn't work. I would also be thankful if anyone knew, whether there was an easy way to filter my data the way I have it (standard highcharts filtering is deactivated but doesn't really help because of the static y values, so I get a huge, white space in the middle unless I filter at the edges. Thank you in advance for your help.
data = [{
"id": 1,
"release": "Software1",
"routine_failure_analysis_ended_on": null,
"sw_maintenance_releases_ended_on": "2014-04-01",
"sale_ended_on": "2013-04-01",
"security_vul_support_ended_on": "2015-04-01",
"service_contract_renewal_ended_on": null,
"svc_attach_ended_on": null,
"support_ended_on": "2018-03-31",
"updated_dates_on": "2012-10-03",
"created_at": "2018-05-04T18:53:21.301+02:00",
"updated_at": "2018-05-16T08:36:24.940+02:00"
},
{
"id": 2,
"release": "Software2",
"routine_failure_analysis_ended_on": null,
"sw_maintenance_releases_ended_on": "2019-07-24",
"sale_ended_on": "2017-07-31",
"security_vul_support_ended_on": "2020-07-24",
"service_contract_renewal_ended_on": null,
"svc_attach_ended_on": null,
"support_ended_on": "2022-07-31",
"updated_dates_on": "2015-08-14",
"created_at": "2018-05-05T04:00:44.170+02:00",
"updated_at": "2018-05-16T08:36:29.325+02:00"
},
{
"id": 3,
"release": "Software3",
"routine_failure_analysis_ended_on": null,
"sw_maintenance_releases_ended_on": "2018-03-01",
"sale_ended_on": "2017-03-01",
"security_vul_support_ended_on": "2018-12-01",
"service_contract_renewal_ended_on": null,
"svc_attach_ended_on": null,
"support_ended_on": "2022-02-28",
"updated_dates_on": "2016-09-02",
"created_at": "2018-05-05T04:00:44.401+02:00",
"updated_at": "2018-05-16T08:36:31.643+02:00"
}
];
const colors = ["#516", "#1781e3", "#25b252", "#20c997", "#ffc107", "#ff8b2e", "#dd1122"];
//Change to store y value paired to release/pid
var change = {};
//Which y values need to be displayed
var ticks = [0];
//Description of events
var sale = "Sale";
var support = "Support";
var svc = " SVC attach";
var sw = "Software maintenance";
var routine = "Routine failure analysis";
var service = "Service contract renewal";
var security = "Security vulnerability support";
//Data array for series
var high = [];
data.sort(function(a, b) {
return Date.parse(a.support_ended_on) < Date.parse(b.support_ended_on) ? 1 : -1
})
for (var i = 0; i < data.length; i++) {
var arr = [{
x: Date.parse(data[i].sale_ended_on),
y: (i + 1) * 20,
color: colors[0],
myValue: sale
},
{
x: Date.parse(data[i].sw_maintenance_releases_ended_on),
y: (i + 1) * 20,
color: colors[1],
myValue: sw
},
{
x: Date.parse(data[i].security_vul_support_ended_on),
y: (i + 1) * 20,
color: colors[2],
myValue: security
},
{
x: Date.parse(data[i].svc_attach_ended_on),
y: (i + 1) * 20,
color: colors[3],
myValue: svc
},
{
x: Date.parse(data[i].routine_failure_analysis_ended_on),
y: (i + 1) * 20,
color: colors[4],
myValue: routine
},
{
x: Date.parse(data[i].service_contract_renewal_ended_on),
y: (i + 1) * 20,
color: colors[5],
myValue: service
},
{
x: Date.parse(data[i].support_ended_on),
y: (i + 1) * 20,
color: colors[6],
myValue: support
}
];
var key, value;
line = [{
x: Date.parse(data[i].sale_ended_on),
y: (i + 1) * 20
}, {
x: Date.parse(data[i].support_ended_on),
y: (i + 1) * 20
}]
//Adding to change list, so we can add release/pid as label to y axis
key = (i + 1) * 20;
ticks.push(key);
if (data[i].pid) {
value = data[i].pid;
} else {
value = data[i].release;
}
change[key] = value;
//Expanding high (which is used for the highcharts series) with arr (all points for one pid)
if (data[i].pid) {
high.push({
label: data[i].pid,
name: data[i].pid,
type: 'scatter',
data: arr
}, {
type: 'line',
data: line,
linkedTo: ":previous"
});
} else {
high.push({
label: data[i].release,
name: data[i].release,
type: 'scatter',
data: arr,
showInLegend: false
}, {
type: 'line',
data: line,
linkedTo: ":previous"
});
}
}
Highcharts.chart("container", {
chart: {
height: data.length * 75
},
credits: {
enabled: false
},
yAxis: {
title: {
text: null
},
tickPositions: ticks,
visible: true,
labels: {
formatter: function() {
var value = change[this.value];
return value !== 'undefined' ? value : this.value;
}
}
},
xAxis: {
plotlines: [{
color: "#dd1122",
width: 2,
value: +new Date()
}],
type: 'datetime',
},
plotOptions: {
scatter: {
marker: {
symbol: 'circle',
radius: 7,
lineWidth: 2
}
},
line: {
enableMouseTracking: false,
marker: {
enabled: false
},
color: '#bbb',
lineWidth: 3
}
},
tooltip: {
formatter: function() {
var str = '<b>' + this.series.name + '</b><br/>'
if (this.point.myValue) {
str += this.point.myValue;
} else {
str += "Corrupted data!";
}
if (this.point.x < Date.parse(new Date))
return str += " ended on:<br/>" + Highcharts.dateFormat('%e %b %Y', new Date(this.x));
else
return str += " will end on:<br/>" + Highcharts.dateFormat('%e %b %Y', new Date(this.x));
},
shared: false
},
series: high
})
You have a typo, use plotLines instead of plotlines:
xAxis: {
plotLines: [{
...
}],
...
}
Live demo: https://jsfiddle.net/BlackLabel/p3u8ejtb/
API Reference: https://api.highcharts.com/highcharts/xAxis.plotLines

Changing xaxis label from echarts library

var data = [];
var dataCount = 10;
var startTime = +new Date();
var categories = ['categoryA', 'categoryB', 'categoryC'];
var types = [
{name: 'JS Heap', color: '#7b9ce1'},
{name: 'Documents', color: '#bd6d6c'},
{name: 'Nodes', color: '#75d874'},
{name: 'Listeners', color: '#e0bc78'},
{name: 'GPU Memory', color: '#dc77dc'},
{name: 'GPU', color: '#72b362'}
];
// Generate mock data
echarts.util.each(categories, function (category, index) {
var baseTime = startTime;
for (var i = 0; i < dataCount; i++) {
var typeItem = types[Math.round(Math.random() * (types.length - 1))];
var duration = Math.round(Math.random() * 10000);
data.push({
name: typeItem.name,
value: [
index,
baseTime,
baseTime += duration,
duration
],
itemStyle: {
normal: {
color: typeItem.color
}
}
});
baseTime += Math.round(Math.random() * 2000);
}
});
function renderItem(params, api) {
var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var height = api.size([0, 1])[1] * 0.6;
var rectShape = echarts.graphic.clipRectByRect({
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
}, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
});
return rectShape && {
type: 'rect',
shape: rectShape,
style: api.style()
};
}
option = {
tooltip: {
formatter: function (params) {
return params.marker + params.name + ': ' + params.value[3] + ' ms';
}
},
title: {
text: 'Profile',
left: 'center'
},
dataZoom: [{
type: 'slider',
filterMode: 'weakFilter',
showDataShadow: false,
top: 400,
height: 10,
borderColor: 'transparent',
backgroundColor: '#e2e2e2',
handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line
handleSize: 20,
handleStyle: {
shadowBlur: 6,
shadowOffsetX: 1,
shadowOffsetY: 2,
shadowColor: '#aaa'
},
labelFormatter: ''
}, {
type: 'inside',
filterMode: 'weakFilter'
}],
grid: {
height:300
},
xAxis: {
min: startTime,
scale: true,
axisLabel: {
formatter: function (val) {
return Math.max(0, val - startTime) + ' ms';
}
}
},
yAxis: {
data: categories
},
series: [{
type: 'custom',
renderItem: renderItem,
itemStyle: {
normal: {
opacity: 0.8
}
},
encode: {
x: [1, 2],
y: 0
},
data: data
}]
};
Hi, everyone!! I am working on the echarts library, the only thing i want to change data is the axisLabel from Xaxis part.
What i mean is, for example, "2019-11-5, 2019-11-6...."and so on. So, i hope someone can help me out, thank you so much!!!
Hi, everyone!! I am working on the echarts library, the only thing i want to change data is the axisLabel from Xaxis part.
What i mean is, for example, "2019-11-5, 2019-11-6...."and so on. So, i hope someone can help me out, thank you so much!!!
First, create an array of dates like
var dates = ['2019-11-5','2019-10-3','2019-2-2','2019-1-4','2019-12-5'];
then in xAxis -> axisLabel return date
axisLabel: {
formatter: function (val,index) {
return dates[index];
}
}

How to show more than one "dataMax" in Highcharts?

Currently, I'm showing a max point in the line chart. But I want to change dataMax to top 5 max value points in chart.How can I achieve this in Highcharts?
var defaultData = 'urlto.csv';
var urlInput = document.getElementById('fetchURL');
var pollingCheckbox = document.getElementById('enablePolling');
var pollingInput = document.getElementById('pollingTime');
function createChart() {
Highcharts.chart('closed5', {
chart: {
type: 'area',
zoomType: 'x'
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
style: {},
formatter: function() {
if (this.y === this.series.dataMax) {
return this.y;
}
}
}
}
},
title: {
text: 'Chart for charting'
},
data: {
csvURL: urlInput.value,
enablePolling: pollingCheckbox.checked === true,
dataRefreshRate: parseInt(pollingInput.value, 10)
}
});
if (pollingInput.value < 1 || !pollingInput.value) {
pollingInput.value = 1;
}
}
urlInput.value = defaultData;
// We recreate instead of using chart update to make sure the loaded CSV
// and such is completely gone.
pollingCheckbox.onchange = urlInput.onchange = pollingInput.onchange = createChart;
// Create the chart
createChart();
As #ewolden rightly noticed, you can sort your data and show only the five highest values:
var data = [11, 22, 33, 44, 55, 66, 15, 25, 35, 45, 55, 65],
sortedData = data.slice().sort(function(a, b){
return b - a
});
Highcharts.chart('container', {
series: [{
data: data,
dataLabels: {
enabled: true,
formatter: function() {
if (sortedData.indexOf(this.y) < 5) {
return this.y;
}
}
}
}]
});
Live demo: http://jsfiddle.net/BlackLabel/xkf2w5tb/
API: https://api.highcharts.com/highmaps/series.mapbubble.dataLabels.formatter
As far as I know formatter callback is the way to format the data labels. If you want to show the top N points you should sort the data in a new array and pull the top 5 values. This is an example of how to clone and sort the array and extract the top 5 elements in the formatter call.
let data = [32, 10, 20, 99, 30, 54, 85, 56, 11, 26, 15, 45, 55, 65];
//Copy the array
let temp = data.slice();
// Sort the temp array in descending order
temp.sort((a, b) => b - a);
Highcharts.chart('closed5', {
chart: {
type: 'area',
zoomType: 'x'
},
title: {
text: 'Chart for charting'
},
series: [{
data: data,
dataLabels: {
enabled: true,
formatter: function() {
if (temp.indexOf(this.y) < 5) {
return this.y;
}
},
},
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="closed5"></div>

Change highcharts data label position

This is my jsfiddle link http://jsfiddle.net/bb1m6xyk/1/
I want that all my labels like my data: 0 etc are positioned at the base and in center of each zone.
$('#container').highcharts({
chart: {
type: 'area'
},
yAxis: {
title: {
text: 'Percent'
}
},
plotOptions: {
area: {
enableMouseTracking: false,
showInLegend: false,
stacking: 'percent',
lineWidth: 0,
marker: {
enabled: false
},
dataLabels: {
className:'highlight',
enabled: true,
formatter: function () {
console.log(this);
return this.point.myData
}
}
}
},
series: [{
name: 'over',
color: 'none',
data: overData
}, {
id: 's1',
name: 'Series 1',
data: data,
showInLegend: true,
zoneAxis: 'x',
zones: zones
}]
});
Is this possible? I tried it using className on dataLabels but it doesn't take that into effect.
Any help is appreciated.
There are a few ways to render labels on a chart.
The Renderer
Live example: http://jsfiddle.net/11rj6k6p/
You can use Renderer.label to render the label on the chart - this is a low level approach but it gives you full control how the labels will be rendered. You can loop the zones and set x and y attributes of the labels, e.g. like this:
const labels = ['l1', 'l2', 'l3', 'l4', 'l5']
function drawLabels() {
const zonesLabels = this.zonesLabels
const series = this.get('s1')
const { yAxis, xAxis } = series
const y = yAxis.toPixels(0) - 20 // -20 is an additional offset in px
series.zones.reduce((prev, curr, i) => {
if (curr.value !== undefined) {
const x = (xAxis.toPixels(prev.value) + xAxis.toPixels(curr.value)) / 2
if (!zonesLabels[i]) {
zonesLabels.push(
this.renderer.label(labels[i], x, y).add().attr({
align: 'center',
zIndex: 10
})
)
} else {
zonesLabels[i].attr({ x, y })
}
}
return curr
}, { value: series.dataMin })
}
Then set the function on load - to render the labels, and on redraw - to reposition the labels if the chart size changed.
chart: {
type: 'area',
events: {
load: function() {
this.zonesLabels = []
drawLabels.call(this)
},
redraw: drawLabels
}
},
The annotations module
Live example: http://jsfiddle.net/a5gb7aqz/
If you do not want to use the Renderer API, you can use the annotations module which allows to declare labels in a chart config.
Add the module
<script src="https://code.highcharts.com/modules/annotations.js"></script>
Map zones to the labels config object
const labels = ['l1', 'l2', 'l3', 'l4', 'l5']
function annotationsLabels() {
const zonesLabels = []
zones.reduce((prev, curr, i) => {
zonesLabels.push({
text: labels[i],
point: {
x: (prev.value + curr.value) / 2,
y: 0,
xAxis: 0,
yAxis: 0
}
})
return curr
}, { value: 0 })
return zonesLabels
}
Set the annotations options
annotations: [{
labels: annotationsLabels(),
labelOptions: {
shape: 'rect',
backgroundColor: 'none',
borderColor: 'none',
x: 0,
y: 0
}
}],
Data labels and a new series
Live example: http://jsfiddle.net/wpk1495g/
You can create a new scatter series which will not respond to mouse events and it won't be visible in the legend. The labels can be displayed as data labels.
Map zones to series points
const labels = ['l1', 'l2', 'l3', 'l4', 'l5']
function seriesData() {
const points = []
zones.reduce((prev, curr, i) => {
points.push( {
x: (prev.value + curr.value) / 2,
y: 50,
dataLabels: {
enabled: true,
format: labels[i]
}
})
return curr
}, { value: 0 })
return points
}
Set the series options in the chart config
, {
type: 'scatter',
enableMouseTracking: false,
showInLegend: false,
data: seriesData(),
zIndex: 10,
color: 'none',
dataLabels: { style: { textOutline: false }, x: 0, y: 0 }
}
Output

Spline Graph with diagonally fixed values with 0,0 and ploting remaing same

We are using Spline Graph for our game in which we are facing issue with x and y axis value which we need to put 0,0 and save the values from initially till end as we need to all plotting from start till end of the value.
Check Live Demo Here
JavaScript Code
<script>
var a = 1;
var b = 1;
var factor = 1.2;
$(document).ready(function () {
Highcharts.chart('container', {
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 () {
b = b*1.2;
console.log(b);
var x = a; // current time
var y = b;
a++;
series.addPoint([x, y], true, true);
}, 700);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'number',
min: 0,
tickInterval: 2
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>X: ' + this.x+', Y:'+this.y;
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function () {
// generate an array of random data
var data = [],i;
for (i = 1; i <= 19; i++) {
b = b*factor;
data.push({
x: a,
y: b
});
a++;
}
return data;
}())
}]
});
});
The following code draws a curve line from the origin (0,0) to the end point which gets updated on the interval. You needed to make the shift variable false in the addPoint call. Higchart docs
$(document).ready(function () {
var a = 1;
var b = 1;
var factor = 1.2;
Highcharts.chart('container', {
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 () {
b = b*1.2;
var x = a; // current time
var y = b;
a++;
// Add new end point
series.addPoint([x, y], true, false);
}, 700);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'number',
min: 0,
tickInterval: 2
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>X: ' + this.x+', Y:'+this.y;
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function () {
// generate an array of random data
// Add point at origin and last point of series
var data = [{x:0,y:0}],i;
for (i = 1; i <= 19; i++) {
b = b*factor;
a++
data.push({
x: a,
y: b
});
}
return data;
}())
}]
});
});
Updated JsFiddle

Categories

Resources