shaunlowis / rocketeering

Building a customised 1/4 scale patriot rocket
MIT License
1 stars 0 forks source link

Visualise collected data #8

Open shaunlowis opened 1 month ago

shaunlowis commented 1 month ago

Doing a Rust backend and javascript frontend could be quite cool, here's what ChatGPT had to say:

Integrating Rust with a web interface for live plotting is a great way to make your data visualization accessible and interactive. You can achieve this by using Rust for the backend, serving the live data, and a JavaScript library like Plotly.js or Chart.js for rendering the live plots in a web browser.

Here’s a guide on how to do this with Rust using the Rocket web framework (for the backend) and Plotly.js (for the frontend).

1. Setup Rocket Web Framework

First, you'll need to install Rocket, a fast and flexible web framework for Rust.

In Cargo.toml:

Add the dependencies for Rocket and Serde (for serialization) in your Cargo.toml:

[dependencies]
rocket = { version = "0.5.0-rc.2", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }

2. Backend: Serving Live Data

We’ll create a simple REST API endpoint that streams live data to the frontend. In a real-world scenario, this data would come from the radio link, but we’ll simulate it here.

src/main.rs:

#[macro_use] extern crate rocket;

use rocket::serde::{Serialize, json::Json};
use std::{thread, time::Duration};

// Simulated data point
#[derive(Serialize)]
struct DataPoint {
    x: u32,
    y: u32,
}

// API route that simulates live data
#[get("/live_data")]
fn live_data() -> Json<DataPoint> {
    // Simulate generating data
    let mut x = 0;
    let y = (x * x) % 100;
    x += 1;
    thread::sleep(Duration::from_millis(100));  // Simulate data delay
    Json(DataPoint { x, y })
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![live_data])
}

This backend will serve live data in JSON format whenever the client (frontend) requests it.

3. Frontend: Plotting with Plotly.js

Now, create a simple HTML file that will request the data from the backend and plot it using Plotly.js.

static/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Live Plot</title>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
    <h1>Live Data Plot</h1>
    <div id="plot" style="width: 600px; height: 400px;"></div>

    <script>
        const trace1 = {
            x: [],
            y: [],
            mode: 'lines+markers',
            type: 'scatter'
        };

        const data = [trace1];
        Plotly.newPlot('plot', data);

        // Function to fetch live data and update plot
        async function fetchDataAndPlot() {
            try {
                const response = await fetch("/live_data");
                const dataPoint = await response.json();
                trace1.x.push(dataPoint.x);
                trace1.y.push(dataPoint.y);
                Plotly.update('plot', { x: [trace1.x], y: [trace1.y] });
            } catch (error) {
                console.error("Error fetching data:", error);
            }
        }

        // Fetch data every 1 second
        setInterval(fetchDataAndPlot, 1000);
    </script>
</body>
</html>

Explanation:

  1. HTML Structure:

    • We import the Plotly.js library, which allows us to create and update interactive plots in the browser.
    • A <div> with the id plot is where the plot will be rendered.
  2. JavaScript Code:

    • We create an empty trace object with x and y arrays and define it as a line plot.
    • The fetchDataAndPlot() function fetches data from the /live_data endpoint and pushes the new data points to the x and y arrays. It then calls Plotly.update() to refresh the plot with the new data.
    • We use setInterval() to fetch new data every second and update the plot continuously.

4. Serving Static Files with Rocket

Rocket can serve static files, so let’s modify the Rust backend to serve our index.html file.

src/main.rs (Extended):

#[macro_use] extern crate rocket;

use rocket::serde::{Serialize, json::Json};
use std::{thread, time::Duration};
use rocket::fs::FileServer;

// Simulated data point
#[derive(Serialize)]
struct DataPoint {
    x: u32,
    y: u32,
}

// API route that simulates live data
#[get("/live_data")]
fn live_data() -> Json<DataPoint> {
    let mut x = 0;
    let y = (x * x) % 100;
    x += 1;
    thread::sleep(Duration::from_millis(100));
    Json(DataPoint { x, y })
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![live_data])
        .mount("/", FileServer::from("static"))  // Serve static files from the "static" directory
}

Now, Rocket will serve your index.html file from the static/ directory when you open localhost:8000 in a browser, and the /live_data API will serve live data to update the plot.

5. Running the Application

  1. Create the static directory in your project folder and put index.html inside it.
  2. Build and run the Rocket app:
cargo run
  1. Open a browser and navigate to http://localhost:8000/. You should see the plot updating with live data every second.

6. Summary

You can modify the Rust code to get real data from your radio link or serial device and send it to the frontend, while Plotly.js will keep updating the graph.

Let me know if you'd like to dive deeper into any part or add more features!

shaunlowis commented 3 weeks ago

For Dry run, only plots of collected data is needed, not live data, so a simple python script is sufficient.