I am very new to data visulizations.
Currently we are having a requirement to draw a chart similar to below using HighChart.js
See jsfiddle: http://jsfiddle.net/rgpz2ru5/22/ for what I tried so far.
I am successfully able to draw chart but facing issue while drawing lines between the datalabel and point (just shown in above image)?
Can you please help?
See below code to draw a chart:
$('#container').highcharts({
chart: {
type: 'scatter',
},
xAxis: {
visible: false
},
yAxis: {
title: {
text: ''
},
labels: {
formatter: function() {
return null
}
}
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
inside: false,
formatter: function(){
console.log("X"+this.x)
console.log("this.x%2"+this.x%2)
if(this.x%2 == 0){
console.log("in if")
return "<div style='position: relative;height:70px; border-left:solid thin #ff0000;margin-left:10px'><span style='position: absolute;bottom: 0;right: 0;'>hello</span></div>";
}else{
console.log("in else")
return "<span style='color:black'>"+this.key+"</span><div style='height:70px; border-left:solid thin #ff0000;margin-left:10px'/>";
}
},
useHTML:true
}
},scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: false,
lineColor: "#ffb74d"
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.x} cm, {point.y} kg'
}
}
},
series: [{
data: [{
x: 1,
y: 1,
dataLabels: {
y: -80
},
marker: {
radius: 3
},
name: 'SDS',
color: "#ffb74d"
}, {
x: 2,
y: 1,
dataLabels: {
y: 80
},
marker: {
radius: 5
},
name: 'MIP',
color:"#ffe0b2"
}, {
x: 3,
y: 1,
dataLabels: {
y: -80,
distance : 50,
softConnector : false,
connectorColor : '#D0D0D0',
},
marker: {
radius: 7
},
name: 'MDP',
color:"#ff9800"
},{
x: 4,
y: 1,
dataLabels: {
y: 80
},
marker: {
radius: 9
},
name: 'RAD',
color:"#ffb74d"
},{
x: 5,
y: 1,
dataLabels: {
y: -80
},
marker: {
radius: 3
},
name: 'SDS',
color: "#ffb74d"
}, {
x: 6,
y: 1,
dataLabels: {
y: 80
},
marker: {
radius: 5
},
name: 'MIP',
color:"#ffe0b2"
}, {
x: 7,
y: 1,
dataLabels: {
y: -80
},
marker: {
radius: 7
},
name: 'MDP',
color:"#ff9800"
},{
x: 8,
y: 1,
dataLabels: {
y: 80
},
marker: {
radius: 9
},
name: 'RAD',
color:"#ffb74d"
},{
x: 9,
y: 1,
dataLabels: {
y: -80
},
marker: {
radius: 3
},
name: 'SDS',
color: "#ffb74d"
}, {
x: 10,
y: 1,
dataLabels: {
y: 80
},
marker: {
radius: 5
},
name: 'MIP',
color:"#ffe0b2"
}, {
x: 11,
y: 1,
dataLabels: {
y: -80
},
marker: {
radius: 7
},
name: 'MDP',
color:"#ff9800"
},{
x: 12,
y: 1,
dataLabels: {
y: 80
},
marker: {
radius: 9
},
name: 'RAD',
color:"#ffb74d"
}]
}]
});
Can you please help?
Your chart seems to be of a specific kind. I personally have not seen any such visualizations before. Also, having worked with HighCharts, I doubt if any type of highchart can be transformed as yours.
However, on the first look on your figure the following idea appeared in my mind with angular framework.
You can achieve this kind of visualization using basic html and css.
Assuming you are aware with Angular terminology. I suggest having a list of all your values. Loop them in a simple div as follows:
<div ng-repeat = "c in pointsList" > </div>
Next you can use ng-style or ng-class to add dynamic css to your each div.
Seeing your figure, I assume you only following css properties:
1. border-radius
2. background-color
3. width
4. height
Seems like you have fixed categories for each type of bubbles. So you can make few fixed classes in your css and apply them dynamically on the basis of your type of point. Basically, it would look like:
<div ng-repeat = "c in pointsList" ng-class = "{'css1' : c.type1, 'css2' : c.type2}" > </div>
Along with this you will need to apply display: inline-block to bring all divs in a line.
I know, its too naive solution, but if you have limited requirements of such chart, this can help you achieve it with minimal adjustments.
To make similar chart you can use bubble chart: http://jsfiddle.net/rgpz2ru5/
Or standard scatter chart: http://jsfiddle.net/rgpz2ru5/1/
You can change marker size of scatter using marker.radius parameter:
marker: {
radius: 5,
states: {
hover: {
lineColor: "#ffb74d"
}
}
},
You can add your labels using chart.renderer.path and chart.renderer.label:
http://api.highcharts.com/highcharts/Renderer.path
http://api.highcharts.com/highcharts/Renderer.label
var drawLabels = function(chart) {
$('.cLabels').remove();
var series = chart.series,
renderer = chart.renderer,
plotTop = chart.plotTop,
plotLeft = chart.plotLeft;
Highcharts.each(series, function(s) {
Highcharts.each(s.data, function(p) {
renderer.path(['M', p.plotX + plotLeft, p.plotY + plotTop, 'L', p.plotX + plotLeft, p.plotY + plotTop - 30]).attr({
stroke: 'black',
'stroke-width': 1
}).addClass('cLabels').add();
renderer.label(p.name, p.plotX + plotLeft, p.plotY + plotTop - 50).attr({
'text-anchor': 'middle',
padding: 0
}).addClass('cLabels').add();
});
});
}
Here you can see an example how it can work: http://jsfiddle.net/rgpz2ru5/29/
Related
I am attempting to create the following chart:
However I can't seem to get the plotbands to work in this way; right now, they fill the entire axis:
I am not sure if I should use annotations instead, but so far I haven't gotten it to work. What can I try next?
Highcharts.chart('container',{
credits: {
enabled: false
},
title: {
text: "hello world",
style: {
visibility: 'hidden'
}
},
chart: {
type: 'line',
width: 400,
},
legend: {
enabled: false
},
exporting: {
enabled: true,
allowHTML:true,
chartOptions: {
chart: {
marginLeft: 175,
marginRight: 175
},
plotOptions: {
line: {
dataLabels: {
style: {
fontSize: 14
},
verticalAlign: "top",
useHTML: true
}
}
}
}
},
yAxis: {
startOnTick: false,
endOnTick: false,
gridLineWidth: 2,
tickWidth: 2,
tickLength: 20,
plotBands: [{
color: 'rgba(231, 23, 60, 0.5)', // Color value
from: 5, // Start of the plot band
to: 6.2 // End of the plot band
},
{
color: 'rgba(53, 101, 237, 0.5)', // Color value
from: 1, // Start of the plot band
to: 3 // End of the plot band
}
],
title: {
align: 'high',
offset: -40,
text: 'mmol/L',
style: {
fontWeight: "bold",
fontSize: 15
},
rotation: 0,
y: -20
},
min: 0,
max: 7,
labels: {
x: -10,
y: -3,
formatter: function () {
if (this.value != 0) {
if (this.value < 8) {
return this.value;
}
}
},
style: {
fontWeight: "400",
lineHight: "20",
padding: "0",
fontSize: "13"
}
}
},
annotations: [{
shapes: [{
point: '0',
type: 'circle',
r: 10
}, {
point: '3',
type: 'rect',
width: 20,
height: 20,
x: -10,
y: -25
}, {
fill: 'none',
stroke: 'red',
strokeWidth: 3,
type: 'path',
points: ['0', '1', {
x: 6,
y: 195,
xAxis: 0,
yAxis: 0
}],
markerEnd: 'arrow'
}],
labels: [{
point: {
x: 6,
y: 195,
xAxis: 0,
yAxis: 0
}
}]
}],
xAxis: {
gridLineColor: 'transparent',
accessibility: {
rangeDescription: 'Range: 2010 to 2020'
},
categories: [2018, 2019]
},
plotOptions: {
line: {
dataLabels: {
style: {
fontSize: 14
},
verticalAlign: "top",
useHTML: true,
format: '<div style="max-width: 10ch; text-align: center;">{y}<br/>mmol/L</div>'
}
}
},
series: [{
name: '',
color: "black",
data: [5.4, 3],
showInLegend: false,
dataLabels: {
enabled: true,
useHTML: true,
}
}],
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/series-label.js"></script>
<script src="https://code.highcharts.com/modules/annotations.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
<figure class="highcharts-figure">
<div id="container"></div>
</figure>
This kind of plotBand shape is not possible from the API level, but you can simulate it in several ways. Example configurations:
SVG Renderer:
chart: {
events: {
render() {
const chart = this;
if (chart.rects) {
chart.rects = chart.rects.destroy();
}
chart.rects = chart.renderer.g('rects').attr({
zIndex: 1
}).add();
let x = chart.xAxis[0].toPixels(1),
y = chart.yAxis[0].toPixels(4),
width = chart.xAxis[0].toPixels(2) - chart.xAxis[0].toPixels(1),
height = chart.yAxis[0].toPixels(2) - chart.yAxis[0].toPixels(4);
chart.rect = chart.renderer.rect(x, y, width, height)
.attr({
fill: 'grey'
}).add(chart.rects)
chart.rect = chart.renderer.rect(chart.xAxis[0].toPixels(3), y, width, height)
.attr({
fill: 'grey'
}).add(chart.rects)
}
}
},
Demo:
https://jsfiddle.net/BlackLabel/wst607ub/
API Reference:
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer
Annotations:
annotations: [{
draggable: false,
shapes: [{
points: [{
x: 1,
y: 2,
xAxis: 0, // xAxis reference used, use xAxis value
yAxis: 0 // yAxis reference used, use xAxis value
}, {
x: 2,
y: 2,
xAxis: 0,
yAxis: 0
}, {
x: 2,
y: 4,
xAxis: 0,
yAxis: 0
}, {
x: 1,
y: 4,
xAxis: 0,
yAxis: 0
}],
type: 'path'
}]
}]
Demo:
https://jsfiddle.net/BlackLabel/uvxzp6o7/
API Reference:
https://api.highcharts.com/highcharts/annotations
Polygon series:
series: [{
name: 'Polygons',
type: 'polygon',
color: 'grey',
showInLegend: false,
enableMouseTracking: false,
states: {
inactive: {
opacity: 1,
},
},
data: [
[1, 2],
[2, 2],
[2, 4],
[1, 4],
null, // allows multiple polygons
[3, 2],
[4, 2],
[4, 4],
[3, 4],
]
}]
Demo:
https://jsfiddle.net/BlackLabel/4n7ep3k2/
API Reference:
https://api.highcharts.com/highcharts/series.polygon
Take note that annotations and polygon series require the module to be included.
I got stuck somewhere and there I want your help. I want a Pie chart data-label feature into the variable Pie chart. which is like the data should stay in the centre of the chart piece.
I tried so many ways but not fit in the centre like the data label indication line.
Please check the code and design below and help me to fix my issue...
This's the design reference for the Output
This's the current output of my code
This's the link for the current output...
<script>
Highcharts.setOptions({
colors: ['#2B2E33', '#4D5566', '#8590A6', '#B8C3D9', '#02D42E']
});
Highcharts.chart('container', {
chart: {
type: 'variablepie',
style: {
fontFamily: "'Montserrat-Regular', 'sans-serif'",
letterSpacing: '0.5px',
},
events: {
load: function() {
var series = this.series[0],
distance = series.points[0].shapeArgs.r / 2;
series.update({
dataLabels: {
distance: -distance
}
});
}
}
},
title: {
text: ' '
},
tooltip: {
headerFormat: '',
pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {point.name}</b> {point.y}<br/>'
},
accessibility: {
point: {
valueSuffix: '%'
}
},
legend: {
symbolRadius: 0,
itemStyle: {
fontWeight: 'bold',
color:'#8590A6',
textOverflow: 'clip'
}
},
plotOptions: {
variablepie: {
allowPointSelect: true,
cursor: 'pointer',
//showInLegend: true,
dataLabels: {
enabled: true,
alignTo: 'center',
format: '{point.percentage:.1f} %',
distance: -10,
style:{
textOutline: 'none',
fontSize: 15,
lineHeight: 0,
color:'white',
fontWeight: 'bold',
},
filter: {
property: 'percentage',
operator: '>',
value: 2
}
}
}
},
series: [{
innerSize: '40%',
zMin: 0,
name: 'countries',
data: [{
name: 'Google',
y: 25,
z: 100,
}, {
name: 'Facebook',
y: 14,
z: 115
}, {
name: 'Pinterest',
y: 11,
z: 85
}, {
name: 'Yelp',
y: 10,
z: 90
}, {
name: 'Local Services',
y: 40,
z: 140
}]
}]
}, function (chart) {
$legend = $('#customLegend');
$.each(chart.series[0].data, function (j, data) {
$legend.append('<div class="item"><div class="symbol" style="background-color:'+data.color+'"></div><div class="serieName" id="">' + data.name + '</div><div class="value" id="">' + data.y + '</div></div>');
});
$('#customLegend .item').click(function(){
var inx = $(this).index(),
point = chart.series[0].data[inx];
if(point.visible)
point.setVisible(false);
else
point.setVisible(true);
});
});
You can add some extra info to your serie in order to position you label correctly.
For instance:
{
name: 'Pinterest',
y: 11,
z: 85,
dataLabels: {
distance: -30,
x: -20
}
}, {
name: 'Yelp',
y: 10,
z: 90,
dataLabels: {
distance: -30,
x: 30
}
This may help for static charts.
I prepared a demo where the center of the arc point is calculated and used as translate function coordinates to center the data label.
events: {
render: function() {
const series = this.series[0];
series.points.forEach(p => {
const dataLabel = p.dataLabel;
const args = p.shapeArgs;
const angle = (args.start + args.end) / 2;
const r = (args.innerR + args.r) / 2;
const x = args.x + (r * Math.cos(angle)) - dataLabel.bBox.width / 2;
const y = args.y + (r * Math.sin(angle)) - dataLabel.bBox.height / 2;
dataLabel.translate(x, y)
})
}
}
Demo: https://jsfiddle.net/BlackLabel/c3wf85g7/
I've been trying to make the gauge thinner. I succeeded a little by making the innerRadius 90%, but I'm unable to change the size of the green section. It's always bigger. I tried playing around with 'outerRadius' too but lo luck so far.
var gaugeOptions = {
chart: {
type: 'solidgauge'
},
title: null,
pane: {
center: ['30%', '85%'],
size: '150%',
startAngle: -90,
endAngle: 90,
background: {
backgroundColor: Highcharts.defaultOptions.legend.backgroundColor || '#EEE',
innerRadius: '110%',
outerRadius: '85%',
shape: 'arc'
}
},
tooltip: {
enabled: false
},
// the value axis
yAxis: {
stops: [
[0.1, '#55BF3B'], // green
[0.5, '#DDDF0D'], // yellow
[0.9, '#DF5353'] // red
],
lineWidth: 0,
minorTickInterval: null,
tickAmount: 2,
title: {
y: -70
},
labels: {
y: 16
}
},
plotOptions: {
solidgauge: {
dataLabels: {
y: 5,
borderWidth: 0,
useHTML: true
}
}
}
};
// The speed gauge
var chartSpeed = Highcharts.chart('container-speed', Highcharts.merge(gaugeOptions, {
yAxis: {
min: 0,
max: 100,
title: {
text: ''
}
},
credits: {
enabled: false
},
series: [{
name: 'Speed',
data: [20],
dataLabels: {
format: '<div style="text-align:center">' +
'<span style="font-size:25px">{y}</span><br/>' +
'<span style="font-size:12px;opacity:0.4">km/h</span>' +
'</div>'
}
}]
}));
Here's a fiddle. I'm basically trying to make the green match the grey.
The size of the green section can be set by add properties radius and innerRadius in series.data.
In your case, it should be:
series: [{
name: 'Speed',
data: [{
y: 20,
radius: 90,
innerRadius: 105
}],
dataLabels: {...}
}]
more info here
You can also set radius and innerRadius properties on a series level:
series: [{
radius: 90,
innerRadius: 105,
...
}]
Live demo: https://jsfiddle.net/BlackLabel/fwumc7db/
API Reference:
https://api.highcharts.com/highcharts/series.solidgauge.innerRadius
https://api.highcharts.com/highcharts/series.solidgauge.radius
(Highcharts version 6)
Is it possible to have a time line looking chart in addition to data points like in this example:
https://jsfiddle.net/s1eL30Lh/97/
<script src="https://code.highcharts.com/stock/highstock.js"></script>
but without using highstock and instead only use highcharts ?
I know it's possible to use xrange module but it's not quite the same:
https://jsfiddle.net/deep3015/q18yvy75/
If the ranges are long enough to simulate a line then you lack the ability to add "data points" on top of the line, and if you make the ranges small enough to look like data points then you don't have a line.
NOTE
I'm aware of the new chart type 'timeline' in version 7 but I need to work with version 6.1
Yes, it is possible. However, you can't use flags series because it is only supported by Highstock. Check the demo and code posted below.
Code:
function toMs(yeah, month) {
return Date.UTC(yeah, month, 1);
}
var series = [{
// First series
name: 'Running',
color: 'green',
id: 'green',
dataRaw: [{
y: 1,
xRanges: [
// first value: from; second value: to
[toMs(2000, 1), toMs(2002, 8)],
[toMs(2006, 10), toMs(2006, 11)]
]
}]
}, {
// Second series
name: 'Filed',
color: 'yellow',
id: 'yellow',
dataRaw: [{
y: 1,
xRanges: [
// first value: from; second value: to
[toMs(2002, 8), toMs(2006, 10)]
]
}]
},
{
// Second series
name: 'Granted',
color: 'blue',
id: 'blue',
dataRaw: [{
y: 1,
xRanges: [
// first value: from; second value: to
[toMs(2006, 11), toMs(2021, 8)]
]
}]
}
].map(function(series) {
series.data = [];
series.dataRaw.forEach(function(dataRaw) {
dataRaw.xRanges.forEach(function(xRange) {
series.data.push([xRange[0], dataRaw.y], [xRange[1], dataRaw.y], [xRange[1], null]); // null breakes the line
}); // forEach
}); // forEach
return series;
});
console.log(series);
var chart = Highcharts.chart('container', {
chart: {
type: 'scatter'
},
title: {
text: 'Example'
},
plotOptions: {
scatter: {
lineWidth: 5,
marker: {
enabled: true,
symbol: 'circle',
fillColor: '#FFFFFF',
lineWidth: 2,
lineColor: null,
radius: 5
},
dataLabels: {
enabled: true,
align: 'right',
rotation: -30,
x: -2,
y: 15,
formatter: function() {
return Highcharts.dateFormat('%Y-%m', this.x);
}
},
tooltip: {
pointFormatter: function() {
return Highcharts.dateFormat('%Y-%m', this.x);
}
}
},
flags: {
lineWidth: 1
}
},
xAxis: {
title: {
text: 'Time'
},
type: 'datetime',
minTickInterval: 365 * 24 * 36e5,
labels: {
align: 'left'
},
plotBands: [{
from: Date.UTC(2000, 10, 27),
to: Date.UTC(2004, 11, 1),
color: '#EFFFFF',
label: {
text: 'Office 1',
style: {
color: '#999999'
},
y: 30
}
}, {
from: Date.UTC(2004, 11, 1),
to: Date.UTC(2012, 9, 1),
color: '#FFFFEF',
label: {
text: 'Office 2',
style: {
color: '#999999'
},
y: 30
}
}, {
from: Date.UTC(2012, 9, 1),
to: Date.UTC(2020, 10, 27),
color: '#FFEFFF',
label: {
text: 'Office 3',
style: {
color: '#999999'
},
y: 30
}
}]
},
yAxis: {
tickInterval: 1
},
series: series,
annotations: [{
labelOptions: {
backgroundColor: 'rgba(255,255,255,0.5)'
},
labels: [{
distance: 10,
point: {
xAxis: 0,
yAxis: 0,
x: toMs(2002, 8),
y: 1
},
text: 'Filled Date'
}]
}]
});
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/6.1/highcharts.js"></script>
<script src="https://code.highcharts.com/6.1/modules/annotations.js"></script>
<div id="container" style="height: 400px"></div>
Demo:
https://jsfiddle.net/BlackLabel/6eahoxjv/
I'm trying to plot a scatter plot using the Highcharts library. I get some results from my database and format them in front end level using javascript (transformGraph2Data function in the following code does this work - I don't include the code of this function here to keep the question clear and short). More specifically I have the following piece of code:
<script type="text/javascript">
var graph2dataa;
function plotGraph2() {
graph2dataa = transformGraph2Data(<%=graph2data%>);
console.log(graph2dataa);
console.log(typeof graph2dataa);
Highcharts.chart('graphDiv2', {
chart: {
type: 'scatter',
zoomType: 'xy',
events: {
click: function (e) {
var x = e.xAxis[0].value,
y = e.yAxis[0].value,
series = this.series[0];
series.addPoint([x, y]);
}
}
},
xAxis: {
title: {
enabled: true,
text: '<b><%=graph2XaxisTitle%></b>'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true,
plotLines: [{
value: 0,
color: 'red',
dashStyle: 'shortdash',
width: 2
}]
},
yAxis: {
title: {
text: '<b><%=graph2YaxisTitle%></b>',
style: {
fontWeight: 'normal'
}
},
plotLines: [{
value: 0,
color: 'red',
dashStyle: 'shortdash',
width: 2
}]
},
plotOptions: {
series: {
cursor: 'pointer',
turboThreshold: 0
},
scatter: {
marker: {
radius: 2,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
}
}
},
graph2dataa //THIS VARIABLE HOLDS THE ACTUAL DATA I'D LIKE TO PLOT
});
}
</script>
The graph2dataa variable gets the following string value:
series: [{ name: "22h - 4h", color: "#000000", data: [{ name: "HACD3", x: 0.417666669, y: 1.841010179 }, { name: "VPS53", x: 0.113499999, y: 0.153579771 }, { name: "IPO11", x: -0.300000004, y: 0.734065117 }, { name: "FIP1L1", x: 0.067000012, y: 0.165934747 }, { name: "HSPE1", x: 0.186666687, y: 0.407514478 }] }] which is valid and can be plotted if I hardcode it. The problem occurs when I try to pass that value using the graph2dataa variable.
Any ideas what am I doing wrong?
Highcharts require a specific series structure and it should be an array of object, not a string. Your transformGraph2Data function should return the correct structure, which looks this way:
var graph2dataa = [{
name: "22h - 4h",
color: "#000000",
data: [{
name: "HACD3",
x: 0.417666669,
y: 1.841010179
}, {
name: "VPS53",
x: 0.113499999,
y: 0.153579771
}, {
name: "IPO11",
x: -0.300000004,
y: 0.734065117
}, {
name: "FIP1L1",
x: 0.067000012,
y: 0.165934747
}, {
name: "HSPE1",
x: 0.186666687,
y: 0.407514478
}]
}]
Live demo: http://jsfiddle.net/BlackLabel/4ath23yo/