Layered box annotations - chart.js

Is it possible to draw a box annotation on top of another one?
I need to have two bands, one higher than the other as shown below.
I was able to achieve so by using three annotations with the code below. But, it would be better if I can just have two annotations (one with yMin: 4, yMax: 14 and another with yMin: 2, yMax: 18)
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/chart.js#4.1.1/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation#2.1.1/dist/chartjs-plugin-annotation.min.js"></script>
</head>
<body>
<div>
<canvas id="myChart"></canvas>
</div>
<script>
const ctx = document.getElementById('myChart');
const inner = {
type: 'box',
borderWidth: 0,
drawTime: 'beforeDraw',
yMin: 4,
yMax: 14,
backgroundColor: '#bdc3c7'
};
const outerUpper = {
type: 'box',
borderWidth: 0,
drawTime: 'beforeDraw',
yMin: 2,
yMax: 4,
backgroundColor: '#ecf0f1'
};
const outerLower = {
type: 'box',
borderWidth: 0,
drawTime: 'beforeDraw',
yMin: 14,
yMax: 18,
backgroundColor: '#ecf0f1'
};
new Chart(ctx, {
type: 'line',
data: {
datasets: [{
data: [12, 19, 3, 5, 2, 3],
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
},
plugins: {
legend: {
display: false
},
annotation: {
annotations: {
inner,
outerUpper,
outerLower
}
}
}
},
});
</script>
</body>
</html>

Related

How can I give values like below screenshot using Line Chart

how to show those straight Lines.
I added x: { offset: true }, but the next point not looks straight..
My Code
const labels = ["A", "B", "C", "D"];
const data = {
labels: labels,
borderColor: "",
datasets: [
{
label: "Title",
data: [0, 50, 50, -10],
fill: false,
borderWidth: 5,
borderColor: "yellow",
tension: 0.1,
},
],
};
You could use a scatter as following:
const myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
data: [{x:0, y:0}, {x:0, y:10}, {x:2, y:10}, {x:2, y:0}],
}]
},
options: {
showLine: true
}
});
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
data: [{x:0, y:0}, {x:0, y:10}, {x:2, y:10}, {x:2, y:0}],
}]
},
options: {
showLine: true,
scales: {
y: {
max: 20
}
}
}
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#4.1.1/dist/chart.umd.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"/>
</div>
</body>
</html>

chartjs-plugin-annotation box in Django app

I have chartjs v2.9.3 in my Django app and it works great. Now I need to add a box to one of my charts using chartjs-plugin-annotation, and I've followed all the steps, but I can't get it to work.
I've used chartjs-plugin-annotation v0.5.7 which is for v2.9.3. I get no errors in the console log.
First, scripts with chart.js and plugins:
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3/dist/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation#0.5.7/chartjs-plugin-annotation.min.js"></script>
My code for chart (chart works, I just can't get box to appear):
<canvas id="myChart" height="250"></canvas>
<script>
function setChart12(){
$('#myChart').remove();
$('#container_glavni').append('<canvas id="myChart" height="200"></canvas>');
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: date,
datasets: [{
label: 'Number of reports',
data: data_nc
}, {
type: 'line',
label: 'Median',
data: [50],
fill: false,
borderColor: 'rgb(54, 162, 235)',
}],
},
options: {
layout: {
padding: {
top: 30
}
},
responsive: true,
legend: {
display: false
},
plugins: {
datalabels: {
anchor: 'end',
align: 'end',
offset: 5,
},
autocolors: false,
annotation: {
annotations: {
box1: {
type: 'box',
xMin: 0,
xMax: 1,
yMin: 0,
yMax: 30,
backgroundColor: 'rgba(255, 99, 132, 0.25)'}
}
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});}
</script>
I've tried:
Different values for min and max
Different colors
Different code formating
This is because you putted the options in the place where they belong in V1 of the annotation plugin and the syntax too. For V0.5.7 the annotation options have to be placed in the root of the options and also all the annotations are an array instead of seperate objects:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
annotation: {
annotations: [{
id: "hline",
type: "line",
mode: "horizontal",
scaleID: "y-axis-0",
value: 10,
borderColor: "red",
}]
},
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation#0.5.7/chartjs-plugin-annotation.min.js"></script>
</body>

ChartJS multiple X axis and extra labels in y axis

I have a graph using ChartJS latest version 3.3.2. My code is as below:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<title>OCA-Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.min.js"></script>
</head>
<body>
<canvas id="chartJSContainer"></canvas>
<script>
const labels = ["A","B","C","D","E","F","G","H","I","J"];
const data = {
labels: labels,
datasets: [
{
label: 'Dataset 1',
data: [-92, -100, -99, -86, 8, 56, -94, -89, -92, -24],
borderColor: 'transparent',
backgroundColor: 'transparent',
order: 1
},
{
label: 'Dataset 2',
data: [-92, -100, -99, -86, 8, 56, -94, -89, -92, -24],
borderColor: 'black',
backgroundColor: 'blue',
type: 'line',
order: 0
}
]
};
const config = {
type: 'bar',
data: data,
options: {
responsive: true,
plugins: {
legend: {
display: false
},
title: {
display: false
}
},
scales: {
y: {
min: -100,
max: 100
}
}
}
};
var chart = new Chart(document.getElementById('chartJSContainer'), config);
</script>
</body>
</html>
How can I add the same x-axis labels on the top of the graph too and add new labels on the left of the graph too. See capture attached. Thanks.
What I'm looking for
For the X axis on top you can just add another X axis and set position to top, for the labels between the Y axis best is to write a custom plugin for that.
Example:
var options = {
type: 'line',
data: {
labels: ["A", "B", "C", "D", "E", "F"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
x: {
position: 'bottom',
grid: {
offset: true // offset true to get labels in between the lines instead of on the lines
}
},
x2: {
position: 'top',
grid: {
offset: true // offset true to get labels in between the lines instead of on the lines
}
},
y: {
ticks: {
count: (context) => (context.scale.chart.data.labels.length + 1)
}
}
},
plugins: {
labelsY: {
font: 'Arial',
size: '14px',
color: '#666',
align: 'right',
reverseLabels: false // true to make A start at top and F at bottom
}
}
},
plugins: [{
id: 'labelsY',
afterDraw: (chart, args, options) => {
const {
ctx,
scales: {
y,
x
},
data: {
labels
}
} = chart;
let dupLabels = JSON.parse(JSON.stringify(labels)); // remove pointer to internal labels array so you dont get glitchy behaviour
if (options.reverseLabels) {
dupLabels = dupLabels.reverse();
}
dupLabels.forEach((label, i) => {
ctx.save();
ctx.textAlign = options.align || 'right';
ctx.font = `${options.size || '20px'} ${options.font || 'Arial'}`;
ctx.fillStyle = options.color || 'black'
let xPos = x.getPixelForValue(labels[0]) - ctx.measureText(label).width;
let yPos = (y.getPixelForValue(y.ticks[i].value) + y.getPixelForValue(y.ticks[i + 1].value)) / 2;
ctx.fillText(label, xPos, yPos)
ctx.restore();
});
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.0/chart.js"></script>
</body>

ChartJS adding shadow color to grid and custom x-axis labels

I'm using chartJS 2.6.0 with scatter. The code I use is as below:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="stylesheet" href="css/960.css" />
<title>OCA-Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
</head>
<body>
<div class="container_12">
<canvas id="linechart"></canvas>
<script>
var linedata = {
datasets: [{
fill: false,
lineTension: 0,
borderColor: "black",
borderWidth: [2,2,2,2,2,2,2,2,2,2],
pointBackgroundColor: ["blue", "blue","blue", "blue","blue", "blue","blue", "blue","blue", "blue"],
pointRadius: [5,5,5,5,5,5,5,5,5,5],
pointStyle: ["rect","rect","rect","rect","rect","rect","rect","rect","rect","rect"],
data: [
{x: 0.25, y: 80},
{x: 0.75, y: -14},
{x: 1.25, y: -46},
{x: 1.75, y: 30},
{x: 2.25, y: 14},
{x: 2.75, y: -20},
{x: 3.25, y: -72},
{x: 3.75, y: -56},
{x: 4.25, y: -24},
{x: 4.75, y: -52}
]
}]
};
var chartOptions = {
responsive: true,
maintainAspectRatio: true,
legend: {display: false},
gridLines :{
},
scales: {
yAxes: [{
ticks: {
beginAtZero: false,
max: 100,
min: -100
}
}],
xAxes: [{
ticks: {
display: false
}
}]
}
};
var lineID = document.getElementById("linechart").getContext("2d");
var lineChart = new Chart(lineID, {
type: "scatter",
data: linedata,
options: chartOptions
});
</script>
</body>
</html>
What I'm trying to do is to display some texts in the x-axis in the middle of every grid column like what the bar graph does see image Bar graph image
Also, I would like to add a color to the grid just between y-axis -30 and 20 like in the capture below HTML workaround
All I could do is do it in HTML by displaying tags below the graph and using margins and by also placing an image in the background to get what shows in image 2 but it is an ugly solution.
Any help would be appreciated thanks.
For both requirements you can write custom inline plugins.
Example:
var options = {
type: 'scatter',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [{
x: 0.25,
y: 80
},
{
x: 0.75,
y: -14
},
{
x: 1.25,
y: -46
},
{
x: 1.75,
y: 30
},
{
x: 2.25,
y: 14
},
{
x: 2.75,
y: -20
},
{
x: 3.25,
y: -72
},
{
x: 3.75,
y: -56
},
{
x: 4.25,
y: -24
},
{
x: 4.75,
y: -52
}
],
borderWidth: 1
}]
},
options: {
plugins: {
customText: {
text: ['hi', 'this', 'is', 'text', 'in', 'Mid', '!', ':)'],
size: '20px',
color: 'red',
font: 'Arial black'
},
backgrounds: {
hbars: [{
from: -28,
to: -80,
color: "rgb(195, 230, 195)"
},
{
from: 20,
to: 28,
color: "rgb(230, 220, 195)"
},
{
from: 0,
to: 20,
color: "rgb(230, 195, 195)"
}
]
}
}
},
plugins: [{
id: 'backgrounds',
beforeDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales
} = chart;
const y = scales['y-axis-1'];
const x = scales['y-axis-1'];
options.hbars.forEach((hBar) => {
ctx.save();
ctx.fillStyle = hBar.color;
ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
ctx.restore();
})
}
},
{
id: 'customText',
afterDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales
} = chart;
const y = scales['y-axis-1'];
const x = scales['x-axis-1'];
options.text.forEach((text, i) => {
ctx.save();
ctx.textAlign = 'center';
ctx.font = `${options.size || '20px'} ${options.font || 'Arial'}`;
ctx.fillStyle = options.color || 'black'
ctx.fillText(text, x.getPixelForValue((Number(x.ticks[0]) + Number(x.ticks[1])) / 2), y.getPixelForValue((Number(y.ticks[i]) + Number(y.ticks[i + 1])) / 2))
ctx.restore();
})
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>

charts js have a bar spanning negative/positive on y-axis

Is there a way in chartjs to have a bar span across the zero line? As an example,
lets say I have a bar with
data:[x:1, y:100]
How do I tell it to span the y-axis from -100 to 100 (instead of from 0 to 100)?
I have sort of a playground here where I can do either negative or positive per bar, but not both for one bar.
https://jsbin.com/dufonoceja/1/edit?js,output
This can be done since Chart.js v2.9.0, which now supports floating bars. Individual bars can now be specified with the syntax [min, max].
<html>
<head>
<title>Floating Bars</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div>
<canvas id="canvas" height="120"></canvas>
</div>
<script>
var chartData = {
labels: [1,2,3,4,5,6],
datasets: [{
type: 'bar',
label: 'Red Bar',
borderColor: 'black',
borderWidth: 1,
backgroundColor: 'rgba(128,0,0,0.2)',
data: [[0, 100], [-100, 100], [-30, 40], 0, 0, 0],
}, {
type: 'bar',
label: 'Green Bar',
backgroundColor: 'rgba(0,128,0,0.2)',
borderColor: 'black',
borderWidth: 1,
data: [0, 0, 0, 0, [-50, 70], 100],
}
]
};
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
scaleBeginAtZero: false,
responsive: true,
spanGaps: true,
tooltips: {
mode: 'index',
intersect: true
},
scales: {
xAxes: [{
gridLines: {
display: false
},
}],
yAxes: [{
type: 'linear',
ticks: {
beginAtZero: false,
min:-100,
max:100,
stepSize:30
}
}],
}
}
});
};
</script>
</body>
</html>