GridImage Class Methods#
Overview#
The GridImage class extends Image to support grid-based processing
and overlay visualization for arrayed samples on agar plates or other gridded microbe
cultures. It combines complete image processing capabilities with grid-aware operations,
enabling well-level detection, measurement, and visualization.
This class is designed for high-throughput phenotyping workflows where colonies are arranged in regular arrays such as:
96-well plates: 8 rows × 12 columns
384-well plates: 16 rows × 24 columns
1536-well plates: 32 rows × 48 columns
Custom arrays: Any regular grid pattern
The class automatically manages grid detection and alignment, supports grid-based slicing to extract individual well images, and provides overlay visualizations with gridlines, well labels, and measurements aligned to the detected grid structure.
Initialization & Creation#
- GridImage.__init__(arr: ndarray | Image | PathLike | Path | str | None = None, name: str | None = None, grid_finder: GridFinder | None = None, nrows: int = 8, ncols: int = 12, bit_depth: Literal[8, 16] | None = None, illuminant: str | None = 'D65', gamma: GAMMA_ENCODINGS | str | None = GAMMA_ENCODINGS.SRGB)[source]#
Initialize a GridImage with grid-based processing capabilities.
Creates a new GridImage instance with support for grid detection, well-level analysis, and grid-aligned visualization. Inherits all image processing capabilities from the parent hierarchy while adding grid-specific features.
- Parameters:
arr (np.ndarray | Image | PathLike | Path | str | None) – Initial image data. Can be a NumPy array (2-D grayscale or 3-D RGB), an Image instance, a file path string, or None for an empty image. Defaults to None.
name (str | None) – Human-readable name for the image. If None, uses the image UUID. Defaults to None.
grid_finder (Optional[GridFinder]) – Custom grid detection algorithm. If None, an AutoGridFinder is instantiated with the specified nrows and ncols. Defaults to None.
nrows (int) – Number of rows in the grid structure. Used only if grid_finder is None. Typical values: 8 (96-well), 16 (384-well), 32 (1536-well). Defaults to 8.
ncols (int) – Number of columns in the grid structure. Used only if grid_finder is None. Typical values: 12 (96-well), 24 (384-well), 48 (1536-well). Defaults to 12.
bit_depth (Literal[8, 16] | None) – Bit depth of the image (8 or 16 bits). If None, automatically inferred from arr dtype. Defaults to None.
illuminant (str | None) – Reference illuminant for color calculations. ‘D65’ (standard daylight) or ‘D50’ (imaging illuminant). Defaults to ‘D65’.
gamma (GAMMA_ENCODINGS) – Gamma encoding for color correction. GAMMA_ENCODINGS.SRGB for gamma-corrected images, GAMMA_ENCODINGS.LINEAR for linear RGB. Defaults to GAMMA_ENCODINGS.SRGB.
- Raises:
ValueError – If illuminant is not ‘D65’ or ‘D50’.
ValueError – If gamma is not a GAMMA_ENCODINGS member.
TypeError – If arr is provided but is not a valid image type.
Examples
Create from a plate image file:
>>> from phenotypic import GridImage >>> # Load plate image with 96-well grid (8 rows x 12 cols) >>> grid_img = GridImage('plate_scan.jpg', nrows=8, ncols=12) >>> grid_img.show(overlay=True, show_grid=True)
Create with custom grid finder:
>>> from phenotypic import GridImage >>> from phenotypic.grid import AutoGridFinder >>> finder = AutoGridFinder(nrows=16, ncols=24) # 384-well plate >>> grid_img = GridImage('plate_384.jpg', grid_finder=finder) >>> print(grid_img.nrows, grid_img.ncols) # Output: 16 24
Create a GridImage with grid-based processing capabilities. The grid structure can be specified explicitly (nrows, ncols) or detected automatically using a custom GridFinder algorithm.
Key Parameters:
arr: Image data (NumPy array, Image instance, or file path)
nrows, ncols: Grid dimensions (e.g., 8×12 for 96-well plates)
grid_finder: Optional custom grid detection algorithm (defaults to AutoGridFinder)
illuminant, gamma: Color space configuration (inherited from Image)
Example:
from phenotypic import GridImage
# Load 96-well plate image
grid_img = GridImage('plate_96well.jpg', nrows=8, ncols=12)
# Load 384-well plate image
grid_img_384 = GridImage('plate_384well.jpg', nrows=16, ncols=24)
# Show with gridlines overlay
grid_img.plot.overlay(show_grid=True)
- GridImage.copy()#
Creates a copy of the current Image instance, excluding the UUID. .. note:
- The new instance is only informationally a copy. The UUID of the new instance is different.
- Returns:
A copy of the current Image instance.
- Return type:
Image
Create a complete independent copy of the GridImage, including all grid structure, detection results, and metadata.
Grid Operations#
- property GridImage.grid: GridAccessor#
Returns the GridAccessor object for grid-related operations.
- Returns:
Provides access to Grid-related operations.
- Return type:
See Also
GridAccessor
The grid property provides access to grid detection and optimization functionality.
Through this accessor, you can:
Access detected grid structure (row/column edges)
Retrieve grid dimensions (nrows, ncols)
Access the GridFinder instance used for detection
Perform grid refinement and optimization
The grid is automatically detected on first access using the configured GridFinder algorithm. Detection results are cached for efficiency.
Example:
from phenotypic import GridImage
from phenotypic.detect import OtsuDetector
# Create and detect colonies
grid_img = GridImage('plate.jpg', nrows=8, ncols=12)
detector = OtsuDetector()
detected = detector.apply(grid_img)
# Access grid structure
nrows = detected.grid.nrows # 8
ncols = detected.grid.ncols # 12
# Get grid edges
row_edges = detected.grid.get_row_edges()
col_edges = detected.grid.get_col_edges()
# Access grid finder
finder = detected.grid.grid_finder
GridAccessor API:
- class phenotypic._core._image_parts.accessors._grid_accessor.GridAccessor(root_image: GridImage)[source]#
Bases:
objectProvides grid-based access and analysis for microbial colony arrays on agar plates.
This class facilitates operations on grid structures within a GridImage, enabling analysis of robotically-pinned microbial colonies arranged in a regular rectangular array pattern. It provides methods for determining grid properties, retrieving colony information by grid location, and visualizing grid overlays with row and column assignments.
The grid divides an agar plate image into a regular matrix of sections, each potentially containing one or more detected colonies. The grid is ordered left-to-right, top-to-bottom when using flattened indexing.
- Parameters:
root_image (GridImage)
- nrows#
Number of rows in the grid (read/write property). Corresponds to the number of row pins in a colony pinning robot. Must be >= 1.
- Type:
- ncols#
Number of columns in the grid (read/write property). Corresponds to the number of column pins in a colony pinning robot. Must be >= 1.
- Type:
Examples
Access grid information for a 96-well colony plate:
>>> from phenotypic import GridImage >>> # Load image and create grid accessor >>> grid_image = GridImage('agar_plate.png', nrows=8, ncols=12) >>> # Get grid information as a DataFrame >>> grid_info = grid_image.grid.info() >>> print(f"Found {len(grid_info)} colonies across {grid_image.grid.nrows} rows " ... f"and {grid_image.grid.ncols} columns") >>> # Extract a single grid section (colony at row 2, column 3) >>> section_idx = 2 * grid_image.grid.ncols + 3 # Flattened index >>> colony_image = grid_image.grid[section_idx] >>> # Visualize grid columns with color-coded labels >>> fig, ax = grid_image.grid.show_column_overlay(show_grid=True)
Get colony counts by grid section:
>>> # Count colonies in each grid section >>> section_counts = grid_image.grid.get_section_counts(ascending=False) >>> print("Colonies per section (sorted):") >>> print(section_counts) >>> # Get all colony information for row 0 >>> row_info = grid_image.grid.get_info_by_section((0, slice(None)))
- __getitem__(idx: int | tuple[int, int] | slice | tuple[slice | int, slice | int]) Image[source]#
Extract grid section(s) as a subimage.
Returns a cropped image corresponding to one or more grid sections. Supports flexible indexing including single sections, row/column slices, and flattened index ranges. The grid is indexed left-to-right, top-to-bottom (row-major order). Only objects belonging to the specified grid sections are included. For multiple sections, the subimage is cropped to the union of all section bounding boxes.
- Parameters:
idx (int | tuple[int, int] | slice | tuple[slice | int, slice | int]) –
Grid section identifier(s). Supported formats:
int: Single flattened section index (0 to nrows*ncols-1). Example: grid[54] for center section in 8x12 grid.
tuple[int, int]: Single section as (row_index, col_index). Example: grid[4, 6] for row 4, column 6.
slice: Range of flattened section indices. Example: grid[0:12] for first row in 8x12 grid.
tuple[int, slice]: Specific row, range of columns. Example: grid[2, 0:6] for row 2, columns 0-5.
tuple[slice, int]: Range of rows, specific column. Example: grid[0:4, 3] for rows 0-3, column 3.
tuple[slice, slice]: Slices in both dimensions (only if at least one is a full slice ‘:’). Examples: grid[2, :], grid[:, 5], grid[:, :], grid[:].
Note: Slicing in both dimensions is not allowed unless one is a full slice. For example, grid[0:5, 2:7] raises ValueError. Use grid[rows, col] OR grid[row, cols], but not grid[rows, cols].
- Returns:
- A subimage containing the selected grid section(s).
For a single section, pixels and objects are relative to that section’s top-left corner. For multiple sections, the image is cropped to the union of all selected section bounding boxes, preserving complete objects even if they extend beyond ideal grid boundaries. Object labels are preserved for objects in the selected sections; objects from other sections have their labels removed (set to 0). The subimage is marked with IMAGE_TYPE=GRID_SECTION metadata. If no objects are present in the parent image, returns a copy of the entire parent image.
- Return type:
phenotypic.Image
- Raises:
IndexError – If idx is out of bounds for the grid dimensions, or if idx is a tuple with length != 2.
ValueError – If attempting to slice in both row AND column dimensions simultaneously with non-full slices (e.g., grid[0:5, 2:7]).
TypeError – If idx is not a supported type.
Examples
# Single section by flattened index top_left = grid_image.grid[0] print(f"Section size: {top_left.shape}") # Single section by (row, col) indexing center = grid_image.grid[4, 6] # Flattened index slice - first row (sections 0-11 for 8x12 grid) first_row = grid_image.grid[0:12] # All columns in row 2 row_2 = grid_image.grid[2, :] # All rows in column 5 col_5 = grid_image.grid[:, 5] # Rows 0-3 in column 5 subset = grid_image.grid[0:4, 5] # Row 2, columns 0-5 subset = grid_image.grid[2, 0:6] # Every other section (step slicing) checkerboard = grid_image.grid[::2] # Full grid extraction all_sections = grid_image.grid[:] # This raises ValueError: cannot slice both dimensions # grid_image.grid[0:5, 2:7]
- get_centroid_alignment_info(axis: int) tuple[numpy.ndarray, numpy.ndarray][source]#
Calculate linear regression fit for colony centroids along a grid axis.
Computes the slope and intercept of a best-fit line through the centroids of colonies arranged along a specified axis (rows or columns). This quantifies alignment quality and any systematic drift in the pinned colony array. Uses standard least-squares linear regression to fit the line: y = m*x + b.
For row-wise analysis (axis=0), the function groups colonies by their row index and fits a line to the relationship between column position and column coordinate. For column-wise analysis (axis=1), it groups by column index and fits a line to the relationship between row position and row coordinate.
- Parameters:
axis (int) –
Axis along which to compute alignment:
0: Row-wise alignment. For each row, measures how colony centers vary along the column (CC) axis as a function of their grid column position. Slope indicates pixels of drift per grid column.
1: Column-wise alignment. For each column, measures how colony centers vary along the row (RR) axis as a function of their grid row position. Slope indicates pixels of drift per grid row.
- Returns:
- A tuple containing:
m_slope (np.ndarray[float]): Slopes for each row or column. Length is nrows if axis=0, ncols if axis=1. Values represent pixels of drift per grid position unit. NaN indicates no colonies in that row/column, 0 indicates single colony with no drift measurable.
b_intercept (np.ndarray): Y-intercepts for each row/column, rounded to nearest integer. NaN indicates no colonies in that row/column.
- Return type:
tuple[np.ndarray, np.ndarray]
- Raises:
NoObjectsError – If the parent image contains no detected objects (colonies).
ValueError – If axis is neither 0 nor 1.
Examples
Analyze colony alignment across grid axes:
>>> # Check row alignment (horizontal drift of colonies across each row) >>> row_slopes, row_intercepts = grid_image.grid.get_centroid_alignment_info(axis=0) >>> print(f"Row alignment slopes (pixels/column): {row_slopes}") >>> # Check column alignment (vertical drift of colonies across each column) >>> col_slopes, col_intercepts = grid_image.grid.get_centroid_alignment_info(axis=1) >>> print(f"Column alignment slopes (pixels/row): {col_slopes}") >>> # Identify rows with significant drift indicating pinning issues >>> drift_threshold = 0.05 # pixels per grid position >>> problematic_rows = np.where(np.abs(row_slopes) > drift_threshold)[0] >>> print(f"Rows with significant drift: {problematic_rows}")
- get_col_edges() numpy.ndarray[source]#
Get the column boundary positions in pixel coordinates.
Returns the x-coordinates (column indices) that define the vertical boundaries of each grid column in the image. For an ncols-column grid, returns ncols+1 boundary values: the left edge of column 0, internal boundaries between adjacent columns, and the right edge of column ncols-1.
- Returns:
- 1D array of strictly increasing column edge positions (pixel
column indices). Length is ncols+1. First value is 0 or the left edge of the first column, last value is the image width or right boundary.
- Return type:
np.ndarray
Examples
Retrieve and use column edge positions:
>>> col_edges = grid_image.grid.get_col_edges() >>> print(f"Column edges: {col_edges}") >>> # Output: [0.0, 106.5, 213.0, 319.5, ...] for a 12-column grid >>> # Calculate column width >>> col_width = col_edges[1] - col_edges[0] >>> print(f"Column width: {col_width} pixels") >>> # Extract pixels for column 3 >>> col_3_min, col_3_max = int(col_edges[3]), int(col_edges[4]) >>> column_3_data = grid_image.gray[:, col_3_min:col_3_max] >>> # Visualize grid column positions >>> fig, ax = plt.subplots() >>> ax.imshow(grid_image.gray) >>> ax.vlines(x=col_edges, ymin=0, ymax=grid_image.shape[0], colors='cyan')
- get_col_map() numpy.ndarray[source]#
Get an object map with objects labeled by their grid column number.
Creates a copy of the object map where each detected colony is relabeled according to its grid column assignment. All pixels belonging to colonies in the same grid column receive the same label. This is useful for visualizing or analyzing all colonies in a particular column together.
- Returns:
- 2D integer array with same shape as the parent image. Each
pixel belonging to a colony is set to that colony’s grid column number (1-indexed, ranging from 1 to ncols). Pixels not belonging to any colony are 0. Can be passed directly to label2rgb for visualization.
- Return type:
np.ndarray
Examples
Get and visualize column-labeled colony map:
>>> col_map = grid_image.grid.get_col_map() >>> # All colonies in column 0 have value 1, column 1 have value 2, etc. >>> print(f"Unique values in col_map: {np.unique(col_map)}") >>> # Output: [0, 1, 2, 3, ..., 12] for a 12-column grid >>> # Count total pixels belonging to each column >>> for col_num in range(1, grid_image.grid.ncols + 1): ... col_pixels = np.sum(col_map == col_num) ... print(f"Column {col_num}: {col_pixels} pixels") >>> # Visualize columns with distinct colors >>> from skimage.color import label2rgb >>> colored_columns = label2rgb(label=col_map, image=grid_image.gray[:]) >>> plt.imshow(colored_columns)
- get_info_by_section(section_number: int | tuple[int, int]) pandas.DataFrame[source]#
Get grid information for colonies in a specific grid section.
Retrieves detailed colony information (bounding box coordinates, centroid, area, etc.) for all objects within a given grid section. The section can be specified either by flattened index or by (row, column) tuple. Returns an empty DataFrame if no colonies are present in the requested section.
- Parameters:
section_number (int | tuple[int, int]) –
Grid section identifier:
If int: flattened section index (0 to nrows*ncols-1)
If tuple[int, int]: (row_index, col_index) pair specifying grid position, with both indices 0-based
- Returns:
- DataFrame with one row per colony in the specified section.
Contains the same columns as the info() method, including ObjectLabel, CenterRR, CenterCC, bounding box coordinates, grid position columns (RowNum, ColNum, SectionNum), and optionally metadata columns. Returns empty DataFrame if section contains no colonies.
- Return type:
pd.DataFrame
- Raises:
ValueError – If section_number is neither an int nor a 2-tuple.
Examples
Retrieve colony information for specific grid sections:
>>> # Get colonies using flattened index (section 25) >>> section_info = grid_image.grid.get_info_by_section(25) >>> print(f"Colonies in section 25: {len(section_info)}") >>> # Get colonies using (row, column) notation >>> # Get colonies in grid position (row=2, col=5) >>> section_info = grid_image.grid.get_info_by_section((2, 5)) >>> if len(section_info) > 0: ... # Analyze properties of colonies in this section ... colony = section_info.iloc[0] ... print(f"Colony area: {colony['Area']} pixels") ... print(f"Colony center: ({colony['CenterRR']}, {colony['CenterCC']})") ... else: ... print("No colony detected in this section") >>> # Find largest colony in section 10 >>> section_10 = grid_image.grid.get_info_by_section(10) >>> if len(section_10) > 0: ... largest = section_10.loc[section_10['Area'].idxmax()] ... print(f"Largest colony: label={largest.name}, area={largest['Area']}")
- get_row_edges() numpy.ndarray[source]#
Get the row boundary positions in pixel coordinates.
Returns the y-coordinates (row indices) that define the horizontal boundaries of each grid row in the image. For an nrows-row grid, returns nrows+1 boundary values: the top edge of row 0, internal boundaries between adjacent rows, and the bottom edge of row nrows-1.
- Returns:
- 1D array of strictly increasing row edge positions (pixel
row indices). Length is nrows+1. First value is 0 or the top edge of the first row, last value is the image height or bottom boundary.
- Return type:
np.ndarray
Examples
Retrieve and use row edge positions:
>>> row_edges = grid_image.grid.get_row_edges() >>> print(f"Row edges: {row_edges}") >>> # Output: [0.0, 95.2, 190.4, 285.6, ...] for an 8-row grid >>> # Calculate row height >>> row_height = row_edges[1] - row_edges[0] >>> print(f"Row height: {row_height} pixels") >>> # Extract pixels for row 4 >>> row_4_min, row_4_max = int(row_edges[4]), int(row_edges[5]) >>> row_4_data = grid_image.gray[row_4_min:row_4_max, :] >>> # Visualize grid row positions >>> fig, ax = plt.subplots() >>> ax.imshow(grid_image.gray) >>> ax.hlines(y=row_edges, xmin=0, xmax=grid_image.shape[1], colors='cyan')
- get_row_map() numpy.ndarray[source]#
Get an object map with objects labeled by their grid row number.
Creates a copy of the object map where each detected colony is relabeled according to its grid row assignment. All pixels belonging to colonies in the same grid row receive the same label. This is useful for visualizing or analyzing all colonies in a particular row together.
- Returns:
- 2D integer array with same shape as the parent image. Each
pixel belonging to a colony is set to that colony’s grid row number (1-indexed, ranging from 1 to nrows). Pixels not belonging to any colony are 0. Can be passed directly to label2rgb for visualization.
- Return type:
np.ndarray
Examples
Get and visualize row-labeled colony map:
>>> row_map = grid_image.grid.get_row_map() >>> # All colonies in row 0 have value 1, row 1 have value 2, etc. >>> print(f"Unique values in row_map: {np.unique(row_map)}") >>> # Output: [0, 1, 2, 3, ..., 8] for an 8-row grid >>> # Count total pixels belonging to each row >>> for row_num in range(1, grid_image.grid.nrows + 1): ... row_pixels = np.sum(row_map == row_num) ... print(f"Row {row_num}: {row_pixels} pixels") >>> # Visualize rows with distinct colors >>> from skimage.color import label2rgb >>> colored_rows = label2rgb(label=row_map, image=grid_image.gray[:]) >>> plt.imshow(colored_rows)
- get_section_counts(ascending: bool = False) pandas.Series[source]#
Count the number of objects (colonies) in each grid section.
Returns a Series showing how many colonies were detected in each grid section, sorted by count. Useful for quality control to identify problematic sections with unexpected colony counts (e.g., empty sections, multiple colonies in single pinned location, indicating pinning errors or detection artifacts).
- Parameters:
ascending (bool, optional) – If False (default), sort counts in descending order (sections with most colonies first). If True, sort ascending (fewest colonies first, useful for identifying empty sections). Defaults to False.
- Returns:
- A pandas Series where:
Index: Grid section number (0 to nrows*ncols-1), unsorted sections (those with no colonies) are not included
Values: Count of colonies in that section
Index name: GRID.ROW_MAJOR_IDX constant
- Return type:
pd.Series
Examples
Count and analyze colonies per grid section:
>>> section_counts = grid_image.grid.get_section_counts() >>> # Find sections with multiple colonies (potential pinning errors) >>> problem_sections = section_counts[section_counts > 1] >>> print(f"Sections with multiple colonies: {problem_sections}") >>> # Output: >>> # SectionNum >>> # 5 2 >>> # 12 3 >>> # dtype: int64 >>> # Find empty sections (no colony detected) >>> expected_sections = set(range(grid_image.grid.nrows * grid_image.grid.ncols)) >>> detected_sections = set(section_counts.index) >>> empty_sections = expected_sections - detected_sections >>> print(f"Empty sections: {empty_sections}") >>> # Statistics on detection completeness >>> num_expected = grid_image.grid.nrows * grid_image.grid.ncols >>> num_detected = len(section_counts) >>> completeness = 100 * num_detected / num_expected >>> print(f"Array completeness: {completeness:.1f}%")
- get_section_map() numpy.ndarray[source]#
Get an object map with objects labeled by their grid section number.
Creates a copy of the object map where each detected colony is relabeled according to its grid section assignment (flattened grid index). Section numbering is 0-indexed, ordered left-to-right, top-to-bottom (row-major).
- Returns:
- 2D integer array with same shape as the parent image. Each
pixel belonging to a colony is set to that colony’s grid section number (0-indexed, ranging from 0 to nrows*ncols-1). Pixels not belonging to any colony are 0. Can be passed directly to label2rgb for visualization.
- Return type:
np.ndarray
Examples
Get and visualize section-labeled colony map:
>>> section_map = grid_image.grid.get_section_map() >>> # For an 8x12 grid: >>> # Section 0: top-left (row 0, col 0) >>> # Section 11: top-right (row 0, col 11) >>> # Section 84: bottom-left (row 7, col 0) >>> # Section 95: bottom-right (row 7, col 11) >>> # Identify empty sections >>> empty_sections = [] >>> for section_num in range(grid_image.grid.nrows * grid_image.grid.ncols): ... if np.sum(section_map == section_num) == 0: ... empty_sections.append(section_num) >>> print(f"Empty sections: {empty_sections}") >>> # Visualize section distribution >>> from skimage.color import label2rgb >>> colored_sections = label2rgb(label=section_map, image=grid_image.gray[:]) >>> plt.imshow(colored_sections)
- info(include_metadata=True) pandas.DataFrame[source]#
Get grid information for all detected colonies.
Returns a DataFrame with bounding box measurements and grid location (row, column, section) assignments for each detected object (colony). This is the primary method for accessing detailed colony positioning and measurement data.
- Parameters:
include_metadata (bool, optional) – Whether to include image metadata columns in the output DataFrame. Defaults to True.
- Returns:
- DataFrame with one row per detected colony. Columns include:
ObjectLabel: Unique identifier for the colony
CenterRR, CenterCC: Row and column coordinates of colony center
MinRR, MaxRR, MinCC, MaxCC: Bounding box coordinates
RowNum: Grid row index (0-indexed)
ColNum: Grid column index (0-indexed)
SectionNum: Flattened grid section index (0 to nrows*ncols-1)
Additional columns if include_metadata=True
- Return type:
pd.DataFrame
Examples
Retrieve and analyze grid information:
>>> # Get full grid information >>> grid_info = grid_image.grid.info() >>> # Count colonies by row >>> colonies_per_row = grid_info.groupby('RowNum').size() >>> # Find largest colony in grid section 10 >>> section_10 = grid_info[grid_info['SectionNum'] == 10] >>> largest = section_10.loc[section_10['Area'].idxmax()] >>> # Get colonies without metadata >>> grid_info_minimal = grid_image.grid.info(include_metadata=False)
- napari(name: str | None = None, reset: bool = False, *, viewer: napari.Viewer | None = None, show_grid: bool = True, gridline_color: str = 'cyan', gridline_edge_width: float = 2.0, section_box_edge_width: float = 2.0, opacity: float = 1.0) napari.Viewer[source]#
Add grid overlay layers to a persistent global napari viewer.
Creates or reuses a single napari viewer instance and adds Shapes layers for gridlines and section boxes.
- Parameters:
name (str | None) – Optional custom name used in layer naming. If None, uses the image’s
nameattribute. Defaults to None.reset (bool) – If True, closes the current napari viewer and creates a fresh one. Defaults to False.
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management is bypassed. Defaults to None.
show_grid (bool) – If True, add Shapes layers with gridlines and colored section box rectangles. Defaults to True.
gridline_color (str) – Edge color for gridlines (any napari color spec). Defaults to
"cyan".gridline_edge_width (float) – Stroke width in pixels for gridlines. Defaults to 2.0.
section_box_edge_width (float) – Stroke width in pixels for section box edges. Defaults to 2.0.
opacity (float) – Layer opacity from 0.0 (transparent) to 1.0 (opaque). Defaults to 1.0.
- Returns:
The global napari viewer instance with grid layers.
- Return type:
napari.Viewer
- Raises:
ImportError – If napari is not installed.
ValueError – If opacity is not in [0.0, 1.0].
Examples
Overlay grid on a grayscale image:
>>> from phenotypic.data import load_synth_yeast_plate >>> gi = load_synth_yeast_plate() >>> viewer = gi.gray.napari() >>> viewer = gi.grid.napari()
- show_column_overlay(use_enhanced: bool = False, show_grid: bool = True, ax: plt.Axes | None = None, figsize: tuple[int, int] = (9, 10)) tuple[plt.Figure, plt.Axes][source]#
Visualize colonies with column-based color coding and optional grid overlay.
Displays the image with an overlay where each colony is colored according to its grid column assignment. This helps visualize the column structure of the pinned array and identify any column-wise positioning issues or misalignment.
- Parameters:
use_enhanced (bool, optional) – If True, use the detection matrix version of the parent image (detect_mat) for better contrast and visibility. If False, use the standard grayscale image (gray). Defaults to False.
show_grid (bool, optional) – If True, overlay cyan dashed gridlines marking the column and row boundaries. Defaults to True.
ax (plt.Axes | None, optional) – Existing Matplotlib Axes object to plot into. If None, a new figure and axes are created with the specified figsize. Defaults to None.
figsize (tuple[int, int], optional) – Figure size as (width, height) in inches, only used when ax is None. Defaults to (9, 10).
- Returns:
- A tuple containing the Matplotlib Figure and
Axes objects. If ax was provided as input, the function returns the created figure and the input ax object (not func_ax). If ax is None, returns the newly created figure and axes.
- Return type:
tuple[plt.Figure, plt.Axes]
Examples
Display column overlay visualization with options:
>>> # Display column overlay with gridlines >>> fig, ax = grid_image.grid.show_column_overlay(show_grid=True) >>> plt.title("Colony Array - Column Overlay") >>> plt.show() >>> # Use enhanced image for better contrast >>> fig, ax = grid_image.grid.show_column_overlay( ... use_enhanced=True, ... show_grid=True, ... figsize=(12, 14) ... ) >>> # Plot on existing axes >>> fig, axes = plt.subplots(1, 2, figsize=(16, 10)) >>> grid_image.grid.show_column_overlay(ax=axes[0]) >>> grid_image.grid.show_row_overlay(ax=axes[1])
- show_row_overlay(use_enhanced: bool = False, show_grid: bool = True, ax: plt.Axes | None = None, figsize: tuple[int, int] = (9, 10)) tuple[plt.Figure, plt.Axes][source]#
Visualize colonies with row-based color coding and optional grid overlay.
Displays the image with an overlay where each colony is colored according to its grid row assignment. This helps visualize the row structure of the pinned array and identify any row-wise positioning issues or misalignment.
- Parameters:
use_enhanced (bool, optional) – If True, use the detection matrix version of the parent image (detect_mat) for better contrast and visibility. If False, use the standard grayscale image (gray). Defaults to False.
show_grid (bool, optional) – If True, overlay cyan dashed gridlines marking the row and column boundaries. Defaults to True.
ax (plt.Axes | None, optional) – Existing Matplotlib Axes object to plot into. If None, a new figure and axes are created with the specified figsize. Defaults to None.
figsize (tuple[int, int], optional) – Figure size as (width, height) in inches, only used when ax is None. Defaults to (9, 10).
- Returns:
- A tuple containing the Matplotlib Figure and
Axes objects. If ax is None, returns the created figure and axes. If ax is provided, returns the created figure and the input ax object.
- Return type:
tuple[plt.Figure, plt.Axes]
Examples
Display row overlay visualization with options:
>>> # Display row overlay with gridlines >>> fig, ax = grid_image.grid.show_row_overlay(show_grid=True) >>> plt.title("Colony Array - Row Overlay") >>> plt.show() >>> # Use enhanced image for better contrast >>> fig, ax = grid_image.grid.show_row_overlay( ... use_enhanced=True, ... show_grid=True, ... figsize=(12, 14) ... ) >>> # Create side-by-side comparison >>> fig, axes = plt.subplots(1, 2, figsize=(16, 10)) >>> grid_image.grid.show_column_overlay(ax=axes[0]) >>> grid_image.grid.show_row_overlay(ax=axes[1]) >>> plt.suptitle("Column vs Row Grid Visualization") >>> plt.show()
Grid-Based Access#
GridImage supports grid-aware slicing to extract individual well images or sub-regions aligned to the detected grid structure. This enables well-level analysis and processing.
Grid Coordinate Transformations:
The class provides methods to convert between:
Pixel coordinates (x, y in image space)
Grid coordinates (row, column in well space)
Well indices (linear index from 0 to nrows×ncols-1)
Extracting Individual Wells:
grid_img = GridImage('plate.jpg', nrows=8, ncols=12)
# Extract specific well by row/column
well_A1 = grid_img.grid.get_well(row=0, col=0)
well_H12 = grid_img.grid.get_well(row=7, col=11)
# Iterate over all wells
for row in range(grid_img.grid.nrows):
for col in range(grid_img.grid.ncols):
well = grid_img.grid.get_well(row, col)
# Process individual well image
Data Access (Inherited from Image)#
GridImage inherits all data access methods and properties from the Image class.
All the following are available:
Data Accessors:
Image.gray- Grayscale representationImage.rgb- RGB/RGBA image dataImage.detect_mat- Enhanceable grayscale copyImage.objects- High-level interface to detected objectsImage.objmap- Labeled object mapImage.objmask- Binary mask of detected objects
Color Space Operations:
Image.color- Unified ColorAccessor interfaceImage.color.XYZ- CIE XYZ color spaceImage.color.XYZ_D65- XYZ under D65 illuminantImage.color.Lab- Perceptually uniform L*a*b* color spaceImage.color.xy- CIE xy chromaticity coordinatesImage.color.hsv- HSV (Hue-Saturation-Value) color space
Visualization & Plotting:
Image.plot- Unified PlotAccessor interfaceImage.plot.morph_progression()- Visualize morphological operation effectsImage.plot.structural_response_curve()- Quantify detection sensitivityImage.plot.boundary_displacement()- Spatial sensitivity heatmapImage.plot.size_distribution()- Comprehensive size analysisImage.plot.spatial_size_map()- Pseudo-color size distribution mapImage.plot.size_scatter()- Size-intensity correlation scatter plot
For detailed documentation of these inherited methods, see Image Class Methods.
Grid Visualization#
Display the grid image with optional overlays including:
Gridlines: Show detected row and column boundaries
Well labels: Annotate wells with row/column identifiers (A1, B2, etc.)
Detection results: Overlay detected objects with boundaries
Measurements: Display well-level measurements on the grid
This method extends the base Image.show_overlay() with grid-specific visualization
capabilities.
Example:
from phenotypic import GridImage
from phenotypic.detect import OtsuDetector
# Load and detect
grid_img = GridImage('plate.jpg', nrows=8, ncols=12)
detector = OtsuDetector()
detected = detector.apply(grid_img)
# Show with grid overlay and labels
detected.plot.overlay(
show_grid=True,
show_labels=True,
)
# Show with grid overlay (gridlines and section boxes)
detected.plot.overlay(show_grid=True)
Grid-Specific Visualization Methods:
The GridImage class provides additional grid-aware visualization methods:
Well highlighting: Highlight specific wells or well groups
Grid-aligned annotations: Add text or markers at well centers
Well-level heatmaps: Visualize measurements as colors on grid structure
Row/column summaries: Display aggregate statistics per row or column
Example - Well Highlighting:
# Highlight control wells - show grid overlay
detected.plot.overlay(show_grid=True)
Example - Well-Level Heatmap:
# Visualize colony count per well
detected.show_grid_heatmap(
metric='colony_count',
cmap='viridis',
show_values=True
)
File I/O (Inherited)#
GridImage inherits all file I/O methods from Image:
Image.imread()- Load image from fileImage.save2pickle()- Save to pickle formatImage.save2hdf5()- Save to HDF5 format with metadataImage.load_hdf5()- Load from HDF5
The grid structure (nrows, ncols, grid_finder configuration) is preserved during save/load operations, allowing complete restoration of the GridImage state.
Example:
# Create and configure grid image
grid_img = GridImage('plate.jpg', nrows=8, ncols=12)
# Save with grid structure preserved
grid_img.save2hdf5('plate_with_grid.h5')
# Load later - grid structure restored
restored = GridImage.load_hdf5('plate_with_grid.h5')
print(restored.grid.nrows, restored.grid.ncols) # 8, 12
Image Manipulation (Inherited)#
GridImage inherits image manipulation methods from Image:
Image.rotate()- Rotate image with optional centeringImage.__getitem__()- Numpy-like slicing
Note
When using image manipulation operations on GridImage, be aware that geometric transformations (rotation, cropping) may invalidate the detected grid structure. You may need to re-detect the grid after transformations.
Example:
grid_img = GridImage('plate.jpg', nrows=8, ncols=12)
# Rotate (grid structure may need re-detection)
rotated = grid_img.rotate(angle=2.5)
# Grid detection will be re-run on first access
rotated.plot.overlay(show_grid=True)
Metadata Management (Inherited)#
GridImage inherits metadata management from Image:
Image.metadata- Access metadata accessor
Grid-specific metadata (nrows, ncols, grid_finder type) is automatically stored in the metadata and preserved during save/load operations.
Comparison & Utility (Inherited)#
GridImage inherits comparison and utility methods from Image:
Image.__eq__()- Equality comparisonImage.__hash__()- Hash value computationImage.__repr__()- String representationImage.__str__()- Human-readable description
The string representation includes grid dimensions for easy identification:
grid_img = GridImage('plate.jpg', nrows=8, ncols=12)
print(grid_img)
# Output: GridImage(shape=(1200, 1600), grid=8×12, name='plate.jpg')