How to show grid-lines when chart data is empty, in High Stock charts? - charts

I need to show grid lines when my chart has no data. (For now, It shows a blank division when there is no data) How to show grid lines? Is it possible to do? I tried but couldn't find an useful answer. Following is the method I used to draw the chart.
public drawChart(): void {
this.options = new StockChart ({
rangeSelector: {
selected: 0,
inputEnabled: false,
},
chart: {
type: 'spline',
},
yAxis: {
labels: {
formatter: function(): string {
return this.value + '';
},
},
opposite: false,
},
plotOptions: {
series: {
showInNavigator: true,
},
},
series: [],
});
}

To show the gridlines yAxis needs to have defined some min and max values. When series is applied those values are calculated and set to the yAxis, but in the case of the empty data, we need to apply them as the dummy values. Later, when data will be applied we can reset those values by using the yAxis.update feature.
Demo: https://jsfiddle.net/BlackLabel/zcsp8nfr/
API: https://api.highcharts.com/class-reference/Highcharts.Axis#update
API: https://api.highcharts.com/class-reference/Highcharts.Series#update

Related

How to make/create a population pyramid in echarts?

I'm trying to create a population pyramid chart, using echarts (echarts.apache.org). I can't find an example of that kind, and couldn't find how to do it. The values of the chart should all be displayed as positive. A chart example: https://www.internetgeography.net/wp-content/uploads/2019/12/united-kingdom-population-pyramid-2016.gif
I have tried using reverse axes bar chart, with negative numbers, but I couldn't find a way to hack the displayed negative numbers into positive ones.
I tried modifying the stack graph and using negative input values and overwriting the display as positive (Math.abs()).
When importing the data, I multiply by -1, so the output must be positive. valueFormatter: (value) => Math.abs(value)
Modify tooltip.valueFormatter
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
valueFormatter: (value) => Math.abs(value)
}
And modify series.label.formatter display to be positive as well Math.abs(params.value)
label: {
show: true,
position: 'left',
formatter: function (params) {
return Math.abs(params.value);
}
}
And custom xAxis.axisLabel.formatter
xAxis: [
{
type: 'value',
show: true,
axisLabel: {
formatter: function (params) {
return Math.abs(params);
}
}
}
],
Example
Example code with Echarts editor

Highcharts Multiple Series data - label mismatch

I have multiple series lets call them
A, B, C, D
I have pulled the series data like so
data:[1,2,3], data:[4,5,6], data[3,5,7], data[7,8,9]
The data is showing correctly on the bar chart
But when I click the series name/identifier on the y-Axis while the bar shows the correct data, the label that appears beside the bar, is incorrect.It seems to use an index based correlation between series and labels
Here is my code:
axios.get('/api/getData')
.then((response) => {
let data= response.data
//initialize series, category arrays
let series = [];
let categories = [];
//group data by product types
let productTypeGroups = _.groupBy(stockData, (product) => {
return product.type;
});
//loop through grouped data and create series for each product type
for(const[key,value] of Object.entries(productTypeGroups)){
let dataValues= _.map(value, (product)=>{
//push product names into category array
categories.push(product.name)
return product.current_balance < 0 ? 0 : product.current_balance;
})
//set default visibility to true if product is vaccine
let visibility = key === 'A' ? true : false
series.push({
name:key,
data:dataValues,
visible:visibility
})
}
this.dataValuesChart.highchartOptions.xAxis.categories = categories
this.dataValuesChart.dataValues.series = series
Here is the HighCharts Config:
highchartOptions: {
chart: {
type: 'bar',
height: 500
},
title: {
text: 'Stock Balance'
},
subtitle: {
text: ''
},
yAxis: {
title: {
text: 'Doses'
},
labels: {
format: '{value}'
}
},
xAxis: {
categories: [],
labels:{
step:1
}
},
plotOptions: {
series: {
label: {
connectorAllowed: false
}
}
},
series: [],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
}
Here is a screenshot of how the chart displays:
How does the click event know what labels to pull, should we use some sort of dynamic category setting for this to work? Is there another way to do this even?
Credit #ppoctaczek for pointing out the data array can also be a multidimensional array [x, y] as documented here: https://api.highcharts.com/highcharts/series.bar.data
In terms of hiding the unclicked series #ppoctaczek suggested I edit the plotOption section like so. NB default behaviour on click is to add or remove clicked series to already clicked series - you can retain these defaults if that works for you.
plotOptions: {
series: {
label: {
connectorAllowed: false
},
grouping:false,
events:{
legendItemClick: function(){
this.chart.series.forEach(s=>{
s.hide();
});
this.show();
return false;
}
}
}
},
Then in terms of the data array I needed to make it multidimensional, and have the x value referencing the serial indices of the categories across the multiple series. I achieved this by:
//initialize index counter
let i = 0;
//loop through grouped data and create series for each product type
for(const[key,value] of Object.entries(productTypeGroups)){
let balances = [];
_.each(value, (product)=>{
//push product names into category array
categories.push(product.name)
//push index and balance into balances array
balances.push([i, product.current_balance]);
//increment index
i++;
})
//set default visibility to true if product is vaccine
let visibility = key === 'vaccine' ? true : false
series.push({
name:key,
data:balances,
visible:visibility
})
}
Your data array on console.log your series data should look like this:

How I can add the predict data and the actual data in the same graph with ChartJS?

I want to adda the predict data and the actual data in real time in the same graph to get something like that:
my code is like that:
xArr.push(jsonRes[i].timestamp)
yArr.push(jsonRes[i].deplacement)
yMax.push(3)
yMin.push(-3)
yPredict.push()
// draw chart
let canvas = document.getElementById("myChart");
let ctx = canvas.getContext('2d');
myChart = new Chart(ctx, {
type: 'line',
data: {
labels: xArr,
datasets: [{
label: 'Déplacement cumulé de la chaine inclinométrique (mm)', // Name the series
data: yArr, // Specify the data values array
fill: false,
borderColor: '#2196f3', // Add custom color border (Line)
backgroundColor: '#2196f3', // Add custom color background (Points and Fill)
borderWidth: 1 // Specify bar border width
}, {
label: 'Déplacement max toléré', // Name the series
data: yMax, // Specify the data values array
fill: true,
borderColor: '#b30000'
}, {
label: 'Déplacement min toléré', // Name the series
data: yMin, // Specify the data values array
fill: true,
borderColor: '#b30000'
}, {
label: 'ML', // Name the series
data: yPredict, // Specify the data values array
fill: true,
borderColor: '#b30000'
}
]
},
options: {
responsive: true, // Instruct chart js to respond nicely.
maintainAspectRatio: false, // Add to prevent default behaviour of full-width/height
}
});
I want to get an unique graph where I will have a part of actuel data in real time and the next part of predict data. All these datas come from a database as timeseries.
you can use plugin and chagne the chartLineStlyle from where you want to dashed.
https://www.chartjs.org/docs/latest/developers/plugins.html
Use plugin available hook
var chart = new Chart(ctx, {
plugins: [{
beforeInit: function(chart, options) {
//..
}
}] });

ChartJS / MomentJS - Unable to remove deprecation warning. Graph not showing in firefox/opera

so browsers throw
warning about using momentJS incorrectly.
Deprecation warning: value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.
Arguments:
[0] _isAMomentObject: true, _isUTC: false, _useUTC: false, _l: undefined, _i: 12.30, _f: false, _strict: undefined, _locale: [object Object]
Error
So i looked at my code
data: {
labels: ['01.01', '02.01', '03.01', '04.01', '05.01', '06.01', '07.01', '08.01', '09.01', '10.01', '11.01', '12.01'],
datasets: createChatterData(data, this)
},
And read that I should provide a format when dealing with non iso strings.
labels: [moment('01.01', 'MM.DD'), moment('02.01', 'MM.DD'), ...];
Ok that removed first deprecation.
But my datasets data also contains of date
dataset.data.pushObject({
x: moment(datum).format('MM.DD'),
y: parseInt(moment(datum).format('YYYY'))
});
So I tried different variations to that (premodified ambigious datetime)
x: moment(date, 'YYYY.MM.DD').format('MM.DD')
and
x: moment(date, 'MM.DD')
But my graph doesnt map correctly anymore.
Example of codepen chart working in chrome: http://codepen.io/kristjanrein/pen/wJrQLE
Does not display in firefox/opera
I see a couple of issues here.
1) Since you want your X axis to be a time scale, then you should leave your X data value as a moment object. Your current implementation is creating a moment object from a date string and then formatting it back to a string. When you do this, chart.js then takes the string and tries to create a moment object internally when it builds the chart.
Therefore, It is best to keep the data as either a Date or Moment object and use the time scale configuration properties to determine how the data is displayed on the chart. This prevents chart.js from having to construct the moment object and guess at the string format.
2) You are using the pre-2.0 way to create a chart when you use Chart.Scatter. Instead you should use the new style (new Chart()) and pass in a type property.
Here is a modified version of you code that results in no browser warnings and works in Chrome and Firefox (I did not test in Opera).
var getData = function() {
var dummyDataset = [
'2007-11-09T00:00:00.000Z',
'2006-08-04T00:00:00.000Z',
'2006-08-06T00:00:00.000Z',
'2008-01-10T00:00:00.000Z'
];
return dummyDataset.map(function(datum) {
var myMoment = moment(datum);
return {
x: myMoment,
y: parseInt(myMoment.format('YYYY')),
};
});
};
var ctx = document.getElementById("chart1").getContext("2d");
var myScatter = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: "My First dataset",
borderColor: 'rgb(255, 99, 132)',
fill: false,
pointRadius: 4,
pointHoverRadius: 8,
showLine: false,
data: getData()
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Random Data'
},
legend: {
display: true,
labels: {
fontSize: 10,
boxWidth: 20
}
},
elements: {
point: {
pointStyle: 'rect'
}
},
hover: {
mode: 'nearest'
},
scales: {
xAxes: [{
type: 'time',
position: 'bottom',
scaleLabel: {
display: true,
labelString: 'Months'
},
time: {
unit: 'month',
displayFormats: {
month: 'MM'
},
}
}],
yAxes: [ {
type: 'linear',
ticks: {
min: 2005,
max: 2015,
stepSize: 1
},
scaleLabel: {
display: true,
labelString: 'Year'
}
}]
}
}
});
You can see it in action at this forked codepen.
One other thing to keep in mind is that because your data spans multiple years, you will see duplicate months on the X axis. Remember, a time scale is used to plot dates so even if you only display the months, a data point with the same month but with different years will not be plotted at the same location.
If you are actually only wanting to show month string/number values in the X axis, then you should not use the time scale at all and use the linear scale instead. Then when you build your data values, you would extract the month from the data (the same way you are already doing for your Y value).
var getData = function() {
var dummyDataset = [
'2007-11-09T00:00:00.000Z',
'2006-08-04T00:00:00.000Z',
'2006-08-06T00:00:00.000Z',
'2008-01-10T00:00:00.000Z'
];
return dummyDataset.map(function(datum) {
var myMoment = moment(datum);
return {
x: parseInt(myMoment.format('MM')),
y: parseInt(myMoment.format('YYYY')),
};
});
};
So in addition to jordan's answer
I changed my labels and x axis from
['01.01', '02.01', ...] to [1,2,...]
and
from type: 'time' to type: 'linear'
And to make it map not only by month but also by day. I had to make date objects to correct floats. 05.20 to 5.66
const date = datum.key;
const day = parseInt(moment(date).format('DD')) / 30 * 100;
const fullDate = parseFloat(moment(date).format('MM') + '.' + Math.round(day))
// 05.10 would be 5.3 (10 of 30 is 33%)
{
x: fullDate,
y: parseInt(moment(date).format('YYYY'))
date: date, // for tooltip
count: count // for tooltip
}
And i also had to make corrections to my tooltips
callbacks: {
title: function([tooltipItem], data) {
const tooltipInfo = getTooltip(tooltipItem, data.datasets);
return tooltipInfo.date;
},
label: function(tooltipItem, data) {
const tooltipInfo = getTooltip(tooltipItem, data.datasets);
return i18n.t('chart.count') + ': ' + tooltipInfo.count;
},
}
corresponding tooltip dataset
function getTooltip(tooltipItem, datasets) {
return datasets[tooltipItem.datasetIndex].data.find(datum => {
return datum.x === tooltipItem.xLabel && datum.y === tooltipItem.yLabel;
});
}

Kendo Chart Missing CategoryAxis Text for multiple series

I am creating a kendo chart that can have multiple datasets.
I am creating a chartOptions object that is only being manipulated by referencing the properties and is not manipulated through Kendo functionality. This is done by the following code:
var chartOptions = {
theme: "",
seriesDefaults: {
type: "line"
},
title: {
text: ""
},
legend: {
position: "bottom"
},
series: "",
categoryAxis: {
field: "category"
}
};
function createChart() {
$("#chart").kendoChart(
$.extend(true, {}, chartOptions)
);
}
I also have the user defining which datasets they want. The choose their datasets and create their chart. The chart is then rendered but missing its categoryAxis data.
I am setting the series data (the data comes from the server, but is available for example) in the following way:
dataSetContents.Series = {"Series":[{"name":"2009 Data","data":[{"category":"2008","value":18159},{"category":"2007","value":315},{"category":"2009","value":8}]},{"name":"2008-2010","data":[{"category":"2010","value":750},{"category":"2009","value":2980},{"category":"2008","value":4135},{"category":"2007","value":55}]}]}
chartOptions.series = dataSetContents.Series;
I figured out the reason why I was losing my categories. It has to do with the multiple series, the way to fix this by setting the categoryAxis. This can be done by passing the array of categories like this:
chartOptions.categoryAxis = { categories: [2007,2008,2009,2010] };