Separating graphs in rust using egui, eframe, and plotters

234 views Asked by At

I'm working on a project where I need three graphs to appear in one window. I'm able to add a graph to the window, however when I try to add a second graph it seems like the two are overlapping.

the dependinces that I'm using are

egui = "0.22.0"
eframe = { version = "0.22.0", default-features = false, features = [
    "accesskit",
    "default_fonts",
    "glow",      
    "persistence",
] }
egui-plotter = "0.3"
log = "0.4"
plotters-backend = "0.3"
plotters = "0.3"
instant = { version = "0.1", features = ["wasm-bindgen"], optional = true }
serde = { version = "1", features = ["derive"] }
env_logger = "0.10"

the code I'm using

#![warn(clippy::all, rust_2018_idioms)]
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 

use std::time::Duration;

use eframe::egui::{self, CentralPanel, Visuals};
use egui::{Key, Slider, TopBottomPanel};
use egui_plotter::charts::TimeData;

const DISTANCE_M: [f32; 6] = [0.0, 2.0, 2.8, 3.4, 3.8, 4.0];
const TIME_S: [f32; 6] = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0];

fn main() {
    let native_options = eframe::NativeOptions::default();
    eframe::run_native(
        "TimeData Example",
        native_options,
        Box::new(|cc| Box::new(TimeDataExample::new(cc))), 
    )
    .unwrap();
}

struct TimeDataExample {
    timechart: TimeData,
    timechart1: TimeData,
}

impl TimeDataExample {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {
        let context = &cc.egui_ctx;

        context.tessellation_options_mut(|tess_options| {
            tess_options.feathering = false;
        });

        context.set_visuals(Visuals::light());

        let mut points: Vec<(f32, f32)> = Vec::with_capacity(DISTANCE_M.len());

        for (i, distance) in DISTANCE_M.iter().enumerate() {
            points.push((TIME_S[i], *distance));
        }

        let timechart = TimeData::new(&points, "meters", "Distance Over Time");

        let timechart1 = TimeData::new(&points, "meters", "Distance Over Time");

        Self { timechart, timechart1 }
    }
}

impl eframe::App for TimeDataExample {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        TopBottomPanel::bottom("playmenu").show(ctx, |ui| {
            ui.horizontal(|ui| {
                match self.timechart.is_playing() {
                    true => {
                        if ui.button("Pause").clicked() {
                            self.timechart.toggle_playback();
                        }
                    }
                    false => {
                        if ui.button("Play").clicked() {
                            self.timechart.toggle_playback();
                        }
                    }
                }

                let start_time = self.timechart.start_time();
                let current_time = self.timechart.current_time();
                let mut set_time = current_time;
                let end_time = self.timechart.end_time();
                let mut speed = self.timechart.get_playback_speed();

                let time_slider =
                    Slider::new(&mut set_time, start_time..=end_time).show_value(false);

                let speed_slider = Slider::new(&mut speed, 0.25..=4.0).logarithmic(true);

                ui.add(time_slider);
                ui.add(speed_slider);

                if set_time != current_time {
                    self.timechart.set_time(set_time);
                }

                self.timechart.set_playback_speed(speed);

                ui.label(format!("{} : {}", current_time, end_time));
            })
        });   

        CentralPanel::default().show(ctx, |ui| {
            
            ui.with_layout(egui::Layout::top_down(egui::Align::TOP), |ui| {
                self.timechart.draw(ui);

                self.timechart1.draw(ui);
            });     
        });

        if ctx.input(|input| input.key_pressed(Key::Space)) {
            self.timechart.toggle_playback();
        }

        std::thread::sleep(Duration::from_millis(10));
        ctx.request_repaint();
    }
}

When I run the program and click play I get this

I've tried adding ui.separator(); and text such as ui.heading("hello, world"); to separate the two graphs but it just appears at the top of both of the graphs.

example

CentralPanel::default().show(ctx, |ui| {
            
    ui.with_layout(egui::Layout::top_down(egui::Align::TOP), |ui| {
        self.timechart.draw(ui);

        ui.heading("hello, world!"); // replacing this with ui.separator(); seems to do nothing

        self.timechart1.draw(ui);
    });     
});

which gives me the result of this

I'm newer to the rust programming language and in the egui_plotter docs it seems to have an area over transformations with graphs, however I have no idea how to use it, I can't tell if it's applicable to my scenario, and I can't seem to find any reference material that uses it at all.

Much help would be appreciated because I have no idea what to do next.

0

There are 0 answers