From 556292367d44b8c50cd89c23d0d1cdf6ba74878d Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 15:58:50 +0100 Subject: [PATCH 01/26] y_inter --- egui_plot/src/items/mod.rs | 9 --------- egui_plot/src/items/series.rs | 2 +- egui_plot/src/lib.rs | 1 + egui_plot/src/math.rs | 8 ++++++++ 4 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 egui_plot/src/math.rs diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index a4e6b41b..32ba46e8 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -203,15 +203,6 @@ pub trait PlotItem { } } -// ---------------------------------------------------------------------------- - -/// Returns the x-coordinate of a possible intersection between a line segment -/// from `p1` to `p2` and a horizontal line at the given y-coordinate. -fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option { - ((p1.y > y && p2.y < y) || (p1.y < y && p2.y > y)) - .then_some(((y * (p1.x - p2.x)) - (p1.x * p2.y - p1.y * p2.x)) / (p1.y - p2.y)) -} - // ---------------------------------------------------------------------------- // Helper functions diff --git a/egui_plot/src/items/series.rs b/egui_plot/src/items/series.rs index edd9cdf7..2849ae95 100644 --- a/egui_plot/src/items/series.rs +++ b/egui_plot/src/items/series.rs @@ -14,7 +14,7 @@ use emath::Rect; use emath::pos2; use super::DEFAULT_FILL_ALPHA; -use super::y_intersection; +use crate::math::y_intersection; use crate::Id; use crate::LineStyle; use crate::PlotBounds; diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index a3e1078c..37ca4288 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -16,6 +16,7 @@ mod plot; mod plot_ui; mod transform; mod utils; +mod math; use std::cmp::Ordering; use std::ops::RangeInclusive; diff --git a/egui_plot/src/math.rs b/egui_plot/src/math.rs new file mode 100644 index 00000000..4525103d --- /dev/null +++ b/egui_plot/src/math.rs @@ -0,0 +1,8 @@ +use emath::Pos2; + +/// Returns the x-coordinate of a possible intersection between a line segment +/// from `p1` to `p2` and a horizontal line at the given y-coordinate. +pub fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option { + ((p1.y > y && p2.y < y) || (p1.y < y && p2.y > y)) + .then_some(((y * (p1.x - p2.x)) - (p1.x * p2.y - p1.y * p2.x)) / (p1.y - p2.y)) +} From ce700c2c97f908d9b4ba4091a50c67eb65db6eb1 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:01:11 +0100 Subject: [PATCH 02/26] colors --- egui_plot/src/colors.rs | 9 +++++++++ egui_plot/src/items/mod.rs | 8 -------- egui_plot/src/lib.rs | 1 + egui_plot/src/plot.rs | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 egui_plot/src/colors.rs diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs new file mode 100644 index 00000000..8cb76c5f --- /dev/null +++ b/egui_plot/src/colors.rs @@ -0,0 +1,9 @@ +use egui::{Color32, Ui}; + +pub(crate) fn rulers_color(ui: &Ui) -> Color32 { + if ui.visuals().dark_mode { + Color32::from_gray(100).additive() + } else { + Color32::from_black_alpha(180) + } +} \ No newline at end of file diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 32ba46e8..4f1dd7c4 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -206,14 +206,6 @@ pub trait PlotItem { // ---------------------------------------------------------------------------- // Helper functions -pub(crate) fn rulers_color(ui: &Ui) -> Color32 { - if ui.visuals().dark_mode { - Color32::from_gray(100).additive() - } else { - Color32::from_black_alpha(180) - } -} - pub(crate) fn vertical_line(pointer: Pos2, transform: &PlotTransform, line_color: Color32) -> Shape { let frame = transform.frame(); Shape::line_segment( diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 37ca4288..ff48ba4f 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -17,6 +17,7 @@ mod plot_ui; mod transform; mod utils; mod math; +mod colors; use std::cmp::Ordering; use std::ops::RangeInclusive; diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 664dc9ff..973c32e6 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -52,7 +52,7 @@ use crate::VPlacement; use crate::axis::AxisWidget; use crate::items; use crate::items::horizontal_line; -use crate::items::rulers_color; +use crate::colors::rulers_color; use crate::items::vertical_line; use crate::legend::LegendWidget; From 2938a7dcf9fbddf9b7ff83953fdd70b788fd0941 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:01:44 +0100 Subject: [PATCH 03/26] colors --- egui_plot/src/colors.rs | 19 ++++++++++++++++++- egui_plot/src/items/bar_chart.rs | 2 +- egui_plot/src/items/box_plot.rs | 2 +- egui_plot/src/items/rect_elem.rs | 20 -------------------- egui_plot/src/items/span.rs | 2 +- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs index 8cb76c5f..7677654a 100644 --- a/egui_plot/src/colors.rs +++ b/egui_plot/src/colors.rs @@ -1,4 +1,5 @@ -use egui::{Color32, Ui}; +use egui::{Color32, Rgba, Stroke, Ui}; +use emath::NumExt; pub(crate) fn rulers_color(ui: &Ui) -> Color32 { if ui.visuals().dark_mode { @@ -6,4 +7,20 @@ pub(crate) fn rulers_color(ui: &Ui) -> Color32 { } else { Color32::from_black_alpha(180) } +} + +pub(crate) fn highlighted_color(mut stroke: Stroke, fill: Color32) -> (Stroke, Color32) { + stroke.width *= 2.0; + + let mut fill = Rgba::from(fill); + if fill.is_additive() { + // Make slightly brighter + fill = 1.3 * fill; + } else { + // Make more opaque: + let fill_alpha = (2.0 * fill.a()).at_most(1.0); + fill = fill.to_opaque().multiply(fill_alpha); + } + + (stroke, fill.into()) } \ No newline at end of file diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index c08fe4c5..f3ce6a54 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -13,7 +13,7 @@ use emath::Pos2; use super::add_rulers_and_text; use super::find_closest_rect; use super::rect_elem::RectElement; -use super::rect_elem::highlighted_color; +use crate::colors::highlighted_color; use crate::ClosestElem; use crate::Cursor; use crate::Id; diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index fc0c780e..a9e88d5c 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -12,7 +12,7 @@ use emath::Pos2; use super::add_rulers_and_text; use super::find_closest_rect; use super::rect_elem::RectElement; -use super::rect_elem::highlighted_color; +use crate::colors::highlighted_color; use crate::ClosestElem; use crate::Cursor; use crate::Id; diff --git a/egui_plot/src/items/rect_elem.rs b/egui_plot/src/items/rect_elem.rs index 99afcd68..e31beb97 100644 --- a/egui_plot/src/items/rect_elem.rs +++ b/egui_plot/src/items/rect_elem.rs @@ -1,8 +1,3 @@ -use egui::emath::NumExt as _; -use egui::epaint::Color32; -use egui::epaint::Rgba; -use egui::epaint::Stroke; - use super::Orientation; use super::PlotPoint; use crate::transform::PlotBounds; @@ -61,18 +56,3 @@ pub(super) trait RectElement { // ---------------------------------------------------------------------------- // Helper functions -pub(super) fn highlighted_color(mut stroke: Stroke, fill: Color32) -> (Stroke, Color32) { - stroke.width *= 2.0; - - let mut fill = Rgba::from(fill); - if fill.is_additive() { - // Make slightly brighter - fill = 1.3 * fill; - } else { - // Make more opaque: - let fill_alpha = (2.0 * fill.a()).at_most(1.0); - fill = fill.to_opaque().multiply(fill_alpha); - } - - (stroke, fill.into()) -} diff --git a/egui_plot/src/items/span.rs b/egui_plot/src/items/span.rs index 191c6890..983ec4ad 100644 --- a/egui_plot/src/items/span.rs +++ b/egui_plot/src/items/span.rs @@ -22,7 +22,7 @@ use super::PlotItem; use super::PlotItemBase; use super::PlotPoint; use super::PlotTransform; -use super::rect_elem::highlighted_color; +use crate::colors::highlighted_color; use crate::Axis; use crate::utils::find_name_candidate; From 7d49158a4380461ab2a31ea4b98727e86e6c1d23 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:03:04 +0100 Subject: [PATCH 04/26] move rect elem --- egui_plot/src/items/bar_chart.rs | 2 +- egui_plot/src/items/box_plot.rs | 2 +- egui_plot/src/items/mod.rs | 3 +-- egui_plot/src/lib.rs | 5 +++-- egui_plot/src/{items => }/rect_elem.rs | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename egui_plot/src/{items => }/rect_elem.rs (100%) diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index f3ce6a54..93768d59 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -12,7 +12,7 @@ use emath::Pos2; use super::add_rulers_and_text; use super::find_closest_rect; -use super::rect_elem::RectElement; +use crate::rect_elem::RectElement; use crate::colors::highlighted_color; use crate::ClosestElem; use crate::Cursor; diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index a9e88d5c..776eb889 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -11,7 +11,7 @@ use emath::Pos2; use super::add_rulers_and_text; use super::find_closest_rect; -use super::rect_elem::RectElement; +use crate::rect_elem::RectElement; use crate::colors::highlighted_color; use crate::ClosestElem; use crate::Cursor; diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 4f1dd7c4..93296ec7 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -27,7 +27,7 @@ pub use line::VLine; pub use plot_image::PlotImage; pub use points::Points; pub use polygon::Polygon; -use rect_elem::RectElement; +use crate::rect_elem::RectElement; pub use series::Line; pub use span::Span; pub use text::Text; @@ -52,7 +52,6 @@ mod line; mod plot_image; mod points; mod polygon; -mod rect_elem; mod series; mod span; mod text; diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index ff48ba4f..a686439f 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -9,15 +9,16 @@ //! mod axis; +mod colors; mod items; mod legend; +mod math; mod memory; mod plot; mod plot_ui; +mod rect_elem; mod transform; mod utils; -mod math; -mod colors; use std::cmp::Ordering; use std::ops::RangeInclusive; diff --git a/egui_plot/src/items/rect_elem.rs b/egui_plot/src/rect_elem.rs similarity index 100% rename from egui_plot/src/items/rect_elem.rs rename to egui_plot/src/rect_elem.rs From a33c0d1e27d13b91f5fff32e246e64659b710536 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:04:30 +0100 Subject: [PATCH 05/26] wip values --- egui_plot/src/{items => }/values.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename egui_plot/src/{items => }/values.rs (100%) diff --git a/egui_plot/src/items/values.rs b/egui_plot/src/values.rs similarity index 100% rename from egui_plot/src/items/values.rs rename to egui_plot/src/values.rs From fbad11ea978b6998f45eb56716fa589cd9d66632 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:09:00 +0100 Subject: [PATCH 06/26] move values out of items --- egui_plot/src/items/arrows.rs | 4 ++-- egui_plot/src/items/bar_chart.rs | 8 ++++---- egui_plot/src/items/box_plot.rs | 8 ++++---- egui_plot/src/items/heatmap.rs | 6 +++--- egui_plot/src/items/line.rs | 6 +++--- egui_plot/src/items/mod.rs | 13 +++++-------- egui_plot/src/items/plot_image.rs | 4 ++-- egui_plot/src/items/points.rs | 8 ++++---- egui_plot/src/items/polygon.rs | 6 +++--- egui_plot/src/items/series.rs | 8 ++++---- egui_plot/src/items/text.rs | 4 ++-- egui_plot/src/lib.rs | 15 ++++++++------- egui_plot/src/plot.rs | 2 +- egui_plot/src/plot_ui.rs | 2 +- 14 files changed, 46 insertions(+), 48 deletions(-) diff --git a/egui_plot/src/items/arrows.rs b/egui_plot/src/items/arrows.rs index a717e1b9..a5d96009 100644 --- a/egui_plot/src/items/arrows.rs +++ b/egui_plot/src/items/arrows.rs @@ -8,10 +8,10 @@ use emath::Rot2; use crate::Id; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoints; +use crate::values::PlotPoints; use crate::PlotTransform; impl<'a> Arrows<'a> { diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index 93768d59..7bffa38d 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -14,17 +14,17 @@ use super::add_rulers_and_text; use super::find_closest_rect; use crate::rect_elem::RectElement; use crate::colors::highlighted_color; -use crate::ClosestElem; +use crate::values::ClosestElem; use crate::Cursor; use crate::Id; use crate::LabelFormatter; -use crate::Orientation; +use crate::values::Orientation; use crate::PlotBounds; use crate::PlotConfig; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotTransform; /// A bar chart. diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index 776eb889..94af2073 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -13,17 +13,17 @@ use super::add_rulers_and_text; use super::find_closest_rect; use crate::rect_elem::RectElement; use crate::colors::highlighted_color; -use crate::ClosestElem; +use crate::values::ClosestElem; use crate::Cursor; use crate::Id; use crate::LabelFormatter; -use crate::Orientation; +use crate::values::Orientation; use crate::PlotBounds; use crate::PlotConfig; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotTransform; /// A diagram containing a series of [`BoxElem`] elements. diff --git a/egui_plot/src/items/heatmap.rs b/egui_plot/src/items/heatmap.rs index bd1e731b..1f022a78 100644 --- a/egui_plot/src/items/heatmap.rs +++ b/egui_plot/src/items/heatmap.rs @@ -17,12 +17,12 @@ use super::Cursor; use super::LabelFormatter; use super::PlotBounds; use super::PlotTransform; -use crate::ClosestElem; +use crate::values::ClosestElem; use crate::PlotConfig; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; +use crate::values::PlotPoint; /// Default base colors for heatmap palette pub const BASE_COLORS: [Color32; 10] = [ diff --git a/egui_plot/src/items/line.rs b/egui_plot/src/items/line.rs index 14fb3745..d12a475f 100644 --- a/egui_plot/src/items/line.rs +++ b/egui_plot/src/items/line.rs @@ -7,12 +7,12 @@ use egui::Ui; use egui::epaint::PathStroke; use crate::Id; -use crate::LineStyle; +use crate::values::LineStyle; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotTransform; /// A horizontal line in a plot, filling the full width diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 93296ec7..b6c6ae59 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -31,13 +31,11 @@ use crate::rect_elem::RectElement; pub use series::Line; pub use span::Span; pub use text::Text; -pub use values::ClosestElem; -pub use values::LineStyle; -pub use values::MarkerShape; -pub use values::Orientation; -pub use values::PlotGeometry; -pub use values::PlotPoint; -pub use values::PlotPoints; +use crate::values::ClosestElem; +use crate::values::LineStyle; +use crate::values::Orientation; +use crate::values::PlotGeometry; +use crate::values::PlotPoint; use super::Cursor; use super::LabelFormatter; @@ -55,7 +53,6 @@ mod polygon; mod series; mod span; mod text; -mod values; const DEFAULT_FILL_ALPHA: f32 = 0.05; diff --git a/egui_plot/src/items/plot_image.rs b/egui_plot/src/items/plot_image.rs index 338caa7d..bbc7bbe1 100644 --- a/egui_plot/src/items/plot_image.rs +++ b/egui_plot/src/items/plot_image.rs @@ -14,10 +14,10 @@ use emath::pos2; use crate::Id; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotTransform; /// An image in the plot. diff --git a/egui_plot/src/items/points.rs b/egui_plot/src/items/points.rs index 0d0150f6..d7e0fb87 100644 --- a/egui_plot/src/items/points.rs +++ b/egui_plot/src/items/points.rs @@ -10,13 +10,13 @@ use emath::pos2; use emath::vec2; use crate::Id; -use crate::MarkerShape; +use crate::values::MarkerShape; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; -use crate::PlotPoints; +use crate::values::PlotPoint; +use crate::values::PlotPoints; use crate::PlotTransform; impl<'a> Points<'a> { diff --git a/egui_plot/src/items/polygon.rs b/egui_plot/src/items/polygon.rs index 3c95ab1f..3efca4c8 100644 --- a/egui_plot/src/items/polygon.rs +++ b/egui_plot/src/items/polygon.rs @@ -8,12 +8,12 @@ use egui::Ui; use egui::epaint::PathStroke; use super::DEFAULT_FILL_ALPHA; -use crate::LineStyle; +use crate::values::LineStyle; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoints; +use crate::values::PlotPoints; use crate::PlotTransform; /// A convex polygon. diff --git a/egui_plot/src/items/series.rs b/egui_plot/src/items/series.rs index 2849ae95..f89c4bc1 100644 --- a/egui_plot/src/items/series.rs +++ b/egui_plot/src/items/series.rs @@ -16,13 +16,13 @@ use emath::pos2; use super::DEFAULT_FILL_ALPHA; use crate::math::y_intersection; use crate::Id; -use crate::LineStyle; +use crate::values::LineStyle; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; -use crate::PlotPoints; +use crate::values::PlotPoint; +use crate::values::PlotPoints; use crate::PlotTransform; /// A series of values forming a path. diff --git a/egui_plot/src/items/text.rs b/egui_plot/src/items/text.rs index f760126c..c7c5451b 100644 --- a/egui_plot/src/items/text.rs +++ b/egui_plot/src/items/text.rs @@ -11,10 +11,10 @@ use emath::Align2; use crate::Id; use crate::PlotBounds; -use crate::PlotGeometry; +use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotTransform; impl Text { diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index a686439f..8b368e06 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -19,6 +19,7 @@ mod plot_ui; mod rect_elem; mod transform; mod utils; +mod values; use std::cmp::Ordering; use std::ops::RangeInclusive; @@ -43,20 +44,20 @@ pub use crate::items::BarChart; pub use crate::items::BoxElem; pub use crate::items::BoxPlot; pub use crate::items::BoxSpread; -pub use crate::items::ClosestElem; +pub use crate::values::ClosestElem; pub use crate::items::HLine; pub use crate::items::Heatmap; pub use crate::items::Line; -pub use crate::items::LineStyle; -pub use crate::items::MarkerShape; -pub use crate::items::Orientation; +pub use crate::values::LineStyle; +pub use crate::values::MarkerShape; +pub use crate::values::Orientation; pub use crate::items::PlotConfig; -pub use crate::items::PlotGeometry; +pub use crate::values::PlotGeometry; pub use crate::items::PlotImage; pub use crate::items::PlotItem; pub use crate::items::PlotItemBase; -pub use crate::items::PlotPoint; -pub use crate::items::PlotPoints; +pub use crate::values::PlotPoint; +pub use crate::values::PlotPoints; pub use crate::items::Points; pub use crate::items::Polygon; pub use crate::items::Span; diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 973c32e6..7d9b67ad 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -44,7 +44,7 @@ use crate::PlotBounds; use crate::PlotFrameCursors; use crate::PlotItem; use crate::PlotMemory; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotResponse; use crate::PlotTransform; use crate::PlotUi; diff --git a/egui_plot/src/plot_ui.rs b/egui_plot/src/plot_ui.rs index c41bcd67..d0dc7df8 100644 --- a/egui_plot/src/plot_ui.rs +++ b/egui_plot/src/plot_ui.rs @@ -12,7 +12,7 @@ use crate::BoundsModification; use crate::Plot; use crate::PlotBounds; use crate::PlotItem; -use crate::PlotPoint; +use crate::values::PlotPoint; use crate::PlotTransform; use crate::Span; From 733395b0cfce19a529fda5153130499d027ee4d3 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:10:12 +0100 Subject: [PATCH 07/26] find closest rect --- egui_plot/src/items/bar_chart.rs | 2 +- egui_plot/src/items/box_plot.rs | 2 +- egui_plot/src/items/mod.rs | 19 ------------------- egui_plot/src/math.rs | 24 +++++++++++++++++++++++- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index 7bffa38d..a79de9a4 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -11,7 +11,7 @@ use emath::NumExt as _; use emath::Pos2; use super::add_rulers_and_text; -use super::find_closest_rect; +use crate::math::find_closest_rect; use crate::rect_elem::RectElement; use crate::colors::highlighted_color; use crate::values::ClosestElem; diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index 94af2073..5c041d6a 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -10,7 +10,7 @@ use emath::NumExt as _; use emath::Pos2; use super::add_rulers_and_text; -use super::find_closest_rect; +use crate::math::find_closest_rect; use crate::rect_elem::RectElement; use crate::colors::highlighted_color; use crate::values::ClosestElem; diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index b6c6ae59..916f5656 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -344,22 +344,3 @@ pub(super) fn rulers_and_tooltip_at_value( }); } -fn find_closest_rect<'a, T>( - rects: impl IntoIterator, - point: Pos2, - transform: &PlotTransform, -) -> Option -where - T: 'a + RectElement, -{ - rects - .into_iter() - .enumerate() - .map(|(index, bar)| { - let bar_rect = transform.rect_from_values(&bar.bounds_min(), &bar.bounds_max()); - let dist_sq = bar_rect.distance_sq_to_pos(point); - - ClosestElem { index, dist_sq } - }) - .min_by_key(|e| e.dist_sq.ord()) -} diff --git a/egui_plot/src/math.rs b/egui_plot/src/math.rs index 4525103d..ee50d4bf 100644 --- a/egui_plot/src/math.rs +++ b/egui_plot/src/math.rs @@ -1,4 +1,6 @@ -use emath::Pos2; +use emath::{Float, Pos2}; +use crate::{ClosestElem, PlotTransform}; +use crate::rect_elem::RectElement; /// Returns the x-coordinate of a possible intersection between a line segment /// from `p1` to `p2` and a horizontal line at the given y-coordinate. @@ -6,3 +8,23 @@ pub fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option { ((p1.y > y && p2.y < y) || (p1.y < y && p2.y > y)) .then_some(((y * (p1.x - p2.x)) - (p1.x * p2.y - p1.y * p2.x)) / (p1.y - p2.y)) } + +pub fn find_closest_rect<'a, T>( + rects: impl IntoIterator, + point: Pos2, + transform: &PlotTransform, +) -> Option +where + T: 'a + RectElement, +{ + rects + .into_iter() + .enumerate() + .map(|(index, bar)| { + let bar_rect = transform.rect_from_values(&bar.bounds_min(), &bar.bounds_max()); + let dist_sq = bar_rect.distance_sq_to_pos(point); + + ClosestElem { index, dist_sq } + }) + .min_by_key(|e| e.dist_sq.ord()) +} \ No newline at end of file From 87ef9c23c3291ba381b6f23db624d05edd3a113c Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:13:22 +0100 Subject: [PATCH 08/26] lines --- egui_plot/src/items/line.rs | 18 +++++++++++++++++- egui_plot/src/items/mod.rs | 19 ++----------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/egui_plot/src/items/line.rs b/egui_plot/src/items/line.rs index d12a475f..d045f601 100644 --- a/egui_plot/src/items/line.rs +++ b/egui_plot/src/items/line.rs @@ -5,7 +5,7 @@ use egui::Shape; use egui::Stroke; use egui::Ui; use egui::epaint::PathStroke; - +use emath::{pos2, Pos2}; use crate::Id; use crate::values::LineStyle; use crate::PlotBounds; @@ -284,3 +284,19 @@ impl PlotItem for VLine { bounds } } + +pub fn vertical_line(pointer: Pos2, transform: &PlotTransform, line_color: Color32) -> Shape { + let frame = transform.frame(); + Shape::line_segment( + [pos2(pointer.x, frame.top()), pos2(pointer.x, frame.bottom())], + (1.0, line_color), + ) +} + +pub fn horizontal_line(pointer: Pos2, transform: &PlotTransform, line_color: Color32) -> Shape { + let frame = transform.frame(); + Shape::line_segment( + [pos2(frame.left(), pointer.y), pos2(frame.right(), pointer.y)], + (1.0, line_color), + ) +} diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 916f5656..3f38a72a 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -18,12 +18,13 @@ use egui::Pos2; use egui::Shape; use egui::TextStyle; use egui::Ui; -use egui::pos2; use egui::vec2; use emath::Float as _; pub use heatmap::Heatmap; pub use line::HLine; pub use line::VLine; +pub use line::vertical_line; +pub use line::horizontal_line; pub use plot_image::PlotImage; pub use points::Points; pub use polygon::Polygon; @@ -202,22 +203,6 @@ pub trait PlotItem { // ---------------------------------------------------------------------------- // Helper functions -pub(crate) fn vertical_line(pointer: Pos2, transform: &PlotTransform, line_color: Color32) -> Shape { - let frame = transform.frame(); - Shape::line_segment( - [pos2(pointer.x, frame.top()), pos2(pointer.x, frame.bottom())], - (1.0, line_color), - ) -} - -pub(crate) fn horizontal_line(pointer: Pos2, transform: &PlotTransform, line_color: Color32) -> Shape { - let frame = transform.frame(); - Shape::line_segment( - [pos2(frame.left(), pointer.y), pos2(frame.right(), pointer.y)], - (1.0, line_color), - ) -} - fn add_rulers_and_text( elem: &dyn RectElement, plot: &PlotConfig<'_>, From e8b840fc3ed198750c43bf2736a088035e44bcfa Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:14:15 +0100 Subject: [PATCH 09/26] alpha --- egui_plot/src/colors.rs | 4 +++- egui_plot/src/items/mod.rs | 2 -- egui_plot/src/items/polygon.rs | 2 +- egui_plot/src/items/series.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs index 7677654a..73b7e394 100644 --- a/egui_plot/src/colors.rs +++ b/egui_plot/src/colors.rs @@ -23,4 +23,6 @@ pub(crate) fn highlighted_color(mut stroke: Stroke, fill: Color32) -> (Stroke, C } (stroke, fill.into()) -} \ No newline at end of file +} + +pub const DEFAULT_FILL_ALPHA: f32 = 0.05; \ No newline at end of file diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 3f38a72a..e50b01c0 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -55,8 +55,6 @@ mod series; mod span; mod text; -const DEFAULT_FILL_ALPHA: f32 = 0.05; - /// Base data shared by all plot items. #[derive(Clone, Debug, PartialEq, Eq)] pub struct PlotItemBase { diff --git a/egui_plot/src/items/polygon.rs b/egui_plot/src/items/polygon.rs index 3efca4c8..6768a8d7 100644 --- a/egui_plot/src/items/polygon.rs +++ b/egui_plot/src/items/polygon.rs @@ -7,7 +7,7 @@ use egui::Stroke; use egui::Ui; use egui::epaint::PathStroke; -use super::DEFAULT_FILL_ALPHA; +use crate::colors::DEFAULT_FILL_ALPHA; use crate::values::LineStyle; use crate::PlotBounds; use crate::values::PlotGeometry; diff --git a/egui_plot/src/items/series.rs b/egui_plot/src/items/series.rs index f89c4bc1..e81d0b9d 100644 --- a/egui_plot/src/items/series.rs +++ b/egui_plot/src/items/series.rs @@ -13,7 +13,7 @@ use emath::Pos2; use emath::Rect; use emath::pos2; -use super::DEFAULT_FILL_ALPHA; +use crate::colors::DEFAULT_FILL_ALPHA; use crate::math::y_intersection; use crate::Id; use crate::values::LineStyle; From 7d56eeb579d06456b6d8663798c940fbafe3df05 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:16:40 +0100 Subject: [PATCH 10/26] heatmap colors --- egui_plot/src/colors.rs | 15 ++++++++++++++- egui_plot/src/items/heatmap.rs | 16 +--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs index 73b7e394..207af15e 100644 --- a/egui_plot/src/colors.rs +++ b/egui_plot/src/colors.rs @@ -25,4 +25,17 @@ pub(crate) fn highlighted_color(mut stroke: Stroke, fill: Color32) -> (Stroke, C (stroke, fill.into()) } -pub const DEFAULT_FILL_ALPHA: f32 = 0.05; \ No newline at end of file +pub const DEFAULT_FILL_ALPHA: f32 = 0.05; +/// Default base colors. Used for now only in heatmap palette. +pub const BASE_COLORS: [Color32; 10] = [ + Color32::from_rgb(48, 18, 59), + Color32::from_rgb(35, 106, 141), + Color32::from_rgb(30, 160, 140), + Color32::from_rgb(88, 200, 98), + Color32::from_rgb(164, 223, 39), + Color32::from_rgb(228, 223, 14), + Color32::from_rgb(250, 187, 13), + Color32::from_rgb(246, 135, 8), + Color32::from_rgb(213, 68, 2), + Color32::from_rgb(122, 4, 2), +]; \ No newline at end of file diff --git a/egui_plot/src/items/heatmap.rs b/egui_plot/src/items/heatmap.rs index 1f022a78..84c5bc7a 100644 --- a/egui_plot/src/items/heatmap.rs +++ b/egui_plot/src/items/heatmap.rs @@ -12,7 +12,7 @@ use egui::Ui; use egui::Vec2; use egui::WidgetText; use emath::Float as _; - +use crate::colors::BASE_COLORS; use super::Cursor; use super::LabelFormatter; use super::PlotBounds; @@ -24,20 +24,6 @@ use crate::PlotItem; use crate::PlotItemBase; use crate::values::PlotPoint; -/// Default base colors for heatmap palette -pub const BASE_COLORS: [Color32; 10] = [ - Color32::from_rgb(48, 18, 59), - Color32::from_rgb(35, 106, 141), - Color32::from_rgb(30, 160, 140), - Color32::from_rgb(88, 200, 98), - Color32::from_rgb(164, 223, 39), - Color32::from_rgb(228, 223, 14), - Color32::from_rgb(250, 187, 13), - Color32::from_rgb(246, 135, 8), - Color32::from_rgb(213, 68, 2), - Color32::from_rgb(122, 4, 2), -]; - /// Default resolution for heatmap color palette pub const DEFAULT_RESOLUTION: usize = 128; From b1321be8e7ad0a6d07462f9ecff9e4dda78a5809 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:22:58 +0100 Subject: [PATCH 11/26] placement --- egui_plot/src/axis.rs | 66 +------------------------------------- egui_plot/src/lib.rs | 7 ++-- egui_plot/src/placement.rs | 63 ++++++++++++++++++++++++++++++++++++ egui_plot/src/plot.rs | 4 +-- 4 files changed, 70 insertions(+), 70 deletions(-) create mode 100644 egui_plot/src/placement.rs diff --git a/egui_plot/src/axis.rs b/egui_plot/src/axis.rs index d3b64ff3..e6e82c28 100644 --- a/egui_plot/src/axis.rs +++ b/egui_plot/src/axis.rs @@ -15,7 +15,7 @@ use egui::WidgetText; use egui::emath::Rot2; use egui::emath::remap_clamp; use egui::epaint::TextShape; - +use crate::placement::{HPlacement, Placement, VPlacement}; use super::GridMark; use super::transform::PlotTransform; @@ -44,70 +44,6 @@ impl From for usize { } } -/// Placement of the horizontal X-Axis. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum VPlacement { - Top, - Bottom, -} - -/// Placement of the vertical Y-Axis. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum HPlacement { - Left, - Right, -} - -/// Placement of an axis. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Placement { - /// Bottom for X-axis, or left for Y-axis. - LeftBottom, - - /// Top for x-axis and right for y-axis. - RightTop, -} - -impl From for Placement { - #[inline] - fn from(placement: HPlacement) -> Self { - match placement { - HPlacement::Left => Self::LeftBottom, - HPlacement::Right => Self::RightTop, - } - } -} - -impl From for HPlacement { - #[inline] - fn from(placement: Placement) -> Self { - match placement { - Placement::LeftBottom => Self::Left, - Placement::RightTop => Self::Right, - } - } -} - -impl From for Placement { - #[inline] - fn from(placement: VPlacement) -> Self { - match placement { - VPlacement::Top => Self::RightTop, - VPlacement::Bottom => Self::LeftBottom, - } - } -} - -impl From for VPlacement { - #[inline] - fn from(placement: Placement) -> Self { - match placement { - Placement::LeftBottom => Self::Bottom, - Placement::RightTop => Self::Top, - } - } -} - /// Axis configuration. /// /// Used to configure axis label and ticks. diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 8b368e06..b9aca49f 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -20,6 +20,7 @@ mod rect_elem; mod transform; mod utils; mod values; +mod placement; use std::cmp::Ordering; use std::ops::RangeInclusive; @@ -35,9 +36,9 @@ use egui::Vec2b; pub use crate::axis::Axis; pub use crate::axis::AxisHints; -pub use crate::axis::HPlacement; -pub use crate::axis::Placement; -pub use crate::axis::VPlacement; +pub use placement::HPlacement; +pub use placement::Placement; +pub use placement::VPlacement; pub use crate::items::Arrows; pub use crate::items::Bar; pub use crate::items::BarChart; diff --git a/egui_plot/src/placement.rs b/egui_plot/src/placement.rs new file mode 100644 index 00000000..e504c5ef --- /dev/null +++ b/egui_plot/src/placement.rs @@ -0,0 +1,63 @@ +/// Placement of the horizontal X-Axis. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VPlacement { + Top, + Bottom, +} + +/// Placement of the vertical Y-Axis. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HPlacement { + Left, + Right, +} + +/// Placement of an axis. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Placement { + /// Bottom for X-axis, or left for Y-axis. + LeftBottom, + + /// Top for x-axis and right for y-axis. + RightTop, +} + +impl From for Placement { + #[inline] + fn from(placement: HPlacement) -> Self { + match placement { + HPlacement::Left => Self::LeftBottom, + HPlacement::Right => Self::RightTop, + } + } +} + +impl From for HPlacement { + #[inline] + fn from(placement: Placement) -> Self { + match placement { + Placement::LeftBottom => Self::Left, + Placement::RightTop => Self::Right, + } + } +} + +impl From for Placement { + #[inline] + fn from(placement: VPlacement) -> Self { + match placement { + VPlacement::Top => Self::RightTop, + VPlacement::Bottom => Self::LeftBottom, + } + } +} + +impl From for VPlacement { + #[inline] + fn from(placement: Placement) -> Self { + match placement { + Placement::LeftBottom => Self::Bottom, + Placement::RightTop => Self::Top, + } + } +} \ No newline at end of file diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 7d9b67ad..ab4bfbb3 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -36,7 +36,7 @@ use crate::CursorLinkGroups; use crate::GridInput; use crate::GridMark; use crate::GridSpacer; -use crate::HPlacement; +use crate::placement::HPlacement; use crate::LabelFormatter; use crate::Legend; use crate::LinkedBounds; @@ -48,7 +48,7 @@ use crate::values::PlotPoint; use crate::PlotResponse; use crate::PlotTransform; use crate::PlotUi; -use crate::VPlacement; +use crate::placement::VPlacement; use crate::axis::AxisWidget; use crate::items; use crate::items::horizontal_line; From bb3c3f9edb2a44956e10e571ce857414bacfdc40 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:25:51 +0100 Subject: [PATCH 12/26] corner to placement --- egui_plot/src/legend.rs | 20 +------------------- egui_plot/src/lib.rs | 2 +- egui_plot/src/placement.rs | 18 ++++++++++++++++++ egui_plot/src/plot.rs | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/egui_plot/src/legend.rs b/egui_plot/src/legend.rs index eea606df..6bd27114 100644 --- a/egui_plot/src/legend.rs +++ b/egui_plot/src/legend.rs @@ -21,27 +21,9 @@ use egui::WidgetType; use egui::epaint::CircleShape; use egui::pos2; use egui::vec2; - +use crate::placement::Corner; use super::items::PlotItem; -/// Where to place the plot legend. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum Corner { - LeftTop, - RightTop, - LeftBottom, - RightBottom, -} - -impl Corner { - pub fn all() -> impl Iterator { - [Self::LeftTop, Self::RightTop, Self::LeftBottom, Self::RightBottom] - .iter() - .copied() - } -} - /// How to handle multiple conflicting color for a legend item. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index b9aca49f..a63b914e 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -65,7 +65,7 @@ pub use crate::items::Span; pub use crate::items::Text; pub use crate::items::VLine; pub use crate::legend::ColorConflictHandling; -pub use crate::legend::Corner; +pub use crate::placement::Corner; pub use crate::legend::Legend; pub use crate::memory::PlotMemory; pub use crate::plot::Plot; diff --git a/egui_plot/src/placement.rs b/egui_plot/src/placement.rs index e504c5ef..fa16b97d 100644 --- a/egui_plot/src/placement.rs +++ b/egui_plot/src/placement.rs @@ -60,4 +60,22 @@ impl From for VPlacement { Placement::RightTop => Self::Top, } } +} + +/// Where to place the plot legend. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum Corner { + LeftTop, + RightTop, + LeftBottom, + RightBottom, +} + +impl Corner { + pub fn all() -> impl Iterator { + [Self::LeftTop, Self::RightTop, Self::LeftBottom, Self::RightBottom] + .iter() + .copied() + } } \ No newline at end of file diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index ab4bfbb3..e93536ed 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -30,7 +30,7 @@ use crate::AxisHints; use crate::BoundsLinkGroups; use crate::BoundsModification; use crate::CoordinatesFormatter; -use crate::Corner; +use crate::placement::Corner; use crate::Cursor; use crate::CursorLinkGroups; use crate::GridInput; From 744eb25891f026d6cbb32656311a4f0e5f9a5cee Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:29:22 +0100 Subject: [PATCH 13/26] bounds --- egui_plot/src/lib.rs | 9 --------- egui_plot/src/plot.rs | 4 ++-- egui_plot/src/transform.rs | 13 +++++++++++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index a63b914e..bdc89706 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -144,15 +144,6 @@ struct PlotFrameCursors { #[derive(Default, Clone)] struct CursorLinkGroups(HashMap>); -#[derive(Clone)] -struct LinkedBounds { - bounds: PlotBounds, - auto_bounds: Vec2b, -} - -#[derive(Default, Clone)] -struct BoundsLinkGroups(HashMap); - // ---------------------------------------------------------------------------- /// What [`Plot::show`] returns. diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index e93536ed..4397880e 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -27,7 +27,7 @@ use emath::vec2; use crate::Axis; use crate::AxisHints; -use crate::BoundsLinkGroups; +use crate::transform::BoundsLinkGroups; use crate::BoundsModification; use crate::CoordinatesFormatter; use crate::placement::Corner; @@ -39,7 +39,7 @@ use crate::GridSpacer; use crate::placement::HPlacement; use crate::LabelFormatter; use crate::Legend; -use crate::LinkedBounds; +use crate::transform::LinkedBounds; use crate::PlotBounds; use crate::PlotFrameCursors; use crate::PlotItem; diff --git a/egui_plot/src/transform.rs b/egui_plot/src/transform.rs index 0025074b..9979e045 100644 --- a/egui_plot/src/transform.rs +++ b/egui_plot/src/transform.rs @@ -1,12 +1,12 @@ use std::ops::RangeInclusive; -use egui::Pos2; +use egui::{Id, Pos2}; use egui::Rect; use egui::Vec2; use egui::Vec2b; use egui::pos2; use egui::remap; - +use ahash::HashMap; use super::PlotPoint; use crate::Axis; @@ -538,3 +538,12 @@ impl PlotTransform { } } } + +#[derive(Clone)] +pub struct LinkedBounds { + pub bounds: PlotBounds, + pub auto_bounds: Vec2b, +} + +#[derive(Default, Clone)] +pub struct BoundsLinkGroups(pub HashMap); \ No newline at end of file From 55f4e7f060571975bfead2503f8f6117b212640e Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:30:00 +0100 Subject: [PATCH 14/26] bounds 2 --- egui_plot/src/lib.rs | 11 ----------- egui_plot/src/plot.rs | 2 +- egui_plot/src/plot_ui.rs | 2 +- egui_plot/src/transform.rs | 13 ++++++++++++- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index bdc89706..b3fbbeb9 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -167,17 +167,6 @@ pub struct PlotResponse { // ---------------------------------------------------------------------------- -/// User-requested modifications to the plot bounds. We collect them in the plot -/// build function to later apply them at the right time, as other modifications -/// need to happen first. -enum BoundsModification { - SetX(RangeInclusive), - SetY(RangeInclusive), - Translate(Vec2), - AutoBounds(Vec2b), - Zoom(Vec2, PlotPoint), -} - // ---------------------------------------------------------------------------- // Grid diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 4397880e..6ce0666d 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -28,7 +28,7 @@ use emath::vec2; use crate::Axis; use crate::AxisHints; use crate::transform::BoundsLinkGroups; -use crate::BoundsModification; +use crate::transform::BoundsModification; use crate::CoordinatesFormatter; use crate::placement::Corner; use crate::Cursor; diff --git a/egui_plot/src/plot_ui.rs b/egui_plot/src/plot_ui.rs index d0dc7df8..b118a1f9 100644 --- a/egui_plot/src/plot_ui.rs +++ b/egui_plot/src/plot_ui.rs @@ -7,7 +7,7 @@ use egui::Vec2; use egui::Vec2b; use egui::epaint::Hsva; -use crate::BoundsModification; +use crate::transform::BoundsModification; #[expect(unused_imports)] // for links in docstrings use crate::Plot; use crate::PlotBounds; diff --git a/egui_plot/src/transform.rs b/egui_plot/src/transform.rs index 9979e045..e58f9353 100644 --- a/egui_plot/src/transform.rs +++ b/egui_plot/src/transform.rs @@ -546,4 +546,15 @@ pub struct LinkedBounds { } #[derive(Default, Clone)] -pub struct BoundsLinkGroups(pub HashMap); \ No newline at end of file +pub struct BoundsLinkGroups(pub HashMap); + +/// User-requested modifications to the plot bounds. We collect them in the plot +/// build function to later apply them at the right time, as other modifications +/// need to happen first. +pub enum BoundsModification { + SetX(RangeInclusive), + SetY(RangeInclusive), + Translate(Vec2), + AutoBounds(Vec2b), + Zoom(Vec2, PlotPoint), +} \ No newline at end of file From 38b8c49209e7088576954a85ce20a07f728f1104 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:30:42 +0100 Subject: [PATCH 15/26] bounds 3 --- egui_plot/src/bounds.rs | 280 ++++++++++++++++++++++++++++++ egui_plot/src/items/arrows.rs | 2 +- egui_plot/src/items/bar_chart.rs | 2 +- egui_plot/src/items/box_plot.rs | 2 +- egui_plot/src/items/heatmap.rs | 2 +- egui_plot/src/items/line.rs | 2 +- egui_plot/src/items/mod.rs | 2 +- egui_plot/src/items/plot_image.rs | 2 +- egui_plot/src/items/points.rs | 2 +- egui_plot/src/items/polygon.rs | 2 +- egui_plot/src/items/series.rs | 2 +- egui_plot/src/items/span.rs | 2 +- egui_plot/src/items/text.rs | 2 +- egui_plot/src/lib.rs | 6 +- egui_plot/src/memory.rs | 2 +- egui_plot/src/plot.rs | 8 +- egui_plot/src/plot_ui.rs | 4 +- egui_plot/src/rect_elem.rs | 2 +- egui_plot/src/transform.rs | 280 +----------------------------- egui_plot/src/values.rs | 2 +- 20 files changed, 305 insertions(+), 303 deletions(-) create mode 100644 egui_plot/src/bounds.rs diff --git a/egui_plot/src/bounds.rs b/egui_plot/src/bounds.rs new file mode 100644 index 00000000..e851dbbf --- /dev/null +++ b/egui_plot/src/bounds.rs @@ -0,0 +1,280 @@ +use std::ops::RangeInclusive; +use ahash::HashMap; +use egui::Id; +use emath::{Vec2, Vec2b}; +use crate::PlotPoint; + +/// 2D bounding box of f64 precision. +/// +/// The range of data values we show. +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct PlotBounds { + pub(crate) min: [f64; 2], + pub(crate) max: [f64; 2], +} + +impl PlotBounds { + pub const NOTHING: Self = Self { + min: [f64::INFINITY; 2], + max: [-f64::INFINITY; 2], + }; + + #[inline] + pub fn from_min_max(min: [f64; 2], max: [f64; 2]) -> Self { + Self { min, max } + } + + #[inline] + pub fn min(&self) -> [f64; 2] { + self.min + } + + #[inline] + pub fn max(&self) -> [f64; 2] { + self.max + } + + #[inline] + pub fn new_symmetrical(half_extent: f64) -> Self { + Self { + min: [-half_extent; 2], + max: [half_extent; 2], + } + } + + #[inline] + pub fn is_finite(&self) -> bool { + self.min[0].is_finite() && self.min[1].is_finite() && self.max[0].is_finite() && self.max[1].is_finite() + } + + #[inline] + pub fn is_finite_x(&self) -> bool { + self.min[0].is_finite() && self.max[0].is_finite() + } + + #[inline] + pub fn is_finite_y(&self) -> bool { + self.min[1].is_finite() && self.max[1].is_finite() + } + + #[inline] + pub fn is_valid(&self) -> bool { + self.is_finite() && self.width() > 0.0 && self.height() > 0.0 + } + + #[inline] + pub fn is_valid_x(&self) -> bool { + self.is_finite_x() && self.width() > 0.0 + } + + #[inline] + pub fn is_valid_y(&self) -> bool { + self.is_finite_y() && self.height() > 0.0 + } + + #[inline] + pub fn width(&self) -> f64 { + self.max[0] - self.min[0] + } + + #[inline] + pub fn height(&self) -> f64 { + self.max[1] - self.min[1] + } + + #[inline] + pub fn center(&self) -> PlotPoint { + [ + emath::fast_midpoint(self.min[0], self.max[0]), + emath::fast_midpoint(self.min[1], self.max[1]), + ] + .into() + } + + /// Expand to include the given (x,y) value + #[inline] + pub fn extend_with(&mut self, value: &PlotPoint) { + self.extend_with_x(value.x); + self.extend_with_y(value.y); + } + + /// Expand to include the given x coordinate + #[inline] + pub fn extend_with_x(&mut self, x: f64) { + self.min[0] = self.min[0].min(x); + self.max[0] = self.max[0].max(x); + } + + /// Expand to include the given y coordinate + #[inline] + pub fn extend_with_y(&mut self, y: f64) { + self.min[1] = self.min[1].min(y); + self.max[1] = self.max[1].max(y); + } + + #[inline] + fn clamp_to_finite(&mut self) { + for d in 0..2 { + self.min[d] = self.min[d].clamp(f64::MIN, f64::MAX); + if self.min[d].is_nan() { + self.min[d] = 0.0; + } + + self.max[d] = self.max[d].clamp(f64::MIN, f64::MAX); + if self.max[d].is_nan() { + self.max[d] = 0.0; + } + } + } + + #[inline] + pub fn expand_x(&mut self, pad: f64) { + if pad.is_finite() { + self.min[0] -= pad; + self.max[0] += pad; + self.clamp_to_finite(); + } + } + + #[inline] + pub fn expand_y(&mut self, pad: f64) { + if pad.is_finite() { + self.min[1] -= pad; + self.max[1] += pad; + self.clamp_to_finite(); + } + } + + #[inline] + pub fn merge_x(&mut self, other: &Self) { + self.min[0] = self.min[0].min(other.min[0]); + self.max[0] = self.max[0].max(other.max[0]); + } + + #[inline] + pub fn merge_y(&mut self, other: &Self) { + self.min[1] = self.min[1].min(other.min[1]); + self.max[1] = self.max[1].max(other.max[1]); + } + + #[inline] + pub fn set_x(&mut self, other: &Self) { + self.min[0] = other.min[0]; + self.max[0] = other.max[0]; + } + + #[inline] + pub fn set_x_center_width(&mut self, x: f64, width: f64) { + self.min[0] = x - width / 2.0; + self.max[0] = x + width / 2.0; + } + + #[inline] + pub fn set_y(&mut self, other: &Self) { + self.min[1] = other.min[1]; + self.max[1] = other.max[1]; + } + + #[inline] + pub fn set_y_center_height(&mut self, y: f64, height: f64) { + self.min[1] = y - height / 2.0; + self.max[1] = y + height / 2.0; + } + + #[inline] + pub fn merge(&mut self, other: &Self) { + self.min[0] = self.min[0].min(other.min[0]); + self.min[1] = self.min[1].min(other.min[1]); + self.max[0] = self.max[0].max(other.max[0]); + self.max[1] = self.max[1].max(other.max[1]); + } + + #[inline] + pub fn translate_x(&mut self, delta: f64) { + if delta.is_finite() { + self.min[0] += delta; + self.max[0] += delta; + self.clamp_to_finite(); + } + } + + #[inline] + pub fn translate_y(&mut self, delta: f64) { + if delta.is_finite() { + self.min[1] += delta; + self.max[1] += delta; + self.clamp_to_finite(); + } + } + + #[inline] + pub fn translate(&mut self, delta: (f64, f64)) { + self.translate_x(delta.0); + self.translate_y(delta.1); + } + + #[inline] + pub fn zoom(&mut self, zoom_factor: Vec2, center: PlotPoint) { + self.min[0] = center.x + (self.min[0] - center.x) / (zoom_factor.x as f64); + self.max[0] = center.x + (self.max[0] - center.x) / (zoom_factor.x as f64); + self.min[1] = center.y + (self.min[1] - center.y) / (zoom_factor.y as f64); + self.max[1] = center.y + (self.max[1] - center.y) / (zoom_factor.y as f64); + } + + #[inline] + pub fn add_relative_margin_x(&mut self, margin_fraction: Vec2) { + let width = self.width().max(0.0); + self.expand_x(margin_fraction.x as f64 * width); + } + + #[inline] + pub fn add_relative_margin_y(&mut self, margin_fraction: Vec2) { + let height = self.height().max(0.0); + self.expand_y(margin_fraction.y as f64 * height); + } + + #[inline] + pub fn range_x(&self) -> RangeInclusive { + self.min[0]..=self.max[0] + } + + #[inline] + pub fn range_y(&self) -> RangeInclusive { + self.min[1]..=self.max[1] + } + + #[inline] + pub fn make_x_symmetrical(&mut self) { + let x_abs = self.min[0].abs().max(self.max[0].abs()); + self.min[0] = -x_abs; + self.max[0] = x_abs; + } + + #[inline] + pub fn make_y_symmetrical(&mut self) { + let y_abs = self.min[1].abs().max(self.max[1].abs()); + self.min[1] = -y_abs; + self.max[1] = y_abs; + } +} + +#[derive(Clone)] +pub struct LinkedBounds { + pub bounds: PlotBounds, + pub auto_bounds: Vec2b, +} + +#[derive(Default, Clone)] +pub struct BoundsLinkGroups(pub HashMap); + +/// User-requested modifications to the plot bounds. We collect them in the plot +/// build function to later apply them at the right time, as other modifications +/// need to happen first. +pub enum BoundsModification { + SetX(RangeInclusive), + SetY(RangeInclusive), + Translate(Vec2), + AutoBounds(Vec2b), + Zoom(Vec2, PlotPoint), +} \ No newline at end of file diff --git a/egui_plot/src/items/arrows.rs b/egui_plot/src/items/arrows.rs index a5d96009..d3b31974 100644 --- a/egui_plot/src/items/arrows.rs +++ b/egui_plot/src/items/arrows.rs @@ -7,7 +7,7 @@ use egui::Ui; use emath::Rot2; use crate::Id; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index a79de9a4..72e42c6a 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -19,7 +19,7 @@ use crate::Cursor; use crate::Id; use crate::LabelFormatter; use crate::values::Orientation; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::PlotConfig; use crate::values::PlotGeometry; use crate::PlotItem; diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index 5c041d6a..0dc90298 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -18,7 +18,7 @@ use crate::Cursor; use crate::Id; use crate::LabelFormatter; use crate::values::Orientation; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::PlotConfig; use crate::values::PlotGeometry; use crate::PlotItem; diff --git a/egui_plot/src/items/heatmap.rs b/egui_plot/src/items/heatmap.rs index 84c5bc7a..0d4674f4 100644 --- a/egui_plot/src/items/heatmap.rs +++ b/egui_plot/src/items/heatmap.rs @@ -15,7 +15,7 @@ use emath::Float as _; use crate::colors::BASE_COLORS; use super::Cursor; use super::LabelFormatter; -use super::PlotBounds; +use crate::bounds::PlotBounds; use super::PlotTransform; use crate::values::ClosestElem; use crate::PlotConfig; diff --git a/egui_plot/src/items/line.rs b/egui_plot/src/items/line.rs index d045f601..3c3b259c 100644 --- a/egui_plot/src/items/line.rs +++ b/egui_plot/src/items/line.rs @@ -8,7 +8,7 @@ use egui::epaint::PathStroke; use emath::{pos2, Pos2}; use crate::Id; use crate::values::LineStyle; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index e50b01c0..4ba34554 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -40,7 +40,7 @@ use crate::values::PlotPoint; use super::Cursor; use super::LabelFormatter; -use super::PlotBounds; +use crate::bounds::PlotBounds; use super::PlotTransform; mod arrows; diff --git a/egui_plot/src/items/plot_image.rs b/egui_plot/src/items/plot_image.rs index bbc7bbe1..441aede7 100644 --- a/egui_plot/src/items/plot_image.rs +++ b/egui_plot/src/items/plot_image.rs @@ -13,7 +13,7 @@ use emath::Vec2; use emath::pos2; use crate::Id; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/items/points.rs b/egui_plot/src/items/points.rs index d7e0fb87..8e91b7d3 100644 --- a/egui_plot/src/items/points.rs +++ b/egui_plot/src/items/points.rs @@ -11,7 +11,7 @@ use emath::vec2; use crate::Id; use crate::values::MarkerShape; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/items/polygon.rs b/egui_plot/src/items/polygon.rs index 6768a8d7..58d7fd60 100644 --- a/egui_plot/src/items/polygon.rs +++ b/egui_plot/src/items/polygon.rs @@ -9,7 +9,7 @@ use egui::epaint::PathStroke; use crate::colors::DEFAULT_FILL_ALPHA; use crate::values::LineStyle; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/items/series.rs b/egui_plot/src/items/series.rs index e81d0b9d..0fc2ee5c 100644 --- a/egui_plot/src/items/series.rs +++ b/egui_plot/src/items/series.rs @@ -17,7 +17,7 @@ use crate::colors::DEFAULT_FILL_ALPHA; use crate::math::y_intersection; use crate::Id; use crate::values::LineStyle; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/items/span.rs b/egui_plot/src/items/span.rs index 983ec4ad..ddab2cf8 100644 --- a/egui_plot/src/items/span.rs +++ b/egui_plot/src/items/span.rs @@ -16,7 +16,7 @@ use egui::pos2; use emath::TSTransform; use super::LineStyle; -use super::PlotBounds; +use crate::bounds::PlotBounds; use super::PlotGeometry; use super::PlotItem; use super::PlotItemBase; diff --git a/egui_plot/src/items/text.rs b/egui_plot/src/items/text.rs index c7c5451b..e38dbc6a 100644 --- a/egui_plot/src/items/text.rs +++ b/egui_plot/src/items/text.rs @@ -10,7 +10,7 @@ use egui::epaint::TextShape; use emath::Align2; use crate::Id; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index b3fbbeb9..62b83849 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -21,9 +21,9 @@ mod transform; mod utils; mod values; mod placement; +mod bounds; use std::cmp::Ordering; -use std::ops::RangeInclusive; use ahash::HashMap; use egui::Color32; @@ -31,8 +31,6 @@ use egui::Id; use egui::NumExt as _; use egui::Response; use egui::Ui; -use egui::Vec2; -use egui::Vec2b; pub use crate::axis::Axis; pub use crate::axis::AxisHints; @@ -70,7 +68,7 @@ pub use crate::legend::Legend; pub use crate::memory::PlotMemory; pub use crate::plot::Plot; pub use crate::plot_ui::PlotUi; -pub use crate::transform::PlotBounds; +pub use bounds::PlotBounds; pub use crate::transform::PlotTransform; type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a; diff --git a/egui_plot/src/memory.rs b/egui_plot/src/memory.rs index dec5cc03..739aa51c 100644 --- a/egui_plot/src/memory.rs +++ b/egui_plot/src/memory.rs @@ -5,7 +5,7 @@ use egui::Id; use egui::Pos2; use egui::Vec2b; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::PlotTransform; /// Information about the plot that has to persist between frames. diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 6ce0666d..c5639973 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -27,8 +27,8 @@ use emath::vec2; use crate::Axis; use crate::AxisHints; -use crate::transform::BoundsLinkGroups; -use crate::transform::BoundsModification; +use crate::bounds::BoundsLinkGroups; +use crate::bounds::BoundsModification; use crate::CoordinatesFormatter; use crate::placement::Corner; use crate::Cursor; @@ -39,8 +39,8 @@ use crate::GridSpacer; use crate::placement::HPlacement; use crate::LabelFormatter; use crate::Legend; -use crate::transform::LinkedBounds; -use crate::PlotBounds; +use crate::bounds::LinkedBounds; +use crate::bounds::PlotBounds; use crate::PlotFrameCursors; use crate::PlotItem; use crate::PlotMemory; diff --git a/egui_plot/src/plot_ui.rs b/egui_plot/src/plot_ui.rs index b118a1f9..b81ad744 100644 --- a/egui_plot/src/plot_ui.rs +++ b/egui_plot/src/plot_ui.rs @@ -7,10 +7,10 @@ use egui::Vec2; use egui::Vec2b; use egui::epaint::Hsva; -use crate::transform::BoundsModification; +use crate::bounds::BoundsModification; #[expect(unused_imports)] // for links in docstrings use crate::Plot; -use crate::PlotBounds; +use crate::bounds::PlotBounds; use crate::PlotItem; use crate::values::PlotPoint; use crate::PlotTransform; diff --git a/egui_plot/src/rect_elem.rs b/egui_plot/src/rect_elem.rs index e31beb97..d411f8b7 100644 --- a/egui_plot/src/rect_elem.rs +++ b/egui_plot/src/rect_elem.rs @@ -1,6 +1,6 @@ use super::Orientation; use super::PlotPoint; -use crate::transform::PlotBounds; +use crate::bounds::PlotBounds; use crate::transform::PlotTransform; /// Trait that abstracts from rectangular 'Value'-like elements, such as bars or diff --git a/egui_plot/src/transform.rs b/egui_plot/src/transform.rs index e58f9353..d31be605 100644 --- a/egui_plot/src/transform.rs +++ b/egui_plot/src/transform.rs @@ -1,269 +1,12 @@ -use std::ops::RangeInclusive; - -use egui::{Id, Pos2}; +use egui::Pos2; use egui::Rect; use egui::Vec2; use egui::Vec2b; use egui::pos2; use egui::remap; -use ahash::HashMap; use super::PlotPoint; use crate::Axis; - -/// 2D bounding box of f64 precision. -/// -/// The range of data values we show. -#[derive(Clone, Copy, PartialEq, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct PlotBounds { - pub(crate) min: [f64; 2], - pub(crate) max: [f64; 2], -} - -impl PlotBounds { - pub const NOTHING: Self = Self { - min: [f64::INFINITY; 2], - max: [-f64::INFINITY; 2], - }; - - #[inline] - pub fn from_min_max(min: [f64; 2], max: [f64; 2]) -> Self { - Self { min, max } - } - - #[inline] - pub fn min(&self) -> [f64; 2] { - self.min - } - - #[inline] - pub fn max(&self) -> [f64; 2] { - self.max - } - - #[inline] - pub fn new_symmetrical(half_extent: f64) -> Self { - Self { - min: [-half_extent; 2], - max: [half_extent; 2], - } - } - - #[inline] - pub fn is_finite(&self) -> bool { - self.min[0].is_finite() && self.min[1].is_finite() && self.max[0].is_finite() && self.max[1].is_finite() - } - - #[inline] - pub fn is_finite_x(&self) -> bool { - self.min[0].is_finite() && self.max[0].is_finite() - } - - #[inline] - pub fn is_finite_y(&self) -> bool { - self.min[1].is_finite() && self.max[1].is_finite() - } - - #[inline] - pub fn is_valid(&self) -> bool { - self.is_finite() && self.width() > 0.0 && self.height() > 0.0 - } - - #[inline] - pub fn is_valid_x(&self) -> bool { - self.is_finite_x() && self.width() > 0.0 - } - - #[inline] - pub fn is_valid_y(&self) -> bool { - self.is_finite_y() && self.height() > 0.0 - } - - #[inline] - pub fn width(&self) -> f64 { - self.max[0] - self.min[0] - } - - #[inline] - pub fn height(&self) -> f64 { - self.max[1] - self.min[1] - } - - #[inline] - pub fn center(&self) -> PlotPoint { - [ - emath::fast_midpoint(self.min[0], self.max[0]), - emath::fast_midpoint(self.min[1], self.max[1]), - ] - .into() - } - - /// Expand to include the given (x,y) value - #[inline] - pub fn extend_with(&mut self, value: &PlotPoint) { - self.extend_with_x(value.x); - self.extend_with_y(value.y); - } - - /// Expand to include the given x coordinate - #[inline] - pub fn extend_with_x(&mut self, x: f64) { - self.min[0] = self.min[0].min(x); - self.max[0] = self.max[0].max(x); - } - - /// Expand to include the given y coordinate - #[inline] - pub fn extend_with_y(&mut self, y: f64) { - self.min[1] = self.min[1].min(y); - self.max[1] = self.max[1].max(y); - } - - #[inline] - fn clamp_to_finite(&mut self) { - for d in 0..2 { - self.min[d] = self.min[d].clamp(f64::MIN, f64::MAX); - if self.min[d].is_nan() { - self.min[d] = 0.0; - } - - self.max[d] = self.max[d].clamp(f64::MIN, f64::MAX); - if self.max[d].is_nan() { - self.max[d] = 0.0; - } - } - } - - #[inline] - pub fn expand_x(&mut self, pad: f64) { - if pad.is_finite() { - self.min[0] -= pad; - self.max[0] += pad; - self.clamp_to_finite(); - } - } - - #[inline] - pub fn expand_y(&mut self, pad: f64) { - if pad.is_finite() { - self.min[1] -= pad; - self.max[1] += pad; - self.clamp_to_finite(); - } - } - - #[inline] - pub fn merge_x(&mut self, other: &Self) { - self.min[0] = self.min[0].min(other.min[0]); - self.max[0] = self.max[0].max(other.max[0]); - } - - #[inline] - pub fn merge_y(&mut self, other: &Self) { - self.min[1] = self.min[1].min(other.min[1]); - self.max[1] = self.max[1].max(other.max[1]); - } - - #[inline] - pub fn set_x(&mut self, other: &Self) { - self.min[0] = other.min[0]; - self.max[0] = other.max[0]; - } - - #[inline] - pub fn set_x_center_width(&mut self, x: f64, width: f64) { - self.min[0] = x - width / 2.0; - self.max[0] = x + width / 2.0; - } - - #[inline] - pub fn set_y(&mut self, other: &Self) { - self.min[1] = other.min[1]; - self.max[1] = other.max[1]; - } - - #[inline] - pub fn set_y_center_height(&mut self, y: f64, height: f64) { - self.min[1] = y - height / 2.0; - self.max[1] = y + height / 2.0; - } - - #[inline] - pub fn merge(&mut self, other: &Self) { - self.min[0] = self.min[0].min(other.min[0]); - self.min[1] = self.min[1].min(other.min[1]); - self.max[0] = self.max[0].max(other.max[0]); - self.max[1] = self.max[1].max(other.max[1]); - } - - #[inline] - pub fn translate_x(&mut self, delta: f64) { - if delta.is_finite() { - self.min[0] += delta; - self.max[0] += delta; - self.clamp_to_finite(); - } - } - - #[inline] - pub fn translate_y(&mut self, delta: f64) { - if delta.is_finite() { - self.min[1] += delta; - self.max[1] += delta; - self.clamp_to_finite(); - } - } - - #[inline] - pub fn translate(&mut self, delta: (f64, f64)) { - self.translate_x(delta.0); - self.translate_y(delta.1); - } - - #[inline] - pub fn zoom(&mut self, zoom_factor: Vec2, center: PlotPoint) { - self.min[0] = center.x + (self.min[0] - center.x) / (zoom_factor.x as f64); - self.max[0] = center.x + (self.max[0] - center.x) / (zoom_factor.x as f64); - self.min[1] = center.y + (self.min[1] - center.y) / (zoom_factor.y as f64); - self.max[1] = center.y + (self.max[1] - center.y) / (zoom_factor.y as f64); - } - - #[inline] - pub fn add_relative_margin_x(&mut self, margin_fraction: Vec2) { - let width = self.width().max(0.0); - self.expand_x(margin_fraction.x as f64 * width); - } - - #[inline] - pub fn add_relative_margin_y(&mut self, margin_fraction: Vec2) { - let height = self.height().max(0.0); - self.expand_y(margin_fraction.y as f64 * height); - } - - #[inline] - pub fn range_x(&self) -> RangeInclusive { - self.min[0]..=self.max[0] - } - - #[inline] - pub fn range_y(&self) -> RangeInclusive { - self.min[1]..=self.max[1] - } - - #[inline] - pub fn make_x_symmetrical(&mut self) { - let x_abs = self.min[0].abs().max(self.max[0].abs()); - self.min[0] = -x_abs; - self.max[0] = x_abs; - } - - #[inline] - pub fn make_y_symmetrical(&mut self) { - let y_abs = self.min[1].abs().max(self.max[1].abs()); - self.min[1] = -y_abs; - self.max[1] = y_abs; - } -} +use crate::bounds::PlotBounds; /// Contains the screen rectangle and the plot bounds and provides methods to /// transform between them. @@ -539,22 +282,3 @@ impl PlotTransform { } } -#[derive(Clone)] -pub struct LinkedBounds { - pub bounds: PlotBounds, - pub auto_bounds: Vec2b, -} - -#[derive(Default, Clone)] -pub struct BoundsLinkGroups(pub HashMap); - -/// User-requested modifications to the plot bounds. We collect them in the plot -/// build function to later apply them at the right time, as other modifications -/// need to happen first. -pub enum BoundsModification { - SetX(RangeInclusive), - SetY(RangeInclusive), - Translate(Vec2), - AutoBounds(Vec2b), - Zoom(Vec2, PlotPoint), -} \ No newline at end of file diff --git a/egui_plot/src/values.rs b/egui_plot/src/values.rs index 06a3f809..c08823b7 100644 --- a/egui_plot/src/values.rs +++ b/egui_plot/src/values.rs @@ -12,7 +12,7 @@ use egui::epaint::PathStroke; use egui::lerp; use egui::pos2; -use crate::transform::PlotBounds; +use crate::bounds::PlotBounds; /// A point coordinate in the plot. /// From e568e6b2fad702b176045cca06c9c25aad082831 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:34:41 +0100 Subject: [PATCH 16/26] grid --- egui_plot/src/axis.rs | 2 +- egui_plot/src/grid.rs | 205 +++++++++++++++++++++++++++++++++++++++ egui_plot/src/lib.rs | 216 ++---------------------------------------- egui_plot/src/plot.rs | 14 +-- 4 files changed, 219 insertions(+), 218 deletions(-) create mode 100644 egui_plot/src/grid.rs diff --git a/egui_plot/src/axis.rs b/egui_plot/src/axis.rs index e6e82c28..eca55f27 100644 --- a/egui_plot/src/axis.rs +++ b/egui_plot/src/axis.rs @@ -16,7 +16,7 @@ use egui::emath::Rot2; use egui::emath::remap_clamp; use egui::epaint::TextShape; use crate::placement::{HPlacement, Placement, VPlacement}; -use super::GridMark; +use crate::grid::GridMark; use super::transform::PlotTransform; // Gap between tick labels and axis label in units of the axis label height diff --git a/egui_plot/src/grid.rs b/egui_plot/src/grid.rs new file mode 100644 index 00000000..7f0da353 --- /dev/null +++ b/egui_plot/src/grid.rs @@ -0,0 +1,205 @@ +use std::cmp::Ordering; + +type GridSpacerFn<'a> = dyn Fn(GridInput) -> Vec + 'a; +pub type GridSpacer<'a> = Box>; + +/// Input for "grid spacer" functions. +/// +/// See [`Plot::x_grid_spacer()`] and [`Plot::y_grid_spacer()`]. +pub struct GridInput { + /// Min/max of the visible data range (the values at the two edges of the + /// plot, for the current axis). + pub bounds: (f64, f64), + + /// Recommended (but not required) lower-bound on the step size returned by + /// custom grid spacers. + /// + /// Computed as the ratio between the diagram's bounds (in plot coordinates) + /// and the viewport (in frame/window coordinates), scaled up to + /// represent the minimal possible step. + /// + /// Always positive. + pub base_step_size: f64, +} + +/// One mark (horizontal or vertical line) in the background grid of a plot. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct GridMark { + /// X or Y value in the plot. + pub value: f64, + + /// The (approximate) distance to the next value of same thickness. + /// + /// Determines how thick the grid line is painted. It's not important that + /// `step_size` matches the difference between two `value`s precisely, + /// but rather that grid marks of same thickness have same `step_size`. + /// For example, months can have a different number of days, but + /// consistently using a `step_size` of 30 days is a valid approximation. + pub step_size: f64, +} + +/// Recursively splits the grid into `base` subdivisions (e.g. 100, 10, 1). +/// +/// The logarithmic base, expressing how many times each grid unit is +/// subdivided. 10 is a typical value, others are possible though. +pub fn log_grid_spacer(log_base: i64) -> GridSpacer<'static> { + let log_base = log_base as f64; + let step_sizes = move |input: GridInput| -> Vec { + // handle degenerate cases + if input.base_step_size.abs() < f64::EPSILON { + return Vec::new(); + } + + // The distance between two of the thinnest grid lines is "rounded" up + // to the next-bigger power of base + let smallest_visible_unit = next_power(input.base_step_size, log_base); + + let step_sizes = [ + smallest_visible_unit, + smallest_visible_unit * log_base, + smallest_visible_unit * log_base * log_base, + ]; + + generate_marks(step_sizes, input.bounds) + }; + + Box::new(step_sizes) +} + +/// Splits the grid into uniform-sized spacings (e.g. 100, 25, 1). +/// +/// This function should return 3 positive step sizes, designating where the +/// lines in the grid are drawn. Lines are thicker for larger step sizes. +/// Ordering of returned value is irrelevant. +/// +/// Why only 3 step sizes? Three is the number of different line thicknesses +/// that egui typically uses in the grid. Ideally, those 3 are not hardcoded +/// values, but depend on the visible range (accessible through `GridInput`). +pub fn uniform_grid_spacer<'a>(spacer: impl Fn(GridInput) -> [f64; 3] + 'a) -> GridSpacer<'a> { + let get_marks = move |input: GridInput| -> Vec { + let bounds = input.bounds; + let step_sizes = spacer(input); + generate_marks(step_sizes, bounds) + }; + + Box::new(get_marks) +} + +/// Returns next bigger power in given base +/// e.g. +/// ```ignore +/// use egui_plot::next_power; +/// assert_eq!(next_power(0.01, 10.0), 0.01); +/// assert_eq!(next_power(0.02, 10.0), 0.1); +/// assert_eq!(next_power(0.2, 10.0), 1); +/// ``` +fn next_power(value: f64, base: f64) -> f64 { + debug_assert_ne!(value, 0.0, "Bad input"); // can be negative (typical for Y axis) + base.powi(value.abs().log(base).ceil() as i32) +} + +/// Fill in all values between [min, max] which are a multiple of `step_size` +fn generate_marks(step_sizes: [f64; 3], bounds: (f64, f64)) -> Vec { + let mut steps = vec![]; + fill_marks_between(&mut steps, step_sizes[0], bounds); + fill_marks_between(&mut steps, step_sizes[1], bounds); + fill_marks_between(&mut steps, step_sizes[2], bounds); + + // Remove duplicates: + // This can happen because we have overlapping steps, e.g.: + // step_size[0] = 10 => [-10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + // 110, 120] step_size[1] = 100 => [ 0, + // 100 ] step_size[2] = 1000 => [ 0 + // ] + + steps.sort_by(|a, b| cmp_f64(a.value, b.value)); + + let min_step = step_sizes.iter().fold(f64::INFINITY, |a, &b| a.min(b)); + let eps = 0.1 * min_step; // avoid putting two ticks too closely together + + let mut deduplicated: Vec = Vec::with_capacity(steps.len()); + for step in steps { + if let Some(last) = deduplicated.last_mut() { + if (last.value - step.value).abs() < eps { + // Keep the one with the largest step size + if last.step_size < step.step_size { + *last = step; + } + continue; + } + } + deduplicated.push(step); + } + + deduplicated +} + +#[test] +fn test_generate_marks() { + fn approx_eq(a: &GridMark, b: &GridMark) -> bool { + (a.value - b.value).abs() < 1e-10 && a.step_size == b.step_size + } + + let gm = |value, step_size| GridMark { value, step_size }; + + let marks = generate_marks([0.01, 0.1, 1.0], (2.855, 3.015)); + let expected = vec![ + gm(2.86, 0.01), + gm(2.87, 0.01), + gm(2.88, 0.01), + gm(2.89, 0.01), + gm(2.90, 0.1), + gm(2.91, 0.01), + gm(2.92, 0.01), + gm(2.93, 0.01), + gm(2.94, 0.01), + gm(2.95, 0.01), + gm(2.96, 0.01), + gm(2.97, 0.01), + gm(2.98, 0.01), + gm(2.99, 0.01), + gm(3.00, 1.), + gm(3.01, 0.01), + ]; + + let mut problem = if marks.len() == expected.len() { + None + } else { + Some(format!( + "Different lengths: got {}, expected {}", + marks.len(), + expected.len() + )) + }; + + for (i, (a, b)) in marks.iter().zip(&expected).enumerate() { + if !approx_eq(a, b) { + problem = Some(format!("Mismatch at index {i}: {a:?} != {b:?}")); + break; + } + } + + if let Some(problem) = problem { + panic!("Test failed: {problem}. Got: {marks:#?}, expected: {expected:#?}"); + } +} + +fn cmp_f64(a: f64, b: f64) -> Ordering { + match a.partial_cmp(&b) { + Some(ord) => ord, + None => a.is_nan().cmp(&b.is_nan()), + } +} + +/// Fill in all values between [min, max] which are a multiple of `step_size` +fn fill_marks_between(out: &mut Vec, step_size: f64, (min, max): (f64, f64)) { + debug_assert!(min <= max, "Bad plot bounds: min: {min}, max: {max}"); + let first = (min / step_size).ceil() as i64; + let last = (max / step_size).ceil() as i64; + + let marks_iter = (first..last).map(|i| { + let value = (i as f64) * step_size; + GridMark { value, step_size } + }); + out.extend(marks_iter); +} \ No newline at end of file diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 62b83849..530fe1f2 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -22,8 +22,8 @@ mod utils; mod values; mod placement; mod bounds; +mod grid; -use std::cmp::Ordering; use ahash::HashMap; use egui::Color32; @@ -68,6 +68,11 @@ pub use crate::legend::Legend; pub use crate::memory::PlotMemory; pub use crate::plot::Plot; pub use crate::plot_ui::PlotUi; +pub use crate::grid::GridInput; +pub use crate::grid::GridMark; +pub use crate::grid::GridSpacer; +pub use crate::grid::log_grid_spacer; +pub use crate::grid::uniform_grid_spacer; pub use bounds::PlotBounds; pub use crate::transform::PlotTransform; @@ -76,9 +81,6 @@ type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a; /// Optional label formatter function for customizing hover labels. pub type LabelFormatter<'a> = Option>>; -type GridSpacerFn<'a> = dyn Fn(GridInput) -> Vec + 'a; -type GridSpacer<'a> = Box>; - type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a; /// Specifies the coordinates formatting when passed to @@ -165,212 +167,6 @@ pub struct PlotResponse { // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- -// Grid - -/// Input for "grid spacer" functions. -/// -/// See [`Plot::x_grid_spacer()`] and [`Plot::y_grid_spacer()`]. -pub struct GridInput { - /// Min/max of the visible data range (the values at the two edges of the - /// plot, for the current axis). - pub bounds: (f64, f64), - - /// Recommended (but not required) lower-bound on the step size returned by - /// custom grid spacers. - /// - /// Computed as the ratio between the diagram's bounds (in plot coordinates) - /// and the viewport (in frame/window coordinates), scaled up to - /// represent the minimal possible step. - /// - /// Always positive. - pub base_step_size: f64, -} - -/// One mark (horizontal or vertical line) in the background grid of a plot. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct GridMark { - /// X or Y value in the plot. - pub value: f64, - - /// The (approximate) distance to the next value of same thickness. - /// - /// Determines how thick the grid line is painted. It's not important that - /// `step_size` matches the difference between two `value`s precisely, - /// but rather that grid marks of same thickness have same `step_size`. - /// For example, months can have a different number of days, but - /// consistently using a `step_size` of 30 days is a valid approximation. - pub step_size: f64, -} - -/// Recursively splits the grid into `base` subdivisions (e.g. 100, 10, 1). -/// -/// The logarithmic base, expressing how many times each grid unit is -/// subdivided. 10 is a typical value, others are possible though. -pub fn log_grid_spacer(log_base: i64) -> GridSpacer<'static> { - let log_base = log_base as f64; - let step_sizes = move |input: GridInput| -> Vec { - // handle degenerate cases - if input.base_step_size.abs() < f64::EPSILON { - return Vec::new(); - } - - // The distance between two of the thinnest grid lines is "rounded" up - // to the next-bigger power of base - let smallest_visible_unit = next_power(input.base_step_size, log_base); - - let step_sizes = [ - smallest_visible_unit, - smallest_visible_unit * log_base, - smallest_visible_unit * log_base * log_base, - ]; - - generate_marks(step_sizes, input.bounds) - }; - - Box::new(step_sizes) -} - -/// Splits the grid into uniform-sized spacings (e.g. 100, 25, 1). -/// -/// This function should return 3 positive step sizes, designating where the -/// lines in the grid are drawn. Lines are thicker for larger step sizes. -/// Ordering of returned value is irrelevant. -/// -/// Why only 3 step sizes? Three is the number of different line thicknesses -/// that egui typically uses in the grid. Ideally, those 3 are not hardcoded -/// values, but depend on the visible range (accessible through `GridInput`). -pub fn uniform_grid_spacer<'a>(spacer: impl Fn(GridInput) -> [f64; 3] + 'a) -> GridSpacer<'a> { - let get_marks = move |input: GridInput| -> Vec { - let bounds = input.bounds; - let step_sizes = spacer(input); - generate_marks(step_sizes, bounds) - }; - - Box::new(get_marks) -} - -// ---------------------------------------------------------------------------- - -/// Returns next bigger power in given base -/// e.g. -/// ```ignore -/// use egui_plot::next_power; -/// assert_eq!(next_power(0.01, 10.0), 0.01); -/// assert_eq!(next_power(0.02, 10.0), 0.1); -/// assert_eq!(next_power(0.2, 10.0), 1); -/// ``` -fn next_power(value: f64, base: f64) -> f64 { - debug_assert_ne!(value, 0.0, "Bad input"); // can be negative (typical for Y axis) - base.powi(value.abs().log(base).ceil() as i32) -} - -/// Fill in all values between [min, max] which are a multiple of `step_size` -fn generate_marks(step_sizes: [f64; 3], bounds: (f64, f64)) -> Vec { - let mut steps = vec![]; - fill_marks_between(&mut steps, step_sizes[0], bounds); - fill_marks_between(&mut steps, step_sizes[1], bounds); - fill_marks_between(&mut steps, step_sizes[2], bounds); - - // Remove duplicates: - // This can happen because we have overlapping steps, e.g.: - // step_size[0] = 10 => [-10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, - // 110, 120] step_size[1] = 100 => [ 0, - // 100 ] step_size[2] = 1000 => [ 0 - // ] - - steps.sort_by(|a, b| cmp_f64(a.value, b.value)); - - let min_step = step_sizes.iter().fold(f64::INFINITY, |a, &b| a.min(b)); - let eps = 0.1 * min_step; // avoid putting two ticks too closely together - - let mut deduplicated: Vec = Vec::with_capacity(steps.len()); - for step in steps { - if let Some(last) = deduplicated.last_mut() { - if (last.value - step.value).abs() < eps { - // Keep the one with the largest step size - if last.step_size < step.step_size { - *last = step; - } - continue; - } - } - deduplicated.push(step); - } - - deduplicated -} - -#[test] -fn test_generate_marks() { - fn approx_eq(a: &GridMark, b: &GridMark) -> bool { - (a.value - b.value).abs() < 1e-10 && a.step_size == b.step_size - } - - let gm = |value, step_size| GridMark { value, step_size }; - - let marks = generate_marks([0.01, 0.1, 1.0], (2.855, 3.015)); - let expected = vec![ - gm(2.86, 0.01), - gm(2.87, 0.01), - gm(2.88, 0.01), - gm(2.89, 0.01), - gm(2.90, 0.1), - gm(2.91, 0.01), - gm(2.92, 0.01), - gm(2.93, 0.01), - gm(2.94, 0.01), - gm(2.95, 0.01), - gm(2.96, 0.01), - gm(2.97, 0.01), - gm(2.98, 0.01), - gm(2.99, 0.01), - gm(3.00, 1.), - gm(3.01, 0.01), - ]; - - let mut problem = if marks.len() == expected.len() { - None - } else { - Some(format!( - "Different lengths: got {}, expected {}", - marks.len(), - expected.len() - )) - }; - - for (i, (a, b)) in marks.iter().zip(&expected).enumerate() { - if !approx_eq(a, b) { - problem = Some(format!("Mismatch at index {i}: {a:?} != {b:?}")); - break; - } - } - - if let Some(problem) = problem { - panic!("Test failed: {problem}. Got: {marks:#?}, expected: {expected:#?}"); - } -} - -fn cmp_f64(a: f64, b: f64) -> Ordering { - match a.partial_cmp(&b) { - Some(ord) => ord, - None => a.is_nan().cmp(&b.is_nan()), - } -} - -/// Fill in all values between [min, max] which are a multiple of `step_size` -fn fill_marks_between(out: &mut Vec, step_size: f64, (min, max): (f64, f64)) { - debug_assert!(min <= max, "Bad plot bounds: min: {min}, max: {max}"); - let first = (min / step_size).ceil() as i64; - let last = (max / step_size).ceil() as i64; - - let marks_iter = (first..last).map(|i| { - let value = (i as f64) * step_size; - GridMark { value, step_size } - }); - out.extend(marks_iter); -} - /// Helper for formatting a number so that we always show at least a few /// decimals, unless it is an integer, in which case we never show any decimals. pub fn format_number(number: f64, num_decimals: usize) -> String { diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index c5639973..c0a9af48 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -33,9 +33,9 @@ use crate::CoordinatesFormatter; use crate::placement::Corner; use crate::Cursor; use crate::CursorLinkGroups; -use crate::GridInput; -use crate::GridMark; -use crate::GridSpacer; +use crate::grid::GridInput; +use crate::grid::GridMark; +use crate::grid::GridSpacer; use crate::placement::HPlacement; use crate::LabelFormatter; use crate::Legend; @@ -177,7 +177,7 @@ impl<'a> Plot<'a> { show_grid: true.into(), grid_spacing: Rangef::new(8.0, 300.0), - grid_spacers: [crate::log_grid_spacer(10), crate::log_grid_spacer(10)], + grid_spacers: [crate::grid::log_grid_spacer(10), crate::grid::log_grid_spacer(10)], clamp_grid: false, sense: egui::Sense::click_and_drag(), @@ -434,7 +434,7 @@ impl<'a> Plot<'a> { /// drawn. For example, if x = 80..=230 is visible and you want big /// marks at steps of 100 and small ones at 25, you can return: /// ```no_run - /// # use egui_plot::GridMark; + /// # use egui_plot::grid::GridMark; /// vec![ /// // 100s /// GridMark { @@ -466,8 +466,8 @@ impl<'a> Plot<'a> { /// # () /// ``` /// - /// There are helpers for common cases, see [`crate::log_grid_spacer`] and - /// [`crate::uniform_grid_spacer`]. + /// There are helpers for common cases, see [`crate::grid::log_grid_spacer`] and + /// [`crate::grid::uniform_grid_spacer`]. #[inline] pub fn x_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec + 'a) -> Self { self.grid_spacers[0] = Box::new(spacer); From c58e8641969fa7b0d8a1ff8340e077f34df1d527 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:36:05 +0100 Subject: [PATCH 17/26] label --- egui_plot/src/items/bar_chart.rs | 4 ++-- egui_plot/src/items/box_plot.rs | 2 +- egui_plot/src/items/heatmap.rs | 2 +- egui_plot/src/items/mod.rs | 2 +- egui_plot/src/label.rs | 20 ++++++++++++++++++++ egui_plot/src/lib.rs | 21 +-------------------- egui_plot/src/plot.rs | 2 +- 7 files changed, 27 insertions(+), 26 deletions(-) create mode 100644 egui_plot/src/label.rs diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index 72e42c6a..6123d9e4 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -17,7 +17,7 @@ use crate::colors::highlighted_color; use crate::values::ClosestElem; use crate::Cursor; use crate::Id; -use crate::LabelFormatter; +use crate::label::LabelFormatter; use crate::values::Orientation; use crate::bounds::PlotBounds; use crate::PlotConfig; @@ -414,6 +414,6 @@ impl RectElement for Bar { Orientation::Vertical => scale[1], }; let decimals = ((-scale.abs().log10()).ceil().at_least(0.0) as usize).at_most(6); - crate::format_number(self.value, decimals) + crate::label::format_number(self.value, decimals) } } diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index 0dc90298..62ee50ca 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -16,7 +16,7 @@ use crate::colors::highlighted_color; use crate::values::ClosestElem; use crate::Cursor; use crate::Id; -use crate::LabelFormatter; +use crate::label::LabelFormatter; use crate::values::Orientation; use crate::bounds::PlotBounds; use crate::PlotConfig; diff --git a/egui_plot/src/items/heatmap.rs b/egui_plot/src/items/heatmap.rs index 0d4674f4..56885c6a 100644 --- a/egui_plot/src/items/heatmap.rs +++ b/egui_plot/src/items/heatmap.rs @@ -14,7 +14,7 @@ use egui::WidgetText; use emath::Float as _; use crate::colors::BASE_COLORS; use super::Cursor; -use super::LabelFormatter; +use crate::label::LabelFormatter; use crate::bounds::PlotBounds; use super::PlotTransform; use crate::values::ClosestElem; diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 4ba34554..4575378c 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -39,7 +39,7 @@ use crate::values::PlotGeometry; use crate::values::PlotPoint; use super::Cursor; -use super::LabelFormatter; +use crate::label::LabelFormatter; use crate::bounds::PlotBounds; use super::PlotTransform; diff --git a/egui_plot/src/label.rs b/egui_plot/src/label.rs new file mode 100644 index 00000000..9a15f147 --- /dev/null +++ b/egui_plot/src/label.rs @@ -0,0 +1,20 @@ +use emath::NumExt; +use crate::PlotPoint; + +/// Helper for formatting a number so that we always show at least a few +/// decimals, unless it is an integer, in which case we never show any decimals. +pub fn format_number(number: f64, num_decimals: usize) -> String { + let is_integral = number as i64 as f64 == number; + if is_integral { + // perfect integer - show it as such: + format!("{number:.0}") + } else { + // make sure we tell the user it is not an integer by always showing a decimal + // or two: + format!("{:.*}", num_decimals.at_least(1), number) + } +} + +type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a; +/// Optional label formatter function for customizing hover labels. +pub type LabelFormatter<'a> = Option>>; \ No newline at end of file diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 530fe1f2..ef70ca2b 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -23,7 +23,7 @@ mod values; mod placement; mod bounds; mod grid; - +mod label; use ahash::HashMap; use egui::Color32; @@ -76,11 +76,6 @@ pub use crate::grid::uniform_grid_spacer; pub use bounds::PlotBounds; pub use crate::transform::PlotTransform; -type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a; - -/// Optional label formatter function for customizing hover labels. -pub type LabelFormatter<'a> = Option>>; - type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a; /// Specifies the coordinates formatting when passed to @@ -167,20 +162,6 @@ pub struct PlotResponse { // ---------------------------------------------------------------------------- -/// Helper for formatting a number so that we always show at least a few -/// decimals, unless it is an integer, in which case we never show any decimals. -pub fn format_number(number: f64, num_decimals: usize) -> String { - let is_integral = number as i64 as f64 == number; - if is_integral { - // perfect integer - show it as such: - format!("{number:.0}") - } else { - // make sure we tell the user it is not an integer by always showing a decimal - // or two: - format!("{:.*}", num_decimals.at_least(1), number) - } -} - /// Determine a color from a 0-1 strength value. pub fn color_from_strength(ui: &Ui, strength: f32) -> Color32 { let base_color = ui.visuals().text_color(); diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index c0a9af48..d993fc10 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -37,7 +37,7 @@ use crate::grid::GridInput; use crate::grid::GridMark; use crate::grid::GridSpacer; use crate::placement::HPlacement; -use crate::LabelFormatter; +use crate::label::LabelFormatter; use crate::Legend; use crate::bounds::LinkedBounds; use crate::bounds::PlotBounds; From dbfb186ef8887c5da3f959abee21e064a88514a8 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:38:55 +0100 Subject: [PATCH 18/26] cursor --- egui_plot/src/cursor.rs | 28 ++++++++++++++++++++++++++++ egui_plot/src/lib.rs | 35 ++++------------------------------- 2 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 egui_plot/src/cursor.rs diff --git a/egui_plot/src/cursor.rs b/egui_plot/src/cursor.rs new file mode 100644 index 00000000..4d32b975 --- /dev/null +++ b/egui_plot/src/cursor.rs @@ -0,0 +1,28 @@ +use ahash::HashMap; +use egui::Id; + +/// Indicates a vertical or horizontal cursor line in plot coordinates. +#[derive(Copy, Clone, PartialEq)] +pub enum Cursor { + /// Horizontal cursor line at the given y-coordinate. + Horizontal { + /// Y-coordinate of the horizontal cursor line. + y: f64, + }, + + /// Vertical cursor line at the given x-coordinate. + Vertical { + /// X-coordinate of the vertical cursor line. + x: f64, + }, +} + +/// Contains the cursors drawn for a plot widget in a single frame. +#[derive(PartialEq, Clone)] +pub(crate) struct PlotFrameCursors { + pub(crate) id: Id, + pub(crate) cursors: Vec, +} + +#[derive(Default, Clone)] +pub(crate) struct CursorLinkGroups(pub(crate) HashMap>); \ No newline at end of file diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index ef70ca2b..6c302772 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -24,11 +24,10 @@ mod placement; mod bounds; mod grid; mod label; +mod cursor; -use ahash::HashMap; use egui::Color32; use egui::Id; -use egui::NumExt as _; use egui::Response; use egui::Ui; @@ -68,6 +67,9 @@ pub use crate::legend::Legend; pub use crate::memory::PlotMemory; pub use crate::plot::Plot; pub use crate::plot_ui::PlotUi; +pub use crate::cursor::Cursor; +pub(crate) use crate::cursor::PlotFrameCursors; +pub(crate) use crate::cursor::CursorLinkGroups; pub use crate::grid::GridInput; pub use crate::grid::GridMark; pub use crate::grid::GridSpacer; @@ -111,35 +113,6 @@ impl Default for CoordinatesFormatter<'_> { } } -// ---------------------------------------------------------------------------- - -/// Indicates a vertical or horizontal cursor line in plot coordinates. -#[derive(Copy, Clone, PartialEq)] -pub enum Cursor { - /// Horizontal cursor line at the given y-coordinate. - Horizontal { - /// Y-coordinate of the horizontal cursor line. - y: f64, - }, - - /// Vertical cursor line at the given x-coordinate. - Vertical { - /// X-coordinate of the vertical cursor line. - x: f64, - }, -} - -/// Contains the cursors drawn for a plot widget in a single frame. -#[derive(PartialEq, Clone)] -struct PlotFrameCursors { - id: Id, - cursors: Vec, -} - -#[derive(Default, Clone)] -struct CursorLinkGroups(HashMap>); - -// ---------------------------------------------------------------------------- /// What [`Plot::show`] returns. pub struct PlotResponse { From 1e41b111d6a2cf59daf7ef097425cc57e3e65bbe Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:39:29 +0100 Subject: [PATCH 19/26] colors --- egui_plot/src/axis.rs | 3 ++- egui_plot/src/colors.rs | 8 +++++++- egui_plot/src/lib.rs | 7 ------- egui_plot/src/plot.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/egui_plot/src/axis.rs b/egui_plot/src/axis.rs index eca55f27..9fc72f82 100644 --- a/egui_plot/src/axis.rs +++ b/egui_plot/src/axis.rs @@ -15,6 +15,7 @@ use egui::WidgetText; use egui::emath::Rot2; use egui::emath::remap_clamp; use egui::epaint::TextShape; +use crate::colors; use crate::placement::{HPlacement, Placement, VPlacement}; use crate::grid::GridMark; use super::transform::PlotTransform; @@ -266,7 +267,7 @@ impl<'a> AxisWidget<'a> { // Fade in labels as they get further apart: let strength = remap_clamp(spacing_in_points, label_spacing, 0.0..=1.0); - let text_color = super::color_from_strength(ui, strength); + let text_color = colors::color_from_strength(ui, strength); let galley = painter.layout_no_wrap(text, font_id.clone(), text_color); let galley_size = match axis { Axis::X => galley.size(), diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs index 207af15e..06618c45 100644 --- a/egui_plot/src/colors.rs +++ b/egui_plot/src/colors.rs @@ -38,4 +38,10 @@ pub const BASE_COLORS: [Color32; 10] = [ Color32::from_rgb(246, 135, 8), Color32::from_rgb(213, 68, 2), Color32::from_rgb(122, 4, 2), -]; \ No newline at end of file +]; + +/// Determine a color from a 0-1 strength value. +pub fn color_from_strength(ui: &Ui, strength: f32) -> Color32 { + let base_color = ui.visuals().text_color(); + base_color.gamma_multiply(strength.sqrt()) +} \ No newline at end of file diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 6c302772..e02b506d 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -26,10 +26,8 @@ mod grid; mod label; mod cursor; -use egui::Color32; use egui::Id; use egui::Response; -use egui::Ui; pub use crate::axis::Axis; pub use crate::axis::AxisHints; @@ -135,8 +133,3 @@ pub struct PlotResponse { // ---------------------------------------------------------------------------- -/// Determine a color from a 0-1 strength value. -pub fn color_from_strength(ui: &Ui, strength: f32) -> Color32 { - let base_color = ui.visuals().text_color(); - base_color.gamma_multiply(strength.sqrt()) -} diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index d993fc10..4e0653b6 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -1479,7 +1479,7 @@ impl<'a> Plot<'a> { let line_strength = remap_clamp(spacing_in_points, self.grid_spacing, 0.0..=1.0); - let line_color = crate::color_from_strength(ui, line_strength); + let line_color = crate::colors::color_from_strength(ui, line_strength); let mut p0 = pos_in_gui; let mut p1 = pos_in_gui; From 30f521efce80727f895f03a98320ae4ae3140597 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:42:23 +0100 Subject: [PATCH 20/26] plotresponse --- egui_plot/src/lib.rs | 25 +------------------------ egui_plot/src/plot.rs | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index e02b506d..591de598 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -27,7 +27,6 @@ mod label; mod cursor; use egui::Id; -use egui::Response; pub use crate::axis::Axis; pub use crate::axis::AxisHints; @@ -64,6 +63,7 @@ pub use crate::placement::Corner; pub use crate::legend::Legend; pub use crate::memory::PlotMemory; pub use crate::plot::Plot; +pub use crate::plot::PlotResponse; pub use crate::plot_ui::PlotUi; pub use crate::cursor::Cursor; pub(crate) use crate::cursor::PlotFrameCursors; @@ -110,26 +110,3 @@ impl Default for CoordinatesFormatter<'_> { Self::with_decimals(3) } } - - -/// What [`Plot::show`] returns. -pub struct PlotResponse { - /// What the user closure returned. - pub inner: R, - - /// The response of the plot. - pub response: Response, - - /// The transform between screen coordinates and plot coordinates. - pub transform: PlotTransform, - - /// The id of a currently hovered item if any. - /// - /// This is `None` if either no item was hovered. - /// A plot item can be hovered either by hovering its representation in the - /// plot (line, marker, etc.) or by hovering the item in the legend. - pub hovered_plot_item: Option, -} - -// ---------------------------------------------------------------------------- - diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 4e0653b6..8531e3a2 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -45,7 +45,6 @@ use crate::PlotFrameCursors; use crate::PlotItem; use crate::PlotMemory; use crate::values::PlotPoint; -use crate::PlotResponse; use crate::PlotTransform; use crate::PlotUi; use crate::placement::VPlacement; @@ -1817,3 +1816,22 @@ fn axis_widgets<'a>( ([x_axis_widgets, y_axis_widgets], plot_rect) } + +/// What [`Plot::show`] returns. +pub struct PlotResponse { + /// What the user closure returned. + pub inner: R, + + /// The response of the plot. + pub response: Response, + + /// The transform between screen coordinates and plot coordinates. + pub transform: PlotTransform, + + /// The id of a currently hovered item if any. + /// + /// This is `None` if either no item was hovered. + /// A plot item can be hovered either by hovering its representation in the + /// plot (line, marker, etc.) or by hovering the item in the legend. + pub hovered_plot_item: Option, +} \ No newline at end of file From ae3acade38d2c36910f563b9c463f8c9d1377fda Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:45:52 +0100 Subject: [PATCH 21/26] coordinates overlays --- egui_plot/src/items/mod.rs | 2 +- egui_plot/src/lib.rs | 37 ++------------------------- egui_plot/src/overlays/coordinates.rs | 37 +++++++++++++++++++++++++++ egui_plot/src/overlays/mod.rs | 5 ++++ egui_plot/src/plot.rs | 2 +- 5 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 egui_plot/src/overlays/coordinates.rs create mode 100644 egui_plot/src/overlays/mod.rs diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 4575378c..59eb118f 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -1,4 +1,4 @@ -//! Contains items that can be added to a plot. +//! Contains items that can be added to a plot at some plot coordinates. #![expect(clippy::type_complexity)] // TODO(#163): simplify some of the callback types with type aliases use std::ops::RangeInclusive; diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 591de598..56b0a829 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -25,6 +25,7 @@ mod bounds; mod grid; mod label; mod cursor; +mod overlays; use egui::Id; @@ -75,38 +76,4 @@ pub use crate::grid::log_grid_spacer; pub use crate::grid::uniform_grid_spacer; pub use bounds::PlotBounds; pub use crate::transform::PlotTransform; - -type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a; - -/// Specifies the coordinates formatting when passed to -/// [`Plot::coordinates_formatter`]. -pub struct CoordinatesFormatter<'a> { - function: Box>, -} - -impl<'a> CoordinatesFormatter<'a> { - /// Create a new formatter based on the pointer coordinate and the plot - /// bounds. - pub fn new(function: impl Fn(&PlotPoint, &PlotBounds) -> String + 'a) -> Self { - Self { - function: Box::new(function), - } - } - - /// Show a fixed number of decimal places. - pub fn with_decimals(num_decimals: usize) -> Self { - Self { - function: Box::new(move |value, _| format!("x: {:.d$}\ny: {:.d$}", value.x, value.y, d = num_decimals)), - } - } - - fn format(&self, value: &PlotPoint, bounds: &PlotBounds) -> String { - (self.function)(value, bounds) - } -} - -impl Default for CoordinatesFormatter<'_> { - fn default() -> Self { - Self::with_decimals(3) - } -} +pub use crate::overlays::CoordinatesFormatter; diff --git a/egui_plot/src/overlays/coordinates.rs b/egui_plot/src/overlays/coordinates.rs new file mode 100644 index 00000000..29f28318 --- /dev/null +++ b/egui_plot/src/overlays/coordinates.rs @@ -0,0 +1,37 @@ +use crate::bounds::PlotBounds; +use crate::values::PlotPoint; + +type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a; + +/// Specifies the coordinates formatting when passed to +/// [`Plot::coordinates_formatter`]. +pub struct CoordinatesFormatter<'a> { + function: Box>, +} + +impl<'a> CoordinatesFormatter<'a> { + /// Create a new formatter based on the pointer coordinate and the plot + /// bounds. + pub fn new(function: impl Fn(&PlotPoint, &PlotBounds) -> String + 'a) -> Self { + Self { + function: Box::new(function), + } + } + + /// Show a fixed number of decimal places. + pub fn with_decimals(num_decimals: usize) -> Self { + Self { + function: Box::new(move |value, _| format!("x: {:.d$}\ny: {:.d$}", value.x, value.y, d = num_decimals)), + } + } + + pub(crate) fn format(&self, value: &PlotPoint, bounds: &PlotBounds) -> String { + (self.function)(value, bounds) + } +} + +impl Default for CoordinatesFormatter<'_> { + fn default() -> Self { + Self::with_decimals(3) + } +} \ No newline at end of file diff --git a/egui_plot/src/overlays/mod.rs b/egui_plot/src/overlays/mod.rs new file mode 100644 index 00000000..e8e57404 --- /dev/null +++ b/egui_plot/src/overlays/mod.rs @@ -0,0 +1,5 @@ +//! Contains widgets that can be added to a plot at some fixed screen coordinates. + +mod coordinates; + +pub use coordinates::CoordinatesFormatter; \ No newline at end of file diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 8531e3a2..01e05eae 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -29,7 +29,7 @@ use crate::Axis; use crate::AxisHints; use crate::bounds::BoundsLinkGroups; use crate::bounds::BoundsModification; -use crate::CoordinatesFormatter; +use crate::overlays::CoordinatesFormatter; use crate::placement::Corner; use crate::Cursor; use crate::CursorLinkGroups; From af79657dc49016392f72d3a1f0b4f95545d74040 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:46:31 +0100 Subject: [PATCH 22/26] legend as overlay --- egui_plot/src/lib.rs | 5 ++--- egui_plot/src/{ => overlays}/legend.rs | 6 +++--- egui_plot/src/overlays/mod.rs | 1 + egui_plot/src/plot.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename egui_plot/src/{ => overlays}/legend.rs (99%) diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 56b0a829..11a6ff83 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -11,7 +11,6 @@ mod axis; mod colors; mod items; -mod legend; mod math; mod memory; mod plot; @@ -59,9 +58,9 @@ pub use crate::items::Polygon; pub use crate::items::Span; pub use crate::items::Text; pub use crate::items::VLine; -pub use crate::legend::ColorConflictHandling; +pub use overlays::legend::ColorConflictHandling; pub use crate::placement::Corner; -pub use crate::legend::Legend; +pub use overlays::legend::Legend; pub use crate::memory::PlotMemory; pub use crate::plot::Plot; pub use crate::plot::PlotResponse; diff --git a/egui_plot/src/legend.rs b/egui_plot/src/overlays/legend.rs similarity index 99% rename from egui_plot/src/legend.rs rename to egui_plot/src/overlays/legend.rs index 6bd27114..b0eb8adc 100644 --- a/egui_plot/src/legend.rs +++ b/egui_plot/src/overlays/legend.rs @@ -22,7 +22,7 @@ use egui::epaint::CircleShape; use egui::pos2; use egui::vec2; use crate::placement::Corner; -use super::items::PlotItem; +use crate::PlotItem; /// How to handle multiple conflicting color for a legend item. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -209,7 +209,7 @@ impl LegendEntry { } #[derive(Clone)] -pub(super) struct LegendWidget { +pub(crate) struct LegendWidget { rect: Rect, entries: Vec, config: Legend, @@ -218,7 +218,7 @@ pub(super) struct LegendWidget { impl LegendWidget { /// Create a new legend from items, the names of items that are hidden and /// the style of the text. Returns `None` if the legend has no entries. - pub(super) fn try_new<'a>( + pub(crate) fn try_new<'a>( rect: Rect, config: Legend, items: &[Box], diff --git a/egui_plot/src/overlays/mod.rs b/egui_plot/src/overlays/mod.rs index e8e57404..3b90942f 100644 --- a/egui_plot/src/overlays/mod.rs +++ b/egui_plot/src/overlays/mod.rs @@ -1,5 +1,6 @@ //! Contains widgets that can be added to a plot at some fixed screen coordinates. mod coordinates; +pub mod legend; pub use coordinates::CoordinatesFormatter; \ No newline at end of file diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 01e05eae..59bead5a 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -53,7 +53,7 @@ use crate::items; use crate::items::horizontal_line; use crate::colors::rulers_color; use crate::items::vertical_line; -use crate::legend::LegendWidget; +use crate::overlays::legend::LegendWidget; /// Combined axis widgets: `[x_axis_widgets, y_axis_widgets]` type AxisWidgets<'a> = [Vec>; 2]; From 30f7ccfddc87848e056f2d89e67f575e3726702c Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 16:50:11 +0100 Subject: [PATCH 23/26] cleanups --- egui_plot/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 11a6ff83..7bb2fc18 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -76,3 +76,6 @@ pub use crate::grid::uniform_grid_spacer; pub use bounds::PlotBounds; pub use crate::transform::PlotTransform; pub use crate::overlays::CoordinatesFormatter; +pub use crate::colors::color_from_strength; +pub use crate::label::format_number; +pub use crate::label::LabelFormatter; From bfb23f4e947077265b72b159043ea2028f2f3833 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 17:23:46 +0100 Subject: [PATCH 24/26] cargo fmt --- egui_plot/src/axis.rs | 7 ++- egui_plot/src/bounds.rs | 7 ++- egui_plot/src/colors.rs | 9 ++-- egui_plot/src/cursor.rs | 2 +- egui_plot/src/grid.rs | 4 +- egui_plot/src/items/arrows.rs | 6 +-- egui_plot/src/items/bar_chart.rs | 18 ++++---- egui_plot/src/items/box_plot.rs | 18 ++++---- egui_plot/src/items/heatmap.rs | 11 ++--- egui_plot/src/items/line.rs | 12 ++--- egui_plot/src/items/mod.rs | 15 +++---- egui_plot/src/items/plot_image.rs | 6 +-- egui_plot/src/items/points.rs | 8 ++-- egui_plot/src/items/polygon.rs | 8 ++-- egui_plot/src/items/series.rs | 10 ++--- egui_plot/src/items/span.rs | 4 +- egui_plot/src/items/text.rs | 6 +-- egui_plot/src/label.rs | 5 ++- egui_plot/src/lib.rs | 63 +++++++++++++-------------- egui_plot/src/math.rs | 9 ++-- egui_plot/src/memory.rs | 2 +- egui_plot/src/overlays/coordinates.rs | 4 +- egui_plot/src/overlays/legend.rs | 3 +- egui_plot/src/overlays/mod.rs | 5 ++- egui_plot/src/placement.rs | 2 +- egui_plot/src/plot.rs | 34 +++++++-------- egui_plot/src/plot_ui.rs | 6 +-- egui_plot/src/rect_elem.rs | 1 - egui_plot/src/transform.rs | 2 +- 29 files changed, 151 insertions(+), 136 deletions(-) diff --git a/egui_plot/src/axis.rs b/egui_plot/src/axis.rs index 9fc72f82..f7f7dbc6 100644 --- a/egui_plot/src/axis.rs +++ b/egui_plot/src/axis.rs @@ -15,10 +15,13 @@ use egui::WidgetText; use egui::emath::Rot2; use egui::emath::remap_clamp; use egui::epaint::TextShape; + +use super::transform::PlotTransform; use crate::colors; -use crate::placement::{HPlacement, Placement, VPlacement}; use crate::grid::GridMark; -use super::transform::PlotTransform; +use crate::placement::HPlacement; +use crate::placement::Placement; +use crate::placement::VPlacement; // Gap between tick labels and axis label in units of the axis label height const AXIS_LABEL_GAP: f32 = 0.25; diff --git a/egui_plot/src/bounds.rs b/egui_plot/src/bounds.rs index e851dbbf..eb1af275 100644 --- a/egui_plot/src/bounds.rs +++ b/egui_plot/src/bounds.rs @@ -1,7 +1,10 @@ use std::ops::RangeInclusive; + use ahash::HashMap; use egui::Id; -use emath::{Vec2, Vec2b}; +use emath::Vec2; +use emath::Vec2b; + use crate::PlotPoint; /// 2D bounding box of f64 precision. @@ -277,4 +280,4 @@ pub enum BoundsModification { Translate(Vec2), AutoBounds(Vec2b), Zoom(Vec2, PlotPoint), -} \ No newline at end of file +} diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs index 06618c45..1721274e 100644 --- a/egui_plot/src/colors.rs +++ b/egui_plot/src/colors.rs @@ -1,5 +1,8 @@ -use egui::{Color32, Rgba, Stroke, Ui}; -use emath::NumExt; +use egui::Color32; +use egui::Rgba; +use egui::Stroke; +use egui::Ui; +use emath::NumExt as _; pub(crate) fn rulers_color(ui: &Ui) -> Color32 { if ui.visuals().dark_mode { @@ -44,4 +47,4 @@ pub const BASE_COLORS: [Color32; 10] = [ pub fn color_from_strength(ui: &Ui, strength: f32) -> Color32 { let base_color = ui.visuals().text_color(); base_color.gamma_multiply(strength.sqrt()) -} \ No newline at end of file +} diff --git a/egui_plot/src/cursor.rs b/egui_plot/src/cursor.rs index 4d32b975..a56effc2 100644 --- a/egui_plot/src/cursor.rs +++ b/egui_plot/src/cursor.rs @@ -25,4 +25,4 @@ pub(crate) struct PlotFrameCursors { } #[derive(Default, Clone)] -pub(crate) struct CursorLinkGroups(pub(crate) HashMap>); \ No newline at end of file +pub(crate) struct CursorLinkGroups(pub(crate) HashMap>); diff --git a/egui_plot/src/grid.rs b/egui_plot/src/grid.rs index 7f0da353..509c7545 100644 --- a/egui_plot/src/grid.rs +++ b/egui_plot/src/grid.rs @@ -5,7 +5,7 @@ pub type GridSpacer<'a> = Box>; /// Input for "grid spacer" functions. /// -/// See [`Plot::x_grid_spacer()`] and [`Plot::y_grid_spacer()`]. +/// See [`crate::Plot::x_grid_spacer()`] and [`crate::Plot::y_grid_spacer()`]. pub struct GridInput { /// Min/max of the visible data range (the values at the two edges of the /// plot, for the current axis). @@ -202,4 +202,4 @@ fn fill_marks_between(out: &mut Vec, step_size: f64, (min, max): (f64, GridMark { value, step_size } }); out.extend(marks_iter); -} \ No newline at end of file +} diff --git a/egui_plot/src/items/arrows.rs b/egui_plot/src/items/arrows.rs index d3b31974..eaa97049 100644 --- a/egui_plot/src/items/arrows.rs +++ b/egui_plot/src/items/arrows.rs @@ -7,12 +7,12 @@ use egui::Ui; use emath::Rot2; use crate::Id; -use crate::bounds::PlotBounds; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::values::PlotPoints; use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::values::PlotGeometry; +use crate::values::PlotPoints; impl<'a> Arrows<'a> { pub fn new(name: impl Into, origins: impl Into>, tips: impl Into>) -> Self { diff --git a/egui_plot/src/items/bar_chart.rs b/egui_plot/src/items/bar_chart.rs index 6123d9e4..e7bf7351 100644 --- a/egui_plot/src/items/bar_chart.rs +++ b/egui_plot/src/items/bar_chart.rs @@ -11,21 +11,21 @@ use emath::NumExt as _; use emath::Pos2; use super::add_rulers_and_text; -use crate::math::find_closest_rect; -use crate::rect_elem::RectElement; -use crate::colors::highlighted_color; -use crate::values::ClosestElem; use crate::Cursor; use crate::Id; -use crate::label::LabelFormatter; -use crate::values::Orientation; -use crate::bounds::PlotBounds; use crate::PlotConfig; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::values::PlotPoint; use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::colors::highlighted_color; +use crate::label::LabelFormatter; +use crate::math::find_closest_rect; +use crate::rect_elem::RectElement; +use crate::values::ClosestElem; +use crate::values::Orientation; +use crate::values::PlotGeometry; +use crate::values::PlotPoint; /// A bar chart. pub struct BarChart { diff --git a/egui_plot/src/items/box_plot.rs b/egui_plot/src/items/box_plot.rs index 62ee50ca..08463a47 100644 --- a/egui_plot/src/items/box_plot.rs +++ b/egui_plot/src/items/box_plot.rs @@ -10,21 +10,21 @@ use emath::NumExt as _; use emath::Pos2; use super::add_rulers_and_text; -use crate::math::find_closest_rect; -use crate::rect_elem::RectElement; -use crate::colors::highlighted_color; -use crate::values::ClosestElem; use crate::Cursor; use crate::Id; -use crate::label::LabelFormatter; -use crate::values::Orientation; -use crate::bounds::PlotBounds; use crate::PlotConfig; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::values::PlotPoint; use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::colors::highlighted_color; +use crate::label::LabelFormatter; +use crate::math::find_closest_rect; +use crate::rect_elem::RectElement; +use crate::values::ClosestElem; +use crate::values::Orientation; +use crate::values::PlotGeometry; +use crate::values::PlotPoint; /// A diagram containing a series of [`BoxElem`] elements. pub struct BoxPlot { diff --git a/egui_plot/src/items/heatmap.rs b/egui_plot/src/items/heatmap.rs index 56885c6a..4f34e721 100644 --- a/egui_plot/src/items/heatmap.rs +++ b/egui_plot/src/items/heatmap.rs @@ -12,16 +12,17 @@ use egui::Ui; use egui::Vec2; use egui::WidgetText; use emath::Float as _; -use crate::colors::BASE_COLORS; + use super::Cursor; -use crate::label::LabelFormatter; -use crate::bounds::PlotBounds; use super::PlotTransform; -use crate::values::ClosestElem; use crate::PlotConfig; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; +use crate::bounds::PlotBounds; +use crate::colors::BASE_COLORS; +use crate::label::LabelFormatter; +use crate::values::ClosestElem; +use crate::values::PlotGeometry; use crate::values::PlotPoint; /// Default resolution for heatmap color palette diff --git a/egui_plot/src/items/line.rs b/egui_plot/src/items/line.rs index 3c3b259c..2bd67848 100644 --- a/egui_plot/src/items/line.rs +++ b/egui_plot/src/items/line.rs @@ -5,15 +5,17 @@ use egui::Shape; use egui::Stroke; use egui::Ui; use egui::epaint::PathStroke; -use emath::{pos2, Pos2}; +use emath::Pos2; +use emath::pos2; + use crate::Id; -use crate::values::LineStyle; -use crate::bounds::PlotBounds; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::values::PlotPoint; use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::values::LineStyle; +use crate::values::PlotGeometry; +use crate::values::PlotPoint; /// A horizontal line in a plot, filling the full width #[derive(Clone, Debug, PartialEq)] diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 59eb118f..007a30e0 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -23,26 +23,26 @@ use emath::Float as _; pub use heatmap::Heatmap; pub use line::HLine; pub use line::VLine; -pub use line::vertical_line; pub use line::horizontal_line; +pub use line::vertical_line; pub use plot_image::PlotImage; pub use points::Points; pub use polygon::Polygon; -use crate::rect_elem::RectElement; pub use series::Line; pub use span::Span; pub use text::Text; + +use super::Cursor; +use super::PlotTransform; +use crate::bounds::PlotBounds; +use crate::label::LabelFormatter; +use crate::rect_elem::RectElement; use crate::values::ClosestElem; use crate::values::LineStyle; use crate::values::Orientation; use crate::values::PlotGeometry; use crate::values::PlotPoint; -use super::Cursor; -use crate::label::LabelFormatter; -use crate::bounds::PlotBounds; -use super::PlotTransform; - mod arrows; mod bar_chart; mod box_plot; @@ -326,4 +326,3 @@ pub(super) fn rulers_and_tooltip_at_value( ui.label(text); }); } - diff --git a/egui_plot/src/items/plot_image.rs b/egui_plot/src/items/plot_image.rs index 441aede7..be0b41a4 100644 --- a/egui_plot/src/items/plot_image.rs +++ b/egui_plot/src/items/plot_image.rs @@ -13,12 +13,12 @@ use emath::Vec2; use emath::pos2; use crate::Id; -use crate::bounds::PlotBounds; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::values::PlotPoint; use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::values::PlotGeometry; +use crate::values::PlotPoint; /// An image in the plot. #[derive(Clone)] diff --git a/egui_plot/src/items/points.rs b/egui_plot/src/items/points.rs index 8e91b7d3..24a02b08 100644 --- a/egui_plot/src/items/points.rs +++ b/egui_plot/src/items/points.rs @@ -10,14 +10,14 @@ use emath::pos2; use emath::vec2; use crate::Id; -use crate::values::MarkerShape; -use crate::bounds::PlotBounds; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; +use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::values::MarkerShape; +use crate::values::PlotGeometry; use crate::values::PlotPoint; use crate::values::PlotPoints; -use crate::PlotTransform; impl<'a> Points<'a> { pub fn new(name: impl Into, series: impl Into>) -> Self { diff --git a/egui_plot/src/items/polygon.rs b/egui_plot/src/items/polygon.rs index 58d7fd60..9e431b48 100644 --- a/egui_plot/src/items/polygon.rs +++ b/egui_plot/src/items/polygon.rs @@ -7,14 +7,14 @@ use egui::Stroke; use egui::Ui; use egui::epaint::PathStroke; +use crate::PlotItem; +use crate::PlotItemBase; +use crate::PlotTransform; +use crate::bounds::PlotBounds; use crate::colors::DEFAULT_FILL_ALPHA; use crate::values::LineStyle; -use crate::bounds::PlotBounds; use crate::values::PlotGeometry; -use crate::PlotItem; -use crate::PlotItemBase; use crate::values::PlotPoints; -use crate::PlotTransform; /// A convex polygon. pub struct Polygon<'a> { diff --git a/egui_plot/src/items/series.rs b/egui_plot/src/items/series.rs index 0fc2ee5c..a3e88f48 100644 --- a/egui_plot/src/items/series.rs +++ b/egui_plot/src/items/series.rs @@ -13,17 +13,17 @@ use emath::Pos2; use emath::Rect; use emath::pos2; +use crate::Id; +use crate::PlotItem; +use crate::PlotItemBase; +use crate::PlotTransform; +use crate::bounds::PlotBounds; use crate::colors::DEFAULT_FILL_ALPHA; use crate::math::y_intersection; -use crate::Id; use crate::values::LineStyle; -use crate::bounds::PlotBounds; use crate::values::PlotGeometry; -use crate::PlotItem; -use crate::PlotItemBase; use crate::values::PlotPoint; use crate::values::PlotPoints; -use crate::PlotTransform; /// A series of values forming a path. pub struct Line<'a> { diff --git a/egui_plot/src/items/span.rs b/egui_plot/src/items/span.rs index ddab2cf8..c990d4d5 100644 --- a/egui_plot/src/items/span.rs +++ b/egui_plot/src/items/span.rs @@ -16,14 +16,14 @@ use egui::pos2; use emath::TSTransform; use super::LineStyle; -use crate::bounds::PlotBounds; use super::PlotGeometry; use super::PlotItem; use super::PlotItemBase; use super::PlotPoint; use super::PlotTransform; -use crate::colors::highlighted_color; use crate::Axis; +use crate::bounds::PlotBounds; +use crate::colors::highlighted_color; use crate::utils::find_name_candidate; /// Padding between the label of the span and both the edge of the view and the diff --git a/egui_plot/src/items/text.rs b/egui_plot/src/items/text.rs index e38dbc6a..b0632f20 100644 --- a/egui_plot/src/items/text.rs +++ b/egui_plot/src/items/text.rs @@ -10,12 +10,12 @@ use egui::epaint::TextShape; use emath::Align2; use crate::Id; -use crate::bounds::PlotBounds; -use crate::values::PlotGeometry; use crate::PlotItem; use crate::PlotItemBase; -use crate::values::PlotPoint; use crate::PlotTransform; +use crate::bounds::PlotBounds; +use crate::values::PlotGeometry; +use crate::values::PlotPoint; impl Text { pub fn new(name: impl Into, position: PlotPoint, text: impl Into) -> Self { diff --git a/egui_plot/src/label.rs b/egui_plot/src/label.rs index 9a15f147..e6e264a4 100644 --- a/egui_plot/src/label.rs +++ b/egui_plot/src/label.rs @@ -1,4 +1,5 @@ -use emath::NumExt; +use emath::NumExt as _; + use crate::PlotPoint; /// Helper for formatting a number so that we always show at least a few @@ -17,4 +18,4 @@ pub fn format_number(number: f64, num_decimals: usize) -> String { type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a; /// Optional label formatter function for customizing hover labels. -pub type LabelFormatter<'a> = Option>>; \ No newline at end of file +pub type LabelFormatter<'a> = Option>>; diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 7bb2fc18..9b728806 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -9,73 +9,72 @@ //! mod axis; +mod bounds; mod colors; +mod cursor; +mod grid; mod items; +mod label; mod math; mod memory; +mod overlays; +mod placement; mod plot; mod plot_ui; mod rect_elem; mod transform; mod utils; mod values; -mod placement; -mod bounds; -mod grid; -mod label; -mod cursor; -mod overlays; +pub use bounds::PlotBounds; use egui::Id; - -pub use crate::axis::Axis; -pub use crate::axis::AxisHints; +pub use overlays::legend::ColorConflictHandling; +pub use overlays::legend::Legend; pub use placement::HPlacement; pub use placement::Placement; pub use placement::VPlacement; + +pub use crate::axis::Axis; +pub use crate::axis::AxisHints; +pub use crate::colors::color_from_strength; +pub use crate::cursor::Cursor; +pub(crate) use crate::cursor::CursorLinkGroups; +pub(crate) use crate::cursor::PlotFrameCursors; +pub use crate::grid::GridInput; +pub use crate::grid::GridMark; +pub use crate::grid::log_grid_spacer; +pub use crate::grid::uniform_grid_spacer; pub use crate::items::Arrows; pub use crate::items::Bar; pub use crate::items::BarChart; pub use crate::items::BoxElem; pub use crate::items::BoxPlot; pub use crate::items::BoxSpread; -pub use crate::values::ClosestElem; pub use crate::items::HLine; pub use crate::items::Heatmap; pub use crate::items::Line; -pub use crate::values::LineStyle; -pub use crate::values::MarkerShape; -pub use crate::values::Orientation; pub use crate::items::PlotConfig; -pub use crate::values::PlotGeometry; pub use crate::items::PlotImage; pub use crate::items::PlotItem; pub use crate::items::PlotItemBase; -pub use crate::values::PlotPoint; -pub use crate::values::PlotPoints; pub use crate::items::Points; pub use crate::items::Polygon; pub use crate::items::Span; pub use crate::items::Text; pub use crate::items::VLine; -pub use overlays::legend::ColorConflictHandling; -pub use crate::placement::Corner; -pub use overlays::legend::Legend; +pub use crate::label::LabelFormatter; +pub use crate::label::format_number; pub use crate::memory::PlotMemory; +pub use crate::overlays::CoordinatesFormatter; +pub use crate::placement::Corner; pub use crate::plot::Plot; pub use crate::plot::PlotResponse; pub use crate::plot_ui::PlotUi; -pub use crate::cursor::Cursor; -pub(crate) use crate::cursor::PlotFrameCursors; -pub(crate) use crate::cursor::CursorLinkGroups; -pub use crate::grid::GridInput; -pub use crate::grid::GridMark; -pub use crate::grid::GridSpacer; -pub use crate::grid::log_grid_spacer; -pub use crate::grid::uniform_grid_spacer; -pub use bounds::PlotBounds; pub use crate::transform::PlotTransform; -pub use crate::overlays::CoordinatesFormatter; -pub use crate::colors::color_from_strength; -pub use crate::label::format_number; -pub use crate::label::LabelFormatter; +pub use crate::values::ClosestElem; +pub use crate::values::LineStyle; +pub use crate::values::MarkerShape; +pub use crate::values::Orientation; +pub use crate::values::PlotGeometry; +pub use crate::values::PlotPoint; +pub use crate::values::PlotPoints; diff --git a/egui_plot/src/math.rs b/egui_plot/src/math.rs index ee50d4bf..cdfdd9ef 100644 --- a/egui_plot/src/math.rs +++ b/egui_plot/src/math.rs @@ -1,5 +1,8 @@ -use emath::{Float, Pos2}; -use crate::{ClosestElem, PlotTransform}; +use emath::Float as _; +use emath::Pos2; + +use crate::ClosestElem; +use crate::PlotTransform; use crate::rect_elem::RectElement; /// Returns the x-coordinate of a possible intersection between a line segment @@ -27,4 +30,4 @@ where ClosestElem { index, dist_sq } }) .min_by_key(|e| e.dist_sq.ord()) -} \ No newline at end of file +} diff --git a/egui_plot/src/memory.rs b/egui_plot/src/memory.rs index 739aa51c..f469656a 100644 --- a/egui_plot/src/memory.rs +++ b/egui_plot/src/memory.rs @@ -5,8 +5,8 @@ use egui::Id; use egui::Pos2; use egui::Vec2b; -use crate::bounds::PlotBounds; use crate::PlotTransform; +use crate::bounds::PlotBounds; /// Information about the plot that has to persist between frames. #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] diff --git a/egui_plot/src/overlays/coordinates.rs b/egui_plot/src/overlays/coordinates.rs index 29f28318..4b687a38 100644 --- a/egui_plot/src/overlays/coordinates.rs +++ b/egui_plot/src/overlays/coordinates.rs @@ -4,7 +4,7 @@ use crate::values::PlotPoint; type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a; /// Specifies the coordinates formatting when passed to -/// [`Plot::coordinates_formatter`]. +/// [`crate::Plot::coordinates_formatter`]. pub struct CoordinatesFormatter<'a> { function: Box>, } @@ -34,4 +34,4 @@ impl Default for CoordinatesFormatter<'_> { fn default() -> Self { Self::with_decimals(3) } -} \ No newline at end of file +} diff --git a/egui_plot/src/overlays/legend.rs b/egui_plot/src/overlays/legend.rs index b0eb8adc..b512d946 100644 --- a/egui_plot/src/overlays/legend.rs +++ b/egui_plot/src/overlays/legend.rs @@ -21,8 +21,9 @@ use egui::WidgetType; use egui::epaint::CircleShape; use egui::pos2; use egui::vec2; -use crate::placement::Corner; + use crate::PlotItem; +use crate::placement::Corner; /// How to handle multiple conflicting color for a legend item. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/egui_plot/src/overlays/mod.rs b/egui_plot/src/overlays/mod.rs index 3b90942f..1af8664d 100644 --- a/egui_plot/src/overlays/mod.rs +++ b/egui_plot/src/overlays/mod.rs @@ -1,6 +1,7 @@ -//! Contains widgets that can be added to a plot at some fixed screen coordinates. +//! Contains widgets that can be added to a plot at some fixed screen +//! coordinates. mod coordinates; pub mod legend; -pub use coordinates::CoordinatesFormatter; \ No newline at end of file +pub use coordinates::CoordinatesFormatter; diff --git a/egui_plot/src/placement.rs b/egui_plot/src/placement.rs index fa16b97d..be7782ae 100644 --- a/egui_plot/src/placement.rs +++ b/egui_plot/src/placement.rs @@ -78,4 +78,4 @@ impl Corner { .iter() .copied() } -} \ No newline at end of file +} diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 59bead5a..4c8359ec 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -27,33 +27,33 @@ use emath::vec2; use crate::Axis; use crate::AxisHints; -use crate::bounds::BoundsLinkGroups; -use crate::bounds::BoundsModification; -use crate::overlays::CoordinatesFormatter; -use crate::placement::Corner; use crate::Cursor; use crate::CursorLinkGroups; -use crate::grid::GridInput; -use crate::grid::GridMark; -use crate::grid::GridSpacer; -use crate::placement::HPlacement; -use crate::label::LabelFormatter; use crate::Legend; -use crate::bounds::LinkedBounds; -use crate::bounds::PlotBounds; use crate::PlotFrameCursors; use crate::PlotItem; use crate::PlotMemory; -use crate::values::PlotPoint; use crate::PlotTransform; use crate::PlotUi; -use crate::placement::VPlacement; use crate::axis::AxisWidget; +use crate::bounds::BoundsLinkGroups; +use crate::bounds::BoundsModification; +use crate::bounds::LinkedBounds; +use crate::bounds::PlotBounds; +use crate::colors::rulers_color; +use crate::grid::GridInput; +use crate::grid::GridMark; +use crate::grid::GridSpacer; use crate::items; use crate::items::horizontal_line; -use crate::colors::rulers_color; use crate::items::vertical_line; +use crate::label::LabelFormatter; +use crate::overlays::CoordinatesFormatter; use crate::overlays::legend::LegendWidget; +use crate::placement::Corner; +use crate::placement::HPlacement; +use crate::placement::VPlacement; +use crate::values::PlotPoint; /// Combined axis widgets: `[x_axis_widgets, y_axis_widgets]` type AxisWidgets<'a> = [Vec>; 2]; @@ -465,8 +465,8 @@ impl<'a> Plot<'a> { /// # () /// ``` /// - /// There are helpers for common cases, see [`crate::grid::log_grid_spacer`] and - /// [`crate::grid::uniform_grid_spacer`]. + /// There are helpers for common cases, see [`crate::grid::log_grid_spacer`] + /// and [`crate::grid::uniform_grid_spacer`]. #[inline] pub fn x_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec + 'a) -> Self { self.grid_spacers[0] = Box::new(spacer); @@ -1834,4 +1834,4 @@ pub struct PlotResponse { /// A plot item can be hovered either by hovering its representation in the /// plot (line, marker, etc.) or by hovering the item in the legend. pub hovered_plot_item: Option, -} \ No newline at end of file +} diff --git a/egui_plot/src/plot_ui.rs b/egui_plot/src/plot_ui.rs index b81ad744..6dcf2dd6 100644 --- a/egui_plot/src/plot_ui.rs +++ b/egui_plot/src/plot_ui.rs @@ -7,14 +7,14 @@ use egui::Vec2; use egui::Vec2b; use egui::epaint::Hsva; -use crate::bounds::BoundsModification; #[expect(unused_imports)] // for links in docstrings use crate::Plot; -use crate::bounds::PlotBounds; use crate::PlotItem; -use crate::values::PlotPoint; use crate::PlotTransform; use crate::Span; +use crate::bounds::BoundsModification; +use crate::bounds::PlotBounds; +use crate::values::PlotPoint; /// Provides methods to interact with a plot while building it. It is the single /// argument of the closure provided to [`Plot::show`]. See [`Plot`] for an diff --git a/egui_plot/src/rect_elem.rs b/egui_plot/src/rect_elem.rs index d411f8b7..61d18ce5 100644 --- a/egui_plot/src/rect_elem.rs +++ b/egui_plot/src/rect_elem.rs @@ -55,4 +55,3 @@ pub(super) trait RectElement { // ---------------------------------------------------------------------------- // Helper functions - diff --git a/egui_plot/src/transform.rs b/egui_plot/src/transform.rs index d31be605..a7c1b542 100644 --- a/egui_plot/src/transform.rs +++ b/egui_plot/src/transform.rs @@ -4,6 +4,7 @@ use egui::Vec2; use egui::Vec2b; use egui::pos2; use egui::remap; + use super::PlotPoint; use crate::Axis; use crate::bounds::PlotBounds; @@ -281,4 +282,3 @@ impl PlotTransform { } } } - From 068113112a709a67a319ab89e1766c2e7bd5f4de Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 17:39:47 +0100 Subject: [PATCH 25/26] run linter in makefile --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 5f60b44d..07235765 100644 --- a/Makefile +++ b/Makefile @@ -119,6 +119,7 @@ run_checks: check_no_commented_out_code \ checks_no_unfinished \ check_shear \ check_deny \ + check_linter \ check_pub_change_intentional # Performs a compilation check of all crates in the workspace, without building. @@ -153,6 +154,9 @@ check_license: check_cycles: cargo-cycles +check_linter: + python3 ./scripts/lint.py + check_pub_change_intentional: if [ "$$(cargo public-api diff latest -p egui_plot -sss --deny all)" != "" ]; then \ echo "--------------------------------"; \ From 6a2f2dd7d3df460b88ea20fd8569694c21632e51 Mon Sep 17 00:00:00 2001 From: Michal Sustr Date: Wed, 3 Dec 2025 17:40:07 +0100 Subject: [PATCH 26/26] fixes --- egui_plot/src/colors.rs | 1 + egui_plot/src/label.rs | 1 + egui_plot/src/plot.rs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/egui_plot/src/colors.rs b/egui_plot/src/colors.rs index 1721274e..56d21a8f 100644 --- a/egui_plot/src/colors.rs +++ b/egui_plot/src/colors.rs @@ -29,6 +29,7 @@ pub(crate) fn highlighted_color(mut stroke: Stroke, fill: Color32) -> (Stroke, C } pub const DEFAULT_FILL_ALPHA: f32 = 0.05; + /// Default base colors. Used for now only in heatmap palette. pub const BASE_COLORS: [Color32; 10] = [ Color32::from_rgb(48, 18, 59), diff --git a/egui_plot/src/label.rs b/egui_plot/src/label.rs index e6e264a4..f65cce94 100644 --- a/egui_plot/src/label.rs +++ b/egui_plot/src/label.rs @@ -17,5 +17,6 @@ pub fn format_number(number: f64, num_decimals: usize) -> String { } type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a; + /// Optional label formatter function for customizing hover labels. pub type LabelFormatter<'a> = Option>>; diff --git a/egui_plot/src/plot.rs b/egui_plot/src/plot.rs index 4c8359ec..7a88ea00 100644 --- a/egui_plot/src/plot.rs +++ b/egui_plot/src/plot.rs @@ -433,7 +433,7 @@ impl<'a> Plot<'a> { /// drawn. For example, if x = 80..=230 is visible and you want big /// marks at steps of 100 and small ones at 25, you can return: /// ```no_run - /// # use egui_plot::grid::GridMark; + /// # use egui_plot::GridMark; /// vec![ /// // 100s /// GridMark {