From 8c623a7a79f0fb25e13129b97254c1afacf929b5 Mon Sep 17 00:00:00 2001 From: 4bb4 <67376761+4bb4@users.noreply.github.com> Date: Fri, 30 Oct 2020 12:24:08 +0100 Subject: [PATCH] Added an examples-shared crate to be used from the others --- implot-examples/README.md | 15 + implot-examples/examples-shared/Cargo.toml | 11 + .../examples-shared/src/bar_plots.rs | 40 +++ implot-examples/examples-shared/src/lib.rs | 4 + .../examples-shared/src/line_plots.rs | 270 ++++++++++++++++++ .../examples-shared/src/scatter_plots.rs | 53 ++++ .../examples-shared/src/text_plots.rs | 29 ++ 7 files changed, 422 insertions(+) create mode 100644 implot-examples/README.md create mode 100644 implot-examples/examples-shared/Cargo.toml create mode 100644 implot-examples/examples-shared/src/bar_plots.rs create mode 100644 implot-examples/examples-shared/src/lib.rs create mode 100644 implot-examples/examples-shared/src/line_plots.rs create mode 100644 implot-examples/examples-shared/src/scatter_plots.rs create mode 100644 implot-examples/examples-shared/src/text_plots.rs diff --git a/implot-examples/README.md b/implot-examples/README.md new file mode 100644 index 0000000..5637f1e --- /dev/null +++ b/implot-examples/README.md @@ -0,0 +1,15 @@ +# Examples + +This folder contains examples that demonstrate how to use the Rust bindings. +Things are structured as follows: + +* [examples-shared](examples-shared/) is a library crate that contains the actual usage + examples. It is used in the backend-specific crates. +* [implot-glium-examples](implot-glium-examples/) is an example for using `implot-rs` in +conjunction with a [Glium](https://github.com/glium/glium) backend. +* [implot-wgpu-examples](implot-wgpu-examples/) is an example for using `implot-rs` in +conjunction with a [WebGPU](https://github.com/gfx-rs/wgpu) backend. + +If you want to just copy-paste code to start with, copy `examples-shared` along with +your favourite backend example crate. + diff --git a/implot-examples/examples-shared/Cargo.toml b/implot-examples/examples-shared/Cargo.toml new file mode 100644 index 0000000..892d458 --- /dev/null +++ b/implot-examples/examples-shared/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "examples-shared" +version = "0.1.0" +authors = ["4bb4 <67376761+4bb4@users.noreply.github.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +implot = { path = "../../" } +imgui = "0.5.0" diff --git a/implot-examples/examples-shared/src/bar_plots.rs b/implot-examples/examples-shared/src/bar_plots.rs new file mode 100644 index 0000000..f9fbb2d --- /dev/null +++ b/implot-examples/examples-shared/src/bar_plots.rs @@ -0,0 +1,40 @@ +//! This example demonstrates how bar plots are to be used. For more general +//! features of the libray, see the line_plots example. + +use imgui::{im_str, Ui}; +use implot::{Plot, PlotBars, PlotUi}; + +pub fn show_basic_vertical_plot(ui: &Ui, plot_ui: &PlotUi) { + ui.text(im_str!("This header shows a simple vertical bar plot.")); + let content_width = ui.window_content_region_width(); + Plot::new("Vertical bar 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 axis_positions = vec![0.2, 0.4, 0.6, 0.8]; + let values = vec![0.1, 0.2, 0.3, 0.4]; + PlotBars::new("legend label") + .with_bar_width(0.1) + .plot(&axis_positions, &values); + }); +} + +pub fn show_basic_horizontal_plot(ui: &Ui, plot_ui: &PlotUi) { + ui.text(im_str!("This header shows a simple horizontal bar plot.")); + let content_width = ui.window_content_region_width(); + Plot::new("Horizontal bar 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 axis_positions = vec![0.2, 0.4, 0.6, 0.8]; + let values = vec![0.1, 0.2, 0.3, 0.4]; + PlotBars::new("legend label") + .with_bar_width(0.05) + .with_horizontal_bars() + .plot(&axis_positions, &values); + }); +} diff --git a/implot-examples/examples-shared/src/lib.rs b/implot-examples/examples-shared/src/lib.rs new file mode 100644 index 0000000..d297424 --- /dev/null +++ b/implot-examples/examples-shared/src/lib.rs @@ -0,0 +1,4 @@ +pub mod bar_plots; +pub mod line_plots; +pub mod scatter_plots; +pub mod text_plots; diff --git a/implot-examples/examples-shared/src/line_plots.rs b/implot-examples/examples-shared/src/line_plots.rs new file mode 100644 index 0000000..c98efef --- /dev/null +++ b/implot-examples/examples-shared/src/line_plots.rs @@ -0,0 +1,270 @@ +//! This example demonstrates how line plots are to be used, along with some querying features +//! that will be applicable to all kinds of plots. + +use imgui::{im_str, Condition, Ui}; +use implot::{ + get_plot_limits, get_plot_mouse_position, get_plot_query, is_plot_hovered, is_plot_queried, + push_style_color, push_style_var_f32, push_style_var_i32, set_colormap_from_preset, + set_colormap_from_vec, set_plot_y_axis, AxisFlags, Colormap, ImPlotLimits, ImPlotPoint, + ImPlotRange, ImVec4, Marker, Plot, PlotColorElement, PlotFlags, PlotLine, PlotUi, 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); + }); +} + +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( + &ImPlotRange { Min: 1.0, Max: 3.5 }, + YAxisChoice::Second, + Condition::Always, + ) + .build(plot_ui, || { + let x_positions = vec![0.1, 0.9]; + + // The first Y axis is the default + 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_configurable_plot(ui: &Ui, plot_ui: &PlotUi) { + ui.text(im_str!( + "This header demos what we can configure about plots." + )); + + // 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; + + // - Unlabelled X axis ticks + let x_ticks = vec![2.2, 2.5, 2.8]; + + // - Labelled Y axis ticks + let y_ticks = vec![(1.1, "A".to_owned()), (1.4, "B".to_owned())]; + + // 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) + .build(plot_ui, || { + PlotLine::new("A line").plot(&vec![2.1, 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: Option = None; + let mut plot_limits: Option = None; + let mut query_limits: Option = None; + + // 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 = Some(get_plot_mouse_position(None)); + } + + 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 { + ui.text(im_str!("hovered at {}, {}", pos.x, pos.y)); + } + 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)); + } +} + +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(); + + // 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_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); +} diff --git a/implot-examples/examples-shared/src/scatter_plots.rs b/implot-examples/examples-shared/src/scatter_plots.rs new file mode 100644 index 0000000..709e7ea --- /dev/null +++ b/implot-examples/examples-shared/src/scatter_plots.rs @@ -0,0 +1,53 @@ +//! This example demonstrates how scatter plots are to be used. For more general +//! features of the libray, see the line_plots example. + +use imgui::{im_str, Ui}; +use implot::{push_style_var_f32, push_style_var_i32, Marker, Plot, PlotScatter, PlotUi, StyleVar}; + +pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { + ui.text(im_str!( + "This header just draws a scatter plot with as little code as possible." + )); + let content_width = ui.window_content_region_width(); + Plot::new("Simple scatter 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.2, 0.1, 0.5, 0.9]; + let y_positions = vec![0.1, 0.1, 0.3, 0.3, 0.9]; + PlotScatter::new("legend label").plot(&x_positions, &y_positions); + }); +} + +pub fn show_custom_markers_plot(ui: &Ui, plot_ui: &PlotUi) { + ui.text(im_str!( + "This header shows how markers can be used in scatter plots." + )); + let content_width = ui.window_content_region_width(); + Plot::new("Multi-marker scatter 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, || { + // Change to cross marker for one scatter plot call + let x_positions = vec![0.1, 0.2, 0.1, 0.5, 0.9]; + let y_positions = vec![0.1, 0.1, 0.3, 0.3, 0.9]; + let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32); + PlotScatter::new("legend label 1").plot(&x_positions, &y_positions); + markerchoice.pop(); + + // One can combine things like marker size and markor choice + let x_positions = vec![0.4, 0.1]; + let y_positions = vec![0.5, 0.3]; + let marker_choice = push_style_var_i32(&StyleVar::Marker, Marker::Diamond as i32); + let marker_size = push_style_var_f32(&StyleVar::MarkerSize, 12.0); + PlotScatter::new("legend label 2").plot(&x_positions, &y_positions); + + // TODO(4bb4) check if these have to be in reverse push order. Does not + // seem to be the case. + marker_size.pop(); + marker_choice.pop(); + }); +} diff --git a/implot-examples/examples-shared/src/text_plots.rs b/implot-examples/examples-shared/src/text_plots.rs new file mode 100644 index 0000000..9591390 --- /dev/null +++ b/implot-examples/examples-shared/src/text_plots.rs @@ -0,0 +1,29 @@ +//! This example demonstrates how the text plotting features are to be used. For more general +//! features of the libray, see the line_plots example. + +use imgui::{im_str, Ui}; +use implot::{Plot, PlotText, PlotUi}; + +pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { + ui.text(im_str!( + "This header just plots some text with as little code as possible." + )); + let content_width = ui.window_content_region_width(); + Plot::new("Simple text 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, || { + // The text passed to "new" is what gets displayed. + let x_position: f64 = 0.5; + let y_position: f64 = 0.2; + let vertical: bool = false; + PlotText::new("horizontal displayed text").plot(x_position, y_position, vertical); + + // The text passed to "new" is what gets displayed. + let x_position: f64 = 0.2; + let y_position: f64 = 0.2; + let vertical: bool = true; + PlotText::new("vertical displayed text").plot(x_position, y_position, vertical); + }); +}