Browse Source

Break out plotting to own crate `egui_plot` (#3282)

This replaces `egui::plot` with the new crate `egui_plot`
pull/3285/head
Emil Ernerfeldt 1 year ago
committed by GitHub
parent
commit
7b169ec13d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/labels.yml
  2. 5
      ARCHITECTURE.md
  3. 2
      CHANGELOG.md
  4. 11
      Cargo.lock
  5. 1
      Cargo.toml
  6. 2
      crates/egui/src/input_state.rs
  7. 2
      crates/egui/src/lib.rs
  8. 3
      crates/egui/src/ui.rs
  9. 1
      crates/egui/src/widgets/mod.rs
  10. 5
      crates/egui_demo_lib/Cargo.toml
  11. 4
      crates/egui_demo_lib/src/demo/context_menu.rs
  12. 8
      crates/egui_demo_lib/src/demo/plot_demo.rs
  13. 4
      crates/egui_demo_lib/src/demo/widget_gallery.rs
  14. 5
      crates/egui_plot/CHANGELOG.md
  15. 42
      crates/egui_plot/Cargo.toml
  16. 9
      crates/egui_plot/README.md
  17. 6
      crates/egui_plot/src/axis.rs
  18. 8
      crates/egui_plot/src/items/bar.rs
  19. 7
      crates/egui_plot/src/items/box_elem.rs
  20. 8
      crates/egui_plot/src/items/mod.rs
  21. 8
      crates/egui_plot/src/items/rect_elem.rs
  22. 5
      crates/egui_plot/src/items/values.rs
  23. 0
      crates/egui_plot/src/legend.rs
  24. 20
      crates/egui_plot/src/lib.rs
  25. 0
      crates/egui_plot/src/memory.rs
  26. 0
      crates/egui_plot/src/transform.rs
  27. 1
      crates/emath/Cargo.toml
  28. 1
      examples/save_plot/Cargo.toml
  29. 2
      examples/save_plot/src/main.rs
  30. 19
      scripts/generate_changelog.py

2
.github/workflows/labels.yml

@ -29,4 +29,4 @@ jobs:
with:
mode: minimum
count: 1
labels: "CI, dependencies, docs and examples, ecolor, eframe, egui_extras, egui_glow, egui-wgpu, egui-winit, egui, epaint, plot, typo"
labels: "CI, dependencies, docs and examples, ecolor, eframe, egui_extras, egui_glow, egui_plot, egui-wgpu, egui-winit, egui, epaint, typo"

5
ARCHITECTURE.md

@ -5,7 +5,7 @@ Also see [`CONTRIBUTING.md`](CONTRIBUTING.md) for what to do before opening a PR
## Crate overview
The crates in this repository are: `egui, emath, epaint, egui_extras, egui-winit, egui_glium, egui_glow, egui_demo_lib, egui_demo_app`.
The crates in this repository are: `egui, emath, epaint, egui_extras, egui_plot, egui-winit, egui_glium, egui_glow, egui_demo_lib, egui_demo_app`.
### `egui`: The main GUI library.
Example code: `if ui.button("Click me").clicked() { … }`
@ -24,6 +24,9 @@ Depends on `emath`.
### `egui_extras`
This adds additional features on top of `egui`.
### `egui_plot`
Plotting for `egui`.
### `egui-winit`
This crates provides bindings between [`egui`](https://github.com/emilk/egui) and [winit](https://crates.io/crates/winit).

2
CHANGELOG.md

@ -1,7 +1,7 @@
# egui changelog
All notable changes to the `egui` crate will be documented in this file.
NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG.md), [`egui-winit`](crates/egui-winit/CHANGELOG.md), [`egui_glium`](crates/egui_glium/CHANGELOG.md), [`egui_glow`](crates/egui_glow/CHANGELOG.md) and [`egui-wgpu`](crates/egui-wgpu/CHANGELOG.md) have their own changelogs!
NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`egui_plot`](crates/egui_plot/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG.md), [`egui-winit`](crates/egui-winit/CHANGELOG.md), [`egui_glium`](crates/egui_glium/CHANGELOG.md), [`egui_glow`](crates/egui_glow/CHANGELOG.md) and [`egui-wgpu`](crates/egui-wgpu/CHANGELOG.md) have their own changelogs!
This file is updated upon each release.
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.

11
Cargo.lock

@ -1246,6 +1246,7 @@ dependencies = [
"document-features",
"egui",
"egui_extras",
"egui_plot",
"enum-map",
"log",
"serde",
@ -1287,6 +1288,15 @@ dependencies = [
"web-sys",
]
[[package]]
name = "egui_plot"
version = "0.22.0"
dependencies = [
"document-features",
"egui",
"serde",
]
[[package]]
name = "ehttp"
version = "0.2.0"
@ -3128,6 +3138,7 @@ name = "save_plot"
version = "0.1.0"
dependencies = [
"eframe",
"egui_plot",
"env_logger",
"image",
"rfd",

1
Cargo.toml

@ -6,6 +6,7 @@ members = [
"crates/egui_demo_lib",
"crates/egui_extras",
"crates/egui_glow",
"crates/egui_plot",
"crates/egui-wgpu",
"crates/egui-winit",
"crates/egui",

2
crates/egui/src/input_state.rs

@ -754,7 +754,7 @@ impl PointerState {
/// Latest reported pointer position.
/// When tapping a touch screen, this will be `None`.
#[inline(always)]
pub(crate) fn latest_pos(&self) -> Option<Pos2> {
pub fn latest_pos(&self) -> Option<Pos2> {
self.latest_pos
}

2
crates/egui/src/lib.rs

@ -328,6 +328,8 @@ pub mod widgets;
#[cfg(feature = "accesskit")]
pub use accesskit;
pub use ahash;
pub use epaint;
pub use epaint::ecolor;
pub use epaint::emath;

3
crates/egui/src/ui.rs

@ -809,7 +809,8 @@ impl Ui {
self.interact(rect, id, sense)
}
pub(crate) fn advance_cursor_after_rect(&mut self, rect: Rect) -> Id {
/// Allocate a rect without interacting with it.
pub fn advance_cursor_after_rect(&mut self, rect: Rect) -> Id {
egui_assert!(!rect.any_nan());
let item_spacing = self.spacing().item_spacing;
self.placer.advance_after_rects(rect, rect, item_spacing);

1
crates/egui/src/widgets/mod.rs

@ -12,7 +12,6 @@ pub(crate) mod drag_value;
mod hyperlink;
mod image;
mod label;
pub mod plot;
mod progress_bar;
mod selected_label;
mod separator;

5
crates/egui_demo_lib/Cargo.toml

@ -23,8 +23,10 @@ all-features = true
default = []
chrono = ["egui_extras/datepicker", "dep:chrono"]
## Allow serialization using [`serde`](https://docs.rs/serde).
serde = ["egui/serde", "dep:serde"]
serde = ["egui/serde", "egui_plot/serde", "dep:serde"]
## Enable better syntax highlighting using [`syntect`](https://docs.rs/syntect).
syntax_highlighting = ["syntect"]
@ -32,6 +34,7 @@ syntax_highlighting = ["syntect"]
[dependencies]
egui = { version = "0.22.0", path = "../egui", default-features = false }
egui_extras = { version = "0.22.0", path = "../egui_extras" }
egui_plot = { version = "0.22.0", path = "../egui_plot" }
enum-map = { version = "2", features = ["serde"] }
log = { version = "0.4", features = ["std"] }
unicode_names2 = { version = "0.6.0", default-features = false }

4
crates/egui_demo_lib/src/demo/context_menu.rs

@ -122,7 +122,7 @@ impl super::View for ContextMenus {
impl ContextMenus {
fn example_plot(&self, ui: &mut egui::Ui) -> egui::Response {
use egui::plot::{Line, PlotPoints};
use egui_plot::{Line, PlotPoints};
let n = 128;
let line = Line::new(
(0..=n)
@ -137,7 +137,7 @@ impl ContextMenus {
})
.collect::<PlotPoints>(),
);
egui::plot::Plot::new("example_plot")
egui_plot::Plot::new("example_plot")
.show_axes(self.show_axes)
.allow_drag(self.allow_drag)
.allow_zoom(self.allow_zoom)

8
crates/egui_demo_lib/src/demo/plot_demo.rs

@ -3,7 +3,7 @@ use std::ops::RangeInclusive;
use egui::*;
use egui::plot::{
use egui_plot::{
Arrows, AxisBools, AxisHints, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, CoordinatesFormatter,
Corner, GridInput, GridMark, HLine, Legend, Line, LineStyle, MarkerShape, Plot, PlotImage,
PlotPoint, PlotPoints, PlotResponse, Points, Polygon, Text, VLine,
@ -575,7 +575,7 @@ impl CustomAxesDemo {
.max_digits(4),
AxisHints::default()
.label("Absolute")
.placement(plot::HPlacement::Right),
.placement(egui_plot::HPlacement::Right),
];
Plot::new("custom_axes")
.data_aspect(2.0 * MINS_PER_DAY as f32)
@ -636,7 +636,7 @@ impl LinkedAxesDemo {
))
}
fn configure_plot(plot_ui: &mut plot::PlotUi) {
fn configure_plot(plot_ui: &mut egui_plot::PlotUi) {
plot_ui.line(LinkedAxesDemo::line_with_slope(0.5));
plot_ui.line(LinkedAxesDemo::line_with_slope(1.0));
plot_ui.line(LinkedAxesDemo::line_with_slope(2.0));
@ -671,7 +671,7 @@ impl LinkedAxesDemo {
.height(250.0)
.y_axis_width(3)
.y_axis_label("y")
.y_axis_position(plot::HPlacement::Right)
.y_axis_position(egui_plot::HPlacement::Right)
.link_axis(link_group_id, self.link_x, self.link_y)
.link_cursor(link_group_id, self.link_cursor_x, self.link_cursor_y)
.show(ui, LinkedAxesDemo::configure_plot);

4
crates/egui_demo_lib/src/demo/widget_gallery.rs

@ -259,7 +259,7 @@ impl WidgetGallery {
}
fn example_plot(ui: &mut egui::Ui) -> egui::Response {
use egui::plot::{Line, PlotPoints};
use egui_plot::{Line, PlotPoints};
let n = 128;
let line_points: PlotPoints = (0..=n)
.map(|i| {
@ -269,7 +269,7 @@ fn example_plot(ui: &mut egui::Ui) -> egui::Response {
})
.collect();
let line = Line::new(line_points);
egui::plot::Plot::new("example_plot")
egui_plot::Plot::new("example_plot")
.height(32.0)
.show_axes(false)
.data_aspect(1.0)

5
crates/egui_plot/CHANGELOG.md

@ -0,0 +1,5 @@
# Changelog for egui_plot
All notable changes to the `egui_plot` integration will be noted in this file.
This file is updated upon each release.
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.

42
crates/egui_plot/Cargo.toml

@ -0,0 +1,42 @@
[package]
name = "egui_plot"
version = "0.22.0"
authors = [
"Dominik Rössler <dominik@freshx.de>",
"Emil Ernerfeldt <emil.ernerfeldt@gmail.com>",
"René Rössler <rene@freshx.de>",
]
description = "Immediate mode plotting for the egui GUI library"
edition = "2021"
rust-version = "1.67"
homepage = "https://github.com/emilk/egui"
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/emilk/egui"
categories = ["visualization", "gui"]
keywords = ["egui", "plot", "plotting"]
include = ["../LICENSE-APACHE", "../LICENSE-MIT", "**/*.rs", "Cargo.toml"]
[package.metadata.docs.rs]
all-features = true
[lib]
[features]
default = []
## Allow serialization using [`serde`](https://docs.rs/serde).
serde = ["dep:serde", "egui/serde"]
[dependencies]
egui = { version = "0.22.0", path = "../egui", default-features = false }
#! ### Optional dependencies
## Enable this when generating docs.
document-features = { version = "0.2", optional = true }
serde = { version = "1", optional = true, features = ["derive"] }

9
crates/egui_plot/README.md

@ -0,0 +1,9 @@
# egui_plot
[![Latest version](https://img.shields.io/crates/v/egui_plot.svg)](https://crates.io/crates/egui_plot)
[![Documentation](https://docs.rs/egui_plot/badge.svg)](https://docs.rs/egui_plot)
[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
![MIT](https://img.shields.io/badge/license-MIT-blue.svg)
![Apache](https://img.shields.io/badge/license-Apache-blue.svg)
Immediate mode plotting for [`egui`](https://github.com/emilk/egui).

6
crates/egui/src/widgets/plot/axis.rs → crates/egui_plot/src/axis.rs

@ -1,9 +1,7 @@
use std::{fmt::Debug, ops::RangeInclusive, sync::Arc};
use epaint::{
emath::{remap_clamp, round_to_decimals},
Pos2, Rect, Shape, Stroke, TextShape,
};
use egui::emath::{remap_clamp, round_to_decimals, Pos2, Rect};
use egui::epaint::{Shape, Stroke, TextShape};
use crate::{Response, Sense, TextStyle, Ui, WidgetText};

8
crates/egui/src/widgets/plot/items/bar.rs → crates/egui_plot/src/items/bar.rs

@ -1,8 +1,8 @@
use crate::emath::NumExt;
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
use egui::emath::NumExt;
use egui::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
use crate::plot::{BarChart, Cursor, PlotPoint, PlotTransform};
use crate::{BarChart, Cursor, PlotPoint, PlotTransform};
/// One bar in a [`BarChart`]. Potentially floating, allowing stacked bar charts.
/// Width can be changed to allow variable-width histograms.
@ -185,6 +185,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::plot::format_number(self.value, decimals)
crate::format_number(self.value, decimals)
}
}

7
crates/egui/src/widgets/plot/items/box_elem.rs → crates/egui_plot/src/items/box_elem.rs

@ -1,8 +1,9 @@
use crate::emath::NumExt;
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
use egui::emath::NumExt as _;
use egui::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
use crate::{BoxPlot, Cursor, PlotPoint, PlotTransform};
use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
use crate::plot::{BoxPlot, Cursor, PlotPoint, PlotTransform};
/// Contains the values of a single box in a box plot.
#[derive(Clone, Debug, PartialEq)]

8
crates/egui/src/widgets/plot/items/mod.rs → crates/egui_plot/src/items/mod.rs

@ -187,10 +187,10 @@ impl PlotItem for HLine {
// Round to minimize aliasing:
let points = vec![
ui.ctx().round_pos_to_pixels(
ui.painter().round_pos_to_pixels(
transform.position_from_point(&PlotPoint::new(transform.bounds().min[0], *y)),
),
ui.ctx().round_pos_to_pixels(
ui.painter().round_pos_to_pixels(
transform.position_from_point(&PlotPoint::new(transform.bounds().max[0], *y)),
),
];
@ -303,10 +303,10 @@ impl PlotItem for VLine {
// Round to minimize aliasing:
let points = vec![
ui.ctx().round_pos_to_pixels(
ui.painter().round_pos_to_pixels(
transform.position_from_point(&PlotPoint::new(*x, transform.bounds().min[1])),
),
ui.ctx().round_pos_to_pixels(
ui.painter().round_pos_to_pixels(
transform.position_from_point(&PlotPoint::new(*x, transform.bounds().max[1])),
),
];

8
crates/egui/src/widgets/plot/items/rect_elem.rs → crates/egui_plot/src/items/rect_elem.rs

@ -1,7 +1,9 @@
use egui::emath::NumExt as _;
use egui::epaint::{Color32, Rgba, Stroke};
use crate::transform::{PlotBounds, PlotTransform};
use super::{Orientation, PlotPoint};
use crate::plot::transform::{PlotBounds, PlotTransform};
use epaint::emath::NumExt;
use epaint::{Color32, Rgba, Stroke};
/// Trait that abstracts from rectangular 'Value'-like elements, such as bars or boxes
pub(super) trait RectElement {

5
crates/egui/src/widgets/plot/items/values.rs → crates/egui_plot/src/items/values.rs

@ -1,7 +1,8 @@
use epaint::{Pos2, Shape, Stroke, Vec2};
use std::ops::{Bound, RangeBounds, RangeInclusive};
use crate::plot::transform::PlotBounds;
use egui::{Pos2, Shape, Stroke, Vec2};
use crate::transform::PlotBounds;
/// A point coordinate in the plot.
///

0
crates/egui/src/widgets/plot/legend.rs → crates/egui_plot/src/legend.rs

20
crates/egui/src/widgets/plot/mod.rs → crates/egui_plot/src/lib.rs

@ -1,8 +1,12 @@
//! Simple plotting library.
//!
//! ## Feature flags
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
//!
use std::{ops::RangeInclusive, sync::Arc};
use ahash::HashMap;
use egui::ahash::HashMap;
use epaint::util::FloatOrd;
use epaint::Hsva;
@ -10,7 +14,7 @@ use axis::AxisWidget;
use items::PlotItem;
use legend::LegendWidget;
use crate::*;
use egui::*;
pub use items::{
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, HLine, Line, LineStyle, MarkerShape,
@ -182,7 +186,7 @@ pub struct PlotResponse<R> {
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// use egui::plot::{Line, Plot, PlotPoints};
/// use egui_plot::{Line, Plot, PlotPoints};
/// let sin: PlotPoints = (0..1000).map(|i| {
/// let x = i as f64 * 0.01;
/// [x, x.sin()]
@ -394,7 +398,7 @@ impl Plot {
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// use egui::plot::{Line, Plot, PlotPoints};
/// use egui_plot::{Line, Plot, PlotPoints};
/// let sin: PlotPoints = (0..1000).map(|i| {
/// let x = i as f64 * 0.01;
/// [x, x.sin()]
@ -443,7 +447,7 @@ impl Plot {
/// 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::GridMark;
/// vec![
/// // 100s
/// GridMark { value: 100.0, step_size: 100.0 },
@ -1781,8 +1785,8 @@ impl PreparedPlot {
if self.sharp_grid_lines {
// Round to avoid aliasing
p0 = ui.ctx().round_pos_to_pixels(p0);
p1 = ui.ctx().round_pos_to_pixels(p1);
p0 = ui.painter().round_pos_to_pixels(p0);
p1 = ui.painter().round_pos_to_pixels(p1);
}
shapes.push((
@ -1851,7 +1855,7 @@ impl PreparedPlot {
/// Returns next bigger power in given base
/// e.g.
/// ```ignore
/// use egui::plot::next_power;
/// 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);

0
crates/egui/src/widgets/plot/memory.rs → crates/egui_plot/src/memory.rs

0
crates/egui/src/widgets/plot/transform.rs → crates/egui_plot/src/transform.rs

1
crates/emath/Cargo.toml

@ -24,6 +24,7 @@ default = []
## Enable additional checks if debug assertions are enabled (debug builds).
extra_debug_asserts = []
## Always enable additional checks.
extra_asserts = []

1
examples/save_plot/Cargo.toml

@ -11,6 +11,7 @@ publish = false
eframe = { path = "../../crates/eframe", features = [
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
egui_plot = { path = "../../crates/egui_plot" }
image = { version = "0.24", default-features = false, features = ["png"] }
rfd = "0.11.0"
env_logger = "0.10"

2
examples/save_plot/src/main.rs

@ -1,8 +1,8 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use eframe::egui;
use eframe::egui::plot::{Legend, Line, Plot, PlotPoints};
use eframe::egui::ColorImage;
use egui_plot::{Legend, Line, Plot, PlotPoints};
fn main() -> Result<(), eframe::Error> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

19
scripts/generate_changelog.py

@ -131,6 +131,7 @@ def main() -> None:
"ecolor",
"eframe",
"egui_extras",
"egui_plot",
"egui_glow",
"egui-wgpu",
"egui-winit",
@ -141,8 +142,6 @@ def main() -> None:
unsorted_prs = []
unsorted_commits = []
plot = []
for commit_info, pr_info in zip(commit_infos, pr_infos):
hexsha = commit_info.hexsha
title = commit_info.title
@ -170,14 +169,11 @@ def main() -> None:
continue # We get so many typo PRs. Let's not flood the changelog with them.
added = False
if 'plot' in labels:
plot.append(summary)
added = True
else:
for crate in crate_names:
if crate in labels:
sections.setdefault(crate, []).append(summary)
added = True
for crate in crate_names:
if crate in labels:
sections.setdefault(crate, []).append(summary)
added = True
if not added:
if not any(label in labels for label in ignore_labels):
@ -188,9 +184,6 @@ def main() -> None:
if crate in sections:
summary = sections[crate]
print_section(crate, summary)
if crate == 'egui':
if 0 < len(plot):
print_section("egui plot", plot)
print_section("Unsorted PRs", unsorted_prs)
print_section("Unsorted commits", unsorted_commits)

Loading…
Cancel
Save