Skip to content

visualdynamics.gui.icons

icons

Type icons for the project tree.

Icons are drawn at runtime with QPainter rather than shipped as assets, so they stay sharp at any DPI and need no files. Each type gets a distinct shape as well as a distinct color — shape carries the meaning, so the icons are still tellable apart at 16 px and without relying on color vision.

Functions:

Name Description
color_swatch

A filled chip for a palette color, for drop-downs and menus.

control_icon

Toolbar glyphs: play, pause, add, and the element types.

child_icon

Icon for a sub-item, drawn in its parent object's color.

quantity_of

The quantity a simple dimension names, if it is one we draw.

quantity_icon

Icon for what a record measures, rather than for what holds it.

record_icon

The icon for one record: what that record measures.

ratio_icon

Two quantities as a fraction, the way the dimension reads:

type_icon

Icon for a visualdynamics type, by class name. Requires a running QApplication.

object_icon

The icon for an object, which is not always its class's.

placeholder_icon

The type's glyph in grey: expected by the project's type, not

viridis

The colour at t in 0..1 on viridis, clamped.

Classes

Functions:

color_swatch cached

color_swatch(rgb: tuple[float, float, float]) -> QIcon

A filled chip for a palette color, for drop-downs and menus.

Source code in src/visualdynamics/gui/icons.py
@cache
@cache
def color_swatch(rgb: tuple[float, float, float]) -> QIcon:
    """A filled chip for a palette color, for drop-downs and menus."""
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    painter.setPen(_pen('#00000066', 3))
    painter.setBrush(QBrush(QColor.fromRgbF(*rgb)))
    painter.drawRoundedRect(QRectF(9, 9, 46, 46), 8, 8)
    painter.end()
    return QIcon(pixmap)

control_icon

control_icon(name: str) -> QIcon

Toolbar glyphs: play, pause, add, and the element types.

Source code in src/visualdynamics/gui/icons.py
def control_icon(name: str) -> QIcon:
    """Toolbar glyphs: play, pause, add, and the element types."""
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    {'play': _draw_play, 'pause': _draw_pause,
     'faster': _draw_faster, 'slower': _draw_slower,
     'up': _draw_up, 'down': _draw_down,
     'add': _draw_add,
     'beam': _draw_beam, 'tri': _draw_tri, 'quad': _draw_quad,
     'edit': _draw_edit, 'trash': _draw_trash,
     'colormap': _draw_colormap,
     'curves': _draw_curves, 'map': _draw_map,
     'waterfall': _draw_waterfall,
     'drive_point': _draw_drive_point, 'cmif': _draw_cmif,
     'averaging': _draw_averaging, 'shocks': _draw_shocks,
     'residual': _draw_residual,
     'report': _draw_report,
     'bars': _draw_bars, 'percent_bars': _draw_percent_bars,
     'kurtosis': _draw_kurtosis, 'filter': _draw_filter,
     'truncate': _draw_truncate, 'octave': _draw_octave,
     'log_axis': _draw_log_axis,
     'wavelet': _draw_wavelet,
     'dofs': _draw_dofs, 'link': _draw_link, 'unlink': _draw_unlink,
     'table': _draw_channel_table, 'overlay': _draw_overlay,
     'ratio': _draw_ratio,
     'project': _draw_project,
     'rotate': _draw_rotate,
     'reset': _draw_reset,
     'rigid': _draw_rigid,
     'integrate': _draw_integrate, 'differentiate': _draw_differentiate,
     'transform': _draw_transform, 'expand': _draw_expand,
     'merge': _draw_merge, 'sine': _draw_sine,
     'refresh': _draw_refresh}.get(name, _draw_default)(painter, CONTROL_COLOR)
    painter.end()
    return QIcon(pixmap)

child_icon cached

child_icon(
    kind: str,
    parent_type: str = "Geometry",
    units_defined: bool = True,
    empty: bool = False,
) -> QIcon

Icon for a sub-item, drawn in its parent object's color.

Carries the same undefined-units badge as a top-level icon, so a single channel with no units declared is visible without expanding anything.

Source code in src/visualdynamics/gui/icons.py
@cache
def child_icon(kind: str, parent_type: str = 'Geometry',
               units_defined: bool = True, empty: bool = False) -> QIcon:
    """Icon for a sub-item, drawn in its parent object's color.

    Carries the same undefined-units badge as a top-level icon, so a single
    channel with no units declared is visible without expanding anything.
    """
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    draw = _CHILD_DRAW.get(kind, _draw_default)
    draw(painter, EMPTY_COLOR if empty else COLORS.get(parent_type, '#7f7f7f'))
    if not units_defined:
        _draw_units_badge(painter)
    painter.end()
    return QIcon(pixmap)

quantity_of

quantity_of(dimension: str) -> str | None

The quantity a simple dimension names, if it is one we draw.

Compounds return None; record_icon splits those into their channel factors itself, and the other callers — a channel table's unit, a DOF-arrow quantity — only ever hold simple dimensions.

Source code in src/visualdynamics/gui/icons.py
def quantity_of(dimension: str) -> str | None:
    """The quantity a *simple* dimension names, if it is one we draw.

    Compounds return None; `record_icon` splits those into their channel
    factors itself, and the other callers — a channel table's unit, a
    DOF-arrow quantity — only ever hold simple dimensions.
    """
    dimension = (dimension or '').strip()
    return dimension if dimension in _QUANTITY_DRAW else None

quantity_icon cached

quantity_icon(
    quantity: str, units_defined: bool = True
) -> QIcon

Icon for what a record measures, rather than for what holds it.

Source code in src/visualdynamics/gui/icons.py
@cache
def quantity_icon(quantity: str, units_defined: bool = True) -> QIcon:
    """Icon for what a record measures, rather than for what holds it."""
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    _QUANTITY_DRAW[quantity](painter, QUANTITY_COLORS[quantity])
    if not units_defined:
        _draw_units_badge(painter)
    painter.end()
    return QIcon(pixmap)

record_icon

record_icon(data: DataArray, index: int) -> QIcon

The icon for one record: what that record measures.

A density or a square resolves to its base quantity — a PSD record is accelerations, squared per hertz — and a ratio or a cross term draws both quantities as a fraction, response over reference: an FRF record wears acceleration-over-force, a CPSD cross term the same. Identical factors collapse to the single glyph, and a record whose quantities we cannot draw — a coherence, an undeclared channel — keeps its object's type icon. Undefined units keep their badge either way, and a dimension_hint is enough to choose: a source that said "force" without sizing it has still said what the record is.

Source code in src/visualdynamics/gui/icons.py
def record_icon(data: DataArray, index: int) -> QIcon:
    """The icon for one record: what that record measures.

    A density or a square resolves to its base quantity — a PSD record
    is accelerations, squared per hertz — and a ratio or a cross term
    draws *both* quantities as a fraction, response over reference: an
    FRF record wears acceleration-over-force, a CPSD cross term the
    same. Identical factors collapse to the single glyph, and a record
    whose quantities we cannot draw — a coherence, an undeclared
    channel — keeps its object's type icon. Undefined units keep their
    badge either way, and a `dimension_hint` is enough to choose: a
    source that said "force" without sizing it has still said what the
    record is.
    """
    from ..core.data import channel_quantities

    defined = data.ordinate_dim[index] != 'unknown'
    response, reference = channel_quantities(data.known_dim(index))
    if (response in _QUANTITY_DRAW and reference in _QUANTITY_DRAW
            and response != reference):
        return ratio_icon(response, reference, defined)
    if response in _QUANTITY_DRAW:
        return quantity_icon(response, defined)
    return type_icon(type(data).__name__, defined)

ratio_icon cached

ratio_icon(
    response: str,
    reference: str,
    units_defined: bool = True,
) -> QIcon

Two quantities as a fraction, the way the dimension reads: response upper-left, reference lower-right, a slash between.

Source code in src/visualdynamics/gui/icons.py
@cache
def ratio_icon(response: str, reference: str,
               units_defined: bool = True) -> QIcon:
    """Two quantities as a fraction, the way the dimension reads:
    response upper-left, reference lower-right, a slash between."""
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    scale = 0.58
    painter.save()
    painter.scale(scale, scale)
    _QUANTITY_DRAW[response](painter, QUANTITY_COLORS[response])
    painter.restore()
    painter.save()
    painter.translate(SIZE * (1 - scale), SIZE * (1 - scale))
    painter.scale(scale, scale)
    _QUANTITY_DRAW[reference](painter, QUANTITY_COLORS[reference])
    painter.restore()
    painter.setPen(QPen(QColor('#8e8e93'), 3.0))
    painter.drawLine(QPointF(SIZE * 0.30, SIZE * 0.92),
                     QPointF(SIZE * 0.70, SIZE * 0.08))
    if not units_defined:
        _draw_units_badge(painter)
    painter.end()
    return QIcon(pixmap)

type_icon cached

type_icon(
    type_name: str, units_defined: bool = True
) -> QIcon

Icon for a visualdynamics type, by class name. Requires a running QApplication.

Source code in src/visualdynamics/gui/icons.py
@cache
def type_icon(type_name: str, units_defined: bool = True) -> QIcon:
    """Icon for a visualdynamics type, by class name. Requires a running QApplication."""
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    _DRAW.get(type_name, _draw_default)(painter, COLORS.get(type_name, '#7f7f7f'))
    if not units_defined:
        _draw_units_badge(painter)
    painter.end()
    return QIcon(pixmap)

object_icon

object_icon(obj: Any, units_defined: bool = True) -> QIcon

The icon for an object, which is not always its class's.

A PSD integrated onto proportional bands is still a Psd — same units, same dimension, the same area under it — and deliberately so: everything that reads a spectrum works on either without asking. But the two do not look alike and must not read alike in the tree, so the icon asks the object a question its class name cannot answer.

The same rule as record_icon: what a thing measures, not what holds it.

Source code in src/visualdynamics/gui/icons.py
def object_icon(obj: Any, units_defined: bool = True) -> QIcon:
    """The icon for an object, which is not always its class's.

    A PSD integrated onto proportional bands is still a `Psd` — same
    units, same dimension, the same area under it — and deliberately so:
    everything that reads a spectrum works on either without asking. But
    the two do not *look* alike and must not read alike in the tree, so
    the icon asks the object a question its class name cannot answer.

    The same rule as `record_icon`: what a thing measures, not what
    holds it.
    """
    from ..core.data import Psd

    name = type(obj).__name__
    # `type(obj) is Psd`, not isinstance: Specification subclasses Psd
    # and has an icon of its own to keep
    if type(obj) is Psd and getattr(obj, 'bandwidth', None) is not None:
        name = 'OctavePsd'
    return type_icon(name, units_defined)

placeholder_icon cached

placeholder_icon(type_name: str) -> QIcon

The type's glyph in grey: expected by the project's type, not yet in the project.

Source code in src/visualdynamics/gui/icons.py
@cache
def placeholder_icon(type_name: str) -> QIcon:
    """The type's glyph in grey: expected by the project's type, not
    yet in the project."""
    pixmap = QPixmap(SIZE, SIZE)
    pixmap.fill(Qt.GlobalColor.transparent)
    painter = QPainter(pixmap)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)
    _DRAW.get(type_name, _draw_default)(painter, EMPTY_COLOR)
    painter.end()
    return QIcon(pixmap)

viridis

viridis(t: float) -> QColor

The colour at t in 0..1 on viridis, clamped.

Source code in src/visualdynamics/gui/icons.py
def viridis(t: float) -> QColor:
    """The colour at `t` in 0..1 on viridis, clamped."""
    return QColor(*[round(v) for v in colormap(float(t))])