-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Demo immapp: Add Haiku Butterfly (using ImPlot3d)
- Loading branch information
Showing
4 changed files
with
244 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
bindings/imgui_bundle/demos_cpp/demos_immapp/haiku_butterfly.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// Lorenz Attractor & Butterfly Effect | ||
// This example demonstrates the Lorenz Attractor and the butterfly effect, | ||
// showing how tiny changes in initial conditions lead to diverging trajectories. | ||
|
||
#include "imgui.h" | ||
#include "implot3d/implot3d.h" | ||
#include "immapp/runner.h" | ||
#include "imgui_md_wrapper/imgui_md_wrapper.h" | ||
#include <vector> | ||
|
||
struct LorenzParams { | ||
float sigma = 10.0f; | ||
float rho = 28.0f; | ||
float beta = 8.0f / 3.0f; | ||
float dt = 0.01f; | ||
int max_size = 2000; | ||
} PARAMS; | ||
|
||
|
||
class AnimatedLorenzTrajectory { | ||
public: | ||
AnimatedLorenzTrajectory(float x, float y, float z) : xs({x}), ys({y}), zs({z}) {} | ||
|
||
void step() { | ||
float x = xs.back(), y = ys.back(), z = zs.back(); | ||
float dx = PARAMS.sigma * (y - x); | ||
float dy = x * (PARAMS.rho - z) - y; | ||
float dz = x * y - PARAMS.beta * z; | ||
x += dx * PARAMS.dt; | ||
y += dy * PARAMS.dt; | ||
z += dz * PARAMS.dt; | ||
|
||
xs.push_back(x); | ||
ys.push_back(y); | ||
zs.push_back(z); | ||
|
||
if (xs.size() > static_cast<size_t>(PARAMS.max_size)) { | ||
xs.erase(xs.begin()); | ||
ys.erase(ys.begin()); | ||
zs.erase(zs.begin()); | ||
} | ||
} | ||
std::vector<float> xs, ys, zs; | ||
}; | ||
|
||
class CompareLorenzTrajectories | ||
{ | ||
public: | ||
float initial_delta = 0.1f; | ||
|
||
CompareLorenzTrajectories() { init_trajectories(); } | ||
|
||
void init_trajectories() { | ||
traj1 = std::make_unique<AnimatedLorenzTrajectory>(0.0f, 1.0f, 1.05f); | ||
traj2 = std::make_unique<AnimatedLorenzTrajectory>(0.0f + initial_delta, 1.0f, 1.05f); | ||
} | ||
|
||
void gui_params() { | ||
ImGui::SliderFloat("Sigma", &PARAMS.sigma, 0.0f, 100.0f); | ||
ImGui::SetItemTooltip("Controls the rate of divergence between nearby points (chaos level)."); | ||
|
||
ImGui::SliderFloat("Rho", &PARAMS.rho, 0.0f, 100.0f); | ||
ImGui::SetItemTooltip("Determines the size and shape of the attractor."); | ||
|
||
ImGui::SliderFloat("Beta", &PARAMS.beta, 0.0f, 10.0f); | ||
ImGui::SetItemTooltip("A damping parameter affecting vertical movement."); | ||
|
||
ImGui::SliderFloat("dt", &PARAMS.dt, 0.0f, 0.05f); | ||
ImGui::SetItemTooltip("Time step size for numerical integration (smaller is smoother)."); | ||
|
||
ImGui::SliderFloat("Initial Delta", &initial_delta, 0.0f, 0.2f); | ||
ImGui::SetItemTooltip("Initial difference between trajectories to demonstrate divergence."); | ||
|
||
if (ImGui::Button("Reset")) { | ||
init_trajectories(); | ||
} | ||
} | ||
|
||
void gui_plot() { | ||
if (ImPlot3D::BeginPlot("Lorenz Attractor", HelloImGui::EmToVec2(40, 40))) { | ||
ImPlot3D::SetupAxes("X", "Y", "Z", | ||
ImPlot3DAxisFlags_AutoFit, | ||
ImPlot3DAxisFlags_AutoFit, | ||
ImPlot3DAxisFlags_AutoFit); | ||
ImPlot3D::PlotLine( | ||
"Trajectory", traj1->xs.data(), traj1->ys.data(), traj1->zs.data(), traj1->xs.size()); | ||
ImPlot3D::PlotLine("Trajectory2", traj2->xs.data(), traj2->ys.data(), traj2->zs.data(), traj2->xs.size()); | ||
ImPlot3D::EndPlot(); | ||
} | ||
traj1->step(); | ||
traj2->step(); | ||
} | ||
|
||
void gui() { | ||
ImGuiMd::RenderUnindented(R"( | ||
# Lorenz Attractor & Butterfly Effect | ||
This is a simple example of the Lorenz Attractor. It shows two trajectories that diverge | ||
because of a small initial difference, illustrating chaos theory in action. | ||
The term **butterfly effect** in popular media may stem from the real-world implications | ||
of the Lorenz attractor, namely that tiny changes in initial conditions evolve to | ||
completely different trajectories.)"); | ||
ImGui::SeparatorText("Parameters"); | ||
gui_params(); | ||
ImGui::SeparatorText("Plot"); | ||
gui_plot(); | ||
} | ||
|
||
private: | ||
std::unique_ptr<AnimatedLorenzTrajectory> traj1, traj2; | ||
}; | ||
|
||
int main() { | ||
CompareLorenzTrajectories lorenz_comparer; | ||
ImmApp::AddOnsParams addOnsParams; | ||
addOnsParams.withImplot3d = true; | ||
addOnsParams.withMarkdown = true; | ||
|
||
HelloImGui::RunnerParams runnerParams; | ||
runnerParams.fpsIdling.enableIdling = false; | ||
runnerParams.appWindowParams.windowGeometry.sizeAuto = true; | ||
runnerParams.appWindowParams.windowTitle = "Butterfly Effect"; | ||
runnerParams.callbacks.ShowGui = [&]() { lorenz_comparer.gui(); }; | ||
|
||
ImmApp::Run(runnerParams, addOnsParams); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
bindings/imgui_bundle/demos_python/demos_immapp/haiku_butterfly.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
"""# Lorenz Attractor & Butterfly Effect | ||
This is a simple example of the Lorenz Attractor. It shows two trajectories that diverge | ||
because of a small initial difference, illustrating chaos theory in action. | ||
The term **butterfly effect** in popular media may stem from the real-world implications | ||
of the Lorenz attractor, namely that tiny changes in initial conditions evolve to | ||
completely different trajectories. | ||
""" | ||
# TODO: HANDLE NEWLINES IN MARKDOWN AS SPACE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
|
||
import numpy as np | ||
from imgui_bundle import implot3d, immapp, imgui, imgui_md, hello_imgui | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass | ||
class LorenzParams: | ||
sigma: float = 10.0 | ||
rho: float = 28.0 | ||
beta: float = 8.0 / 3.0 | ||
dt: float = 0.01 | ||
max_size: int = 2000 | ||
|
||
PARAMS = LorenzParams() | ||
|
||
|
||
class AnimatedLorenzTrajectory: | ||
def __init__(self, x, y, z): | ||
self.xs = np.array([x]) | ||
self.ys = np.array([y]) | ||
self.zs = np.array([z]) | ||
|
||
def step(self): | ||
x, y, z = self.xs[-1], self.ys[-1], self.zs[-1] | ||
dx = PARAMS.sigma * (y - x) | ||
dy = x * (PARAMS.rho - z) - y | ||
dz = x * y - PARAMS.beta * z | ||
x += dx * PARAMS.dt | ||
y += dy * PARAMS.dt | ||
z += dz * PARAMS.dt | ||
|
||
self.xs = np.concatenate([self.xs, [x]]) | ||
self.ys = np.concatenate([self.ys, [y]]) | ||
self.zs = np.concatenate([self.zs, [z]]) | ||
if len(self.xs) > PARAMS.max_size: | ||
self.xs = self.xs[-PARAMS.max_size:] | ||
self.ys = self.ys[-PARAMS.max_size:] | ||
self.zs = self.zs[-PARAMS.max_size:] | ||
|
||
|
||
class CompareLorenzTrajectories: | ||
initial_delta = 0.1 | ||
def __init__(self): | ||
self.init_trajectories() | ||
|
||
def init_trajectories(self): | ||
x, y, z = 0.0, 1.0, 1.05 | ||
self.traj1 = AnimatedLorenzTrajectory(x, y, z) | ||
self.traj2 = AnimatedLorenzTrajectory(x + self.initial_delta, y, z) | ||
|
||
def gui_params(self): | ||
_, PARAMS.sigma = imgui.slider_float("Sigma", PARAMS.sigma, 0.0, 100.0) | ||
imgui.set_item_tooltip("Controls the rate of divergence between nearby points (chaos level).") | ||
|
||
_, PARAMS.rho = imgui.slider_float("Rho", PARAMS.rho, 0.0, 100.0) | ||
imgui.set_item_tooltip("Determines the size and shape of the attractor.") | ||
|
||
_, PARAMS.beta = imgui.slider_float("Beta", PARAMS.beta, 0.0, 10.0) | ||
imgui.set_item_tooltip("A damping parameter affecting vertical movement.") | ||
|
||
_, PARAMS.dt = imgui.slider_float("dt", PARAMS.dt, 0.0, 0.05) | ||
imgui.set_item_tooltip("Time step size for numerical integration (smaller is smoother).") | ||
|
||
_, self.initial_delta = imgui.slider_float("Initial Delta", self.initial_delta, 0.0, 0.2) | ||
imgui.set_item_tooltip("Initial difference between trajectories to demonstrate divergence.") | ||
|
||
if imgui.button("Reset"): | ||
self.init_trajectories() | ||
|
||
def gui_plot(self): | ||
if implot3d.begin_plot("Lorenz Attractor", hello_imgui.em_to_vec2(40, 40)): | ||
implot3d.setup_axes("X", "Y", "Z", | ||
implot3d.AxisFlags_.auto_fit.value, implot3d.AxisFlags_.auto_fit.value, implot3d.AxisFlags_.auto_fit.value) | ||
implot3d.plot_line("Trajectory", self.traj1.xs, self.traj1.ys, self.traj1.zs) | ||
implot3d.plot_line("Trajectory2", self.traj2.xs, self.traj2.ys, self.traj2.zs) | ||
implot3d.end_plot() | ||
self.traj1.step() | ||
self.traj2.step() | ||
|
||
def gui(self): | ||
imgui_md.render_unindented(__doc__) | ||
imgui.separator_text("Parameters") | ||
self.gui_params() | ||
imgui.separator_text("Plot") | ||
self.gui_plot() | ||
|
||
|
||
lorenz_comparer = CompareLorenzTrajectories() | ||
|
||
immapp.run(lambda: lorenz_comparer.gui(), | ||
with_implot3d=True, | ||
with_markdown=True, | ||
window_size_auto=True, | ||
window_title="Butterfly Effect", | ||
fps_idle=0) |