How can I group bars with same month in ChartJS? - javascript

I'm currently working on a chart where you can compare values from previous years with values from the current year.
Here is my code for the chart :
this.chart = new Chart(this.myChart.nativeElement, {
type: 'bar',
data: {
datasets: []
},
options: {
plugins: {
legend: {
display: false
},
tooltip: {
enabled: true,
callbacks: {
label: (tooltipItem: TooltipItem<any>): string | string[] => {
return `${tooltipItem.formattedValue} ${$localize`kWh`}`
},
}
}
},
scales: {
y: {
beginAtZero: true
},
x: {
adapters: {
date: {
locale: 'fr-FR',
zone: 'Europe/Paris'
}
},
ticks: {
source: 'labels',
},
display: true,
type: 'time',
time: {
unit: 'month',
displayFormats: {
month: 'MMM',
day: 'dd MMMM',
week: 'WW-yy'
},
tooltipFormat: { month: 'long', year: '2-digit' }
}
},
},
transitions: {
show: {
animation: {
duration: 0
}
},
hide: {
animation: {
duration: 0
}
}
}
}
});
Then I give my datasets to the chart this way :
initChartData() {
this.chart.data.labels = this.dataObject.datas.map(c => c.startDate)
this.chart.data.datasets[0] = {
data: this.dataObject.datas.map(c => ({ x: c.startDate.toString(), y: c.data })) as any,
backgroundColor: '#58c0d8',
borderColor: '#58c0d8',
}
this.chart.update();
}
I give the data as an object, so my tooltip has the correct date, because it is formatted via the time options i previously gave to the chart.
The problem is that, as I give the data in this way to the chart, the chart cannot superimpose the two set of bars and it gives me a result like this :
If I stop furnishing the data as an object, giving only the value, it gives a result almost good, like this :
but as you can see if I hover the second bar :
it will give my the exact same month, from the same year, which is not the desired behavior. I completly understand why it is doing this, because as i dont give it any personnal label, the bar tooltip can't know his year, so as for me the only solution was to give the data as an object, but i can't make it work with the data side by side.
I've been struggling for two days now with this so I really hope someone can help me out, and I want to thanks anyone who will try in advance !

Related

Chart.js is removing the final x-axis label when toggling between views

I am using JS/JQuery/Kendo and have and am attempting to toggle between two different view types in the same graph. The first view is of a Cadence (Week) within a period (Months), on initial render the x-axis labels are correct in showing the start and end of a cadence, for sake of this example lets say the cadence starts on 2/2/23 and ends on 2/9/23, the graph points and labels are correct, but when clicking on the button to toggle the views, the cadence week is also correct on the graphs but instead of showing the end date of 2/9, the graph in this view stops at the current date, but also does not render, all that shows is the most recent update, this is less of a concern at the moment because if I toggle back to the original view of the cadence, suddenly the final date is cut off, so instead of seeing 2/2-2/9, we now see 2/2-2/8 and I have no clue why, I've tried using the offset as well as autoSkip properties but I'm still seeing the behavior, in my call to render the graph I am also using chart.update() but still seeing the incorrect data points. Here is my code, note that the definitions are in a call to render the graph, hence the chart.update() at the bottom of the definitions:
var customLineScales: {
xAxes: any[],
yAxes: {
ticks: {
suggestedMin: number,
suggestedMax: number,
userCallback: (value: any, index: number, values: any[]) => string
}
} []
} = {
xAxes: [{
type: 'time',
time: {
tooltipFormat: 'll',
unit: 'day',
min: chartStart,
max: chartEnd
},
ticks: {
suggestedMin: chartStart,
suggestedMax: chartEnd,
},
gridLines: {
display: false,
drawBorder: false,
}
}],
yAxes: []
};
var chart = new Chart(lineChart, {
type: 'line',
data: {
labels: cleanedUpdateLabels,
datasets: [{
label: historicalData.Name,
data: cleanedUpdateDataPoints,
}]
},
options: {
responsive: true,
elements: {
point: {
hitRadius: hitRadius,
hoverRadius: 5,
radius: UpdateValueRadius
},
scales: customLineScales,
});
chart.update();
Code for toggle switch:
if (Cadence === "Weekly") {
var weekSoFar = historicalData.HistoricalUpdates.map(function (update: any) {
if (vm.get('showPeriod')) {
return update.Date;
} else {
if (update.Date >= cadence.startDate && update.Date <= cadence.endDate) {
return update.Date;
}
}
});
if (vm.get('showPeriod')) {
chart.data.labels = cleanedUpdateLabels;
} else {
newChart.data.labels = cleanedUpdateLabels;
}
}

How to display single data-values with ApexCharts correctly?

I am currently trying to build a barchart with ApexCharts. Everything works fine when the data-array has more than one entry. Somehow, whenever data only contains one element, the diagram messes up the width of the bar.
Correct state with multiple entries:
Buggy state with one entry
My goal is to display a single value with the same xaxis scale and the same barwitdh as the barchart displays multiple values.
I already tried using an array of timestamps for each hour as catigories-prop but this didn't work for me.
I use 'dateime' as type for my xaxis.
Data is an array that can contain 0, 1 or x entries. It is given to the Barchart-Component as data-prop.
Categories contains a the timestamp to each entry of data. Therefore it can also have 0, 1, or x values. Categories is used as the Barcharts categories-prop.
Here are my configurations (For the buggy state):
var options = {
series: [
{
name: "Servings",
data: [[1669082400000, 44]]
}
],
chart: {
height: 350,
type: "bar",
animations: {
enabled: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
xaxis: {
type: 'datetime',
labels: {
datetimeUTC: false,
datetimeFormatter: {
year: 'yyyy',
month: 'MMM',
day: 'dd',
hour: 'HH:mm'
}
},
categories: [
1669082400000,
],
min: 1669075200000,
max: 1669161600000
},
tooltip: {
intersect: false,
shared: true
},
yaxis: {
reversed: false,
}
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
Would be nice if somebody could help me out, I'm tripping over this one.

ChartJS options.scales is being completely ignored

I am trying to make a chart which has years along the x-axis and dollar amounts along the y-axis. I finally got close to what I'm looking for, but I found that because the x coordinates are numbers, ChartJS is putting commas in them which looks really strange for years.
After some digging, I used the callbacks. options.plugin.tooltip.callbacks.label worked to let me remove commas in the tooltips, but when I use options.scales.x[0].ticks.callback to try to fix the labels on the bottom, not only does it not work, but I don't see the console.log statement in their ever being printed so it seems it's not even calling the callback. I've tried several variations of how to do the callback based on what I found online and on Stack Overflow which I think correspond to the different ways ChartJS did this in different versions. (I'm on version 3.5.1.)
Then, I realized that... none of the options under options.scales appear to have any effect. I change the min, the title, the tick settings (color to red, callback, etc.) and it has no effect. (This also explains why I was having trouble when using the line chart and had to switch to scatter; apparently type: 'linear' wasn't being picked up nor did it do anything different when I set it to type: 'date' or whatever the exact working was for that.)
Meanwhile, the other options like options.showLine or options.elements do have an effect and I'm seeing the chart and not getting any errors in the console. So, it is picking up the options, just ignoring everything I have in options.scales.
Here is the relevant code:
// Sample data added to make this example self-contained
// This is my internal data format
let data = {
"Series1": [ {x: 2001, y: 100 }, {x: 2002, y: 110 }, {x: 2003, y: 107 }, ],
"Series2": [ {x: 2001, y: 107 }, {x: 2002, y: 102 }, {x: 2004, y: 95 }, ],
}
// Define data //////////////////////////////////////////////////////
// I convert data to format ChartJS wants and add a few options
let datasets = [];
for(let label in data) {
let c = colorIterator.next().value
datasets.push({
label: label,
data: data[label],
backgroundColor: c,
borderColor: c,
});
}
// Define options //////////////////////////////////////////////////////
let chartConfig = {
type: 'scatter',
data: { datasets: datasets, },
options: {
title: { display: false },
indexAxis: 'x', responsive: true, maintainAspectRatio: false,
showLine: true,
elements: {
line: { display: true, tension: 0, borderWidth: 1, fill: false, },
point: { radius: 3 }
},
interaction: { mode: 'x', },
scales: {
x: [{
type: 'linear',
min: 1995, max: (new Date()).getFullYear()+1, stepSize: 1,
title: { display: true, text: 'Year' },
ticks: {
display: true,
major: { enabled: true },
color: 'red',
callback: function(value, index, ticks) {
console.log(value);
return Chart.Ticks.formatters.numeric.apply(this, [value, index, ticks])
.replace(",","");
}
}
}],
y: [{
title: { display: true, text: '$' },
ticks: {
display: true,
color: 'red',
},
}],
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if(label) {
let x = context.label.replace(",","");
let y = context.formattedValue;
return 'Year ' + x + ' "' + label + '": $' + y;
} else { return 'x'; }
},
},
},
},
}
};
// MAKE CHART //////////////////////////////////////////////////////
let mainChart = new Chart(document.getElementById(c.id), chartConfig);
As described in the docs the scales are not arrays. All the scales are objects in the scale object.
So you will need to change your code to this:
options: {
scales: {
x: {
// x options
},
y: {
// y options
},
}
}

Highcharts Date.UTC does not work properly for real data

I've built something like this. I get my data from the server, put it in an object called series, and pass it to 'series' in Highcharts code block. Basically, for every staff, there will be a date, and my default value(Y-Axis) is '1' for now. However, I can't get dates on the chart as expected even if it looks that I had correct data and did correct parsing. Unexpectedly, I get my millisecond values as Y-axis values, which does not make any sense, and every staff has a default date, which is 1 January. (For ex., staff 1, 1 January, x-axis value = 1554422400000)
I get dates like this, 19-02-2019 17:32. Then I split them, and use it like this,
([Date.UTC(parseInt(yearsplit[0]), datesplit[1]-1, parseInt(datesplit[0])), 1])
which looks exactly the same format in Highcharts, ([Date.UTC(1971, 2, 16), 0.86])
var responsePromise = $http.post('statistics/getAllProtocolRecords', data, null);
responsePromise.success(function (dataFromServer, status, headers, config) {
var series = [{
name: "",
data: []
}];
dataFromServer.protocolRecords.forEach((data) => {
var datesplit = data.checkupDate.split("-");
var yearsplit = datesplit[2].split(" ");
series.push({
name: data.staff,
data: [Date.UTC(parseInt(yearsplit[0]), datesplit[1]-1, parseInt(datesplit[0])), 1]
})
});
series.shift();
Highcharts.chart('container', {
chart: {
type: 'spline'
},
title: {
text: 'Toplam Muayene Kaydı (' + sysrefHcCheckupType + ')'
},
subtitle: {
text: ''
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: { // don't display the dummy year
month: '%e. %b',
year: '%b'
},
title: {
text: 'Tarih'
}
},
yAxis: {
title: {
text: 'Toplam Muayene (Gün)'
},
min: 0
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.x:%e. %b}: {point.y:%f} '
},
plotOptions: {
spline: {
marker: {
enabled: true
}
}
},
colors: ['#00bdff', '#FF0700', '#df0300', '#ff0700', '#c0df00'],
series: series
});
});
I've just realized that I'd made a little mistake in push function. In series.push, 'data' should like this, surrounded by array brackets:
data: [
[ Date.UTC(parseInt(yearsplit[0]), parseInt(datesplit[1])-1, parseInt(datesplit[0])), 1]
]

C3 graph overlapping x-axis label

C3 graph overlap x-axis labels which is in date time format. I have googled this query but didn't get any solution for it.Is it possible that c3 only shows couple of date time rather then showing altogether which result in overlap x-axis labels
var data = {
x: 'x',
xFormat:'%Y-%m-%d/%H:%M',
empty: {
label: {
text: "No Data"
}
},
columns: [
['x', '{$dateArray}'],
['Attack', {$data}],
],colors: {
Attack: '#67b7dc',
},
types: {
Attack: 'area'
}};
var chart = c3.generate({bindto: '#chart1',
size: {
height: 630,
},
data: data,
grid: {
x: {
show: true
},
y: {
show: true
}
},
tooltip: {
format: {
value: function (value, ratio, id) {
var format = value+' Gbps [ IP: '+destIp[value]+' ]';
return format;
}
}
},
zoom: {
enabled: true
},
subchart: {
show: true
},axis: {
x: {
type: 'timeseries',
tick: {
format: '%b %d, %H:%M',
rotate: 90,
multiline: false
}
},
y: {
tick: {
format: function (d) {
return d.toFixed(3);
}
},
label: {
text: 'Attack Size ( Gbps )',
position: 'outer-middle'
}
}
}
});
Use c3.js chart config tick.count, set it to desired integer value like 2,3 or 4.
Use c3.js Timeseries Chart exmaple to play with this config.
Problem without tick.count:-
Problem solved with tick.count config:-

Categories