diff --git a/src/silx/gui/_glutils/font.py b/src/silx/gui/_glutils/font.py index bee9745642..2fd5653072 100644 --- a/src/silx/gui/_glutils/font.py +++ b/src/silx/gui/_glutils/font.py @@ -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 @@ -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" @@ -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() @@ -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 @@ -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 diff --git a/src/silx/gui/plot/backends/BackendBase.py b/src/silx/gui/plot/backends/BackendBase.py index abe6dbf518..333140fea4 100755 --- a/src/silx/gui/plot/backends/BackendBase.py +++ b/src/silx/gui/plot/backends/BackendBase.py @@ -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' @@ -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: @@ -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: @@ -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 """ diff --git a/src/silx/gui/plot/backends/glutils/GLText.py b/src/silx/gui/plot/backends/glutils/GLText.py index 36ee07e05d..e3ed86b0ff 100644 --- a/src/silx/gui/plot/backends/glutils/GLText.py +++ b/src/silx/gui/plot/backends/glutils/GLText.py @@ -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 @@ -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': """ @@ -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 @@ -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() @@ -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( @@ -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: @@ -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 diff --git a/src/silx/gui/plot/items/marker.py b/src/silx/gui/plot/items/marker.py index 4c988874a9..6907d047e7 100755 --- a/src/silx/gui/plot/items/marker.py +++ b/src/silx/gui/plot/items/marker.py @@ -23,6 +23,7 @@ # ###########################################################################*/ """This module provides markers item of the :class:`Plot`. """ +from __future__ import annotations __authors__ = ["T. Vincent"] __license__ = "MIT" @@ -30,7 +31,6 @@ import logging -from typing import Tuple, Optional from ....utils.proxy import docstring from .core import (Item, DraggableMixIn, ColorMixIn, LineMixIn, SymbolMixIn, @@ -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. @@ -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 diff --git a/src/silx/gui/utils/image.py b/src/silx/gui/utils/image.py index cebe2ed393..3dbb949254 100644 --- a/src/silx/gui/utils/image.py +++ b/src/silx/gui/utils/image.py @@ -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 @@ -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. @@ -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) @@ -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, @@ -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 diff --git a/src/silx/gui/utils/matplotlib.py b/src/silx/gui/utils/matplotlib.py index 8843cf9f55..56049cd15c 100644 --- a/src/silx/gui/utils/matplotlib.py +++ b/src/silx/gui/utils/matplotlib.py @@ -29,6 +29,8 @@ It provides the matplotlib :class:`FigureCanvasQTAgg` class corresponding to the used backend. """ +from __future__ import annotations + __authors__ = ["T. Vincent"] __license__ = "MIT" @@ -72,24 +74,30 @@ def qFontToFontProperties(font: qt.QFont): ) -def rasterMathText(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=1.0): +def rasterMathText( + 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 matplotlib supporting latex-like 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