I'm prototyping and trying to create a code to use on Apache that will display data from multiple temperature sensors on a multi line chart. (in the feild the sensors will be reading values with more spread)
there is a file get_data.php that grabs the last 12 hours of readings with the sensor_name (which is a unique address) the temp value and timestamp that the server adds to the in coming data.
my problem is the code works, but the time axis X, is mixed up and it looks like the code is putting each sensor line after another, but if two or more points have the same values it jumps the line around. what can I do to make a normal multi line graph?
here is what the graph looks like, second image has some sensors removed
enter image description here enter image description here
[{"sensor_name":"28ff64182dd67d11","sensor_value":"18.62","timestamp":"2024-02-24 22:53:26"},{"sensor_name":"28f4403300000099","sensor_value":"19","timestamp":"2024-02-24 22:54:00"},{"sensor_name":"28f2aa310000004b","sensor_value":"19","timestamp":"2024-02-24 22:54:00"},{"sensor_name":"280eda3100000029","sensor_value":"19.06","timestamp":"2024-02-24 22:54:00"},{"sensor_name":"28ee2a33000000a1","sensor_value":"19","timestamp":"2024-02-24 22:54:01"},{"sensor_name":"286dce31000000d0","sensor_value":"19.06","timestamp":"2024-02-24 22:54:01"},{"sensor_name":"288b9533000000a9","sensor_value":"19.06","timestamp":"2024-02-24 22:54:01"},{"sensor_name":"283b333300000001","sensor_value":"18.81","timestamp":"2024-02-24 22:54:02"},{"sensor_name":"28ff64182dd67d11","sensor_value":"18.56","timestamp":"2024-02-24 22:58:34"},{"sensor_name":"28f4403300000099","sensor_value":"18.75","timestamp":"2024-02-24 22:59:09"},{"sensor_name":"28f2aa310000004b","sensor_value":"19","timestamp":"2024-02-24 22:59:10"},{"sensor_name":"280eda3100000029","sensor_value":"19","timestamp":"2024-02-24 22:59:10"},{"sensor_name":"28ee2a33000000a1","sensor_value":"19","timestamp":"2024-02-24 22:59:10"},{"sensor_name":"286dce31000000d0","sensor_value":"18.94","timestamp":"2024-02-24 22:59:10"},{"sensor_name":"288b9533000000a9","sensor_value":"19","timestamp":"2024-02-24 22:59:11"},{"sensor_name":"283b333300000001","sensor_value":"18.75","timestamp":"2024-02-24 22:59:11"},{"sensor_name":"28ff64182dd67d11","sensor_value":"18.5","timestamp":"2024-02-24 23:03:42"},{"sensor_name":"28f4403300000099","sensor_value":"18.75","timestamp":"2024-02-24 23:04:19"},{"sensor_name":"28f2aa310000004b","sensor_value":"19","timestamp":"2024-02-24 23:04:19"},{"sensor_name":"280eda3100000029","sensor_value":"18.87","timestamp":"2024-02-24 23:04:20"},{"sensor_name":"28ee2a33000000a1","sensor_value":"19","timestamp":"2024-02-24 23:04:20"},{"sensor_name":"286dce31000000d0","sensor_value":"18.87","timestamp":"2024-02-24 23:04:20"},{"sensor_name":"288b9533000000a9","sensor_value":"18.87","timestamp":"2024-02-24 23:04:21"},{"sensor_name":"283b333300000001","sensor_value":"18.62","timestamp":"2024-02-24 23:04:21"},{"sensor_name":"28ff64182dd67d11","sensor_value":"18.44","timestamp":"2024-02-24 23:08:50"},{"sensor_name":"28f4403300000099","sensor_value":"18.75","timestamp":"2024-02-24 23:09:29"},{"sensor_name":"28f2aa310000004b","sensor_value":"18.75","timestamp":"2024-02-24 23:09:30"},{"sensor_name":"280eda3100000029","sensor_value":"18.81","timestamp":"2024-02-24 23:09:30"},{"sensor_name":"28ee2a33000000a1","sensor_value":"18.75","timestamp":"2024-02-24 23:09:30"},{"sensor_name":"286dce31000000d0","sensor_value":"18.75","timestamp":"2024-02-24 23:09:31"},{"sensor_name":"288b9533000000a9","sensor_value":"18.75","timestamp":"2024-02-24 23:09:31"},{"sensor_name":"283b333300000001","sensor_value":"18.56","timestamp":"2024-02-24 23:09:32"},{"sensor_name":"28ff64182dd67d11","sensor_value":"18.37","timestamp":"2024-02-24 23:13:59"},{"sensor_name":"28f4403300000099","sensor_value":"18.75","timestamp":"2024-02-24 23:14:40"},{"sensor_name":"28f2aa310000004b","sensor_value":"18.75","timestamp":"2024-02-24 23:14:40"},{"sensor_name":"280eda3100000029","sensor_value":"18.69","timestamp":"2024-02-24 23:14:41"},]
here is the code that outputed the chart above
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Temperature Data</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div id="loadingIndicator">Loading data...</div>
<canvas id="temperatureChart" width="800" height="400"></canvas>
<script>
// Function to retrieve data from PHP script
function getData(callback) {
document.getElementById('loadingIndicator').style.display = 'block'; // Show loading indicator
fetch('get_data.php')
.then(response => {
if (!response.ok) {
throw new Error('Failed to fetch data');
}
return response.json();
})
.then(data => callback(data))
.catch(error => {
document.getElementById('loadingIndicator').style.display = 'none'; // Hide loading indicator
console.error('Error:', error);
// Handle error (e.g., display error message to user)
});
}
// Function to process data and create chart
function createChart(data) {
const datasets = {};
data.forEach(entry => {
if (!datasets[entry.sensor_name]) {
datasets[entry.sensor_name] = {
label: entry.sensor_name,
data: [],
borderColor: getRandomColor(),
fill: false
};
}
datasets[entry.sensor_name].data.push({
x: entry.timestamp, // Assuming timestamp is already in the correct format
y: entry.sensor_value
});
});
const ctx = document.getElementById('temperatureChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
datasets: Object.values(datasets)
},
options: {
scales: {
xAxes: [{
type: 'time', // Assuming timestamps are already in a valid time format
time: {
unit: 'minute',
stepSize: 5
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Temperature'
}
}]
}
}
});
document.getElementById('loadingIndicator').style.display = 'none'; // Hide loading indicator
}
// Function to generate random color
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
// Retrieve data and create chart
getData(createChart);
</script>
</body>
</html>
I'm expecting a normal multi line chart
kinda like this enter image description here
----- I have tried to update the code, now it is not responding with anything. thinking there is a deeper problem here that I can't figure out.
updated format and adapter
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Temperature Data</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div id="loadingIndicator">Loading data...</div>
<canvas id="temperatureChart" width="800" height="400"></canvas>
<script>
// Register time adapter for Chart.js
Chart.register({
id: 'custom-time',
beforeInit: function(chart, options) {
chart.data.labels = chart.data.labels.map(function(value) {
return new Date(value);
});
}
});
// Function to retrieve data from PHP script
function getData(callback) {
document.getElementById('loadingIndicator').style.display = 'block'; // Show loading indicator
fetch('get_data.php')
.then(response => {
if (!response.ok) {
throw new Error('Failed to fetch data');
}
return response.json();
})
.then(data => callback(data))
.catch(error => {
document.getElementById('loadingIndicator').style.display = 'none'; // Hide loading indicator
console.error('Error:', error);
// Handle error (e.g., display error message to user)
});
}
// Function to process data and create chart
function createChart(data) {
const datasets = {};
data.forEach(entry => {
if (!datasets[entry.sensor_name]) {
datasets[entry.sensor_name] = {
label: entry.sensor_name,
data: [],
borderColor: getRandomColor(),
fill: false
};
}
datasets[entry.sensor_name].data.push({
x: entry.timestamp, // Assuming timestamp is already in the correct format
y: entry.sensor_value
});
});
const ctx = document.getElementById('temperatureChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
datasets: Object.values(datasets)
},
options: {
scales: {
x: {
type: 'custom-time', // Use custom time adapter
time: {
unit: 'minute',
stepSize: 5
}
},
y: {
scaleLabel: {
display: true,
labelString: 'Temperature'
}
}
}
}
});
document.getElementById('loadingIndicator').style.display = 'none'; // Hide loading indicator
}
// Function to generate random color
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
// Retrieve data and create chart
getData(createChart);
</script>
</body>
</html>
----------FIXED Thanks to Kikon the code now works, they where right about they way it was writen. (I'll try to come back and mark as accepted, I mihgt be too new of a member atm)
code as it stands to get that resault
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Temperature Data</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@^3"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
</head>
<body>
<div id="loadingIndicator">Loading data...</div>
<canvas id="temperatureChart" width="800" height="400"></canvas>
<script>
// Function to retrieve data from PHP script
function getData(callback) {
document.getElementById('loadingIndicator').style.display = 'block'; // Show loading indicator
fetch('get_data.php')
.then(response => {
if (!response.ok) {
throw new Error('Failed to fetch data');
}
return response.json();
})
.then(data => callback(data))
.catch(error => {
document.getElementById('loadingIndicator').style.display = 'none'; // Hide loading indicator
console.error('Error:', error);
// Handle error (e.g., display error message to user)
});
}
// Function to process data and create chart
function createChart(data) {
const datasets = {};
data.forEach(entry => {
if (!datasets[entry.sensor_name]) {
datasets[entry.sensor_name] = {
label: entry.sensor_name,
data: [],
borderColor: getRandomColor(),
fill: false
};
}
datasets[entry.sensor_name].data.push({
x: moment(entry.timestamp), // Use moment to parse timestamp
y: entry.sensor_value
});
});
const ctx = document.getElementById('temperatureChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
datasets: Object.values(datasets)
},
options: {
scales: {
x: {
type: 'time', // Use time scale
time: {
unit: 'minute',
stepSize: 5
}
},
y: {
scaleLabel: {
display: true,
labelString: 'Temperature'
}
}
}
}
});
document.getElementById('loadingIndicator').style.display = 'none'; // Hide loading indicator
}
// Function to generate random color
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
// Retrieve data and create chart
getData(createChart);
</script>
</body>
</html>
Thanks Kikon!
timeis not activated and the defaultcategorytype scale is used, that puts the labels in the order in which they are first provided and not in time-order (check the labels on x axis- they are not in the correct order!). ReplacexAxes: [{...}]withx: {...}andyAxes: [{...}]withy: {...}, see the migration guides.typeof the x scale should be"time"and including an adapter means just adding one or two scripts after the chart.js one that are responsible for working with dates. Here is the script that has to be included for adapter chartjs-adapter-date-fns, amd here the two scripts for adapter moment. You only have to use one adapter; moment supports more formats.