33import math
44import numpy as np
55from 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+
913class 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+ # =======================
173298def 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
195328def 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
199332if __name__ == "__main__" :
0 commit comments