ChartJs days of the week from numbers - chart.js

I have a chart were the data looks like this where X represents days of the week:
{x: 1, y: 18, r: 4.7614}
{x: 6, y: 17, r: 4.7619}
{x: 0, y: 16, r: 4.7657}
I'd like to rename the numbers to weekdays on the X axis (0: "Sunday", 1: "Monday") etc., but I can't figure it out.
My config looks like this: (but obviously not working).
Any help would be appreciated, thank you.
const config = {
type: "bubble",
data: data,
options: {
responsive: true,
scales: {
x: ["Sun", "Mon", "Thu", "Wen", "Tru", "Fri", "Sat"],
},
},
}

You can use the tickCallback to transform the value to whatever you like, easyest thing to do is make an array with all the weekDays and then use the value as an index like so:
const weekDays = ["Sun", "Mon", "Thu", "Wen", "Tru", "Fri", "Sat"];
const options = {
type: 'bubble',
data: {
datasets: [{
label: '# of Votes',
data: [{
x: 0,
y: 1,
r: 4
}, {
x: 1,
y: 1,
r: 4
}, {
x: 2,
y: 1,
r: 4
}, {
x: 3,
y: 1,
r: 4
}, {
x: 4,
y: 1,
r: 4
}, {
x: 5,
y: 1,
r: 4
}, {
x: 6,
y: 1,
r: 4
}],
backgroundColor: 'pink'
}]
},
options: {
scales: {
x: {
ticks: {
callback: (val) => (weekDays[val])
}
}
}
}
};
const 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.5.0/chart.js"></script>
</body>

Related

apexcharts draw line chart on top of scatter chart

Currently using "Scatter Charts" to display my xy coordinates, working great. Another requirement is to draw a line chart based on average numbers on top of the scatter chart. Is this possible?
Link to Scatter Charts - https://apexcharts.com/angular-chart-demos/scatter-charts/basic/
Sample graph -
Yes, you can draw mixed charts with ApexCharts. You even have a demo of what you are looking for: Line Scatter – ApexCharts.js
I put the demo here for convenience:
let options = {
series: [{
name: 'Points',
type: 'scatter',
data: [{
x: 1,
y: 2.14
}, {
x: 1.2,
y: 2.19
}, {
x: 1.8,
y: 2.43
}, {
x: 2.3,
y: 3.8
}, {
x: 2.6,
y: 4.14
}, {
x: 2.9,
y: 5.4
}, {
x: 3.2,
y: 5.8
}, {
x: 3.8,
y: 6.04
}, {
x: 4.55,
y: 6.77
}, {
x: 4.9,
y: 8.1
}, {
x: 5.1,
y: 9.4
}, {
x: 7.1,
y: 7.14
},{
x: 9.18,
y: 8.4
}]
}, {
name: 'Line',
type: 'line',
data: [{
x: 1,
y: 2
}, {
x: 2,
y: 3
}, {
x: 3,
y: 4
}, {
x: 4,
y: 5
}, {
x: 5,
y: 6
}, {
x: 6,
y: 7
}, {
x: 7,
y: 8
}, {
x: 8,
y: 9
}, {
x: 9,
y: 10
}, {
x: 10,
y: 11
}]
}],
chart: {
height: 350,
type: 'line'
},
fill: {
type: 'solid'
},
markers: {
size: [6, 0]
},
tooltip: {
shared: false,
intersect: true
},
legend: {
show: false
},
xaxis: {
type: 'numeric',
min: 0,
max: 12,
tickAmount: 12
}
};
let chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<div id="chart"></div>
This particular example has not been integrated using Angular, but I think you can do it quite easily. Take a look at this page if you need additional inspiration: Angular Mixed Chart / Combination Chart Examples – ApexCharts.js

ChartJS 2.9.4 can't overlay line data on Horizontal Bar chart

We have an issue where we can not overlay multiple graph types on top of each other with ChartJS 2.9.4 . We have narrowed this down specifically to HorizontalBar chart types.
I can't see what's wrong with the script code below, but the ChartJS persists in not showing anything when any line type is added. The current dual horizontalBar work perfectly.
Also frustratingly ChartJS seems to show by default to show no errors or notice information at all in any way to the console.
Solution attempts :
Lots of rearranging of layout, including ordering of data array.
Confirming all options and settings.
Putting "type" data in different areas (Chart/datasets/data)
Reading lots of Stack Overflow on vaguely related issues
Finding that the system does work with 'bar' rather than 'horizontalBar'
This question
Changing "drawing order"
Making it default to "line" and then setting HorizontalBar as the exception value (set within the data array)
Aim:
Code:
<script>
Chart.platform.disableCSSInjection = true;
var ctx = document.getElementById("historicChart");
var historicChart = new Chart(ctx, {
type: "horizontalBar",
data: {
labels: ["Mar 2017","Mar 2016","Mar 2015","Mar 2014","Mar 2013","Mar 2012","Mar 2011"],
datasets: [
{
type: "line",
label: "Visits",
data: ["3", "4", "1", "5", "6","0"],
pointBackgroundColor: '#FFC900',
pointRadius: 8,
pointStyle: 'circle',
showLine: true
},
{
label: "Applicants",
data: ["2","4","5","8","9","4","3"],
backgroundColor: "#436B94",
borderWidth: 0
},
{
label: "Intakes",
data: ["1","1","0","1","3","0","1"],
backgroundColor: "#C40500",
borderWidth: 0
}
]
},
options: {
scales: {
xAxes: [{
stacked: false,
ticks: {
stepSize: 1
}
}],
yAxes: [{
stacked: false
}]
}
}
}
);
</script>
<div class='graphbox'>
<h3>Applicants & Intakes over time</h3>
<canvas id="historicChart"></canvas>
</div>
How can I achieve this?
They fixed this issue in v3 so upgrading to that is 1 solution, the other one is downgrading to version 2.8, in a git issue on their repo someone posted a workaround but that only works till version 2.8.
V3:
HorizontalBar has been removed as a type, use bar chart instead and set the index axis to y in your options
Example:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
type: 'line',
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
indexAxis: 'y'
}
}
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.2.0/chart.js"></script>
</body>
V2 solutions, for if stuck on v2 with plugin support
To achieve this in 2.8 you will have to specify your data as objects and specify the x and y coordinates
Example:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
datasets: [{
label: "Clients Signed",
data: [2, 0, 3, 5, 1, 3, 6, 5, 3, 10]
}, {
label: "Quota",
data: [{
x: 2,
y: 'Q2 2015'
}, {
x: 2,
y: 'Q3 2015'
}, {
x: 2,
y: 'Q4 2015'
}, {
x: 2,
y: 'Q1 2016'
}, {
x: 2,
y: 'Q2 2016'
}, {
x: 2,
y: 'Q3 2016'
}, {
x: 2,
y: 'Q4 2016'
}, {
x: 2,
y: 'Q1 2017'
}, {
x: 2,
y: 'Q2 2017'
}, {
x: 2,
y: 'Q3 2017'
}],
type: 'line'
}],
labels: ["Q2 2015", "Q3 2015", "Q4 2015", "Q1 2016", "Q2 2016", "Q3 2016", "Q4 2016", "Q1 2017", "Q2 2017", "Q3 2017"]
},
options: {
barPercentage: 1.0,
categoryPercentage: 1.0
}
});
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
<script src="https://npmcdn.com/chart.js#2.8.0/dist/Chart.bundle.min.js"></script>
</body>
Git issue: https://github.com/chartjs/Chart.js/issues/4096

Render bars from multiple datasets at full-width when there is no overlapping data in ChartJS

Examples within. For reference, I am using the latest version of ChartJS (3.2.1) and the latest version of react-chartjs-2 (3.0.3).
I want to know how to make my bar chart display in a specific way given multiple, varying datasets. I'd like for the bars on the chart to render at their standard widths, while also allowing side-by-side overlapping where necessary.
ChartJS will handle this in my "ideal" way when you're using one dataset which may have two values that fall on the same X-Axis coordinate, but I can't seem to mimic this behavior when using multiple datasets.
It seems as though whenever two datasets share an axis, the bar widths either adjust to accommodate both sets of data even if they don't occupy the same space, or they stack on top of one another when should they occupy the same space. My goal is to only have the bars "shrink" their width when necessary, and keep their full-width otherwise.
Here is an example of what I would like to see with multiple datasets (this is how ChartJS handles the rendering when there is one dataset with barThickness: "flex" set):
In the middle, you'll notice the bar widths automatically adjusted to make room for one another.
Here is an example of what I get when I use two datasets that do not have any points where they overlap (barThickness: "flex" is set on both):
And, lastly, here is an example with some points of overlap when using two datasets:
So far the only way I've even sniffed a way around this is by creating multiple x-axes, one for one dataset, one for the other, and one for overlap. Then, by manipulating my data structures, creating datasets for each axis that contain exactly the datapoints that correspond to the desired bar widths.
That's certainly a solution, but I am dealing with a production codebase, thousands of rows of data, and several additional datasets (all of which have varying states, conditions for visibility, and rules). It becomes next-to-impossible to manage all of them together like this, let alone in a maintainable way. I've gone through the vast majority of StackOverflow questions and ChartJS documentation trying to find a cleaner solution, but have come up short thus far and would appreciate your help.
A simplified version of the code below. I've included some unused bits and pieces (mostly commented out) just to show the things I've tried thus far:
var ctx1 = document.getElementById("canvas1").getContext("2d");
var ctx2 = document.getElementById("canvas2").getContext("2d");
var ctx3 = document.getElementById("canvas3").getContext("2d");
function getBackgroundColor(data) {
const bar = data.dataset.data[data.dataIndex];
return bar.projection ? "green" : "black";
}
const dataset1Labels = ['Mar 2021', 'Apr 2021', 'May 2021', 'Jun 2021', 'Jul 2021', 'Aug 2021']
const dataset2Labels = ['Jan 2020', 'Feb 2020', 'Mar 2020', 'Apr 2020', ...dataset1Labels]
const dataset3Labels = ['Jan 2020', 'Feb 2020', 'Mar 2020', 'Apr 2020', 'May 2020', 'Jun 2020', 'Jul 2020', 'Aug 2020', ...dataset1Labels]
const dataset1 = [
{ x: "Mar 2021", y: 1, projection: false },
{ x: "Apr 2021", y: 4, projection: false },
{ x: "May 2021", y: 6, projection: false },
{ x: "May 2021", y: 9, projection: true },
{ x: "Jun 2021", y: 11, projection: true },
{ x: "Jul 2021", y: 13, projection: true },
{ x: "Aug 2021", y: 16, projection: true },
]
const dataset2 = [
{ x: "Jan 2020", y: 1 },
{ x: "Feb 2020", y: 4 },
{ x: "Mar 2020", y: 6 },
{ x: "Apr 2020", y: 8 },
{ x: "Mar 2021", y: 6 },
{ x: "Apr 2021", y: 8 },
]
const dataset3 = [
{ x: "Jan 2020", y: 1 },
{ x: "Feb 2020", y: 4 },
{ x: "Mar 2020", y: 6 },
{ x: "Apr 2020", y: 8 },
{ x: "May 2020", y: 10 },
{ x: "Jun 2020", y: 12 },
{ x: "Jul 2020", y: 12 },
{ x: "Aug 2020", y: 16 },
{ x: "Mar 2021", y: 1 },
{ x: "Apr 2021", y: 4 },
{ x: "May 2021", y: 6 },
]
var myChart = new Chart(ctx1, {
type: 'bar',
data: {
labels: dataset1Labels,
datasets: [{
label: "2 data types, distinguished by color",
data: dataset1,
backgroundColor: getBackgroundColor,
barThickness: "flex",
}]
},
options: {
plugins: {
title: {
display: true,
text: '1 dataset. Can Overlap. Full width bars.'
},
legend: {
position: "bottom",
},
},
scales: {
x: {
id: "dates",
offset: true,
},
}
}
});
var myChart2 = new Chart(ctx2, {
type: 'bar',
data: {
labels: dataset2Labels,
datasets: [
{
label: "previous year",
data: dataset2,
backgroundColor: "blue",
xAxisID: "dates",
},
{
label: "current year",
data: dataset1,
backgroundColor: "green",
},
]},
options: {
plugins: {
title: {
display: true,
text: '2 datasets. Cannot Overlap. Full width bars.'
},
legend: {
position: "bottom",
},
},
scales: {
x: {
id: "dates2",
display: false,
stacked: false,
bounds: "ticks",
grid: {
offset: true,
},
},
}
}
});
var myChart3 = new Chart(ctx3, {
type: 'bar',
data: {
labels: dataset3Labels,
datasets: [
{
label: "previous year",
data: dataset3,
backgroundColor: "blue",
// group: false,
// barThickness: "flex",
// categoryPercentage: 1,
// barPercentage: 1,
},
{
label: "current year",
data: dataset1,
backgroundColor: "green",
// group: false,
// categoryPercentage: 1,
// barThickness: "flex",
// barPercentage: 1,
},
]},
options: {
plugins: {
title: {
display: true,
text: '2 datasets. Can overlap. Half-width bars.'
},
legend: {
position: "bottom",
},
},
scales: {
x: {
id: "dates3",
display: false,
grid: {
offset: true,
},
},
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.2.1/dist/chart.min.js"></script>
<h2>Chart #1</h2>
<canvas id="canvas1"></canvas>
<h2>Chart #2</h2>
<p>Note that March and April 2021 both have data from both datasets, but only one dataset is visible</p>
<canvas id="canvas2"></canvas>
<h2>Chart #3</h2>
<canvas id="canvas3"></canvas>

Chart JS Logarithmic x-axis

I want to create a graph with the x-axis logarithmic. I took an example and changed the type to logarithmic. But I am getting all y values on the y-axis itself(see attached).But when I make y-axis logarithmic, It is works as expected. I am using chartjs version 2.9.3. When I used 2.8.0 there was no output.
This is my code:
<!doctype html>
<html>
<head>
<title>Logarithmic Line Chart</title>
<script src="/PHP/test/Chart.min.js"></script>
<script src="/PHP/test/utils.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div style="width:75%;">
<canvas id="canvas"></canvas>
</div>
<button id="randomizeData">Randomize Data</button>
<script>
var randomScalingFactor = function() {
return Math.ceil(Math.random() * 10.0) * Math.pow(10, Math.ceil(Math.random() * 5));
};
var config = {
type: 'line',
data: {
labels: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
datasets: [{
label: 'My First dataset',
backgroundColor: window.chartColors.red,
borderColor: window.chartColors.red,
fill: false,
data: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
},]
},
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Line Chart - Logarithmic'
},
scales: {
xAxes: [{
stacked:false,
display: true,
type:'logarithmic',
}],
yAxes: [{
stacked:false,
display: true,
}]
}
}
};
window.onload = function() {
var ctx = document.getElementById('canvas');
window.myLine = new Chart(ctx, config);
};
document.getElementById('randomizeData').addEventListener('click', function() {
config.data.datasets.forEach(function(dataset) {
dataset.data = dataset.data.map(function() {
return randomScalingFactor();
});
});
window.myLine.update();
});
</script>
</body>
</html>
If both axes are numeric the data needs to be provided as an array of points, i.e.:
[ { x: 111, y: 222 }, ... ]
From the documentation:
This alternate is used for sparse datasets, such as those in scatter charts. Each data point is specified using an object containing x and y properties.
Here's a working example from the posted code:
var config = {
type: 'line',
data: {
datasets: [{
label: 'My First dataset',
backgroundColor: 'red',
borderColor: 'red',
fill: false,
data: [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 4, y: 4 },
{ x: 5, y: 5 },
{ x: 6, y: 6 },
{ x: 7, y: 7 },
{ x: 8, y: 8 },
{ x: 9, y: 9 },
{ x: 10, y: 10 },
{ x: 11, y: 11 },
{ x: 12, y: 12 },
{ x: 13, y: 13 },
{ x: 14, y: 14 },
{ x: 15, y: 15 }
]
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Line Chart - Logarithmic'
},
scales: {
xAxes: [{
type: 'logarithmic'
}]
}
}
};
window.onload = function() {
var ctx = document.getElementById('canvas');
window.myLine = new Chart(ctx, config);
};
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3/dist/Chart.min.js"></script>
<canvas id="canvas"></canvas>

chart.js automatic x axis distributed in time milliseconds

I'm building a local html file that will generate some graphs using chartjs when offline. I'm just testing some example data I have.
See fiddle below.
http://jsfiddle.net/joshmoto/0odcemL7/
The issue is, i've set 8 points of data for each dataset, but the graph is only outputting 2 points for each dataset.
I need my x axis to display a automatic time grid distributed in seconds. My time data consists millisecond data, but my x axis grid needs to show steps in seconds. But my points must remain accurately positioned on the graph within the steps as the data is milliseconds.
.
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [{
t: new Date(0.37),
y: 2640
}, {
t: new Date(0.85),
y: 2560
}, {
t: new Date(1.33),
y: 2560
}, {
t: new Date(1.78),
y: 2560
}, {
t: new Date(2.23),
y: 2680
}, {
t: new Date(2.7),
y: 2920
}, {
t: new Date(3.16),
y: 3200
}, {
t: new Date(3.63),
y: 3520
}]
}, {
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [{
t: new Date(0.02),
y: 19.58
}, {
t: new Date(0.45),
y: 16.28
}, {
t: new Date(0.92),
y: 8.56
}, {
t: new Date(1.39),
y: 8.47
}, {
t: new Date(1.86),
y: 23.36
}, {
t: new Date(2.33),
y: 45.78
}, {
t: new Date(2.78),
y: 56.03
}, {
t: new Date(3.23),
y: 62.36
}]
}],
},
options: {
scales: {
// xAxes: [{
// type: 'time',
// displayFormats: {
// quarter: 'ss.SSS'
// },
// time: {
// unit: 'second'
// }
// }]
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="container">
<div class="col-12 mt-3 mb-3">
<canvas id="log_chart" width="600" height="200"></canvas>
</div>
</div>
Basically the data works like this...
t is the x axis but in time format seconds.
y is the value ranging from 0 - 5000
I'm trying my hardest to follow the docs but struggling to work this one out, I can't see anything obvious. If anyone can help out that would be awesome.
I think you need to provide more information to Chart.js so that it knows what to do with the X-Axis. On previous projects, I've given a labels property within the data.
Example -
// document ready
(function ($) {
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [1, 2, 3, 4, 5, 6, 7, 8],
datasets: [
{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [2640,2560,2560,2560, 2680, 2920, 3200, 3520]
},
{
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [19.58, 16.28, 8.56, 8.47, 23.36, 45.78, 56.03, 62.36]
}
],
},
options: {
scales: {
yAxes: [{
stacked: false
}],
}
}
});
})(jQuery);
So the labels property can then fill your X axis, and your data sets just plot the raw data onto the graph. The problem you'll run into with this kind of dataset is that the sensors readings are significantly lower than the engine speed, so not well represented on the chart. You'll have to work out some kind of way of normalising this data so it can be properly represented, e.g. adding a multiply to the mass airflow sensor readings.
I figured out using x axis type: linear; and removed the date functionality and just used the raw millisecond data in x rather than t.
See working example below.
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [{
x: 0.37,
y: 2640
}, {
x: 0.85,
y: 2560
}, {
x: 1.33,
y: 2560
}, {
x: 1.78,
y: 2560
}, {
x: 2.23,
y: 2680
}, {
x: 2.7,
y: 2920
}, {
x: 3.16,
y: 3200
}, {
x: 3.63,
y: 3520
}]
}, {
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [{
x: 0.02,
y: 19.58
}, {
x: 0.45,
y: 16.28
}, {
x: 0.92,
y: 8.56
}, {
x: 1.39,
y: 8.47
}, {
x: 1.86,
y: 23.36
}, {
x: 2.33,
y: 45.78
}, {
x: 2.78,
y: 56.03
}, {
x: 3.23,
y: 62.36
}]
}],
},
options: {
responsive: true,
title: {
display: true,
text: "Chart.js Time Scale"
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom'
}]
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="container">
<div class="col-12 mt-3 mb-3">
<canvas id="log_chart" width="600" height="200"></canvas>
</div>
</div>