Class docstrings

This commit is contained in:
Julian Stirling 2025-07-10 13:26:23 +01:00
parent 11a1fd7f85
commit a30b726b91
16 changed files with 118 additions and 10 deletions

View file

@ -16,6 +16,12 @@ AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocu
class RecentringThing(lt.Thing):
"""A Thing for recentring the stage by monitoring parasitic z motion of the stage.
As the stage moves over a sphere-cap there is parasitic motion in z during xy
movement. The highest z position is the centre of motion.
"""
@lt.thing_action
def recentre(
self,

View file

@ -175,6 +175,13 @@ def _get_capture_index_by_id(captures: list[CaptureInfo], buffer_id: int) -> int
class SharpnessDataArrays(BaseModel):
"""A BaseModel with the position and sharpness data from JPEGSharpnessMonitor.
Each JPEG Size (representing a sharpness metric) has an associated timestamp,
as does each stage position. The stage positions need to be interpolated so
they correspond with the image timestamps.
"""
jpeg_times: NDArray
jpeg_sizes: NDArray
stage_times: NDArray
@ -182,6 +189,21 @@ class SharpnessDataArrays(BaseModel):
class JPEGSharpnessMonitor:
"""A class with direct access to the CameraThing for monitoring the MJPEG stream.
The autofocus algorithm uses sharpness calculated from the file size of the
images in the MJPEG stream. This class monitors both the stage position and the
jpeg sharpness over time.
The ``run`` context manager is used to start monitoring the camera stream. Position
monitoring happens during ``focus_rel``. Raw data can be retrieved with
``data_dict`` and data with interpolate ``z`` positions can be retrieved with
move_data.
A new JPEGSharpnessMonitor instance is created each time an action with the
SharpnessMonitorDep as an argument is called.
"""
def __init__(self, stage: Stage, camera: Camera, portal: lt.deps.BlockingPortal):
self.camera = camera
self.stage = stage
@ -564,7 +586,7 @@ class AutofocusThing(lt.Thing):
) -> tuple[bool, list[CaptureInfo], Optional[int]]:
"""Capture a series of images checking that sharpest image central.
The images are seperated in z offset by stack_parameters.stack_dz, as they
The images are separated in z offset by stack_parameters.stack_dz, as they
are captured the last stack_parameters.min_images_to_test images are checked
to see if the sharpest image is central enough in the stack. If it is the stack
completes.
@ -577,7 +599,7 @@ class AutofocusThing(lt.Thing):
* the stack result (True for successful stack, False for failed stack),
* a list of CaptureInfo objects,
* the buffer_id of the shapest image (or None if the stack failed)
* the buffer_id of the sharpest image (or None if the stack failed).
"""
# Move down by the height of the z stack, plus an overshoot
# Better to start too low and take too many images than too high and need to refocus

View file

@ -17,12 +17,24 @@ from .camera import CameraDependency as CamDep
class ChannelDistributions(BaseModel):
"""A BaseModel for storing the channel distribution of a background image."""
means: list[float]
"""The mean of each channel in the colourspace."""
standard_deviations: list[float]
"""The standard deviation of each channel in the colourspace."""
colorspace: str = "LUV"
"""The colourspace used."""
class BackgroundDetectThing(lt.Thing):
"""Thing for setting a background image and detecting sample in the field of view.
This uses an LUV colour space checking only the mean and standard deviation of the
UV channels. Over time different, selectable, background detection methods will be
added.
"""
# Requires a getter and a setter to support being a BaseModel but being
# saved to file as a dict
_background_distributions: Optional[ChannelDistributions] = None

View file

@ -19,6 +19,8 @@ from labthings_fastapi.types.numpy import NDArray
class JPEGBlob(lt.blob.Blob):
"""A class representing a JPEG image as a LabThings FastAPI Blob."""
media_type: str = "image/jpeg"

View file

@ -45,6 +45,14 @@ XYCoordinateType = Tuple[float, float]
class HardwareInterfaceModel(BaseModel):
"""A pydantic base model for a stage and camera interface.
This class provides access to both the stage and the camera, but
it is confusing both because it is a BaseModel of callables rather
than a class with methods, and because it uses names from the underlying
Thing actions, but performs different actions.
"""
move: Callable[[NDArray], None]
get_position: Callable[[], NDArray]
grab_image: Callable[[], NDArray]
@ -123,6 +131,14 @@ HardwareInterfaceDep = Annotated[
class MoveHistory(NamedTuple):
"""A named tuple containing the position over time for a single move.
This a named tuple with elements:
* ``times``
* ``stage_positions``
"""
times: List[float]
stage_positions: List[CoordinateType]
@ -163,6 +179,13 @@ class LoggingMoveWrapper:
class CSMUncalibratedError(HTTPException):
"""An HTTP Exception raised if camera stage mapping data is needed but unavailable.
Camera Stage Mapping data is needed to convert from distances specified in fractions
of the feild of view to distances in motor steps. This is used when clicking on the
live preview to move, or when performing a scan.
"""
def __init__(self):
HTTPException.__init__(
self,
@ -186,9 +209,8 @@ class CameraStageMapper(lt.Thing):
direction: Tuple[float, float, float],
) -> DenumpifyingDict:
"""Move a microscope's stage in 1D, and figure out the relationship with the camera."""
move = LoggingMoveWrapper(
hw.move
) # log positions and times for stage calibration
# log positions and times for stage calibration
move = LoggingMoveWrapper(hw.move)
tracker = Tracker(hw.grab_image, hw.get_position, settle=hw.settle)
direction_array: np.ndarray = np.array(direction)

View file

@ -43,6 +43,12 @@ def nested_dict_get(data: dict, key: Sequence[str], create=False) -> Any:
class SettingsManager(lt.Thing):
"""Provides functionality to other Things about the current server state.
The SettingsManager is used to get information the microscope ID, the hostname
and the state of other Things.
"""
external_metadata = lt.ThingSetting(
initial_value={},
model=Mapping,

View file

@ -75,6 +75,13 @@ def _scan_running(method):
class SmartScanThing(lt.Thing):
"""A Thing for scanning samples and interacting with past scans.
SmartScanThing exposes all functionality for automatically scanning samples,
previewing live stitching, retrieving data from past scans, and for deleting
past scans.
"""
def __init__(self, scans_folder):
self._scan_dir_manager = scan_directories.ScanDirectoryManager(scans_folder)
self._preview_stitch_popen = None

View file

@ -10,6 +10,8 @@ from pydantic import BaseModel
class CommandOutput(BaseModel):
"""A pydantic model passing the STDOUT and STDERR from a subprocess over HTTP."""
output: str
error: str