Skip to content

Bug report [BUG] create_cistopic_object fails with InvalidIndexError whenever min cell != 1 #230

Description

@dmuratli

Describe the bug

In create_cistopic_object (src/pycisTopic/cistopic_class.py), the min_cell filtering branch indexes the region_data DataFrame with numpy-style 2D syntax:

if min_cell != 1:
    selected_regions = region_data.cisTopic_nr_acc >= min_cell
    fragment_matrix = fragment_matrix[selected_regions, :]
    binary_matrix = binary_matrix[selected_regions, :]
    region_data = region_data[selected_regions, :]   # <-- fails
    region_names = region_data.index.to_list()

region_data is a pandas DataFrame returned by region_names_to_coordinates, so region_data[(boolean_Series, slice)] raises pandas.errors.InvalidIndexError. The call fails for any value of min_cell other than the default of 1, including min_cell=0, since the guard tests the parameter value rather than whether any region is actually dropped.

The equivalent min_frag branch a few lines above handles the same situation correctly with .loc:

if min_frag != 1:
    selected_cells = cell_data.cisTopic_nr_frag >= min_frag
    ...
    cell_data = cell_data.loc[selected_cells,]

This suggests the region block was written by analogy and the .loc was dropped.

The default min_cell=1 skips the branch entirely, which is likely why this has gone unnoticed.

To reproduce

import numpy as np
from scipy.sparse import csr_matrix
from pycisTopic.cistopic_class import create_cistopic_object

rng = np.random.default_rng(0)
n_regions, n_cells = 200, 50
fragment_matrix = csr_matrix(rng.poisson(0.3, size=(n_regions, n_cells)).astype(np.int32))

region_names = [f"chr1:{i * 1000}-{i * 1000 + 500}" for i in range(n_regions)]
cell_names = [f"cell_{i}" for i in range(n_cells)]

# Works
create_cistopic_object(fragment_matrix, cell_names, region_names)

# Raises InvalidIndexError
create_cistopic_object(fragment_matrix, cell_names, region_names, min_cell=10)

Expected behaviour

Regions detected in fewer than min_cell cells are dropped and a CistopicObject is returned.

Actual behaviour

Traceback (most recent call last):
  File ".../pycisTopic/cistopic_class.py", line 637, in create_cistopic_object
    region_data = region_data[selected_regions, :]
                  ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
  File ".../pandas/core/frame.py", line 3805, in __getitem__
    indexer = self.columns.get_loc(key)
  File ".../pandas/core/indexes/base.py", line 3807, in get_loc
    self._check_indexing_error(key)
  File ".../pandas/core/indexes/base.py", line 5963, in _check_indexing_error
    raise InvalidIndexError(key)
pandas.errors.InvalidIndexError: (RegionIDs
GL000009.2:124435-125319    True
...
chrX:155880858-155881766    True
Name: cisTopic_nr_acc, Length: 153377, dtype: bool, slice(None, None, None))

Versions

  • pycisTopic: 2.0a0 (installed as a git dependency of SCENIC+)
  • pandas: 1.5.0
  • numpy: 1.26.4
  • Python: 3.11.8

Suggested fix

region_data = region_data.loc[selected_regions]

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