-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add imgui_fig: display matplotlib figures
- Loading branch information
Showing
5 changed files
with
170 additions
and
0 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
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
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
78 changes: 78 additions & 0 deletions
78
bindings/imgui_bundle/demos_python/demos_immapp/demo_matplotlib.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,78 @@ | ||
import matplotlib | ||
# Important: before importing pyplot, set the renderer to Tk, | ||
# so that the figure is not displayed on the screen before we can capture it. | ||
matplotlib.use('Agg') # | ||
import matplotlib.pyplot as plt | ||
from imgui_bundle import immapp, imgui, imgui_fig, imgui_ctx | ||
import numpy as np | ||
|
||
|
||
class AnimatedFigure: | ||
"""A class that encapsulates a Matplotlib figure, and provides a method to animate it.""" | ||
x: np.ndarray | ||
y: np.ndarray | ||
amplitude: float = 1.0 | ||
plotted_curve: matplotlib.lines.Line2D | ||
phase: float | ||
fig: matplotlib.figure.Figure | ||
ax: matplotlib.axes.Axes | ||
|
||
def __init__(self): | ||
# Data for plotting | ||
self.phase = 0.0 | ||
self.x = np.arange(0.0, 2.0, 0.01) | ||
self.y = 1 + np.sin(2 * np.pi * self.x + self.phase) * self.amplitude | ||
|
||
# Create a figure and a set of subplots | ||
self.fig, self.ax = plt.subplots() | ||
|
||
# Plot the data | ||
self.plotted_curve, = self.ax.plot(self.x, self.y) | ||
|
||
# Add labels and title | ||
self.ax.set(xlabel='time (s)', ylabel='voltage (mV)', | ||
title='Simple Plot: Voltage vs. Time') | ||
|
||
# Add a grid | ||
self.ax.grid() | ||
|
||
def animate(self): | ||
self.phase += 0.1 | ||
self.y = 1 + np.sin(2 * np.pi * self.x + self.phase) * self.amplitude | ||
self.plotted_curve.set_ydata(self.y) | ||
|
||
|
||
def main(): | ||
# Create an animated figure | ||
animated_figure = AnimatedFigure() | ||
|
||
# Create a static figure | ||
x = np.linspace(-2 * np.pi, 2 * np.pi, 100) | ||
y = np.sin(x) * np.exp(-x ** 2 / 20) | ||
static_fig, static_ax = plt.subplots() | ||
static_ax.plot(x, y) | ||
|
||
def gui(): | ||
# Show an animated figure | ||
with imgui_ctx.begin_group(): | ||
animated_figure.animate() | ||
imgui_fig.fig("Animated figure", animated_figure.fig, refresh_image=True, show_options_button=False) | ||
imgui.set_next_item_width(immapp.em_size(20)) | ||
_, animated_figure.amplitude = imgui.slider_float("amplitude", animated_figure.amplitude, 0.1, 2.0) | ||
|
||
imgui.same_line() | ||
|
||
# Show a static figure | ||
imgui_fig.fig("Static figure", static_fig) | ||
|
||
|
||
runner_params = immapp.RunnerParams() | ||
runner_params.fps_idling.fps_idle = 0 # disable idling, so that the animation is fast | ||
runner_params.app_window_params.window_geometry.size = (1400, 600) | ||
runner_params.app_window_params.window_title = "imgui_fig demo" | ||
runner_params.callbacks.show_gui = gui | ||
immapp.run(runner_params) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
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,83 @@ | ||
import matplotlib | ||
# Important: before importing pyplot, set the renderer to Tk, | ||
# so that the figure is not displayed on the screen before we can capture it. | ||
matplotlib.use('Agg') # | ||
import matplotlib.pyplot as plt | ||
|
||
import numpy | ||
import cv2 | ||
import matplotlib | ||
from imgui_bundle.immapp import static | ||
from imgui_bundle import immvision | ||
|
||
from typing import Tuple | ||
# from numpy.typing import ArrayLike | ||
|
||
|
||
""" | ||
Display Matplotlib figures in an ImGui window. | ||
""" | ||
|
||
|
||
Size = Tuple[int, int] | ||
Point2d = Tuple[float, float] | ||
|
||
|
||
@static(fig_cache=dict()) | ||
def _fig_to_image(figure: matplotlib.figure.Figure, refresh_image: bool = False) -> numpy.ndarray: | ||
""" | ||
Convert a Matplotlib figure to an RGB image. | ||
Parameters: | ||
- figure (matplotlib.figure.Figure): The Matplotlib figure to convert. | ||
Returns: | ||
- numpy.ndarray: An RGB image as a NumPy array with uint8 datatype. | ||
""" | ||
statics = _fig_to_image | ||
fig_id = id(figure) | ||
if refresh_image and fig_id in statics.fig_cache: | ||
del statics.fig_cache[fig_id] | ||
if fig_id not in statics.fig_cache: | ||
# draw the renderer | ||
figure.canvas.draw() | ||
# Get the RGBA buffer from the figure | ||
w, h = figure.canvas.get_width_height() | ||
buf = numpy.fromstring(figure.canvas.tostring_rgb(), dtype=numpy.uint8) | ||
buf.shape = (h, w, 3) | ||
img_rgb = cv2.cvtColor(buf, cv2.COLOR_RGB2BGR) | ||
matplotlib.pyplot.close(figure) | ||
statics.fig_cache[fig_id] = img_rgb | ||
return statics.fig_cache[fig_id] | ||
|
||
|
||
def fig(label_id: str, | ||
figure: matplotlib.figure.Figure, | ||
image_display_size: Size = (0, 0), | ||
refresh_image: bool = False, | ||
show_options_button: bool = False) -> Point2d: | ||
""" | ||
Display a Matplotlib figure in an ImGui window. | ||
Parameters: | ||
- label_id (str): An identifier for the ImGui image widget. | ||
- figure (matplotlib.figure.Figure): The Matplotlib figure to display. | ||
- image_display_size (Size): Size of the displayed image (width, height). | ||
- refresh_image (bool): Flag to refresh the image. | ||
- show_options_button (bool): Flag to show additional options. | ||
Returns: | ||
- Point2d: The position of the mouse in the image display. | ||
Important: | ||
before importing pyplot, set the renderer to Tk, | ||
so that the figure is not displayed on the screen before we can capture it. | ||
```python | ||
import matplotlib | ||
matplotlib.use('Agg') | ||
import matplotlib.pyplot as plt | ||
``` | ||
""" | ||
image_rgb = _fig_to_image(figure, refresh_image) | ||
mouse_position = immvision.image_display(label_id, image_rgb, image_display_size, refresh_image, show_options_button) | ||
return mouse_position |