Skip to content

Commit a55802f

Browse files
committed
Work on demo_implot (3D part)
1 parent fae8b66 commit a55802f

4 files changed

Lines changed: 288 additions & 13 deletions

File tree

bindings/imgui_bundle/demos_cpp/demo_imgui_bundle.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ int main(int, char **)
9595
DEMO_DETAILS("Dear ImGui Bundle", demo_imgui_bundle_intro),
9696
DEMO_DETAILS("Dear ImGui", demo_imgui_show_demo_window),
9797
DEMO_DETAILS("Immediate Apps", demo_immapp_launcher),
98-
DEMO_DETAILS("Implot", demo_implot),
98+
DEMO_DETAILS("Implot [3D]", demo_implot),
9999
DEMO_DETAILS("Node Editor", demo_node_editor_launcher),
100100
DEMO_DETAILS("Markdown", demo_imgui_md),
101101
DEMO_DETAILS("Text Editor", demo_text_edit),
@@ -139,6 +139,7 @@ int main(int, char **)
139139
addons.withNodeEditor = true;
140140
addons.withMarkdown = true;
141141
addons.withImplot = true;
142+
addons.withImplot3d = true;
142143
addons.withTexInspect = true;
143144
ImmApp::Run(runnerParams, addons);
144145

bindings/imgui_bundle/demos_cpp/demo_implot.cpp

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@
55
#include "implot/implot.h"
66
#include "immapp/immapp.h"
77
#include "demo_utils/api_demos.h"
8+
#include "imgui_internal.h"
89

10+
#ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
11+
#include "implot3d/implot3d.h"
12+
#endif
13+
14+
// =======================
15+
// Demos for ImPlot (2D)
16+
// =======================
917

1018
void DemoMixedPlot()
1119
{
@@ -96,22 +104,154 @@ static void DemoHeatmap()
96104
}
97105

98106

107+
// =======================
108+
// Demos for ImPlot3D
109+
// =======================
110+
111+
#ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
112+
void Demo3D_LinePlots() {
113+
static float xs1[1001], ys1[1001], zs1[1001];
114+
for (int i = 0; i < 1001; i++) {
115+
xs1[i] = i * 0.001f;
116+
ys1[i] = 0.5f + 0.5f * cosf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
117+
zs1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
118+
}
119+
static double xs2[20], ys2[20], zs2[20];
120+
for (int i = 0; i < 20; i++) {
121+
xs2[i] = i * 1 / 19.0f;
122+
ys2[i] = xs2[i] * xs2[i];
123+
zs2[i] = xs2[i] * ys2[i];
124+
}
125+
if (ImPlot3D::BeginPlot("Line Plots")) {
126+
ImPlot3D::SetupAxes("x", "y", "z");
127+
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001);
128+
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle);
129+
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, ImPlot3DLineFlags_Segments);
130+
ImPlot3D::EndPlot();
131+
}
132+
}
133+
134+
135+
void Demo3D_SurfacePlots() {
136+
constexpr int N = 20;
137+
static float xs[N * N], ys[N * N], zs[N * N];
138+
static float t = 0.0f;
139+
t += ImGui::GetIO().DeltaTime;
140+
141+
// Define the range for X and Y
142+
constexpr float min_val = -1.0f;
143+
constexpr float max_val = 1.0f;
144+
constexpr float step = (max_val - min_val) / (N - 1);
145+
146+
// Populate the xs, ys, and zs arrays
147+
for (int i = 0; i < N; i++) {
148+
for (int j = 0; j < N; j++) {
149+
int idx = i * N + j;
150+
xs[idx] = min_val + j * step; // X values are constant along rows
151+
ys[idx] = min_val + i * step; // Y values are constant along columns
152+
zs[idx] = ImSin(2 * t + ImSqrt((xs[idx] * xs[idx] + ys[idx] * ys[idx]))); // z = sin(2t + sqrt(x^2 + y^2))
153+
}
154+
}
155+
156+
// Choose fill color
157+
ImGui::Text("Fill color");
158+
static int selected_fill = 1; // Colormap by default
159+
static ImVec4 solid_color = ImVec4(0.8f, 0.8f, 0.2f, 0.6f);
160+
const char* colormaps[] = {"Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet",
161+
"Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys"};
162+
static int sel_colormap = 5; // Jet by default
163+
{
164+
ImGui::Indent();
165+
166+
// Choose solid color
167+
ImGui::RadioButton("Solid", &selected_fill, 0);
168+
if (selected_fill == 0) {
169+
ImGui::SameLine();
170+
ImGui::ColorEdit4("##SurfaceSolidColor", (float*)&solid_color);
171+
}
172+
173+
// Choose colormap
174+
ImGui::RadioButton("Colormap", &selected_fill, 1);
175+
if (selected_fill == 1) {
176+
ImGui::SameLine();
177+
ImGui::Combo("##SurfaceColormap", &sel_colormap, colormaps, IM_ARRAYSIZE(colormaps));
178+
}
179+
ImGui::Unindent();
180+
}
181+
182+
// Choose range
183+
static bool custom_range = false;
184+
static float range_min = -1.0f;
185+
static float range_max = 1.0f;
186+
ImGui::Checkbox("Custom range", &custom_range);
187+
{
188+
ImGui::Indent();
189+
190+
if (!custom_range)
191+
ImGui::BeginDisabled();
192+
ImGui::SliderFloat("Range min", &range_min, -1.0f, range_max - 0.01f);
193+
ImGui::SliderFloat("Range max", &range_max, range_min + 0.01f, 1.0f);
194+
if (!custom_range)
195+
ImGui::EndDisabled();
196+
197+
ImGui::Unindent();
198+
}
199+
200+
// Begin the plot
201+
if (selected_fill == 1)
202+
ImPlot3D::PushColormap(colormaps[sel_colormap]);
203+
if (ImPlot3D::BeginPlot("Surface Plots", ImVec2(-1, 400), ImPlot3DFlags_NoClip)) {
204+
// Set styles
205+
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1.5, 1.5);
206+
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.8f);
207+
if (selected_fill == 0)
208+
ImPlot3D::SetNextFillStyle(solid_color);
209+
ImPlot3D::SetNextLineStyle(ImPlot3D::GetColormapColor(1));
210+
211+
// Plot the surface
212+
if (custom_range)
213+
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, (double)range_min, (double)range_max);
214+
else
215+
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N);
216+
217+
// End the plot
218+
ImPlot3D::PopStyleVar();
219+
ImPlot3D::EndPlot();
220+
}
221+
if (selected_fill == 1)
222+
ImPlot3D::PopColormap();
223+
}
224+
#endif // #ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
225+
226+
227+
// =======================
228+
// Main demo function
229+
// =======================
99230
void demo_implot()
100231
{
101232
ImGuiMd::RenderUnindented(R"(
102-
# ImPlot
103-
[Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
233+
# ImPlot & ImPlot3D
234+
* [Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
235+
* [Implot3D](https://github.com/brenocq/implot3d) provides immediate Mode 3D Plotting, with an API inspired from ImPlot.
236+
104237
You can see lots of demos together with their code [online](https://traineq.org/implot_demo/src/implot_demo.html)
105238
)");
106239
if (ImGui::Button("View the full demo"))
107240
{
108241
BrowseToUrl("https://traineq.org/implot_demo/src/implot_demo.html");
109242
}
110243
ImGui::NewLine();
111-
if (ImGui::CollapsingHeader("Mixed plot##2", ImGuiTreeNodeFlags_DefaultOpen))
244+
if (ImGui::CollapsingHeader("ImPlot: Mixed plot##2"))
112245
DemoMixedPlot();
113-
if (ImGui::CollapsingHeader("Heatmap"))
246+
if (ImGui::CollapsingHeader("ImPlot: Heatmap"))
114247
DemoHeatmap();
248+
249+
#ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
250+
if (ImGui::CollapsingHeader("ImPlot3D: Line plots##2"))
251+
Demo3D_LinePlots();
252+
if (ImGui::CollapsingHeader("ImPlot3D: Surface Plots##2"))
253+
Demo3D_SurfacePlots();
254+
#endif
115255
}
116256

117257
#else // IMGUI_BUNDLE_WITH_IMPLOT

bindings/imgui_bundle/demos_python/demo_imgui_bundle.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class DemoDetails:
9191
DemoDetails("Dear ImGui Bundle", demo_imgui_bundle_intro),
9292
DemoDetails("Dear ImGui", demo_imgui_show_demo_window),
9393
DemoDetails("Immediate Apps", demo_immapp_launcher),
94-
DemoDetails("Implot", demo_implot),
94+
DemoDetails("Implot [3D]", demo_implot),
9595
DemoDetails("Node Editor", demo_node_editor_launcher),
9696
DemoDetails("Markdown", demo_imgui_md),
9797
DemoDetails("Text Editor", demo_text_edit),
@@ -131,6 +131,7 @@ def show_gui():
131131
addons.with_node_editor = True
132132
addons.with_markdown = True
133133
addons.with_implot = True
134+
addons.with_implot3d = True
134135
addons.with_tex_inspect = True
135136

136137
return runner_params, addons

bindings/imgui_bundle/demos_python/demo_implot.py

Lines changed: 140 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import math
44
import numpy as np
55
from numpy.typing import NDArray
6-
from imgui_bundle import imgui, implot, imgui_md, immapp, ImVec2, ImVec4
6+
from imgui_bundle import imgui, implot, implot3d, imgui_md, immapp, ImVec2, ImVec4
77

88

9+
# ========================
10+
# Demos for ImPlot (2D)
11+
# ========================
12+
913
class DemoDragRectState:
1014
x_data: NDArray[np.float64]
1115
y_data1: NDArray[np.float64]
@@ -170,11 +174,134 @@ def demo_heatmap():
170174
implot.pop_colormap()
171175

172176

177+
# ========================
178+
# Demos for ImPlot3D
179+
# ========================
180+
def demo3d_lineplots():
181+
xs1 = np.linspace(0, 1, 1001)
182+
ys1 = 0.5 + 0.5 * np.cos(50 * (xs1 + imgui.get_time() / 10))
183+
zs1 = 0.5 + 0.5 * np.sin(50 * (xs1 + imgui.get_time() / 10))
184+
185+
xs2 = np.linspace(0, 1, 20)
186+
ys2 = xs2 * xs2
187+
zs2 = xs2 * ys2
188+
189+
if implot3d.begin_plot("Line Plots"):
190+
implot3d.setup_axes("x", "y", "z")
191+
implot3d.plot_line("f(x)", xs1, ys1, zs1)
192+
implot3d.set_next_marker_style(implot3d.Marker_.circle.value)
193+
implot3d.plot_line("g(x)", xs2, ys2, zs2, implot3d.LineFlags_.segments.value)
194+
implot3d.end_plot()
195+
196+
197+
def demo3d_surfaceplots():
198+
statics = demo3d_surfaceplots
199+
N = 20
200+
if not hasattr(statics, "xs"):
201+
statics.xs = np.zeros(N * N)
202+
statics.ys = np.zeros(N * N)
203+
statics.zs = np.zeros(N * N)
204+
statics.t = 0.0
205+
206+
statics.t += imgui.get_io().delta_time
207+
208+
# Define the range for X and Y
209+
min_val = -1.0
210+
max_val = 1.0
211+
step = (max_val - min_val) / (N - 1)
212+
213+
# Populate the xs, ys, and zs arrays
214+
for i in range(N):
215+
for j in range(N):
216+
idx = i * N + j
217+
statics.xs[idx] = min_val + j * step # X values are constant along rows
218+
statics.ys[idx] = min_val + i * step # Y values are constant along columns
219+
# z = sin(2t + sqrt(x^2 + y^2))
220+
statics.zs[idx] = math.sin(2 * statics.t + math.sqrt(statics.xs[idx] * statics.xs[idx] + statics.ys[idx] * statics.ys[idx]))
221+
222+
# Choose fill color
223+
imgui.text("Fill color")
224+
if not hasattr(statics, "selected_fill"):
225+
statics.selected_fill = 1 # Colormap by default
226+
if not hasattr(statics, "solid_color"):
227+
statics.solid_color = [0.8, 0.8, 0.2, 0.6]
228+
colormaps = [
229+
"Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet",
230+
"Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys"
231+
]
232+
if not hasattr(statics, "sel_colormap"):
233+
statics.sel_colormap = 5 # Jet by default
234+
235+
imgui.indent()
236+
237+
# Choose solid color
238+
if imgui.radio_button("Solid", statics.selected_fill == 0):
239+
statics.selected_fill = 0
240+
if statics.selected_fill == 0:
241+
imgui.same_line()
242+
_, statics.solid_color = imgui.color_edit4("##SurfaceSolidColor", statics.solid_color)
243+
244+
# Choose colormap
245+
if imgui.radio_button("Colormap", statics.selected_fill == 1):
246+
statics.selected_fill = 1
247+
if statics.selected_fill == 1:
248+
imgui.same_line()
249+
_, statics.sel_colormap = imgui.combo("##SurfaceColormap", statics.sel_colormap, colormaps)
250+
251+
imgui.unindent()
252+
253+
# Choose range
254+
if not hasattr(statics, "custom_range"):
255+
statics.custom_range = False
256+
if not hasattr(statics, "range_min"):
257+
statics.range_min = -1.0
258+
if not hasattr(statics, "range_max"):
259+
statics.range_max = 1.0
260+
_, statics.custom_range = imgui.checkbox("Custom range", statics.custom_range)
261+
imgui.indent()
262+
if not statics.custom_range:
263+
imgui.begin_disabled()
264+
_, statics.range_min = imgui.slider_float("Range min", statics.range_min, -1.0, statics.range_max - 0.01)
265+
_, statics.range_max = imgui.slider_float("Range max", statics.range_max, statics.range_min + 0.01, 1.0)
266+
if not statics.custom_range:
267+
imgui.end_disabled()
268+
imgui.unindent()
269+
270+
# Begin the plot
271+
if statics.selected_fill == 1:
272+
implot3d.push_colormap(colormaps[statics.sel_colormap])
273+
if implot3d.begin_plot("Surface Plots", ImVec2(-1, 400), implot3d.Flags_.no_clip.value):
274+
# Set styles
275+
implot3d.setup_axes_limits(-1, 1, -1, 1, -1.5, 1.5)
276+
implot3d.push_style_var(implot3d.StyleVar_.fill_alpha.value, 0.8)
277+
if statics.selected_fill == 0:
278+
implot3d.set_next_fill_style(statics.solid_color)
279+
implot3d.set_next_line_style(implot3d.get_colormap_color(1))
280+
281+
# Plot the surface
282+
if statics.custom_range:
283+
implot3d.plot_surface("Wave Surface", statics.xs, statics.ys, statics.zs, N, N, statics.range_min, statics.range_max)
284+
else:
285+
implot3d.plot_surface("Wave Surface", statics.xs, statics.ys, statics.zs, N, N)
286+
287+
# End the plot
288+
implot3d.pop_style_var()
289+
implot3d.end_plot()
290+
291+
if statics.selected_fill == 1:
292+
implot3d.pop_colormap()
293+
294+
295+
# =======================
296+
# Main demo function
297+
# =======================
173298
def demo_gui():
174299
imgui_md.render_unindented(
175300
"""
176-
# ImPlot
177-
[Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
301+
# ImPlot & ImPlot3D
302+
* [Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
303+
* [Implot3D](https://github.com/brenocq/implot3d) provides immediate Mode 3D Plotting, with an API inspired from ImPlot.
304+
178305
You can see lots of demos together with their code [online](https://traineq.org/implot_demo/src/implot_demo.html)
179306
"""
180307
)
@@ -184,16 +311,22 @@ def demo_gui():
184311
webbrowser.open("https://traineq.org/implot_demo/src/implot_demo.html")
185312
imgui.new_line()
186313

187-
if imgui.collapsing_header("Drag Rects"):
314+
if imgui.collapsing_header("ImPlot: Drag Rects"):
188315
demo_drag_rects()
189-
if imgui.collapsing_header("Mixed plot##2", imgui.TreeNodeFlags_.default_open.value):
316+
if imgui.collapsing_header("ImPlot: Mixed plot##2"):
190317
demo_mixed_plot()
191-
if imgui.collapsing_header("Heatmap"):
318+
if imgui.collapsing_header("ImPlot: Heatmap"):
192319
demo_heatmap()
193320

321+
if imgui.collapsing_header("ImPlot3D: Line plots ##2"):
322+
demo3d_lineplots()
323+
if imgui.collapsing_header("ImPlot3D: Surface Plots##2"):
324+
demo3d_surfaceplots()
325+
326+
194327

195328
def main():
196-
immapp.run(demo_gui, with_implot=True, with_markdown=True, window_size=(1000, 800))
329+
immapp.run(demo_gui, with_implot=True, with_implot3d=True, with_markdown=True, window_size=(1000, 800))
197330

198331

199332
if __name__ == "__main__":

0 commit comments

Comments
 (0)