I'm trying to build a chart.js Line and with scatter points and I would like to have the datalabel to show just on the scatter points, I've tried to do it with datalabels plugin from chart js but it shows the datalabel for all datasets including the line, How can I show just the specific scatter points? this is what the code looks like:
Chart.register(ChartDataLabels);
fetch('https://raw.githubusercontent.com/ConeDigital/assets/main/data.json')
.then(response => response.json())
.then(data => {
var ctx = document.getElementById('myChart2').getContext('2d'),
chart = new Chart(ctx, {
type: 'line',
data: getChartData(data),
options: {
legend: {
display: false
},
plugins: {
datalabels: { // This code is used to display data values
anchor: 'end',
align: 'top',
font: {
weight: 'bold',
size: 16
}
}
},
tooltips: {
mode: 'index',
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ': ' + tooltipItem.yLabel+"%";
},
labelColor: function (tooltipItem, chart) {
let border = ''
let background = ''
let colors
if ( tooltipItem.datasetIndex === 1 ) {
colors = {
borderColor: '#fff',
backgroundColor: '#001F5B'
}
} else {
colors = {
borderColor: '#fff',
backgroundColor: '#eb8484'
}
}
return colors
}
}
},
responsive: true,
scales: {
xAxes: [{
stacked: false,
scaleLabel: {
display: false,
labelString: 'Datum'
},
ticks: {
display: false
},
gridLines: {
display: false,
drawBorder: false,
}
}],
yAxes: [{
stacked: false,
ticks: {
display: false
},
gridLines: {
display: false,
drawBorder: false
},
scaleLabel: {
display: false,
labelString: 'Procent'
}
}]
}
}
});
})
function getChartData(json) {
var labels = [];
var omx_dataset = {
label: 'OMXS30',
borderColor: '#eb8484',
fill: false,
pointRadius: 0,
borderWidth: 1,
data: []
};
var gadd_dataset = {
label: "GADD SMP SEK",
borderColor: '#001F5B',
fill: false,
pointRadius: 0,
borderWidth: 1,
data: []
};
var mark1_dataset = {
label: 'Start',
borderWidth: 2,
borderColor: '#FF0000',
fill: false,
type: 'scatter',
data: [{
x: '2011-03-29',
y: 0
}],
pointRadius: 12
};
var mark2_dataset = {
label: '2016',
borderWidth: 2,
borderColor: '#FF0000',
fill: false,
type: 'scatter',
data: [{
x: '2015-12-31',
y: 20
}],
pointRadius: 12
};
var mark3_dataset = {
label: '2020',
borderWidth: 2,
borderColor: '#FF0000',
fill: false,
type: 'scatter',
data: [{
x: '2020-01-07',
y: 59
}],
pointRadius: 12
};
var mark4_dataset = {
label: '2022',
borderWidth: 2,
borderColor: '#FF0000',
fill: false,
type: 'scatter',
data: [{
x: '2022-01-03',
y: 109
}],
pointRadius: 12
};
json.map((point,i) => {
labels.push(point.Date)
const gadd_num = (point['GADD SMP SEK']*100).toFixed(2)
const omx_num = (point['OMXS30']*100).toFixed(2)
gadd_dataset.data.push(gadd_num)
omx_dataset.data.push(omx_num)
//console.log(point.Date)
//result1_dataset.data.push(point.date)
})
return {
labels: labels,
datasets: [omx_dataset, gadd_dataset, mark1_dataset, mark2_dataset, mark3_dataset, mark4_dataset]
}
}
Right now it shows all the datalabels from all the datasets and it looks messed up,
Thanks in advance
You could add the datalabels config to the line datasets, disabling the plugin, as the following:
var omx_dataset = {
label: 'OMXS30',
borderColor: '#eb8484',
fill: false,
pointRadius: 0,
borderWidth: 1,
data: []
datalabels: {
display: false
}
};
var gadd_dataset = {
label: "GADD SMP SEK",
borderColor: '#001F5B',
fill: false,
pointRadius: 0,
borderWidth: 1,
data: [],
datalabels: {
display: false
}
};
Related
We are using react chart js but the problem occurs when we try to show multi-line charts in small widgets with high y-axis values.
Overflow occurs in smaller widths and large y axes numbers. I already try a thousand suffixes but it doesn't work. Is it possible to keep the y-axis constant by making the x-axis smaller? Or handle it responsive.
function randomTwoNumbers(n1, n2) {
return Math.floor(Math.random() * (n2 - n1 + 1) + n1)
}
function generateData(count) {
let data = []
for (let index = 0; index < count; index++) {
data.push({
x: `2022-07-${index}T00:00:00.000Z`,
y: randomTwoNumbers(1000000, 9999999)
})
}
return data
}
const data = {
datasets: [
{
data: generateData(100),
label: 'Temperature',
borderColor: '#236EF1',
tension: 0.5,
pointRadius: 1,
pointHoverRadius: 5,
pointHitRadius: 20,
yAxisID: 'y0'
},
{
data: generateData(100),
label: 'Humidity',
borderColor: '#CA840C',
tension: 0.5,
pointRadius: 1,
pointHoverRadius: 5,
pointHitRadius: 20,
yAxisID: 'y1'
}
]
}
const options = {
responsive: true,
resizeDelay: 300,
scales: {
x: {
display: true,
grid: {
borderColor: '#5E646E',
tickColor: '#5E646E',
display: true,
drawOnChartArea: false
},
ticks: {
autoSkip: false,
maxRotation: 0,
font: {
size: 10,
family: 'Inter',
lineHeight: '12px',
weight: '500'
}
},
time: {
unit: 'day',
displayFormats: {
minute: 'p',
hour: 'p',
day: 'MMM, do'
}
},
type: 'time',
offset: true,
adapters: {
date: {
locale: {
code: 'en-US',
formatLong: {},
localize: {},
match: {}
}
}
}
},
y0: {
display: true,
grid: {
borderColor: '#5E646E',
tickColor: '#5E646E',
display: true,
drawOnChartArea: false
},
ticks: {
font: {
size: 10,
family: 'Inter',
lineHeight: '12px',
weight: '500'
}
},
stack: 'single',
offset: false
},
y1: {
display: true,
grid: {
borderColor: '#5E646E',
tickColor: '#5E646E',
display: true,
drawOnChartArea: false
},
ticks: {
font: {
size: 10,
family: 'Inter',
lineHeight: '12px',
weight: '500'
}
},
stack: 'single',
offset: false
}
},
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
title: {
display: false
},
tooltip: {
displayColors: false
}
}
}
var config = {
type: 'line',
data,
options
}
var ctx = document.getElementById('canvas').getContext('2d')
window.myLine = new Chart(ctx, config)
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.2/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-moment/1.0.1/chartjs-adapter-moment.min.js"></script>
<div style="width: 200px">
<canvas id="canvas"></canvas>
</div>
I am trying to create a stacked horizontal bar chart with an average line on each bar using the ChartJS library. I tried several times and searched on the Internet but I did not find out any satisfying answers. I appreciate your helping. Thanks.
Example:
.
In this example, the red line on each bar implies the average value of its group.
To create the stacked horizontal bar chart, please see
https://jsfiddle.net/lamtn862004/9wm1krqf/10/.
var data = {
labels: ["January", "February", "March"],
datasets: [
{
label: "Dogs",
backgroundColor: "rgba(237, 192, 169)",
data: [20, 10, 25],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Cats",
backgroundColor: "rgba(253, 234, 175)",
data: [70, 85, 65],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Birds",
backgroundColor: "rgba(179, 211, 200)",
data: [10, 5, 10],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
]
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
type: 'groupableHBar',
data: data,
options: {
scales: {
yAxes: [{
stacked: true,
type: 'category',
id: 'y-axis-0'
}],
xAxes: [{
stacked: true,
type: 'linear',
ticks: {
beginAtZero:true
},
gridLines: {
display: false,
drawTicks: true,
},
id: 'x-axis-0'
},
{
stacked: true,
position: 'top',
type: 'linear',
ticks: {
beginAtZero:true
},
id: 'x-axis-1',
gridLines: {
display: true,
drawTicks: true,
},
display: false
}]
}
}
});
Now, I want to add the average line to each bar (as shown in the image).
Also, do you know the other solutions with open-source libraries for doing this?
The lines can be drawn using floating bars tied to the separate axis y2. To do so, you need to add another dataset as follows (I don't exactly understand what values you want to display, hence I randomly chose 40, 65 and 55):
{
label: "Lines",
backgroundColor: "rgb(255, 0, 0)",
data: [40, 65, 55].map(v => [v - 0.3, v + 0.3]),
yAxisID: 'y2',
order: -1
}
Further you must define a new scales option as shown below:
y2: {
display: false
}
Please take a look at your amended runnable code and see how it works.
var data = {
labels: ["January", "February", "March"],
datasets: [{
label: "Dogs",
backgroundColor: "rgba(237, 192, 169)",
data: [20, 10, 25]
},
{
label: "Cats",
backgroundColor: "rgba(253, 234, 175)",
data: [70, 85, 65]
},
{
label: "Birds",
backgroundColor: "rgba(179, 211, 200)",
data: [10, 5, 10]
},
{
label: "Lines",
backgroundColor: "rgb(255, 0, 0)",
data: [40, 65, 55].map(v => [v - 0.3, v + 0.3]),
yAxisID: 'y2',
order: -1
}
]
};
new Chart('myChart', {
type: 'bar',
data: data,
options: {
indexAxis: 'y',
plugins: {
legend: {
display: false
}
},
scales: {
y: {
stacked: true,
grid: {
display: false
}
},
y2: {
display: false
},
x: {
stacked: true,
beginAtZero: true,
grid: {
display: false
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="myChart" height="100"></canvas>
I want to make horizontal bar chart using chartjs in react like this: chart i want to make
but i end up doing like this chart i make
can someon help me please, im new in react and chartjs
Here's the continuation of this post: How to make labels on both side from horizontal bar chart js
here's what i code:
this the data:
export const dataPasienKeluarMasuk = {
type: 'bar',
labels: [
[0, 1, 2, 3,4], // expect output 0 - 4
[5, 6, 7, 8, 9], // expect output 5 - 9
[10, 14], // ext..
[15, 19],
[20, 24],
[25, 29],
[30, 34],
],
datasets: [
{
label: 'Pasien Masuk',
xAxisID: 'A',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
xAxisID: 'A',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
],
}
here's the chart:
import { HorizontalBar } from 'react-chartjs-2'
import { dataPasienKeluarMasuk } from ...blabla
<HorizontalBar
data={dataPasienKeluarMasuk}
height={227}
options={{
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
display: true,
position: 'bottom',
},
scales: {
xAxes: [
{
id: 'A',
position: 'left',
},
],
},
}}
/>
You should define both axes as stacked:
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
In order to see only positive values displayed on the x-axis ticks, you need to define a ticks.callback function on the x-axis.
ticks: {
callback: value => Math.abs(value)
}
To have only positive values displayed in the tooltips, you further need to define a tooltips.callback.label functions as shown below.
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
let ds = data.datasets[tooltipItem.datasetIndex];
return ds.label + ': ' + Math.abs( ds.data[tooltipItem.index]);
}
}
},
Please take a look at the runnable code snippet below and see how it works (this is a pure Chart.js solution but it should easily be adaptable to react-chart.js).
new Chart(document.getElementById('canvas'), {
type: 'horizontalBar',
data: {
labels: ['a', 'b', 'c', 'd', 'e'],
datasets: [{
label: 'Pasien Masuk',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
position: 'bottom',
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
let ds = data.datasets[tooltipItem.datasetIndex];
return ds.label + ': ' + Math.abs( ds.data[tooltipItem.index]);
}
}
},
scales: {
xAxes: [{
stacked: true,
ticks: {
callback: value => Math.abs(value)
}
}],
yAxes: [{
stacked: true
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas"></canvas>
this snippet is based from uminder's answer
new Chart(document.getElementById('canvas'), {
type: 'horizontalBar',
data: {
labels: ['a', 'b', 'c', 'd', 'e'],
datasets: [{
label: 'Pasien Masuk',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
display: true,
position: 'bottom',
},
scales: {
xAxes: [{
stacked: true,
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return value < 0? -(value) : value
}
}
}],
yAxes: [{
stacked: true
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
var value = tooltipItem.xLabel;
value = value < 0? -(value) : value
return label + ': ' + value;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas"></canvas>
I need to show the last bar value only. like this image:
I try this code but it shows all values.
var dataX = {
labels: [['Personne', 'seule'], ['Couple sans', 'enfant'], ['Couple avec', 'enfant(s)'], ['Famille', 'monoparentale'], 'Autres'],
datasets: [{
label: 'Data 1',
data: [33,28,25,8,2.5],
backgroundColor: '#00BBF1',
borderWidth: 0
},
{
label: 'Data 2',
data: [29,30,30,8,2],
backgroundColor: '#3CC6F4',
borderWidth: 0
},
{
label: 'Data 3',
data: [41,22,22,11,3],
backgroundColor: '#92D9F8',
borderWidth: 0
}]
};
var optionsX = {
tooltips: {
enabled: false
},
responsive: true,
maintainAspectRatio: false,
legend: false,
scales: {
xAxes: [{
gridLines : {
color: "#fff"
},
}],
yAxes: [{
gridLines : {
display : false
},
ticks: {
min: 0,
max: 50,
stepSize: 10,
callback: function(value) {
return value + "%"
},
}
}]
},
plugins: {
datalabels: {
color: '#59595B',
font: {
weight: 'bold',
size: 14,
},
align: 'end',
anchor: 'end',
formatter: function(value, context) {
return value +'%';
}
}
},
};
var ctx = document.getElementById('chart-one');
var myChart = new Chart(ctx, {
type: 'bar',
data: dataX,
options: optionsX
});
You can change the plugins.datalabels.formatter function as follows:
plugins: {
...
datalabels: {
formatter: (value, context) => context.datasetIndex == 2 ? value + '%' : ''
}
}
Please take a look at your amended code below and see how it works.
var dataX = {
labels: [
['Personne', 'seule'],
['Couple sans', 'enfant'],
['Couple avec', 'enfant(s)'],
['Famille', 'monoparentale'], 'Autres'
],
datasets: [{
label: 'Data 1',
data: [33, 28, 25, 8, 2.5],
backgroundColor: '#00BBF1',
borderWidth: 0
},
{
label: 'Data 2',
data: [29, 30, 30, 8, 2],
backgroundColor: '#3CC6F4',
borderWidth: 0
},
{
label: 'Data 3',
data: [41, 22, 22, 11, 3],
backgroundColor: '#92D9F8',
borderWidth: 0
}
]
};
var optionsX = {
tooltips: {
enabled: false
},
responsive: true,
maintainAspectRatio: false,
legend: false,
scales: {
xAxes: [{
gridLines: {
color: "#fff"
},
}],
yAxes: [{
gridLines: {
display: false
},
ticks: {
min: 0,
max: 50,
stepSize: 10,
callback: function(value) {
return value + "%"
},
}
}]
},
plugins: {
datalabels: {
color: '#59595B',
font: {
weight: 'bold',
size: 14,
},
align: 'end',
anchor: 'end',
formatter: (value, context) => context.datasetIndex == 2 ? value + '%' : ''
}
},
};
var ctx = document.getElementById('chart-one');
var myChart = new Chart(ctx, {
type: 'bar',
data: dataX,
options: optionsX
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
<canvas id="chart-one"></canvas>
I'm unable to find an explanation so as why my customized scatter charts display a line chart instead.
I've created this custom chart by extending it from scatter using the basic :
Chart.defaults.scatterCustom = Chart.defaults.scatter;
Chart.controllers.scatterCustom = Chart.controllers.scatter.extend({ ...
Following is the entire code i'm using and a fiddle to illustrate my problem.
We can see the 3 differents charts, 2 are default scatter and one is customScatter.
The draw function was added later, thinking it would bring back the normal behaviour but it doesn't change anything.
Any help greatly appreciated!
tidechart = {
tideChart: "",
initTidechart: function() {
Chart.defaults.scatterCustom = Chart.defaults.scatter;
Chart.controllers.scatterCustom = Chart.controllers.scatter.extend({
draw: function(ease) {
Chart.controllers.scatter.prototype.draw.call(this, ease);
},
fireSliderEvent: function(point, canvas, boundingRect) {
var mouseX = Math.round((boundingRect.left + point._view.x) / (boundingRect.right - boundingRect.left) * canvas.width / this.chart.chart.currentDevicePixelRatio);
var mouseY = Math.round((boundingRect.top + point._view.y) / (boundingRect.bottom - boundingRect.top) * canvas.height / this.chart.chart.currentDevicePixelRatio);
var oEvent = document.createEvent('MouseEvents');
oEvent.initMouseEvent('click', true, true, document.defaultView,
0, mouseX, mouseY, mouseX, mouseY,
false, false, false, false, 0, canvas);
canvas.dispatchEvent(oEvent);
},
highlightPointsByIndex: function(datasetIndex, index) {
var canvas = this.chart.canvas;
var boundingRect = canvas.getBoundingClientRect();
var points = this.chart.getDatasetMeta(datasetIndex).data;
this.fireSliderEvent(points[index], canvas, boundingRect);
},
highlightPointsByValue: function(points, value) {
var dataPoints = this._data;
for (var index = 0; index < dataPoints.length; ++index) {
if (dataPoints[index].toString() === value.toString()) {
this.highlightPointsByIndex(points, index);
break;
}
}
}
});
tideChartOptions = {
maintainAspectRatio: false,
legend: {
display: true
},
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest",
filter: function(tooltipItem) {
return tooltipItem.datasetIndex != 0;
}
},
responsive: true,
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Tide level'
},
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.0)',
zeroLineColor: "transparent",
},
ticks: {
suggestedMin: 0,
suggestedMax: 10,
padding: 20,
fontColor: "#9a9a9a"
},
afterTickToLabelConversion: function(q) {
for (var tick in q.ticks) {
q.ticks[tick] += ' m';
}
},
}],
xAxes: [{
display: true,
type: 'time',
time: {
parser: 'YYYY-MM-DD HH:mm:ss',
tooltipFormat: 'll HH:mm',
unit: 'day',
unitStepSize: 1,
displayFormats: {
'month': 'MMM DD'
}
},
gridLines: {
drawBorder: false,
color: 'rgba(225,78,202,0.1)',
zeroLineColor: "transparent",
},
ticks: {
padding: 20,
fontColor: "#9a9a9a"
}
}]
}
};
var data = {
labels: ['01/01/2020','01/02/2020','01/03/2020','01/04/2020'],
datasets: [
{
label: 'Camera 1',
type: 'scatter',
fill: false,
backgroundColor: '#2DAAE1',
borderColor: '#2DAAE1',
borderWidth: 0,
pointBackgroundColor: '#2DAAE1',
pointHoverBackgroundColor: '#2DAAE1',
pointBorderWidth: 0,
pointHoverRadius: 5,
pointRadius: 2,
data: [1,5,6,7]
},
{
fill: false,
type: 'scatter',
label: 'Camera 2',
backgroundColor: '#FFC329',
borderColor: '#FFC329',
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
pointBackgroundColor: '#FFC329',
pointHoverBackgroundColor: '#FFC329',
pointBorderWidth: 0,
pointHoverRadius: 5,
pointRadius: 2,
data: [3,2,8,1]
},
{
fill: false,
type: 'scatterCustom',
label: 'Camera 3',
backgroundColor: '#FF5229',
borderColor: '#FF5229',
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
pointBackgroundColor: '#FF5229',
pointHoverBackgroundColor: '#FF5229',
pointBorderWidth: 0,
pointHoverRadius: 5,
pointRadius: 2,
data: [8,4,5,3]
}
]
};
//tidechart.tideChart = new Chart(ctx, config);
tidechart.tideChart = new Chart($("#tidechart"), {
data: data,
options: tideChartOptions
});
}
}
tidechart.initTidechart();
This solves it
Chart.defaults.global.datasets.scatterCustom = Chart.defaults.global.datasets.scatter;