Added support for linked axes. See comments.

This commit adds support for linked axes between plots. One can specify
such linked limits using the new `linked_x_axis()` function (and the
variants for the Y axes) by specifying an `Rc<RefCell<ImPlotRange>>`
value, and passing clones of the same `Rc` to other plots.

The values within those `Rc` need to be kept persistent between frames,
hence the way to use this functionality is to keep a clone of the `Rc`
outside the frame-drawing function as part of the application state.

The regular limit setting API is unaffected.
This commit is contained in:
4bb4 2021-05-30 11:45:16 +02:00
parent ad80781f4d
commit 06cc3061c1
5 changed files with 570 additions and 391 deletions

View file

@ -9,44 +9,64 @@ pub mod text_plots;
use imgui::{im_str, Condition, Ui, Window};
use implot::PlotUi;
pub fn show_demos(ui: &Ui, plot_ui: &PlotUi) {
Window::new(im_str!("implot-rs demo"))
.size([430.0, 450.0], Condition::FirstUseEver)
.build(ui, || {
ui.text(im_str!("Hello from implot-rs!"));
ui.text_wrapped(im_str!(
"The headers here demo the plotting features of the library.\
/// State of the demo code
pub struct DemoState {
/// State of the line plots demo
line_plots: line_plots::LinePlotDemoState,
}
impl DemoState {
/// Create a new demo code state object with default values in it.
pub fn new() -> Self {
Self {
line_plots: line_plots::LinePlotDemoState::new(),
}
}
/// Show all the demos
pub fn show_demos(&mut self, ui: &Ui, plot_ui: &PlotUi) {
// Most of the demos are currently still stateless, so the code here mostly just calls into
// the modules. The line plots demo is stateful though. Things will be refactored soon to
// make all the individual demos stateful to unify things more.
Window::new(im_str!("implot-rs demo"))
.size([430.0, 450.0], Condition::FirstUseEver)
.build(ui, || {
ui.text(im_str!("Hello from implot-rs!"));
ui.text_wrapped(im_str!(
"The headers here demo the plotting features of the library.\
Have a look at the example source code to see how they are implemented.\n\
Check out the demo from ImPlot itself first for instructions on how to\
interact with ImPlot plots."
));
));
ui.separator();
ui.text(im_str!("Bar plots:"));
bar_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Bar plots:"));
bar_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Line plots:"));
line_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Line plots:"));
// The line plots demo is stateful
self.line_plots.show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Scatter plots:"));
scatter_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Scatter plots:"));
scatter_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Text plots:"));
text_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Text plots:"));
text_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Stairs plots:"));
stairs_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Stairs plots:"));
stairs_plots::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Heatmaps:"));
heatmaps::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Heatmaps:"));
heatmaps::show_demo_headers(ui, plot_ui);
ui.separator();
ui.text(im_str!("Stem plots:"));
stem_plots::show_demo_headers(ui, plot_ui);
});
ui.separator();
ui.text(im_str!("Stem plots:"));
stem_plots::show_demo_headers(ui, plot_ui);
});
}
}

View file

@ -11,367 +11,413 @@ use implot::{
StyleVar, YAxisChoice,
};
pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header just plots a line with as little code as possible."
));
let content_width = ui.window_content_region_width();
Plot::new("Simple line plot")
// The size call could also be omitted, though the defaults don't consider window
// width, which is why we're not doing so here.
.size([content_width, 300.0])
.build(plot_ui, || {
// If this is called outside a plot build callback, the program will panic.
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
use std::{cell::RefCell, rc::Rc};
/// State of the line plots demo.
pub struct LinePlotDemoState {
linked_limits: Rc<RefCell<ImPlotRange>>,
}
pub fn show_two_yaxis_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header shows how to create a plot with multiple Y axes."
));
let content_width = ui.window_content_region_width();
Plot::new("Multiple Y axis plots")
// The size call could also be omitted, though the defaults don't consider window
// width, which is why we're not doing so here.
.size([content_width, 300.0])
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::Y_AXIS_2))
.y_limits(
ImPlotRange { Min: 0.0, Max: 1.0 },
YAxisChoice::First,
Condition::Always,
)
.y_limits(
// One can also use [f32; 2], (f32, f32) and ImVec2 for limit setting
[1.0, 3.5],
YAxisChoice::Second,
Condition::Always,
)
.build(plot_ui, || {
let x_positions = vec![0.1, 0.9];
impl LinePlotDemoState {
/// Create a new line plots demo state object with default values in it.
pub fn new() -> Self {
Self {
linked_limits: Rc::new(RefCell::new(ImPlotRange { Min: 0.0, Max: 1.0 })),
}
}
// The first Y axis is the default
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header just plots a line with as little code as possible."
));
let content_width = ui.window_content_region_width();
Plot::new("Simple line plot")
// The size call could also be omitted, though the defaults don't consider window
// width, which is why we're not doing so here.
.size([content_width, 300.0])
.build(plot_ui, || {
// If this is called outside a plot build callback, the program will panic.
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
}
// Now we switch to the second axis for the next call
set_plot_y_axis(YAxisChoice::Second);
let y_positions = vec![3.3, 1.2];
PlotLine::new("legend label two").plot(&x_positions, &y_positions);
});
}
pub fn show_two_yaxis_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header shows how to create a plot with multiple Y axes."
));
let content_width = ui.window_content_region_width();
Plot::new("Multiple Y axis plots")
// The size call could also be omitted, though the defaults don't consider window
// width, which is why we're not doing so here.
.size([content_width, 300.0])
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::Y_AXIS_2))
.y_limits(
ImPlotRange { Min: 0.0, Max: 1.0 },
YAxisChoice::First,
Condition::Always,
)
.y_limits(
// One can also use [f32; 2], (f32, f32) and ImVec2 for limit setting
[1.0, 3.5],
YAxisChoice::Second,
Condition::Always,
)
.build(plot_ui, || {
let x_positions = vec![0.1, 0.9];
pub fn show_axis_equal_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!("This plot has axis equal set (1:1 aspect ratio)."));
let content_width = ui.window_content_region_width();
Plot::new("Axis equal line plot")
// The size call could also be omitted, though the defaults don't consider window
// width, which is why we're not doing so here.
.size([content_width, 300.0])
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::AXIS_EQUAL))
.build(plot_ui, || {
// If this is called outside a plot build callback, the program will panic.
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
}
// The first Y axis is the default
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demos what we can configure about plots."
));
// Now we switch to the second axis for the next call
set_plot_y_axis(YAxisChoice::Second);
let y_positions = vec![3.3, 1.2];
PlotLine::new("legend label two").plot(&x_positions, &y_positions);
});
}
// Settings for the plot
// - X and Y size in pixels
let x_size = 300.0;
let y_size = 200.0;
// - Strings for the axis labels
let x_label = "X label!";
let y_label = "Y label!";
// - Plot limits
let x_min = 2.0;
let x_max = 3.0;
let y_min = 1.0;
let y_max = 2.0;
// - Plot flags, see the PlotFlags docs for more info
let plot_flags = PlotFlags::NONE;
// - Axis flags, see the AxisFlags docs for more info. All flags are bitflags-created,
// so they support a bunch of convenient operations, see https://docs.rs/bitflags
let x_axis_flags = AxisFlags::NONE;
let y_axis_flags = AxisFlags::NONE;
pub fn show_axis_equal_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!("This plot has axis equal set (1:1 aspect ratio)."));
let content_width = ui.window_content_region_width();
Plot::new("Axis equal line plot")
// The size call could also be omitted, though the defaults don't consider window
// width, which is why we're not doing so here.
.size([content_width, 300.0])
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::AXIS_EQUAL))
.build(plot_ui, || {
// If this is called outside a plot build callback, the program will panic.
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
}
// - Unlabelled X axis ticks
let x_ticks = vec![2.2, 2.5, 2.8];
pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demos what we can configure about plots."
));
// - Labelled Y axis ticks
let y_ticks = vec![(1.1, "A".to_owned()), (1.4, "B".to_owned())];
// Settings for the plot
// - X and Y size in pixels
let x_size = 300.0;
let y_size = 200.0;
// - Strings for the axis labels
let x_label = "X label!";
let y_label = "Y label!";
// - Plot limits
let x_min = 2.0;
let x_max = 3.0;
let y_min = 1.0;
let y_max = 2.0;
// - Plot flags, see the PlotFlags docs for more info
let plot_flags = PlotFlags::NONE;
// - Axis flags, see the AxisFlags docs for more info. All flags are bitflags-created,
// so they support a bunch of convenient operations, see https://docs.rs/bitflags
let x_axis_flags = AxisFlags::NONE;
let y_axis_flags = AxisFlags::NONE;
// Axis labels
Plot::new("Configured line plot")
.size([x_size, y_size])
.x_label(&x_label)
.y_label(&y_label)
.x_limits(
ImPlotRange {
Min: x_min,
Max: x_max,
},
// Always means that the limits stay what we force them to here, even if the user
// scrolls or drags in the plot with the mouse. FirstUseEver sets the limits the
// first time the plot is drawn, but the user can then modify them and the change
// will stick.
Condition::Always,
)
.y_limits(
ImPlotRange {
Min: y_min,
Max: y_max,
},
YAxisChoice::First,
Condition::Always,
)
.x_ticks(&x_ticks, false)
.y_ticks_with_labels(YAxisChoice::First, &y_ticks, false)
// If any of these flag setting calls are omitted, the defaults are used.
.with_plot_flags(&plot_flags)
.with_x_axis_flags(&x_axis_flags)
.with_y_axis_flags(YAxisChoice::First, &y_axis_flags)
.with_legend_location(&PlotLocation::West, &PlotOrientation::Horizontal, true)
.build(plot_ui, || {
PlotLine::new("A line 2").plot(&vec![2.4, 2.9], &vec![1.1, 1.9]);
});
}
// - Unlabelled X axis ticks
let x_ticks = vec![2.2, 2.5, 2.8];
pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demos how to use the querying features."
));
let content_width = ui.window_content_region_width();
// - Labelled Y axis ticks
let y_ticks = vec![(1.1, "A".to_owned()), (1.4, "B".to_owned())];
// Create some containers for exfiltrating data from the closure below
let mut hover_pos_plot: Option<ImPlotPoint> = None;
let mut hover_pos_pixels: Option<ImVec2> = None;
let mut hover_pos_from_pixels: Option<ImPlotPoint> = None;
let mut plot_limits: Option<ImPlotLimits> = None;
let mut query_limits: Option<ImPlotLimits> = None;
let mut legend1_hovered = false;
let mut legend2_hovered = false;
// Draw a plot
Plot::new("Plot querying")
.size([content_width, 300.0])
.x_limits(ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver)
.y_limits(
ImPlotRange { Min: 0.0, Max: 5.0 },
YAxisChoice::First,
Condition::FirstUseEver,
)
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY))
.build(plot_ui, || {
if is_plot_hovered() {
hover_pos_plot = Some(get_plot_mouse_position(None));
hover_pos_pixels = Some(plot_to_pixels_vec2(&(hover_pos_plot.unwrap()), None));
}
// Getting the plot position from pixels also works when the plot is not hovered,
// the coordinates are then simply outside the visible range.
hover_pos_from_pixels = Some(pixels_to_plot_vec2(
&ImVec2 {
x: ui.io().mouse_pos[0],
y: ui.io().mouse_pos[1],
// Axis labels
Plot::new("Configured line plot")
.size([x_size, y_size])
.x_label(&x_label)
.y_label(&y_label)
.x_limits(
ImPlotRange {
Min: x_min,
Max: x_max,
},
None,
// Always means that the limits stay what we force them to here, even if the user
// scrolls or drags in the plot with the mouse. FirstUseEver sets the limits the
// first time the plot is drawn, but the user can then modify them and the change
// will stick.
Condition::Always,
)
.y_limits(
ImPlotRange {
Min: y_min,
Max: y_max,
},
YAxisChoice::First,
Condition::Always,
)
.x_ticks(&x_ticks, false)
.y_ticks_with_labels(YAxisChoice::First, &y_ticks, false)
// If any of these flag setting calls are omitted, the defaults are used.
.with_plot_flags(&plot_flags)
.with_x_axis_flags(&x_axis_flags)
.with_y_axis_flags(YAxisChoice::First, &y_axis_flags)
.with_legend_location(&PlotLocation::West, &PlotOrientation::Horizontal, true)
.build(plot_ui, || {
PlotLine::new("A line 2").plot(&vec![2.4, 2.9], &vec![1.1, 1.9]);
});
}
pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demos how to use the querying features."
));
let content_width = ui.window_content_region_width();
// Create some containers for exfiltrating data from the closure below
let mut hover_pos_plot: Option<ImPlotPoint> = None;
let mut hover_pos_pixels: Option<ImVec2> = None;
let mut hover_pos_from_pixels: Option<ImPlotPoint> = None;
let mut plot_limits: Option<ImPlotLimits> = None;
let mut query_limits: Option<ImPlotLimits> = None;
let mut legend1_hovered = false;
let mut legend2_hovered = false;
// Draw a plot
Plot::new("Plot querying")
.size([content_width, 300.0])
.x_limits(ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver)
.y_limits(
ImPlotRange { Min: 0.0, Max: 5.0 },
YAxisChoice::First,
Condition::FirstUseEver,
)
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY))
.build(plot_ui, || {
if is_plot_hovered() {
hover_pos_plot = Some(get_plot_mouse_position(None));
hover_pos_pixels = Some(plot_to_pixels_vec2(&(hover_pos_plot.unwrap()), None));
}
// Getting the plot position from pixels also works when the plot is not hovered,
// the coordinates are then simply outside the visible range.
hover_pos_from_pixels = Some(pixels_to_plot_vec2(
&ImVec2 {
x: ui.io().mouse_pos[0],
y: ui.io().mouse_pos[1],
},
None,
));
// Plot a line so we have a legend entry
PlotLine::new("Legend1").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]);
PlotLine::new("Legend2").plot(&vec![0.0, 0.0], &vec![1.0, 1.0]);
legend1_hovered = is_legend_entry_hovered("Legend1");
legend2_hovered = is_legend_entry_hovered("Legend2");
if is_plot_queried() {
query_limits = Some(get_plot_query(None));
}
plot_limits = Some(get_plot_limits(None));
});
// Print some previously-exfiltrated info. This is because calling
// things like is_plot_hovered or get_plot_mouse_position() outside
// of an actual Plot is not allowed.
if let Some(pos) = hover_pos_plot {
ui.text(im_str!("hovered at {}, {}", pos.x, pos.y));
}
if let Some(pixel_position) = hover_pos_pixels {
// Try out converting plot mouse position to pixel position
ui.text(im_str!(
"pixel pos from plot: {}, {}",
pixel_position.x,
pixel_position.y
));
// Plot a line so we have a legend entry
PlotLine::new("Legend1").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]);
PlotLine::new("Legend2").plot(&vec![0.0, 0.0], &vec![1.0, 1.0]);
legend1_hovered = is_legend_entry_hovered("Legend1");
legend2_hovered = is_legend_entry_hovered("Legend2");
if is_plot_queried() {
query_limits = Some(get_plot_query(None));
}
plot_limits = Some(get_plot_limits(None));
});
// Print some previously-exfiltrated info. This is because calling
// things like is_plot_hovered or get_plot_mouse_position() outside
// of an actual Plot is not allowed.
if let Some(pos) = hover_pos_plot {
ui.text(im_str!("hovered at {}, {}", pos.x, pos.y));
}
if let Some(pixel_position) = hover_pos_pixels {
// Try out converting plot mouse position to pixel position
ui.text(im_str!(
"pixel pos from imgui: {}, {}",
ui.io().mouse_pos[0],
ui.io().mouse_pos[1]
));
}
if let Some(limits) = plot_limits {
ui.text(im_str!("Plot limits are {:#?}", limits));
}
if let Some(query) = query_limits {
ui.text(im_str!("Query limits are {:#?}", query));
}
ui.text(im_str!(
"pixel pos from plot: {}, {}",
pixel_position.x,
pixel_position.y
"Legend hovering - 1: {}, 2: {}",
legend1_hovered,
legend2_hovered
));
// Try out converting pixel position to plot position
if let Some(pos) = hover_pos_from_pixels {
ui.text(im_str!("plot pos from imgui: {}, {}", pos.x, pos.y,));
}
}
pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"pixel pos from imgui: {}, {}",
ui.io().mouse_pos[0],
ui.io().mouse_pos[1]
"This header demos how to use the styling features."
));
}
if let Some(limits) = plot_limits {
ui.text(im_str!("Plot limits are {:#?}", limits));
}
if let Some(query) = query_limits {
ui.text(im_str!("Query limits are {:#?}", query));
}
ui.text(im_str!(
"Legend hovering - 1: {}, 2: {}",
legend1_hovered,
legend2_hovered
));
let content_width = ui.window_content_region_width();
// Try out converting pixel position to plot position
if let Some(pos) = hover_pos_from_pixels {
ui.text(im_str!("plot pos from imgui: {}, {}", pos.x, pos.y,));
// The style stack works the same as for other imgui things - we can push
// things to have them apply, then pop again to undo the change. In implot-rs,
// pushing returns a value on which we have to call .pop() later. Pushing
// variables can be done outside of plot calls as well.
let style = push_style_color(&PlotColorElement::PlotBg, 1.0, 1.0, 1.0, 0.2);
Plot::new("Style demo plot")
.size([content_width, 300.0])
.x_limits(ImPlotRange { Min: 0.0, Max: 6.0 }, Condition::Always)
.y_limits(
ImPlotRange {
Min: -1.0,
Max: 3.0,
},
YAxisChoice::First,
Condition::Always,
)
.with_plot_flags(&(PlotFlags::NONE))
.with_y_axis_flags(YAxisChoice::First, &(AxisFlags::NONE))
.build(plot_ui, || {
// Markers can be selected as shown here. The markers are internally represented
// as an u32, hence this calling style.
let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32);
PlotLine::new("Left eye").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]);
// Calling pop() on the return value of the push above will undo the marker choice.
markerchoice.pop();
// Line weights can be set the same way, along with some other things - see
// the docs of StyleVar for more info.
let lineweight = push_style_var_f32(&StyleVar::LineWeight, 5.0);
PlotLine::new("Right eye").plot(&vec![4.0, 4.0], &vec![2.0, 1.0]);
lineweight.pop();
let x_values = vec![1.0, 2.0, 4.0, 5.0];
let y_values = vec![1.0, 0.0, 0.0, 1.0];
PlotLine::new("Mouth").plot(&x_values, &y_values);
});
style.pop();
}
}
pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demos how to use the styling features."
));
let content_width = ui.window_content_region_width();
pub fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!("This header demos how to select colormaps."));
let content_width = ui.window_content_region_width();
// The style stack works the same as for other imgui things - we can push
// things to have them apply, then pop again to undo the change. In implot-rs,
// pushing returns a value on which we have to call .pop() later. Pushing
// variables can be done outside of plot calls as well.
let style = push_style_color(&PlotColorElement::PlotBg, 1.0, 1.0, 1.0, 0.2);
Plot::new("Style demo plot")
.size([content_width, 300.0])
.x_limits(ImPlotRange { Min: 0.0, Max: 6.0 }, Condition::Always)
.y_limits(
ImPlotRange {
Min: -1.0,
Max: 3.0,
// Select a colormap from the presets. The presets are listed in the Colormap enum
// and usually have something from 9 to 11 colors in them, with the second number
// being the option to resample the colormap to a custom number of colors if picked
// higher than 1.
set_colormap_from_preset(Colormap::Plasma, 1);
Plot::new("Colormap demo plot")
.size([content_width, 300.0])
.build(plot_ui, || {
(1..10)
.map(|x| x as f64 * 0.1)
.map(|x| {
PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])
})
.count();
});
// One can also specify a colormap as a vector of RGBA colors. ImPlot uses ImVec4 for this,
// so we follow suit. Make sure to set the last number (w in ImVec4) to 1.0 to see anything -
// it's the alpha channel.
set_colormap_from_vec(vec![
ImVec4 {
x: 0.9,
y: 0.9,
z: 0.0,
w: 1.0,
},
YAxisChoice::First,
Condition::Always,
)
.with_plot_flags(&(PlotFlags::NONE))
.with_y_axis_flags(YAxisChoice::First, &(AxisFlags::NONE))
.build(plot_ui, || {
// Markers can be selected as shown here. The markers are internally represented
// as an u32, hence this calling style.
let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32);
PlotLine::new("Left eye").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]);
// Calling pop() on the return value of the push above will undo the marker choice.
markerchoice.pop();
ImVec4 {
x: 0.0,
y: 0.9,
z: 0.9,
w: 1.0,
},
]);
// Line weights can be set the same way, along with some other things - see
// the docs of StyleVar for more info.
let lineweight = push_style_var_f32(&StyleVar::LineWeight, 5.0);
PlotLine::new("Right eye").plot(&vec![4.0, 4.0], &vec![2.0, 1.0]);
lineweight.pop();
Plot::new("Colormap demo plot #2")
.size([content_width, 300.0])
.build(plot_ui, || {
(1..10)
.map(|x| x as f64 * 0.1)
.map(|x| {
PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])
})
.count();
});
let x_values = vec![1.0, 2.0, 4.0, 5.0];
let y_values = vec![1.0, 0.0, 0.0, 1.0];
PlotLine::new("Mouth").plot(&x_values, &y_values);
});
style.pop();
}
pub fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!("This header demos how to select colormaps."));
let content_width = ui.window_content_region_width();
// Select a colormap from the presets. The presets are listed in the Colormap enum
// and usually have something from 9 to 11 colors in them, with the second number
// being the option to resample the colormap to a custom number of colors if picked
// higher than 1.
set_colormap_from_preset(Colormap::Plasma, 1);
Plot::new("Colormap demo plot")
.size([content_width, 300.0])
.build(plot_ui, || {
(1..10)
.map(|x| x as f64 * 0.1)
.map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x]))
.count();
});
// One can also specify a colormap as a vector of RGBA colors. ImPlot uses ImVec4 for this,
// so we follow suit. Make sure to set the last number (w in ImVec4) to 1.0 to see anything -
// it's the alpha channel.
set_colormap_from_vec(vec![
ImVec4 {
x: 0.9,
y: 0.9,
z: 0.0,
w: 1.0,
},
ImVec4 {
x: 0.0,
y: 0.9,
z: 0.9,
w: 1.0,
},
]);
Plot::new("Colormap demo plot #2")
.size([content_width, 300.0])
.build(plot_ui, || {
(1..10)
.map(|x| x as f64 * 0.1)
.map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x]))
.count();
});
// Colormaps are not pushed, they are simply set, because they don't stack or anything.
// We can reset to the default by just setting the "Standard" preset.
set_colormap_from_preset(Colormap::Standard, 0);
}
pub fn show_conversions_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demonstrates (in code) how to convert various ranges into ImRange"
));
let content_width = ui.window_content_region_width();
Plot::new("Simple line plot, conversion 1")
.size([content_width, 300.0])
.x_limits(ImVec2 { x: 0.0, y: 1.0 }, Condition::Always)
.y_limits([0.0, 1.0], YAxisChoice::First, Condition::Always)
.build(plot_ui, || {
// If this is called outside a plot build callback, the program will panic.
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
}
pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Line plot: Basic")).build(&ui) {
show_basic_plot(&ui, &plot_ui);
// Colormaps are not pushed, they are simply set, because they don't stack or anything.
// We can reset to the default by just setting the "Standard" preset.
set_colormap_from_preset(Colormap::Standard, 0);
}
if CollapsingHeader::new(im_str!("Line plot: Configured")).build(&ui) {
show_configurable_plot(&ui, &plot_ui);
pub fn show_conversions_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"This header demonstrates (in code) how to convert various ranges into ImRange"
));
let content_width = ui.window_content_region_width();
Plot::new("Simple line plot, conversion 1")
.size([content_width, 300.0])
.x_limits(ImVec2 { x: 0.0, y: 1.0 }, Condition::Always)
.y_limits([0.0, 1.0], YAxisChoice::First, Condition::Always)
.build(plot_ui, || {
// If this is called outside a plot build callback, the program will panic.
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
}
if CollapsingHeader::new(im_str!("Line Plot: Plot queries")).build(&ui) {
show_query_features_plot(&ui, &plot_ui);
pub fn show_linked_x_axis_plots(&mut self, ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!(
"These plots have their X axes linked, but not the Y axes"
));
let content_width = ui.window_content_region_width();
Plot::new("Linked plot 1")
.size([content_width, 300.0])
.linked_x_limits(self.linked_limits.clone())
.build(plot_ui, || {
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
Plot::new("Linked plot 2")
.size([content_width, 300.0])
.linked_x_limits(self.linked_limits.clone())
.build(plot_ui, || {
let x_positions = vec![0.1, 0.9];
let y_positions = vec![0.1, 0.9];
PlotLine::new("legend label").plot(&x_positions, &y_positions);
});
}
if CollapsingHeader::new(im_str!("Line plot: Plot styling")).build(&ui) {
show_style_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Colormaps")).build(&ui) {
show_colormaps_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Multiple Y Axes")).build(&ui) {
show_two_yaxis_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: \"Axis equal\"")).build(&ui) {
show_axis_equal_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Range conversions")).build(&ui) {
show_conversions_plot(&ui, &plot_ui);
pub fn show_demo_headers(&mut self, ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Line plot: Basic")).build(&ui) {
Self::show_basic_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Configured")).build(&ui) {
Self::show_configurable_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line Plot: Plot queries")).build(&ui) {
Self::show_query_features_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Plot styling")).build(&ui) {
Self::show_style_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Colormaps")).build(&ui) {
Self::show_colormaps_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Multiple Y Axes")).build(&ui) {
Self::show_two_yaxis_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: \"Axis equal\"")).build(&ui) {
Self::show_axis_equal_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Range conversions")).build(&ui) {
Self::show_conversions_plot(&ui, &plot_ui);
}
if CollapsingHeader::new(im_str!("Line plot: Linked plots")).build(&ui) {
self.show_linked_x_axis_plots(&ui, &plot_ui);
}
}
}

View file

@ -8,6 +8,7 @@ fn main() {
let system = support::init(file!());
let mut showing_demo = false;
let mut showing_rust_demo = true;
let mut demo_state = examples_shared::DemoState::new();
let plotcontext = Context::create();
system.main_loop(move |_, ui| {
// The context is moved into the closure after creation so plot_ui is valid.
@ -18,7 +19,7 @@ fn main() {
}
if showing_rust_demo {
examples_shared::show_demos(ui, &plot_ui);
demo_state.show_demos(ui, &plot_ui);
}
Window::new(im_str!("Welcome to the ImPlot-rs demo!"))

View file

@ -1,4 +1,3 @@
use imgui::{im_str, Condition, Window};
use implot::Context;
@ -9,6 +8,7 @@ fn main() {
let system = support::init(file!());
let mut showing_demo = false;
let mut showing_rust_demo = true;
let mut demo_state = examples_shared::DemoState::new();
let plotcontext = Context::create();
system.main_loop(move |_, ui| {
// The context is moved into the closure after creation so plot_ui is valid.
@ -19,7 +19,7 @@ fn main() {
}
if showing_rust_demo {
examples_shared::show_demos(ui, &plot_ui);
demo_state.show_demos(ui, &plot_ui);
}
Window::new(im_str!("Welcome to the ImPlot-rs demo!"))