Skip to content

visualdynamics.plot.bars

bars

The comparison as bar charts: a bar per control channel.

A table of six channels is read; a table of sixty is scanned, and the one channel that matters is somewhere in it. A bar chart is the same numbers arranged so the answer is the shape rather than a row — which channel is worst, how many are out, and by how much, before anything is read at all.

Two charts, because a random vibration run is judged two ways and they disagree often enough to be worth seeing apart. RMS error is the level: how far the whole channel sits from what was asked for, in dB. Lines outside abort is the shape: a channel can sit at exactly the right level and still be out of tolerance across half its band, and one that is 2 dB low everywhere may never cross an abort limit at all.

A threshold is drawn as shaded ground rather than as a line: what is being said is "past here is out", and a filled region says it where a line leaves it to be inferred — red past the upper, blue past the lower, the same two colours the specification plot shades its abort zones with. The shading is the handle, and dragging it snaps to a tenth of a dB or of a percent. A tolerance is a judgement — ±3 dB and a tenth of the band are where most specifications land, not where they all do — so those are a starting point, and everything reads off wherever they are put. In a report they are drawn and not moved: there is nobody on the other end of a drag in a file.

Classes:

Name Description
BarChart

A bar per channel, a threshold that can be dragged, and a count.

Functions:

Name Description
error_chart

How far each channel's RMS sits from what was asked for, in dB.

lines_chart

How much of each channel's band fell outside its abort limits.

level_chart

The RMS level each channel of a specification asks for, a bar

kurtosis_chart

How Gaussian each channel is: Pearson kurtosis, a bar apiece.

replication_chart

One reading of a transient replication, a bar per control channel.

Classes

BarChart

BarChart(
    plot: Any,
    rows: Sequence[tuple[str, float]],
    colors: Mapping[str, str],
    low: float | None,
    high: float | None = None,
    changed: Callable[..., None] | None = None,
    label: str = "",
    units: str = "",
    neutral: str = "response_curve",
    baseline: float = 0.0,
)

A bar per channel, a threshold that can be dragged, and a count.

Owns its plot. changed is called with the thresholds whenever one is moved, so whoever put the chart up can remember where they were put — a threshold that reset on every redraw would be no threshold at all.

Methods:

Name Description
beyond

Which way this bar is out, or None.

share

The percentage of channels outside, wherever the lines are.

set_threshold

Move a threshold, snapped, and restate everything from it.

Source code in src/visualdynamics/plot/bars.py
def __init__(self, plot: Any, rows: Sequence[tuple[str, float]], colors: Mapping[str, str],
             low: float | None, high: float | None = None,
             changed: Callable[..., None] | None = None,
             label: str = '', units: str = '',
             neutral: str = 'response_curve',
             baseline: float = 0.0) -> None:
    self.plot: Any = plot
    self.rows: list[Any] = list(rows)
    self.colors: dict[str, str] = colors
    #: the thresholds; `low` None is a chart with none at all — a
    #: level chart, where nothing is out and nothing is coloured
    self.low: float | None = None if low is None else float(low)
    self.high: float | None = None if high is None else float(high)
    self.changed: Callable[..., None] | None = changed
    self.label: str | None = label
    self.units: str | None = units
    #: what a bar inside the thresholds is painted. The ink by
    #: default — a comparison's in-tolerance channels are the
    #: subject of the chart — but a reading whose whole point is
    #: the *exception* stands its ordinary channels back in grey
    #: (the kurtosis chart, Brandon 2026-08-24), which is also
    #: what the report has always drawn there.
    self.neutral: str = neutral
    #: where a bar grows from. Zero for a reading whose zero means
    #: 'no error at all'; the *nominal* for one that has a nominal
    #: — a kurtosis bar drawn from zero is three units of
    #: agreement dressed up as a measurement, where drawn from
    #: three it is the departure from Gaussian and reads both ways
    #: (Brandon, 2026-08-24).
    self.baseline: float = float(baseline)
    #: the bars themselves, one item holding all of them
    self.bars: Any = None
    self.lines: list[Any] = []
    self.summary: Any = None
    self._moving = False
    self._draw()
Methods:
beyond
beyond(value: float) -> str | None

Which way this bar is out, or None.

A one-sided chart has a ceiling and no floor: no amount of staying inside the abort limits is a fault.

Source code in src/visualdynamics/plot/bars.py
def beyond(self, value: float) -> str | None:
    """Which way this bar is out, or None.

    A one-sided chart has a ceiling and no floor: no amount of
    staying inside the abort limits is a fault.
    """
    if not np.isfinite(value) or self.low is None:
        return None
    if self.high is None:
        return 'over' if value >= self.low else None
    if value > self.high:
        return 'over'
    if value < self.low:
        return 'under'
    return None
share
share() -> float

The percentage of channels outside, wherever the lines are.

Source code in src/visualdynamics/plot/bars.py
def share(self) -> float:
    """The percentage of channels outside, wherever the lines are."""
    if self.low is None:
        return 0.0
    return outside_fraction(self.values(), self.low, self.high)
set_threshold
set_threshold(which: str, value: float) -> None

Move a threshold, snapped, and restate everything from it.

What dragging the shading does, and what a caller does to set one outright — one path, so a dragged threshold and a stored one cannot land on different numbers.

Source code in src/visualdynamics/plot/bars.py
def set_threshold(self, which: str, value: float) -> None:
    """Move a threshold, snapped, and restate everything from it.

    What dragging the shading does, and what a caller does to set
    one outright — one path, so a dragged threshold and a stored one
    cannot land on different numbers.
    """
    if self._moving:
        return
    # rounded twice: the second one is only to keep binary
    # floating point from turning 2.9 into 2.9000000000000004
    position = round(round(float(value) / SNAP) * SNAP, 10)
    if which == 'low':
        self.low = position
    else:
        self.high = position
    self._moving = True
    try:
        self._restate()
        if self.changed is not None:
            self.changed(self.low, self.high)
    finally:
        self._moving = False

Functions:

error_chart

error_chart(
    plot: Any,
    rows: Sequence[tuple[str, float, float]],
    colors: Mapping[str, str],
    low: float = -ERROR_DB,
    high: float = ERROR_DB,
    changed: Callable[..., None] | None = None,
) -> BarChart

How far each channel's RMS sits from what was asked for, in dB.

Two thresholds, moved independently: a specification is not always written symmetrically, and over-testing and under-testing are not the same fault.

Source code in src/visualdynamics/plot/bars.py
def error_chart(plot: Any, rows: Sequence[tuple[str, float, float]],
                colors: Mapping[str, str], low: float = -ERROR_DB,
                high: float = ERROR_DB,
                changed: Callable[..., None] | None = None) -> BarChart:
    """How far each channel's RMS sits from what was asked for, in dB.

    Two thresholds, moved independently: a specification is not always
    written symmetrically, and over-testing and under-testing are not
    the same fault.
    """
    return BarChart(plot, [(label, value) for label, value, _p in rows],
                    colors, low=low, high=high, changed=changed,
                    label='RMS error', units='dB')

lines_chart

lines_chart(
    plot: Any,
    rows: Sequence[tuple[str, float, float]],
    colors: Mapping[str, str],
    low: float = LINES_PERCENT,
    changed: Callable[..., None] | None = None,
) -> BarChart

How much of each channel's band fell outside its abort limits.

Source code in src/visualdynamics/plot/bars.py
def lines_chart(plot: Any, rows: Sequence[tuple[str, float, float]],
                colors: Mapping[str, str], low: float = LINES_PERCENT,
                changed: Callable[..., None] | None = None) -> BarChart:
    """How much of each channel's band fell outside its abort limits."""
    return BarChart(plot, [(label, percent) for label, _v, percent in rows],
                    colors, low=low, high=None, changed=changed,
                    label='lines outside abort', units='%')

level_chart

level_chart(
    plot: Any,
    rows: Sequence[tuple[str, float]],
    colors: Mapping[str, str],
    units: str = "",
) -> BarChart

The RMS level each channel of a specification asks for, a bar apiece — the table's column as a picture, so which channel is loudest is seen before anything is read. No thresholds: a specification on its own has nothing to be out of (Brandon, 2026-09-06: the RMS error reading without the ±3 dB colouring).

Source code in src/visualdynamics/plot/bars.py
def level_chart(plot: Any, rows: Sequence[tuple[str, float]],
                colors: Mapping[str, str], units: str = '') -> BarChart:
    """The RMS level each channel of a specification asks for, a bar
    apiece — the table's column as a picture, so which channel is
    loudest is seen before anything is read. No thresholds: a
    specification on its own has nothing to be out of (Brandon,
    2026-09-06: the RMS error reading without the ±3 dB colouring).
    """
    return BarChart(plot, list(rows), colors, low=None, high=None,
                    label='RMS level', units=units,
                    neutral='specification_curve')

kurtosis_chart

kurtosis_chart(
    plot: Any,
    rows: Sequence[tuple[str, float]],
    colors: Mapping[str, str],
    low: float = LOW,
    high: float = HIGH,
    changed: Callable[..., None] | None = None,
) -> BarChart

How Gaussian each channel is: Pearson kurtosis, a bar apiece.

Two thresholds around the nominal three, because both directions say something — above, peaks the spectrum never predicted; below, a record that has been clipped or was never random. The ordinary channels stand back in grey so the exceptions are the chart.

Every channel whatever it measures: kurtosis is dimensionless, so this is the one reading here where accelerations and forces share an axis honestly.

Source code in src/visualdynamics/plot/bars.py
def kurtosis_chart(plot: Any, rows: Sequence[tuple[str, float]],
                   colors: Mapping[str, str],
                   low: float = KURTOSIS_LOW, high: float = KURTOSIS_HIGH,
                   changed: Callable[..., None] | None = None) -> BarChart:
    """How Gaussian each channel is: Pearson kurtosis, a bar apiece.

    Two thresholds around the nominal three, because both directions
    say something — above, peaks the spectrum never predicted; below,
    a record that has been clipped or was never random. The ordinary
    channels stand back in grey so the exceptions are the chart.

    Every channel whatever it measures: kurtosis is dimensionless, so
    this is the one reading here where accelerations and forces share
    an axis honestly.
    """
    return BarChart(plot, list(rows), colors, low=low, high=high,
                    changed=changed, label='Pearson kurtosis', units='',
                    neutral='specification_curve', baseline=NOMINAL)

replication_chart

replication_chart(
    plot: Any,
    rows: Sequence[tuple[str, float]],
    colors: Mapping[str, str],
    which: str,
    low: float,
    high: float | None,
    changed: Callable[..., None] | None = None,
) -> BarChart

One reading of a transient replication, a bar per control channel.

rows is [(label, value)] already reduced to the reading wanted — which repeat those values came from is the caller's business, and on screen it is the one the event box is pointing at.

Source code in src/visualdynamics/plot/bars.py
def replication_chart(plot: Any, rows: Sequence[tuple[str, float]], colors: Mapping[str, str],
                      which: str, low: float, high: float | None,
                      changed: Callable[..., None] | None = None
                      ) -> BarChart:
    """One reading of a transient replication, a bar per control channel.

    `rows` is [(label, value)] already reduced to the reading wanted —
    which repeat those values came from is the caller's business, and
    on screen it is the one the event box is pointing at.
    """
    label, units = REPLICATION_LABELS[which]
    return BarChart(plot, list(rows), colors, low=low, high=high,
                    changed=changed, label=label, units=units)