Skip to content

Commit 7686503

Browse files
authored
Merge pull request #5 from pygfx/docs
Add docs
2 parents 56794c6 + 5507a35 commit 7686503

File tree

8 files changed

+651
-0
lines changed

8 files changed

+651
-0
lines changed

docs/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = .
9+
BUILDDIR = _build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

docs/api.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
rendercanvas base classes
2+
=========================
3+
4+
.. autoclass:: rendercanvas.base.WgpuCanvasInterface
5+
:members:
6+
7+
.. autoclass:: rendercanvas.base.WgpuCanvasBase
8+
:members:
9+
10+
.. .. autoclass:: rendercanvas.base.WgpuLoop
11+
.. :members:
12+
13+
.. .. autoclass:: rendercanvas.base.WgpuTimer
14+
.. :members:

docs/conf.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# This file only contains a selection of the most common options. For a full
4+
# list see the documentation:
5+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
6+
7+
# -- Path setup --------------------------------------------------------------
8+
9+
# If extensions (or modules to document with autodoc) are in another directory,
10+
# add these directories to sys.path here. If the directory is relative to the
11+
# documentation root, use os.path.abspath to make it absolute, like shown here.
12+
13+
import os
14+
import sys
15+
import shutil
16+
17+
18+
ROOT_DIR = os.path.abspath(os.path.join(__file__, "..", ".."))
19+
sys.path.insert(0, ROOT_DIR)
20+
21+
os.environ["WGPU_FORCE_OFFSCREEN"] = "true"
22+
23+
24+
# Load wglibu so autodoc can query docstrings
25+
import rendercanvas # noqa: E402
26+
27+
28+
# -- Project information -----------------------------------------------------
29+
30+
project = "rendercanvas"
31+
copyright = "2020-2024, Almar Klein, Korijn van Golen"
32+
author = "Almar Klein, Korijn van Golen"
33+
release = rendercanvas.__version__
34+
35+
36+
# -- General configuration ---------------------------------------------------
37+
38+
# Add any Sphinx extension module names here, as strings. They can be
39+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40+
# ones.
41+
extensions = [
42+
"sphinx.ext.autodoc",
43+
"sphinx.ext.napoleon",
44+
"sphinx.ext.intersphinx",
45+
"sphinx_rtd_theme",
46+
]
47+
48+
intersphinx_mapping = {
49+
"python": ("https://docs.python.org/3", None),
50+
"numpy": ("https://numpy.org/doc/stable", None),
51+
"wgpu": ("https://wgpu-py.readthedocs.io/en/latest", None),
52+
}
53+
54+
# Add any paths that contain templates here, relative to this directory.
55+
templates_path = ["_templates"]
56+
57+
# List of patterns, relative to source directory, that match files and
58+
# directories to ignore when looking for source files.
59+
# This pattern also affects html_static_path and html_extra_path.
60+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
61+
62+
master_doc = "index"
63+
64+
65+
# -- Options for HTML output -------------------------------------------------
66+
67+
# The theme to use for HTML and HTML Help pages. See the documentation for
68+
# a list of builtin themes.
69+
70+
html_theme = "sphinx_rtd_theme"
71+
72+
# Add any paths that contain custom static files (such as style sheets) here,
73+
# relative to this directory. They are copied after the builtin static files,
74+
# so a file named "default.css" will overwrite the builtin "default.css".
75+
html_static_path = []

docs/gui.rst

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
gui API
2+
=======
3+
4+
.. currentmodule:: rendercanvas
5+
6+
You can use vanilla wgpu for compute tasks and to render offscreen. To
7+
render to a window on screen we need a *canvas*. Since the Python
8+
ecosystem provides many different GUI toolkits, rendercanvas implements a base
9+
canvas class, and has builtin support for a few GUI toolkits. At the
10+
moment these include GLFW, Jupyter, Qt, and wx.
11+
12+
13+
The Canvas base classes
14+
-----------------------
15+
16+
For each supported GUI toolkit there is a module that implements a ``WgpuCanvas`` class,
17+
which inherits from :class:`WgpuCanvasBase`, providing a common API.
18+
The GLFW, Qt, and Jupyter backends also inherit from :class:`WgpuAutoGui` to include
19+
support for events (interactivity). In the next sections we demonstrates the different
20+
canvas classes that you can use.
21+
22+
23+
The auto GUI backend
24+
--------------------
25+
26+
Generally the best approach for examples and small applications is to use the
27+
automatically selected GUI backend. This ensures that the code is portable
28+
across different machines and environments. Using ``rendercanvas.auto`` selects a
29+
suitable backend depending on the environment and more. See
30+
:ref:`interactive_use` for details.
31+
32+
To implement interaction, the ``canvas`` has a :func:`WgpuAutoGui.handle_event()` method
33+
that can be overloaded. Alternatively you can use it's :func:`WgpuAutoGui.add_event_handler()`
34+
method. See the `event spec <https://jupyter-rfb.readthedocs.io/en/stable/events.html>`_
35+
for details about the event objects.
36+
37+
38+
.. code-block:: py
39+
40+
from wgpu.gui.auto import WgpuCanvas, run, call_later
41+
42+
canvas = WgpuCanvas(title="Example")
43+
canvas.request_draw(your_draw_function)
44+
45+
run()
46+
47+
48+
Support for GLFW
49+
----------------
50+
51+
`GLFW <https://github.com/FlorianRhiem/pyGLFW>`_ is a lightweight windowing toolkit.
52+
Install it with ``pip install glfw``. The preferred approach is to use the auto backend,
53+
but you can replace ``from rendercanvas.auto`` with ``from rendercanvas.glfw`` to force using GLFW.
54+
55+
.. code-block:: py
56+
57+
from wgpu.gui.glfw import WgpuCanvas, run, call_later
58+
59+
canvas = WgpuCanvas(title="Example")
60+
canvas.request_draw(your_draw_function)
61+
62+
run()
63+
64+
65+
Support for Qt
66+
--------------
67+
68+
There is support for PyQt5, PyQt6, PySide2 and PySide6. The rendercanvas library detects what
69+
library you are using by looking what module has been imported.
70+
For a toplevel widget, the ``rendercanvas.qt.WgpuCanvas`` class can be imported. If you want to
71+
embed the canvas as a subwidget, use ``rendercanvas.qt.WgpuWidget`` instead.
72+
73+
Also see the `Qt triangle example <https://github.com/pygfx/wgpu-py/blob/main/examples/triangle_qt.py>`_
74+
and `Qt triangle embed example <https://github.com/pygfx/wgpu-py/blob/main/examples/triangle_qt_embed.py>`_.
75+
76+
.. code-block:: py
77+
78+
# Import any of the Qt libraries before importing the WgpuCanvas.
79+
# This way wgpu knows which Qt library to use.
80+
from PySide6 import QtWidgets
81+
from wgpu.gui.qt import WgpuCanvas
82+
83+
app = QtWidgets.QApplication([])
84+
85+
# Instantiate the canvas
86+
canvas = WgpuCanvas(title="Example")
87+
88+
# Tell the canvas what drawing function to call
89+
canvas.request_draw(your_draw_function)
90+
91+
app.exec_()
92+
93+
94+
Support for wx
95+
--------------
96+
97+
There is support for embedding a wgpu visualization in wxPython.
98+
For a toplevel widget, the ``gui.wx.WgpuCanvas`` class can be imported. If you want to
99+
embed the canvas as a subwidget, use ``gui.wx.WgpuWidget`` instead.
100+
101+
Also see the `wx triangle example <https://github.com/pygfx/wgpu-py/blob/main/examples/triangle_wx.py>`_
102+
and `wx triangle embed example <https://github.com/pygfx/wgpu-py/blob/main/examples/triangle_wx_embed.py>`_.
103+
104+
.. code-block:: py
105+
106+
import wx
107+
from wgpu.gui.wx import WgpuCanvas
108+
109+
app = wx.App()
110+
111+
# Instantiate the canvas
112+
canvas = WgpuCanvas(title="Example")
113+
114+
# Tell the canvas what drawing function to call
115+
canvas.request_draw(your_draw_function)
116+
117+
app.MainLoop()
118+
119+
120+
121+
Support for offscreen
122+
---------------------
123+
124+
You can also use a "fake" canvas to draw offscreen and get the result as a numpy array.
125+
Note that you can render to a texture without using any canvas
126+
object, but in some cases it's convenient to do so with a canvas-like API.
127+
128+
.. code-block:: py
129+
130+
from wgpu.gui.offscreen import WgpuCanvas
131+
132+
# Instantiate the canvas
133+
canvas = WgpuCanvas(size=(500, 400), pixel_ratio=1)
134+
135+
# ...
136+
137+
# Tell the canvas what drawing function to call
138+
canvas.request_draw(your_draw_function)
139+
140+
# Perform a draw
141+
array = canvas.draw() # numpy array with shape (400, 500, 4)
142+
143+
144+
Support for Jupyter lab and notebook
145+
------------------------------------
146+
147+
WGPU can be used in Jupyter lab and the Jupyter notebook. This canvas
148+
is based on `jupyter_rfb <https://github.com/vispy/jupyter_rfb>`_, an ipywidget
149+
subclass implementing a remote frame-buffer. There are also some `wgpu examples <https://jupyter-rfb.readthedocs.io/en/stable/examples/>`_.
150+
151+
.. code-block:: py
152+
153+
# from wgpu.gui.jupyter import WgpuCanvas # Direct approach
154+
from wgpu.gui.auto import WgpuCanvas # Approach compatible with desktop usage
155+
156+
canvas = WgpuCanvas()
157+
158+
# ... wgpu code
159+
160+
canvas # Use as cell output
161+
162+
163+
.. _interactive_use:
164+
165+
Using a canvas interactively
166+
----------------------------
167+
168+
The rendercanvas gui's are designed to support interactive use. Firstly, this is
169+
realized by automatically selecting the appropriate GUI backend. Secondly, the
170+
``run()`` function (which normally enters the event-loop) does nothing in an
171+
interactive session.
172+
173+
Many interactive environments have some sort of GUI support, allowing the repl
174+
to stay active (i.e. you can run new code), while the GUI windows is also alive.
175+
In rendercanvas we try to select the GUI that matches the current environment.
176+
177+
On ``jupyter notebook`` and ``jupyter lab`` the jupyter backend (i.e.
178+
``jupyter_rfb``) is normally selected. When you are using ``%gui qt``, rendercanvas will
179+
honor that and use Qt instead.
180+
181+
On ``jupyter console`` and ``qtconsole``, the kernel is the same as in ``jupyter notebook``,
182+
making it (about) impossible to tell that we cannot actually use
183+
ipywidgets. So it will try to use ``jupyter_rfb``, but cannot render anything.
184+
It's theefore advised to either use ``%gui qt`` or set the ``WGPU_GUI_BACKEND`` env var
185+
to "glfw". The latter option works well, because these kernels *do* have a
186+
running asyncio event loop!
187+
188+
On other environments that have a running ``asyncio`` loop, the glfw backend is
189+
preferred. E.g on ``ptpython --asyncio``.
190+
191+
On IPython (the old-school terminal app) it's advised to use ``%gui qt`` (or
192+
``--gui qt``). It seems not possible to have a running asyncio loop here.
193+
194+
On IDE's like Spyder or Pyzo, rendercanvas detects the integrated GUI, running on
195+
glfw if asyncio is enabled or Qt if a qt app is running.
196+
197+
On an interactive session without GUI support, one must call ``run()`` to make
198+
the canvases interactive. This enters the main loop, which prevents entering new
199+
code. Once all canvases are closed, the loop returns. If you make new canvases
200+
afterwards, you can call ``run()`` again. This is similar to ``plt.show()`` in Matplotlib.

0 commit comments

Comments
 (0)