Jump to content

Charting My Local Weather (with help from AI) ...


webtrekker

Recommended Posts

A good while ago, I coded my own web app to produce some nice-looking dials that showed me the current weather for locations all over the globe.

 

weather_station_dials.png.ae343be964d402946b571e52e470e90f.png

 

This week, I decided I'd like to have a weather charting app that pulled weather data (from the openweathermap.org API) for my location every hour of every day and produced charts of the data so that I had a historical record of the local weather.

 

Now then, although I'm quite capable of producing such an app, it is very time-consuming, so I thought I'd give ChatGPT AI a go at producing the code for me.

 

After numerous prompts to tweak things and get ChatGPT to correct its errors, it finally produced something worthwhile and capable of doing the job, with no actual code written by me!

 

What the code does is, it calls a PHP script every hour that retrieves the data (in JSON format) from openweathermap, parses it, adds a timestamp, then saves it as a CSV file on my server. To view the data logged so far, an HTML/JS file can be run in any browser that gets the CSV data from the server and produces charts of it using a JS script called 'chart.js.'

 

weather_station_charts.png.57cf4e8e647f44c68c74ece10903df4c.png

I'm logging data for Temperature, Humidity, Windspeed and Pressure, and these can be shown on 4 different charts using the Radio Buttons above the chart area. The charts can be zoomed and panned as needed, and a Tooltip appears when hovering over any data point to show the time and value of that point.

 

I've only logged 10 hours so far, but everything is working fine and, as time progresses, I will have some valuable data to look back on.

 

All in all, not bad for a FREE weather station that requires NO CODING! (Of course, your AI prompts need to be well-thought-out though, so previous coding knowledge is advantageous).

Edited by webtrekker
  • Like 1
Link to comment
Share on other sites

4 hours ago, Campion said:

Nice one @webtrekker , I'm a bit envious because I'm trying to teach myself some coding (in python) but only making slow progress. 

 

I've had a look at Python before but, as most of my interest lies in producing web apps, I decided to stick with PHP for the back-end (server-side) and HTML + JavaScript for the front-end (Client/Browser-side). It all depends on your end goals, really.

 

Mind you, I'm not saying I'm an expert in any of these languages, but I get by, and there's a ton of help and code-snippets on the net to make things easier. All of my work is done inside Notepad++ (no fancy IDE's for me!). I use 123Reg (previously TSO-Host) for webspace and simply edit my code in Notepad++ and upload it directly from there.

 

One thing I'm tending to use more and more is AI. I find ChatGPT is very good at writing code (PHP, JS, Python, ... you name it!) from prompts. I can then copy the code and paste it into NP++, upload it, and try running it in the browser. Any issues can usually be corrected with further prompts in ChatGPT to refine the code until it performs in the way I had intended.

 

With regard to JavaScript, there are many JS Libraries that can be included in your HTML to perform certain tasks, such as the charts produced in my Weather app, which uses chart.js to handle the donkey work.

 

Whatever language you decide to use for the back-end, I'd definitely say you need to learn JavaScript (as well as HTML, for the mark-up) on the front-end too. Of course, if your intention is to produce apps that execute outside of the browser environment, then you can learn any programming language, even BASIC. I've grown fond of web apps, though, as I can run them on any device anywhere in the world that has an internet connection. I once wrote a program for handling Gift Cards for my daughter's sweet shop. The app used PHP and MySQL Database to scan and record data from barcodes that had been printed on the cards. It ran in the Opera browser on the screen of the POS (Point-Of-Sale) till she had on the counter.

 

Anyway, I'm starting to bore even myself now, so I'll leave it there for the time being! 😉

 

[PS. A word of warning! When coding for the web, make sure any user input to your code (Client-side or Server-side) is properly 'Sanitized' before you upload the code. ChatGPT is particularly good at sanitizing PHP and JS code for you. I know it's extra work, but you don't want to learn the hard way by having all of your server files attacked and deleted, or corrupted!].

 

 

 

 

 

 

 

Edited by webtrekker
  • Like 1
Link to comment
Share on other sites

Here is ChatGPT in action...

 

I gave it a simple enough Prompt to produce a Biorhythm Chart -

 

bio_chart4.png.6a55a8780bda19988f0e70a3bd06b618.png

 

It eventually produced HTML and JS code, which I uploaded and ran in Firefox to produce the following Biorhythm Chart for Elvis Presley (8 Jan 1935)...

 

bio_chart1.png.6be6d9d7c611ae9a90d97f8e88c8438c.png

 

The curves can be toggled on/off using the coloured buttons in the Legend

 

bio_chart3.png.1dfda972c3349498e423dc9d833bc641.png

 

 

bio_chart2.png.0177f875dfe1d6971b85217a488aa119.png

 

 

It's as easy as that! (well, sort of) using just ChatGPT AI to write your code.

  • Like 1
Link to comment
Share on other sites

Here's the Biorhythm code for anyone interested in running it themselves ...

 

 

bio_chart.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Biorhythm Chart</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            overflow: hidden;
        }
        canvas {
            width: 100vw;
            height: 75vh;
        }
        form {
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <h1>Biorhythm Chart</h1>
    <form id="dob-form">
        <label for="dob">Enter your date of birth:</label>
        <input type="date" id="dob" name="dob" required>
        <button type="submit">Generate Chart</button>
    </form>
    <canvas id="biorhythmChart"></canvas>

    <script>
        document.getElementById('dob-form').addEventListener('submit', function(event) {
            event.preventDefault(); // Prevent form submission

            const dobInput = document.getElementById('dob').value;

            // Sanitize input
            if (!dobInput || !/^\d{4}-\d{2}-\d{2}$/.test(dobInput)) {
                alert('Please enter a valid date of birth.');
                return;
            }

            const dob = new Date(dobInput);
            if (isNaN(dob.getTime())) {
                alert('Invalid date. Please try again.');
                return;
            }

            const today = new Date();
            const dates = [];
            const physical = [];
            const emotional = [];
            const intellectual = [];

            for (let i = 0; i < 30; i++) {
                const currentDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + i);
                dates.push(currentDate.toISOString().split('T')[0]);

                const daysAlive = Math.floor((currentDate - dob) / (1000 * 60 * 60 * 24));

                physical.push(Math.sin((2 * Math.PI * daysAlive) / 23));
                emotional.push(Math.sin((2 * Math.PI * daysAlive) / 28));
                intellectual.push(Math.sin((2 * Math.PI * daysAlive) / 33));
            }

            const ctx = document.getElementById('biorhythmChart').getContext('2d');
            new Chart(ctx, {
                type: 'line', // Changed chart type to 'line' which supports filling the area
                data: {
                    labels: dates,
                    datasets: [
                        {
                            label: 'Physical',
                            data: physical,
                            borderColor: 'red',
                            backgroundColor: 'rgba(255, 0, 0, 0.2)', // Filled area with semi-transparent color
                            fill: true,
                            tension: 0.1
                        },
                        {
                            label: 'Emotional',
                            data: emotional,
                            borderColor: 'blue',
                            backgroundColor: 'rgba(0, 0, 255, 0.2)', // Filled area with semi-transparent color
                            fill: true,
                            tension: 0.1
                        },
                        {
                            label: 'Intellectual',
                            data: intellectual,
                            borderColor: 'green',
                            backgroundColor: 'rgba(0, 255, 0, 0.2)', // Filled area with semi-transparent color
                            fill: true,
                            tension: 0.1
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            title: {
                                display: true,
                                text: 'Date'
                            },
                            ticks: {
                                autoSkip: true,
                                maxRotation: 45,
                                minRotation: 45,
                                padding: 10  // Padding for the ticks to avoid overlap
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: 'Value'
                            },
                            suggestedMin: -1,
                            suggestedMax: 1
                        }
                    },
                    plugins: {
                        legend: {
                            position: 'top',
                        }
                    },
                    layout: {
                        padding: {
                            bottom: 40  // Increased padding to give more space for x-axis labels
                        }
                    }
                }
            });
        });
    </script>
</body>
</html>

 

  • Thanks 1
Link to comment
Share on other sites

I've added an 'Average' option to the Biorhythm chart which averages the 3 curves for each day and plots a new curve (Black, dashed).

 

I've also reformatted the X-axis labels to make them easier to read.

 

Here's the complete code for anyone interested ...

 

bio_chart.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Biorhythm Chart</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/moment.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            overflow: hidden;
        }
        canvas {
            width: 100vw;
            height: 75vh;
        }
        form {
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <h1>Biorhythm Chart</h1>
    <form id="dob-form">
        <label for="dob">Enter your date of birth:</label>
        <input type="date" id="dob" name="dob" required>
        <button type="submit">Generate Chart</button>
    </form>
    <canvas id="biorhythmChart"></canvas>

    <script>
        document.getElementById('dob-form').addEventListener('submit', function(event) {
            event.preventDefault(); // Prevent form submission

            const dobInput = document.getElementById('dob').value;

            // Input sanitization
            if (!dobInput || !/\d{4}-\d{2}-\d{2}/.test(dobInput)) {
                alert('Please enter a valid date in the format YYYY-MM-DD.');
                return;
            }

            const dob = new Date(dobInput);
            if (isNaN(dob.getTime())) {
                alert('Invalid date. Please try again.');
                return;
            }

            const today = new Date();
            const dates = [];
            const physical = [];
            const emotional = [];
            const intellectual = [];
            const average = [];

            for (let i = 0; i < 30; i++) {
                const currentDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + i);
                const formattedDate = moment(currentDate).format('YYYY-MM-DD'); // Properly formatted date
                dates.push(formattedDate);

                const daysAlive = Math.floor((currentDate - dob) / (1000 * 60 * 60 * 24));

                const phys = Math.sin((2 * Math.PI * daysAlive) / 23);
                const emo = Math.sin((2 * Math.PI * daysAlive) / 28);
                const intel = Math.sin((2 * Math.PI * daysAlive) / 33);

                physical.push(phys);
                emotional.push(emo);
                intellectual.push(intel);

                // Calculate the average
                average.push((phys + emo + intel) / 3);
            }

            const ctx = document.getElementById('biorhythmChart').getContext('2d');

            new Chart(ctx, {
                type: 'line',
                data: {
                    labels: dates, // Dates formatted in ISO 8601
                    datasets: [
                        {
                            label: 'Physical',
                            data: physical,
                            borderColor: 'red',
                            backgroundColor: 'rgba(255, 0, 0, 0.2)',
                            fill: true,
                            tension: 0.1
                        },
                        {
                            label: 'Emotional',
                            data: emotional,
                            borderColor: 'blue',
                            backgroundColor: 'rgba(0, 0, 255, 0.2)',
                            fill: true,
                            tension: 0.1
                        },
                        {
                            label: 'Intellectual',
                            data: intellectual,
                            borderColor: 'green',
                            backgroundColor: 'rgba(0, 255, 0, 0.2)',
                            fill: true,
                            tension: 0.1
                        },
                        {
                            label: 'Average',
                            data: average,
                            borderColor: 'black',
                            borderDash: [5, 5], // Dashed line for average
                            fill: false,
                            tension: 0.1
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            type: 'time', // Set x-axis as time
                            time: {
                                parser: 'YYYY-MM-DD', // Parse input dates correctly
                                unit: 'day',
                                displayFormats: {
                                    day: 'MMM D' // Format for x-axis labels (e.g., Dec 13)
                                }
                            },
                            title: {
                                display: true,
                                text: 'Date'
                            },
                            ticks: {
                                autoSkip: true,
                                maxRotation: 45,
                                minRotation: 45,
                                padding: 10
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: 'Value'
                            },
                            suggestedMin: -1,
                            suggestedMax: 1,
                            grid: {
                                drawOnChartArea: true,
                                color: (context) => {
                                    return context.tick.value === 0 ? 'black' : 'rgba(0, 0, 0, 0.1)';
                                },
                                lineWidth: (context) => {
                                    return context.tick.value === 0 ? 2 : 1;
                                }
                            }
                        }
                    },
                    plugins: {
                        legend: {
                            position: 'top',
                        }
                    },
                    layout: {
                        padding: {
                            bottom: 40
                        }
                    }
                }
            });
        });
    </script>
</body>
</html>

 

The result (current Biorhythm for Nikola Tesla 😀) ...

 

Tesla_bio_chart.png.30694a0cb313dc6ee6e864f396aba7ca.png

Edited by webtrekker
  • Thanks 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...