Skip to content
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

Improvements to GUI selection and Qt support #431

Merged
merged 9 commits into from
Mar 31, 2024
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
39 changes: 9 additions & 30 deletions docs/source/user_guide/gpu.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,39 +33,18 @@ View available GPU

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

from wgpu.backends.wgpu_native import enumerate_adapters
from pprint import pprint
import wgpu

for adapter in enumerate_adapters():
pprint(adapter.request_adapter_info())
for adapter in wgpu.gpu.enumerate_adapters():
print(adapter.summary)

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

{'adapter_type': 'IntegratedGPU',
'architecture': '',
'backend_type': 'Vulkan',
'description': 'Mesa 22.3.6',
'device': 'AMD Radeon Graphics (RADV REMBRANDT)',
'vendor': 'radv'}
{'adapter_type': 'DiscreteGPU',
'architecture': '',
'backend_type': 'Vulkan',
'description': '535.129.03',
'device': 'NVIDIA T1200 Laptop GPU',
'vendor': 'NVIDIA'}
{'adapter_type': 'CPU',
'architecture': '',
'backend_type': 'Vulkan',
'description': 'Mesa 22.3.6 (LLVM 15.0.6)',
'device': 'llvmpipe (LLVM 15.0.6, 256 bits)',
'vendor': 'llvmpipe'}
{'adapter_type': 'Unknown',
'architecture': '',
'backend_type': 'OpenGL',
'description': '',
'device': 'AMD Radeon Graphics (rembrandt, LLVM 15.0.6, DRM 3.52, '
'6.4.0-0.deb12.2-amd64)',
'vendor': ''}
AMD Radeon Graphics (RADV REMBRANDT) (IntegratedGPU) on Vulkan
NVIDIA T1200 Laptop GPU (DiscreteGPU) on Vulkan
llvmpipe (LLVM 15.0.6, 256 bits) (CPU) on Vulkan
AMD Radeon Graphics (rembrandt, LLVM 15.0.6, DRM 3.52, 6.4.0-0.deb12.2-amd64) (Unknown) on OpenGL


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

# GPU that is currently in use by the renderer
plot.renderer.device.adapter.request_adapter_info()
print(plot.renderer.device.adapter.summary)

9 changes: 4 additions & 5 deletions fastplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@
from .graphics.selectors import *
from .legends import *
from .widgets import ImageWidget
from .utils import _notebook_print_banner, config
from .utils import config
from .utils.gui import run

from wgpu.gui.auto import run
from wgpu.backends.wgpu_native import enumerate_adapters
import wgpu


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

adapters = [a.request_adapter_info() for a in enumerate_adapters()]
adapters = [a.summary for a in wgpu.gpu.enumerate_adapters()]

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

_notebook_print_banner()

__all__ = [
"Plot",
Expand Down
16 changes: 7 additions & 9 deletions fastplotlib/graphics/selectors/_linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
from numbers import Real

import numpy as np

import pygfx

try:
import ipywidgets

HAS_IPYWIDGETS = True
except (ImportError, ModuleNotFoundError):
HAS_IPYWIDGETS = False

from ...utils.gui import IS_JUPYTER
from .._base import Graphic, GraphicCollection
from .._features._selection_features import LinearSelectionFeature
from ._base_selector import BaseSelector


if IS_JUPYTER:
# If using the jupyter backend, user has jupyter_rfb, and thus also ipywidgets
import ipywidgets


class LinearSelector(BaseSelector):
@property
def limits(self) -> Tuple[float, float]:
Expand Down Expand Up @@ -240,7 +238,7 @@ def make_ipywidget_slider(self, kind: str = "IntSlider", **kwargs):

"""

if not HAS_IPYWIDGETS:
if not IS_JUPYTER:
raise ImportError(
"Must installed `ipywidgets` to use `make_ipywidget_slider()`"
)
Expand Down
18 changes: 8 additions & 10 deletions fastplotlib/graphics/selectors/_linear_region.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
from typing import *
from numbers import Real

try:
import ipywidgets

HAS_IPYWIDGETS = True
except (ImportError, ModuleNotFoundError):
HAS_IPYWIDGETS = False

import numpy as np

import pygfx

from ...utils.gui import IS_JUPYTER
from .._base import Graphic, GraphicCollection
from ._base_selector import BaseSelector
from .._features._selection_features import LinearRegionSelectionFeature
from ._base_selector import BaseSelector


if IS_JUPYTER:
# If using the jupyter backend, user has jupyter_rfb, and thus also ipywidgets
import ipywidgets


class LinearRegionSelector(BaseSelector):
Expand Down Expand Up @@ -390,7 +388,7 @@ def make_ipywidget_slider(self, kind: str = "IntRangeSlider", **kwargs):

"""

if not HAS_IPYWIDGETS:
if not IS_JUPYTER:
raise ImportError(
"Must installed `ipywidgets` to use `make_ipywidget_slider()`"
)
Expand Down
40 changes: 5 additions & 35 deletions fastplotlib/layouts/_frame/_frame.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,7 @@
import os

from ._toolbar import ToolBar

from ...graphics import ImageGraphic

from .._utils import CANVAS_OPTIONS_AVAILABLE


class UnavailableOutputContext:
# called when a requested output context is not available
# ex: if trying to force jupyter_rfb canvas but jupyter_rfb is not installed
def __init__(self, context_name, msg):
self.context_name = context_name
self.msg = msg

def __call__(self, *args, **kwargs):
raise ModuleNotFoundError(
f"The following output context is not available: {self.context_name}\n{self.msg}"
)


# TODO: potentially put all output context and toolbars in their own module and have this determination done at import
if CANVAS_OPTIONS_AVAILABLE["jupyter"]:
from ._jupyter_output import JupyterOutputContext
else:
JupyterOutputContext = UnavailableOutputContext(
"Jupyter",
"You must install fastplotlib using the `'notebook'` option to use this context:\n"
'pip install "fastplotlib[notebook]"',
)

if CANVAS_OPTIONS_AVAILABLE["qt"]:
from ._qt_output import QOutputContext
else:
QtOutput = UnavailableOutputContext(
"Qt", "You must install `PyQt6` to use this output context"
)
from ._toolbar import ToolBar


class Frame:
Expand Down Expand Up @@ -158,6 +124,8 @@ def show(

# return the appropriate OutputContext based on the current canvas
if self.canvas.__class__.__name__ == "JupyterWgpuCanvas":
from ._jupyter_output import JupyterOutputContext # noqa - inline import
kushalkolar marked this conversation as resolved.
Show resolved Hide resolved

self._output = JupyterOutputContext(
frame=self,
make_toolbar=toolbar,
Expand All @@ -167,6 +135,8 @@ def show(
)

elif self.canvas.__class__.__name__ == "QWgpuCanvas":
from ._qt_output import QOutputContext # noqa - inline import

self._output = QOutputContext(
frame=self, make_toolbar=toolbar, add_widgets=add_widgets
)
Expand Down
3 changes: 1 addition & 2 deletions fastplotlib/layouts/_frame/_qt_output.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from PyQt6 import QtWidgets

from ...utils.gui import QtWidgets
from ._qt_toolbar import QToolbar


Expand Down
3 changes: 1 addition & 2 deletions fastplotlib/layouts/_frame/_qt_toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import traceback
from typing import *

from PyQt6 import QtWidgets, QtCore

from ...utils.gui import QtCore, QtWidgets
from ...graphics.selectors import PolygonSelector
from ._toolbar import ToolBar
from ._qtoolbar_template import Ui_QToolbar
Expand Down
5 changes: 2 additions & 3 deletions fastplotlib/layouts/_frame/_qtoolbar_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt6 import QtCore, QtGui, QtWidgets
from ...utils.gui import QtGui, QtCore, QtWidgets


class Ui_QToolbar(object):
Expand All @@ -30,7 +29,7 @@ def setupUi(self, QToolbar):
self.maintain_aspect_button = QtWidgets.QPushButton(parent=QToolbar)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
font.setWeight(QtGui.QFont.Weight.Bold)
self.maintain_aspect_button.setFont(font)
self.maintain_aspect_button.setCheckable(True)
self.maintain_aspect_button.setObjectName("maintain_aspect_button")
Expand Down
12 changes: 3 additions & 9 deletions fastplotlib/layouts/_gridplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pygfx

from wgpu.gui.auto import WgpuCanvas
from wgpu.gui import WgpuCanvasBase

from ._frame import Frame
from ._utils import make_canvas_and_renderer, create_controller, create_camera
Expand All @@ -22,7 +22,7 @@ def __init__(
cameras: Union[str, list, np.ndarray] = "2d",
controller_types: Union[str, list, np.ndarray] = None,
controller_ids: Union[str, list, np.ndarray] = None,
canvas: Union[str, WgpuCanvas, pygfx.Texture] = None,
canvas: Union[str, WgpuCanvasBase, pygfx.Texture] = None,
renderer: pygfx.WgpuRenderer = None,
size: Tuple[int, int] = (500, 300),
names: Union[list, np.ndarray] = None,
Expand Down Expand Up @@ -219,12 +219,6 @@ def __init__(
for cam in cams[1:]:
_controller.add_camera(cam)

if canvas is None:
canvas = WgpuCanvas()

if renderer is None:
renderer = pygfx.renderers.WgpuRenderer(canvas)

self._canvas = canvas
self._renderer = renderer

Expand Down Expand Up @@ -266,7 +260,7 @@ def __init__(
Frame.__init__(self)

@property
def canvas(self) -> WgpuCanvas:
def canvas(self) -> WgpuCanvasBase:
"""The canvas associated to this GridPlot"""
return self._canvas

Expand Down
4 changes: 2 additions & 2 deletions fastplotlib/layouts/_plot.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import *

import pygfx
from wgpu.gui.auto import WgpuCanvas
from wgpu.gui import WgpuCanvasBase

from ._subplot import Subplot
from ._frame import Frame
Expand All @@ -11,7 +11,7 @@
class Plot(Subplot, Frame, RecordMixin):
def __init__(
self,
canvas: Union[str, WgpuCanvas] = None,
canvas: Union[str, WgpuCanvasBase] = None,
renderer: pygfx.WgpuRenderer = None,
camera: Union[str, pygfx.PerspectiveCamera] = "2d",
controller: Union[str, pygfx.Controller] = None,
Expand Down
6 changes: 3 additions & 3 deletions fastplotlib/layouts/_plot_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import pygfx
from pylinalg import vec_transform, vec_unproject
from wgpu.gui.auto import WgpuCanvas
from wgpu.gui import WgpuCanvasBase

from ._utils import create_camera, create_controller
from ..graphics._base import Graphic
Expand All @@ -29,7 +29,7 @@ def __init__(
camera: Union[pygfx.PerspectiveCamera],
controller: Union[pygfx.Controller],
scene: pygfx.Scene,
canvas: WgpuCanvas,
canvas: WgpuCanvasBase,
renderer: pygfx.WgpuRenderer,
name: str = None,
):
Expand Down Expand Up @@ -122,7 +122,7 @@ def scene(self) -> pygfx.Scene:
return self._scene

@property
def canvas(self) -> WgpuCanvas:
def canvas(self) -> WgpuCanvasBase:
"""Canvas associated to the plot area"""
return self._canvas

Expand Down
4 changes: 2 additions & 2 deletions fastplotlib/layouts/_subplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pygfx

from wgpu.gui.auto import WgpuCanvas
from wgpu.gui import WgpuCanvasBase

from ..graphics import TextGraphic
from ._utils import make_canvas_and_renderer, create_camera, create_controller
Expand All @@ -20,7 +20,7 @@ def __init__(
parent_dims: Tuple[int, int] = None,
camera: Union[str, pygfx.PerspectiveCamera] = "2d",
controller: Union[str, pygfx.Controller] = None,
canvas: Union[str, WgpuCanvas, pygfx.Texture] = None,
canvas: Union[str, WgpuCanvasBase, pygfx.Texture] = None,
renderer: pygfx.WgpuRenderer = None,
name: str = None,
):
Expand Down
Loading
Loading