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]
Describe the bug
In
create_cistopic_object(src/pycisTopic/cistopic_class.py), themin_cellfiltering branch indexes theregion_dataDataFrame with numpy-style 2D syntax:region_datais a pandas DataFrame returned byregion_names_to_coordinates, soregion_data[(boolean_Series, slice)]raisespandas.errors.InvalidIndexError. The call fails for any value ofmin_cellother than the default of 1, includingmin_cell=0, since the guard tests the parameter value rather than whether any region is actually dropped.The equivalent
min_fragbranch a few lines above handles the same situation correctly with.loc:This suggests the region block was written by analogy and the
.locwas dropped.The default
min_cell=1skips the branch entirely, which is likely why this has gone unnoticed.To reproduce
Expected behaviour
Regions detected in fewer than
min_cellcells are dropped and aCistopicObjectis returned.Actual behaviour
Versions
Suggested fix