2021-11-29 17:39:58 +00:00
|
|
|
use std::f64::consts::TAU;
|
|
|
|
|
2021-02-14 20:39:04 +00:00
|
|
|
use egui::*;
|
2021-06-24 10:29:51 +00:00
|
|
|
use plot::{
|
2021-11-29 17:39:58 +00:00
|
|
|
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, Corner, HLine, Legend, Line, LineStyle,
|
|
|
|
MarkerShape, Plot, PlotImage, Points, Polygon, Text, VLine, Value, Values,
|
2021-06-24 10:29:51 +00:00
|
|
|
};
|
2021-02-14 20:39:04 +00:00
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
2021-05-27 16:40:20 +00:00
|
|
|
struct LineDemo {
|
2021-02-14 20:39:04 +00:00
|
|
|
animate: bool,
|
|
|
|
time: f64,
|
2021-04-24 12:26:54 +00:00
|
|
|
circle_radius: f64,
|
2021-02-14 20:39:04 +00:00
|
|
|
circle_center: Pos2,
|
|
|
|
square: bool,
|
|
|
|
proportional: bool,
|
2021-07-06 18:15:04 +00:00
|
|
|
line_style: LineStyle,
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
impl Default for LineDemo {
|
2021-02-14 20:39:04 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2021-06-24 13:20:31 +00:00
|
|
|
animate: !cfg!(debug_assertions),
|
2021-02-14 20:39:04 +00:00
|
|
|
time: 0.0,
|
2021-04-24 12:26:54 +00:00
|
|
|
circle_radius: 1.5,
|
2021-02-14 20:39:04 +00:00
|
|
|
circle_center: Pos2::new(0.0, 0.0),
|
|
|
|
square: false,
|
|
|
|
proportional: true,
|
2021-07-06 18:15:04 +00:00
|
|
|
line_style: LineStyle::Solid,
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
impl LineDemo {
|
2021-02-14 20:39:04 +00:00
|
|
|
fn options_ui(&mut self, ui: &mut Ui) {
|
|
|
|
let Self {
|
|
|
|
animate,
|
|
|
|
time: _,
|
|
|
|
circle_radius,
|
|
|
|
circle_center,
|
|
|
|
square,
|
|
|
|
proportional,
|
2021-07-06 18:15:04 +00:00
|
|
|
line_style,
|
2021-05-27 16:40:20 +00:00
|
|
|
..
|
2021-02-14 20:39:04 +00:00
|
|
|
} = self;
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.group(|ui| {
|
|
|
|
ui.vertical(|ui| {
|
|
|
|
ui.label("Circle:");
|
|
|
|
ui.add(
|
2021-03-27 15:09:09 +00:00
|
|
|
egui::DragValue::new(circle_radius)
|
2021-03-07 18:51:07 +00:00
|
|
|
.speed(0.1)
|
2021-06-24 10:29:51 +00:00
|
|
|
.clamp_range(0.0..=f64::INFINITY)
|
2021-03-07 18:51:07 +00:00
|
|
|
.prefix("r: "),
|
2021-02-14 20:39:04 +00:00
|
|
|
);
|
2021-03-07 18:51:07 +00:00
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.add(
|
2021-03-27 15:09:09 +00:00
|
|
|
egui::DragValue::new(&mut circle_center.x)
|
2021-03-07 18:51:07 +00:00
|
|
|
.speed(0.1)
|
|
|
|
.prefix("x: "),
|
|
|
|
);
|
|
|
|
ui.add(
|
2021-03-27 15:09:09 +00:00
|
|
|
egui::DragValue::new(&mut circle_center.y)
|
2021-03-07 18:51:07 +00:00
|
|
|
.speed(1.0)
|
|
|
|
.prefix("y: "),
|
|
|
|
);
|
|
|
|
});
|
2021-02-14 20:39:04 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.vertical(|ui| {
|
|
|
|
ui.style_mut().wrap = Some(false);
|
|
|
|
ui.checkbox(animate, "animate");
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.checkbox(square, "square view")
|
|
|
|
.on_hover_text("Always keep the viewport square.");
|
|
|
|
ui.checkbox(proportional, "Proportional data axes")
|
|
|
|
.on_hover_text("Tick are the same size on both axes.");
|
2021-08-28 10:19:35 +00:00
|
|
|
|
2021-07-06 18:15:04 +00:00
|
|
|
ComboBox::from_label("Line style")
|
|
|
|
.selected_text(line_style.to_string())
|
|
|
|
.show_ui(ui, |ui| {
|
2021-10-20 14:34:43 +00:00
|
|
|
for style in [
|
2021-07-06 18:15:04 +00:00
|
|
|
LineStyle::Solid,
|
|
|
|
LineStyle::dashed_dense(),
|
|
|
|
LineStyle::dashed_loose(),
|
|
|
|
LineStyle::dotted_dense(),
|
|
|
|
LineStyle::dotted_loose(),
|
|
|
|
]
|
|
|
|
.iter()
|
2021-10-20 14:34:43 +00:00
|
|
|
{
|
2021-07-06 18:15:04 +00:00
|
|
|
ui.selectable_value(line_style, *style, style.to_string());
|
2021-10-20 14:34:43 +00:00
|
|
|
}
|
2021-07-06 18:15:04 +00:00
|
|
|
});
|
|
|
|
});
|
2021-02-14 20:39:04 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
fn circle(&self) -> Line {
|
2021-02-14 20:39:04 +00:00
|
|
|
let n = 512;
|
|
|
|
let circle = (0..=n).map(|i| {
|
|
|
|
let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU);
|
2021-04-24 12:26:54 +00:00
|
|
|
let r = self.circle_radius;
|
2021-02-14 20:39:04 +00:00
|
|
|
Value::new(
|
|
|
|
r * t.cos() + self.circle_center.x as f64,
|
|
|
|
r * t.sin() + self.circle_center.y as f64,
|
|
|
|
)
|
|
|
|
});
|
2021-05-27 16:40:20 +00:00
|
|
|
Line::new(Values::from_values_iter(circle))
|
2021-02-14 20:39:04 +00:00
|
|
|
.color(Color32::from_rgb(100, 200, 100))
|
2021-07-06 18:15:04 +00:00
|
|
|
.style(self.line_style)
|
2021-02-14 20:39:04 +00:00
|
|
|
.name("circle")
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
fn sin(&self) -> Line {
|
2021-04-24 12:26:54 +00:00
|
|
|
let time = self.time;
|
2021-05-27 16:40:20 +00:00
|
|
|
Line::new(Values::from_explicit_callback(
|
2021-04-24 12:26:54 +00:00
|
|
|
move |x| 0.5 * (2.0 * x).sin() * time.sin(),
|
2021-06-24 10:29:51 +00:00
|
|
|
..,
|
2021-04-24 12:26:54 +00:00
|
|
|
512,
|
2021-05-27 16:40:20 +00:00
|
|
|
))
|
2021-04-24 12:26:54 +00:00
|
|
|
.color(Color32::from_rgb(200, 100, 100))
|
2021-07-06 18:15:04 +00:00
|
|
|
.style(self.line_style)
|
2021-05-10 15:06:50 +00:00
|
|
|
.name("wave")
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
fn thingy(&self) -> Line {
|
2021-04-24 12:26:54 +00:00
|
|
|
let time = self.time;
|
2021-05-27 16:40:20 +00:00
|
|
|
Line::new(Values::from_parametric_callback(
|
2021-04-24 12:26:54 +00:00
|
|
|
move |t| ((2.0 * t + time).sin(), (3.0 * t).sin()),
|
|
|
|
0.0..=TAU,
|
2021-05-27 16:40:20 +00:00
|
|
|
256,
|
|
|
|
))
|
2021-04-24 12:26:54 +00:00
|
|
|
.color(Color32::from_rgb(100, 150, 250))
|
2021-07-06 18:15:04 +00:00
|
|
|
.style(self.line_style)
|
2021-04-24 12:26:54 +00:00
|
|
|
.name("x = sin(2t), y = sin(3t)")
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
impl Widget for &mut LineDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
2021-02-14 20:39:04 +00:00
|
|
|
self.options_ui(ui);
|
|
|
|
if self.animate {
|
|
|
|
ui.ctx().request_repaint();
|
|
|
|
self.time += ui.input().unstable_dt.at_most(1.0 / 30.0) as f64;
|
|
|
|
};
|
2021-11-13 10:56:22 +00:00
|
|
|
let mut plot = Plot::new("lines_demo").legend(Legend::default());
|
2021-02-14 20:39:04 +00:00
|
|
|
if self.square {
|
|
|
|
plot = plot.view_aspect(1.0);
|
|
|
|
}
|
|
|
|
if self.proportional {
|
|
|
|
plot = plot.data_aspect(1.0);
|
|
|
|
}
|
2021-11-13 10:56:22 +00:00
|
|
|
plot.show(ui, |plot_ui| {
|
|
|
|
plot_ui.line(self.circle());
|
|
|
|
plot_ui.line(self.sin());
|
|
|
|
plot_ui.line(self.thingy());
|
|
|
|
})
|
2021-11-27 22:59:32 +00:00
|
|
|
.response
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct MarkerDemo {
|
|
|
|
fill_markers: bool,
|
|
|
|
marker_radius: f32,
|
2021-06-24 13:20:31 +00:00
|
|
|
automatic_colors: bool,
|
2021-05-27 16:40:20 +00:00
|
|
|
marker_color: Color32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for MarkerDemo {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
fill_markers: true,
|
|
|
|
marker_radius: 5.0,
|
2021-06-24 13:20:31 +00:00
|
|
|
automatic_colors: true,
|
|
|
|
marker_color: Color32::GREEN,
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MarkerDemo {
|
|
|
|
fn markers(&self) -> Vec<Points> {
|
|
|
|
MarkerShape::all()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, marker)| {
|
|
|
|
let y_offset = i as f32 * 0.5 + 1.0;
|
|
|
|
let mut points = Points::new(Values::from_values(vec![
|
|
|
|
Value::new(1.0, 0.0 + y_offset),
|
|
|
|
Value::new(2.0, 0.5 + y_offset),
|
|
|
|
Value::new(3.0, 0.0 + y_offset),
|
|
|
|
Value::new(4.0, 0.5 + y_offset),
|
|
|
|
Value::new(5.0, 0.0 + y_offset),
|
|
|
|
Value::new(6.0, 0.5 + y_offset),
|
|
|
|
]))
|
|
|
|
.name(format!("{:?}", marker))
|
|
|
|
.filled(self.fill_markers)
|
|
|
|
.radius(self.marker_radius)
|
|
|
|
.shape(marker);
|
|
|
|
|
2021-06-24 13:20:31 +00:00
|
|
|
if !self.automatic_colors {
|
2021-05-27 16:40:20 +00:00
|
|
|
points = points.color(self.marker_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
points
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Widget for &mut MarkerDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
|
|
|
ui.horizontal(|ui| {
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.checkbox(&mut self.fill_markers, "Fill");
|
2021-05-27 16:40:20 +00:00
|
|
|
ui.add(
|
|
|
|
egui::DragValue::new(&mut self.marker_radius)
|
|
|
|
.speed(0.1)
|
2021-06-24 10:29:51 +00:00
|
|
|
.clamp_range(0.0..=f64::INFINITY)
|
2021-06-24 13:20:31 +00:00
|
|
|
.prefix("Radius: "),
|
2021-05-27 16:40:20 +00:00
|
|
|
);
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.checkbox(&mut self.automatic_colors, "Automatic colors");
|
|
|
|
if !self.automatic_colors {
|
2021-05-27 16:40:20 +00:00
|
|
|
ui.color_edit_button_srgba(&mut self.marker_color);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-11-13 10:56:22 +00:00
|
|
|
let markers_plot = Plot::new("markers_demo")
|
2021-06-07 20:36:13 +00:00
|
|
|
.data_aspect(1.0)
|
|
|
|
.legend(Legend::default());
|
2021-11-27 22:59:32 +00:00
|
|
|
markers_plot
|
|
|
|
.show(ui, |plot_ui| {
|
|
|
|
for marker in self.markers() {
|
|
|
|
plot_ui.points(marker);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.response
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-16 21:13:22 +00:00
|
|
|
#[derive(Default, PartialEq)]
|
2021-06-07 20:36:13 +00:00
|
|
|
struct LegendDemo {
|
|
|
|
config: Legend,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LegendDemo {
|
|
|
|
fn line_with_slope(slope: f64) -> Line {
|
2021-06-24 10:29:51 +00:00
|
|
|
Line::new(Values::from_explicit_callback(move |x| slope * x, .., 100))
|
2021-06-07 20:36:13 +00:00
|
|
|
}
|
|
|
|
fn sin() -> Line {
|
2021-06-24 10:29:51 +00:00
|
|
|
Line::new(Values::from_explicit_callback(move |x| x.sin(), .., 100))
|
2021-06-07 20:36:13 +00:00
|
|
|
}
|
|
|
|
fn cos() -> Line {
|
2021-06-24 10:29:51 +00:00
|
|
|
Line::new(Values::from_explicit_callback(move |x| x.cos(), .., 100))
|
2021-06-07 20:36:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Widget for &mut LegendDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
|
|
|
let LegendDemo { config } = self;
|
|
|
|
|
2021-06-24 13:20:31 +00:00
|
|
|
egui::Grid::new("settings").show(ui, |ui| {
|
|
|
|
ui.label("Text style:");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
TextStyle::all().for_each(|style| {
|
|
|
|
ui.selectable_value(&mut config.text_style, style, format!("{:?}", style));
|
|
|
|
});
|
2021-06-07 20:36:13 +00:00
|
|
|
});
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.end_row();
|
|
|
|
|
|
|
|
ui.label("Position:");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
Corner::all().for_each(|position| {
|
|
|
|
ui.selectable_value(&mut config.position, position, format!("{:?}", position));
|
|
|
|
});
|
2021-06-07 20:36:13 +00:00
|
|
|
});
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.end_row();
|
|
|
|
|
|
|
|
ui.label("Opacity:");
|
|
|
|
ui.add(
|
|
|
|
egui::DragValue::new(&mut config.background_alpha)
|
|
|
|
.speed(0.02)
|
|
|
|
.clamp_range(0.0..=1.0),
|
|
|
|
);
|
|
|
|
ui.end_row();
|
2021-06-07 20:36:13 +00:00
|
|
|
});
|
2021-06-24 13:20:31 +00:00
|
|
|
|
2021-11-13 10:56:22 +00:00
|
|
|
let legend_plot = Plot::new("legend_demo").legend(*config).data_aspect(1.0);
|
2021-11-27 22:59:32 +00:00
|
|
|
legend_plot
|
|
|
|
.show(ui, |plot_ui| {
|
|
|
|
plot_ui.line(LegendDemo::line_with_slope(0.5).name("lines"));
|
|
|
|
plot_ui.line(LegendDemo::line_with_slope(1.0).name("lines"));
|
|
|
|
plot_ui.line(LegendDemo::line_with_slope(2.0).name("lines"));
|
|
|
|
plot_ui.line(LegendDemo::sin().name("sin(x)"));
|
|
|
|
plot_ui.line(LegendDemo::cos().name("cos(x)"));
|
|
|
|
})
|
|
|
|
.response
|
2021-06-07 20:36:13 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-24 10:29:51 +00:00
|
|
|
|
|
|
|
#[derive(PartialEq, Default)]
|
2022-01-15 12:59:52 +00:00
|
|
|
struct ItemsDemo {
|
|
|
|
texture: Option<egui::TextureHandle>,
|
|
|
|
}
|
2021-06-24 10:29:51 +00:00
|
|
|
|
|
|
|
impl Widget for &mut ItemsDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
|
|
|
let n = 100;
|
|
|
|
let mut sin_values: Vec<_> = (0..=n)
|
|
|
|
.map(|i| remap(i as f64, 0.0..=n as f64, -TAU..=TAU))
|
|
|
|
.map(|i| Value::new(i, i.sin()))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let line = Line::new(Values::from_values(sin_values.split_off(n / 2))).fill(-1.5);
|
|
|
|
let polygon = Polygon::new(Values::from_parametric_callback(
|
|
|
|
|t| (4.0 * t.sin() + 2.0 * t.cos(), 4.0 * t.cos() + 2.0 * t.sin()),
|
|
|
|
0.0..TAU,
|
|
|
|
100,
|
|
|
|
));
|
|
|
|
let points = Points::new(Values::from_values(sin_values))
|
|
|
|
.stems(-1.5)
|
|
|
|
.radius(1.0);
|
|
|
|
|
|
|
|
let arrows = {
|
|
|
|
let pos_radius = 8.0;
|
|
|
|
let tip_radius = 7.0;
|
|
|
|
let arrow_origins = Values::from_parametric_callback(
|
|
|
|
|t| (pos_radius * t.sin(), pos_radius * t.cos()),
|
|
|
|
0.0..TAU,
|
|
|
|
36,
|
|
|
|
);
|
|
|
|
let arrow_tips = Values::from_parametric_callback(
|
|
|
|
|t| (tip_radius * t.sin(), tip_radius * t.cos()),
|
|
|
|
0.0..TAU,
|
|
|
|
36,
|
|
|
|
);
|
|
|
|
Arrows::new(arrow_origins, arrow_tips)
|
|
|
|
};
|
2022-01-15 12:59:52 +00:00
|
|
|
|
|
|
|
let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
|
|
|
|
ui.ctx()
|
|
|
|
.load_texture("plot_demo", egui::ColorImage::example())
|
|
|
|
});
|
2021-06-24 10:29:51 +00:00
|
|
|
let image = PlotImage::new(
|
2022-01-15 12:59:52 +00:00
|
|
|
texture,
|
2021-06-24 10:29:51 +00:00
|
|
|
Value::new(0.0, 10.0),
|
2022-01-22 10:23:12 +00:00
|
|
|
5.0 * vec2(texture.aspect_ratio(), 1.0),
|
2021-06-24 10:29:51 +00:00
|
|
|
);
|
|
|
|
|
2021-06-28 08:51:06 +00:00
|
|
|
let plot = Plot::new("items_demo")
|
2021-06-24 10:29:51 +00:00
|
|
|
.legend(Legend::default().position(Corner::RightBottom))
|
|
|
|
.show_x(false)
|
|
|
|
.show_y(false)
|
|
|
|
.data_aspect(1.0);
|
2021-11-13 10:56:22 +00:00
|
|
|
plot.show(ui, |plot_ui| {
|
|
|
|
plot_ui.hline(HLine::new(9.0).name("Lines horizontal"));
|
|
|
|
plot_ui.hline(HLine::new(-9.0).name("Lines horizontal"));
|
|
|
|
plot_ui.vline(VLine::new(9.0).name("Lines vertical"));
|
|
|
|
plot_ui.vline(VLine::new(-9.0).name("Lines vertical"));
|
|
|
|
plot_ui.line(line.name("Line with fill"));
|
|
|
|
plot_ui.polygon(polygon.name("Convex polygon"));
|
|
|
|
plot_ui.points(points.name("Points with stems"));
|
|
|
|
plot_ui.text(Text::new(Value::new(-3.0, -3.0), "wow").name("Text"));
|
|
|
|
plot_ui.text(Text::new(Value::new(-2.0, 2.5), "so graph").name("Text"));
|
|
|
|
plot_ui.text(Text::new(Value::new(3.0, 3.0), "much color").name("Text"));
|
|
|
|
plot_ui.text(Text::new(Value::new(2.5, -2.0), "such plot").name("Text"));
|
|
|
|
plot_ui.image(image.name("Image"));
|
|
|
|
plot_ui.arrows(arrows.name("Arrows"));
|
|
|
|
})
|
2021-11-27 22:59:32 +00:00
|
|
|
.response
|
2021-11-13 10:56:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-16 21:13:22 +00:00
|
|
|
#[derive(Default, PartialEq)]
|
2021-11-27 22:59:32 +00:00
|
|
|
struct InteractionDemo {}
|
2021-11-13 10:56:22 +00:00
|
|
|
|
|
|
|
impl Widget for &mut InteractionDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
2021-11-27 22:59:32 +00:00
|
|
|
let plot = Plot::new("interaction_demo").height(300.0);
|
|
|
|
|
|
|
|
let InnerResponse {
|
|
|
|
response,
|
|
|
|
inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered),
|
|
|
|
} = plot.show(ui, |plot_ui| {
|
|
|
|
(
|
|
|
|
plot_ui.screen_from_plot(Value::new(0.0, 0.0)),
|
|
|
|
plot_ui.pointer_coordinate(),
|
|
|
|
plot_ui.pointer_coordinate_drag_delta(),
|
|
|
|
plot_ui.plot_bounds(),
|
|
|
|
plot_ui.plot_hovered(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.label(format!(
|
|
|
|
"plot bounds: min: {:.02?}, max: {:.02?}",
|
|
|
|
bounds.min(),
|
|
|
|
bounds.max()
|
|
|
|
));
|
|
|
|
ui.label(format!(
|
|
|
|
"origin in screen coordinates: x: {:.02}, y: {:.02}",
|
|
|
|
screen_pos.x, screen_pos.y
|
|
|
|
));
|
|
|
|
ui.label(format!("plot hovered: {}", hovered));
|
|
|
|
let coordinate_text = if let Some(coordinate) = pointer_coordinate {
|
|
|
|
format!("x: {:.02}, y: {:.02}", coordinate.x, coordinate.y)
|
2021-11-13 10:56:22 +00:00
|
|
|
} else {
|
|
|
|
"None".to_string()
|
|
|
|
};
|
|
|
|
ui.label(format!("pointer coordinate: {}", coordinate_text));
|
|
|
|
let coordinate_text = format!(
|
2021-11-27 22:59:32 +00:00
|
|
|
"x: {:.02}, y: {:.02}",
|
|
|
|
pointer_coordinate_drag_delta.x, pointer_coordinate_drag_delta.y
|
2021-11-13 10:56:22 +00:00
|
|
|
);
|
|
|
|
ui.label(format!(
|
|
|
|
"pointer coordinate drag delta: {}",
|
|
|
|
coordinate_text
|
|
|
|
));
|
2021-11-27 22:59:32 +00:00
|
|
|
|
|
|
|
response
|
2021-06-24 10:29:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 17:39:58 +00:00
|
|
|
#[derive(PartialEq, Eq)]
|
|
|
|
enum Chart {
|
|
|
|
GaussBars,
|
|
|
|
StackedBars,
|
|
|
|
BoxPlot,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Chart {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::GaussBars
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct ChartsDemo {
|
|
|
|
chart: Chart,
|
|
|
|
vertical: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ChartsDemo {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
vertical: true,
|
|
|
|
chart: Chart::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ChartsDemo {
|
|
|
|
fn bar_gauss(&self, ui: &mut Ui) -> Response {
|
|
|
|
let mut chart = BarChart::new(
|
|
|
|
(-395..=395)
|
|
|
|
.step_by(10)
|
|
|
|
.map(|x| x as f64 * 0.01)
|
|
|
|
.map(|x| {
|
|
|
|
(
|
|
|
|
x,
|
|
|
|
(-x * x / 2.0).exp() / (2.0 * std::f64::consts::PI).sqrt(),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
// The 10 factor here is purely for a nice 1:1 aspect ratio
|
|
|
|
.map(|(x, f)| Bar::new(x, f * 10.0).width(0.095))
|
|
|
|
.collect(),
|
|
|
|
)
|
|
|
|
.color(Color32::LIGHT_BLUE)
|
|
|
|
.name("Normal Distribution");
|
|
|
|
if !self.vertical {
|
|
|
|
chart = chart.horizontal();
|
|
|
|
}
|
|
|
|
|
|
|
|
Plot::new("Normal Distribution Demo")
|
|
|
|
.legend(Legend::default())
|
|
|
|
.data_aspect(1.0)
|
|
|
|
.show(ui, |plot_ui| plot_ui.bar_chart(chart))
|
|
|
|
.response
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bar_stacked(&self, ui: &mut Ui) -> Response {
|
|
|
|
let mut chart1 = BarChart::new(vec![
|
|
|
|
Bar::new(0.5, 1.0).name("Day 1"),
|
|
|
|
Bar::new(1.5, 3.0).name("Day 2"),
|
|
|
|
Bar::new(2.5, 1.0).name("Day 3"),
|
|
|
|
Bar::new(3.5, 2.0).name("Day 4"),
|
|
|
|
Bar::new(4.5, 4.0).name("Day 5"),
|
|
|
|
])
|
|
|
|
.width(0.7)
|
|
|
|
.name("Set 1");
|
|
|
|
|
|
|
|
let mut chart2 = BarChart::new(vec![
|
|
|
|
Bar::new(0.5, 1.0),
|
|
|
|
Bar::new(1.5, 1.5),
|
|
|
|
Bar::new(2.5, 0.1),
|
|
|
|
Bar::new(3.5, 0.7),
|
|
|
|
Bar::new(4.5, 0.8),
|
|
|
|
])
|
|
|
|
.width(0.7)
|
|
|
|
.name("Set 2")
|
|
|
|
.stack_on(&[&chart1]);
|
|
|
|
|
|
|
|
let mut chart3 = BarChart::new(vec![
|
|
|
|
Bar::new(0.5, -0.5),
|
|
|
|
Bar::new(1.5, 1.0),
|
|
|
|
Bar::new(2.5, 0.5),
|
|
|
|
Bar::new(3.5, -1.0),
|
|
|
|
Bar::new(4.5, 0.3),
|
|
|
|
])
|
|
|
|
.width(0.7)
|
|
|
|
.name("Set 3")
|
|
|
|
.stack_on(&[&chart1, &chart2]);
|
|
|
|
|
|
|
|
let mut chart4 = BarChart::new(vec![
|
|
|
|
Bar::new(0.5, 0.5),
|
|
|
|
Bar::new(1.5, 1.0),
|
|
|
|
Bar::new(2.5, 0.5),
|
|
|
|
Bar::new(3.5, -0.5),
|
|
|
|
Bar::new(4.5, -0.5),
|
|
|
|
])
|
|
|
|
.width(0.7)
|
|
|
|
.name("Set 4")
|
|
|
|
.stack_on(&[&chart1, &chart2, &chart3]);
|
|
|
|
|
|
|
|
if !self.vertical {
|
|
|
|
chart1 = chart1.horizontal();
|
|
|
|
chart2 = chart2.horizontal();
|
|
|
|
chart3 = chart3.horizontal();
|
|
|
|
chart4 = chart4.horizontal();
|
|
|
|
}
|
|
|
|
|
|
|
|
Plot::new("Stacked Bar Chart Demo")
|
|
|
|
.legend(Legend::default())
|
|
|
|
.data_aspect(1.0)
|
|
|
|
.show(ui, |plot_ui| {
|
|
|
|
plot_ui.bar_chart(chart1);
|
|
|
|
plot_ui.bar_chart(chart2);
|
|
|
|
plot_ui.bar_chart(chart3);
|
|
|
|
plot_ui.bar_chart(chart4);
|
|
|
|
})
|
|
|
|
.response
|
|
|
|
}
|
|
|
|
|
|
|
|
fn box_plot(&self, ui: &mut Ui) -> Response {
|
|
|
|
let yellow = Color32::from_rgb(248, 252, 168);
|
|
|
|
let mut box1 = BoxPlot::new(vec![
|
|
|
|
BoxElem::new(0.5, BoxSpread::new(1.5, 2.2, 2.5, 2.6, 3.1)).name("Day 1"),
|
|
|
|
BoxElem::new(2.5, BoxSpread::new(0.4, 1.0, 1.1, 1.4, 2.1)).name("Day 2"),
|
|
|
|
BoxElem::new(4.5, BoxSpread::new(1.7, 2.0, 2.2, 2.5, 2.9)).name("Day 3"),
|
|
|
|
])
|
|
|
|
.name("Experiment A");
|
|
|
|
|
|
|
|
let mut box2 = BoxPlot::new(vec![
|
|
|
|
BoxElem::new(1.0, BoxSpread::new(0.2, 0.5, 1.0, 2.0, 2.7)).name("Day 1"),
|
|
|
|
BoxElem::new(3.0, BoxSpread::new(1.5, 1.7, 2.1, 2.9, 3.3))
|
|
|
|
.name("Day 2: interesting")
|
|
|
|
.stroke(Stroke::new(1.5, yellow))
|
|
|
|
.fill(yellow.linear_multiply(0.2)),
|
|
|
|
BoxElem::new(5.0, BoxSpread::new(1.3, 2.0, 2.3, 2.9, 4.0)).name("Day 3"),
|
|
|
|
])
|
|
|
|
.name("Experiment B");
|
|
|
|
|
|
|
|
let mut box3 = BoxPlot::new(vec![
|
|
|
|
BoxElem::new(1.5, BoxSpread::new(2.1, 2.2, 2.6, 2.8, 3.0)).name("Day 1"),
|
|
|
|
BoxElem::new(3.5, BoxSpread::new(1.3, 1.5, 1.9, 2.2, 2.4)).name("Day 2"),
|
|
|
|
BoxElem::new(5.5, BoxSpread::new(0.2, 0.4, 1.0, 1.3, 1.5)).name("Day 3"),
|
|
|
|
])
|
|
|
|
.name("Experiment C");
|
|
|
|
|
|
|
|
if !self.vertical {
|
|
|
|
box1 = box1.horizontal();
|
|
|
|
box2 = box2.horizontal();
|
|
|
|
box3 = box3.horizontal();
|
|
|
|
}
|
|
|
|
|
|
|
|
Plot::new("Box Plot Demo")
|
|
|
|
.legend(Legend::default())
|
|
|
|
.show(ui, |plot_ui| {
|
|
|
|
plot_ui.box_plot(box1);
|
|
|
|
plot_ui.box_plot(box2);
|
|
|
|
plot_ui.box_plot(box3);
|
|
|
|
})
|
|
|
|
.response
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Widget for &mut ChartsDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
|
|
|
ui.label("Type:");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.selectable_value(&mut self.chart, Chart::GaussBars, "Histogram");
|
|
|
|
ui.selectable_value(&mut self.chart, Chart::StackedBars, "Stacked Bar Chart");
|
|
|
|
ui.selectable_value(&mut self.chart, Chart::BoxPlot, "Box Plot");
|
|
|
|
});
|
|
|
|
ui.label("Orientation:");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.selectable_value(&mut self.vertical, true, "Vertical");
|
|
|
|
ui.selectable_value(&mut self.vertical, false, "Horizontal");
|
|
|
|
});
|
|
|
|
match self.chart {
|
|
|
|
Chart::GaussBars => self.bar_gauss(ui),
|
|
|
|
Chart::StackedBars => self.bar_stacked(ui),
|
|
|
|
Chart::BoxPlot => self.box_plot(ui),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
#[derive(PartialEq, Eq)]
|
|
|
|
enum Panel {
|
|
|
|
Lines,
|
|
|
|
Markers,
|
2021-06-07 20:36:13 +00:00
|
|
|
Legend,
|
2021-11-29 17:39:58 +00:00
|
|
|
Charts,
|
2021-06-24 10:29:51 +00:00
|
|
|
Items,
|
2021-11-13 10:56:22 +00:00
|
|
|
Interaction,
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Panel {
|
|
|
|
fn default() -> Self {
|
2021-11-29 17:39:58 +00:00
|
|
|
Self::Charts
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Default)]
|
|
|
|
pub struct PlotDemo {
|
|
|
|
line_demo: LineDemo,
|
|
|
|
marker_demo: MarkerDemo,
|
2021-06-07 20:36:13 +00:00
|
|
|
legend_demo: LegendDemo,
|
2021-11-29 17:39:58 +00:00
|
|
|
charts_demo: ChartsDemo,
|
2021-06-24 10:29:51 +00:00
|
|
|
items_demo: ItemsDemo,
|
2021-11-13 10:56:22 +00:00
|
|
|
interaction_demo: InteractionDemo,
|
2021-05-27 16:40:20 +00:00
|
|
|
open_panel: Panel,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::Demo for PlotDemo {
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
"🗠 Plot"
|
|
|
|
}
|
|
|
|
|
2022-01-10 22:13:10 +00:00
|
|
|
fn show(&mut self, ctx: &Context, open: &mut bool) {
|
2021-10-07 19:39:04 +00:00
|
|
|
use super::View as _;
|
2021-05-27 16:40:20 +00:00
|
|
|
Window::new(self.name())
|
|
|
|
.open(open)
|
|
|
|
.default_size(vec2(400.0, 400.0))
|
2021-08-28 11:18:21 +00:00
|
|
|
.vscroll(false)
|
2021-05-27 16:40:20 +00:00
|
|
|
.show(ctx, |ui| self.ui(ui));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::View for PlotDemo {
|
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.horizontal(|ui| {
|
2021-05-27 16:40:20 +00:00
|
|
|
egui::reset_button(ui, self);
|
2021-06-24 13:20:31 +00:00
|
|
|
ui.collapsing("Instructions", |ui| {
|
|
|
|
ui.label("Pan by dragging, or scroll (+ shift = horizontal).");
|
|
|
|
if cfg!(target_arch = "wasm32") {
|
2021-11-13 10:56:22 +00:00
|
|
|
ui.label("Zoom with ctrl / ⌘ + pointer wheel, or with pinch gesture.");
|
2021-06-24 13:20:31 +00:00
|
|
|
} else if cfg!(target_os = "macos") {
|
|
|
|
ui.label("Zoom with ctrl / ⌘ + scroll.");
|
|
|
|
} else {
|
|
|
|
ui.label("Zoom with ctrl + scroll.");
|
|
|
|
}
|
|
|
|
ui.label("Reset view with double-click.");
|
|
|
|
ui.add(crate::__egui_github_link_file!());
|
|
|
|
});
|
2021-05-27 16:40:20 +00:00
|
|
|
});
|
|
|
|
ui.separator();
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Lines, "Lines");
|
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Markers, "Markers");
|
2021-06-07 20:36:13 +00:00
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Legend, "Legend");
|
2021-11-29 17:39:58 +00:00
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Charts, "Charts");
|
2021-06-24 10:29:51 +00:00
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Items, "Items");
|
2021-11-13 10:56:22 +00:00
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Interaction, "Interaction");
|
2021-05-27 16:40:20 +00:00
|
|
|
});
|
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
match self.open_panel {
|
|
|
|
Panel::Lines => {
|
|
|
|
ui.add(&mut self.line_demo);
|
|
|
|
}
|
|
|
|
Panel::Markers => {
|
|
|
|
ui.add(&mut self.marker_demo);
|
|
|
|
}
|
2021-06-07 20:36:13 +00:00
|
|
|
Panel::Legend => {
|
|
|
|
ui.add(&mut self.legend_demo);
|
|
|
|
}
|
2021-11-29 17:39:58 +00:00
|
|
|
Panel::Charts => {
|
|
|
|
ui.add(&mut self.charts_demo);
|
|
|
|
}
|
2021-06-24 10:29:51 +00:00
|
|
|
Panel::Items => {
|
|
|
|
ui.add(&mut self.items_demo);
|
|
|
|
}
|
2021-11-13 10:56:22 +00:00
|
|
|
Panel::Interaction => {
|
|
|
|
ui.add(&mut self.interaction_demo);
|
|
|
|
}
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
}
|