1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-30 05:10:03 -04:00

Improve plot item UX (#1816)

* initial work

* changelog entry

* fix CI

* Update egui/src/widgets/plot/items/values.rs

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>

* Update egui/src/widgets/plot/items/values.rs

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>

* derive 'FromIterator'

* remove `bytemuck` dependency again and remove borrowing plot points for now

* update doctest

* update documentation

* remove unnecessary numeric cast

* cargo fmt

* Update egui/src/widgets/plot/items/values.rs

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Sven Niederberger
2022-07-24 17:13:12 +02:00
committed by GitHub
parent cf591da1a0
commit 0bf9fc9428
14 changed files with 302 additions and 234 deletions

View File

@@ -116,17 +116,21 @@ impl super::View for ContextMenus {
impl ContextMenus {
fn example_plot(&self, ui: &mut egui::Ui) -> egui::Response {
use egui::plot::{Line, Value, Values};
use egui::plot::{Line, PlotPoints};
let n = 128;
let line = Line::new(Values::from_values_iter((0..=n).map(|i| {
use std::f64::consts::TAU;
let x = egui::remap(i as f64, 0.0..=n as f64, -TAU..=TAU);
match self.plot {
Plot::Sin => Value::new(x, x.sin()),
Plot::Bell => Value::new(x, 10.0 * gaussian(x)),
Plot::Sigmoid => Value::new(x, sigmoid(x)),
}
})));
let line = Line::new(
(0..=n)
.map(|i| {
use std::f64::consts::TAU;
let x = egui::remap(i as f64, 0.0..=n as f64, -TAU..=TAU);
match self.plot {
Plot::Sin => [x, x.sin()],
Plot::Bell => [x, 10.0 * gaussian(x)],
Plot::Sigmoid => [x, sigmoid(x)],
}
})
.collect::<PlotPoints>(),
);
egui::plot::Plot::new("example_plot")
.show_axes(self.show_axes)
.allow_drag(self.allow_drag)

View File

@@ -5,8 +5,8 @@ use egui::plot::{GridInput, GridMark};
use egui::*;
use plot::{
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, CoordinatesFormatter, Corner, HLine,
Legend, Line, LineStyle, MarkerShape, Plot, PlotImage, Points, Polygon, Text, VLine, Value,
Values,
Legend, Line, LineStyle, MarkerShape, Plot, PlotImage, PlotPoint, PlotPoints, Points, Polygon,
Text, VLine,
};
// ----------------------------------------------------------------------------
@@ -108,15 +108,17 @@ impl LineDemo {
fn circle(&self) -> Line {
let n = 512;
let circle = (0..=n).map(|i| {
let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU);
let r = self.circle_radius;
Value::new(
r * t.cos() + self.circle_center.x as f64,
r * t.sin() + self.circle_center.y as f64,
)
});
Line::new(Values::from_values_iter(circle))
let circle_points: PlotPoints = (0..=n)
.map(|i| {
let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU);
let r = self.circle_radius;
[
r * t.cos() + self.circle_center.x as f64,
r * t.sin() + self.circle_center.y as f64,
]
})
.collect();
Line::new(circle_points)
.color(Color32::from_rgb(100, 200, 100))
.style(self.line_style)
.name("circle")
@@ -124,7 +126,7 @@ impl LineDemo {
fn sin(&self) -> Line {
let time = self.time;
Line::new(Values::from_explicit_callback(
Line::new(PlotPoints::from_explicit_callback(
move |x| 0.5 * (2.0 * x).sin() * time.sin(),
..,
512,
@@ -136,7 +138,7 @@ impl LineDemo {
fn thingy(&self) -> Line {
let time = self.time;
Line::new(Values::from_parametric_callback(
Line::new(PlotPoints::from_parametric_callback(
move |t| ((2.0 * t + time).sin(), (3.0 * t).sin()),
0.0..=TAU,
256,
@@ -199,15 +201,15 @@ impl MarkerDemo {
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),
]))
let y_offset = i as f64 * 0.5 + 1.0;
let mut points = Points::new(vec![
[1.0, 0.0 + y_offset],
[2.0, 0.5 + y_offset],
[3.0, 0.0 + y_offset],
[4.0, 0.5 + y_offset],
[5.0, 0.0 + y_offset],
[6.0, 0.5 + y_offset],
])
.name(format!("{:?}", marker))
.filled(self.fill_markers)
.radius(self.marker_radius)
@@ -259,13 +261,25 @@ struct LegendDemo {
impl LegendDemo {
fn line_with_slope(slope: f64) -> Line {
Line::new(Values::from_explicit_callback(move |x| slope * x, .., 100))
Line::new(PlotPoints::from_explicit_callback(
move |x| slope * x,
..,
100,
))
}
fn sin() -> Line {
Line::new(Values::from_explicit_callback(move |x| x.sin(), .., 100))
Line::new(PlotPoints::from_explicit_callback(
move |x| x.sin(),
..,
100,
))
}
fn cos() -> Line {
Line::new(Values::from_explicit_callback(move |x| x.cos(), .., 100))
Line::new(PlotPoints::from_explicit_callback(
move |x| x.cos(),
..,
100,
))
}
fn ui(&mut self, ui: &mut Ui) -> Response {
@@ -327,7 +341,7 @@ impl CustomAxisDemo {
CustomAxisDemo::MINS_PER_DAY * min
}
let values = Values::from_explicit_callback(
let values = PlotPoints::from_explicit_callback(
move |x| 1.0 / (1.0 + (-2.5 * (x / CustomAxisDemo::MINS_PER_DAY - 2.0)).exp()),
days(0.0)..days(5.0),
100,
@@ -410,7 +424,7 @@ impl CustomAxisDemo {
}
};
let label_fmt = |_s: &str, val: &Value| {
let label_fmt = |_s: &str, val: &PlotPoint| {
format!(
"Day {d}, {h}:{m:02}\n{p:.2}%",
d = get_day(val.x),
@@ -458,13 +472,25 @@ impl Default for LinkedAxisDemo {
impl LinkedAxisDemo {
fn line_with_slope(slope: f64) -> Line {
Line::new(Values::from_explicit_callback(move |x| slope * x, .., 100))
Line::new(PlotPoints::from_explicit_callback(
move |x| slope * x,
..,
100,
))
}
fn sin() -> Line {
Line::new(Values::from_explicit_callback(move |x| x.sin(), .., 100))
Line::new(PlotPoints::from_explicit_callback(
move |x| x.sin(),
..,
100,
))
}
fn cos() -> Line {
Line::new(Values::from_explicit_callback(move |x| x.cos(), .., 100))
Line::new(PlotPoints::from_explicit_callback(
move |x| x.cos(),
..,
100,
))
}
fn configure_plot(plot_ui: &mut plot::PlotUi) {
@@ -519,28 +545,26 @@ impl ItemsDemo {
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()))
.map(|i| [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(
let line = Line::new(sin_values.split_off(n / 2)).fill(-1.5);
let polygon = Polygon::new(PlotPoints::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 points = Points::new(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(
let arrow_origins = PlotPoints::from_parametric_callback(
|t| (pos_radius * t.sin(), pos_radius * t.cos()),
0.0..TAU,
36,
);
let arrow_tips = Values::from_parametric_callback(
let arrow_tips = PlotPoints::from_parametric_callback(
|t| (tip_radius * t.sin(), tip_radius * t.cos()),
0.0..TAU,
36,
@@ -557,7 +581,7 @@ impl ItemsDemo {
});
let image = PlotImage::new(
texture,
Value::new(0.0, 10.0),
PlotPoint::new(0.0, 10.0),
5.0 * vec2(texture.aspect_ratio(), 1.0),
);
@@ -574,10 +598,10 @@ impl ItemsDemo {
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.text(Text::new(PlotPoint::new(-3.0, -3.0), "wow").name("Text"));
plot_ui.text(Text::new(PlotPoint::new(-2.0, 2.5), "so graph").name("Text"));
plot_ui.text(Text::new(PlotPoint::new(3.0, 3.0), "much color").name("Text"));
plot_ui.text(Text::new(PlotPoint::new(2.5, -2.0), "such plot").name("Text"));
plot_ui.image(image.name("Image"));
plot_ui.arrows(arrows.name("Arrows"));
})
@@ -600,7 +624,7 @@ impl InteractionDemo {
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.screen_from_plot(PlotPoint::new(0.0, 0.0)),
plot_ui.pointer_coordinate(),
plot_ui.pointer_coordinate_drag_delta(),
plot_ui.plot_bounds(),

View File

@@ -260,13 +260,16 @@ impl WidgetGallery {
}
fn example_plot(ui: &mut egui::Ui) -> egui::Response {
use egui::plot::{Line, Value, Values};
use egui::plot::{Line, PlotPoints};
let n = 128;
let line = Line::new(Values::from_values_iter((0..=n).map(|i| {
use std::f64::consts::TAU;
let x = egui::remap(i as f64, 0.0..=n as f64, -TAU..=TAU);
Value::new(x, x.sin())
})));
let line_points: PlotPoints = (0..=n)
.map(|i| {
use std::f64::consts::TAU;
let x = egui::remap(i as f64, 0.0..=n as f64, -TAU..=TAU);
[x, x.sin()]
})
.collect();
let line = Line::new(line_points);
egui::plot::Plot::new("example_plot")
.height(32.0)
.data_aspect(1.0)