I'm drawing a binomial tree using a network graph by fixing initial positions for each node.
If I hover over a node, it highlights each node that's connected to that node by default.
How can I override this to highlight only the antecedent nodes (i.e. from right to left through the paths from the hovered node back to the single node on the far left).
I tried picking up the previous two nodes on the end of the links connected to the hovered node, and continuously iterating until there's no more antecedent nodes, but it's not working out.
function iterateBack(node) {
console.log("Node " + node.id);
var previousNodes = node.linksTo
if (previousNodes != null) {
previousNodes.forEach(function(l) {
var precedingNode = l.fromNode;
precedingNode.update({
//color: 'black',
active: true
});
iterateBack(precedingNode);
});
}
}
Highcharts.chart('container', {
tooltip: {
enabled: false
},
credits: {
enabled: false
},
chart: {
type: 'networkgraph',
margin: 20,
height: '100%',
},
plotOptions: {
series: {
cursor: 'crosshair',
stickyTracking: false,
point: {
events: {
mouseOver: function() {
//this.active = true;
iterateBack(this);
this.linksFrom.forEach(function(l) {
l.update({
active: false
});
});
},
mouseOut: function() {
this.linksTo.forEach(function(l) {
l.update({
active: false
});
});
this.linksFrom.forEach(function(l) {
l.update({
active: false
});
});
}
}
},
}
},
series: [{
marker: {
radius: 15,
lineWidth: 2,
lineColor: 'black',
},
layoutAlgorithm: {
maxIterations: 1,
initialPositions: function() {
var chart = this.series[0].chart,
width = chart.plotWidth,
height = chart.plotHeight;
this.nodes.forEach(function(node, i) {
var initialX = 0;
var initialY = 500;
var distance = 80;
var identifiers = node.id.split(",");
var round = identifiers[0] - 1;
var level = identifiers[1] - 1;
node.plotX = initialX + (round * distance * 2);
node.plotY = initialY - (round * distance) + (level * 2 * distance);
});
}
},
keys: ['from', 'to'],
data: [
['1,1', '2,1', 'win'],
['1,1', '2,2', 'win'],
['2,1', '3,1', 'win'],
['2,1', '3,2', 'lose'],
['2,2', '3,2', 'win'],
['2,2', '3,3', 'lose'],
['3,1', '4,1', 'win'],
['3,1', '4,2', 'lose'],
['3,2', '4,2', 'win'],
['3,2', '4,3', 'lose'],
['3,3', '4,3', 'win'],
['3,3', '4,4', 'lose'],
['4,1', '5,1', 'win'],
['4,1', '5,2', 'lose'],
['4,2', '5,2', 'win'],
['4,2', '5,3', 'lose'],
['4,3', '5,3', 'win'],
['4,3', '5,4', 'lose'],
['4,4', '5,4', 'win'],
['4,4', '5,5', 'lose'],
['5,1', '6,1', 'win'],
['5,1', '6,2', 'lose'],
['5,2', '6,2', 'win'],
['5,2', '6,3', 'lose'],
['5,3', '6,3', 'win'],
['5,3', '6,4', 'lose'],
['5,4', '6,4', 'win'],
['5,4', '6,5', 'lose'],
['5,5', '6,5', 'win'],
['5,5', '6,6', 'lose']
],
nodes: [{
id: '1,1'
},
{
id: '2,1'
},
{
id: '2,2'
},
{
id: '3,1'
},
{
id: '3,2'
},
{
id: '3,3'
},
{
id: '4,1'
},
{
id: '4,2'
},
{
id: '4,3'
},
{
id: '4,4'
},
{
id: '5,1'
},
{
id: '5,2'
},
{
id: '5,3'
},
{
id: '5,4'
},
{
id: '5,5'
},
{
id: '6,1'
},
{
id: '6,2'
},
{
id: '6,3'
},
{
id: '6,4'
},
{
id: '6,5'
},
{
id: '6,6'
}
],
}]
})
Overwrite the default setState method from networkgraph Point class prototype and use your iterateBack function in mouse over event.
(function(H) {
H.seriesTypes.networkgraph.prototype.pointClass.prototype.setState = function() {
H.Point.prototype.setState.apply(this, arguments);
}
}(Highcharts));
Live demo: https://jsfiddle.net/BlackLabel/ua72mrqp/
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
Related
I am trying to display a custom tooltip on a react highcharts network chart that includes the node id as well as the title and other fields in the JSON data I am feeding it. However I am not able to get this to work using the formatted function specified in the API.
My simplified code is as follows:
import React, { useState, useEffect, useRef } from 'react';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import networkgraph from "highcharts/modules/networkgraph";
networkgraph(Highcharts);
const NetworkChart = () => {
const chartComponent = useRef(null); // reference to chart obj
const [nodeData, setNodeData] = useState([
{ 'id': 'A', title:'ABC', other:'X', dataLabels: { enabled: true }, marker: { radius: 11, fillColor: 'red' } },
{ 'id': 'P', title:'CDE', other:'Y', dataLabels: { enabled: true } },
{ 'id': 'K', title:'EDF', other:'X', dataLabels: { enabled: true } },
{ 'id': 'S', title:'DFG', other:'Z', dataLabels: { enabled: true } },
{ 'id': 'D', title:'SDF', other:'Y', dataLabels: { enabled: true } },
]);
const [linkData, setLinkData] = useState([
{ 'from': 'D', 'to': 'A' },
{ 'from': 'S', 'to': 'A' },
{ 'from': 'K', 'to': 'A' },
{ 'from': 'P', 'to': 'A' }
]);
const [chartOptions, setChartOptions] = useState({
chart: {
type: 'networkgraph',
plotBorderWidth: 1,
},
title: {
text: 'Phrasal verbs'
},
subtitle: {
text: 'Integration: ' + 'euler'
},
credits: false,
plotOptions: {
networkgraph: {
layoutAlgorithm: {
enableSimulation: false,
integration: 'euler',
linkLength: 25,
},
keys: ['from', 'to'],
marker: {
radius: 5,
lineWidth: 1
}
},
series: {
point: {
events: {
click: function () {
// click function
},
}
}
}
},
series: [{
allowPointSelect: true,
nodes: nodeData,
data: linkData,
}]
});
return (
<div>
<HighchartsReact
highcharts={Highcharts}
options={chartOptions}
containerProps={{ style: { height: 700 } }}
allowChartUpdate = {true}
ref={chartComponent}
/>
</div>
)
};
export default NetworkChart;
Currently all I see is node id on hover. What I want to see is node id, title and other field values when I hover on each node in the chart.
You can get the required propeerties through: this.point.options
tooltip: {
formatter: function() {
const { title, other } = this.point.options;
return 'Title: ' + title + ' Other: ' + other
}
}
Live demo: http://jsfiddle.net/BlackLabel/4zgrnqc2/
API Reference: https://api.highcharts.com/highcharts/tooltip.formatter
I'm trying to draw a chart where categories can be filtered, and it's working pretty nicely, I used this to do it.
Problem is : my last category is the total of the others, and so is taller. I want that when the "total" checkbox is unchecheck the chart resize, but it doesn't and resize only if I also uncheck the "class7" checkbox.
you can try it here : https://jsfiddle.net/4rfdgvum/
var chart=null;
$(function() {
var chart = new Highcharts.Chart('container', {
chart: {
type: 'column',
shadow: true
},
title: {
text: 'My Title'
},
xAxis: {
categories: [{"class":"class1","name":"cat1"},{"class":"class2","name":"cat2"},{"class":"class3","name":"cat3"},{"class":"class4","name":"cat4"},{"class":"class5","name":"cat5"},{"class":"class6","name":"cat6"},{"class":"class7","name":"cat7"},{'class': 'total','name':'total'}],
labels: {
formatter: function() {
return this.value.name;
},
useHTML: true
}
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Numbers'
}
},
legend: {
enabled: true
},
tooltip: {
formatter: function () {
return '<b>' + this.x.name + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
formatter: function(){
return Highcharts.numberFormat(this.percentage,0) + '%';
}
}
}
},
series: [{
name: 'Ok',
color: 'green',
stack: 'a',
data: [
223,174,139,27,17,6,3,589 ]
},
{
name: 'Not Ok',
color: 'red',
stack: 'a',
data: [
21,29,26,14,15,11,11,127 ]
},
{
name: 'Partialy Ok',
color:'orange',
stack: 'a',
data: [
5,11,25,1,1,3,0,46 ]
},
{
name: 'Not usable',
color:'grey',
stack: 'a',
data: [
20,70,67,160,163,170,168,818 ]
},
{
name: 'Not done',
color:'brown',
stack: 'a',
data: [
173,158,185,240,246,252,260,1514 ]
}
]
}, function() {
$('input[type=checkbox]').bind('click', function() {
togglePointsByClass(this.value, $(this).is(':checked'), chart)
});
});
var visibleArr = [0,1,2,3,4,5,6,7];
function togglePointsByClass(className, shouldShow, chart) {
var isChartDirty = false;
if (shouldShow) {
chart.xAxis[0].userOptions.categories.forEach(function(category, i) {
if (category.class === className) {
visibleArr.push(i);
}
});
} else {
chart.xAxis[0].userOptions.categories.forEach(function(category, i) {
if (category.class === className && visibleArr.indexOf(i) > -1) {
visibleArr.splice(visibleArr.indexOf(i), 1);
}
});
}
if (visibleArr.length) {
chart.xAxis[0].update({
min: Math.min.apply(null, visibleArr),
max: Math.max.apply(null, visibleArr)
})
}
}
$('#container').highcharts().redraw();
});
Thanks
You can use axis.setExtremes() for setting max of the yAxis.
if (visibleArr.length) {
chart.xAxis[0].update({
min: Math.min.apply(null, visibleArr),
max: Math.max.apply(null, visibleArr)
}, false, false);
const max = visibleArr.reduce((a, b) => Math.max(chart.yAxis[0].stacks.columna[b].total, a), -Infinity)
chart.yAxis[0].setExtremes(0, max);
}
example: https://jsfiddle.net/mw7euo1a/
I created a Pie Donut chart with highcharts, it works well. Now what I want to do is when I hover an area, I want to highlight its parents and children and also to have all their data in the tooltip.
Here is my chart :
https://jsfiddle.net/whoknows/q9srL6o7/2/
And here is what I'd like to do :
http://i.imgur.com/AMr42dO.png
Thanks.
It is possible to use setState in mouseOver and mouseOut events of points to set hover state for multiple points. Tooltip formatter can also display multiple points that will match criteria. I have added hoverGroup variable to each point to find those points for setting states and for tooltip.
Example: http://jsfiddle.net/q9srL6o7/4/
$(function () {
var chart;
$(document).ready(function () {
var colors = ["#00bcd4", "#00838f", "#69f0ae", "#f4511e", "#d81b60", "#1e88e5"],
categories = ['Site #1', 'Site #2', 'Site #3', 'Site #4', 'Site #5'],
data = [{
y: 55.11,
color: colors[0],
drilldown: {
name: 'Site #1',
categories: ['Leisure', 'Business'],
data: [45.01, 10.1],
drilldown: {
name: 'In/Out',
categories: ['In', 'In', 'Out', 'Out'],
data: [32.97, 12.04, 6.1, 4]
}
}
}, {
y: 21.63,
color: colors[1],
drilldown: {
name: 'Site #2',
categories: ['Leisure', 'Business'],
data: [13.12, 8.51],
drilldown: {
name: 'In/Out',
categories: ['In', 'In', 'Out', 'Out'],
data: [8.53, 4.59, 3.12, 5.39]
}
}
}, {
y: 11.94,
color: colors[2],
drilldown: {
name: 'Site #3',
categories: ['Leisure', 'Business'],
data: [9.91, 2.03],
drilldown: {
name: 'In/Out',
categories: ['In', 'In', 'Out', 'Out'],
data: [5.91, 4, 1, 1.03]
}
}
}, {
y: 7.15,
color: colors[3],
drilldown: {
name: 'Site #4',
categories: ['Leisure', 'Business'],
data: [4.55, 2.6],
drilldown: {
name: 'In/Out',
categories: ['In', 'In', 'Out', 'Out'],
data: [4, 0.55, 0.75, 1.85]
}
}
}, {
y: 4.17,
color: colors[4],
drilldown: {
name: 'Site #5',
categories: ['Leisure', 'Business'],
data: [2.49, 1.68],
drilldown: {
name: 'In/Out',
categories: ['In', 'In', 'Out', 'Out'],
data: [1.46, 1.03, 0.45, 1.23]
}
}
}],
siteData = [],
trafficData = [],
inoutData = [],
inoutColors = ['#faba59', '#f79f45', '#8cd260', '#5cc064'];
for (var i = 0; i < data.length; i++) {
siteData.push({
name: categories[i],
y: data[i].y,
color: data[i].color,
hoverGroup: i
});
for (var j = 0; j < data[i].drilldown.data.length; j++) {
trafficData.push({
name: data[i].drilldown.categories[j],
y: data[i].drilldown.data[j],
color: j === 0 ? '#f06e4a' : '#36a061',
hoverGroup: i
});
}
for (var k = 0; k < data[i].drilldown.drilldown.data.length; k++) {
inoutData.push({
name: data[i].drilldown.drilldown.categories[k],
y: data[i].drilldown.drilldown.data[k],
color: inoutColors[k],
hoverGroup: i
});
}
}
// Create the chart
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'pie'
},
showInLegend: false,
legend: {
enabled: false
},
credits: {
enabled: false
},
title: {
enabled: false,
text: ''
},
yAxis: {
title: {
text: 'Total percent market share'
}
},
plotOptions: {
pie: {
shadow: false,
point: {
events: {
mouseOver: function () {
var hoverGroup = this.hoverGroup,
series = this.series.chart.series;
$.each(series, function (i, s) {
$.each(s.points, function (j, p) {
if (p.hoverGroup == hoverGroup) p.setState('hover');
});
});
},
mouseOut: function () {
var series = this.series.chart.series;
$.each(series, function (i, s) {
$.each(s.points, function (j, p) {
p.setState('');
});
});
}
}
}
}
},
tooltip: {
valueSuffix: '',
formatter: function () {
var ret = '',
once = true,
hoverGroup = this.point.hoverGroup,
series = this.series.chart.series;
$.each(series, function (i, s) {
$.each(s.points, function (j, p) {
if (p.hoverGroup == hoverGroup) {
ret = '<span style="color:' + p.color + ';">●</span> ' + p.name + ' :' + p.y + '<br/>' + ret;
}
});
});
return ret;
}
},
series: [{
name: 'In/Out',
data: inoutData,
size: '85%',
innerSize: '20%',
dataLabels: {
formatter: function () {
return null;
}
}
}, {
name: 'Type de trafic',
data: trafficData,
size: '90%',
innerSize: '85%',
dataLabels: {
formatter: function () {
return null;
}
}
}, {
name: 'Site',
data: siteData,
size: '100%',
innerSize: '90%',
dataLabels: {
formatter: function () {
return null;
}
}
}]
});
});
});
I am new in Highcharts. I am creating multiple series reading from Java server side JSON list, the JSON objects consist multiple series and each series have 'Electric IRms' following by 'Temperature' mapping to two Y Axis label.
The problem I encounter is 2nd Y axis unit is not display.
The JSON list format are
{name, "serialNumber1_type1", {"data", [[timestamp1, value1],
[[timestamp2, value2], ...
{name, "serialNumber1_type2", {"data", [[timestamp1, value1],
[[timestamp2, value2], ...
{name, "serialNumber2_type1", {"data", [[timestamp1, value1],
[[timestamp2, value2],
{name, "serialNumber2_type2", {"data", [[timestamp1, value1],
...
{"title","HighCharts Title"}
e.g my JSON list
[{"name":"5004672_IRms"},{"data":[[1373958000000,53],[1373958300000,53]....
{"name","5004672_Temperature"},{"data":[[1373958000000,80],[1373958300000,81]....
{"name":"5004687_IRms"},{"data":[[1373958000000,54],[1373958300000,53]..
{"name","5004687_Temperature"},{"data":[[1373958000000,82],[1373958300000,83]...
....
{"title", "HighCharts_Title"}
]
My code below
$(function() {
var titleName='';
var options = {
chart: {
renderTo: 'container',
type: 'spline'
},
rangeSelector : {
{
type: 'day',
count: 1,
text: '1 d'
},{
type: 'week',
count: 1,
text: '1 wk'
}, {
type: 'all',
text: 'all'
}],
selected: 1
},
title: {
text: '(IRms & Temperature)'
},
xAxis: {
title: {
text: 'Time (UTC)'
},
type: 'datetime',
labels: {
align: 'left',
formatter: function() {
return Highcharts.dateFormat('%I:%M %P', this.value);
}
},
gridLineDashStyle: 'dot',
gridLineWidth: 1,
tickInterval: 60 * 60 * 1000,
lineWidth: 2,
lineColor: '#92A8CD',
tickWidth: 3,
tickLength: 6,
tickColor: '#92A8CD',
},
yAxis: [{
labels: {
formatter: function() {
return this.value;
}
},
title: {
text: ''
},
opposite: true
},
{
gridLineWidth: 0,
title: {
text: '',
style: {
color: '#4572A7'
}
},
labels: {
formatter: function() {
return this.value +'°F';
}
}
}
],
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
...
width: 200
});
sname = this.series.name;
$.getJSON('/em/em/historypointdetail?pointid=' + sname, function(response) {
......
});
}
}
},
marker: {
lineWidth:
}
},
series: []
};
var serialNumber;
$.getJSON('/em/em/lli?id=<c:out value="${elementIds}" />',function(data) {
$.each(data, function(key,value) {
$.each(value, function(key,val) {
if (key == 'name') {
serialNumber = val;
}
else if (key == 'data') {
var dataseries = { data: []};
$.each(val, function(key,val) {
dataseries.data.push(val);
});
dataseries.name=serialNumber;
var names = serialNumber.split('_');
if (names[1] == 'IRms') {
options.title.text = 'Current';
options.series.yAxis = 0;
options.yAxis[0].title.text = 'Current';
}
else if (names[1] == 'Temperature') {
options.title.text = 'Temperature';
options.series.yAxis = 1;
options.yAxis[1].title.text = 'Temperature';
}
options.series.push(dataseries);
}
else if (key == 'title') {
htext = val;
}
});
});
chart = new Highcharts.StockChart(options);
chart.setTitle({text: htext});
}).error(function() {console.log('error');});
I created two Y Axis and 2nd Y Axis have labels return this.value + " F". but 2nd Y Axis
label is not display when chart draw.
Thanks
When adding series to different yAxis, you need to specify index of that yAxis, or ID, for example:
var dataseries = { data: [], yAxis: 1};
I have a chart that displays series data by year.
eg 1011, 1112, 1213, 1415, and shows an actual and target for each year.
If the user clicks on a column, the chart drills down into that dataset, however I'd like to be able to show Actual and Target next to each other, rather than a single column...
JSFiddle: http://jsfiddle.net/MuydK/
Any help appreciated, am stumped on this as tried several methods.
I believe I understand how to set up the data into a series set rather than just a dataset, but don't know what changes I need to make to SetChart etc...
Also the Series titles disappear once I've drilled in and out once, any ideas...?
Many Thanks for you help.
var chart;
$(document).ready(function () {
var colors = Highcharts.getOptions().colors,
categories1 = ['1011', '1112', '1213', '1415'],
name1 = 'Actual',
data1 = [ ...
I updated your code with simple data, I think this is what you want,This is just a demo you can update code according to you.
JSFiddle
Here is code:
$(function () {
var chart;
$(document).ready(function () {
var colors = Highcharts.getOptions().colors,
categories1 = ['1011', '1112', '1213', '1415'],
name1 = 'Actual',
data1 = [
{
y: 1674,
color: colors[0],
drilldown: {
name: '1011 Actual',
categories: ['BS', 'B', 'IT', 'C'],
data: [3, 32, 54, 50],
color: colors[0],
name1: '1011 Target',
data1: [0, 31, 50, 60],
color1:colors[1]
}
}
]; var colors = Highcharts.getOptions().colors,
categories2 = ['1011', '1112', '1213', '1415'],
name2 = 'Target',
data2 = [
{
y: 1633,
color: colors[1],
drilldown: {
name: '1011 Actual',
categories: ['BS', 'B', 'IT', 'C'],
data: [3, 32, 54, 50],
color: colors[0],
name1: '1011 Target',
data1: [0, 31, 50, 60],
color1:colors[1]
}
}
]; function setChart(name, categories, data, color) {
console.log(name, categories, data, color);
chart.xAxis[0].setCategories(categories);
while (chart.series.length > 0) {
chart.series[0].remove(true);
}
for (var i = 0; i < data.length; i++) {
chart.addSeries({
name: name[i],
data: data[i],
color: color[i]
});
}
}
chart = new Highcharts.Chart({
chart: {
renderTo: 'con1',
type: 'column'
},
title: {
text: 'Learner Responsive 16-18'
},
subtitle: {
text: 'Click the columns to view breakdown by department. Click again to view by Academic Year.'
},
xAxis: {
categories: categories1
, labels: {rotation:-90, align:'right'}
},
yAxis: {
title: {
text: 'Learner Responsive 16-18'
}
},
plotOptions: {
column: {
cursor: 'pointer',
point: {
events: {
click: function () {
var drilldown = this.drilldown;
if (drilldown) { // drill down
setChart([drilldown.name,drilldown.name1], drilldown.categories, [drilldown.data, drilldown.data1], [drilldown.color,drilldown.color1]);
} else { // restore
setChart(name, categories1, [data1, data2], 'white');
}
}
}
},
dataLabels: {
enabled: true,
color: colors[0],
style: {
fontWeight: 'bold'
},
formatter: function () {
return this.y; // +'%';
}
}
}
},
tooltip: {
formatter: function () {
var point = this.point,
series = point.series,
s = 'Learner Responsive 16-18' + '<br/>' + this.x + ' ' + series.name + ' is <b>' + this.y + '</b><br/>';
if (point.drilldown) {
s += 'Click to view <b>' + point.category + ' ' + series.name + ' </b>' + ' by department';
} else {
s += 'Click to return to view by academic year.';
}
return s;
}
},
series: [{
name: name1,
data: data1,
color: colors[0]
},{
name: name2,
data: data2,
color: colors[1]
}],
exporting: {
enabled: false
}
},
function (chart) {
console.log(chart);
});
});
});