0

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)

Working Graph

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!

4
  • The problem is that you use an old format that is no longer valid to specify scale properties and thus the axis of type time is not activated and the default category type 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!). Replace xAxes: [{...}] with x: {...} and yAxes: [{...}] with y: {...}, see the migration guides. Commented Feb 25, 2024 at 16:35
  • You'll also have to configure a time adapter for the time axis to work. Commented Feb 25, 2024 at 16:35
  • Your updated code is probably again from an old incompatible version of chart.js. The type of 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. Commented Feb 25, 2024 at 23:28
  • Also, check browser console for errors and warnings and pos here if there are errors/warnings referring to chart.js and you don't see what changes are required to get rid of the message. "Not responding with anything" is typically associated with some important error messages. Commented Feb 25, 2024 at 23:29

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.