I have a simple React component which is supposed to render two Highcharts using the highcharts-react library. The data for the charts comes from a parent component's state and is passed to this component as a prop. When the page loads, the pie chart is empty (eg there's just an empty circle with no series). If I inspect the HighchartsReact element using the React element inspector, I can see that the correct data is in the options prop. Also, if I manually alter any of the data in the inspector, the chart suddenly shows up. My guess is that it has something to do with the chart not updating properly but I can't exactly pin down what I am doing wrong.
const sharedPlotOptions = {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: null,
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [{
name: 'Countries',
colorByPoint: true,
data: []
}]
}
export function CountryPopulationPlot(props) {
let adultData = props.countries.map(country => ({
name: country.name,
y: country.population //TODO: use adult only data
}))
let allData = props.countries.map(country => ({
name: country.name,
y: country.population
}))
let adultPlotOptions = sharedPlotOptions
adultPlotOptions.series[0].data = adultData
let allPlotOptions = sharedPlotOptions
allPlotOptions.series[0].data = allData
return(
<div>
<HighchartsReact
highcharts={Highcharts}
options={adultPlotOptions}
oneToOne={true}
/>
<HighchartsReact
highcharts={Highcharts}
options={allPlotOptions}
/>
</div>
);
}
EDIT: oneToOne prop was an attempt at fixing the bug, it doesn't seem to have any effect.
In Highcharts for Pie charts to render, the adultData and allData should be in the format as below:
[
{
name: "USA",
y: 1000
},
{
name: "Italy",
y: 500
}
]
(or)
[
{
"name": "USA",
"y": 1000
},
{
"name": "Italy",
"y": 500
}
]
Please double check this in your input data. I have written a blog post and a working application on GitHub with a simple Highcharts Pie chart example. Please check: http://softwaredevelopercentral.blogspot.com/2020/03/react-highcharts-and-spring-boot.html
I'm having the same issue and found a rough workaround. Like you said this happens on the initial component render. Therefore triggering a re-render by updating a state solves the problem.
const [shouldRender, doRender] = useState(true)
useEffect(() => {
if (shouldRender) { // this stops the cycle after the first re-render
doRender(!shouldRender)
}
Would like to add in case someone has a better solution, I'm rendering multiple graphs with the same props and only pie charts are an issue.
Related
I have apex chart in angular that is receiving input from a parent component. See code below
`
#Input() labels: string[] = [];
#Input() series: number[] = [];
constructor() {}
ngOnInit(): void {
this.chartOptions = {
series: this.series,
chart: {
type: 'donut',
width: 200,
},
dataLabels: {
enabled: false,
},
colors: ['#197254', '#62DAB3', '#E2F96F'],
legend: {
show: false,
},
labels: this.labels,
tooltip: {
enabled: false,
},
//dont show data label
plotOptions: {
pie: {
donut: {
size: '80%',
labels: {
show: false,
},
},
},
},
};
}
The series is gotten from the parent after it makes network request.
`
<app-piechart id="pie" [labels]="['Monthly', 'Quaterly', 'Anually']" [series]="[stats.activeSubscriber.subscriptionTypeAggregate.monthly.count, stats.activeSubscriber.subscriptionTypeAggregate.quarterly.count, stats.activeSubscriber.subscriptionTypeAggregate.annually.count]"></app-piechart>
`If i pass random value to the component directly, the pie chart renders well but if i pass in variable into the arrays, it shows like the image below
enter image description here
Please assit
If i pass random value to the component directly, the pie chart renders well but if i pass in variable into the arrays, it shows like the image below
enter image description here
And i confirmed the variables is in the pie chart component using the angular extension on chrome.
I have fixed the issue.
Apparently i was passing string into the series array
like ['1', '2',...]
instead of [1, 2, ..]
I'm using html, css and javascript for the project. The server is set up locally including node, express and highcharts.
In my html i have a div container, that i'm referencing in my highcharts function. The data i'm using in the highchart come from a csv file. I wrote a simple getData function, that parses the data into an array. And at the top of the highchartsfunction, i'm using await getData, so the chart can only be rendered after getting the data for it. All functions are async. On that one page i'm having seven charts, all constructed using the syntax following below, each with its own getData function and div container.
Two problems:
Problem No.1:
The charts are not getting displayed until i refresh the page and often times i even have to refresh it several times, till every chart is getting shown at a time (Like 20 times). The functions are all executed, i checked that in the console.
Problem No.2:
I would like to write this dynamically, as i want to have multiple pages on my website, each using its own csv file, but basically the same code.
*Edit:
From time to time i receive: "Error: Highcharts error #13: www.highcharts.com/errors/13/" in the console, but as i keep refreshing it changes the line/js it is referencing to. It always is the part of the highcharts function, in which i give it its container Highcharts.chart('hammerchart', {. I checked this error and what it sais is basically, that the script can't find a container with the #id. Which i don't understand as im using "DOMContentLoaded". I tried the "load" event instead, which solved the error #13, but ended up in no chart getting displayed at all without any error message.
*Edit2:
Until now i only used firefox to view my website. I checked Chrome aswell and here i don't have any error message, but it also never shows any of the charts aswell at all.
If someone could help me out here, i would be really happy, as i tried to fix this for days now with no success. I'm also open for suggestions, regarding the handling of my data. Thank you veeeery much in advance!!
Code:
CSV Data sample
2015,2.5,7.2,1.6,6.5,2.2
2016,3.5,7.6,2.6,9.3,1.2
2017,2.5,7.2,1.6,6.5,2.2
2018,3.5,7.6,2.6,9.3,1.2
2019,2.5,7.2,1.6,6.5,2.2
HTML
<div id="hammerchart">
</div>
CSS
#hammerchart{
width:49%;
height: 500px;
margin:0.5%;
margin-top:50px;
flex: 1 1 600px;
}
Javascript - first declaration of the arrays, then my parsing function, splitting the csv by linebreaks and commas. Then i'm using parseFloat(), so that i don't have strings in it. In the highcharts function i'm using await getData and DOMContentloaded, to make sure both html and my data are ready.
const years = [];
const columntwos = [];
const columnthrees = [];
const columnfours = [];
const columnfives = [];
const columnsixs = [];
async function getDataone() {
const response = await fetch('/javascripts/hammerchart.CSV');
const data = await response.text();
const table = data.split('\n');
table.forEach(row => {
const columns = row.split(',');
const year = columns[0];
years.push(year);
const columntwo = columns[1];
columntwos.push(parseFloat(columntwo));
const columnthree = columns[2];
columnthrees.push(parseFloat(columnthree));
const columnfour = columns[3];
columnfours.push(parseFloat(columnfour));
const columnfive = columns[4];
columnfives.push(parseFloat(columnfive));
const columnsix = columns[5];
columnsixs.push(parseFloat(columnsix));
});
};
async function hammerchart() {
await getDataone();
document.addEventListener('DOMContentLoaded', () => {
Highcharts.chart('hammerchart', {
chart: {
zoomType: 'xy'
},
title: {
text: 'Data'
},
subtitle: {
text: ''
},
credits: {
text: 'highcharts',
},
xAxis: [{
categories: years,
plotBands: [{ // visualize
from: 4.5,
to: 6,
color: 'rgba(68, 170, 213, .2)'
}],
crosshair: true
}],
yAxis: [{ // Primary yAxis
labels: {
format: '{value}$',
style: {
color: Highcharts.getOptions().colors[1]
}
},
title: {
text: 'Amount in $',
style: {
color: Highcharts.getOptions().colors[1]
}
}
}, { // Secondary yAxis
title: {
text: 'Ratio in %',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '{value} %',
style: {
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}],
tooltip: {
shared: true
},
legend: {
layout: 'vertical',
align: 'left',
x: 120,
verticalAlign: 'top',
y: 100,
floating: true,
backgroundColor:
Highcharts.defaultOptions.legend.backgroundColor || // theme
'rgba(255,255,255,0.25)'
},
series: [{
name: 'columntwo',
type: 'areaspline',
data: columntwos,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnthree',
type: 'areaspline',
data: columnthrees,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnfour',
type: 'areaspline',
data: columnfours,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnfive',
type: 'column',
data: columnfives,
tooltip: {
valueSuffix: '$'
}
}, {
name: 'columnsix',
type: 'spline',
yAxis: 1,
data: columnsixs,
tooltip: {
valueSuffix: '%'
}
}]
});
});
};
hammerchart();
I'm using highchart large tree map demo. I'm getting level data on click of each section. But also need to get the data on back button. So I'm using events drill up function to get data on click of back button. below is my code.
this.setState({
data: {
series: [{
type: 'treemap',
layoutAlgorithm: 'squarified',
allowDrillToNode: true,
animationLimit: 1000,
dataLabels: {
enabled: false
},
levelIsConstant: false,
levels: [{
level: 1,
dataLabels: {
enabled: true
},
borderWidth: 0,
}],
data: points,
events: {
click:(e)=>{
console.log(e)
},
drillup:(e)=>{
console.log(e)
}
}
}],
// subtitle: {
// text: 'Click points to drill down. Source: WHO.'
// },
title: {
text: ''
}
}
})
But don't know drill up is not working even click is working and also I added
import drilldown from "highcharts/modules/drilldown";
drilldown(Highcharts);
But still not getting any data. Please help.
Notice that treemap series don't use the drilldown module, but has own drilldown implementation, which logic you can find here: https://code.highcharts.com/modules/treemap.src.js
What you will need to do is render a custom button while clicking the point and attach an update functionality on this button. Something like here:
Demo: https://jsfiddle.net/BlackLabel/gas07t34/
events: {
click() {
let chart = this.chart;
chart.button = chart.renderer.button('back', 500, 0, function() {
chart.series[0].update({
data: data1
})
chart.button.destroy();
}).add()
this.update({
data: data2
})
}
}
API: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#button
API: https://api.highcharts.com/class-reference/Highcharts.Series#update
Am creating a pie chart using data from http request butthe data is never rendered in a pie chart
I have tried
in the html
<div class="col-md-4" *ngIf="overallready">
<chart [options]="overallinsp" class="chart"></chart>
</div>
in typescript code i have
this._reportService.getOverview(utctime:number) //performs http request
.subscribe(
let dtaval = JSON.parse(JSON.stringify(res.totalinspectiondata));
console.log(dtval)
this.overallinsp = {
credits: {
enabled: false
},
chart: {
...
type: 'pie'
},
title: {
text: ...
},
series: [{
name: 'Brands',
colorByPoint: true,
data:dtval
}]
}
this.overallready = true;
)
The above console.log() produces
[{"name":"Bulker delivered","y":0},{"name":"Normal delivered truck","y":4}]
setting the value manually in the series works that is
series: [{
name: 'Brands',
colorByPoint: true,
data:[{"name":"Bulker delivered","y":0},{"name":"Normal delivered truck","y":4}]
}]
What could be wrong since manually setting the data output works but referencing it fails to work?
I have the following scenario in haml:
#ownershipChart{"chart-data" => [["pie1", 100], ["pie2", 150], ["pie3", 200]]}
#ownershipChart{"chart-data" => [["pie4", 45], ["pie5", 50], ["pie6", 20]]}
and in javascript:
$(function(){
$('#ownershipChart').highcharts({
chart: {
type: 'pie'
},
title:{
text: 'Ownership'
},
plotOptions:{
pie:{
allowPointSelect: true
}
},
series: [{
type: 'pie',
name: 'Ownership',
data: $('#ownershipChart').attr('chart-data')
}]
});
});
As you can figure, I'm trying to create one highcharts function that applies across these two charts at the same time. First, I know this is incorrect because $('#ownershipChart').attr('chart-data') isn't returning anything. Second, is this the right way to think about it? I'm currently dynamically generating the haml div id="ownershipChart" so dynamically generating a highcharts js object every time also feels wrong.
What's the best way to generate multiple highcharts when the div ids they are attached to is unknown and varies user by user?
You could instead use a class, and loop through each instance creating the chart as you go. Something like this:
$(function () {
$('.ownershipChart').each(function() {
$(this).highcharts({
chart: {
type: 'pie'
},
title: {
text: 'Ownership'
},
plotOptions: {
pie: {
allowPointSelect: true
}
},
series: [{
type: 'pie',
name: 'Ownership',
data: $(this).attr('chart-data')
}]
});
});
});
Note that the data property is filled by a reference to this, which means the data will be read from the current element in the iteration.