How to create multiple y-axis time series chart - django

I am trying to map multiple charts where x-axis (time) is fixed but y-axis can take multiple values like CPU%, RAM, IO-RATE and so on. If I try to build individual graphs things seems pretty easy but I have this weird requirement where I need to map everything on to same chart. I have been trying out things with chartjs library and I could see that Cartesian axes is capable of handling multiple axes. But the examples I find around Cartesian mostly have x-axis with some fixed label values. In my case it's time and I wonder how to do the same for time series. I also found this example for multiple time series but that doesn't seem to create multiple y-axis. What is required is something like this but I am having hard time trying to figure out how to achieve this.
I am using django for backend and I am open to try out any library out there that does this and can easily integrate with django. Currently I have been exploring things with chartjs.

First you need to define a unique xAxis and define it as a time cartesian axis.
xAxes: [{
type: 'time',
time: {
unit: 'minute',
tooltipFormat: 'HH:mm:ss'
}
}],
Then you define a linear cartesian yAxis for each dataset and make sure, the value of the yAxis.id matches the corresponding dataset.yAxisID. Use 'yAxis.position' to define whether the axis shall appear left or right of the chart.
Optionally you may also define the following Plugin Core API beforeLayout function that makes sure that an yAxis is also hidden when it's data set is hidden through a mouse click on a legend label.
plugins: [{
beforeLayout: chart => chart.data.datasets.forEach((ds, i) => chart.config.options.scales.yAxes[i].display = !ds._meta[0].hidden)
}],
Please have a look at below runnable code snippet that illustrates how it can be done.
const now = new Date().getTime();
const timestamps = new Array(10).fill().map((v, i) => now - i * 60000).reverse();
new Chart('chart', {
type: 'line',
plugins: [{
beforeLayout: chart => chart.data.datasets.forEach((ds, i) => chart.config.options.scales.yAxes[i].display = !ds._meta[0].hidden)
}],
data: {
labels: timestamps,
datasets: [{
label: 'CPU',
yAxisID: 'yAxis-CPU',
data: [68, 70, 71, 72, 75, 75, 76, 77, 79, 76],
borderColor: 'red',
fill: false
},
{
label: 'RAM',
yAxisID: 'yAxis-RAM',
data: [22, 23, 23, 23, 22, 20, 22, 22, 23, 25],
borderColor: 'blue',
fill: false
},
{
label: 'IO-RATE',
yAxisID: 'yAxis-IO-RATE',
data: [0.5, 0.6, 0.7, 0.8, 0.8, 0.2, 0.1, 0.1, 0.2, 0.2],
borderColor: 'green',
fill: false
}
]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'minute',
displayFormats: {
minute: 'HH:mm'
},
tooltipFormat: 'HH:mm:ss'
}
}],
yAxes: [{
id: 'yAxis-CPU',
type: 'linear',
position: 'left',
scaleLabel: {
display: true,
labelString: 'CPU %'
},
gridLines : {
display: false
},
ticks: {
beginAtZero: true
}
},
{
id: 'yAxis-RAM',
type: 'linear',
position: 'left',
scaleLabel: {
display: true,
labelString: 'RAM %'
},
gridLines : {
display: false
},
ticks: {
beginAtZero: true
}
},
{
id: 'yAxis-IO-RATE',
type: 'linear',
position: 'right',
scaleLabel: {
display: true,
labelString: 'IO-Rate %'
},
gridLines : {
display: false
},
ticks: {
beginAtZero: true
}
}
]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="chart" height="90"></canvas>

Related

How to skip tick interval on chart.js x-axis?

I am working with Chart.js. I want to display every third tick and label on the chart.
With the code below, I am able to skip every third label not the interval/tick also.
I want to skip/remove the interval. Is it possible to skip the tick and interval without modifying the input data ?
I'll for thank full for any kind of inputs/help?
options: {
scales: {
xAxes: [{
autoSkip: false,
ticks: {
callback: function(tick, index, array) {
return (index % 3) ? "" : tick;
}
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
You can define the scriptable option options.scales.x.grid.tickColor as follows. This generates an array that specifies a color for every 3rd tick line only.
grid: {
tickColor: labels.map((l, i) => i % 3 ? null : 'lightgray')
}
For further information, consult Grid Line Configuration from the Chart.js documentation.
Please take a look at the runnable code below and see how it works.
const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
const data = [65, 59, 80, 81, 56, 55, 40];
new Chart('myChart', {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'My Dataset',
data: data,
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
},
options: {
scales: {
x: {
autoSkip: false,
grid: {
tickColor: labels.map((l, i) => i % 3 ? null : 'lightgray')
},
ticks: {
callback: (t, i) => i % 3 ? '' : labels[i]
},
},
y: {
beginAtZero: true
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="myChart" height="80"></canvas>

Draw stacked horizontal bar chart with Average line using ChartJS

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>

Chartjs: Why do I have 2 Y Axis labels?

My chart data is working, but I would like the Y axis to start below my lowest value and extend just a bit above the largest value and I was looking at the yAxes-> ticks-> min/max to do this. But when I add this to the options, a second second Y axis label is added with a scale of -1.0 to 1.0; I'm not sure how to get rid of that. I have attached some screen shots and some mocked up js code. Thanks
var chartData = {
labels: ['January', 'February', 'March'],
datasets: [{
type: 'line',
label: 'Dataset 1',
borderColor: 'blue',
borderWidth: 2,
fill: false,
data: [
85, 80, 75
]
}, {
type: 'bar',
label: 'Dataset 2',
backgroundColor: 'red',
data: [
90, 85, 80
],
borderColor: 'white',
borderWidth: 2
}, {
type: 'bar',
label: 'Dataset 3',
backgroundColor: 'green',
data: [
95, 90, 85
]
}]
};
var ctx = document.getElementById('canvas').getContext('2d');
window.myMixedChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
title: {
display: true,
text: 'A Funky Label'
},
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: false
}],
yAxes: [
{
ticks: {
max: 100,
min: 50,
stepSize: 10,
callback: function (value, index, values) {
return value + " HP";
}
}
},
{
stacked: false
}
]
},
layout: {
padding: {
left: 10,
right: 10,
top: 0,
bottom: 0
}
}
}
});
}
I discovered the answer:
I was trying to determine if I wanted a stacked bar chart or regular bar chart with multiple series chart. Anyway, after deciding to stick with the regular bar chart with multiple series I removed this from my options section:
stacked: false
Once removed the second Y axis disappeared

Chart with Time axis only displaying first grid line and tick label (unitStepSize)

I am trying to display a simple line chart of temperatures versus time. The dataset has temperatures and times in ten minute intervals. Times are in HH:mm format.
The graph is displaying correctly but only the left axis, right axis and first tick time value and grid line are displaying.
My data looks like this:
12:00 20.1
12:10 20.3
12:20 20.5
...
13:20 21
13:30 21.4
I get the left axis labelled as 12:00 then one label at 12:10 with grid line, and then nothing until 13:30 on the right axis.
If I leave out the unitStepSize I get ticks and gridlines every minute (crowded). So obviously I am missing something to do with this parameter.
var myChart = new Chart(ctx,
{
type: 'line',
data: data,
options :
{
responsive:false,
maintainAspectRatio: false,
scales:
{
xAxes: [
{
type: 'time',
scaleLabel:
{
display: true,
labelString: 'Time'
},
time:
{
unit: 'minute',
unitStepSize: '10',
format: "HH:mm",
displayFormats:
{
minute: 'HH:mm',
hour: 'HH:mm'
}
}
}],
yAxes: [
{
scaleLabel:
{
display: true,
labelString: 'Temp'
},
ticks: {
max: 25,
min: 15,
stepSize: 1
}
}]
}
}
});
The issue you are currently facing is causing because, you are passing the unitStepSize value as a string.
It should be a number, with no quotes ('') around it.
var ctx = document.querySelector('#canvas').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['12:00', '12:10', '12:20', '13:20', '13:30'],
datasets: [{
label: 'Temperatures',
data: [20, 21, 22, 21, 23],
backgroundColor: 'rgba(75,192,192, 0.4)',
borderColor: '#4bc0c0',
pointBackgroundColor: 'black',
tension: 0,
fill: false
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
scaleLabel: {
display: true,
labelString: 'Time'
},
time: {
unit: 'minute',
unitStepSize: 10,
format: "HH:mm",
displayFormats: {
minute: 'HH:mm',
hour: 'HH:mm'
}
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Temp'
},
ticks: {
max: 25,
min: 15,
stepSize: 1
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="canvas"></canvas>

How do I invert an y-axis using chart.js (v2.0-dev)

I am creating line charts with 2 y-axes. one of those axes has two datasets but both run from the range of 0-100. The higher number being the better one. The second y-axis is usually lower in range (often in the single digits) and the best result is 1.
How can I invert the second y-axis so that 1 is at the top of the chart?
(I will try to find a solution myself, but at 5k+ lines in chart.js, it might take a while )
Thanks ^_^
Dev 2.0 of chart js supports an option to reverse the ticks when setting up the axis so your declaration of the second axis would become
{
type: "invertedLinear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
display: true,
position: "right",
id: "y-axis-2",
ticks: {
reverse: true
},
// grid line settings
gridLines: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
}
}
Here it is in action https://jsfiddle.net/nwc8ys34/15/
Using v 2.7.0, and the following seems to work:
options: {
scales: {
yAxes: [{
ticks: {
reverse: true,
}
}]
}
}
In v3 the scale configs have been changed so the desired behaviour can be accomplished like so:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [40, 80, 100, 70, 60, 80],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange',
yAxisID: 'y2'
}
]
},
options: {
scales: {
y: {},
y2: {
position: 'right',
reverse: true
}
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
</body>
Chart.js 4:
datasets: [{
label: "Strength",
yAxisID: "y1",
data: mappedData.sigStrength
}, {
label: "Bars",
yAxisID: "y2",
data: mappedData.sigBars
}]
scales: {
y1: {
type: "linear",
display: true,
position: "left",
reverse: true
},
y2: {
type: "linear",
display: true,
position: "right",
ticks: {
stepSize: 1
}
}
},