Skip to content

Support NoneType for color_indices in apply_selection() method of the Interactive selector Class #80

@bruno-pannunzio

Description

@bruno-pannunzio

Hello,

Currently developing the napari-phasors plugin, I encountered a bug when making manual selections in the canvas. The problem arises when the selection doesn't contain any valid values, so the color_indices is None (which is needed as a default value in an internal implementation of the plugin). Here is the traceback when doing a selection without any valid values which passes color_indices as None in the selector. I don't know exactly how to replicate this code easily, since it happened in the napari viewer. But let me know if you need a minimal code to replicate this error:

Traceback (most recent call last):
  File ".../cbook.py", line 361, in process
    func(*args, **kwargs)
    ~~~~^^^^^^^^^^^^^^^^^
  File ".../biaplotter/selectors.py", line 612, in on_button_press
    self.apply_selection()
    ~~~~~~~~~~~~~~~~~~~~^^
  File ".../biaplotter/selectors.py", line 594, in apply_selection
    color_indices[self._selected_indices] = self._class_value
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object does not support item assignment

I tried this changes to the apply_selection method, and it seems, at least in this case, that the color_indices can be passed as None with no errors:

def apply_selection(self):
        """Applies the selection to the data, updating the colors."""
        if self._selected_indices is None or len(self._selected_indices) == 0:
            self._selected_indices = None
            return

        # Ensure the overlay_colormap of the active artist is set to cat10_mod_cmap if needed
        if not self._active_artist.overlay_colormap.cmap.name.startswith(
            "cat10"
        ):
            # Clear previous color indices to remove previous feature coloring
            self._active_artist.color_indices = 0
            if isinstance(self._active_artist, Scatter):
                self._active_artist.overlay_colormap = cat10_mod_cmap
            elif isinstance(self._active_artist, Histogram2D):
                self._active_artist.overlay_colormap = (
                    cat10_mod_cmap_first_transparent
                )

        # Update color indices for the selected indices
        color_indices = self._active_artist.color_indices
        
        # Handle the case where color_indices is None
        if color_indices is None:
            # Initialize color_indices with zeros if it's None
            # Get data length from the active artist
            if hasattr(self._active_artist, 'data') and self._active_artist.data is not None:
                data_length = len(self._active_artist.data)
                color_indices = np.zeros(data_length, dtype=np.int8)
                self._active_artist.color_indices = color_indices
            else:
                # If we can't determine data length, we can't proceed
                self._selected_indices = None
                return
        
        # Now safely assign the selection values
        color_indices[self._selected_indices] = self._class_value
        self._active_artist.color_indices = color_indices

        # Emit signal and reset selected indices
        self.selection_applied_signal.emit(color_indices)
        self._selected_indices = None
        # Remove selector and create a new one
        self.remove()
        self.create_selector()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions