Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion demo/src/plot_demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ struct LineDemo {
line_style: LineStyle,
gradient: bool,
gradient_fill: bool,
invert_x: bool,
invert_y: bool,
}

impl Default for LineDemo {
Expand All @@ -197,6 +199,8 @@ impl Default for LineDemo {
line_style: LineStyle::Solid,
gradient: false,
gradient_fill: false,
invert_x: false,
invert_y: false,
}
}
}
Expand All @@ -216,6 +220,8 @@ impl LineDemo {
line_style,
gradient,
gradient_fill,
invert_x,
invert_y,
} = self;

ui.horizontal(|ui| {
Expand Down Expand Up @@ -277,6 +283,11 @@ impl LineDemo {
ui.checkbox(gradient, "Gradient line");
ui.add_enabled(*gradient, Checkbox::new(gradient_fill, "Gradient fill"));
});

ui.vertical(|ui| {
ui.checkbox(invert_x, "Invert X axis");
ui.checkbox(invert_y, "Invert Y axis");
});
});
}

Expand Down Expand Up @@ -352,7 +363,10 @@ impl LineDemo {
let mut plot = Plot::new("lines_demo")
.legend(Legend::default().title("Lines"))
.show_axes(self.show_axes)
.show_grid(self.show_grid);
.show_grid(self.show_grid)
.invert_x(self.invert_x)
.invert_y(self.invert_y);

if self.square {
plot = plot.view_aspect(1.0);
}
Expand Down
4 changes: 2 additions & 2 deletions demo/tests/snapshots/demos/Items.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/demos/Lines.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/demos/Linked Axes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/light_mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/scale_0.50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/scale_1.00.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/scale_1.39.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions demo/tests/snapshots/scale_2.00.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 34 additions & 2 deletions egui_plot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ pub struct Plot<'a> {
height: Option<f32>,
data_aspect: Option<f32>,
view_aspect: Option<f32>,
invert_x: bool,
invert_y: bool,

reset: bool,

Expand Down Expand Up @@ -221,6 +223,8 @@ impl<'a> Plot<'a> {
height: None,
data_aspect: None,
view_aspect: None,
invert_x: false,
invert_y: false,

reset: false,

Expand Down Expand Up @@ -273,6 +277,22 @@ impl<'a> Plot<'a> {
self
}

/// Set whether to invert the x-axis (i.e. positive values go to the left).
/// By default the x-axis is not inverted (i.e. positive values go to the right).
#[inline]
pub fn invert_x(mut self, invert: bool) -> Self {
self.invert_x = invert;
self
}

/// Set whether to invert the y-axis (i.e. positive values go down).
/// By default the y-axis is not inverted (i.e. positive values go up).
#[inline]
pub fn invert_y(mut self, invert: bool) -> Self {
self.invert_y = invert;
self
}

/// Width of plot. By default a plot will fill the ui it is in.
/// If you set [`Self::view_aspect`], the width can be calculated from the height.
#[inline]
Expand Down Expand Up @@ -803,6 +823,8 @@ impl<'a> Plot<'a> {
mut min_size,
data_aspect,
view_aspect,
invert_x,
invert_y,
mut show_x,
mut show_y,
label_formatter,
Expand Down Expand Up @@ -920,7 +942,12 @@ impl<'a> Plot<'a> {
auto_bounds: default_auto_bounds,
hovered_legend_item: None,
hidden_items: Default::default(),
transform: PlotTransform::new(plot_rect, min_auto_bounds, center_axis),
transform: PlotTransform::new_with_invert_axis(
plot_rect,
min_auto_bounds,
center_axis,
Vec2b::new(invert_x, invert_y),
),
last_click_pos_for_zoom: None,
x_axis_thickness: Default::default(),
y_axis_thickness: Default::default(),
Expand Down Expand Up @@ -1094,7 +1121,12 @@ impl<'a> Plot<'a> {
}
}

mem.transform = PlotTransform::new(plot_rect, bounds, center_axis);
mem.transform = PlotTransform::new_with_invert_axis(
plot_rect,
bounds,
center_axis,
Vec2b::new(invert_x, invert_y),
);

// Enforce aspect ratio
if let Some(data_aspect) = data_aspect {
Expand Down
48 changes: 42 additions & 6 deletions egui_plot/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ pub struct PlotTransform {

/// Whether to always center the x-range or y-range of the bounds.
centered: Vec2b,

/// Whether to always invert the x and/or y axis
inverted_axis: Vec2b,
}

impl PlotTransform {
Expand Down Expand Up @@ -338,9 +341,21 @@ impl PlotTransform {
frame,
bounds: new_bounds,
centered: center_axis,
inverted_axis: Vec2b::new(false, false),
}
}

pub fn new_with_invert_axis(
frame: Rect,
bounds: PlotBounds,
center_axis: impl Into<Vec2b>,
invert_axis: impl Into<Vec2b>,
) -> Self {
let mut new = Self::new(frame, bounds, center_axis);
new.inverted_axis = invert_axis.into();
new
}

/// ui-space rectangle.
#[inline]
pub fn frame(&self) -> &Rect {
Expand Down Expand Up @@ -386,15 +401,24 @@ impl PlotTransform {
remap(
value,
self.bounds.min[0]..=self.bounds.max[0],
(self.frame.left() as f64)..=(self.frame.right() as f64),
if self.inverted_axis[0] {
(self.frame.right() as f64)..=(self.frame.left() as f64)
} else {
(self.frame.left() as f64)..=(self.frame.right() as f64)
},
) as f32
}

pub fn position_from_point_y(&self, value: f64) -> f32 {
remap(
value,
self.bounds.min[1]..=self.bounds.max[1],
(self.frame.bottom() as f64)..=(self.frame.top() as f64), // negated y axis!
// negated y axis by default
if self.inverted_axis[1] {
(self.frame.top() as f64)..=(self.frame.bottom() as f64)
} else {
(self.frame.bottom() as f64)..=(self.frame.top() as f64)
},
) as f32
}

Expand All @@ -410,14 +434,24 @@ impl PlotTransform {
pub fn value_from_position(&self, pos: Pos2) -> PlotPoint {
let x = remap(
pos.x as f64,
(self.frame.left() as f64)..=(self.frame.right() as f64),
if self.inverted_axis[0] {
(self.frame.right() as f64)..=(self.frame.left() as f64)
} else {
(self.frame.left() as f64)..=(self.frame.right() as f64)
},
self.bounds.range_x(),
);
let y = remap(
pos.y as f64,
(self.frame.bottom() as f64)..=(self.frame.top() as f64), // negated y axis!
// negated y axis by default
if self.inverted_axis[1] {
(self.frame.top() as f64)..=(self.frame.bottom() as f64)
} else {
(self.frame.bottom() as f64)..=(self.frame.top() as f64)
},
self.bounds.range_y(),
);

PlotPoint::new(x, y)
}

Expand All @@ -437,12 +471,14 @@ impl PlotTransform {

/// delta position / delta value = how many ui points per step in the X axis in "plot space"
pub fn dpos_dvalue_x(&self) -> f64 {
self.frame.width() as f64 / self.bounds.width()
let flip = if self.inverted_axis[0] { -1.0 } else { 1.0 };
flip * (self.frame.width() as f64) / self.bounds.width()
}

/// delta position / delta value = how many ui points per step in the Y axis in "plot space"
pub fn dpos_dvalue_y(&self) -> f64 {
-self.frame.height() as f64 / self.bounds.height() // negated y axis!
let flip = if self.inverted_axis[1] { 1.0 } else { -1.0 };
flip * (self.frame.height() as f64) / self.bounds.height()
}

/// delta position / delta value = how many ui points per step in "plot space"
Expand Down
2 changes: 2 additions & 0 deletions examples/custom_plot_manipulation/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ impl eframe::App for PlotExample {
.allow_zoom(false)
.allow_drag(false)
.allow_scroll(false)
.invert_x(false)
.invert_y(true)
.legend(Legend::default())
.show(ui, |plot_ui| {
if let Some(mut scroll) = scroll {
Expand Down