# Panels

The dock panels and what they draw: build123d compounds in the scene, plotly figures and grouped tables.

## femforge\_workbench.panels

Panel components: one trame template per dock panel, built inside its DivLayout with state namespaced by panel id.

Modules:

- **`artifacts`** –

  The artifact browser: the telemetry artifact index in a table, with one artifact's record, files and spec beside it.
- **`browsers`** –

  The browsers workbench: the run index over one run's detail, beside the artifact index over one artifact's detail.
- **`field_viewer`** –

  The field viewer: a controller that opens a run's VTU as a FieldScene, the controls that steer it, and the 3D and plotly 2D views that show it.
- **`figure`** –

  The plotly panel: a figure that fills its dock tab, updated in place and bound to plotly events.
- **`launcher`** –

  The launcher panel: the catalogue as cards that open docks and renderables and run and stop scripts.
- **`log`** –

  The log panel: an xterm terminal fed line by line from the server loop, with a ring buffer replayed to clients that mount later.
- **`log_browser`** –

  The log browser: the telemetry log frame narrowed in polars, and a live mode following this process's tap and every other process's journal.
- **`monitors`** –

  The live monitors workbench: the run monitor beside the sweep monitor, over the log browser and the terminal as tabs.
- **`outputs`** –

  The outputs panel: one toggle per declared output of a catalogue card, each shown by its kind, the whole set swapped by show().
- **`run_monitor`** –

  The run monitor: the selected run's heartbeat, stage strip, convergence chart and a log tail, polled every second while visible.
- **`runs`** –

  The run browser: the telemetry run index in a table, with one bundle's stages, results, files and retention beside it.
- **`scene`** –

  The scene panels: one off-screen pyvista plotter each, mirrored in the browser by VTK.wasm or streamed by trame-rca, under a preset toolbar.
- **`sweep_monitor`** –

  The sweep monitor: a sweep's progress, its points grouped by state with dead workers marked stalled, and the failures with their tracebacks.
- **`table`** –

  The table panel: a TanStack table over a polars frame that sorts, filters, facets, hides and groups in the client, with the layout persisted per panel.
- **`terminal`** –

  The terminal panel: an xterm attached to a local shell or an Elmer container through a pseudo-terminal bridged on the server loop.

Type Aliases:

- **`Handler`** –

  A client event handler, called with the values its JS arguments evaluate to.
- **`Listener`** –

  A state listener, called with the changed state as keyword arguments.

Classes:

- **`Cls`** –

  Tailwind compositions the panels share; the strings appear literally so the stylesheet build scans them.
- **`Shared`** –

  The state keys panels share: a selection made in one panel is read by the others.
- **`ItemField`** –

  The keys of a picker item: the label shown, the value chosen and, optionally, whether it is offered but unavailable.
- **`Carry`** –

  What a disposed panel leaves in `legacy` for the panel rebuilt in its place.
- **`PanelComponent`** –

  A dock panel: its template is built once inside `layout`; state variables go through `key`.

Functions:

- **`labelled`** –

  A caption beside the control built inside the returned field: a toolbar row has no room for a floating label.
- **`chooser`** –

  A single-choice select over fixed values, bound to a state variable.
- **`picker`** –

  A single-choice select over the `{title, value}` items a state variable holds, bound to another.
- **`select_run`** –

  Publishes `run_id` as the shared selection; picking the selected run again still notifies every listener, so each one re-reads the run.

Attributes:

- **`FILL`** –

  The style of a panel's root: a column filling the dock body.
- **`TRIGGER_WIDTH`** –

  The default width of a toolbar select; a picker over long ids widens it.
- **`ITEM`** –

  The loop variable a picker's items are named by.

### FILL

```python
FILL = {'height': '100%', 'width': '100%', 'display': 'flex', 'flexDirection': 'column', 'minHeight': '0'}
```

The style of a panel's root: a column filling the dock body.

### TRIGGER\_WIDTH

```python
TRIGGER_WIDTH = 'w-36'
```

The default width of a toolbar select; a picker over long ids widens it.

### ITEM

```python
ITEM = 'item'
```

The loop variable a picker's items are named by.

### Listener

```python
Listener = Callable[..., object]
```

A state listener, called with the changed state as keyword arguments.

### Handler

```python
Handler = Callable[..., object]
```

A client event handler, called with the values its JS arguments evaluate to.

### Cls

Bases: `StrEnum`

Tailwind compositions the panels share; the strings appear literally so the stylesheet build scans them.

### Shared

Bases: `StrEnum`

The state keys panels share: a selection made in one panel is read by the others.

### ItemField

Bases: `StrEnum`

The keys of a picker item: the label shown, the value chosen and, optionally, whether it is offered but unavailable.

### Carry

Bases: `StrEnum`

What a disposed panel leaves in `legacy` for the panel rebuilt in its place.

### PanelComponent

```python
PanelComponent(app: Workbench, id: str, title: str)
```

Bases: `TrameComponent`

A dock panel: its template is built once inside `layout`; state variables go through `key`.

Parameters:

- **`app`** (`Workbench`) –

  The workbench shell the panel is built in.
- **`id`** (`str`) –

  The panel id, which names its template and namespaces its state.
- **`title`** (`str`) –

  The panel's tab title.

Methods:

- **`build`** –

  Adds the panel's widgets to its layout.
- **`key`** –

  A state variable or trigger name namespaced to this panel.
- **`status`** –

  Reports in the shell's status line.
- **`refresh`** –

  Pushes the template again after its widgets changed.
- **`callback`** –

  A client event handler calling `fn` with the JS `args`, unregistered again when the panel is disposed.
- **`listen`** –

  Registers a state listener like `state.change`, one the panel drops again when disposed.
- **`dispose`** –

  Releases what the panel registered on the server once it left the dock: triggers, state listeners and controller slots.
- **`succeed`** –

  Called on a panel rebuilt under the id of `previous`, already disposed, to carry over what a fresh build would lose.
- **`on_visible`** –

  Called when dockview shows or hides the panel.
- **`on_layout_changed`** –

  Called after the dock re-laid out its groups.

Attributes:

- **`listeners`** (`list[Listener]`) –

  The state listeners registered through `listen`, dropped again by `dispose`.
- **`bound`** (`list[Handler]`) –

  The callables handed to `callback`, whose triggers `dispose` unregisters.
- **`legacy`** (`dict[Carry, object]`) –

  What `dispose` leaves for a successor; read by its `succeed`, never through the reloadable classes.

#### listeners

```python
listeners: list[Listener] = []
```

The state listeners registered through `listen`, dropped again by `dispose`.

#### bound

```python
bound: list[Handler] = []
```

The callables handed to `callback`, whose triggers `dispose` unregisters.

#### legacy

```python
legacy: dict[Carry, object] = {}
```

What `dispose` leaves for a successor; read by its `succeed`, never through the reloadable classes.

#### build

```python
build() -> None
```

Adds the panel's widgets to its layout.

#### key

```python
key(name: str) -> str
```

A state variable or trigger name namespaced to this panel.

#### status

```python
status(message: str) -> None
```

Reports in the shell's status line.

#### refresh

```python
refresh() -> None
```

Pushes the template again after its widgets changed.

#### callback

```python
callback(fn: Handler, args: str | None = None) -> Callback
```

A client event handler calling `fn` with the JS `args`, unregistered again when the panel is disposed.

#### listen

```python
listen(*names: str) -> Callable[[L], L]
```

Registers a state listener like `state.change`, one the panel drops again when disposed.

#### dispose

```python
dispose() -> None
```

Releases what the panel registered on the server once it left the dock: triggers, state listeners and controller slots.

#### succeed

```python
succeed(previous: PanelComponent) -> None
```

Called on a panel rebuilt under the id of `previous`, already disposed, to carry over what a fresh build would lose.

#### on\_visible

```python
on_visible(visible: bool) -> None
```

Called when dockview shows or hides the panel.

#### on\_layout\_changed

```python
on_layout_changed() -> None
```

Called after the dock re-laid out its groups.

### labelled

```python
labelled(label: str) -> Field
```

A caption beside the control built inside the returned field: a toolbar row has no room for a floating label.

### chooser

```python
chooser(model: str, values: Sequence[str], *, width: str = TRIGGER_WIDTH, disabled: bool = False, label: Callable[[str], str] = title) -> None
```

A single-choice select over fixed values, bound to a state variable.

Parameters:

- **`model`** (`str`) –

  The state variable the choice is bound to.
- **`values`** (`Sequence[str]`) –

  The values offered, in order.
- **`width`** (`str`, default: `TRIGGER_WIDTH` ) –

  The trigger's Tailwind width class.
- **`disabled`** (`bool`, default: `False` ) –

  Whether the select is disabled.
- **`label`** (`Callable[[str], str]`, default: `title` ) –

  Makes the text each value reads as; Title Case by default.

### picker

```python
picker(model: str, items: str, *, placeholder: str = '', width: str = TRIGGER_WIDTH, disabled: bool = False) -> None
```

A single-choice select over the `{title, value}` items a state variable holds, bound to another.

Parameters:

- **`model`** (`str`) –

  The state variable the choice is bound to.
- **`items`** (`str`) –

  The state variable holding the items.
- **`placeholder`** (`str`, default: `''` ) –

  The text shown while nothing is chosen.
- **`width`** (`str`, default: `TRIGGER_WIDTH` ) –

  The trigger's Tailwind width class.
- **`disabled`** (`bool`, default: `False` ) –

  Whether the select is disabled.

### select\_run

```python
select_run(state: State, run_id: str) -> None
```

Publishes `run_id` as the shared selection; picking the selected run again still notifies every listener, so each one re-reads the run.

## femforge\_workbench.compound

A build123d Compound as a Renderable: instanced VTK actors with view-dependent silhouettes.

Classes:

- **`CompoundRenderable`** –

  A Renderable over a build123d Compound; the push to the OCP CAD Viewer is opt-in through `ocp_vscode` or FEMFORGE\_OCP\_VSCODE.

### CompoundRenderable

```python
CompoundRenderable(compound: Compound, *, ocp_vscode: bool | None = None)
```

A Renderable over a build123d Compound; the push to the OCP CAD Viewer is opt-in through `ocp_vscode` or FEMFORGE\_OCP\_VSCODE.

Methods:

- **`render`** –

  Draw the compound into `plotter` under a top-down parallel projection; the plotter keeps its own background and anti-aliasing.

#### render

```python
render(plotter: Plotter) -> None
```

Draw the compound into `plotter` under a top-down parallel projection; the plotter keeps its own background and anti-aliasing.

## femforge\_workbench.b3d\_pv

Instanced VTK actors for a build123d Compound, with silhouettes and feature edges drawn over them.

Classes:

- **`Build123Instancer`** –

  Converts a build123d Compound hierarchy into instanced VTK actors: each unique shape meshed once, every occurrence an actor with its own world matrix and color.

### Build123Instancer

```python
Build123Instancer(tolerance: float = 0.1, angular_tolerance: float = 0.5, default_color: tuple[float, float, float] = (0.9137, 0.6941, 0.1529))
```

Converts a build123d Compound hierarchy into instanced VTK actors: each unique shape meshed once, every occurrence an actor with its own world matrix and color.

Parameters:

- **`tolerance`** (`float`, default: `0.1` ) –

  The linear deflection the shapes are meshed to.
- **`angular_tolerance`** (`float`, default: `0.5` ) –

  The angular deflection the shapes are meshed to, in radians.
- **`default_color`** (`tuple[float, float, float]`, default: `(0.9137, 0.6941, 0.1529)` ) –

  The RGB color of a shape that carries none.

Methods:

- **`parse`** –

  Replaces the actors with one per leaf of `obj`'s hierarchy.
- **`add_to_plotter`** –

  Adds every actor to `plotter`.
- **`show`** –

  Shows the actors in a new plotter window, passing `kwargs` to its show.
- **`add_silhouettes`** –

  Adds a view-dependent silhouette per instance, recomputed on every camera move, so `add_feature_edges` suits large assemblies better.
- **`add_feature_edges`** –

  Adds each instance's crease and boundary edges, computed once per unique shape; smooth bodies show little.

#### parse

```python
parse(obj: Compound) -> Build123Instancer
```

Replaces the actors with one per leaf of `obj`'s hierarchy.

#### add\_to\_plotter

```python
add_to_plotter(plotter: Plotter) -> Plotter
```

Adds every actor to `plotter`.

#### show

```python
show(**kwargs) -> Plotter
```

Shows the actors in a new plotter window, passing `kwargs` to its show.

#### add\_silhouettes

```python
add_silhouettes(plotter: Plotter, color: str | tuple[float, float, float] = 'black', line_width: float = 1.5, opacity: float = 1.0, feature_angle: float | None = 70.0, border_edges: bool = True) -> list[vtkActor]
```

Adds a view-dependent silhouette per instance, recomputed on every camera move, so `add_feature_edges` suits large assemblies better.

Parameters:

- **`plotter`** (`Plotter`) –

  The plotter to add the silhouettes to.
- **`color`** (`str | tuple[float, float, float]`, default: `'black'` ) –

  The line color.
- **`line_width`** (`float`, default: `1.5` ) –

  The line width, in pixels.
- **`opacity`** (`float`, default: `1.0` ) –

  The line opacity.
- **`feature_angle`** (`float | None`, default: `70.0` ) –

  The angle above which a crease draws too, in degrees; None draws the rim alone.
- **`border_edges`** (`bool`, default: `True` ) –

  Draws the mesh's border edges too.

#### add\_feature\_edges

```python
add_feature_edges(plotter: Plotter, color: str | tuple[float, float, float] = 'black', line_width: float = 1.5, opacity: float = 1.0, feature_angle: float = 30.0, boundary_edges: bool = True) -> list[vtkActor]
```

Adds each instance's crease and boundary edges, computed once per unique shape; smooth bodies show little.

Parameters:

- **`plotter`** (`Plotter`) –

  The plotter to add the edges to.
- **`color`** (`str | tuple[float, float, float]`, default: `'black'` ) –

  The line color.
- **`line_width`** (`float`, default: `1.5` ) –

  The line width, in pixels.
- **`opacity`** (`float`, default: `1.0` ) –

  The line opacity.
- **`feature_angle`** (`float`, default: `30.0` ) –

  The angle above which a crease draws, in degrees.
- **`boundary_edges`** (`bool`, default: `True` ) –

  Draws the mesh's boundary edges too.

## femforge\_workbench.plotly

Figure conventions in the dock: the tab carries the title on screen, layout.meta.title names the figure for export.

Functions:

- **`layout_json`** –

  The figure's layout as plain JSON.
- **`title_of`** –

  The name a figure gives itself: layout.meta.title, else its on-screen title, else empty.
- **`export_options`** –

  The modebar's toImageButtonOptions: a 2x PNG named after the figure's title.
- **`with_title`** –

  A copy of the figure carrying its export title centred at the top, with the margin that needs.

### layout\_json

```python
layout_json(figure: Figure) -> Json
```

The figure's layout as plain JSON.

### title\_of

```python
title_of(figure: Figure) -> str
```

The name a figure gives itself: layout.meta.title, else its on-screen title, else empty.

### export\_options

```python
export_options(figure: Figure) -> Json
```

The modebar's toImageButtonOptions: a 2x PNG named after the figure's title.

### with\_title

```python
with_title(figure: Figure) -> Figure
```

A copy of the figure carrying its export title centred at the top, with the margin that needs.

## femforge\_workbench.plotting

Figure helpers: the regular grid a scatter of samples needs before it can draw as a surface.

Functions:

- **`xyz_to_meshgrid`** –

  Cubic-interpolates scattered (x, y, z) samples onto a regular grid for surface plotting.

### xyz\_to\_meshgrid

```python
xyz_to_meshgrid(x: PlotData, y: PlotData, z: PlotData, grid_points: int = 100) -> tuple[PlotData, PlotData, PlotData]
```

Cubic-interpolates scattered (x, y, z) samples onto a regular grid for surface plotting.

Parameters:

- **`x`** (`PlotData`) –

  The samples' x coordinates.
- **`y`** (`PlotData`) –

  The samples' y coordinates.
- **`z`** (`PlotData`) –

  The sample values.
- **`grid_points`** (`int`, default: `100` ) –

  The grid's point count along each axis.

## femforge\_workbench.grid

Grouped rows on polars frames: a composite label per group for the tables to group by.

Type Aliases:

- **`Row`** –

  A table row: each column's value by name.

Functions:

- **`group_rows`** –

  The frame with a group label per `by` value: the value, the first of each `first` column, the row count and the maximum of each `max_` column.

Attributes:

- **`GROUP_COLUMN`** –

  The column group\_rows adds and the tables group by; reserved in every frame a table shows.

### GROUP\_COLUMN

```python
GROUP_COLUMN = 'group'
```

The column group\_rows adds and the tables group by; reserved in every frame a table shows.

### Row

```python
Row = dict[str, object]
```

A table row: each column's value by name.

### group\_rows

```python
group_rows(frame: DataFrame, by: str, first: Sequence[str] = (), max_: Sequence[str] = ()) -> DataFrame
```

The frame with a group label per `by` value: the value, the first of each `first` column, the row count and the maximum of each `max_` column.

Parameters:

- **`frame`** (`DataFrame`) –

  The rows to label.
- **`by`** (`str`) –

  The column whose values form the groups.
- **`first`** (`Sequence[str]`, default: `()` ) –

  Columns whose first value per group joins the label.
- **`max_`** (`Sequence[str]`, default: `()` ) –

  Columns whose maximum per group joins the label.
