Skip to content

Commit dbb93ee

Browse files
committed
feat: custom data with id and hashmap for userdata in plot
1 parent 4919add commit dbb93ee

File tree

18 files changed

+201
-42
lines changed

18 files changed

+201
-42
lines changed

demo/src/plot_demo.rs

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use std::collections::HashMap;
12
use std::ops::RangeInclusive;
23
use std::{f64::consts::TAU, sync::Arc};
34

5+
use egui::mutex::Mutex;
46
use egui::{
5-
Checkbox, Color32, ComboBox, NumExt as _, Pos2, Response, ScrollArea, Stroke, TextWrapMode,
7+
Checkbox, Color32, ComboBox, Id, NumExt as _, Pos2, Response, ScrollArea, Stroke, TextWrapMode,
68
Vec2b, WidgetInfo, WidgetType, remap, vec2,
79
};
810

@@ -24,6 +26,7 @@ enum Panel {
2426
Interaction,
2527
CustomAxes,
2628
LinkedAxes,
29+
Userdata,
2730
}
2831

2932
impl Default for Panel {
@@ -44,6 +47,7 @@ pub struct PlotDemo {
4447
interaction_demo: InteractionDemo,
4548
custom_axes_demo: CustomAxesDemo,
4649
linked_axes_demo: LinkedAxesDemo,
50+
userdata_demo: UserdataDemo,
4751
open_panel: Panel,
4852
}
4953

@@ -124,6 +128,7 @@ impl PlotDemo {
124128
ui.selectable_value(&mut self.open_panel, Panel::Interaction, "Interaction");
125129
ui.selectable_value(&mut self.open_panel, Panel::CustomAxes, "Custom Axes");
126130
ui.selectable_value(&mut self.open_panel, Panel::LinkedAxes, "Linked Axes");
131+
ui.selectable_value(&mut self.open_panel, Panel::Userdata, "Userdata");
127132
});
128133
ui.separator();
129134

@@ -152,6 +157,9 @@ impl PlotDemo {
152157
Panel::LinkedAxes => {
153158
self.linked_axes_demo.ui(ui);
154159
}
160+
Panel::Userdata => {
161+
self.userdata_demo.ui(ui);
162+
}
155163
}
156164
}
157165
}
@@ -642,7 +650,7 @@ impl CustomAxesDemo {
642650
}
643651
};
644652

645-
let label_fmt = |_s: &str, val: &PlotPoint| {
653+
let label_fmt = |_s: &str, val: &PlotPoint, _| {
646654
format!(
647655
"Day {d}, {h}:{m:02}\n{p:.2}%",
648656
d = day(val.x),
@@ -1197,6 +1205,145 @@ impl ChartsDemo {
11971205
}
11981206
}
11991207

1208+
#[derive(PartialEq, serde::Deserialize, serde::Serialize, Default)]
1209+
struct UserdataDemo {}
1210+
1211+
#[derive(Clone)]
1212+
struct DemoPoint {
1213+
x: f64,
1214+
y: f64,
1215+
custom_label: String,
1216+
importance: f32,
1217+
}
1218+
1219+
impl UserdataDemo {
1220+
#[expect(clippy::unused_self, clippy::significant_drop_tightening)]
1221+
fn ui(&self, ui: &mut egui::Ui) -> Response {
1222+
ui.label(
1223+
"This demo shows how to attach custom data to plot items and display it in tooltips.",
1224+
);
1225+
ui.separator();
1226+
1227+
// Create multiple datasets with custom metadata
1228+
let sine_points = (0..=500)
1229+
.map(|i| {
1230+
let x = i as f64 / 100.0;
1231+
DemoPoint {
1232+
x,
1233+
y: x.sin(),
1234+
custom_label: format!("Sine #{i}"),
1235+
importance: (i % 100) as f32 / 100.0,
1236+
}
1237+
})
1238+
.collect::<Vec<_>>();
1239+
1240+
let cosine_points = (0..=500)
1241+
.map(|i| {
1242+
let x = i as f64 / 100.0;
1243+
DemoPoint {
1244+
x,
1245+
y: x.cos(),
1246+
custom_label: format!("Cosine #{i}"),
1247+
importance: (1.0 - (i % 100) as f32 / 100.0),
1248+
}
1249+
})
1250+
.collect::<Vec<_>>();
1251+
1252+
let damped_points = (0..=500)
1253+
.map(|i| {
1254+
let x = i as f64 / 100.0;
1255+
DemoPoint {
1256+
x,
1257+
y: (-x * 0.5).exp() * (2.0 * x).sin(),
1258+
custom_label: format!("Damped #{i}"),
1259+
importance: if i % 50 == 0 { 1.0 } else { 0.3 },
1260+
}
1261+
})
1262+
.collect::<Vec<_>>();
1263+
1264+
// Store custom data in a shared map
1265+
let custom_data = Arc::new(Mutex::new(HashMap::<Id, Vec<DemoPoint>>::new()));
1266+
1267+
let custom_data_ = custom_data.clone();
1268+
Plot::new("Userdata Plot Demo")
1269+
.legend(Legend::default().position(Corner::LeftTop))
1270+
.label_formatter(move |name, value, item| {
1271+
if let Some((id, index)) = item {
1272+
let lock = custom_data_.lock();
1273+
if let Some(points) = lock.get(&id) {
1274+
if let Some(point) = points.get(index) {
1275+
return format!(
1276+
"{}\nPosition: ({:.3}, {:.3})\nLabel: {}\nImportance: {:.1}%",
1277+
name,
1278+
value.x,
1279+
value.y,
1280+
point.custom_label,
1281+
point.importance * 100.0
1282+
);
1283+
}
1284+
}
1285+
}
1286+
format!("{}\n({:.3}, {:.3})", name, value.x, value.y)
1287+
})
1288+
.show(ui, |plot_ui| {
1289+
let mut lock = custom_data.lock();
1290+
1291+
// Sine wave with custom data
1292+
let sine_id = Id::new("sine_wave");
1293+
lock.insert(sine_id, sine_points.clone());
1294+
plot_ui.line(
1295+
Line::new(
1296+
"sin(x)",
1297+
sine_points.iter().map(|p| [p.x, p.y]).collect::<Vec<_>>(),
1298+
)
1299+
.id(sine_id)
1300+
.color(Color32::from_rgb(200, 100, 100)),
1301+
);
1302+
1303+
// Cosine wave with custom data
1304+
let cosine_id = Id::new("cosine_wave");
1305+
lock.insert(cosine_id, cosine_points.clone());
1306+
plot_ui.line(
1307+
Line::new(
1308+
"cos(x)",
1309+
cosine_points.iter().map(|p| [p.x, p.y]).collect::<Vec<_>>(),
1310+
)
1311+
.id(cosine_id)
1312+
.color(Color32::from_rgb(100, 200, 100)),
1313+
);
1314+
1315+
// Damped sine wave with custom data
1316+
let damped_id = Id::new("damped_wave");
1317+
lock.insert(damped_id, damped_points.clone());
1318+
plot_ui.line(
1319+
Line::new(
1320+
"e^(-0.5x) · sin(2x)",
1321+
damped_points.iter().map(|p| [p.x, p.y]).collect::<Vec<_>>(),
1322+
)
1323+
.id(damped_id)
1324+
.color(Color32::from_rgb(100, 100, 200)),
1325+
);
1326+
1327+
// Add some points with high importance as markers
1328+
let important_points: Vec<_> = damped_points
1329+
.iter()
1330+
.filter(|p| p.importance > 0.9)
1331+
.map(|p| [p.x, p.y])
1332+
.collect();
1333+
1334+
if !important_points.is_empty() {
1335+
plot_ui.points(
1336+
Points::new("Important Points", important_points)
1337+
.color(Color32::from_rgb(255, 150, 0))
1338+
.radius(4.0)
1339+
.shape(MarkerShape::Diamond),
1340+
);
1341+
}
1342+
})
1343+
.response
1344+
}
1345+
}
1346+
12001347
fn is_approx_zero(val: f64) -> bool {
12011348
val.abs() < 1e-6
12021349
}
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)