Skip to content

Commit

Permalink
various small fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
bimac committed Sep 30, 2024
1 parent 9a6c913 commit 4eb42fd
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 191 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
cache: true
python-version: '3.10'
- name: Install dependencies
run: pdm sync -dG doc -dG pyside6
run: pdm sync -dG doc -dG qt5
- name: Install GraphViz
run: sudo apt-get install -y graphviz
- name: Sphinx build
Expand Down
1 change: 1 addition & 0 deletions docs/source/_templates/custom-class-template.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
.. autoclass:: {{ objname }}
:members:
:undoc-members:
:show-inheritance:
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

# -- Settings for automatic API generation -----------------------------------
autodoc_mock_imports = ["PySpin"]
autodoc_class_signature = 'mixed' # 'mixed', 'separated'
autodoc_class_signature = 'separated' # 'mixed', 'separated'
autodoc_member_order = 'groupwise' # 'alphabetical', 'groupwise', 'bysource'
autodoc_inherit_docstrings = False
autodoc_typehints = 'description' # 'description', 'signature', 'none', 'both'
Expand All @@ -73,7 +73,7 @@
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = True
napoleon_use_admonition_for_notes = True
napoleon_use_admonition_for_references = True
Expand Down
4 changes: 2 additions & 2 deletions docs/source/dev_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Checking and formatting of code
pdm run ruff format
pdm run ruff check --fix
pdm run mypy
pdm run mypy --package iblqt $(qtpy mypy-args)
Building the documentation
Expand All @@ -55,4 +55,4 @@ Building the package

.. code-block:: bash
pdm build
pdm build
2 changes: 2 additions & 0 deletions iblqt/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
"""A collection of extensions and enhancements to the Qt framework."""

__version__ = '0.1.0'
91 changes: 59 additions & 32 deletions iblqt/core.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Non-GUI functionality, including event handling, data types, and data management."""

import logging

from pyqtgraph import ColorMap, colormap # type: ignore
Expand All @@ -16,6 +18,7 @@
import pandas as pd
from pandas import DataFrame
import numpy as np
import numpy.typing as npt

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,7 +48,18 @@ def __init__(
super().__init__(parent, *args, **kwargs)
self._dataFrame: DataFrame = DataFrame() if dataFrame is None else dataFrame

def setDataFrame(self, dataFrame: DataFrame) -> None:
def getDataFrame(self) -> DataFrame:
"""
Get the underlying DataFrame.
Returns
-------
DataFrame
The DataFrame represented by the model.
"""
return self._dataFrame

def setDataFrame(self, dataFrame: DataFrame):
"""
Set a new DataFrame.
Expand All @@ -58,18 +72,8 @@ def setDataFrame(self, dataFrame: DataFrame) -> None:
self._dataFrame = dataFrame.copy()
self.endResetModel()

def dataFrame(self) -> DataFrame:
"""
Get the underlying DataFrame.
Returns
-------
DataFrame
The DataFrame represented by the model.
"""
return self._dataFrame

dataFrame = Property(DataFrame, fget=dataFrame, fset=setDataFrame)
dataFrame = Property(DataFrame, fget=getDataFrame, fset=setDataFrame) # type: Property
"""The DataFrame containing the models data."""

def headerData(
self,
Expand Down Expand Up @@ -182,11 +186,17 @@ def sort(self, column: int, order: Qt.SortOrder = Qt.SortOrder.AscendingOrder):


class ColoredDataFrameTableModel(DataFrameTableModel):
colormapChanged = Signal(str)
alphaChanged = Signal(int)
"""Extension of DataFrameTableModel providing color-mapped numerical data."""

colormapChanged = Signal(str) # type: Signal
"""Emitted when the colormap has been changed."""

alphaChanged = Signal(int) # type: Signal
"""Emitted when the alpha value has been changed."""

_normData = DataFrame()
_background: np.ndarray
_foreground: np.ndarray
_background: npt.NDArray[np.int_]
_foreground: npt.NDArray[np.int_]
_cmap: ColorMap
_alpha: int

Expand Down Expand Up @@ -218,8 +228,19 @@ def __init__(
self.modelReset.connect(self._normalizeData)
self.dataChanged.connect(self._normalizeData)
self.colormapChanged.connect(self._defineColors)
self.setColormap(colormap)
self.setAlpha(alpha)
self.setProperty('colormap', colormap)
self.setProperty('alpha', alpha)

def getColormap(self) -> str:
"""
Return the name of the current colormap.
Returns
-------
str
The name of the current colormap
"""
return self._cmap.name

@Slot(str)
def setColormap(self, name: str):
Expand All @@ -238,11 +259,19 @@ def setColormap(self, name: str):
return
log.warning(f'No such colormap: "{name}"')

def colormap(self) -> str:
"""Return the name of the current colormap."""
return self._cmap.name
colormap = Property(str, fget=getColormap, fset=setColormap, notify=colormapChanged) # type: Property
"""The name of the colormap."""

def getAlpha(self) -> int:
"""
Return the alpha value of the colormap.
colormap = Property(str, fget=colormap, fset=setColormap)
Returns
-------
int
The alpha value of the colormap.
"""
return self._alpha

@Slot(int)
def setAlpha(self, alpha: int = 255):
Expand All @@ -258,11 +287,8 @@ def setAlpha(self, alpha: int = 255):
self.alphaChanged.emit(self._alpha)
self.layoutChanged.emit()

def alpha(self) -> int:
"""Return the alpha value of the colormap."""
return self._alpha

alpha = Property(int, fget=alpha, fset=setAlpha)
alpha = Property(int, fget=getAlpha, fset=setAlpha, notify=alphaChanged) # type: Property
"""The alpha value of the colormap."""

def _normalizeData(self) -> None:
"""Normalize the Data for mapping to a colormap."""
Expand Down Expand Up @@ -334,9 +360,10 @@ def data(
row = self._dataFrame.index[index.row()]
col = index.column()
if role == Qt.BackgroundRole:
val = self._background[row][col]
return QColor.fromRgb(*val, self._alpha)
rgb = self._background[row][col]
return QVariant(QColor.fromRgb(*rgb, self._alpha))
if role == Qt.ForegroundRole:
val = self._foreground[row][col]
return QColor('black' if (val * self._alpha) < 32512 else 'white')
lum: int = self._foreground[row][col]
color = QColor('black' if (lum * self._alpha) < 32512 else 'white')
return QVariant(color)
return super().data(index, role)
53 changes: 21 additions & 32 deletions iblqt/widgets.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
"""A collection of reusable Qt widgets designed for general use in PyQt or PySide applications."""
"""Graphical user interface components."""

from qtpy.QtWidgets import QPushButton
from qtpy.QtCore import Signal, Slot, Property


class StatefulButton(QPushButton):
"""A QPushButton that maintains an active/inactive state.
Parameters
----------
*args : tuple
Positional arguments passed to QPushButton constructor.
active : bool, optional
Initial state of the button (default is False).
**kwargs : dict
Keyword arguments passed to QPushButton constructor.
Attributes
----------
clickedWhileActive : Signal
Emitted when the button is clicked while it is in the active state.
clickedWhileInactive : Signal
Emitted when the button is clicked while it is in the inactive state.
stateChanged : Signal
Emitted when the button's state has changed. The signal carries the new state.
"""

clickedWhileActive = Signal(name='clickedWhileActive')
clickedWhileInactive = Signal(name='clickedWhileInactive')
stateChanged = Signal(bool, name='stateChanged')
"""A QPushButton that maintains an active/inactive state."""

clickedWhileActive = Signal() # type: Signal
"""Emitted when the button is clicked while it is in the active state."""

clickedWhileInactive = Signal() # type: Signal
"""Emitted when the button is clicked while it is in the inactive state."""

stateChanged = Signal(bool) # type: Signal
"""Emitted when the button's state has changed. The signal carries the new state
(True for active, False for inactive)."""

def __init__(self, *args, active: bool = False, **kwargs):
"""Initialize the StateButton with the specified active state.
"""Initialize the StatefulButton with the specified active state.
Parameters
----------
Expand All @@ -46,8 +33,7 @@ def __init__(self, *args, active: bool = False, **kwargs):
self._isActive = active
self.clicked.connect(self._onClick)

@Property(bool)
def active(self) -> bool:
def getActive(self) -> bool:
"""Get the active state of the button.
Returns
Expand All @@ -58,20 +44,23 @@ def active(self) -> bool:
return self._isActive

@Slot(bool)
def setActive(self, active: bool):
def setActive(self, value: bool):
"""Set the active state of the button.
Emits `stateChanged` if the state has changed.
Parameters
----------
active : bool
value : bool
The new active state of the button.
"""
if self._isActive != active:
self._isActive = active
if self._isActive != value:
self._isActive = value
self.stateChanged.emit(self._isActive)

active = Property(bool, fget=getActive, fset=setActive, notify=stateChanged) # type: Property
"""The active state of the button."""

@Slot()
def _onClick(self):
"""Handle the button click event.
Expand Down
Loading

0 comments on commit 4eb42fd

Please sign in to comment.