I would like to set the color of y-axis tick labels in Chart.js bar and line charts based on the numeric label value. Specifically, I'd like negative values to be rendered red. Additionally rather than displaying "-1", "-2", etc., I'd like to override to display "(1)", "(2)", etc.
I've seen examples for changing tick labels based on index / position, but not conditionally based on the label value. Thanks in advance for any guidance.
You can define the scriptable option scales.x.ticks.color as an array of colors that depend on the corresponding data value each. The following definition for example shows red tick labels for every bar of a value less than 10.
scales: {
x: {
ticks: {
color: data.map(v => v < 10 ? 'red' : undefined)
}
}
}
For further information, consult Tick Configuration from the Chart.js documentation.
Please take a look at below runnable code and see how it works.
const data = [4, 12, 5, 13, 15, 8];
new Chart('myChart', {
type: 'bar',
data: {
labels: ['A', 'B', 'C', 'D', 'E', 'F'],
datasets: [{
label: 'Dataset',
data: data,
}]
},
options: {
responsive: false,
scales: {
x: {
ticks: {
color: data.map(v => v < 10 ? 'red' : undefined)
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="myChart" height="180"></canvas>
I am currently trying to create a doughnut chart that represents a projects completion with 2 mains sections; complete and incomplete. is there any way that I can make it so that the complete sections is split into multiple subsections which display peoples usernames when hovered without cluttering the legend?
Beneath is an artistic rendition because I feel like I haven't given enough information.
You can use the generateLabels function as described here.
Please take a look at below runnable sample code and see how it works.
var labels = ['Incomplete', 'Sam', 'Claudia', 'Kevin', 'Sonia', 'Kate'];
var data = [14, 5, 4, 3, 7, 5];
new Chart('myChart', {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: labels.map((l, i) => i ? 'yellow' : 'lightblue'),
weight: 0.6
}]
},
options: {
plugins: {
legend: {
labels: {
generateLabels: () => [{
text: 'Incomplete',
fillStyle: 'lightblue',
strokeStyle: 'lightblue',
},
{
text: 'Complete',
fillStyle: 'yellow',
strokeStyle: 'yellow',
}]
}
}
}
}
});
canvas {
max-height: 250px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="myChart"></canvas>
I'm trying to create a line chart with chart.js where the data in a dataset contains points:
data: [{x:0,y:5},{x:2.1,y:4.3},{x:3.9,y:3}]
The x values of those points contain decimals. The resulting chart looks like this:
Instead of showing the second data point at (2.1 | 4.3) it is drawn at (1 | 4.3)!
Can someone point me into the right direction on this one?
The code to reproduce this behavior:
<body>
<div>
<canvas id="myChart" width="400" height="200"></canvas>
</div>
<script>
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
datasets: [{
label: 'some label',
data: [{x:0,y:5},{x:2.1,y:4.3},{x:3.9,y:3}],
borderColor: 'red',
fill: false,
lineTension: 0
}]
},
options: {
scales: {
xAxes: [{
ticks: {
max: 10,
min: 0,
stepSize: 0.1
}
}],
yAxes: [{
ticks: {
max: 6,
min: 0,
stepSize: 1
}
}]
}
}
});
</script>
</body>
For the y-axis, using the stepSize variable of the ticks option does the trick. Doing the same for the x-axis is a little more complex but not impossible.
The first issue is that your x-axis labels are at integer intervals so the chart has nowhere to position the decimal values than at the closest integer. This can be fixed by specifying all the values in the desired intervals (ie: 0.1, 0.2,...,3.0) in the labels.
Then, making use of the autoSkip and maxTicksLimit, you can hide the labels not needed and so create the chart seen in your image, but with the points in the correct position.
I made a working version of this using your code in this fiddle. Hope this helps!
I have this chart:
...which is displaying exactly how I want it to with one exception... The data in the bars is for between the two times in the x axis... so all the labels need shifting to lie on the grid lines, not between them as default for a bar chart. So the red and blue bar is data between 8:00 and 9:00. I hope I've explained that clearly enough.
I'm trawling through the Chart.js docs and it just doesn't seem like this is possible! I know I could change my labels to be, for example, 8pm - 9pm, but that seems a much more visually clunky way of doing it. Is there a way anyone know of achieving this? Ideally there would be another '12am' on the last vertical grid line too.
You can draw the tick lables at the desired position directly on to the canvas using the Plugin Core API. It offers number of hooks that may be used for performing custom code. In below code snippet, I use the afterDraw hook to draw my own labels on the xAxis.
const hours = ['00', '01', '02', '03', '04', '05', '06'];
const values = [0, 0, 0, 0, 10, 6, 0];
const chart = new Chart(document.getElementById('myChart'), {
type: 'bar',
plugins: [{
afterDraw: chart => {
var xAxis = chart.scales['x-axis-0'];
var tickDistance = xAxis.width / (xAxis.ticks.length - 1);
xAxis.ticks.forEach((value, index) => {
if (index > 0) {
var x = -tickDistance + tickDistance * 0.66 + tickDistance * index;
var y = chart.height - 10;
chart.ctx.save();
chart.ctx.fillText(value == '0am' ? '12am' : value, x, y);
chart.ctx.restore();
}
});
}
}],
data: {
labels: hours,
datasets: [{
label: 'Dataset 1',
data: values,
categoryPercentage: 0.99,
barPercentage: 0.99,
backgroundColor: 'blue'
}]
},
options: {
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'HH',
unit: 'hour',
displayFormats: {
hour: 'Ha'
},
tooltipFormat: 'Ha'
},
gridLines: {
offsetGridLines: true
},
ticks: {
min: moment(hours[0], 'HH').subtract(1, 'hours'),
fontColor: 'white'
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>
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.