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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions