I need to createa multi line highstock type of chart:
My test.json file looks like this:
[{"name":"serverA","data":[[1372737609,2.6075],[1372737906,2.6533],[1372738205,2.7834],[1372738526,3.6527],[1372738802,0.6352],[1372739093,0.6073]]},{"name":"serverB","data":[[1372737602,36.3042],[1372737929,16.1145],[1372738218,6.4503],[1372738503,23.8908],[1372738803,3.9025],[1372739079,10.8216],[1372739371,3.1338]]},{"name":"serverC","data":[[1372737600,3.9025],[1372737908,13.8542],[1372738184,10.9094],[1372738491,14.6655],[1372738777,80.7615],[1372739081,6.9777],[1372739383,10.0971]]}]
This is my script:
(function() {
var seriesOptions = [],
yAxisOptions = [],
colors = Highcharts.getOptions().colors;
$.getJSON('test.txt', function(data) {
alert(data);
seriesOptions: data
createChart();
});
// create the chart when all data is loaded
function createChart() {
$('#container').highcharts('StockChart', {
chart: {
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function() {
return (this.value > 0 ? '+' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2
},
series: seriesOptions
});
}
});
I get this error:
Uncaught TypeError: undefined is not a function
any ideas what I am doing wrong here?
Change from: seriesOptions: data to seriesOptions = data;
Related
I'm trying to change the Highstock names. names = ['MSFT', 'AAPL', 'GOOG']; To names = ['ONE', 'TWO', 'THREE']; I want to change the names by any names. Please Help.
<script type="text/javascript">
var seriesOptions = [],
seriesCounter = 0,
names = ['ONE', 'TWO', 'THREE'];
/**
* Create the chart when all data is loaded
*/
function createChart() {
Highcharts.stockChart('container', {
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent',
showInNavigator: true
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
series: seriesOptions
});
}
$.each(names, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
seriesOptions[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter += 1;
if (seriesCounter === names.length) {
createChart();
}
});
});
</script>
But when i change these names Chart does not load. Any kind of Help Apreciated. How can i change these names please help. Thanks
Original Code.
<div id="container" style="height: 400px; min-width: 310px; margin-bottom:20px;"></div>
<script type="text/javascript">
var seriesOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'];
/**
* Create the chart when all data is loaded
*/
function createChart() {
Highcharts.stockChart('container', {
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent',
showInNavigator: true
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
series: seriesOptions
});
}
$.each(names, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
seriesOptions[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter += 1;
if (seriesCounter === names.length) {
createChart();
}
});
});
</script>
The chart is being populated with values from the line:
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
where name.tolowercase() takes the value of the names variable
names = ['MSFT', 'AAPL', 'GOOG'];
and fetches content from the file:
https://www.highcharts.com/samples/data/jsonp.php?filename=msft-c.json&callback=?
https://www.highcharts.com/samples/data/jsonp.php?filename=aapl-c.json&callback=?
https://www.highcharts.com/samples/data/jsonp.php?filename=goog-c.json&callback=?
So when you replace with
names = ['ONE', 'TWO', 'THREE'];
it does not find corresponding files on the server
https://www.highcharts.com/samples/data/jsonp.php?filename=one-c.json&callback=?
Hope it helps :).
The files will need to be placed on the server with relevant data for the charts to load.
You get an error when you want to get a JSON response for the files 'one', 'two' and 'three', for that reason the chart doesn't load.
To handle that exception I suggest you to use the jQuery's Ajax methods .fail() and .always() like this.
If you see my example, the chart loads, even without data.
Not sure why because I have done it in the past, but I have a Highcharts bar chart and it won't animate. This is the declaration of the chart,
function initializeData() {
$http.get(url).success(function(ret) {
$scope.jsondata = ret;
var newdata = [];
for (x = 0; x < 5; x++) {
newdata.push({
name: setName($scope.jsondata[x].name),
y: $scope.jsondata[x].data[0],
color: getColor($scope.jsondata[x].data[0])
});
}
$scope.chart.series[0].setData(newdata);
});
mainInterval = $interval(updateData, 5000);
}
function updateData() {
$http.get(url).success(function(ret) {
$scope.jsondata = ret;
console.debug("here");
for (x = 0; x < 5; x++) {
$scope.chart.series[0].data[x].update({
y: $scope.jsondata[x].data[0],
color: getColor($scope.jsondata[x].data[0])
});
}
});
}
$scope.chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'bar',
animation: true,
events: {
load: initializeData
}
},
title: {
text: ''
},
xAxis: {
type: 'category',
labels: {
style: {
fontSize: '11px'
}
}
},
yAxis: {
min: 0,
max: 100,
title: {
text: 'Total Score',
align: 'high'
}
},
legend: {
enabled: false
},
tooltip: {
pointFormat: 'Total Score <b>{point.y:.3f}</b>'
},
series: [{
name: 'Active Users',
data: [],
dataLabels: {
enabled: true,
rotation: 30,
style: {
fontSize: '10px',
fontFamily: 'Verdana, sans-serif'
},
format: '{point.y:.3f}', // one decimal
}
}]
});
And as you can see I have animate : true, so I am not sure what is the problem here. I have this older plunker where all of the data is in separate series, but it animates fine. But this is the plunker I am working on and having trouble with. They are like identical basically. In the newer one I broke out the initialization of data into its own method, but that is the only real main difference.
Some edits:
So as I was saying, I have done things this way with an areaspline chart (I know it was said they work a bit different but they are set up identically).
function initializeData() {
$interval.cancel(mainInterval);
$scope.previousPackets = '';
$http.get("https://api.myjson.com/bins/nodx").success(function(returnedData) {
var newdata = [];
var x = (new Date()).getTime();
for (var step = 9; step >= 0; step--) {
newdata.push([x - 1000 * step, 0]);
}
$scope.chart.series[0].setData(newdata);
});
mainInterval = $interval(updateData, 2000);
}
function updateData() {
$http.get(url + acronym + '/latest').success(function(returnedData) {
var x = (new Date()).getTime();
if ($scope.previousPackets != returnedData[0].numPackets) {
$scope.chart.series[0].addPoint([x, returnedData[0].numPackets], true, true);
$scope.previousPackets = returnedData[0].numPackets;
} else {
$scope.chart.series[0].addPoint([x, 0], true, true);
}
});
}
$scope.chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'areaspline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: initializeData
}
},
title: {
text: ''
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Packets'
},
plotLines: [{
value: 0,
width: 1,
color: '#d9534f'
}]
},
tooltip: {
formatter: function() {
return Highcharts.numberFormat(this.y) + ' packets<b> | </b>' + Highcharts.dateFormat('%H:%M:%S', this.x);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Packets',
data: []
}]
});
I also updated the first chunk of code with the initializeData() method and updateData() method which are seemingly identical in both different charts.
It looks like it plays an important role if you provide your data at chart initialization or after. For simplicity I refactored your code a little
function initializeChart(initialData, onload) {
$scope.chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'bar',
animation: true,
events: {
load: onload
}
....
series: [{
name: 'Active Users',
data: initialData,
dataLabels: {
enabled: true,
format: '{point.y:.3f}', // one decimal
}
}]
});
}
function getData(callback) {
$http.get(url).success(function(ret) {
$scope.jsondata = ret;
var newdata = [];
for (x = 0; x < 5; x++) {
newdata.push([setName(ret[x].name), ret[x].data]);
}
callback(newdata);
});
}
As a result your two planks are in essense reduced to two methods below. The first initializes chart with preloaded data and the second updates data in existing chart.
function readDataFirst() {
getData(function(newdata) {
initializeChart(newdata);
});
}
function initializeChartFirst() {
initializeChart([], function() {
getData(function(newdata) {
$scope.chart.series[0].setData(newdata);
})
});
}
The first one animates fine while the second does not. It looks like highcharts skips animation if dataset is not initial and is treated incompatible.
However if you really want to have animation in your current plant (chart first workflow) you can achieve that by initializing first serie with zeros and then with the real data. This case it will be treated as update
function forceAnimationByDoubleInitialization() {
getData(function(newdata) {
initializeChart([]);
var zerodata = newdata.map(function(item) {
return [item[0], 0]
});
$scope.chart.series[0].setData(zerodata);
$scope.chart.series[0].setData(newdata);
});
All these options are available at http://plnkr.co/edit/pZhBJoV7PmjDNRNOj2Uc
im using HighStock multiple series: http://www.highcharts.com/stock/demo/compare
The problem is that my application gives me this data format:
[data1],
[data2],
and HighStock is expecting this:
[
[data1],
[data2],
]
My JS for loading data is:
$(function () {
var seriesOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'],
// create the chart when all data is loaded
createChart = function () {
$('#graph1').highcharts('StockChart', {
legend: {
enabled: true,
align: 'center',
verticalAlign: 'bottom',
},
credits:{
enabled: false
},
title: {
text: 'Bitcoin Exchanges'
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2
},
series: seriesOptions
});
};
$.each(names, function (i, name) {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
seriesOptions[i] = {
name: name,
data: data
};
seriesCounter += 1;
if (seriesCounter === names.length) {
createChart();
}
});
});
});
How can I push that data to an parent array so the library can consume it?
Thanks in advance.
The chart calls in JSON file that hold a string(color) and integer(count). I want to change the color of the each slice in a pie chart according to what the JSON file holds. So if the JSON file is [["Green",1],["Red",44],["Yellow",30]] I would like the the "Green" slice to have the color of green...etc. I've tried:
plotOptions: {
pie: {
//colors: ['#739600', '#bb0826', '#fcc60A'],
formatter: function () {
if ('Green' === this.value) {
return '<span style="fill: #739600;">' + this.value + '</span>';
}
else if ('Red' === this.value) {
return '<span style="fill: #bb0826;">' + this.value + '</span>';
}
else if ('Yellow' === this.value) {
return '<span style="fill: #fcc60A;">' + this.value + '</span>';
}
}, ...
It's not working how I expected. http://jsfiddle.net/LazerickL/bvaxmcLr/4/
Any help would be appreciated.
UPDATE
I had to restructure my JavaScript to call $.getJSON function. So, how would I proceed to implement the color slices for my latest code below? Thanks for any help!
$(document).ready(function() {
var options = {
chart: {
renderTo: 'containter',
defaultSeriesType: 'pie',
options3d: {
enabled: true,
alpha: 45
}
},
title: {
text: null
},
credits: {
enabled: false
},
tooltip: {
pointFormat:
'{series.name}: <b>{point.y}</b>'
},
plotOptions: {
pie: {
//colors: ['#739600', '#bb0826', '#fcc60A'],
allowPointSelect: true,
cursor: 'pointer',
depth: 30,
showInLegend: true,
dataLabels: {
enabled: true,
color: '#000000',
connectorColor: '#000000',
formatter: function () {
return '<b>' + this.point.name + '</b>: ' + this.point.y;
}
}
}
},
series: [{
type: 'pie',
name: 'Amount',
data: []
}]
}
$.getJSON("js/test.json", function (json) {
options.series[0].data = json;
var chart = new Highcharts.Chart(options);
});
});
To set your colors on your pies you'll need to update how you're pushing things into the data array to include the color of your pie. I accomplish this by adding a field to your data array but you could use an if statement like you had in the function if you prefer.
Here is an updated fiddle: http://jsfiddle.net/bvaxmcLr/8/
Also, your placement of the formatter function is invalid. That formatter javascript only applies to data labels as far as I know.
The important change from your script is removing the formatter function and updating to this to push the color value onto each data point:
var data={'d':[
{'Status_Color':'Green', 'Corrective_Action_ID':3},
{'Status_Color':'Red', 'Corrective_Action_ID':5},
{'Status_Color':'Yellow', 'Corrective_Action_ID':10},
]};
$.each(data.d, function (key, value) {
var colorVal = '';
if(value.Status_Color=='Green'){
colorVal = '#739600';
}
if(value.Status_Color=='Red'){
colorVal = '#bb0826';
}
if(value.Status_Color=='Yellow'){
colorVal = '#fcc60A';
}
var temp = {name:value.Status_Color, color:colorVal, y:value.Corrective_Action_ID};
options.series[0].data.push(temp);
})
Here is the whole script:
$(function () {
$(document).ready(function () {
var options = {
chart: {
renderTo: 'container',
type: 'pie',
options3d: {
enabled: true,
alpha: 45
}
},
title: {
text: null
},
subtitle: {
text: null
},
credits: {
enabled: false
},
tooltip: {
pointFormat: '{series.name}: <b>{point.y:.1f}</b>'
},
plotOptions: {
pie: {
depth: 45,
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
},
series: [{
type: 'pie',
name: 'Amount',
data: []
}]
}
var data={'d':[
{'Status_Color':'Green', 'Corrective_Action_ID':3},
{'Status_Color':'Red', 'Corrective_Action_ID':5},
{'Status_Color':'Yellow', 'Corrective_Action_ID':10},
]};
$.each(data.d, function (key, value) {
var colorVal = '';
if(value.Status_Color=='Green'){
colorVal = '#739600';
}
if(value.Status_Color=='Red'){
colorVal = '#bb0826';
}
if(value.Status_Color=='Yellow'){
colorVal = '#fcc60A';
}
var temp = {name:value.Status_Color, color:colorVal, y:value.Corrective_Action_ID};
options.series[0].data.push(temp);
})
chart = new Highcharts.Chart(options);
});
});
Is it possible to have Highcharts drilldown on multiple graphs that are sharing the same data when one graph is clicked?
As an example, I included a JSFiddle that uses the demo code (browser percentages).
http://jsfiddle.net/Pq6gb/
var gridster;
$(function(){
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [150, 150],
widget_margins: [5, 5],
helper: 'clone',
resize: {
enabled: true,
stop: function(e, ui, $widget) {
for (var i = 0; i < Highcharts.charts.length; i++) {
Highcharts.charts[i].reflow();
}
}
}
}).data('gridster');
});
$(function () {
Highcharts.data({
csv: document.getElementById('tsv').innerHTML,
itemDelimiter: '\t',
parsed: function (columns) {
var brands = {},
brandsData = [],
versions = {},
drilldownSeries = [];
// Parse percentage strings
columns[1] = $.map(columns[1], function (value) {
if (value.indexOf('%') === value.length - 1) {
value = parseFloat(value);
}
return value;
});
$.each(columns[0], function (i, name) {
var brand,
version;
if (i > 0) {
// Remove special edition notes
name = name.split(' -')[0];
// Split into brand and version
version = name.match(/([0-9]+[\.0-9x]*)/);
if (version) {
version = version[0];
}
brand = name.replace(version, '');
// Create the main data
if (!brands[brand]) {
brands[brand] = columns[1][i];
} else {
brands[brand] += columns[1][i];
}
// Create the version data
if (version !== null) {
if (!versions[brand]) {
versions[brand] = [];
}
versions[brand].push(['v' + version, columns[1][i]]);
}
}
});
$.each(brands, function (name, y) {
brandsData.push({
name: name,
y: y,
drilldown: versions[name] ? name : null
});
});
$.each(versions, function (key, value) {
drilldownSeries.push({
name: key,
id: key,
data: value
});
});
// Create the chart
$('#container').highcharts({
chart: {
type: 'pie'
},
title: {
text: 'Browser market shares. November, 2013.'
},
subtitle: {
text: 'Click the slices to view versions. Source: netmarketshare.com.'
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
format: '{point.name}: {point.y:.1f}%'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: 'Brands',
colorByPoint: true,
data: brandsData
}],
drilldown: {
series: drilldownSeries
}
})
}
});
});
$(function () {
Highcharts.data({
csv: document.getElementById('tsv').innerHTML,
itemDelimiter: '\t',
parsed: function (columns) {
var brands = {},
brandsData = [],
versions = {},
drilldownSeries = [];
// Parse percentage strings
columns[1] = $.map(columns[1], function (value) {
if (value.indexOf('%') === value.length - 1) {
value = parseFloat(value);
}
return value;
});
$.each(columns[0], function (i, name) {
var brand,
version;
if (i > 0) {
// Remove special edition notes
name = name.split(' -')[0];
// Split into brand and version
version = name.match(/([0-9]+[\.0-9x]*)/);
if (version) {
version = version[0];
}
brand = name.replace(version, '');
// Create the main data
if (!brands[brand]) {
brands[brand] = columns[1][i];
} else {
brands[brand] += columns[1][i];
}
// Create the version data
if (version !== null) {
if (!versions[brand]) {
versions[brand] = [];
}
versions[brand].push(['v' + version, columns[1][i]]);
}
}
});
$.each(brands, function (name, y) {
brandsData.push({
name: name,
y: y,
drilldown: versions[name] ? name : null
});
});
$.each(versions, function (key, value) {
drilldownSeries.push({
name: key,
id: key,
data: value
});
});
// Create the chart
$('#container2').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Browser market shares. November, 2013'
},
subtitle: {
text: 'Click the columns to view versions. Source: netmarketshare.com.'
},
xAxis: {
type: 'category'
},
yAxis: {
title: {
text: 'Total percent market share'
}
},
legend: {
enabled: false
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: 'Brands',
colorByPoint: true,
data: brandsData
}],
drilldown: {
series: drilldownSeries
}
})
}
});
});
There is a pie chart and a bar chart displaying the same data and can drilldown individually. I would like to click on any browser in the pie/bar chart and have both charts filter down to versions of that browser.
How would I go about doing this? Thanks.
Yes, it's possible. This is what you need to implement:
on drilldown event you can find respective point on a second chart and simple call 1point.doDrilldown()1
on drillup even in one chart, call on a second chart.drillUp()
Note: You need to be aware of infinite loop (for example drillUp() in one chart will call drillup event, which will drillUp() first chart again.. ) - just add some flag to call drillUp/doDrilldown only once per user click.