napari_track_edit.data_views.views.layers.contour_labels ======================================================== .. py:module:: napari_track_edit.data_views.views.layers.contour_labels Classes ------- .. autoapisummary:: napari_track_edit.data_views.views.layers.contour_labels.ContourLabels Functions --------- .. autoapisummary:: napari_track_edit.data_views.views.layers.contour_labels.left_only_draw napari_track_edit.data_views.views.layers.contour_labels.left_only_pick napari_track_edit.data_views.views.layers.contour_labels.get_contours Module Contents --------------- .. py:function:: left_only_draw(layer, event) .. py:function:: left_only_pick(layer, event) .. py:function:: get_contours(labels: numpy.ndarray, thickness: int, background_label: int, filled_labels: list[int] | None = None) Computes the contours of a 2D label image. :param labels: An input labels image. :type labels: array of integers :param thickness: It controls the thickness of the inner boundaries. The outside thickness is always 1. The final thickness of the contours will be `thickness + 1`. :type thickness: int :param background_label: That label is used to fill everything outside the boundaries. :type background_label: int :rtype: A new label image in which only the boundaries of the input image are kept. .. py:class:: ContourLabels(data: numpy.array, name: str, opacity: float, scale: tuple, colormap: napari.utils.DirectLabelColormap) Bases: :py:obj:`napari.layers.Labels` Extended labels layer that allows to show contours and filled labels simultaneously .. py:property:: _type_string :type: str .. py:attribute:: _filled_labels :value: [] .. py:property:: filled_labels :type: list[int] | None List of labels in a group .. py:method:: _calculate_contour(labels: numpy.ndarray, data_slice: tuple[slice, ...]) -> numpy.ndarray | None Calculate the contour of a given label array within the specified data slice. :param labels: The label array. :type labels: np.ndarray :param data_slice: The slice of the label array on which to calculate the contour. :type data_slice: Tuple[slice, ...] :returns: The calculated contour as a boolean mask array. Returns None if the contour parameter is less than 1, or if the label array has more than 2 dimensions. :rtype: Optional[np.ndarray] .. py:method:: set_opacity(labels: list[int], value: float) -> None Helper function to set the opacity of multiple labels to the same value. :param labels: list of labels to set the value for. :type labels: list[int] :param value: float alpha value to set. :type value: float .. py:method:: refresh_colormap() Refresh the label colormap after in-place opacity/color changes. `set_opacity` mutates the colormap's `color_dict` alphas in place. Rather than constructing a new DirectLabelColormap (which re-validates every color via `transform_color` - ~0.2s for a 37k-label graph), clear the colormap's cached value->color mapping and re-assign the same object so napari rebuilds only the GPU texture (~0.08s). Setting colormap also emits `selected_label`, which triggers `_ensure_valid_label` and would rebuild the colormap a second time; that validation is only needed when the painting label changes, not on a highlight/opacity refresh, so block it here. .. py:method:: data_setitem(indices, value, refresh=True) Override to handle read-only data (e.g. GraphArrayView). When the underlying data does not support __setitem__ (read-only), accumulate paint atoms during a drag (respecting napari's block_history mechanism) and only fire events.paint once when the drag completes. For writable arrays (numpy), fall back to the default implementation. .. py:method:: _paint_region_with_mask(slice_key, mask, new_label, dims_to_paint, refresh=True, region_data=None) Override to handle read-only data (e.g. GraphArrayView). napari ≥0.8 equivalent of ``data_setitem`` above. This method writes the painted bounding box straight back with ``self.data[slice_key] = region_data``. Read-only data cannot take that write, so run the same steps napari does, minus the write-back: the region is materialized as a numpy copy, so painting into it records the undo atom (firing events.paint, which is what upstream code acts on) and updates the display, while the underlying array is left untouched. .. py:method:: undo() Override undo for read-only data (e.g. GraphArrayView). napari's default Labels.undo() calls data_setitem() to restore old values. For read-only data, ContourLabels.data_setitem() cannot write to the underlying array and instead fires events.paint as a signal for upstream code to handle the change. Firing events.paint during an undo triggers the same paint-event callbacks that initiated the undo in the first place, causing a recursive loop and a TypeError. This override breaks the loop by dropping the display buffer and re-slicing, without going through data_setitem or emitting any paint event. Only the display buffer was ever updated, the underlying array still holds the pre-stroke segmentation. This method is called (via super().undo()) from TrackLabels in three situations: reverting a failed paint on the main layer, reverting a failed paint on an ortho-view copy of the layer, and rolling back an invalid action inside _on_paint error handling. The undone item is dropped rather than handed to the redo queue: a paint that never reached the data cannot be re-applied by this layer, and what the user redoes is the funtracks action. Leaving the redo queue empty is also what keeps napari's own Labels.redo(), bound to Ctrl+Shift+Z, harmless here. .. py:method:: _abort_stroke() Override for read-only data (e.g. GraphArrayView). napari >= 0.8 stages the atoms of an encircle-and-fill stroke (right click in paint mode) instead of committing them one by one, and aborts the stroke when the tool is disabled mid-stroke, e.g. by a mode switch. Its abort walks the staged atoms backwards and writes each one back into the array, either directly or via ``_replay_masked_atom``, which read-only data cannot take. Nothing was ever written (see ``_paint_region_with_mask``), so dropping the staged atoms and re-slicing is all the revert this layer needs, and, as in ``undo``, it avoids emitting a paint event that would re-enter _on_paint. .. py:method:: redo() Override redo for read-only data (e.g. GraphArrayView). There is nothing to do here in our use case, since we have our own history logic, but because napari binds Ctrl+Shift+Z to Labels.redo() we should override here in case the user tries to redo on an ortho-view, triggering the TypeError: 'LazyArrayWrapper' object does not support item assignment error.