Add simple heatmap support

This commit is contained in:
silvana 2023-09-25 12:35:59 +02:00
parent e6a6f67b4d
commit 03b356f575
4 changed files with 131 additions and 19 deletions

47
src/heatmap.rs Normal file
View file

@ -0,0 +1,47 @@
use sys::{ImPlotHeatmapFlags, ImPlotHeatmapFlags__ImPlotHeatmapFlags_ColMajor};
use crate::sys;
use std::ffi::CString;
use std::os::raw::c_char;
pub use crate::sys::ImPlotPoint;
pub struct PlotHeatmap {
label: CString,
}
impl PlotHeatmap {
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("label string has internal null bytes: {}", label)),
}
}
pub fn plot(&self, x: &[f64], rows: i32, cols: i32) {
if x.is_empty() {
return;
}
unsafe {
sys::ImPlot_PlotHeatmap_doublePtr(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
rows,
cols,
0.0,
0.0,
"\0".as_ptr() as *const c_char,
ImPlotPoint {
x: 0f64,
y: rows as f64,
},
ImPlotPoint {
x: cols as f64,
y: 0f64,
},
ImPlotHeatmapFlags__ImPlotHeatmapFlags_ColMajor as ImPlotHeatmapFlags,
);
}
}
}

View file

@ -24,6 +24,7 @@ use std::os::raw::c_char;
pub use sys::{ImAxis, ImPlotPoint, ImPlotRange, ImPlotRect, ImVec2, ImVec4};
mod context;
pub mod heatmap;
pub mod lines;
mod plot;
mod plot_elements;
@ -31,11 +32,11 @@ pub mod rect;
// The bindings for some reason don't contain this - it has to match the IMPLOT_AUTO from
// the original C++ header for things to work properly.
const IMPLOT_AUTO: i32 = -1;
//const IMPLOT_AUTO: i32 = -1;
// Number of Y axes, this is used in a bunch of places for storing things like settings.
// If this changes, also change the YAxisChoice enum.
const NUMBER_OF_Y_AXES: usize = 3;
//const NUMBER_OF_Y_AXES: usize = 3;
/// Choice of Y axis. This an enum instead of just an integer so as to make it impossible
/// to select a Y axis that is not present - this makes it easier to avoid `Result`-type

View file

@ -16,6 +16,25 @@ impl PlotLine {
}
}
pub fn plot_with_step(&self, x: &[f64], step: f64) {
if x.is_empty() {
return;
}
unsafe {
sys::ImPlot_PlotLine_doublePtrInt(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
x.len() as i32,
step,
0f64,
0,
0,
std::mem::size_of::<f64>() as i32,
);
}
}
pub fn plot(&self, x: &[f64], y: &[f64]) {
if x.len().min(y.len()) == 0 {
return;

View file

@ -1,8 +1,8 @@
use std::ffi::CString;
use std::ffi::{c_char, CString};
use bitflags::bitflags;
use implot_sys as sys;
use sys::{ImAxis, ImVec2, *};
use sys::{ImVec2, *};
use crate::{Context, PlotUi};
@ -22,17 +22,17 @@ bitflags! {
#[repr(transparent)]
pub struct PlotFlags: u32 {
const NONE = ImPlotFlags__ImPlotFlags_None;
const NOTITLE = ImPlotFlags__ImPlotFlags_NoTitle;
const NOLEGEND = ImPlotFlags__ImPlotFlags_NoLegend;
const NOMOUSETEXT = ImPlotFlags__ImPlotFlags_NoMouseText;
const NOINPUTS = ImPlotFlags__ImPlotFlags_NoInputs;
const NOMENUS = ImPlotFlags__ImPlotFlags_NoMenus;
const NOBOXSELECT = ImPlotFlags__ImPlotFlags_NoBoxSelect;
const NOCHILD = ImPlotFlags__ImPlotFlags_NoChild;
const NOFRAME = ImPlotFlags__ImPlotFlags_NoFrame;
const NO_TITLE = ImPlotFlags__ImPlotFlags_NoTitle;
const NO_LEGEND = ImPlotFlags__ImPlotFlags_NoLegend;
const NO_MOUSE_TEXT = ImPlotFlags__ImPlotFlags_NoMouseText;
const NO_INPUTS = ImPlotFlags__ImPlotFlags_NoInputs;
const NO_MENUS = ImPlotFlags__ImPlotFlags_NoMenus;
const NO_BOX_SELECT = ImPlotFlags__ImPlotFlags_NoBoxSelect;
const NO_CHILD = ImPlotFlags__ImPlotFlags_NoChild;
const NO_FRAME = ImPlotFlags__ImPlotFlags_NoFrame;
const EQUAL = ImPlotFlags__ImPlotFlags_Equal;
const CROSSHAIRS = ImPlotFlags__ImPlotFlags_Crosshairs;
const CANVASONLY = ImPlotFlags__ImPlotFlags_CanvasOnly;
const CANVAS_ONLY = ImPlotFlags__ImPlotFlags_CanvasOnly;
}
}
@ -70,6 +70,8 @@ pub struct Plot {
flags: ImPlotFlags,
x_flags: ImPlotAxisFlags,
y_flags: ImPlotAxisFlags,
x_limit: Option<[f64; 2]>,
y_limit: Option<[f64; 2]>,
}
impl Plot {
@ -83,6 +85,25 @@ impl Plot {
flags: PlotFlags::NONE.bits() as ImPlotFlags,
x_flags: PlotAxisFlags::NONE.bits() as ImPlotAxisFlags,
y_flags: PlotAxisFlags::NONE.bits() as ImPlotAxisFlags,
x_limit: None,
y_limit: None,
}
}
pub fn color_map_scale(title: &str, min: f64, max: f64, size: ImVec2) {
let title = CString::new(title)
.unwrap_or_else(|_| panic!("string contains internal null bytes: {}", title));
unsafe {
sys::ImPlot_ColormapScale(
title.as_ptr() as *const c_char,
min,
max,
size,
"%.0f\0".as_ptr() as *const c_char,
0,
0,
);
}
}
@ -91,21 +112,31 @@ impl Plot {
self
}
pub fn with_flags(mut self, flags: &PlotFlags) -> Self {
pub fn with_flags(mut self, flags: PlotFlags) -> Self {
self.flags = flags.bits() as ImPlotFlags;
self
}
pub fn with_x_flags(mut self, flags: &PlotAxisFlags) -> Self {
pub fn with_x_flags(mut self, flags: PlotAxisFlags) -> Self {
self.x_flags = flags.bits() as ImPlotAxisFlags;
self
}
pub fn with_y_flags(mut self, flags: &PlotAxisFlags) -> Self {
pub fn with_y_flags(mut self, flags: PlotAxisFlags) -> Self {
self.y_flags = flags.bits() as ImPlotAxisFlags;
self
}
pub fn with_x_limit(mut self, min: f64, max: f64) -> Self {
self.x_limit = Some([min, max]);
self
}
pub fn with_y_limit(mut self, min: f64, max: f64) -> Self {
self.y_limit = Some([min, max]);
self
}
pub fn x_label(mut self, label: &str) -> Self {
self.x_label = CString::new(label)
.unwrap_or_else(|_| panic!("string contains internal null bytes: {}", label));
@ -127,15 +158,29 @@ impl Plot {
y: self.size[1],
};
let should_render = sys::ImPlot_BeginPlot(self.title.as_ptr(), size_vec, self.flags);
should_render
sys::ImPlot_BeginPlot(self.title.as_ptr(), size_vec, self.flags)
};
if should_render {
unsafe {
sys::ImPlot_SetupAxis(Axis::X1 as i32, self.x_label.as_ptr(), self.x_flags);
sys::ImPlot_SetupAxis(Axis::Y1 as i32, self.y_label.as_ptr(), self.y_flags);
if let Some(limit) = self.x_limit {
sys::ImPlot_SetupAxisLimits(
Axis::X1 as i32,
limit[0],
limit[1],
ImPlotCond__ImPlotCond_Once as i32,
);
}
if let Some(limit) = self.y_limit {
sys::ImPlot_SetupAxisLimits(
Axis::Y1 as i32,
limit[0],
limit[1],
ImPlotCond__ImPlotCond_Once as i32,
);
}
}
Some(PlotToken {