Skip to content

Commit

Permalink
Work on demo_implot (3D part)
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Jan 2, 2025
1 parent fae8b66 commit 50ef945
Show file tree
Hide file tree
Showing 2 changed files with 284 additions and 11 deletions.
148 changes: 144 additions & 4 deletions bindings/imgui_bundle/demos_cpp/demo_implot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@
#include "implot/implot.h"
#include "immapp/immapp.h"
#include "demo_utils/api_demos.h"
#include "imgui_internal.h"

#ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
#include "implot3d/implot3d.h"
#endif

// =======================
// Demos for ImPlot (2D)
// =======================

void DemoMixedPlot()
{
Expand Down Expand Up @@ -96,22 +104,154 @@ static void DemoHeatmap()
}


// =======================
// Demos for ImPlot3D
// =======================

#ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
void Demo3D_LinePlots() {
static float xs1[1001], ys1[1001], zs1[1001];
for (int i = 0; i < 1001; i++) {
xs1[i] = i * 0.001f;
ys1[i] = 0.5f + 0.5f * cosf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
zs1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
}
static double xs2[20], ys2[20], zs2[20];
for (int i = 0; i < 20; i++) {
xs2[i] = i * 1 / 19.0f;
ys2[i] = xs2[i] * xs2[i];
zs2[i] = xs2[i] * ys2[i];
}
if (ImPlot3D::BeginPlot("Line Plots")) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle);
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, ImPlot3DLineFlags_Segments);
ImPlot3D::EndPlot();
}
}


void Demo3D_SurfacePlots() {
constexpr int N = 20;
static float xs[N * N], ys[N * N], zs[N * N];
static float t = 0.0f;
t += ImGui::GetIO().DeltaTime;

// Define the range for X and Y
constexpr float min_val = -1.0f;
constexpr float max_val = 1.0f;
constexpr float step = (max_val - min_val) / (N - 1);

// Populate the xs, ys, and zs arrays
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int idx = i * N + j;
xs[idx] = min_val + j * step; // X values are constant along rows
ys[idx] = min_val + i * step; // Y values are constant along columns
zs[idx] = ImSin(2 * t + ImSqrt((xs[idx] * xs[idx] + ys[idx] * ys[idx]))); // z = sin(2t + sqrt(x^2 + y^2))
}
}

// Choose fill color
ImGui::Text("Fill color");
static int selected_fill = 1; // Colormap by default
static ImVec4 solid_color = ImVec4(0.8f, 0.8f, 0.2f, 0.6f);
const char* colormaps[] = {"Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet",
"Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys"};
static int sel_colormap = 5; // Jet by default
{
ImGui::Indent();

// Choose solid color
ImGui::RadioButton("Solid", &selected_fill, 0);
if (selected_fill == 0) {
ImGui::SameLine();
ImGui::ColorEdit4("##SurfaceSolidColor", (float*)&solid_color);
}

// Choose colormap
ImGui::RadioButton("Colormap", &selected_fill, 1);
if (selected_fill == 1) {
ImGui::SameLine();
ImGui::Combo("##SurfaceColormap", &sel_colormap, colormaps, IM_ARRAYSIZE(colormaps));
}
ImGui::Unindent();
}

// Choose range
static bool custom_range = false;
static float range_min = -1.0f;
static float range_max = 1.0f;
ImGui::Checkbox("Custom range", &custom_range);
{
ImGui::Indent();

if (!custom_range)
ImGui::BeginDisabled();
ImGui::SliderFloat("Range min", &range_min, -1.0f, range_max - 0.01f);
ImGui::SliderFloat("Range max", &range_max, range_min + 0.01f, 1.0f);
if (!custom_range)
ImGui::EndDisabled();

ImGui::Unindent();
}

// Begin the plot
if (selected_fill == 1)
ImPlot3D::PushColormap(colormaps[sel_colormap]);
if (ImPlot3D::BeginPlot("Surface Plots", ImVec2(-1, 400), ImPlot3DFlags_NoClip)) {
// Set styles
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1.5, 1.5);
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.8f);
if (selected_fill == 0)
ImPlot3D::SetNextFillStyle(solid_color);
ImPlot3D::SetNextLineStyle(ImPlot3D::GetColormapColor(1));

// Plot the surface
if (custom_range)
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, (double)range_min, (double)range_max);
else
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N);

// End the plot
ImPlot3D::PopStyleVar();
ImPlot3D::EndPlot();
}
if (selected_fill == 1)
ImPlot3D::PopColormap();
}
#endif // #ifdef IMGUI_BUNDLE_WITH_IMPLOT3D


// =======================
// Main demo function
// =======================
void demo_implot()
{
ImGuiMd::RenderUnindented(R"(
# ImPlot
[Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
# ImPlot & ImPlot3D
* [Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
* [Implot3D](https://github.com/brenocq/implot3d) provides immediate Mode 3D Plotting, with an API inspired from ImPlot.
You can see lots of demos together with their code [online](https://traineq.org/implot_demo/src/implot_demo.html)
)");
if (ImGui::Button("View the full demo"))
{
BrowseToUrl("https://traineq.org/implot_demo/src/implot_demo.html");
}
ImGui::NewLine();
if (ImGui::CollapsingHeader("Mixed plot##2", ImGuiTreeNodeFlags_DefaultOpen))
if (ImGui::CollapsingHeader("ImPlot: Mixed plot##2", ImGuiTreeNodeFlags_DefaultOpen))
DemoMixedPlot();
if (ImGui::CollapsingHeader("Heatmap"))
if (ImGui::CollapsingHeader("ImPlot: Heatmap"))
DemoHeatmap();

#ifdef IMGUI_BUNDLE_WITH_IMPLOT3D
if (ImGui::CollapsingHeader("ImPlot3D: Line plots##2"))
Demo3D_LinePlots();
if (ImGui::CollapsingHeader("ImPlot3D: Surface Plots##2"))
Demo3D_SurfacePlots();
#endif
}

#else // IMGUI_BUNDLE_WITH_IMPLOT
Expand Down
147 changes: 140 additions & 7 deletions bindings/imgui_bundle/demos_python/demo_implot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import math
import numpy as np
from numpy.typing import NDArray
from imgui_bundle import imgui, implot, imgui_md, immapp, ImVec2, ImVec4
from imgui_bundle import imgui, implot, implot3d, imgui_md, immapp, ImVec2, ImVec4


# ========================
# Demos for ImPlot (2D)
# ========================

class DemoDragRectState:
x_data: NDArray[np.float64]
y_data1: NDArray[np.float64]
Expand Down Expand Up @@ -170,11 +174,134 @@ def demo_heatmap():
implot.pop_colormap()


# ========================
# Demos for ImPlot3D
# ========================
def demo3d_lineplots():
xs1 = np.linspace(0, 1, 1001)
ys1 = 0.5 + 0.5 * np.cos(50 * (xs1 + imgui.get_time() / 10))
zs1 = 0.5 + 0.5 * np.sin(50 * (xs1 + imgui.get_time() / 10))

xs2 = np.linspace(0, 1, 20)
ys2 = xs2 * xs2
zs2 = xs2 * ys2

if implot3d.begin_plot("Line Plots"):
implot3d.setup_axes("x", "y", "z")
implot3d.plot_line("f(x)", xs1, ys1, zs1)
implot3d.set_next_marker_style(implot3d.Marker_.circle.value)
implot3d.plot_line("g(x)", xs2, ys2, zs2, implot3d.LineFlags_.segments.value)
implot3d.end_plot()


def demo3d_surfaceplots():
statics = demo3d_surfaceplots
N = 20
if not hasattr(statics, "xs"):
statics.xs = np.zeros(N * N)
statics.ys = np.zeros(N * N)
statics.zs = np.zeros(N * N)
statics.t = 0.0

statics.t += imgui.get_io().delta_time

# Define the range for X and Y
min_val = -1.0
max_val = 1.0
step = (max_val - min_val) / (N - 1)

# Populate the xs, ys, and zs arrays
for i in range(N):
for j in range(N):
idx = i * N + j
statics.xs[idx] = min_val + j * step # X values are constant along rows
statics.ys[idx] = min_val + i * step # Y values are constant along columns
# z = sin(2t + sqrt(x^2 + y^2))
statics.zs[idx] = math.sin(2 * statics.t + math.sqrt(statics.xs[idx] * statics.xs[idx] + statics.ys[idx] * statics.ys[idx]))

# Choose fill color
imgui.text("Fill color")
if not hasattr(statics, "selected_fill"):
statics.selected_fill = 1 # Colormap by default
if not hasattr(statics, "solid_color"):
statics.solid_color = [0.8, 0.8, 0.2, 0.6]
colormaps = [
"Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet",
"Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys"
]
if not hasattr(statics, "sel_colormap"):
statics.sel_colormap = 5 # Jet by default

imgui.indent()

# Choose solid color
if imgui.radio_button("Solid", statics.selected_fill == 0):
statics.selected_fill = 0
if statics.selected_fill == 0:
imgui.same_line()
_, statics.solid_color = imgui.color_edit4("##SurfaceSolidColor", statics.solid_color)

# Choose colormap
if imgui.radio_button("Colormap", statics.selected_fill == 1):
statics.selected_fill = 1
if statics.selected_fill == 1:
imgui.same_line()
_, statics.sel_colormap = imgui.combo("##SurfaceColormap", statics.sel_colormap, colormaps)

imgui.unindent()

# Choose range
if not hasattr(statics, "custom_range"):
statics.custom_range = False
if not hasattr(statics, "range_min"):
statics.range_min = -1.0
if not hasattr(statics, "range_max"):
statics.range_max = 1.0
_, statics.custom_range = imgui.checkbox("Custom range", statics.custom_range)
imgui.indent()
if not statics.custom_range:
imgui.begin_disabled()
_, statics.range_min = imgui.slider_float("Range min", statics.range_min, -1.0, statics.range_max - 0.01)
_, statics.range_max = imgui.slider_float("Range max", statics.range_max, statics.range_min + 0.01, 1.0)
if not statics.custom_range:
imgui.end_disabled()
imgui.unindent()

# Begin the plot
if statics.selected_fill == 1:
implot3d.push_colormap(colormaps[statics.sel_colormap])
if implot3d.begin_plot("Surface Plots", ImVec2(-1, 400), implot3d.Flags_.no_clip.value):
# Set styles
implot3d.setup_axes_limits(-1, 1, -1, 1, -1.5, 1.5)
implot3d.push_style_var(implot3d.StyleVar_.fill_alpha.value, 0.8)
if statics.selected_fill == 0:
implot3d.set_next_fill_style(statics.solid_color)
implot3d.set_next_line_style(implot3d.get_colormap_color(1))

# Plot the surface
if statics.custom_range:
implot3d.plot_surface("Wave Surface", statics.xs, statics.ys, statics.zs, N, N, statics.range_min, statics.range_max)
else:
implot3d.plot_surface("Wave Surface", statics.xs, statics.ys, statics.zs, N, N)

# End the plot
implot3d.pop_style_var()
implot3d.end_plot()

if statics.selected_fill == 1:
implot3d.pop_colormap()


# =======================
# Main demo function
# =======================
def demo_gui():
imgui_md.render_unindented(
"""
# ImPlot
[Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
# ImPlot & ImPlot3D
* [Implot](https://github.com/epezent/implot) provides immediate Mode Plotting for ImGui.
* [Implot3D](https://github.com/brenocq/implot3d) provides immediate Mode 3D Plotting, with an API inspired from ImPlot.
You can see lots of demos together with their code [online](https://traineq.org/implot_demo/src/implot_demo.html)
"""
)
Expand All @@ -184,16 +311,22 @@ def demo_gui():
webbrowser.open("https://traineq.org/implot_demo/src/implot_demo.html")
imgui.new_line()

if imgui.collapsing_header("Drag Rects"):
if imgui.collapsing_header("ImPlot: Drag Rects"):
demo_drag_rects()
if imgui.collapsing_header("Mixed plot##2", imgui.TreeNodeFlags_.default_open.value):
if imgui.collapsing_header("ImPlot: Mixed plot##2"):
demo_mixed_plot()
if imgui.collapsing_header("Heatmap"):
if imgui.collapsing_header("ImPlot: Heatmap"):
demo_heatmap()

if imgui.collapsing_header("ImPlot3D: Line plots ##2"):
demo3d_lineplots()
if imgui.collapsing_header("ImPlot3D: Surface Plots##2"):
demo3d_surfaceplots()



def main():
immapp.run(demo_gui, with_implot=True, with_markdown=True, window_size=(1000, 800))
immapp.run(demo_gui, with_implot=True, with_implot3d=True, with_markdown=True, window_size=(1000, 800))


if __name__ == "__main__":
Expand Down

0 comments on commit 50ef945

Please sign in to comment.