HI can I tweak tree map and do it ?
I can pass all data hierarchy .
its already implemented in d3 .
Can i use/tweak Any properties of highcharts to render icicle ?
You could use heatmap - see this SO question: Creating ICICLE Chart using Highcharts Library
Other way would be to use treemap. Unfortunately there is no default layout algorithm that would enable icicle chart, so it would have to be created.
How to create custom layout algorithm: http://www.highcharts.com/docs/chart-and-series-types/treemap
For icicle it will be better if children passed to layout algorithm will be unsorted. Feature can be changed by wrapping setTreeValues function.
Example: http://jsfiddle.net/c6bo2asn/
$(function () {
//start wapper
(function (H) {
H.wrap(H.seriesTypes.treemap.prototype, 'setTreeValues', function (proceed) {
var tree = arguments[1];
//setTreeValues: function (tree) {
var series = this,
childrenTotal = 0,
sorted = [],
val,
point = series.points[tree.i];
// First give the children some values
H.each(tree.children, function (child) {
child = series.setTreeValues(child);
series.insertElementSorted(sorted, child, function (el, el2) {
return 0;//do not sort
});
if (!child.ignore) {
childrenTotal += child.val;
} else {
// #todo Add predicate to avoid looping already ignored children
series.eachChildren(child, function (node) {
H.extend(node, {
ignore: true,
isLeaf: false,
visible: false
});
});
}
});
// Set the values
val = H.pick(point && point.value, childrenTotal);
H.extend(tree, {
children: sorted,
childrenTotal: childrenTotal,
// Ignore this node if point is not visible
ignore: !(H.pick(point && point.visible, true) && (val > 0)),
isLeaf: tree.visible && !childrenTotal,
name: H.pick(point && point.name, ""),
val: val
});
return tree;
//},
});
}(Highcharts));
//end wapper
//start layoutAlgorithm logic
function myFunction(parent, children) {
var childrenAreas = [],
widthSoFar = 0,
w;
Highcharts.each(children, function (child,i) {
if (child.level == 1) { //even lines
childrenAreas.push({
x: parent.x,
y: parent.y + parent.height*(i/children.length),
width: parent.width,
height: parent.height/children.length
});
} else {
w = parent.width * child.val/parent.val;
childrenAreas.push({
x: parent.x + widthSoFar,
y: parent.y,
width: child.name === '_empty' ? 0 : w,
height: parent.height
});
widthSoFar += w;
}
});
return childrenAreas;
}
//end layoutAlgorithm logic
//assign new layoutAlgorithm logic
Highcharts.seriesTypes.treemap.prototype.icicle = myFunction;
//create chart
$('#container').highcharts({
series: [{
type: "treemap",
layoutAlgorithm: 'icicle',
dataLabels: {
formatter: function(){
//hide _empty
return this.key === '_empty' ? '' : this.key;
},
rotation: -90
},
borderWidth: 0,
levels: [{
level: 2,
borderWidth: 1
}],
/*
level 1 data points are lines
*/
data: [{
id: 'top',
color: "#EC2500"
}, {
name: 'a Anne',
parent: 'top',
value: 50
}, {
name: 'a Rick',
parent: 'top',
value: 30
}, {
name: 'a Peter',
parent: 'top',
value: 20
}, {
id: 'second'
}, {
name: 'b Anne',
parent: 'second',
value: 30,
color: "#ECE100"
}, {
name: '_empty',
parent: 'second',
value: 20
}, {
name: 'b Peter',
parent: 'second',
value: 30,
color: "#EC9800"
}, {
name: '_empty',
parent: 'second',
value: 20
}, {
id: 'third',
color: '#EC9800'
}, {
name: 'o Anne',
parent: 'third',
value: 20
}, {
name: 'o Rick',
parent: 'third',
value: 10
}, {
name: '_empty',
parent: 'third',
value: 70
}, {
id: 'last',
color: '#669866'
}, {
name: '_empty',
parent: 'last',
value: 20
}, {
name: 'z Anne',
parent: 'last',
value: 10
}, {
name: '_empty',
parent: 'last',
value: 70
}]
}],
title: {
text: 'Fruit consumption'
}
});
});
Related
Highcharts is working when not calling Gantt chart in other views. I've played around trying to get this Gantt chart to work. Looks like there is a conflict with import map only calling highcharts and highcharts.ganttChart is not found. I've tried added the src url through a script tag directly in the html view but still getting this error.
Error msg <
Uncaught (in promise) TypeError: Highcharts.ganttChart is not a function
>
Javascript controller
```
import {Controller} from "#hotwired/stimulus"
export default class extends Controller {
connect() {
let today = new Date(),
day = 1000 * 60 * 60 * 24;
today.setUTCHours(0);
today.setUTCMinutes(0);
today.setUTCSeconds(0);
today.setUTCMilliseconds(0);
today = today.getTime();
let dateFormat = Highcharts.dateFormat;
let series
let chart; // global
async function requestData() {
const response = await fetch('http://localhost:3000/api/v1/charts/index');
if (response.ok) {
const data = await response.json();
series = data.map(function (job, i) {
let data = job.deals.map(function (phase) {
return {
id: 'deal-' + i,
project: phase.project,
client: phase.client,
phase: phase.phase,
start: new Date(phase.from).getTime(),
end: new Date(phase.to).getTime(),
y: i
};
});
return {
name: job.name,
data: data,
current: job.deals[job.current]
};
});
setTimeout(requestData, 1000);
console.log(series);
chart = Highcharts.ganttChart('container', {
series: series,
title: {
text: 'Crew Schedule'
},
tooltip: {
pointFormat: '<span>Client {point.client}</span><br/>' +
'<span>Project: {point.project}</span><br/>' +
'<span>Phase: {point.phase}</span><br/>' +
'<span>From: {point.start:%e. %b}</span><br/><span>To: {point.end:%e. %b}</span>'
},
lang: {
accessibility: {
axis: {
xAxisDescriptionPlural: 'The chart has a two-part X axis showing time in both week numbers and days.',
yAxisDescriptionSingular: 'The chart has a tabular Y axis showing a data table row for each point.'
}
}
},
scrollbar: {
enabled: true
},
rangeSelector: {
enabled: true,
selected: 0
},
accessibility: {
keyboardNavigation: {
seriesNavigation: {
mode: 'serialize'
}
},
point: {
valueDescriptionFormat: 'Assigned to {point.project} from {point.x:%A, %B %e} to {point.x2:%A, %B %e}.'
},
series: {
descriptionFormatter: function (series) {
return series.name + ', job ' + (series.index + 1) + ' of ' + series.chart.series.length + '.';
}
}
},
xAxis: {
currentDateIndicator: true
},
navigator: {
enabled: true,
liveRedraw: true,
series: {
type: 'gantt',
pointPlacement: 0.5,
pointPadding: 0.25,
accessibility: {
enabled: false
}
},
yAxis: {
min: 0,
max: 3,
reversed: true,
categories: []
}
},
yAxis: {
type: 'category',
grid: {
columns: [{
title: {
text: 'Crew'
},
categories: series.map(function (s) {
return s.name;
})
}]
}
}
})
}
return chart;
}
window.addEventListener('load', (event) => {
requestData();
});
}
}
I am using chartJS in my rails app and my chart code is added below. When hovering over sections I need to display as "Label name: $ 636"...Now when hovering it displays as "Label name: 636". The current chart with tooltip is
var ctx = document.getElementById('dollar-issue-area').getContext('2d');
var that = this;
this.chart = new Chart(ctx, {
type: 'pie',
data: {
labels: <%= raw dollar_per_type.collect { |k, v| k } %>,
datasets: [{
label: 'Number of tickets',
data: <%= raw dollar_per_type.collect { |k, v| v } %>,
backgroundColor: palette('tol-dv', <%= raw dollar_per_type.collect { |k, v| k }.length %>).map(function(hex) {return '#' + hex;})
}]
},
options: {
title:{
display: true,
text: 'Dollar per Sub Issue Type from <%= start_date %> to <%= end_date %>'
},
legend: {
display: true,
labels: {
display: false,
fontSize: 10
}
}
}
});
you can use a tooltips callback function.
here, the label callback is used to customize the tooltip content...
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return data['labels'][tooltipItem['index']] + ': $' + data['datasets'][0]['data'][tooltipItem['index']];
}
}
}
see following working snippet...
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['confirmed', 'pending'],
datasets: [{
data: [67, 33],
backgroundColor: [
'rgba(41, 121, 255, 1)',
'rgba(38, 198, 218, 1)'
],
}]
},
options: {
title: {
display: true,
text: 'Dollar per Sub Issue Type'
},
legend: {
display: true,
labels: {
display: false,
fontSize: 10
}
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return data['labels'][tooltipItem['index']] + ': $' + data['datasets'][0]['data'][tooltipItem['index']];
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="myChart"></canvas>
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))
}
my problem is that the primary and secondary yAxis zero is not on the same level. The screenshot can describe my problem better. Is there any possibility to fix this?
Here is the JSFiddle
Highcharts.chart('container', {
title: {
text: 'Stückzahl'
},
xAxis: {
categories: ['5007.205.1.1.1', '5007.225.1.1.1', '5007.285.1.1.1'],
labels:{
enabled: false
}
},
credits: {
enabled: false
},
legend:{
enabled: false
},
yAxis: [{
title: {
text: 'Stückzahl',
},
opposite: false
},{
title: {
text: 'FOR[%]',
},
opposite: true,
max:100,
min:0
}],
series: [
{
type: 'column',
name: 'Sollwert',
pointWidth:30,
grouping: false,
color: 'rgba(0,0,0,0.1)',
data: [2000, 1500, 1600],
yAxis: 0
},{
dataLabels:{
enabled:true
},
type: 'column',
grouping: false,
pointWidth:20,
name: 'John',
data: [1941, 975, 1936],
yAxis: 0
},{
dataLabels:{
enabled:true
},
color:'#ef703e',
grouping: false,
pointWidth:20,
type: 'column',
data: [-27, -15, -350],
yAxis: 0
},{
color:'black',
data: [80,60,99],
yAxis: 1,
type: 'line'
}]
});
To post this question, I need to describe my problem better. So ignore these last lines :/
There is an experimental wrap on Highcharts User Voice - multiple axis alignment control. It was written some time ago but it still works.
The wrap:
/**
* Experimental Highcharts plugin to implement chart.alignThreshold option. This primary axis
* will be computed first, then all following axes will be aligned to the threshold.
* Author: Torstein Hønsi
* Last revision: 2016-11-02
*/
(function (H) {
var Axis = H.Axis,
inArray = H.inArray,
wrap = H.wrap;
wrap(Axis.prototype, 'adjustTickAmount', function (proceed) {
var chart = this.chart,
primaryAxis = chart[this.coll][0],
primaryThreshold,
primaryIndex,
index,
newTickPos,
threshold;
// Find the index and return boolean result
function isAligned(axis) {
index = inArray(threshold, axis.tickPositions); // used in while-loop
return axis.tickPositions.length === axis.tickAmount && index === primaryIndex;
}
if (chart.options.chart.alignThresholds && this !== primaryAxis) {
primaryThreshold = (primaryAxis.series[0] && primaryAxis.series[0].options.threshold) || 0;
threshold = (this.series[0] && this.series[0].options.threshold) || 0;
primaryIndex = primaryAxis.tickPositions && inArray(primaryThreshold, primaryAxis.tickPositions);
if (this.tickPositions && this.tickPositions.length &&
primaryIndex > 0 &&
primaryIndex < primaryAxis.tickPositions.length - 1 &&
this.tickAmount) {
// Add tick positions to the top or bottom in order to align the threshold
// to the primary axis threshold
while (!isAligned(this)) {
if (index < primaryIndex) {
newTickPos = this.tickPositions[0] - this.tickInterval;
this.tickPositions.unshift(newTickPos);
this.min = newTickPos;
} else {
newTickPos = this.tickPositions[this.tickPositions.length - 1] + this.tickInterval;
this.tickPositions.push(newTickPos);
this.max = newTickPos;
}
proceed.call(this);
}
}
} else {
proceed.call(this);
}
});
}(Highcharts));
All you need to do is set alignThresholds in chart options.
Highcharts.chart('container', {
chart: {
alignThresholds: true
},
live example: http://jsfiddle.net/f3urehs0/
I have a simple json document :
[ {
"x" : "a",
"y" : 2
}, {
"x" : "b",
"y" : 8
}, {
"x" : "c",
"y" : 4
}, {
"x" : "d",
"y" : 15
} ]
I want to visualize it using Highcharts having 4 series. I could success, however, the data appeared only as one series (see the next Figure).
Here is part of the code:
var options = {
.
.
.
series: [{ }]
};
.
.
.
var data = JSON.parse(json);
var seriesData = [];
for (var i = 0; i < data.length; i++) {
seriesData.push([data[i].x, data[i].y]);
options.xAxis.categories.push( data[i].x );
}
options.series[0].data = seriesData;
var chart = new Highcharts.Chart(options);
also updating the series
chart.series[0].update({
type: type,
});
works fine.
using
options.series.push({name: data[i].x, data: [data[i].x, data[i].y]});
creates 4 series but not appropriately visualized and also updating the series
chart.series[0].update({
type: type,
});
doesn't work, therefore, I want to focus in the first mentioned method.
any hints?
EDit: code which partially works for me:
var options = {
chart: {
renderTo: 'container',
type: 'column' //default
},
title: {
text: ''
},
yAxis: {
title: {
enabled: true,
text: 'Count',
style: {
fontWeight: 'normal'
}
}
},
xAxis: {
title: {
enabled: true,
text: '',
style: {
fontWeight: 'normal'
}
},
categories: [],
crosshair: true
} ,
plotOptions: {
pie: {
innerSize: 125,
depth: 80
},
column: {
pointPadding: 0.2,
borderWidth: 0,
grouping: false
}
},
series: [{ }]
};
// Set type
$.each(['column', 'pie'], function (i, type) {
$('#' + type).click(function () {
chart.series[0].update({
type: type
});
});
var data = get the data fom json file**
var seriesData = [];
for (var i = 0; i < data.length; i++) {
seriesData.push([data[i].x, data[i].y]);
options.xAxis.categories.push( data[i].x );
}
options.series[0].data = seriesData;
var chart = new Highcharts.Chart(options);
});
});
You have to decide whether you want to have 4 different series and update all 4 series at once or you want to have one series an then build e.g. legend on your own.
If you want to have 4 series, set grouping to false, set xAxis categories and each point should be mapped to one series with one point - the point.x should have the index of the series.
const series = data.map((point, x) => ({ name: point.x, data: [{ x, y: point.y }]}))
const chart = Highcharts.chart('container', {
chart: {
type: 'column'
},
plotOptions: {
column: {
grouping: false
}
},
xAxis: {
categories: data.map(point => point.x)
},
series: series
});
Then you can update your all 4 series:
chart.series.forEach(series => series.update({
type: series.type === 'column' ? 'scatter' : 'column'
}, false))
chart.redraw()
example: http://jsfiddle.net/pdjqrj5y/