Hide grids in Bar Graph - chart.js

import React from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
} from 'chart.js';
import { Bar } from 'react-chartjs-2';
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
);
const options = {
responsive: true,
elements: {
bar: {
borderWidth: 2,
},
},
plugins: {
scales: {
x: {
grid: {
display: false
}
},
y: {
grid: {
display: false
}
},
},
legend: {
display: false,
},
title: {
display: false,
// text: 'Top Application Accessed',
},
},
};
const labels = ["a", "b", "c", "d0", "d", "e", "t"];
const v = [8, 10, 15, 2, 4, 11, 17]
const data = {
labels,
datasets: [
{
label: "Total no of errors",
data: v,
backgroundColor: 'blue',
}
],
};
export default function App() {
return <Bar options={options} data={data} />;
}
In the above code All the code inside scales is not having any effect.
I want to hide grids from my chart.
I want to also add some features to my chart but anything I add to this code having no effect in the results.
Instead of full grids I want dotted grid only parallel to x axis.
I also want to add different colors to all the bars.

You have putted your scale condif in the plugins section of the options object. This is incorrect, you need to place the scales section in the root of the options object. Then it will work fine.
So instead of options.plugins.scales.x and options.plugins.scales.y you will get: options.scales.x and options.scales.y

Related

Charts.js renders axes, but not the dataset

I'm trying to use Charts.js on an AWS Lambda function to create a chart image (png).
However, for some reason it plots the axes, but no data.
this is my code:
export const plotData = (values: number[]): Buffer | null => {
const canvas = createCanvas(800, 600);
let ctx: ChartItem = canvas as unknown as ChartItem;
const plugin: Plugin = {
id: "customCanvasBackgroundColor",
beforeDraw: (chart: any, _args: any, options: any) => {
const { ctx: context } = chart;
context.save();
context.globalCompositeOperation = "destination-over";
context.fillStyle = options.color || "#99ffff";
context.fillRect(0, 0, chart.width, chart.height);
context.restore();
},
};
const chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "ph",
data: values.map((y) => ({
y,
t: new Date(),
})),
borderWidth: 2,
borderColor: "red",
backgroundColor: "rgb(255, 0, 0, 0.5)",
},
],
},
options: {
responsive: false,
animation: false,
scales: {
y: {
beginAtZero: true,
},
},
plugins: {
legend: {
position: "top",
},
title: {
display: true,
text: "TEstuibg",
},
customCanvasBackgroundColor: {
color: "rgba(255,255,255, 1)",
},
},
},
plugins: [plugin],
});
// chart.draw();
chart.update();
return canvas.toBuffer("image/png");
};
And this is what it is rendering when I call plotData([100, 200, 300, 400, 500, 1600]):
I am already disabling animations and responsiveness. Is there something else I need to do?
I would create the image on the onComplete event, than everything should be visible, atleast this works in browsers.
from the documentation: "...The animation configuration provides callbacks which are useful for synchronizing an external draw to the chart animation....", but works surely for your image creating process. link to documentation
...
options: {
animation:{
duration: 0, // "no" animation
onComplete: () => {
...
// create image
...
}
}
}
...
Ofcourse: in this case your function plotData would have to be async or pass a callback function for when the event onComplete fires.

How to use Chartjs to plot a single row of colored bars with a time based x axis

I have some time based data I want a graphical representation of, and was hoping to use Chartjs to plot this.
The data looks something like the following:
Time State
--------------
7am up
9am down
10.45am out
17.35 up
Also, each "state" will have its own color, so I would use this as a bar color when using a bar graph
up = red
down = yellow
out = green
The end result I am after is a simple one row bar like the following...
I thought I may be able to use a Chartjs horizontal stacked bar chart (https://www.chartjs.org/docs/latest/charts/bar.html#horizontal-bar-chart) to do this somehow, but I just can't work out how to get this working.
Some (not working) experimental code is as follows:
private createChart(): void {
if (this.chart !== undefined) {
return;
}
Chart.register(BarController, PointElement, Tooltip, Legend, TimeScale, LinearScale, CategoryScale, LinearScale, BarElement);
const options: ChartOptions = {
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
},
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
type: 'time',
display: true,
// position: 'bottom',
time: {
unit: 'minute',
displayFormats: {
minute: 'h:mm a'
}
}
},
x: {
stacked: false,
}
}
};
this.chart = new Chart(this.canvasRef.nativeElement, {
type: 'bar',
data: this.chartData,
options
});
this.chart.config.options.scales.y.min = new Date('2023-02-13T06:19:31.842Z').getTime();
const labels = [
'up',
'down'
// 'Dataset 2'
];
const d1 = new Date('2023-02-13T06:20:32.842Z').getTime();
const d2 = new Date('2023-02-13T06:21:33.842Z').getTime();
this.chartData = {
labels,
datasets: [{
label: 'up',
data: [{x: 10, y: d1}],
backgroundColor: 'red',
},
{
label: 'down',
data: [{x: 20, y: d2}],
backgroundColor: 'green',
}
]
};
this.chart.update();
}
In the above I have tried various combinations of labels, x values, y values, data shapes, but I only even get an empty graph.
Perhaps this is not really possible (I am trying to use the wrong component).
How can I achieve this using chartjs?
Update
Using example from #winner_joiner below, I have put a copy of it at plunkr and have tried to use the time in the x axis, but can see it is still not plotting the bars using the dates as the length
Well your code basically works, here a slightly modified version of your code.
After your comments and updated question, I reworke the example (seen below). Although it is possible to do with chart.js the question is, maybe for this specific task a different library or solution would be better/more convenient.
Update Chart, with some similar values from your question:
(I'm using here momentjs, since it is recommend usually needed form date/time actions in chartjs, as mentioned in the documentation)
const d0 = moment.duration('07:00:00').asMinutes();
const d1 = moment.duration('09:00:00').asMinutes();
const d2 = moment.duration('10:45:00').asMinutes();
const d3 = moment.duration('17:35:00').asMinutes();
const d4 = moment.duration('19:00:00').asMinutes();
let values = [d0, d1, d2, d3, d4];
let data = {
labels: [''],
datasets: [{
label: 'up',
axis: 'y',
data: [d1],
backgroundColor: 'red',
},{
label: 'down',
axis: 'y',
data: [d2],
backgroundColor: 'yellow',
},{
label: 'out',
axis: 'y',
data: [d3],
backgroundColor: 'green',
},{
label: 'up',
axis: 'y',
data: [d4],
backgroundColor: 'red',
}
]
};
const config = {
data,
type: 'bar',
options:{
plugins: {
tooltip: {
mode: 'dataset',
callbacks: {
label: function(item){
return moment().startOf('day').add({ minute: item.raw}).format('HH:mm');
}
}
},
legend: {
display: false,
},
title: {
display: false,
},
},
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
min: d0,
ticks: {
callback: function(value, index, ticks) {
return moment().startOf('day').add({ minute: value}).format('HH:mm');
}
},
afterBuildTicks: axis => axis.ticks = values.map(v => ({ value: v }))
},
y: {
stacked: true
},
}
}};
new Chart(document.getElementById("chart"), config);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<script src="//cdn.jsdelivr.net/npm/moment#^2"></script>
<script src="//cdn.jsdelivr.net/npm/chartjs-adapter-moment#^1"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>

Vue 3 & Chart JS not updating labels

I'm trying to make a simple Vue3 app which show graphs using Chart.js
For this I'm trying to replicate the code shown in the vue-chart-3 plugin doc, which shows an example using a Doughnut chart
My objective is to show a Line graph with a horizontal time axis
The code is a simple App.vue which template is
<template>
<LineChart v-bind="lineChartProps" />
</template>
And the script part:
<script lang="ts">
import { computed, defineComponent, ref } from "vue";
import { LineChart, useLineChart } from "vue-chart-3";
import { Chart, ChartData, ChartOptions, registerables } from "chart.js";
Chart.register(...registerables);
export default defineComponent({
name: "App",
components: { LineChart },
setup() {
const dataValues = ref([30, 40, 60, 70, 5]);
const dataLabels = ref(["Paris", "Nîmes", "Toulon", "Perpignan", "Autre"]);
const toggleLegend = ref(true);
const testData = computed<ChartData<"doughnut">>(() => ({
labels: dataLabels.value,
datasets: [
{
data: dataValues.value,
backgroundColor: [
"#77CEFF",
"#0079AF",
"#123E6B",
"#97B0C4",
"#A5C8ED",
],
},
],
}));
const options = computed<ChartOptions<"doughnut">>(() => ({
scales: {
myScale: {
type: "logarithmic",
position: toggleLegend.value ? "left" : "right",
},
},
plugins: {
legend: {
position: toggleLegend.value ? "top" : "bottom",
},
title: {
display: true,
text: "Chart.js Doughnut Chart",
},
},
}));
const { lineChartProps, lineChartRef } = useLineChart({
chartData: testData,
options,
});
function switchLegend() {
toggleLegend.value = !toggleLegend.value;
}
return {
switchLegend,
testData,
options,
lineChartRef,
lineChartProps,
};
},
mounted() {
if (localStorage.data == undefined) {
localStorage.data = JSON.stringify(this.data);
} else {
this.data = localStorage.data;
}
let dataProcessed = JSON.parse(this.data);
// console.log(JSON.parse(this.data));
console.log(dataProcessed.data);
var dates = [];
// Obtain dates from dataProcessed Array
for (var i = 0; i < dataProcessed.data.length; i++) {
dates.push(dataProcessed.data[i].date);
}
this.testData.labes = dates;
console.log(dates);
},
});
</script>
The objective is that the mounted hook gets certain parameters of the LocalStorage and put them in the "labels" array of the "testData" variable, which is the one which aparently stores the X axis data of the chart.
In the VUE developer tool, it can be seen how this assignation process is done correctly, but in the chart of the left side, the data have not been updated.
Thank you for your help :D

Chart.js: Strikethrough tick labels

I'd like to conditionally add a strikethrough to tick labels. As far as I can tell, there's no option to natively do that through Chart.js. Is there a way to hook in through the axes callbacks to add that?
I don't know if that is possible because you are dealing with a canvas element, but you can customize the text in the labels by using the ticks callback as in this example:
new Chart(document.getElementById("bar-chart"), {
type: 'bar',
data: {
labels: ["One", "Two", "Three", "Four", "Five"],
datasets: [
{
label: "A chart",
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
data: [2478, 5267, 734, 784, 433]
}
]
},
options: {
legend: { display: false },
title: {
display: true,
text: 'A chart with columns and custom vertical labels'
},
scales: {
yAxes: [{
ticks: {
callback: function (value, index, values) {
return index % 2 == 0 ? value : '**' + value + '**';
}
}
}]
}
}
});
Note the callback funcion there, maybe you can use this to give some labels a distinctive text.
The chart of this example looks like this:

Chartjs 2: Multi level/hierarchical category axis in chartjs

Is it possible to define a bar chart with a multi level/category axis?
For instance I'd like to display the Region/Province categories like in this Excel chart:
I found this example using multiple xAxes.
xAxes:[
{
id:'xAxis1',
type:"category",
ticks:{
callback:function(label){
var month = label.split(";")[0];
var year = label.split(";")[1];
return month;
}
}
},
{
id:'xAxis2',
type:"category",
gridLines: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
ticks:{
callback:function(label){
var month = label.split(";")[0];
var year = label.split(";")[1];
if(month === "February"){
return year;
}else{
return "";
}
}
}
}
]
The problem is it seems that the two axes are not really linked and the alignment of second axis is based on values instead of aligning in middle of lower level category. this case cause issues
Is there a clean way to achieve this in chart.js?
Update:
I ended up creating a feature request on chartjs.
you can provide value separately for different axis via datesets and provide an object with different configuration option (borderColor, pointBackgroundColor, pointBorderColor) etc, i hope It'll help.
here is the link for the with an update (fiddle you shared) Updated Fiddle
data: {
labels: ["January;2015", "February;2015", "March;2015", "January;2016", "February;2016", "March;2016"],
datasets: [{
label: '# of Votes',
xAxisID:'xAxis1',
data: [12, 19, 3, 5, 2, 3]
},
// here i added another data sets for xAxisID 2 and it works just fine
{
label: '# of Potatoes',
xAxisID:'xAxis2',
data: [9, 17, 28, 26, 29, 9]
}]
}
I hope that solves your problem :)
Hope this helps,
I did a bit of research and couldn't find methods to implement your solution in chartjs. Chartjs has grouped bar charts but not subgrouped bar charts like in your case.
Example: http://jsfiddle.net/harshakj89/ax3zxtzw/
Here are some alternatives,
D3js (https://d3js.org/) can be used to create sub grouped bar charts.Data can be loaded from csv or json. D3 is highly configurable, but you may have to put some effort than chartsjs.
https://plnkr.co/edit/qGZ1YuyFZnVtp04bqZki?p=preview
https://stackoverflow.com/questions/37690018/d3-nested-grouped-bar-chart
https://stackoverflow.com/questions/15764698/loading-d3-js-data-from-a-simple-json-string
ZingChart is a commercial tool and can be used to implement bar charts with sub groupes.
https://www.zingchart.com/docs/chart-types/bar-charts/
But I prefer D3 over this library. because D3 comes under BSD License.
This should work as per your requirement http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/#8-grouped-bar-chart
The best library I could found to have exactly this feature is Highcharts, this is my implementation:
and here http://jsfiddle.net/fieldsure/Lr5sjh5x/2/ you can find out how to implement it.
$(function () {
var chart = new Highcharts.Chart({
chart: {
renderTo: "container",
type: "column",
borderWidth: 5,
borderColor: '#e8eaeb',
borderRadius: 0,
backgroundColor: '#f7f7f7'
},
title: {
style: {
'fontSize': '1em'
},
useHTML: true,
x: -27,
y: 8,
text: '<span class="chart-title"> Grouped Categories with 2 Series<span class="chart-href"> Black Label </span> <span class="chart-subtitle">plugin by </span></span>'
},
yAxis: [{ // Primary yAxis
labels: {
format: '${value}',
style: {
color: Highcharts.getOptions().colors[0]
}
},
title: {
text: 'Daily Tickets',
style: {
color: Highcharts.getOptions().colors[0]
}
}
}, { // Secondary yAxis
title: {
text: 'Invoices',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '${value}',
style: {
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}]
,
series: [{
name: 'Daily',
type: 'column',
yAxis: 1,
data: [4, 14, 18, 5, 6, 5, 14, 15, 18],
tooltip: {
valueSuffix: ' mm'
}
}, {
name: 'Invoices',
type: 'column',
data: [4, 17, 18, 8, 9, 5, 13, 15, 18],
tooltip: {
valueSuffix: ' °C'
}
}],
xAxis: {
categories: [{
name: "1/1/2014",
categories: ["Vendor 1", "Vendor 2", "Vendor 3"]
}, {
name: "1/2/2014",
categories: ["Vendor 1", "Vendor 2", "Vendor 3"]
}, {
name: "1/3/2014",
categories: ["Vendor 1", "Vendor 2", "Vendor 3"]
}]
}
});
});
body {
padding: 0px !important;
margin: 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://blacklabel.github.io/grouped_categories/grouped-categories.js"></script>
<div id="container" class="chart-container"></div>
But the problem is the library is not free for commercial purposes, and this is the Chartjs implementation, in my case it is look like this:
const data ={"labels":[{"label":"Exams","children":["Wellness Examination"]},{"label":"Surgery","children":["Neuter Surgery"]},{"label":"Vaccines","children":["Bordetella"]},{"label":"Dentistry","children":["Dental Cleaning"]},{"label":"Diagnostics","children":["Other","Pre-Anesthetic","Adult Diagnostics","Pre-Anesthetic Diagnostics","Heartworm & Tick Borne Disease Test"]},{"label":"Treatments/Other","children":["Other","Microchip"]}],"datasets":[{"label":"Consumed","backgroundColor":"red","tree":[{"value":0,"children":["0"]},{"value":0,"children":["0"]},{"value":1,"children":["1"]},{"value":0,"children":["0"]},{"value":15,"children":["0","1","3","11","0"]},{"value":15,"children":["2","13"]}]},{"label":"Purchased","backgroundColor":"blue","tree":[{"value":28,"children":["28"]},{"value":1,"children":["1"]},{"value":24,"children":["24"]},{"value":10,"children":["10"]},{"value":103,"children":["2","16","34","49","2"]},{"value":165,"children":["75","90"]}]}]};
window.onload = () => {
const ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: data,
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Hierarchical Bar Chart'
},
layout: {
padding: {
// add more space at the bottom for the hierarchy
bottom: 45
}
},
scales: {
xAxes: [{
type: 'hierarchical',
stacked: false,
// offset settings, for centering the categorical
//axis in the bar chart case
offset: true,
// grid line settings
gridLines: {
offsetGridLines: true
}
}],
yAxes: [{
stacked: false,
ticks: {
beginAtZero: true
}
}]
}
}
});
};
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/chart.js/dist/Chart.bundle.js"></script>
<script src="https://unpkg.com/chartjs-scale-hierarchical"></script>
<div id="container" style="width: 75%;">
<canvas id="canvas"></canvas>
</div>
for each more column just add another dataset.