Skip to content

Imgui stats #771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions examples/scatter/spinning_spiral.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
Spinning spiral scatter
=======================

Example of a spinning spiral scatter
Example of a spinning spiral scatter.

This example with 1 million points runs at 125 fps on an AMD RX 570.
"""

# test_example = false
# sphinx_gallery_pygfx_docs = 'animate 10s'
# sphinx_gallery_pygfx_docs = 'animate 15s'

import numpy as np
import fastplotlib as fpl
Expand All @@ -23,16 +25,32 @@

data = np.column_stack([xs, ys, zs])

figure = fpl.Figure(cameras="3d", size=(700, 560))
# generate some random sizes for the points
sizes = np.abs(np.random.normal(loc=0, scale=1, size=n))

figure = fpl.Figure(
cameras="3d",
size=(700, 560),
canvas_kwargs={"max_fps": 500, "vsync": False}
)

spiral = figure[0, 0].add_scatter(data, cmap="viridis_r", alpha=0.8)
spiral = figure[0, 0].add_scatter(data, cmap="viridis_r", alpha=0.5, sizes=sizes)

# pre-generate normally distributed data to jitter the points before each render
jitter = np.random.normal(scale=0.001, size=n * 3).reshape((n, 3))


def update():
# rotate around y axis
spiral.rotate(0.005, axis="y")

# add small jitter
spiral.data[:] += np.random.normal(scale=0.01, size=n * 3).reshape((n, 3))
spiral.data[:] += jitter
# shift array to provide a random-sampling effect
# without re-running a random generator on each iteration
# generating 1 million normally distributed points takes ~50ms even with SFC64
jitter[1000:] = jitter[:-1000]
jitter[:1000] = jitter[-1000:]


figure.add_animations(update)
Expand All @@ -51,10 +69,16 @@ def update():
'maintain_aspect': True,
'depth_range': None
}

figure[0, 0].camera.set_state(camera_state)
figure[0, 0].axes.visible = False


if fpl.IMGUI:
# show fps with imgui overlay
figure.imgui_show_fps = True


# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively
# please see our docs for using fastplotlib interactively in ipython and jupyter
if __name__ == "__main__":
Expand Down
12 changes: 11 additions & 1 deletion fastplotlib/layouts/_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(
controllers: pygfx.Controller | Iterable[Iterable[pygfx.Controller]] = None,
canvas: str | BaseRenderCanvas | pygfx.Texture = None,
renderer: pygfx.WgpuRenderer = None,
canvas_kwargs: dict = None,
size: tuple[int, int] = (500, 300),
names: list | np.ndarray = None,
):
Expand Down Expand Up @@ -111,6 +112,9 @@ def __init__(
renderer: pygfx.Renderer, optional
pygfx renderer instance

canvas_kwargs: dict, optional
kwargs to pass to the canvas

size: (int, int), optional
starting size of canvas in absolute pixels, default (500, 300)

Expand Down Expand Up @@ -163,8 +167,14 @@ def __init__(
else:
subplot_names = None

if canvas_kwargs is not None:
if size not in canvas_kwargs.keys():
canvas_kwargs["size"] = size
else:
canvas_kwargs = {"size": size, "max_fps": 60.0, "vsync": True}

canvas, renderer = make_canvas_and_renderer(
canvas, renderer, canvas_kwargs={"size": size}
canvas, renderer, canvas_kwargs=canvas_kwargs
)

canvas.add_event_handler(self._fpl_reset_layout, "resize")
Expand Down
25 changes: 15 additions & 10 deletions fastplotlib/layouts/_imgui_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
import imgui_bundle
from imgui_bundle import imgui, icons_fontawesome_6 as fa

from wgpu.utils.imgui import ImguiRenderer
from wgpu.utils.imgui import ImguiRenderer, Stats
from rendercanvas import BaseRenderCanvas

import pygfx

from ._figure import Figure
from ._utils import make_canvas_and_renderer
from ..ui import EdgeWindow, SubplotToolbar, StandardRightClickMenu, Popup, GUI_EDGES
from ..ui import ColormapPicker

Expand All @@ -21,8 +20,8 @@ class ImguiFigure(Figure):
def __init__(
self,
shape: tuple[int, int] = (1, 1),
rects=None,
extents=None,
rects: list[tuple | np.ndarray] = None,
extents: list[tuple | np.ndarray] = None,
cameras: (
Literal["2d", "3d"]
| Iterable[Iterable[Literal["2d", "3d"]]]
Expand All @@ -42,16 +41,12 @@ def __init__(
controllers: pygfx.Controller | Iterable[Iterable[pygfx.Controller]] = None,
canvas: str | BaseRenderCanvas | pygfx.Texture = None,
renderer: pygfx.WgpuRenderer = None,
canvas_kwargs: dict = None,
size: tuple[int, int] = (500, 300),
names: list | np.ndarray = None,
):
self._guis: dict[str, EdgeWindow] = {k: None for k in GUI_EDGES}

canvas, renderer = make_canvas_and_renderer(
canvas, renderer, canvas_kwargs={"size": size}
)
self._imgui_renderer = ImguiRenderer(renderer.device, canvas)

super().__init__(
shape=shape,
rects=rects,
Expand All @@ -62,10 +57,13 @@ def __init__(
controllers=controllers,
canvas=canvas,
renderer=renderer,
canvas_kwargs=canvas_kwargs,
size=size,
names=names,
)

self._imgui_renderer = ImguiRenderer(self.renderer.device, self.canvas)

fronts_path = str(
Path(imgui_bundle.__file__).parent.joinpath(
"assets", "fonts", "Font_Awesome_6_Free-Solid-900.otf"
Expand Down Expand Up @@ -97,6 +95,9 @@ def __init__(

self._popups: dict[str, Popup] = {}

self.imgui_show_fps = False
self._stats = Stats(self.renderer.device, self.canvas)

self.register_popup(ColormapPicker)

@property
Expand All @@ -110,7 +111,11 @@ def imgui_renderer(self) -> ImguiRenderer:
return self._imgui_renderer

def _render(self, draw=False):
super()._render(draw)
if self.imgui_show_fps:
with self._stats:
super()._render(draw)
else:
super()._render(draw)

self.imgui_renderer.render()

Expand Down
4 changes: 2 additions & 2 deletions fastplotlib/layouts/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ def make_canvas_and_renderer(
"""

if canvas is None:
canvas = RenderCanvas(max_fps=60, **canvas_kwargs)
canvas = RenderCanvas(**canvas_kwargs)
elif isinstance(canvas, str):
import rendercanvas

m = importlib.import_module("rendercanvas." + canvas)
canvas = m.RenderCanvas(max_fps=60, **canvas_kwargs)
canvas = m.RenderCanvas(**canvas_kwargs)
elif not isinstance(canvas, (BaseRenderCanvas, Texture)):
raise TypeError(
f"canvas option must either be a valid BaseRenderCanvas implementation, a pygfx Texture"
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

install_requires = [
"numpy>=1.23.0",
"pygfx>=0.7.0",
"wgpu>=0.18.1",
"pygfx>=0.8.0",
"wgpu>=0.20.0",
"cmap>=0.1.3",
]

Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy