Skip to content

Plate: add optional stacking_z_height parameter#1110

Merged
rickwierenga merged 1 commit into
PyLabRobot:mainfrom
c-reiter:plate-stacking-z-height
Jun 24, 2026
Merged

Plate: add optional stacking_z_height parameter#1110
rickwierenga merged 1 commit into
PyLabRobot:mainfrom
c-reiter:plate-stacking-z-height

Conversation

@c-reiter

@c-reiter c-reiter commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an optional stacking_z_height parameter to the Plate class — the vertical pitch (in mm) between two identical plates stacked directly on top of each other (i.e. the height one plate adds to a stack: size_z minus the overlap with the plate below).

This mirrors the existing NestedTipRack.stacking_z_height and gives plates the same notion of stacking pitch that nested tip racks already have. It's required by plate-stacker devices (e.g. the Agilent BenchCel I'm adding in #1109) and defaults to None when unknown, so nothing changes for existing labware.

Per the discussion with @rickwierenga: option (b) — add it as an optional param on Plate rather than a new subclass — split out into its own PR.

Changes

  • Plate.__init__: new stacking_z_height: Optional[float] = None parameter, stored on the instance.
  • Plate.__eq__: since stacking_z_height is a physical dimension, plates that differ in it are different labware and now compare unequal. __hash__ is restored to Resource's (defining __eq__ otherwise sets it to None), so plates stay hashable, and stacking_z_height is added to __repr__.
  • Plate.serialize(): new override so stacking_z_height round-trips through deserialize. This also fixes a pre-existing gap where plate_type was silently dropped on serialization (because Plate had no serialize override, so the constructor arg was never persisted — copy() lost it too).
  • ResourceStack: bare plates stacked in the z direction now nest by their stacking pitch. A plate placed directly on another bare plate sinks in by size_z - stacking_z_height, so a stack of N identical plates is size_z + (N - 1) * stacking_z_height tall (both the reported get_size_z() and the child placement). Gated on the value being set, and skipped when the lower plate wears a lid — so existing behavior is unchanged (no library plate sets the value yet). This parallels the lid-nesting ResourceStack already did.
  • Docs: documented stacking_z_height (what it is, how to measure it, why it's needed, and the ResourceStack nesting behavior) on the Plate resource page and the ResourceStack notebook, and added it to the example plate definition in the contributor guide.
  • Tests: Plate — default-is-None, value-stored, serialize/deserialize round-trip (covering both stacking_z_height and plate_type), equality differs on stacking_z_height, hashability. ResourceStack — two/three plates nest, no-nesting without the value (back-compat), and no nesting onto a lidded plate.

Notes

  • No Plate subclasses exist, so adding the keys to serialize() (which deserialize feeds back as constructor kwargs) is safe.
  • Backwards compatible: deserializing older JSON without these keys falls back to the constructor defaults; no existing library plate sets stacking_z_height, so ResourceStack behavior is unchanged for all current labware.

The per-plate vertical pitch when plates are stacked directly on top of
each other. Mirrors `NestedTipRack.stacking_z_height` and is required by
stacker devices such as the Agilent BenchCel. Defaults to `None` when
unknown.

Because `stacking_z_height` is a physical dimension, plates that differ
in it are treated as different labware: `Plate.__eq__` now compares it
(with `__hash__` restored to keep plates hashable), and it is included in
`__repr__`.

Also adds a `Plate.serialize()` override so both `stacking_z_height` and
the pre-existing `plate_type` round-trip through `deserialize` (they were
previously dropped because `Plate` did not override `serialize`).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@c-reiter
c-reiter force-pushed the plate-stacking-z-height branch from 61b3a50 to 3e0f47a Compare June 24, 2026 00:49
@rickwierenga
rickwierenga merged commit d01cad0 into PyLabRobot:main Jun 24, 2026
21 checks passed
@rickwierenga

Copy link
Copy Markdown
Member

thanks!

@BioCam

BioCam commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Nice!

Should the same be applied to PetriDish?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants