My question is an extension of a previous one (enter link description here).
I remove the labels with null associated datas but now I'd like to remove space when this is the case (I have white spaces ath the left in this example).
Have I to deal with min and max ticks options?
<canvas id="myChart" width="200" height="200"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
let obj = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
spangaps: true,
label: 'Exceptionnel',
data: [1, 2, 3, 4, 5, 6, null, 5, null, null, null, null]
}]
};
var myChart = new Chart(ctx, {
type: 'bar',
data: obj,
options: {
scales: {
xAxes: [{
offset: true,
gridLines: {
display: true
},
ticks: {
callback: function (value, index, values) {
var dataValue = obj.datasets[0].data;
if (dataValue[index]) {
return values[index];
}
}
}
}]
}
}
});
</script>
What you consider a whites space at the left of your example is actually an invisible bar of value 1. This can be solved by defining option yAxes.ticks.beginAtZero: true or alternatively also yAxes.ticks.min: 0.
yAxes: [{
ticks: {
beginAtZero: true
}
}],
In case you want to remove leading null entries from your data, this can be done as follows. The Array.shift() method removes the first element from an array.
while(data[0] == null) {
data.shift(); // remove leading null
labels.shift(); // remove corresponding label
}
To also remove the tailing null entries from your data, you can proceed as follows. The Array.pop() method removes the last element from an array.
while(data[data.length-1] == null) {
data.pop(); // remove tailing null
labels.pop(); // remove corresponding label
}
The important thing is to always also remove the corresponding entry from labels, each time you remove an entry from data.
Please have a look at your amended code below.
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const data = [1, 2, 3, 4, 5, 6, null, 5, null, null, null, null];
while(data[0] == null) {
data.shift(); // remove leading null
labels.shift(); // remove corresponding label
}
while(data[data.length-1] == null) {
data.pop(); // remove tailing null
labels.pop(); // remove corresponding label
}
var myChart = new Chart('myChart', {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Exceptionnel',
data: data
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
offset: true,
gridLines: {
display: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>
Related
I want to use the results from API and render them into Angular highcharts.
However, I am unable to set the data accordingly. Below is the error that was thrown on console.
cpm.component.ts:91 ERROR Error: Uncaught (in promise): TypeError: Cannot set properties of undefined (setting 'data')
TypeError: Cannot set properties of undefined (setting 'data').
async ngOnInit(): Promise<void> {
console.log(this.moves)
console.log(this.moves[1]['Moves'])
}
getMoves() {
this.DataService.getMovesFromDB().subscribe(movesArray =>
movesArray.forEach(move => this.moves.push(move)))
return this.moves
}
highcharts = Highcharts;
chartOptionsTest = {
chart: {
type: "spline"
},
title: {
text: "Simulated VS Actual Move"
},
xAxis:{
categories:["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
},
yAxis: {
title:{
text:"Moves"
}
},
tooltip: {
valueSuffix:""
},
series: [
{
name: 'Before',
data: [1000, 5, 5, 5, 1000, 5, 5, 5, 1000, 5, 5, 5]
},
{
name: 'After',
data: this.moves[1]['Moves']
// Error is thrown
}
]
};
Both console.log(this.moves) and console.log(this.moves[1]['Moves']) did show result, for instance, console.log(this.moves[1]['Moves']) shows 23352546, which is the number from this.moves.
May I know what I have done wrongly?
Nope, you can't map the value from this.moves[1]['Moves'] directly in the variable declaration.
You should assign the value to the chartOptionsTest when the Observable is returned (API response returned).
Assumption:
Assume that you call the getMoves method in ngOnInit method.
async ngOnInit(): Promise<void> {
this.getMoves();
}
Declare the chartOptionsTest variable but remove the second item of series array which you set the value with this.moves[1]['Moves'].
chartOptionsTest: any = {
chart: {
type: 'spline',
},
title: {
text: 'Simulated VS Actual Move',
},
xAxis: {
categories: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
},
yAxis: {
title: {
text: 'Moves',
},
},
tooltip: {
valueSuffix: '',
},
series: [
{
name: 'Before',
data: [1000, 5, 5, 5, 1000, 5, 5, 5, 1000, 5, 5, 5],
},
],
};
In the subscribe method which is triggered when the observable (response) is returned, append the value this.moves[1]['Moves'] to the this.chartOptionsTest.series array with Array.push().
getMoves() {
this.DataService.getMovesFromDB().subscribe((movesArray) => {
movesArray.forEach((move) => this.moves.push(move));
this.chartOptionsTest.series.push({
name: 'After',
data: this.moves[1]['Moves'],
});
});
}
While this line
return this.moves;
can be removed as it is unnecessary for me and also it doesn't guarantee to return value if the Observable is not returned and the above code (subscribe part is not triggered to bind the value to this.moves).
Demo # StackBlitz
Im having some trouble with ChartJs and hope you can help. I would like to create a Bar Chart where:
Zero Lables that only contains dataset with zeros are not showing
If only one data value in a chart it is cen
I have added the code example here at codepen: Link to ChartJs CodePen
var Canvas = document.getElementById("myChart");
var Data1 = {
label: 'Project A',
data: [10, 0, 10, 0 ,0 ,0 ,10],
backgroundColor: 'rgba(0, 99, 132, 0.6)',
borderWidth: 0,
yAxisID: "y-axis"
};
var Data2 = {
label: 'Project B',
data: [0 , 5, 5, 0 ,0 ,0 ,10],
backgroundColor: 'rgba(99, 132, 0, 0.6)',
borderWidth: 0,
yAxisID: "y-axis"
};
var MonthData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
datasets: [Data1, Data2]
};
var chartOptions = {
scales: {
xAxes: [{
barPercentage: 1,
categoryPercentage: 0.6
}],
yAxes: [{
id: "y-axis"
}]
}
};
var barChart = new Chart(Canvas, {
type: 'bar',
data: MonthData,
options: chartOptions
});
Another example, please see below. I have added a link to the source. If i could add data to a Bar Chart the same way it would be perfect.
Link to source of picture
EDIT:
Added a codepen for DX chart: DX Link
/Thomas
ChartJS and the DevExtreme chart are 2 different things. If you want the functionality of dxChart in chartJs then you would have to write it yourself (if you don't have access to the source code to see how they did it).
Helping you with the first point is easy - simply unset the data you don't want. Check here. Don't forget to remove the label you don't want to show.
for (let i = 0; i <= Data1.data.length; i++){
if (Data1.data[i] === 0 && Data2.data[i] === 0) {
Data2.data.splice(i, 1);
Data1.data.splice(i, 1);
labels.splice(i, 1); // also remove the corresponding label
i--; // important not to skip any records after removing
}
}
However this sort of data manipulation I would recommend doing in the back end. Just don't set it before sending to the front end and you're done.
For your second point it looks like chartJs cannot help. There is a reason why dxChart is paid and chartJs is free. Learn to make compromises or become a JS ninja. Cheers
Changing intersect to false for the tooltips should fix the problem. (Intersect: true only shows the tooltips if you're hovering over a datapoint, of which there are none if it's zero)
tooltips configuration can be found here: https://www.chartjs.org/docs/2.6.0/configuration/tooltip.html
var chartOptions = {
scales: {
xAxes: [{
barPercentage: 1,
categoryPercentage: 0.6
}],
yAxes: [{
id: "y-axis"
}]
},
tooltips: {
intersect: false
}
};
I create a ApexChart with empty values because I dynamically add series and labels.
var options777 = {
chart: {
height: 397,
type: 'line',
toolbar: {
show: false,
}
},
series: [{
name: 'Elegibility',
type: 'column',
data: []
}],
stroke: {
width: [0, 4]
},
// labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
labels: [],
xaxis: {
type: 'datetime'
},
yaxis: [{
title: {
text: 'Elegibility',
}
}
};
var chart777 = new ApexCharts(
document.querySelector("#elegibilityChart"),
options777
);
if (document.getElementById('elegibilityChart')) {
chart777.render();
}
Then, I have a function that receives two arrays, one with the series data and other with label data. The arrays are same size, series contains numbers and labels strings.
function setData(mySeries, myLabels) {
chart777.updateOptions({
series: {
data: mySeries
},
labels: myLabels
})
}
When I run my code, it returns: error TypeError: "options$$1.series[0] is undefined"
How can I update the series and labels in the ApexChart?
Thanks
If you're updating both the series and the labels, this will need to be done in two separate calls.
Use the updateSeries method to provide the new data series (as an array).
Use the updateOptions method to provide the new labels (as an object that will merge with the existing options, keeping any configurations not overridden).
chart1.updateOptions({
xaxis: {
categories: year
},
series: [{
data: trend
}],
});
You should use code like this, I mean you should update xaxis categories instead of labels and also comment labels in options and instead use xaxis categories.
I have this issue where the markers on the chart gets cutoff for any max value. shown below:
code:
render () {
var data = [
{ name:"Jan", y:200.9, score:2 },
{ name:"Feb", y: 200.5, score:1 },
{ name: "Mar", y:200.4, score:3 },
{ name: "Apr", y:200.4, score:5 },
{ name: "May", y:200.9, score:9},
{ name: "Jun", y:200.4, score:10 },
{ name: "Jun", y:200.4, score:7 }
]
let maxValue= Math.max.apply(null, data.map((dot) => dot.y));
//im setting the yAxis in the chartConfig dynamically when data is rendered
chartConfig.yAxis.max = maxValue;
}
even when I set it to more than the max value from the data, i get the same clipped markers:
say ex:
chartConfig.yAxis.max = maxValue +100;
as you can see the 200 being the only and max value here, the markers are not displayed correctly. if I change the max 'y' value to be 500, then the rest will be displayed correctly, but one with values 500 would be cutoff..
I tried setting the yAxis: {min:0,max:250} does not work.
any ideas what might be the issue or how to solve it..Thanks!
note: I was referring this as an example, http://jsfiddle.net/KdHME/474/ it works here by adding the min max values to yAxis, but does nothing to mine..
Using chart.js, I have a line chart that is displaying datasets compiled in a .net web app.
Is it possible to set a line as hidden/disabled once the data is loaded, based on the label name?
There is a hidden flag in chart.js that enables a dataset to be hidden on load, but this is set when initially defining the dataset. As the data has already been defined within the view, I cannot use this flag. E.g.
var viewsByMonthChartCtx = new Chart(viewsByMonthChartCtx, {
type: 'line',
data: {
labels: ['February 2017','March 2017'],
datasets:
[ { label: 'Home', data: [100,120 ] }, // I want to set 'hidden: true' to the Home dataset post initialization
{ label: 'Search', data: [200,240 ] } ]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
}
});
If you want to hide a dataset after the chart has been initialized (and rendered), then you still use the dataset hidden: true property. You simply just have to access the dataset from your chart instance and set the property to true.
Here is an example where a dataset matching a label is hidden 5 seconds after the page loads.
// the dataset label we want to hide after chart is initialized
var hiddenLabel = 'My Second Dataset';
var timerDuration = 5;
// hide a dataset after X seconds
setTimeout(function() {
var indexToHide = -1;
// find which dataset matches the label we want to hide
myLine.config.data.datasets.forEach(function(e, i) {
if (e.label === hiddenLabel) {
indexToHide = i;
}
});
// get the dataset meta object so we can hide it
var meta = myLine.getDatasetMeta(indexToHide);
// hide the dataset and re-render the chart
meta.hidden = true;
myLine.update();
}, timerDuration * 1000);
As you can see, you can just iterate over the datasets to find the index of the dataset with the matching label, then you simply set the hidden property to true and update the chart.
Here is a codepen that demonstrates a full working example.
With that said, it's not clear why you would want to do this after the chart is hidden. If you already know which dataset you want hidden at page load time, then you could just assemble your data and options chart config dynamically and set the hidden flag to true programmatically. Here is an example.
// the dataset label we want to hide
var hiddenLabel = 'My Second Dataset';
// build our data and options config (if needed you could build the datasets dynamically from dynamic data (this example is static)
var config = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First Dataset",
backgroundColor: chartColors.red,
borderColor: chartColors.red,
data: [5, 10, 25, 15, 10, 20, 30],
fill: false,
}, {
label: "My Second Dataset",
fill: false,
backgroundColor: chartColors.blue,
borderColor: chartColors.blue,
data: [5, 0, 12, 5, 25, 35, 15],
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Hide Dataset Matching "My Seconds Dataset" After 3 Seconds'
},
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
}
}
};
// iterate over our datasets to find the one we want to hide
config.data.datasets.forEach(function(e) {
if (e.label === hiddenLabel) {
e.hidden = true;
}
});
// instantiate the chart
var myLine = new Chart($('#canvas'), config);