Skip to content

Commit af23b58

Browse files
authored
Improvements to GUI selection and Qt support (#431)
* Improved GUI selection wip * Support all modern qt libs * comment * make the ipywidgets imports conditional * Adjust for new wgpu * set min wgpu version * fixes * top might not necessarily the default
1 parent 60cf919 commit af23b58

File tree

18 files changed

+172
-253
lines changed

18 files changed

+172
-253
lines changed

docs/source/user_guide/gpu.rst

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,39 +33,18 @@ View available GPU
3333

3434
You can view all GPUs that are available to ``WGPU`` like this::
3535

36-
from wgpu.backends.wgpu_native import enumerate_adapters
37-
from pprint import pprint
36+
import wgpu
3837

39-
for adapter in enumerate_adapters():
40-
pprint(adapter.request_adapter_info())
38+
for adapter in wgpu.gpu.enumerate_adapters():
39+
print(adapter.summary)
4140

4241
For example, on a Thinkpad AMD laptop with a dedicated nvidia GPU this returns::
4342

44-
{'adapter_type': 'IntegratedGPU',
45-
'architecture': '',
46-
'backend_type': 'Vulkan',
47-
'description': 'Mesa 22.3.6',
48-
'device': 'AMD Radeon Graphics (RADV REMBRANDT)',
49-
'vendor': 'radv'}
50-
{'adapter_type': 'DiscreteGPU',
51-
'architecture': '',
52-
'backend_type': 'Vulkan',
53-
'description': '535.129.03',
54-
'device': 'NVIDIA T1200 Laptop GPU',
55-
'vendor': 'NVIDIA'}
56-
{'adapter_type': 'CPU',
57-
'architecture': '',
58-
'backend_type': 'Vulkan',
59-
'description': 'Mesa 22.3.6 (LLVM 15.0.6)',
60-
'device': 'llvmpipe (LLVM 15.0.6, 256 bits)',
61-
'vendor': 'llvmpipe'}
62-
{'adapter_type': 'Unknown',
63-
'architecture': '',
64-
'backend_type': 'OpenGL',
65-
'description': '',
66-
'device': 'AMD Radeon Graphics (rembrandt, LLVM 15.0.6, DRM 3.52, '
67-
'6.4.0-0.deb12.2-amd64)',
68-
'vendor': ''}
43+
AMD Radeon Graphics (RADV REMBRANDT) (IntegratedGPU) on Vulkan
44+
NVIDIA T1200 Laptop GPU (DiscreteGPU) on Vulkan
45+
llvmpipe (LLVM 15.0.6, 256 bits) (CPU) on Vulkan
46+
AMD Radeon Graphics (rembrandt, LLVM 15.0.6, DRM 3.52, 6.4.0-0.deb12.2-amd64) (Unknown) on OpenGL
47+
6948

7049
GPU currently in use
7150
--------------------
@@ -78,5 +57,5 @@ If you want to know the GPU that a current plot is using you can check the adapt
7857
plot.show()
7958

8059
# GPU that is currently in use by the renderer
81-
plot.renderer.device.adapter.request_adapter_info()
60+
print(plot.renderer.device.adapter.summary)
8261

fastplotlib/__init__.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,20 @@
55
from .graphics.selectors import *
66
from .legends import *
77
from .widgets import ImageWidget
8-
from .utils import _notebook_print_banner, config
8+
from .utils import config
9+
from .utils.gui import run
910

10-
from wgpu.gui.auto import run
11-
from wgpu.backends.wgpu_native import enumerate_adapters
11+
import wgpu
1212

1313

1414
with open(Path(__file__).parent.joinpath("VERSION"), "r") as f:
1515
__version__ = f.read().split("\n")[0]
1616

17-
adapters = [a.request_adapter_info() for a in enumerate_adapters()]
17+
adapters = [a.summary for a in wgpu.gpu.enumerate_adapters()]
1818

1919
if len(adapters) < 1:
2020
raise IndexError("No WGPU adapters found, fastplotlib will not work.")
2121

22-
_notebook_print_banner()
2322

2423
__all__ = [
2524
"Plot",

fastplotlib/graphics/selectors/_linear.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,19 @@
33
from numbers import Real
44

55
import numpy as np
6-
76
import pygfx
87

9-
try:
10-
import ipywidgets
11-
12-
HAS_IPYWIDGETS = True
13-
except (ImportError, ModuleNotFoundError):
14-
HAS_IPYWIDGETS = False
15-
8+
from ...utils.gui import IS_JUPYTER
169
from .._base import Graphic, GraphicCollection
1710
from .._features._selection_features import LinearSelectionFeature
1811
from ._base_selector import BaseSelector
1912

2013

14+
if IS_JUPYTER:
15+
# If using the jupyter backend, user has jupyter_rfb, and thus also ipywidgets
16+
import ipywidgets
17+
18+
2119
class LinearSelector(BaseSelector):
2220
@property
2321
def limits(self) -> Tuple[float, float]:
@@ -240,7 +238,7 @@ def make_ipywidget_slider(self, kind: str = "IntSlider", **kwargs):
240238
241239
"""
242240

243-
if not HAS_IPYWIDGETS:
241+
if not IS_JUPYTER:
244242
raise ImportError(
245243
"Must installed `ipywidgets` to use `make_ipywidget_slider()`"
246244
)

fastplotlib/graphics/selectors/_linear_region.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
from typing import *
22
from numbers import Real
33

4-
try:
5-
import ipywidgets
6-
7-
HAS_IPYWIDGETS = True
8-
except (ImportError, ModuleNotFoundError):
9-
HAS_IPYWIDGETS = False
10-
114
import numpy as np
12-
135
import pygfx
146

7+
from ...utils.gui import IS_JUPYTER
158
from .._base import Graphic, GraphicCollection
16-
from ._base_selector import BaseSelector
179
from .._features._selection_features import LinearRegionSelectionFeature
10+
from ._base_selector import BaseSelector
11+
12+
13+
if IS_JUPYTER:
14+
# If using the jupyter backend, user has jupyter_rfb, and thus also ipywidgets
15+
import ipywidgets
1816

1917

2018
class LinearRegionSelector(BaseSelector):
@@ -390,7 +388,7 @@ def make_ipywidget_slider(self, kind: str = "IntRangeSlider", **kwargs):
390388
391389
"""
392390

393-
if not HAS_IPYWIDGETS:
391+
if not IS_JUPYTER:
394392
raise ImportError(
395393
"Must installed `ipywidgets` to use `make_ipywidget_slider()`"
396394
)

fastplotlib/layouts/_frame/_frame.py

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,7 @@
11
import os
22

3-
from ._toolbar import ToolBar
4-
53
from ...graphics import ImageGraphic
6-
7-
from .._utils import CANVAS_OPTIONS_AVAILABLE
8-
9-
10-
class UnavailableOutputContext:
11-
# called when a requested output context is not available
12-
# ex: if trying to force jupyter_rfb canvas but jupyter_rfb is not installed
13-
def __init__(self, context_name, msg):
14-
self.context_name = context_name
15-
self.msg = msg
16-
17-
def __call__(self, *args, **kwargs):
18-
raise ModuleNotFoundError(
19-
f"The following output context is not available: {self.context_name}\n{self.msg}"
20-
)
21-
22-
23-
# TODO: potentially put all output context and toolbars in their own module and have this determination done at import
24-
if CANVAS_OPTIONS_AVAILABLE["jupyter"]:
25-
from ._jupyter_output import JupyterOutputContext
26-
else:
27-
JupyterOutputContext = UnavailableOutputContext(
28-
"Jupyter",
29-
"You must install fastplotlib using the `'notebook'` option to use this context:\n"
30-
'pip install "fastplotlib[notebook]"',
31-
)
32-
33-
if CANVAS_OPTIONS_AVAILABLE["qt"]:
34-
from ._qt_output import QOutputContext
35-
else:
36-
QtOutput = UnavailableOutputContext(
37-
"Qt", "You must install `PyQt6` to use this output context"
38-
)
4+
from ._toolbar import ToolBar
395

406

417
class Frame:
@@ -158,6 +124,8 @@ def show(
158124

159125
# return the appropriate OutputContext based on the current canvas
160126
if self.canvas.__class__.__name__ == "JupyterWgpuCanvas":
127+
from ._jupyter_output import JupyterOutputContext # noqa - inline import
128+
161129
self._output = JupyterOutputContext(
162130
frame=self,
163131
make_toolbar=toolbar,
@@ -167,6 +135,8 @@ def show(
167135
)
168136

169137
elif self.canvas.__class__.__name__ == "QWgpuCanvas":
138+
from ._qt_output import QOutputContext # noqa - inline import
139+
170140
self._output = QOutputContext(
171141
frame=self, make_toolbar=toolbar, add_widgets=add_widgets
172142
)

fastplotlib/layouts/_frame/_qt_output.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
from PyQt6 import QtWidgets
2-
1+
from ...utils.gui import QtWidgets
32
from ._qt_toolbar import QToolbar
43

54

fastplotlib/layouts/_frame/_qt_toolbar.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
import traceback
55
from typing import *
66

7-
from PyQt6 import QtWidgets, QtCore
8-
7+
from ...utils.gui import QtCore, QtWidgets
98
from ...graphics.selectors import PolygonSelector
109
from ._toolbar import ToolBar
1110
from ._qtoolbar_template import Ui_QToolbar

fastplotlib/layouts/_frame/_qtoolbar_template.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
66
# run again. Do not edit this file unless you know what you are doing.
77

8-
9-
from PyQt6 import QtCore, QtGui, QtWidgets
8+
from ...utils.gui import QtGui, QtCore, QtWidgets
109

1110

1211
class Ui_QToolbar(object):
@@ -30,7 +29,7 @@ def setupUi(self, QToolbar):
3029
self.maintain_aspect_button = QtWidgets.QPushButton(parent=QToolbar)
3130
font = QtGui.QFont()
3231
font.setBold(True)
33-
font.setWeight(75)
32+
font.setWeight(QtGui.QFont.Weight.Bold)
3433
self.maintain_aspect_button.setFont(font)
3534
self.maintain_aspect_button.setCheckable(True)
3635
self.maintain_aspect_button.setObjectName("maintain_aspect_button")

fastplotlib/layouts/_gridplot.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import pygfx
88

9-
from wgpu.gui.auto import WgpuCanvas
9+
from wgpu.gui import WgpuCanvasBase
1010

1111
from ._frame import Frame
1212
from ._utils import make_canvas_and_renderer, create_controller, create_camera
@@ -22,7 +22,7 @@ def __init__(
2222
cameras: Union[str, list, np.ndarray] = "2d",
2323
controller_types: Union[str, list, np.ndarray] = None,
2424
controller_ids: Union[str, list, np.ndarray] = None,
25-
canvas: Union[str, WgpuCanvas, pygfx.Texture] = None,
25+
canvas: Union[str, WgpuCanvasBase, pygfx.Texture] = None,
2626
renderer: pygfx.WgpuRenderer = None,
2727
size: Tuple[int, int] = (500, 300),
2828
names: Union[list, np.ndarray] = None,
@@ -219,12 +219,6 @@ def __init__(
219219
for cam in cams[1:]:
220220
_controller.add_camera(cam)
221221

222-
if canvas is None:
223-
canvas = WgpuCanvas()
224-
225-
if renderer is None:
226-
renderer = pygfx.renderers.WgpuRenderer(canvas)
227-
228222
self._canvas = canvas
229223
self._renderer = renderer
230224

@@ -266,7 +260,7 @@ def __init__(
266260
Frame.__init__(self)
267261

268262
@property
269-
def canvas(self) -> WgpuCanvas:
263+
def canvas(self) -> WgpuCanvasBase:
270264
"""The canvas associated to this GridPlot"""
271265
return self._canvas
272266

fastplotlib/layouts/_plot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import *
22

33
import pygfx
4-
from wgpu.gui.auto import WgpuCanvas
4+
from wgpu.gui import WgpuCanvasBase
55

66
from ._subplot import Subplot
77
from ._frame import Frame
@@ -11,7 +11,7 @@
1111
class Plot(Subplot, Frame, RecordMixin):
1212
def __init__(
1313
self,
14-
canvas: Union[str, WgpuCanvas] = None,
14+
canvas: Union[str, WgpuCanvasBase] = None,
1515
renderer: pygfx.WgpuRenderer = None,
1616
camera: Union[str, pygfx.PerspectiveCamera] = "2d",
1717
controller: Union[str, pygfx.Controller] = None,

0 commit comments

Comments
 (0)