Skip to main content

runmat_runtime/builtins/plotting/
mod.rs

1//! Plotting builtins backed by the runmat-plot renderer.
2
3#[path = "core/common.rs"]
4pub(crate) mod common;
5#[path = "core/context.rs"]
6pub mod context;
7#[path = "core/engine.rs"]
8pub(crate) mod engine;
9#[path = "core/gpu_helpers.rs"]
10pub(crate) mod gpu_helpers;
11#[path = "core/perf.rs"]
12pub(crate) mod perf;
13#[path = "core/point.rs"]
14pub(crate) mod point;
15#[path = "core/properties.rs"]
16pub(crate) mod properties;
17#[path = "core/state.rs"]
18pub(crate) mod state;
19#[path = "core/style.rs"]
20pub(crate) mod style;
21#[path = "core/web.rs"]
22pub mod web;
23
24#[path = "type_resolvers.rs"]
25pub(crate) mod type_resolvers;
26
27#[path = "ops/area.rs"]
28pub(crate) mod area;
29#[path = "ops/bar.rs"]
30pub(crate) mod bar;
31#[path = "ops/caxis.rs"]
32pub(crate) mod caxis;
33#[path = "ops/clf.rs"]
34pub(crate) mod clf;
35#[path = "ops/clim.rs"]
36pub(crate) mod clim;
37#[path = "ops/close.rs"]
38pub(crate) mod close;
39#[path = "ops/cmds.rs"]
40pub(crate) mod cmds;
41#[path = "ops/contour.rs"]
42pub(crate) mod contour;
43#[path = "ops/contour3.rs"]
44pub(crate) mod contour3;
45#[path = "ops/contourf.rs"]
46pub(crate) mod contourf;
47#[path = "ops/drawnow.rs"]
48pub(crate) mod drawnow;
49#[path = "ops/errorbar.rs"]
50pub(crate) mod errorbar;
51#[path = "ops/figure.rs"]
52pub(crate) mod figure;
53#[path = "ops/fill3.rs"]
54pub(crate) mod fill3;
55#[path = "ops/gca.rs"]
56pub(crate) mod gca;
57#[path = "ops/gcf.rs"]
58pub(crate) mod gcf;
59#[path = "ops/get.rs"]
60pub(crate) mod get;
61#[path = "ops/heatmap.rs"]
62pub(crate) mod heatmap;
63#[path = "ops/hist.rs"]
64pub mod hist;
65#[path = "ops/histogram.rs"]
66pub(crate) mod histogram;
67#[path = "ops/hold.rs"]
68pub(crate) mod hold;
69#[path = "ops/image.rs"]
70pub(crate) mod image;
71#[path = "ops/imagesc.rs"]
72pub(crate) mod imagesc;
73#[path = "ops/imshow.rs"]
74pub(crate) mod imshow;
75#[path = "ops/isgraphics.rs"]
76pub(crate) mod isgraphics;
77#[path = "ops/ishandle.rs"]
78pub(crate) mod ishandle;
79#[path = "ops/legend.rs"]
80pub(crate) mod legend;
81#[path = "ops/loglog.rs"]
82pub(crate) mod loglog;
83#[path = "ops/mesh.rs"]
84pub(crate) mod mesh;
85#[path = "ops/meshc.rs"]
86pub(crate) mod meshc;
87#[path = "ops/common/mod.rs"]
88pub(crate) mod op_common;
89#[path = "ops/patch.rs"]
90pub(crate) mod patch;
91#[path = "ops/pie.rs"]
92pub(crate) mod pie;
93#[path = "ops/plot.rs"]
94pub(crate) mod plot;
95#[path = "ops/plot3.rs"]
96pub(crate) mod plot3;
97#[path = "ops/print.rs"]
98pub(crate) mod print;
99#[path = "ops/quiver.rs"]
100pub(crate) mod quiver;
101#[path = "ops/scatter.rs"]
102pub(crate) mod scatter;
103#[path = "ops/scatter3.rs"]
104pub(crate) mod scatter3;
105#[path = "ops/scatterplot.rs"]
106pub(crate) mod scatterplot;
107#[path = "ops/semilogx.rs"]
108pub(crate) mod semilogx;
109#[path = "ops/semilogy.rs"]
110pub(crate) mod semilogy;
111#[path = "ops/set.rs"]
112pub(crate) mod set;
113#[path = "ops/sgtitle.rs"]
114pub(crate) mod sgtitle;
115#[path = "ops/stairs.rs"]
116pub(crate) mod stairs;
117#[path = "ops/stem.rs"]
118pub(crate) mod stem;
119#[path = "ops/subplot.rs"]
120pub(crate) mod subplot;
121#[path = "ops/suptitle.rs"]
122pub(crate) mod suptitle;
123#[path = "ops/surf.rs"]
124pub(crate) mod surf;
125#[path = "ops/surfc.rs"]
126pub(crate) mod surfc;
127#[path = "ops/text.rs"]
128pub(crate) mod text;
129#[path = "ops/title.rs"]
130pub(crate) mod title;
131#[path = "ops/view.rs"]
132pub(crate) mod view;
133#[path = "ops/xlabel.rs"]
134pub(crate) mod xlabel;
135#[path = "ops/xlim.rs"]
136pub(crate) mod xlim;
137#[path = "ops/xline.rs"]
138pub(crate) mod xline;
139#[path = "ops/ylabel.rs"]
140pub(crate) mod ylabel;
141#[path = "ops/ylim.rs"]
142pub(crate) mod ylim;
143#[path = "ops/yline.rs"]
144pub(crate) mod yline;
145#[path = "ops/zlabel.rs"]
146pub(crate) mod zlabel;
147#[path = "ops/zlim.rs"]
148pub(crate) mod zlim;
149
150pub use perf::{set_scatter_target_points, set_surface_vertex_budget};
151pub use properties::resolve_plot_handle;
152pub use state::{
153    clear_figure, clone_figure, close_figure, configure_subplot, current_axes_state,
154    current_figure_handle, figure_handles, import_figure, install_figure_observer,
155    new_figure_handle, record_recent_figure, reset_hold_state_for_run, reset_plot_state,
156    reset_recent_figures, select_axes_for_figure, select_figure, set_hold, take_recent_figures,
157    FigureAxesState, FigureError, FigureEventKind, FigureEventView, FigureHandle, HoldMode,
158};
159use std::collections::HashMap;
160use std::sync::{Mutex, OnceLock};
161use web::present_figure_on_surface as web_present_figure_on_surface;
162pub use web::{
163    bind_surface_to_figure, clear_closed_figure_surfaces, detach_surface, fit_surface_extents,
164    get_surface_camera_state, install_surface, invalidate_surface_revisions, present_surface,
165    render_current_scene, reset_surface_camera, resize_surface, set_plot_theme_config,
166    set_surface_camera_state, web_renderer_ready, PlotCameraProjection, PlotCameraState,
167    PlotSurfaceCameraState,
168};
169
170#[doc(hidden)]
171pub use state::PlotTestLockGuard;
172
173#[doc(hidden)]
174pub fn lock_plot_test_context() -> PlotTestLockGuard {
175    state::lock_plot_test_registry()
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179pub enum RuntimePlottingMode {
180    Auto,
181    Interactive,
182    Static,
183}
184
185#[cfg(feature = "gui")]
186pub fn set_runtime_plotting_mode(mode: RuntimePlottingMode) {
187    let mapped = match mode {
188        RuntimePlottingMode::Auto => engine::native::RuntimePlottingMode::Auto,
189        RuntimePlottingMode::Interactive => engine::native::RuntimePlottingMode::Interactive,
190        RuntimePlottingMode::Static => engine::native::RuntimePlottingMode::Static,
191    };
192    engine::native::set_runtime_plotting_mode(mapped);
193}
194
195#[cfg(not(feature = "gui"))]
196pub fn set_runtime_plotting_mode(_mode: RuntimePlottingMode) {}
197
198#[cfg(all(target_arch = "wasm32", feature = "plot-web"))]
199pub use web::handle_plot_surface_event;
200
201pub(crate) fn plotting_error(builtin: &str, message: impl Into<String>) -> crate::RuntimeError {
202    crate::build_runtime_error(message)
203        .with_builtin(builtin)
204        .build()
205}
206
207pub(crate) fn plotting_error_with_source(
208    builtin: &str,
209    message: impl Into<String>,
210    source: impl std::error::Error + Send + Sync + 'static,
211) -> crate::RuntimeError {
212    crate::build_runtime_error(message)
213        .with_builtin(builtin)
214        .with_source(source)
215        .build()
216}
217
218#[cfg(feature = "plot-core")]
219pub fn export_figure_scene(handle: FigureHandle) -> crate::BuiltinResult<Option<Vec<u8>>> {
220    let Some(figure) = clone_figure(handle) else {
221        return Ok(None);
222    };
223    let scene = runmat_plot::event::FigureScene::capture(&figure);
224    crate::replay::export_figure_scene_payload(&scene).map(Some)
225}
226
227#[cfg(feature = "plot-core")]
228pub fn import_figure_scene(bytes: &[u8]) -> crate::BuiltinResult<Option<FigureHandle>> {
229    let scene = crate::replay::import_figure_scene_payload(bytes)?;
230    let figure = scene.into_figure().map_err(|err| {
231        crate::replay_error_with_source(
232            crate::ReplayErrorKind::ImportRejected,
233            "invalid figure scene content",
234            std::io::Error::new(std::io::ErrorKind::InvalidData, err),
235        )
236    })?;
237    let handle = import_figure(figure);
238    register_imported_figure(handle.as_u32());
239    Ok(Some(handle))
240}
241
242#[cfg(feature = "plot-core")]
243pub async fn import_figure_scene_async(bytes: &[u8]) -> crate::BuiltinResult<Option<FigureHandle>> {
244    let scene = crate::replay::import_figure_scene_payload_async(bytes).await?;
245    let figure = scene.into_figure().map_err(|err| {
246        crate::replay_error_with_source(
247            crate::ReplayErrorKind::ImportRejected,
248            "invalid figure scene content",
249            std::io::Error::new(std::io::ErrorKind::InvalidData, err),
250        )
251    })?;
252    let handle = import_figure(figure);
253    register_imported_figure(handle.as_u32());
254    Ok(Some(handle))
255}
256
257#[cfg(feature = "plot-core")]
258pub async fn import_figure_scene_from_path_async(
259    path: &str,
260) -> crate::BuiltinResult<Option<FigureHandle>> {
261    let bytes = runmat_filesystem::read_async(path).await.map_err(|err| {
262        crate::replay_error_with_source(
263            crate::ReplayErrorKind::ImportRejected,
264            format!("failed to read figure scene payload '{path}'"),
265            err,
266        )
267    })?;
268    import_figure_scene_async(&bytes).await
269}
270
271pub fn present_figure_on_surface(surface_id: u32, handle: u32) -> crate::BuiltinResult<()> {
272    web_present_figure_on_surface(surface_id, handle)?;
273    if take_imported_figure(handle) {
274        let _ = reset_surface_camera(surface_id);
275    }
276    Ok(())
277}
278
279type ImportedFigureRegistry = Mutex<HashMap<u32, ()>>;
280
281fn imported_figure_registry() -> &'static ImportedFigureRegistry {
282    static REGISTRY: OnceLock<ImportedFigureRegistry> = OnceLock::new();
283    REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
284}
285
286fn register_imported_figure(handle: u32) {
287    if let Ok(mut map) = imported_figure_registry().lock() {
288        map.insert(handle, ());
289    }
290}
291
292fn take_imported_figure(handle: u32) -> bool {
293    imported_figure_registry()
294        .lock()
295        .ok()
296        .and_then(|mut map| map.remove(&handle))
297        .is_some()
298}
299
300#[cfg(feature = "plot-core")]
301pub use engine::{
302    render_figure_png_bytes, render_figure_png_bytes_with_axes_cameras,
303    render_figure_png_bytes_with_camera, render_figure_rgba_bytes,
304    render_figure_rgba_bytes_with_axes_cameras, render_figure_rgba_bytes_with_camera,
305    render_figure_snapshot, render_figure_snapshot_with_camera_state,
306};
307
308pub mod ops {
309    pub use super::hist;
310}
311
312#[cfg(test)]
313pub(crate) mod tests {
314    use super::state;
315
316    pub(crate) fn ensure_plot_test_env() {
317        state::disable_rendering_for_tests();
318    }
319
320    pub(crate) fn lock_plot_registry() -> state::PlotTestLockGuard {
321        state::lock_plot_test_registry()
322    }
323}