let's say I am generating chart json that might look something like this:
return jsonify({
chart: {
post_url: '/some/url/'
type: column
},
title: {
text: this is a chart
},
tooltip: {
shared: true
},
xAxis: {
categories: [x[0].strftime('%b %y') for x in arr]
},
plotOptions: {
column: {
stacking: normal
}
}
series: [{
data: [[x.thing for x in month].count(True) for month in arr]
}, {
data: [[x.thing for x in month].count(False) for month in arr]
}]
})
In setOptions, I do the following.
Highcharts.setOptions({
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function(el) {
$.post(this.chart.post_url + this.category, function(data) {
console.log(data);
});
}
}
}
}
}
});
However, this does not allow me to click and go to the post url, saying post_url is not defined. So I imagine that data is lost when the chart is rendered.
What's a way around this?
The this in a point.events.click referres to a point object and not a chart object. You can walk backwards to the chart configuration using this.series.chart.userOptions.chart.post_url like so:
point: {
events: {
click: function() {
alert(this.series.chart.userOptions.chart.post_url);
}
}
}
Here's an example fiddle.
If I understand correctly you want to have the series.points go to a URL when you click on them? You are missing an ending comma after your post_url definition and quotes around the type value. That being said I would set the URL in the series options and not the chart options. Then you might need to set it like:
series: [{
post_url: '/some/url/',
data: [[x.thing for x in month].count(True) for month in arr]
}, {
post_url: '/some/url/',
data: [[x.thing for x in month].count(False) for month in arr]
}]
Then in the click event:
events: {
click: function(el) {
$.post(this.post_url + this.category, function(data) {
console.log(data);
});
}
Demo.
If you still want to use the chart.post_url method you need to fix your typos. Demo.
Related
I have two JSON end points. I am trying to plot a Highcharts bar graph with drilldown. The drilldown will point to another JSON endpoint. In the graph data is coming dynamically from end points.
JSON 1 :- https://api.myjson.com/bins/156yh3
JSON 1 Structure :-
[{
"name": "cricket",
"number": "2"
}]
It will first plot the graph with JSON 1 Data. In the first graph, X-Axis represents "name" and Y-Axis represents "number". Whenever we click on any bar then it will call the JSON 2 endpoint and pass the clicked bar "name" as URL parameter.
JSON 2 end point looks like, api.domain.com/{{name}}//
if we click on "orange" bar then request url will change to api.domain.com/cricket/
JSON 2 Structure :-
[{
"player": "xyz",
"points": "2"
}]
In the second graph, X-Axis represents "player" and Y-Axis represents "points". I think, I have to call a Ajax request in drilldown when a bar is clicked. I can plot the first graph but what is the recommended way to plot the second graph, which will come in drill down.
Code for graph 1 :-
$(function() {
$.getJSON("https://api.myjson.com/bins/156yh3", function(data) {
console.log(data);
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Name Vs Numbers'
},
subtitle: {
text: 'Chart View Here'
},
xAxis: {
type: 'category',
categories: data.map(function(x) {
return x.name;
})
},
yAxis: {
title: {
text: 'Numbers'
}
},
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: [{
colorByPoint: true,
data: data.map(function(x) {
return x.number * 1;
})
}]
});
});
});
HTML :-
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto;"></div>
Refer to this live demo: http://jsfiddle.net/kkulig/1o4mr6jk/
It always adds a new drilldown series (with randomly generated data from the API) on point click event and performs drilldown.
In callback for series.point.events.click I used addSeriesAsDrilldown:
plotOptions: {
series: {
point: {
events: {
click: function(e) {
var point = this,
chart = point.series.chart;
$.getJSON('https://canvasjs.com/services/data/datapoints.php?xstart=1&ystart=10&length=10&type=json&callback=?', function(data) {
chart.addSeriesAsDrilldown(point, {
data: data
});
});
}
}
}
}
},
You can use the value of point.name to construct your URL.
It seems that there's some issue with the core code - it throws an error on drillup (you can check that by commenting out everything before var chart = Highcharts.chart('container', {). this.ddDupes in H.Chart.prototype.drillUp function is undefined so its length property cannot be accessed. I modified the core code by changing the following piece of code:
this.ddDupes.length = []; // #3315
to this:
if (this.ddDupes) {
this.ddDupes.length = []; // #3315
}
and everything works fine.
EDIT
I found a better solution. It's based on the official Highcharts demo referred in the API record for chart.events.drilldown: https://api.highcharts.com/highcharts/chart.events.drilldown
Live demo: http://jsfiddle.net/kkulig/u1z5z40b/
var chart = Highcharts.chart('container', {
chart: {
type: 'column',
events: {
drilldown: function(e) {
var chart = this;
$.getJSON('https://canvasjs.com/services/data/datapoints.php?xstart=1&ystart=10&length=10&type=json&callback=?', function(data) {
chart.addSeriesAsDrilldown(e.point, {
data: data
});
});
}
}
},
series: [{
data: [{
name: 'John',
y: 1,
drilldown: true
}, 2],
}]
});
drilldown: true indicates that the drilldown event should happen even though there's no drilldown series explicitly assigned to the point yet.
I have this fiddle JSfiddle
Here is the reproduced code:
$(function () {
$('#container').highcharts({
chart: {
type: 'bar'
},
xAxis: {
categories: ['Heroku', 'Ruby','Lisp','Javascript','Python','PHP']
},
yAxis: {
categories: ['low','medium','high'],
title: {
text: 'expertise',
align: 'high'
},
labels: {
overflow: 'justify'
}
},
tooltip: {
valueSuffix: ' millions'
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
}
}
},
series: [{
data: ['low','high','low','medium','medium']
}]
});
});
If you look at the fiddle the yAxis does not render and has a value of for every x category. I've been looking at the highcharts api, but I can't seem to get this right. The code makes sense to me but I'm obviously doing something wrong. Can someone point out why the YAxis is not displaying correctly?
As mentioned in my comment, you need to supply the numeric value of the category, not the category name.
In the case of categories, the numeric value is the array index.
Also, in your case, the way you are trying to plot the values, I would add an empty category at the beginning, otherwise your first category of low gets plotted as 0, which doesn't seem right.
So,
categories: ['low','medium','high']
Becomes
categories: ['','low','medium','high'],
And
data: ['low','high','low','medium','medium']
Becomes
data: [1,3,1,2,2]
Updated fiddle:
http://jsfiddle.net/jlbriggs/k64boexd/3/
Check this fiddle:
http://jsfiddle.net/navjot227/k64boexd/2/
Trick is to utilize the formatter function. You can use a similar formatter function on y-axis labels too if that's desired. Though it seems like you need it for data labels for this problem.
$(function() {
$('#container').highcharts({
chart: {
type: 'bar'
},
xAxis: {
categories: ['Heroku', 'Ruby', 'Lisp', 'Javascript', 'Python', 'PHP']
},
yAxis: {
title: {
text: 'expertise',
align: 'high'
},
labels: {
overflow: 'justify',
}
},
tooltip: {
valueSuffix: ' millions'
},
plotOptions: {
bar: {
dataLabels: {
enabled: true,
formatter: function() {
if (this.y == 0) {
return 'low'
} else if (this.y == 1) {
return 'medium'
} else {
console.log(this.y);
return 'high'
}
}
}
}
},
series: [{
data: [0, 2, 0, 1, 1]
}]
});
});
In my opinion, it is kinda unlikely for a line graph to have a y-axis category, since it speaks more of amount or value. In your case, "low, medium, and high" speaks of ranges, with which a certain value can be assigned to any of it.
Thus, Highcharts accepts series data in numeric form. But you can work around it by setting ['low', 'medium', 'high'] in the category attribute of yAxis, then setting series data as an array of number corresponding to the index of the category, i.e. [0,1,1,2,...] and tweaking the tooltip to display the category instead of the y value using formatter attribute.
Here is the code:
$(function() {
yCategories = ['low', 'medium', 'high'];
$('#container').highcharts({
title: {
text: 'Chart with category axes'
},
xAxis: {
categories: ['Heroku', 'Ruby','Lisp','Javascript','Python','PHP']
},
yAxis: {
categories: yCategories
},
tooltip: {
formatter: function() {
return this.point.category + ': ' + yCategories[this.y];
}
},
series: [{
data: [0, 1, 2, 2, 1]
}]
});
});
Here is a working example : JSFiddle
I am trying to update the series data option for 'pie' type chart:
I am using exporting buttons to display options to change chart type, all other chart types work well except pie which needs a different format of series data.
exporting: {
buttons: {
lineButton: {
text: 'line',
onclick: function () {
for(i=0;i<this.series.length;i++) {
this.series[i].update({
type: "line"
});
}
}
},
barButton: {
text: 'bar',
onclick: function () {
for(i=0;i<this.series.length;i++) {
this.series[i].update({
type: "column"
});
}
}
},
pieButton: {
text: 'pie',
onclick: function () {
var pieSeries = [];
$.each(category_totals, function(j, k) {
pieSeries.push( { name: j , y: k } );
});
for(i=0;i<this.series.length;i++) {
this.series[i].remove();
}
this.series = [{
name: title,
colorByPoint: true,
data: pieSeries
}];
this.series[0].update({
type: "pie"
});
}
}
}
...
And I get this error: Uncaught TypeError: this.series[0].update is not a function
The problem is that you sequentially remove the series from the chart, after each call the chart is redrawn and by the end of the for loop the chart doesn't have any series. When you do
this.series = [{
name: title,
colorByPoint: true,
data: pieSeries
}]
you are modifying the javascript object and therefore update method is not available when you try to do
this.series[0].update({
type: "pie"
});
because you are trying to call Highcharts method on a generic javascript object.
What you should do is
this.addSeries({
name: title,
colorByPoint: true,
data: pieSeries,
type: 'pie'
})
Also, a suggestion: pass argument false to remove method so that it it doesn't redraw every time. Just redraw when you add the new series.
So above call would look like
this.addSeries({
name: title,
colorByPoint: true,
data: pieSeries,
type: 'pie'
}, true)
1.
for(i=0;i<this.series.length;i++) {
this.series[i].remove();
}
The code above will not remove series items: see here
2.
The correct way to add series is:
this.addSeries({...});
3.
Final working code:
...
pieButton: {
text: 'pie',
onclick: function () {
var pieSeries = [];
$.each(category_totals, function(j, k) {
pieSeries.push( { name: j , y: k } );
});
while(this.series.length > 0) {
this.series[0].remove(true);
}
this.addSeries({
name: title,
colorByPoint: true,
data: pieSeries,
type: 'pie'
});
// As Rahul Sharma pointed out in comments above,
// you can pass the "type" option to
// addSeries method, making this call redundant
// this.series[0].update({
// type: "pie"
// });
}
}
...
Here is my code:
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
tooltip: {
shared: true
},
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function() {
alert("column index: " + this.series.columnIndex);
}
}
}
}
},
series: [{
name: 'Tokyo',
data: [216.4, 194.1]
}, {
name: 'New York',
data: [91.2, 83.5]
}, {
name: 'London',
data: [52.4, 65.2]
}, {
name: 'Berlin',
data: [47.6, 39.1]
}]
});
});
Here is fiddle: http://jsfiddle.net/a9mp9vhj/1/
Click on the top of the first column and you will see the message: "column index: 0" which is correct. Click on the middle or bottom of the first column and you will see other indeces.
if you set tooltip to be not shared everything starts working.
Is it Highcharts bug? How to get the correct column index with shared columns?
It almost seems like Highcharts isn't taking the x-value of the click into account, and only looks at the y-value of your click location (you can get every index if you click in the "correct" height).
It seems that the event.target.point is correct, while event.point (or this) is not. An example of how this workaround can be used to get the correct columnIndex as Highcharts is currently working (JSFiddle example):
plotOptions: {
series: {
point: {
events: {
click: function(event) {
alert("column index: " + event.target.point.series.columnIndex);
}
}
}
}
}
I have some difficulties displaying a graph with Highstock. It seems like I can't have access to the x-axis part where the graph should be displayed. I am new with Highstocks so my code could seem like a mess but my idea was the following:
First access the json file from the server. Convert it in the right format [[datestamp, value], ....]. Then display the graph.
Here is my Json file (file.json):
[{"date":"2013-10-04T22:31:12.000Z","value":30000},{"date":"2013-10-04T22:31:58.000Z","value":35000},{"date":"2013-10-04T22:32:05.000Z","value":60000},{"date":"2013-10-04T22:32:12.000Z","value":45000}]
My code is the following:
$(function() {
chartOjb = new Object();
var mydata = [];
$.getJSON('file.json', function(data) {
$.each(data, function (index, item) {
chartOjb.name = getTimestamp(item.date);
chartOjb.data = item.value;
mydata.push({ x: chartOjb.name, y: parseFloat(chartOjb.data) });
});
$('#container').highcharts('StockChart', {
chart: {
type: 'candlestick',
zoomType: 'x'
},
navigator: {
adaptToUpdatedData: false,
series: {
data: mydata
}
},
scrollbar: {
liveRedraw: false
},
xAxis: {
type: 'datetime',
title: 'Time',
//minRange: 3600 * 1000/15 // one hour
},
rangeSelector : {
selected : 1
},
title : {
text : value
},
series : [{
name : 'Capacité',
data : data,
tooltip: {
valueDecimals: 2
}
}] }); });
});
Thank you very much for your help
Could you add your function getTimestamp()? Maybe there is something wrong.
Keep in mind that:
x-value should be timestamp,
when using a lot of objects { x: x, y: y }, set turboThreshold