Skip to content

Commit

Permalink
Merge pull request #3957 from t20100/typing
Browse files Browse the repository at this point in the history
silx.gui.plot: Added Python typing
  • Loading branch information
t20100 authored Oct 27, 2023
2 parents b74b48f + 495fd9f commit b3e2bfa
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 66 deletions.
46 changes: 30 additions & 16 deletions src/silx/gui/_glutils/font.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# /*##########################################################################
#
# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
# Copyright (c) 2016-2023 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand All @@ -23,6 +23,8 @@
# ###########################################################################*/
"""Text rasterisation feature leveraging Qt font and text layout support."""

from __future__ import annotations

__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "13/10/2016"
Expand All @@ -42,7 +44,7 @@
_logger = logging.getLogger(__name__)


def getDefaultFontFamily():
def getDefaultFontFamily() -> str:
"""Returns the default font family of the application"""
return qt.QApplication.instance().font().family()

Expand Down Expand Up @@ -70,24 +72,30 @@ def getDefaultFontFamily():
"""Thickest characters: Maximum font weight"""


def rasterTextQt(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=1.0):
def rasterTextQt(
text: str,
font: str | qt.QFont,
size: int = -1,
weight: int = -1,
italic: bool = False,
devicePixelRatio: float = 1.0,
) -> tuple[numpy.ndarray, int]:
"""Raster text using Qt.
It supports multiple lines.
:param str text: The text to raster
:param text: The text to raster
:param font: Font name or QFont to use
:type font: str or :class:`QFont`
:param int size:
:param size:
Font size in points
Used only if font is given as name.
:param int weight:
:param weight:
Font weight in [0, 99], see QFont.Weight.
Used only if font is given as name.
:param bool italic:
:param italic:
True for italic font (default: False).
Used only if font is given as name.
:param float devicePixelRatio:
:param devicePixelRatio:
The current ratio between device and device-independent pixel
(default: 1.0)
:return: Corresponding image in gray scale and baseline offset from top
Expand Down Expand Up @@ -160,24 +168,30 @@ def rasterTextQt(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=
return array, metrics.ascent() - min_row


def rasterText(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=1.0):
def rasterText(
text: str,
font: str | qt.QFont,
size: int = -1,
weight = -1,
italic: bool = False,
devicePixelRatio=1.0,
) -> tuple[numpy.ndarray, int]:
"""Raster text using Qt or matplotlib if there may be math syntax.
It supports multiple lines.
:param str text: The text to raster
:param text: The text to raster
:param font: Font name or QFont to use
:type font: str or :class:`QFont`
:param int size:
:param size:
Font size in points
Used only if font is given as name.
:param int weight:
:param weight:
Font weight in [0, 99], see QFont.Weight.
Used only if font is given as name.
:param bool italic:
:param italic:
True for italic font (default: False).
Used only if font is given as name.
:param float devicePixelRatio:
:param devicePixelRatio:
The current ratio between device and device-independent pixel
(default: 1.0)
:return: Corresponding image in gray scale and baseline offset from top
Expand Down
51 changes: 33 additions & 18 deletions src/silx/gui/plot/backends/BackendBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,18 @@
This API is a simplified version of PyMca PlotBackend API.
"""

from __future__ import annotations


__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
__date__ = "21/12/2018"

from collections.abc import Callable
import weakref

from ... import qt


# Names for setCursor
CURSOR_DEFAULT = 'default'
Expand Down Expand Up @@ -188,17 +194,28 @@ def addShape(self, x, y, shape, color, fill, overlay,
"""
return object()

def addMarker(self, x, y, text, color,
symbol, linestyle, linewidth, constraint, yaxis, font):
def addMarker(
self,
x: float | None,
y: float | None,
text: str | None,
color: str,
symbol: str | None,
linestyle: str,
linewidth: float,
constraint: Callable[[float, float], tuple[float, float]] | None,
yaxis: str,
font: qt.QFont,
) -> object:
"""Add a point, vertical line or horizontal line marker to the plot.
:param float x: Horizontal position of the marker in graph coordinates.
If None, the marker is a horizontal line.
:param float y: Vertical position of the marker in graph coordinates.
If None, the marker is a vertical line.
:param str text: Text associated to the marker (or None for no text)
:param str color: Color to be used for instance 'blue', 'b', '#FF0000'
:param str symbol: Symbol representing the marker.
:param x: Horizontal position of the marker in graph coordinates.
If None, the marker is a horizontal line.
:param y: Vertical position of the marker in graph coordinates.
If None, the marker is a vertical line.
:param text: Text associated to the marker (or None for no text)
:param color: Color to be used for instance 'blue', 'b', '#FF0000'
:param symbol: Symbol representing the marker.
Only relevant for point markers where X and Y are not None.
Value in:
Expand All @@ -209,7 +226,7 @@ def addMarker(self, x, y, text, color,
- 'x' x-cross
- 'd' diamond
- 's' square
:param str linestyle: Style of the line.
:param linestyle: Style of the line.
Only relevant for line markers where X or Y is None.
Value in:
Expand All @@ -218,16 +235,14 @@ def addMarker(self, x, y, text, color,
- '--' dashed line
- '-.' dash-dot line
- ':' dotted line
:param float linewidth: Width of the line.
:param linewidth: Width of the line.
Only relevant for line markers where X or Y is None.
:param constraint: A function filtering marker displacement by
dragging operations or None for no filter.
This function is called each time a marker is
moved.
:type constraint: None or a callable that takes the coordinates of
the current cursor position in the plot as input
and that returns the filtered coordinates.
:param str yaxis: The Y axis this marker belongs to in: 'left', 'right'
dragging operations or None for no filter.
This function is called each time a marker is moved.
It takes the coordinates of the current cursor position in the plot
as input and that returns the filtered coordinates.
:param yaxis: The Y axis this marker belongs to in: 'left', 'right'
:param font: QFont to use to render text
:return: Handle used by the backend to univocally access the marker
"""
Expand Down
36 changes: 20 additions & 16 deletions src/silx/gui/plot/backends/glutils/GLText.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@
from .GLSupport import mat4Translate


# TODO: Font should be configurable by the main program: using mpl.rcParams?


class _Cache(object):
class _Cache:
"""LRU (Least Recent Used) cache.
:param int maxsize: Maximum number of (key, value) pairs in the cache
Expand Down Expand Up @@ -92,7 +89,7 @@ def __setitem__(self, key, value):
ROTATE_90, ROTATE_180, ROTATE_270 = 90, 180, 270


class Text2D(object):
class Text2D:

_SHADERS = {
'vertex': """
Expand Down Expand Up @@ -138,12 +135,19 @@ class Text2D(object):
_sizes = _Cache()
"""Cache already computed sizes"""

def __init__(self, text, font, x=0, y=0,
color=(0., 0., 0., 1.),
bgColor=None,
align=LEFT, valign=BASELINE,
rotate=0,
devicePixelRatio= 1.):
def __init__(
self,
text: str,
font: qt.QFont,
x: float = 0.,
y: float = 0.,
color: tuple[float, float, float, float] = (0., 0., 0., 1.),
bgColor: tuple[float, float, float, float] | None = None,
align: str = LEFT,
valign: str = BASELINE,
rotate: float = 0.,
devicePixelRatio: float = 1.,
):
self.devicePixelRatio = devicePixelRatio
self.font = font
self._vertices = None
Expand All @@ -169,7 +173,7 @@ def _textureKey(self) -> tuple[str, str, float]:
"""Returns the current texture key"""
return self.text, self.font.key(), self.devicePixelRatio

def _getTexture(self):
def _getTexture(self) -> tuple[Texture, int]:
# Retrieve/initialize texture cache for current context
textureKey = self._textureKey()

Expand Down Expand Up @@ -200,11 +204,11 @@ def _getTexture(self):
return textures[textureKey]

@property
def text(self):
def text(self) -> str:
return self._text

@property
def size(self):
def size(self) -> tuple[int, int]:
textureKey = self._textureKey()
if textureKey not in self._sizes:
image, offset = font.rasterText(
Expand All @@ -214,7 +218,7 @@ def size(self):
self._sizes[textureKey] = image.shape[1], image.shape[0]
return self._sizes[textureKey]

def getVertices(self, offset, shape):
def getVertices(self, offset: int, shape: tuple[int, int]) -> numpy.ndarray:
height, width = shape

if self._align == LEFT:
Expand Down Expand Up @@ -247,7 +251,7 @@ def getVertices(self, offset, shape):

return vertices

def render(self, matrix):
def render(self, matrix: numpy.ndarray):
if not self.text.strip():
return

Expand Down
8 changes: 4 additions & 4 deletions src/silx/gui/plot/items/marker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
# ###########################################################################*/
"""This module provides markers item of the :class:`Plot`.
"""
from __future__ import annotations

__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "06/03/2017"


import logging
from typing import Tuple, Optional

from ....utils.proxy import docstring
from .core import (Item, DraggableMixIn, ColorMixIn, LineMixIn, SymbolMixIn,
Expand Down Expand Up @@ -119,14 +119,14 @@ def setText(self, text):
self._text = text
self._updated(ItemChangedType.TEXT)

def getFont(self) -> Optional[qt.QFont]:
def getFont(self) -> qt.QFont | None:
"""Returns a copy of the QFont used to render text.
To modify the text font, use :meth:`setFont`.
"""
return None if self._font is None else qt.QFont(self._font)

def setFont(self, font: Optional[qt.QFont]):
def setFont(self, font: qt.QFont | None):
"""Set the QFont used to render text, use None for default.
A copy is stored, so further modification of the provided font are not taken into account.
Expand All @@ -149,7 +149,7 @@ def getYPosition(self):
"""
return self._y

def getPosition(self) -> Tuple[Optional[float], Optional[float]]:
def getPosition(self) -> tuple[float | None, float | None]:
"""Returns the (x, y) position of the marker in data coordinates
:rtype: 2-tuple of float or None
Expand Down
8 changes: 3 additions & 5 deletions src/silx/gui/utils/image.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# /*##########################################################################
#
# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
# Copyright (c) 2017-2023 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -39,7 +39,7 @@
from .. import qt


def convertArrayToQImage(array):
def convertArrayToQImage(array: numpy.ndarray) -> qt.QImage:
"""Convert an array-like image to a QImage.
The created QImage is using a copy of the array data.
Expand All @@ -50,7 +50,6 @@ def convertArrayToQImage(array):
Channels are expected to be either RGB or RGBA.
:type array: numpy.ndarray of uint8
:return: Corresponding Qt image with RGB888 or ARGB32 format.
:rtype: QImage
"""
array = numpy.array(array, copy=False, order='C', dtype=numpy.uint8)

Expand Down Expand Up @@ -82,7 +81,7 @@ def convertArrayToQImage(array):
return qimage.copy() # Making a copy of the image and its data


def convertQImageToArray(image):
def convertQImageToArray(image: qt.QImage) -> numpy.ndarray:
"""Convert a QImage to a numpy array.
If QImage format is not Format_RGB888, Format_RGBA8888 or Format_ARGB32,
Expand All @@ -94,7 +93,6 @@ def convertQImageToArray(image):
:param QImage image: The QImage to convert.
:return: The image array of RGB or RGBA channels of shape
(height, width, channels (3 or 4))
:rtype: numpy.ndarray of uint8
"""
rgba8888 = getattr(qt.QImage, 'Format_RGBA8888', None) # Only in Qt5

Expand Down
Loading

0 comments on commit b3e2bfa

Please sign in to comment.