mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 22:00:03 -04:00
Draw axis labels and ticks outside of plotting window (#2284)
* Always draw axis labels at plot borders * Revert "Always draw axis labels at plot borders" This reverts commit 9235e6603366d3b8a8189e2a5fc28c9780b7f54f. * Add axis labels for plots * First Draft of axis labels outside of plotting window * plot: Tick placement of opposite axes and digit constraints * plot: Axis label API * plot: Update demo lib * plot: resolve clippy warning * Update changelog * Remove default axis * Fix clippy * plot: Remove unused comments * plot-axis: Rebase label opacity calculation on master * plot: Resolve check.sh warnings * plot-axis: Use 'into impl<WidgetText>' as axis label formatter * plot-axis: Expose more conveniece functions to public API. Add axis labels to demo app * plot-axes: Resolve ./scripts/check.sh warnings * typo in comment * Use `TAU` instead of the legacy `PI` * Simpler generic syntax * Use `Arc` to avoid some expensive clones * Use `Margin` instead of a,b,c,d * Add some vertical spacing * De-duplicate color_from_contrast * better naming * Fix typos * cnt -> num * Axis are present by default, with empty names * Add HPlacement and VPlacement * Don't catch clicks and drags on axes * Remove generics to minimize monomorphization code bloat * Create helper function * Remove changelog entry * Simplify more --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a3ae81cadb
commit
dbe55ba46a
@@ -1,12 +1,12 @@
|
||||
use std::f64::consts::TAU;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use egui::plot::{AxisBools, GridInput, GridMark, PlotResponse};
|
||||
use egui::*;
|
||||
use plot::{
|
||||
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, CoordinatesFormatter, Corner, HLine,
|
||||
Legend, Line, LineStyle, MarkerShape, Plot, PlotImage, PlotPoint, PlotPoints, Points, Polygon,
|
||||
Text, VLine,
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -119,17 +119,9 @@ impl super::View for PlotDemo {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_approx_zero(val: f64) -> bool {
|
||||
val.abs() < 1e-6
|
||||
}
|
||||
|
||||
fn is_approx_integer(val: f64) -> bool {
|
||||
val.fract().abs() < 1e-6
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
struct LineDemo {
|
||||
animate: bool,
|
||||
time: f64,
|
||||
@@ -138,6 +130,8 @@ struct LineDemo {
|
||||
square: bool,
|
||||
proportional: bool,
|
||||
coordinates: bool,
|
||||
show_axes: bool,
|
||||
show_grid: bool,
|
||||
line_style: LineStyle,
|
||||
}
|
||||
|
||||
@@ -151,6 +145,8 @@ impl Default for LineDemo {
|
||||
square: false,
|
||||
proportional: true,
|
||||
coordinates: true,
|
||||
show_axes: true,
|
||||
show_grid: true,
|
||||
line_style: LineStyle::Solid,
|
||||
}
|
||||
}
|
||||
@@ -165,9 +161,10 @@ impl LineDemo {
|
||||
circle_center,
|
||||
square,
|
||||
proportional,
|
||||
line_style,
|
||||
coordinates,
|
||||
..
|
||||
show_axes,
|
||||
show_grid,
|
||||
line_style,
|
||||
} = self;
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
@@ -195,6 +192,13 @@ impl LineDemo {
|
||||
});
|
||||
});
|
||||
|
||||
ui.vertical(|ui| {
|
||||
ui.checkbox(show_axes, "Show axes");
|
||||
ui.checkbox(show_grid, "Show grid");
|
||||
ui.checkbox(coordinates, "Show coordinates on hover")
|
||||
.on_hover_text("Can take a custom formatting function.");
|
||||
});
|
||||
|
||||
ui.vertical(|ui| {
|
||||
ui.style_mut().wrap = Some(false);
|
||||
ui.checkbox(animate, "Animate");
|
||||
@@ -202,8 +206,6 @@ impl LineDemo {
|
||||
.on_hover_text("Always keep the viewport square.");
|
||||
ui.checkbox(proportional, "Proportional data axes")
|
||||
.on_hover_text("Tick are the same size on both axes.");
|
||||
ui.checkbox(coordinates, "Show coordinates")
|
||||
.on_hover_text("Can take a custom formatting function.");
|
||||
|
||||
ComboBox::from_label("Line style")
|
||||
.selected_text(line_style.to_string())
|
||||
@@ -268,11 +270,16 @@ impl LineDemo {
|
||||
impl LineDemo {
|
||||
fn ui(&mut self, ui: &mut Ui) -> Response {
|
||||
self.options_ui(ui);
|
||||
|
||||
if self.animate {
|
||||
ui.ctx().request_repaint();
|
||||
self.time += ui.input(|i| i.unstable_dt).at_most(1.0 / 30.0) as f64;
|
||||
};
|
||||
let mut plot = Plot::new("lines_demo").legend(Legend::default());
|
||||
let mut plot = Plot::new("lines_demo")
|
||||
.legend(Legend::default())
|
||||
.y_axis_width(4)
|
||||
.show_axes(self.show_axes)
|
||||
.show_grid(self.show_grid);
|
||||
if self.square {
|
||||
plot = plot.view_aspect(1.0);
|
||||
}
|
||||
@@ -429,8 +436,8 @@ impl LegendDemo {
|
||||
);
|
||||
ui.end_row();
|
||||
});
|
||||
|
||||
let legend_plot = Plot::new("legend_demo")
|
||||
.y_axis_width(2)
|
||||
.legend(config.clone())
|
||||
.data_aspect(1.0);
|
||||
legend_plot
|
||||
@@ -523,7 +530,7 @@ impl CustomAxesDemo {
|
||||
100.0 * y
|
||||
}
|
||||
|
||||
let x_fmt = |x, _range: &RangeInclusive<f64>| {
|
||||
let x_fmt = |x, _digits, _range: &RangeInclusive<f64>| {
|
||||
if x < 0.0 * MINS_PER_DAY || x >= 5.0 * MINS_PER_DAY {
|
||||
// No labels outside value bounds
|
||||
String::new()
|
||||
@@ -536,7 +543,7 @@ impl CustomAxesDemo {
|
||||
}
|
||||
};
|
||||
|
||||
let y_fmt = |y, _range: &RangeInclusive<f64>| {
|
||||
let y_fmt = |y, _digits, _range: &RangeInclusive<f64>| {
|
||||
// Display only integer percentages
|
||||
if !is_approx_zero(y) && is_approx_integer(100.0 * y) {
|
||||
format!("{:.0}%", percent(y))
|
||||
@@ -557,10 +564,23 @@ impl CustomAxesDemo {
|
||||
|
||||
ui.label("Zoom in on the X-axis to see hours and minutes");
|
||||
|
||||
let x_axes = vec![
|
||||
AxisHints::default().label("Time").formatter(x_fmt),
|
||||
AxisHints::default().label("Value"),
|
||||
];
|
||||
let y_axes = vec![
|
||||
AxisHints::default()
|
||||
.label("Percent")
|
||||
.formatter(y_fmt)
|
||||
.max_digits(4),
|
||||
AxisHints::default()
|
||||
.label("Absolute")
|
||||
.placement(plot::HPlacement::Right),
|
||||
];
|
||||
Plot::new("custom_axes")
|
||||
.data_aspect(2.0 * MINS_PER_DAY as f32)
|
||||
.x_axis_formatter(x_fmt)
|
||||
.y_axis_formatter(y_fmt)
|
||||
.custom_x_axes(x_axes)
|
||||
.custom_y_axes(y_axes)
|
||||
.x_grid_spacer(CustomAxesDemo::x_grid)
|
||||
.label_formatter(label_fmt)
|
||||
.show(ui, |plot_ui| {
|
||||
@@ -582,15 +602,11 @@ struct LinkedAxesDemo {
|
||||
|
||||
impl Default for LinkedAxesDemo {
|
||||
fn default() -> Self {
|
||||
let link_x = true;
|
||||
let link_y = false;
|
||||
let link_cursor_x = true;
|
||||
let link_cursor_y = false;
|
||||
Self {
|
||||
link_x,
|
||||
link_y,
|
||||
link_cursor_x,
|
||||
link_cursor_y,
|
||||
link_x: true,
|
||||
link_y: true,
|
||||
link_cursor_x: true,
|
||||
link_cursor_y: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -642,25 +658,29 @@ impl LinkedAxesDemo {
|
||||
|
||||
let link_group_id = ui.id().with("linked_demo");
|
||||
ui.horizontal(|ui| {
|
||||
Plot::new("linked_axis_1")
|
||||
Plot::new("left-top")
|
||||
.data_aspect(1.0)
|
||||
.width(250.0)
|
||||
.height(250.0)
|
||||
.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);
|
||||
Plot::new("linked_axis_2")
|
||||
Plot::new("right-top")
|
||||
.data_aspect(2.0)
|
||||
.width(150.0)
|
||||
.height(250.0)
|
||||
.y_axis_width(3)
|
||||
.y_axis_label("y")
|
||||
.y_axis_position(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);
|
||||
});
|
||||
Plot::new("linked_axis_3")
|
||||
Plot::new("left-bottom")
|
||||
.data_aspect(0.5)
|
||||
.width(250.0)
|
||||
.height(150.0)
|
||||
.x_axis_label("x")
|
||||
.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)
|
||||
@@ -889,6 +909,7 @@ impl ChartsDemo {
|
||||
Plot::new("Normal Distribution Demo")
|
||||
.legend(Legend::default())
|
||||
.clamp_grid(true)
|
||||
.y_axis_width(3)
|
||||
.allow_zoom(self.allow_zoom)
|
||||
.allow_drag(self.allow_drag)
|
||||
.show(ui, |plot_ui| plot_ui.bar_chart(chart))
|
||||
@@ -1003,3 +1024,11 @@ impl ChartsDemo {
|
||||
.response
|
||||
}
|
||||
}
|
||||
|
||||
fn is_approx_zero(val: f64) -> bool {
|
||||
val.abs() < 1e-6
|
||||
}
|
||||
|
||||
fn is_approx_integer(val: f64) -> bool {
|
||||
val.fract().abs() < 1e-6
|
||||
}
|
||||
|
||||
@@ -271,6 +271,7 @@ fn example_plot(ui: &mut egui::Ui) -> egui::Response {
|
||||
let line = Line::new(line_points);
|
||||
egui::plot::Plot::new("example_plot")
|
||||
.height(32.0)
|
||||
.show_axes(false)
|
||||
.data_aspect(1.0)
|
||||
.show(ui, |plot_ui| plot_ui.line(line))
|
||||
.response
|
||||
|
||||
Reference in New Issue
Block a user