Highcharts giving an extra legend when I get data dynamically from Highcharts - javascript

I need to create highcharts series dynamically...So I used addSeries,But I am gettng an extra legend. If you have any other methods pls let me know...
I am not including my total chart code....I am jst placing my series in chart...
$(function () {
chart = Highcharts.chart('container', {
series: [
{
}
]
});
});
json:
"dataa":
[
{
"name": "Unit Test 1",
"data":[1,13,15,17,40,50,80]
},
{
"name": "Unit Test 2",
"data":[2,20,50,40,20,50,15]
},
{
"name": "Unit Test 3",
"data":[3,50,40,10,30,40,25]
}
]
ajax:
let dataeDatal=datae.dataa.length;
for (let i = 0; i < dataeDatal; i++) {
chart.addSeries({
data: datae.dataa[i].data,
name: datae.dataa[i].name
});
}
}
You can check in the image, I am getting an extra series1 legend

you should initialize your charts as
chart = Highcharts.chart('container', {
series: [] //should be empty array
});
fiddle demo

Related

Decide which serie goes into range-selector highstock

I have a chart with 3 different series and I've included Range Selector from Highstock. I want to be able to select which one of the 3 series is the one set in the Range-Selector. Is there any way to dynamically assign the serie to the Range Selector?
I create the chart with 3 series like this:
//A,B,C data array
Highcharts.stockChart('container', {
series: [
{ data: A },
{ data: B },
{ data: C }
]
});
What I want to accomplish is to be able to select either A,B or C as the serie active to see in the Range-Selector preview.
Here's a jsfiddle: https://jsfiddle.net/usvonfjh/1/
You can show each series in navigator by setting series.line.showInNavigator = true. To set it dynamically use series.update() method where you can pass new options for series.
Code:
let dates = [1496268000000, 1504216800000, 1512082800000, 1519858800000, 1527804000000, 1535752800000, 1543618800000, 1551394800000, 1559340000000, 1567288800000];
let aSerie = dates.map((e, i) => [e, i < 5 ? null : i]);
let bSerie = dates.map((e, i) => [e, i + 1]);
let cSerie = dates.map((e, i) => [e, i * 2]);
Highcharts.stockChart('container', {
chart: {
events: {
load: function() {
const chart = this;
setTimeout(() => {
chart.series[1].update({
showInNavigator: false
});
}, 2000);
}
}
},
rangeSelector: {
verticalAlign: 'top'
},
series: [{
name: "aSerie",
showInNavigator: true,
data: aSerie
}, {
name: "bSerie",
showInNavigator: true,
data: bSerie
}, {
name: "cSerie",
showInNavigator: true,
data: cSerie
}]
});
Demo:
https://jsfiddle.net/BlackLabel/pxw09zrc/
API reference:
https://api.highcharts.com/highstock/series.line.showInNavigator
https://api.highcharts.com/class-reference/Highcharts.Series#update

Issue formatting data in JavaScript for a pie chart

I am not a JavaScript expert and I am trying to put a simple pie chart together using the data from a csv file. The sample code for the pie chart with its input data looks like below and it works perfectly.
var pie = new d3pie("pie", {
header: {
title: {
text: "A Very Simple Pie",
fontSize: 30
}
},
data: {
content: [
{ label: "JavaScript", value: 264131 },
{ label: "Ruby", value: 218812 },
{ label: "Java", value: 157618}
]
}
});
but when I try to use the data from the csv file. It says no data is provided. I obviously try to pass the dynamic data to the data.content but it seems like I am not doing it correctly. Below is my code:
var input_data = []
d3.csv("data.csv", function (data) {
input_data.push({
label: data["First"],
value: +data["Age"]
});
});
console.log(input_data); // This shows [{label: "james", value:30},{"John",value:22}]
var pie = new d3pie("pie", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: input_data
}
});
Any idea what I am doing wrong here?
As noted in my comment, your problem is because d3.csv acts asynchronously, and input_data isn't populated when d3pie tries to create your chart.
There is something highly suspicious going on with input_data in the other examples -- it should be called for every item in data, but seems only to be called once. Rather than using input_data to collate intermediate results, it's much easier to use javascript's map function to transform your csv data into the format you want:
d3.csv("data.csv", function (data) {
var pie = new d3pie("pie", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: data.map( function(d){
return { label: d['First'], value: +d['Age'] }
})
}
});
});
map iterates over an array and produces an array as output, so it's much cleaner and easier than creating extra arrays on to which you push data, etc.
You probably want to put your d3pie code inside your callback function because you want to call it after the data returns (see this example):
var input_data = []
d3.csv("data.csv", function (data) {
input_data.push({
label: data["First"],
value: +data["Age"]
});
console.log(input_data); // This shows [{label: "james", value:30},{"John",value:22}]
var pie = new d3pie("pie", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: input_data
}
});
});
const promise = d3.csv("data.csv", function (data) {
input_data.push({
'label': data["First"],
'value': +data["Age"]
});
});
promise.then(function(){
var pie = new d3pie("pieChart", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: input_data
}
});
});

Chart.js chart in vue.js component does not update

I´m developing a visualization module for some crypto portfolios with vue.js and chart.js but am currently stuck with this:
Empty chart is displayed but non of the values are rendered.
Since the values are dynamically loaded after the chart is initialized I believe that the chart is not updating itself properly (even though I call .update()), but no errors are displayed whatsoever.
I wrapped the chart.js rendering in a vue component:
Vue.component('portfolioValues', {
template: '<canvas width="400" height="200"></canvas>',
data: function() {
return {
portfolio_value: [],
portfolio_labels: [],
chart: null,
}
},
methods: {
load_portfolio_value_local: function() {
values = [];
labels = []
local_data.forEach(element => {
values.push(element.total_usd);
labels.push(moment(element.timestamp, 'X'));
});
this.portfolio_value = values;
this.portfolio_labels = labels;
this.chart.update();
},
render_chart: function() {
this.chart = new Chart(this.$el, {
type: 'line',
data: {
labels: this.portfolio_labels,
datasets: [{
label: "Portfolio Value",
data: this.portfolio_value,
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
distribution: 'linear',
}]
}
}
});
}
},
mounted: function() {
this.render_chart();
this.load_portfolio_value_local();
}
});
For demonstration purposes I just added some data locally, looks like this:
local_data = [{
"timestamp": 1515102737,
"total_btc": 0.102627448096786,
"total_usd": 1539.41274772627
}, {
"timestamp": 1515102871,
"total_btc": 0.102636926127186,
"total_usd": 1538.52649627725
}, {
"timestamp": 1515103588,
"total_btc": 0.102627448096786,
"total_usd": 1532.33042753311
}
]
Here is the full demo code: https://codepen.io/perelin/pen/mppbxV
Any ideas why no data gets rendered? thx!
The problem you have here is how vuejs handles its data.
If you use it like that:
local_data.forEach(element => {
this.portfolio_value.push(element.total_usd);
this.portfolio_labels.push(moment(element.timestamp, 'X'));
});
this.chart.update();
The chart will update. But by re-initializing the arrays you work against vuejs.
TL;DR
If you want to re-initialize an object, you could assign the array to the object:
Object.assign(this.portfolio_value, values);
Object.assign(this.portfolio_labels, labels);
That way, the linking stays working.

How to change randomised data used for graph values with my input data? D3js donut graph

I am fairly new to coding and I need to use d3js library to make graphs. While I get the basics, I don't yet comprehend the whole thing...
So, I found this graph in D3js examples that i want to use. but don't know how to change data showing in graph. I want donut chart to have my input data instead of randomised data as it is shown in example
http://bl.ocks.org/dbuezas/9306799
This is a graph I want to use.
the key function is change(), just replace randomData() to getYourData()
function getYourData() {
let yourData = [
{
label: 'label1',
value: 12,
},
{
label: 'label2',
value: 6,
}
]
return yourData;
}
change(getYourData());
Hopefully you can understand this syntax more easily
change([ { label: "Label 1", value: 10 },
{ label: "Label 2", value: 20 },
{ label: "Label 3", value: 30 } ])
The function change takes an array of objects, each object is a segment of the pie graph.

Dynamically create multi leveled drilldowns in Amcharts

I need to create a multi leveled that is dynamic because I have to drill down to hundreds or even thousands of data providers that will load from the database. The flow goes like this: I have 1, 2, 3, 4, and 5 years that will drill down to 16 Departments each and will drill down to Courses 10 or more courses. Doing it manually is tedious and I need it to be dynamic. Please help me.
The variables:
var ccs_final_data = AmCharts.loadJSON("<?php echo base_url();?>index.php/osa/final_ccs_data");
//VAR CCS AVERAGE_FINAL
var drill_down_to_ccs_courses_average_final = AmCharts.loadJSON("<?php echo base_url();?>index.php/osa/ccs_courses_data_average_final");
var drill_down_to_ccs_sections_BSIT_average_final = AmCharts.loadJSON("<?php echo base_url();?>index.php/osa/ccs_sections_data_BSIT_average_final");
var drill_down_to_ccs_sections_ACT_average_final = AmCharts.loadJSON("<?php echo base_url();?>index.php/osa/ccs_sections_data_ACT_average_final");
var drill_down_to_ccs_sections_BSCS_average_final = AmCharts.loadJSON("<?php echo base_url();?>index.php/osa/ccs_sections_data_BSCS_average_final");
The graph:
var chart2 = AmCharts.makeChart( "ccs2", {
"theme": "light",
type: "serial",
pathToImages: "http://cdn.amcharts.com/lib/3/images/",
dataProvider: ccs_final_data,
categoryField: "category",
categoryAxis: {
labelRotation: 0,
gridPosition: "start"
},
valueAxes: [ {
title: "CCS FINAL TERM - Passing"
} ],
graphs: [ {
valueField: "value",
colorField: "color",
type: "column",
lineAlpha: 100,
fillAlphas: 1
} ],
chartScrollbar: {
"updateOnReleaseOnly": true
},
chartCursor: {
bulletsEnabled: "enabled",
bulletSize: 15,
cursorAlpha: 100,
cursorColor: "#CC0000",
zoomable: true,
categoryBalloonEnabled: true
},
export: {
enabled: true
}
} );
Here's the drill down stuff:
chart2.addListener("clickGraphItem", function (event) {
if(event.item.category == "Average"){
event.chart.dataProvider = drill_down_to_ccs_courses_average_final;
event.chart.validateData();
chart2.addListener("clickGraphItem", function (event) {
if(event.item.category == "BSIT"){
event.chart.dataProvider = drill_down_to_ccs_sections_BSIT_average_final;
event.chart.validateData();
}
else if(event.item.category == "ACT"){
event.chart.dataProvider = drill_down_to_ccs_sections_ACT_average_final;
event.chart.validateData();
}
else if(event.item.category == "BSCS"){
event.chart.dataProvider = drill_down_to_ccs_sections_BSCS_average_final;
event.chart.validateData();
}
});
}
I'd say the best way to make it dynamic is to include some custom field for each data point in your data that would be passed in to server-side script so it knows which data to load.
I'm assuming your data looks like this now:
[ {
"category": "BSIT",
"value": 100
}, {
"category": "ACT",
"value": 200
}, {
"category": "BSCS",
"value": 150
} ]
You could easily add a third field to hold the information for drill-down data load:
[ {
"category": "BSIT",
"value": 100,
"drill": "ccs_sections_data_BSIT_average_final"
}, {
"category": "ACT",
"value": 200,
"drill": "ccs_sections_data_ACT_average_final"
}, {
"category": "BSCS",
"value": 150,
"drill": "ccs_sections_data_BSCS_average_final"
} ]
Then, when clickGraphItem event occurs, you could just take that info and pass it to load script dynamically:
chart2.addListener( "clickGraphItem", function( event ) {
if ( event.item.dataContext.drill !== undefined ) {
event.chart.dataProvider = AmCharts.loadJSON( "<?php echo base_url();?>index.php/osa/" + event.item.dataContext.drill );
event.chart.validateData();
}
} );
This way, you could have any number of drill-down levels, with each level data containing info about where to look for the data for the next level.
Also, I'm not sure as you haven't posted the code for it, so I'm assuming that AmCharts.loadJSON method is synchronous. If it's not (for example if you are using method from Data Loader), you will need to assign the chart's dataProvider after the data is loaded.

Categories