out of order time points on multi line chart

34 Views Asked by At

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!

0

There are 0 best solutions below