There seems to be one feature in FusionCharts preventing me from migrating to the Google Charts API; trend zones (see the second example). Using these I can set horizontal background colours - trends - behind my columns.
It's a powerful visualisation in my use case where I'm banding values.
I have sifted through the documentation and just can't quite find what I need. Has anyone hacked something together that might do the trick?
Thanks for any help you can give!
I wrote a hack that does pretty much exactly what you are looking for:
function drawChart () {
var data = new google.visualization.DataTable();
data.addColumn('number', 'x');
data.addColumn('number', 'y');
data.addColumn('number', 'color band 1');
data.addColumn('number', 'color band 2');
data.addColumn('number', 'color band 3');
data.addColumn('number', 'color band 4');
data.addColumn('number', 'color band 5');
var y = 50;
// fill with 100 rows of random data
for (var i = 0; i < 100; i++) {
y += Math.ceil(Math.random() * 5) * Math.pow(-1, Math.ceil(Math.random() * 2));
if (y < 0) {
y = 10;
}
if (y > 100) {
y = 90;
}
// make the colored bands appear every 20
data.addRow([i, y, 20, 20, 20, 20, 20]);
}
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(data, {
height: 400,
width: 600,
isStacked: true,
vAxis: {
minValue: 0,
maxValue: 100
},
series: {
0: {
type: 'line'
},
1: {
lineWidth: 0,
type: 'area',
visibleInLegend: false,
enableInteractivity: false
},
2: {
lineWidth: 0,
type: 'area',
visibleInLegend: false,
enableInteractivity: false
},
3: {
lineWidth: 0,
type: 'area',
visibleInLegend: false,
enableInteractivity: false
},
4: {
lineWidth: 0,
type: 'area',
visibleInLegend: false,
enableInteractivity: false
},
5: {
lineWidth: 0,
type: 'area',
visibleInLegend: false,
enableInteractivity: false
},
6: {
lineWidth: 0,
type: 'area',
visibleInLegend: false,
enableInteractivity: false
}
}
});
}
google.load('visualization', '1', {packages: ['corechart'], callback: drawChart});
See it working here: http://jsfiddle.net/asgallant/apH2B/
Related
I tried to make scatter graph with Echarts.
Every item has x, y, size, objectid attributes and based on these data I try to build scatter graph. Here is my code:
// x, y, size, objectid
var orgdata = [
[[200, -200, 10, 2]],
[[400, -300, 20, 1]],
[[400, -400, 20, 2]],
];
// map item color based on objectid
var colormap = [
"#FF0000",
"#00FF00",
"#000FFF",
"#FFF0000",
"#0000FF",
];
option = {
xAxis: {type: 'value', position: 'top', min:0, max: 1000},
yAxis: {type: 'value', min: 0, max: -1000},
series: [],
color: colormap
};
for (let i = 0; i < orgdata.length; i++) {
option.series.push({
data: orgdata[i],
type: 'scatter',
symbolSize: function (data) {
return (data[2]);
},
itemStyle: {
color: colormap[orgdata[i][3]]
}
});
}type here
And
Everything else seems to work, but item color doesn't change based on objectid.
How I should fix a code?
I want to convert below chart to SVG so that I can export it to PDF/PPT along with other contents.
click here to see the demo chart
I know I have highchart export, but I can't use it since I have something else apart from chart and html2canvas is not an option because of some security reasons.
function _getDiamondGraphLabel(head, body, lvl, positionLeft, primeColor) {
var positionedTopClass = '',
headFormatted = '',
bodyFormatted = '',
positionedLeftClass = '';
if (lvl) {
positionedTopClass = 'diamond-graph-label-lvl-' + lvl;
}
if (positionLeft) {
positionedLeftClass = 'diamond-graph-label-left';
}
headFormatted = '<div class="diamond-graph-head-label">' + head + '</div>';
bodyFormatted = '<div class="diamond-graph-body-label"><b>' + body + '</b></div>';
var retVal = '<div ' + (primeColor ? 'style="border-color: ' + primeColor + '; border-width: 3px"' : '') + ' class="diamond-graph-label ' +
positionedTopClass + ' ' + positionedLeftClass + '""><div class="diamond-graph-label-content" ' +
(primeColor ? 'style="background-color: ' + primeColor + ' ; color: white"' : '') + '>' + headFormatted + bodyFormatted + '</div></div>';
return retVal;
}
var min = 49560,
per10 = 49560,
per25 = 63560,
per75 = 102537,
per90 = 119537,
median = 83362,
average = 89142,
max = 119537,
counter = 0;
var tickerPositions = [min, per10, per25, per75, per90, median, average, max];
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'columnrange',
inverted: true,
plotBackgroundColor: '#e9e9e9',
height: 25,
plotHeight: 60,
width: $('#container')[0].clientWidth,
spacing: [0, 0, 0, 0]
},
title: {
text: ''
},
xAxis: {
tickLength: 0,
labels: {
enabled: false
}
},
yAxis: {
tickPositions: tickerPositions,
labels: {
useHTML: true,
formatter: function () {
// There is a bug in Highcharts that formatter is calling twice. (reset if the value is higher than tickers length)
if (counter >= tickerPositions.length) {
counter = 0;
}
counter++;
switch (counter) {
case 2:
return _getDiamondGraphLabel('10th', this.value, 0, false, '#000');
case 3:
return _getDiamondGraphLabel('25th', this.value, 1, false, '#000');
case 4:
return _getDiamondGraphLabel('75th', this.value, 1, true, '#000');
case 5:
return _getDiamondGraphLabel('90th', this.value, 0, true, '#000');
case 6:
return _getDiamondGraphLabel("Median", this.value, 2, average < median, "#000");
case 7:
return _getDiamondGraphLabel("Average", this.value, 2, average > median, '#000');
default:
return '<div></div>';
}
}
},
title: {
text: null
}
},
legend: {
enabled: false
},
tooltip: {
enabled: false
},
exporting: {
enabled: false
},
credits: {
enabled: false
},
plotOptions: {
columnrange: {
grouping: false,
borderWidth: 0,
pointPadding: 0,
groupPadding: 0
}
},
series: [{
name: 'MinTo10th',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: min,
high: per10
}],
color: '#ebebeb'
}, {
name: '10thTo25th',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: per10,
high: per25
}],
color: '#bbbbbb'
}, {
name: '25thTo75th',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: per25,
high: per75
}],
color: '#6a6a6a'
}, {
name: '75thTo90th',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: per75,
high: per90
}],
color: '#bbbbbb'
}, {
name: '90thToMax',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: per90,
high: max
}],
color: '#ebebeb'
}, {
name: 'median',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: median,
high: median + 1
}],
color: '#1a8099'
}, {
name: 'average',
stack: 'DIAMOND_STACK',
data: [{
x: 0,
low: average,
high: average + 1
}],
color: '#006699'
}]
});
Can somebody help me with it.
Thanks in advance.
i'm using bubble chart from Highcharts, the label text inside of the bubbles is dynamic and sometimes can be bigger than the bubble itself,
I wonder if there's a way to make the text ellipsis according to the size of the bubble that contain it?
containerOptions = {
chart: {
type: 'bubble',
renderTo: $(container)[0],
events: {
drilldown: function (e) {
if (!e.seriesOptions) {
var chart = this,
drilldowns = {
'Animals': {
name: 'Animals',
data: [
{name: 'Dogs', y:2, x:10, z: 7, drilldown: true},
{name: 'Cats', y:4, x:12, z: 7}
]
},
'Dogs': {
name:"Dogs",
data: [
{name: 'Pitbull', y:3.7, x:7.6, z: 5, drilldown: false},
{name: 'German shepherd', y:6.7, x:6.9, z: 5, drilldown: false}
]
}
},
series = drilldowns[e.point.name];
chart.showLoading('Loading..');
setTimeout(function () {
chart.hideLoading();
chart.addSeriesAsDrilldown(e.point, series);
}, 1000);
}
}
}
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true,
style: { color: 'red' },
format: '{point.name}'
}
}
},
series: [{
name: 'Things',
colorByPoint: true,
data: [{
name: 'Animals',
y: 5,
x: 1,
z: 9,
drilldown: true
}, {
name: 'Fruits',
y: 2,
x: 9,
z: 9,
drilldown: false
}
]
}],
drilldown: {
series: [],
drillUpButton: {
relativeTo: 'spacingBox',
position: {
y: 0,
x: 0
}
}
}
}
}
You can loop through the data labels on load/redraw event and add/remove ellipsis according to the bubble's width and text's width.
function applyEllipsis() {
var series = this.series[0];
var options = series.options.dataLabels;
series.points.forEach(p => {
var r = p.marker.radius;
var label = p.dataLabel;
var text = label.text.textStr;
var bbox = label.getBBox(true);
while (bbox.width > 2 * r && text.length !== 1) {
text = text.slice(0, -1);
p.dataLabel.attr({
text: text + '\u2026'
});
bbox = label.getBBox(true);
}
p.dataLabel.align({
width: bbox.width,
height: bbox.height,
align: options.align,
verticalAlign: options.verticalAlign
}, null, p.dlBox);
});
}
Attach the function on load/redraw
Highcharts.chart('container', {
chart: {
type: 'bubble',
events: {
load: applyEllipsis,
redraw: applyEllipsis
}
},
example: http://jsfiddle.net/12d997o4/
What we are trying to do is to:
display crosshairs only if number of visible series > 1 (color: black)
otherwise disable crosshairs or alternatively set color transparent
Here are our problems:
independent of the number of visible series the crosshairs is not shown for the first hover (but for all subsequent hovers)
our main problem is that the color is not changing although the console.log displays that the color is correctly set due to the number of visible series
Please see the fiddle: example
Thanks for your suggestions!
$(function () {
var chart = new Highcharts.Chart({
chart: {
type: 'area',
renderTo: 'container'
},
title: {
text: 'Historic and Estimated Worldwide Population Growth by Region'
},
subtitle: {
text: 'Source: Wikipedia.org'
},
xAxis: {
categories: ['1750', '1800', '1850', '1900', '1950', '1999', '2050'],
tickmarkPlacement: 'on',
title: {
enabled: false
}
},
yAxis: {
title: {
text: 'Billions'
},
labels: {
formatter: function () {
return this.value / 1000;
}
}
},
tooltip: {
formatter: function () {
// show crosshairs only if visible series >1, else transparent
var nVisible = 0;
for (var i = 0; i < chart.series.length; i++) {
if (chart.series[i].visible) {
nVisible++;
};
if (nVisible > 1) {
break;
};
};
if (nVisible > 1) {
chart.options.tooltip.crosshairs = {
width: 1.5,
dashStyle: 'solid',
color: 'black'
};
} else {
chart.options.tooltip.crosshairs = {
color: 'transparent'
};
};
console.log(chart.options.tooltip.crosshairs.color);
return this.y + ' Billions';
},
backgroundColor: 'rgba(255,255,255,0.95)'
},
plotOptions: {
area: {
stacking: 'normal',
lineColor: '#666666',
lineWidth: 1,
marker: {
lineWidth: 1,
lineColor: '#666666'
}
}
},
series: [{
name: 'Asia',
data: [502, 635, 809, 947, 1402, 3634, 5268]
}, {
name: 'Africa',
data: [106, 107, 111, 133, 221, 767, 1766]
}, {
name: 'Europe',
data: [163, 203, 276, 408, 547, 729, 628]
}, {
name: 'America',
data: [18, 31, 54, 156, 339, 818, 1201]
}, {
name: 'Oceania',
data: [2, 2, 2, 6, 13, 30, 46]
}]
});
});
Don't add crosshair in real time, instead when chart is initialized, enable crosshair and then manage color by attr() updating. For example: http://jsfiddle.net/D5DME/3/
Code:
tooltip: {
crosshairs: [{
width: 1.5,
dashStyle: 'solid',
color: 'black'
}, false],
formatter: function () {
// show crosshairs only if visible series >1, else transparent
var nVisible = 0;
for (var i = 0; i < this.series.chart.series.length; i++) {
if (this.series.chart.series[i].visible) {
nVisible++;
};
};
if(this.series.chart.tooltip.crosshairs[0]) {
if (nVisible > 1) {
this.series.chart.tooltip.crosshairs[0].attr({
stroke: 'black'
});
} else {
this.series.chart.tooltip.crosshairs[0].attr({
stroke: 'rgba(0,0,0,0)'
});
}
}
return this.y + ' Billions';
},
backgroundColor: 'rgba(255,255,255,0.95)'
},
It looks to me that the tooltip code is the wrong place to be trying this. I would use the series hide and show event handlers to detect how many series were showing (a simple counter which increments in show and decrements in hide would work).
http://api.highcharts.com/highstock#plotOptions.series.events.hide
You could try the chart setting options depending on the count.
However, I'm not sure that simply settting chart.options.tootlip. will work dynamically the way you want.
I'm using Rickshaw to create a live-updating time series graph.
Here is the demo: http://abhshkdz.github.io/icuvisualanalytics/prototypes/rickshaw.html
The data is in csv format (time,value), and this is the core javascript for the visualization:
var count = 0, index=0;
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = window.innerWidth - margin.right - margin.left - 100,
height = window.innerHeight - margin.top - margin.bottom - 100;
var graph = new Rickshaw.Graph( {
element: document.querySelector("#chart"),
width: width,
height: height,
renderer: 'line',
min: -300,
max: 500,
preserve: true,
series: new Rickshaw.Series.FixedDuration(
[
{
name: 'ECG',
color: palette.color()
}
],
undefined,
{
timeInterval: 12.5,
maxDataPoints: 400,
timeBase: data[index][count].x
})
})
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
var y_axis = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis')
} );
var hoverDetail = new Rickshaw.Graph.HoverDetail( {
graph: graph
} );
graph.render();
setInterval(function () {
if (count == 2397) {
count = 0;
index++;
}
var d = {'ECG': data[index][count+=3].y};
graph.series.addData(d);
graph.render();
}, 12.5);
Now there is another set of data which is generated by an algorithm. That data is also in csv format (time,value). It basically finds the peaks of this plot. Using that data, I want to mark those points on this visualization itself.
As far as I looked, Rickshaw does not natively support multiple series using different renderers (either both have to be line or both scatter plots etc.).
So how should I go about this?
The multi renderer feature was added about a month ago. This example shows how to combine several renderers in one chart. The relevant code of the example:
var graph = new Rickshaw.Graph( {
element: document.getElementById("chart"),
renderer: 'multi',
width: 900,
height: 500,
dotSize: 2,
series: [
{
name: 'temperature',
data: seriesData.shift(),
color: 'rgba(255, 0, 0, 0.4)',
renderer: 'stack'
}, {
name: 'heat index',
data: seriesData.shift(),
color: 'rgba(255, 127, 0, 0.4)',
renderer: 'stack'
}, {
name: 'dewpoint',
data: seriesData.shift(),
color: 'rgba(127, 0, 0, 0.3)',
renderer: 'scatterplot'
}, {
name: 'pop',
data: seriesData.shift().map(function(d) { return { x: d.x, y: d.y / 4 } }),
color: 'rgba(0, 0, 127, 0.4)',
renderer: 'bar'
}, {
name: 'humidity',
data: seriesData.shift().map(function(d) { return { x: d.x, y: d.y * 1.5 } }),
renderer: 'line',
color: 'rgba(0, 0, 127, 0.25)'
}
]
});