erlab.interactive.utils

Various helper functions and extensions to Qt and pyqtgraph.

This module contains various helper functions and classes that extend the functionality of pyqtgraph and Qt.

Functions

copy_to_clipboard(content)

Copy content to the clipboard.

file_loaders([file_name])

Generate a dictionary of namefilters and loader functions for file dialogs.

format_kwargs(d)

Format a dictionary of keyword arguments for a function call.

generate_code(func, args, kwargs[, module, ...])

Generate Python code for a function call.

load_fit_ui(*[, parent])

Load a fit result from a file.

make_crosshairs([n])

Create a pyqtgraph.TargetItem and associated RotatableLines.

parse_data(data)

save_fit_ui(fit_result, *[, parent])

Save a fit result to a file using a file dialog.

wait_dialog(parent, message)

Show a wait dialog while executing a block of code.

Classes

AnalysisWidgetBase([orientation, num_ax, ...])

AnalysisWidgetBase.

AnalysisWindow(data[, title, layout, ...])

BetterAxisItem(*args, **kwargs)

BetterSpinBox(*args[, integer, compact, ...])

An improved spinbox.

DictMenuBar([parent])

ExclusiveComboGroup([parent, exclude_first])

A group of mutually exclusive comboboxes.

IconActionButton(action[, on, off, ...])

IconButton that supports linking to a QAction.

IconButton([on, off])

Convenience class for creating a QPushButton with a qtawesome icon.

KeyboardEventFilter

Event filter that intercepts select all and copy shortcuts.

ParameterGroup([widgets, ncols, groupbox_kw])

Easy creation of groupboxes with multiple varying parameters.

RotatableLine([offset, target])

pyqtgraph.InfiniteLine that rotates under drag.

xImageItem([image])

pyqtgraph.ImageItem with additional functionality.

class erlab.interactive.utils.AnalysisWidgetBase(orientation='vertical', num_ax=2, link='both', cut_to_data='none', **kwargs)[source]

Bases: GraphicsLayoutWidget

AnalysisWidgetBase.

Parameters:
  • orientation (Literal['vertical', 'horizontal'], default: "vertical") – Sets the orientation of the plots, by default “vertical”

  • num_ax (int, default: 2) – Sets the number of axes.

  • link (Literal['x', 'y', 'both', 'none'], default: "both") – Link axes, by default “both”

  • cut_to_data (Literal['in', 'out', 'both', 'none'], default: "none") – Whether to remove outliers by adjusting color levels, by default “none”

initialize_layout(nax)[source]
get_axis_pos(ax)[source]
get_hist_pos(ax)[source]
setStretchFactors(factors)[source]
setStretchFactor(i, factor)[source]
set_input(data=None)[source]
add_roi(i)[source]
class erlab.interactive.utils.AnalysisWindow(data, title=None, layout='horizontal', data_is_input=True, analysisWidget=None, *args, **kwargs)[source]

Bases: QMainWindow

addParameterGroup(*args, **kwargs)[source]
closeEvent(event)[source]
class erlab.interactive.utils.BetterAxisItem(*args, **kwargs)[source]

Bases: AxisItem

updateAutoSIPrefix()[source]
tickStrings(values, scale, spacing)[source]
labelString()[source]
setLabel(text=None, units=None, unitPrefix=None, **args)[source]
class erlab.interactive.utils.BetterSpinBox(*args, integer=False, compact=True, discrete=False, decimals=3, significant=False, scientific=False, value=0.0, prefix='', **kwargs)[source]

Bases: QAbstractSpinBox

An improved spinbox.

Signals:
  • valueChanged – Emitted when the value is changed.

  • textChanged – Emitted when the text is changed.

Parameters:
  • integer (bool, default: False) – If True, the spinbox will only display integer values.

  • compact (bool, default: True) – Whether to reduce the height of the spinbox.

  • discrete (bool, default: False) –

    If True the spinbox will only step to pre-determined discrete values.

    If False, the spinbox will just add or subtract the predetermined increment when increasing or decreasing the step.

  • decimals (int, default: 3) – The precision of the spinbox. See the significant argument for the meaning. When integer is True, this argument is ignored.

  • significant (bool, default: False) –

    If True, decimals will specify the total number of significant digits, before or after the decimal point, ignoring leading zeros.

    If False, decimals will specify the total number of digits after the decimal point, including leading zeros.

    When integer or scientific is True, this argument is ignored.

  • scientific (bool, default: False) – Whether to print in scientific notation.

  • value (float, default: 0.0) – Initial value of the spinbox.

setPrefix(prefix)[source]
prefix()[source]
setDecimals(decimals)[source]
decimals()[source]
setRange(mn, mx)[source]
widthFromText(text)[source]
widthFromValue(value)[source]
setMaximum(mx)[source]
setMinimum(mn)[source]
setSingleStep(step)[source]
singleStep()[source]
maximum()[source]
minimum()[source]
value()[source]
text()[source]
textFromValue(value)[source]
valueFromText(text)[source]
stepBy(steps)[source]
stepEnabled()[source]
setValue(val)[source]
fixup(_)[source]
validate(strn, pos)[source]
editingFinishedEvent()[source]
keyPressEvent(evt)[source]
focusInEvent(evt)[source]
class erlab.interactive.utils.DictMenuBar(parent=None, **kwargs)[source]

Bases: QMenuBar

add_items(**kwargs)[source]
parse_menu(parent, **kwargs)[source]
parse_action(actopts)[source]
class erlab.interactive.utils.ExclusiveComboGroup(parent=None, exclude_first=False)[source]

Bases: QObject

A group of mutually exclusive comboboxes.

Adapted from this StackOverflow answer.

This group stores only weak references to the comboboxes, so it is necessary to keep a reference to the comboboxes elsewhere in the code.

addCombo(combo)[source]
class erlab.interactive.utils.IconActionButton(action, on=None, off=None, text_from_action=False, **kwargs)[source]

Bases: IconButton

IconButton that supports linking to a QAction.

Parameters:
  • action (QAction) – The QAction to be associated with this button.

  • on (str, optional) – The icon to display when the button is in the “on” state.

  • off (str, optional) – The icon to display when the button is in the “off” state. If action is not toggleable, this icon will never be displayed.

  • text_from_action (bool, optional) – If True, the button’s text will be set from the QAction’s text. Otherwise, the text will be left empty.

  • **kwargs – Additional keyword arguments passed to the IconButton constructor.

setAction(action)[source]
class erlab.interactive.utils.IconButton(on=None, off=None, **kwargs)[source]

Bases: QPushButton

Convenience class for creating a QPushButton with a qtawesome icon.

This button adapts to dark mode changes by resetting the qtawesome cache when a color palette change is detected.

Parameters:
  • on (str, optional) – The icon to display when the button is in the “on” state. If off is not provided, this will be the only icon displayed.

  • off (str, optional) – The icon to display when the button is in the “off” state. If provided, the button will be checkable, and the icon will change when the button is toggled.

  • **kwargs – Additional keyword arguments passed to the QPushButton constructor.

setChecked(value)[source]
get_icon(icon)[source]
refresh_icons()[source]
changeEvent(evt)[source]
class erlab.interactive.utils.KeyboardEventFilter[source]

Bases: QObject

Event filter that intercepts select all and copy shortcuts.

For some operating systems, shortcuts are often intercepted by actions in the menu bar. This filter ensures that the shortcuts work as expected when the target widget has focus.

This filter can be used when the target widget does receive the shortcut event with type QtCore.QEvent.Type.ShortcutOverride, but does not respond to it. If the target widget never receives the event, a different approach using the current focus widget is needed.

eventFilter(obj=None, event=None)[source]
class erlab.interactive.utils.ParameterGroup(widgets=None, ncols=1, groupbox_kw=None, **widgets_kwargs)[source]

Bases: QGroupBox

Easy creation of groupboxes with multiple varying parameters.

Can be used in many different interactive tools for dynamic data analysis.

Parameters:
  • ncols (int, default: 1) – Number of columns in the layout.

  • groupbox_kw (dict | None, default: None) – Keyword arguments passed onto PySide6.QtWidgets.QGroupBox.

  • params – See Examples.

Signals:

sigParameterChanged(dict)

Examples

>>> ParameterGroup(
    **{
        "a": QtWidgets.QDoubleSpinBox(range=(0, 1), singleStep=0.01, value=0.2),
        "b": dict(qwtype="dblspin", range=(0, 2), singleStep=0.04),
        "c": QtWidgets.QSlider(range=(0, 10000))
    }
)
VALID_QWTYPE: Mapping[str, type[QWidget]] = mappingproxy({'spin': <class 'PyQt6.QtWidgets.QSpinBox'>, 'dblspin': <class 'PyQt6.QtWidgets.QDoubleSpinBox'>, 'btspin': <class 'erlab.interactive.utils.BetterSpinBox'>, 'slider': <class 'PyQt6.QtWidgets.QSlider'>, 'chkbox': <class 'PyQt6.QtWidgets.QCheckBox'>, 'pushbtn': <class 'PyQt6.QtWidgets.QPushButton'>, 'chkpushbtn': <class 'PyQt6.QtWidgets.QPushButton'>, 'combobox': <class 'PyQt6.QtWidgets.QComboBox'>, 'fitparam': <class 'erlab.interactive.utils.FittingParameterWidget'>})
layout()[source]
static getParameterWidget(qwtype=None, **kwargs)[source]

Initialize the PySide6.QtWidgets.QWidget corresponding to qwtype.

Parameters:

qwtype (Literal['spin', 'dblspin', 'btspin', 'slider', 'chkbox', 'pushbtn', 'chkpushbtn', 'combobox', 'fitparam'] | None, default: None) – Type of the widget, must a key of ParameterGroup.VALID_QWTYPE.

set_values(**kwargs)[source]
widget_value(widget)[source]
widget_change_signal(widget)[source]
global_connect()[source]
widgets_of_type(widgetclass)[source]
property values: dict[str, float | int | bool]
class erlab.interactive.utils.RotatableLine(offset=0.0, target=None, **kwargs)[source]

Bases: InfiniteLine

pyqtgraph.InfiniteLine that rotates under drag.

The position can be changed by providing a pyqtgraph.TargetItem which will drag the line along with it.

Using the constructor function make_crosshairs() is recommended for creating several lines at once.

Parameters:
  • offset (float, default: 0.0) – Offset angle in degrees.

  • target (TargetItem | None, default: None) – Target item to link the position of the line to.

  • **kwargs – Additional keyword arguments to pass to pyqtgraph.InfiniteLine.

Signals:

sigAngleChanged(float) – Emitted when the angle of the line is changed.

property angle_effective: float

The angle of the line relative to the initial angle.

Link with another RotatableLine.

Providing another RotatableLine will link the angles of both lines.

setAngle(angle)[source]
set_target(target)[source]
mouseDragEvent(ev)[source]
erlab.interactive.utils.copy_to_clipboard(content)[source]

Copy content to the clipboard.

Parameters:

content (str | list[str]) – The content to be copied. If a list of strings is passed, the strings are joined by newlines.

Returns:

str – The copied content.

Return type:

str

erlab.interactive.utils.file_loaders(file_name=None)[source]

Generate a dictionary of namefilters and loader functions for file dialogs.

Parameters:

file_name (str | PathLike | None | Iterable[str | PathLike], default: None) – Name of the file to load. If provided, only the loaders that match the file name are returned. If an iterable of file names is provided, the loaders that match all file names are returned.

Returns:

dict – Dictionary of file loaders. The keys are name filters(argument to setNameFilter), and the values are tuples of the loader function and additional keyword arguments.

Return type:

dict[str, tuple[Callable, dict]]

erlab.interactive.utils.format_kwargs(d)[source]

Format a dictionary of keyword arguments for a function call.

If the keys are valid Python identifiers, the output will be formatted as keyword arguments. Otherwise, the output will be formatted as a dictionary.

Parameters:

d (dict[str, Any]) – Dictionary of keyword arguments.

erlab.interactive.utils.generate_code(func, args, kwargs, module=None, name=None, assign=None, prefix=None, remove_defaults=True, line_length=88, copy=False)[source]

Generate Python code for a function call.

The result can be copied to your clipboard in a form that can be pasted into an interactive Python session or Jupyter notebook cell.

Parameters:
  • func (Callable) – Function to generate code for.

  • args (Collection[Any]) – Positional arguments passed onto the function. Non-string arguments are converted to strings. If given a string, quotes are added. If surrounded by vertical bars (|), the string is not quoted.

  • kwargs (dict[str, Any]) – Keyword arguments passed onto the function.

  • module (str | None, default: None) – Prefix to add to the function name. For example, "scipy.ndimage".

  • name (str | None, default: None) – Name of the function. If None, func.__name__ is used.

  • assign (str | None, default: None) – If provided, the return value will be assigned to this variable.

  • prefix (str | None, default: None) – Prefix to add to the generated string.

  • remove_defaults (bool, default: True) – If True, keyword arguments that have values identical to the defaults are removed.

  • line_length (int, default: 88) – Maximum length of the line. If the line is longer than this, it will be split into multiple lines.

  • copy (bool, default: False) – If True, the result is copied to the clipboard.

Examples

>>> import numpy as np
>>> from erlab.interactive.utils import generate_code
>>> generate_code(
>>>     np.linalg.norm,
>>>     args=["|np.array([1, 2, 3])|"],
>>>     kwargs=dict(ord=2, keepdims=False),
>>>     module="np.linalg",
>>>     assign="value",
>>> )
'value = numpy.linalg.norm(numpy.array([1, 2, 3]), ord=2)'
erlab.interactive.utils.load_fit_ui(*, parent=None)[source]

Load a fit result from a file.

When called, a file dialog is opened to select the file to load. The fit result is loaded from the selected file using xarray_lmfit.load_fit().

Parameters:

parent (QWidget | None, default: None) – Parent widget for the file dialog.

Returns:

result (xr.Dataset or None) – The loaded fit result. Returns None if no file was selected or if the file could not be loaded.

Return type:

Dataset | None

erlab.interactive.utils.make_crosshairs(n=1)[source]

Create a pyqtgraph.TargetItem and associated RotatableLines.

Parameters:

n (Literal[1, 2, 3], default: 1) – Number of lines to create. Must be 1, 2, or 3. If 1, a single line is created. If 2, two lines are created at 0 and 90 degrees. If 3, three lines are created at 0, 120, and 240 degrees.

erlab.interactive.utils.parse_data(data)[source]
erlab.interactive.utils.save_fit_ui(fit_result, *, parent=None)[source]

Save a fit result to a file using a file dialog.

When called, a file dialog is opened to select the file name and format. The fit result dataset is saved to the selected file in the chosen format using xarray_lmfit.save_fit().

Parameters:
  • fit_result (Dataset) – The fit result to save.

  • parent (QWidget | None, default: None) – Parent widget for the file dialog.

erlab.interactive.utils.wait_dialog(parent, message)[source]

Show a wait dialog while executing a block of code.

This context manager creates a simple dialog with a message while the block of code is being executed. The dialog is closed when the block is done.

Parameters:
  • parent (QWidget) – Parent widget.

  • message (str) – Message to display in the dialog.

Example

>>> with wait_dialog(self, "Processing data..."):
>>>    some_long_running_code()
class erlab.interactive.utils.xImageItem(image=None, **kwargs)[source]

Bases: BetterImageItem

pyqtgraph.ImageItem with additional functionality.

This class provides xarray.DataArray support and auto limits based on histogram analysis.

Parameters:
Signals:

sigToleranceChanged()

set_cut_tolerance(cut_tolerance)[source]
data_cut_levels(data=None)[source]

Return appropriate levels estimated from the data.

setImage(image=None, autoLevels=None, cut_to_data=False, **kargs)[source]
setDataArray(data, update_labels=True, **kargs)[source]
getMenu()[source]
getPlotItem()[source]
open_itool()[source]