I am trying to make a function which will be building Highcharts charts dynamically based on parameters passed. I do it the following way:
function makeChart(name, title, series)
{
var options = {
chart: {
type: 'areaspline',
renderTo: name
},
credits: { enabled: false },
legend: { enabled: true },
title: {
text: title
},
xAxis: {
type: 'datetime'
},
yAxis: {
gridLineDashStyle: 'dot',
title: {
text: 'Quantity'
}
},
plotOptions: {
areaspline: {
animation: false,
stacking: '',
lineWidth: 1,
marker: { enabled: false }
}
},
series: [] //chart does not display except title. It will draw if I paste the data here manually
};
this.chart = new Highcharts.Chart(options);
for (index = 0; index < series.length; ++index) {
options.series[index] = {'name':series[index][0], 'data':series[index][1], 'color':series[index][2], 'fillOpacity': .3};
}
}
makeChart('container2', 'second chart', [['thisisname1', [20,21,22,23,24,25,26,27,28], '#d8d8d8']]);//calling function with test parameters
But everything I can see is the charts title. I guess the problem is in adding data to series array. I tried to add it with several ways but it did not work, although I see that the data has been added if I console.log(options.series). Any ideas how to fix that? Thank you.
Place this.chart = new Highcharts.Chart(options); after the for loop.
You're adding the data after the chart has been initialized, for it to work this way you need to tell HighCharts to redraw itself, easier option is to init after the loop. :)
Related
i have a big data set to display ( around 150 category) with a library named vue-apexchart my problem is that i cant find a way to make the graph scrollable on xaxis without having a broken display the following image will explain my problem better
as you can see having too many categories leads to an unreadable chart
can you please help me
i have tried to make a scrollable div, the probleme still remains ( unreadable xaxis )
here's my chartOptions object :
chartOptions: {
chart: {
type: "bar",
height: 350,
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: "55%",
endingShape: "rounded",
},
},
dataLabels: {
enabled: false,
},
stroke: {
show: true,
width: 2,
colors: ["transparent"],
},
xaxis: {
categories: [],
},
fill: {
opacity: 1,
},
},
I think there are two strategies that you could adopt here. In my opinion, the second one is better.
1. Horizontal bar chart
If you do not have strict constraints in terms of UX/UI, a possible solution might be to switch both axes...
plotOptions: {
bar: {
horizontal: true
}
},
... and give your chart much more height:
chart: {
type: 'bar',
height: 2500,
},
Doing that would allow you to use the natural vertical scrolling of your browser.
let data = [];
for (let i = 1; i <= 150; i++) {
data.push({x: `Category ${i}`, y: i});
}
let options = {
series: [{
name: 'Series',
data
}],
chart: {
type: 'bar',
height: 2500
},
yaxis: {
labels: {
style: {
fontSize: '10px'
},
offsetY: 3
}
},
plotOptions: {
bar: {
horizontal: true
}
},
dataLabels: {
enabled: false
}
};
let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<div id="chart"></div>
All categories are visible. This is not very handy, though.
2. Zoom, pan and tick settings
Zooming and panning are useful features. They are available by default in the toolbar, but this toolbar does not appear immediately when your xaxis has categories. To enable the toolbar in this case, you have to change xaxis.tickPlacement from 'between' to 'on' (see Zoom on Category Bar Charts – ApexCharts.js).
Since you have a lot of categories, it is also a good idea to limit the number of visible labels with xaxis.tickAmount.
xaxis: {
tickPlacement: 'on',
tickAmount: 25
},
Thanks to the zoomX() method, you can decide to display your chart with only a subset of your data. The rest is still accessible via zooming and/or panning.
let data = [];
for (let i = 1; i <= 150; i++) {
data.push({x: `Category ${i}`, y: i});
}
let options = {
series: [{
name: 'Series',
data
}],
chart: {
type: 'bar',
height: 350
},
xaxis: {
tickPlacement: 'on',
tickAmount: 25
},
dataLabels: {
enabled: false
}
};
let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
chart.zoomX(37, 71);
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<div id="chart"></div>
Just started a week ago to learn and use Highcharts. In my application a user selects a key value from a list box and, out of that key an array of values will be retrieved and, used the data to create a multiple series of line graph. In the screenshot below the first series (in light blue color) has the name of CDEP158 and, on the second series (in black color), the series name shouldn't be 'Series 2', it should be CDT158. 'Series 2' for the second series is the issue here.
This is the chart data preparation code which accepts dataChart (result) from jquery post callback function called in a click event.
function prepareChartData(dataChart)
{
var dataSeries = [];
var xTitle;
for (var i = 0; i < dataChart.length; i++) {
var items = dataChart[i];
var xDate = +moment(items.Time);
var seriesData = parseFloat(items.Value);
dataSeries.push([xDate, seriesData]);
xTitle = items.Name;
}
if (aeChart === undefined || aeChart === null)
{
plotChartData(dataSeries, xTitle);
return;
}
aeChart.addSeries({
title: xTitle,
data: dataSeries
});
};
Function that creates a new instance of Highchart and its configuration:
function plotChartData(dataseries, xtitle)
{
aeChart = new Highcharts.Chart({
chart: {
renderTo: 'svgtrendspace',
type: 'line',
zoomType: 'xy',
panning: true,
panKey: 'shift',
plotBorderWidth: 1
},
title: {
text: ''
},
legend: {
layout: 'horizontal',
align: 'left',
itemDistance: 10,
borderWidth: 0,
itemMarginTop: 0,
itemMarginBottom: 0,
padding: 20
},
plotOptions: {
series: {
states: {
hover: {
enabled: false
}
},
dataLabels: {
enabled: false,
format: '{y}'
},
allowPointSelect: false
}
},
xAxis: {
type: 'datetime',
labels: {
rotation: -65,
style: {
fontSize: '9px',
fontFamily: 'Verdana, sans-serif'
}
}
},
yAxis: {
gridLineColor: '#DDDDDD',
gridLineWidth: 0.5
},
series: [{
name: xtitle,
data: dataseries,
tooltip: {
pointFormat: '{series.name}: <b>{point.y}</b><br/>',
valueDecimals: 2
}
}]
});
};
Why is that the first series gets the correct name but on the second one it did not? Is my highcharts configuration wrong? How should I properly configure or format it to address the issue?
I have googled it for similar issues related with multiple series but I couldn't find any similar questions or answers that would help me.
The fact that it works for the first series implies that the issue isn't with your code, but rather is with your init.
Can you put a console.log('Title: ' + xTitle); statement right before you call aeChart.addSeries() in the above function to check on what you are passing in? My suspicion is that the second series is not being passed a title, and that HighCharts is therefore putting in Series2 on its own.
Maybe you should not be setting the value of xTitle in every single iteration of the initial for loop?
I have a ASP.NET MVC project with SignalR.
I have a page with a HighChart and the script looks like this:
$(function () {
window.Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$(document).ready(function () {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'line',
marginRight: 10
},
title: {
text: 'GMAS Queues'
},
xAxis: {
type: 'datetime',
tickInterval: 500,
labels: {
enabled: false
}
},
yAxis: {
title: {
text: 'Queue Count'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Processing Queues'
}]
});
});
$.connection.hub.logging = true;
// Reference the auto-generated proxy for the hub.
var chartData = $.connection.processingQueuesHub;
// Create a function that the hub can call back to display messages.
chartData.client.updateQueueCounts = function (data) {
//$.each(data, function(i, item) {
// // Add the message to the page.
// $('#chartDataLog').append('<li><strong>' + htmlEncode(item.QueueName)
// + '</strong>: ' + htmlEncode(item.Length) + '</li>');
//});
// set up the updating of the chart.
var series = chart.series[0];
$.each(data, function (i, item) {
if (item.QueueName == "Queue A") {
var x = Date.parse(item.Date),
y = item.Length;
series.addPoint([x, y], true, false);
}
});
};
However, I see the graph but not the points.
The strange part is the series data points are there:
Anyone know why HighCharts is not rendering the points?
Thanks, Bill N
I have to thank my good friend and co developer for figuring this out. He is a smarter and braver man than me. :) He went to the highcharts source and found that the highcharts breaks if you add to the graph series before the initial animation is completed. The animation is why the clip-rect is zero-width (it animates from zero to full width over 1s when you first create the chart). You end up adding a point to the series before this animation even really starts. This kills the animation but it doesn’t fix the width of the clip-rect. The fix is to add animation is false for the series.
series: [{ name: 'Processing Queues', data: [], animation: false }]
It looks like you are not defining what your chart.series is until it is created. The line in your ajax is as follows and its not waiting for DOM ready:
var series = chart.series[0];
But you do not define chart until $(document).ready(function () {.... Try keeping your chart object in scope of your ajax.
New to highcharts and as the title said I am trying to pull json from a webservice and place it into the chart (bar chart) but I am getting some weird behavior. after I pull the data down through $http.get() I try and set the series to that string of json like series: '$scope.jsondata'. It will fill some legends (more than expected) so it is getting the data. but the bars on the chart wont show.
On the other hand when I go to the url where I am getting the json and just copy and paste all of the json into the series field, it works perfectly.
I have a plunker here I have been working on that shows what I am talking about. You can just paste:
[
{
"name":"Kaia",
"data":[19]
},
{
"name":"Deborah",
"data":[86]
},
{
"name":"Phoebe",
"data":[77]
},
{
"name":"Rory",
"data":[17]
},
{
"name":"Savannah",
"data":[15]
}
]
...into the series field and everything works.
EDIT I havent yet, but I am planning to use $interval to update the data every x seconds. Something like :
$http.get(fullUrl).success(function(data2) {
$scope.records = [];
data2.forEach(function(r) {
$scope.records.push(r);
});
});
mainInterval = $interval(function() {
$http.get(fullUrl).success(function(data2) {
$scope.records = [];
data2.forEach(function(r) {
$scope.records.push(r);
});
});
}, 5000);
So like one of the answers suggested I put the chart creation in the callback of the $http.get() but I think that'd hinder the $interval
You can move the creation of the Chart into the callback of the get call to simplify things. http://plnkr.co/edit/utQG34xOQmtbOukTK71e?p=preview
Note I also updated series: '$scope.jsondata' to series: $scope.jsondata.
$http.get('https://api.myjson.com/bins/38qm9').success(function(ret) {
$scope.jsondata = ret;
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'bar'
},
title: {
text: 'Active Users'
},
xAxis: {
categories: ['user']
},
yAxis: {
min: 0,
title: {
text: 'Total Score',
align: 'high'
},
labels: {
overflow: 'justify'
}
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
}
}
},
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'top',
x: -40,
y: 100,
floating: false,
backgroundColor: ((Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'),
shadow: false
},
credits: {
enabled: false
},
series: $scope.jsondata
});
console.debug($scope.jsondata);
});
I'm using Highcharts to draw a spline. This works good.
I'm using secondary series (columns) for another data.
My problem is: how to set column height to be matched with spline.
As far i've done this: jsfiddle
Columns have height almost i need, but not all.
It is possible at all?
Relevant code:
$('#chart').highcharts({
title: {text: 'Chart'},
chart: {
type: 'spline'
},
xAxis: {
title: {
text: 'X-Axis'
}
},
yAxis: {
title: {
text: 'Y-Axis'
},
labels: {
enabled: false
}
},
series: [{
name: 'Chart',
data: chdata,
marker: {
enabled: false
},
}],
legend: {
enabled: false
}
});
var chartObj = Highcharts.charts[$('#chart').attr('data-highcharts-chart')];
var d = [];
for(var i = 0; i < ldata.length; i++) {
d.push([ldata[i],getYValue(chartObj,0,getClosest(ldata[i],bdata[0]))]);
}
chartObj.addSeries({
type: 'column',
pointWidth: 1,
borderWidth: 0,
data: d
});
I've tried even with plotLines, but it have height of whole chart.
Thanks,
Bartek
Rather than plotting the height of the closest point, try plotting the average height of the points either side of your bar.
You can get even closer if you work out a linear best fit for your bar on the line between the points either side. Something like:
function getY(xVal,points) {
var higher = 0;
var lower=0;
for(var i=0;i<points.length;i++){
if (points[i][0] > xVal) {
higher=i;
lower=i-1;
break;
}
}
return points[lower][1] + ((points[higher][1]-points[lower][1])*(xVal-points[lower][0])/(points[higher][0]-points[lower][0]));
};
http://jsfiddle.net/5h471o3d/