Conversation
…tmap plot function
There was a problem hiding this comment.
Pull request overview
This pull request introduces version 1.7.0 of LIANA, adding spatial proximity support to cell-cell communication inference methods, implementing new spatial analysis features (inflow and global specificity), and improving documentation.
Key changes:
- Integration of spatial proximity weighting into existing ligand-receptor scoring methods with new
spatial_keyandspatial_kwargsparameters - Implementation of two new spatial methods:
inflowfor trivariate (source cell type, ligand, receptor) spatial metrics andcompute_global_specificityfor group-specific interaction analysis - Updated dependencies (decoupler>=1.7.0, cvxpy-base>=1.7.0) and added Python 3.13 support
Reviewed changes
Copilot reviewed 32 out of 34 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| src/liana/init.py | Version bump to 1.7.0 |
| pyproject.toml | Version update, dependency updates (decoupler, cvxpy-base), Python 3.13 classifier |
| src/liana/utils/spatial_neighbors.py | Added spatial_pair_proximity() function and refactored kernel function logic |
| src/liana/utils/init.py | Export new spatial_pair_proximity function |
| src/liana/plotting/_feature_by_group.py | New plotting function for visualizing features by spatial groups |
| src/liana/plotting/_common.py | Fixed string type check from labels is str to isinstance(labels, str) |
| src/liana/plotting/init.py | Export new feature_by_group function |
| src/liana/method/sp/_utils.py | Added utility functions for MuData/AnnData processing and connectivity handling |
| src/liana/method/sp/_inflow.py | New inflow method implementation for trivariate spatial metrics |
| src/liana/method/sp/_compute_global_specificity.py | New method for computing group-specific LR means with permutation testing |
| src/liana/method/sp/_bivariate/_spatial_bivariate.py | Refactored to use shared utility functions from _utils.py |
| src/liana/method/sp/init.py | Export new compute_global_specificity and inflow methods |
| src/liana/method/sc/_rank_aggregate.py | Added spatial_key and spatial_kwargs parameters |
| src/liana/method/sc/_liana_pipe.py | Integrated spatial proximity calculation and weighting into main pipeline |
| src/liana/method/sc/_geometric_mean.py | Added proximity weighting support to geometric mean scoring |
| src/liana/method/sc/_cellphonedb.py | Added proximity weighting support to CellPhoneDB scoring |
| src/liana/method/sc/_cellchat.py | Added proximity weighting support to CellChat scoring |
| src/liana/method/sc/_Method.py | Added spatial_key and spatial_kwargs parameters to Method class |
| src/liana/method/_pipe_utils/_get_mean_perms.py | Added proximity weighting functions for permutation-based methods |
| src/liana/method/init.py | Export new spatial methods |
| src/liana/_docs.py | Added documentation strings for new spatial parameters |
| tests/test_transform_kwargs.py | Tests for transform kwargs with AnnData and MuData |
| tests/test_spatial_proximity.py | Tests for spatial proximity calculations and pipeline integration |
| tests/test_plotting.py | Test for new feature_by_group plotting function |
| tests/test_inflow.py | Comprehensive tests for inflow method |
| tests/test_compute_global_specificity.py | Tests for global specificity computation |
| tests/test_bivar.py | Comment formatting fix |
| docs/notebooks/index.md | Added reference to inflow_score.ipynb |
| docs/notebooks/basic_usage.ipynb | Added cell ID for markdown cell |
| docs/installation.md | New installation documentation |
| docs/index.md | Added installation.md to table of contents |
| CHANGELOG.md | Version 1.7.0 changelog entries |
| .bumpversion.cfg | Version update to 1.7.0 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/liana/method/sp/_inflow.py
Outdated
|
|
||
| xy_stats.rename(columns={xy_stats.columns[0]: 'gene'}, inplace=True) | ||
|
|
||
| # Merge these stats into the resource; TODO: add to .var? |
There was a problem hiding this comment.
The comment formatting is inconsistent. The comment should be '# NOTE: add to .var?' with a space after '#' and before 'NOTE'.
| # Merge these stats into the resource; TODO: add to .var? | |
| # Merge these stats into the resource | |
| # NOTE: add to .var? |
| Sparse connectivity matrix in CSR format with float32 dtype. | ||
| """ | ||
| if connectivity_key not in adata.obsp.keys(): | ||
| raise ValueError(f'No connectivity matrix found in adata.obsp[{connectivity_key}]') |
There was a problem hiding this comment.
The typo 'founds' should be 'found' in the error message.
src/liana/method/sp/_inflow.py
Outdated
| An AnnData object of size (s* l * r *, n), where s correspodns to the cell types passed via the groupby parameter, | ||
| l and r are respectively the ligand and receptors expressed in the data and covered in the resource, and n is the | ||
| number of observations. |
There was a problem hiding this comment.
The docstring states the return value includes 's* l * r *, n' but uses inconsistent spacing and unclear notation. It should be written more clearly, such as '(n_cell_types * n_ligand_receptor_pairs, n_observations)' to match standard matrix dimension notation.
| An AnnData object of size (s* l * r *, n), where s correspodns to the cell types passed via the groupby parameter, | |
| l and r are respectively the ligand and receptors expressed in the data and covered in the resource, and n is the | |
| number of observations. | |
| An AnnData object of shape (n_cell_type_ligand_receptor_combinations, n_observations), where | |
| n_cell_type_ligand_receptor_combinations corresponds to the combinations of cell types (as defined by the | |
| ``groupby`` parameter) with ligands and receptors expressed in the data and covered by the resource, and | |
| n_observations is the number of observations. |
|
|
||
| final_df = final_df.sort_values('pval', ascending=True) | ||
|
|
||
| #Save result |
There was a problem hiding this comment.
Missing space after comment marker. The comment should be '# Save result' with a space after '#'.
| #Save result | |
| # Save result |
| @@ -0,0 +1,33 @@ | |||
| import pytest | |||
| import scanpy | |||
There was a problem hiding this comment.
Unused import. The 'scanpy' module is imported at line 2 but never used in the test file. The tests use 'from scanpy.datasets import pbmc68k_reduced' directly within the test functions.
| import scanpy |
src/liana/method/sp/_inflow.py
Outdated
| **kwargs | ||
| ) | ||
|
|
||
| # NOTE There are some repetitiions with bivariate scores |
There was a problem hiding this comment.
The comment has a typo: 'repetitiions' should be 'repetitions'.
| # NOTE There are some repetitiions with bivariate scores | |
| # NOTE There are some repetitions with bivariate scores |
| original_groupby_labels = adata.obs[groupby].astype('category') | ||
| groups_order = list(original_groupby_labels.cat.categories) | ||
|
|
||
| #Compute observed statistic |
There was a problem hiding this comment.
Missing space after comment marker. The comment should be '# Compute observed statistic' with a space after '#'.
| delayed(_get_group_mean)(X, rng_main.permutation(original_groupby_labels.values), var_names, groups_order=groups_order) | ||
| for _ in tqdm(range(n_perms), desc="Running permutations", disable=not verbose)) | ||
|
|
||
| #Convert results to array |
There was a problem hiding this comment.
Missing space after comment marker. The comment should be '# Convert results to array' with a space after '#'.
| @@ -0,0 +1,136 @@ | |||
| import anndata | |||
| import matplotlib.pyplot as plt | |||
| from matplotlib.gridspec import GridSpec | |||
There was a problem hiding this comment.
Import of 'GridSpec' is not used.
| from matplotlib.gridspec import GridSpec |
| from matplotlib.gridspec import GridSpec | ||
| import numpy | ||
| import itertools | ||
| from liana._constants import DefaultValues as V |
There was a problem hiding this comment.
Import of 'V' is not used.
| from liana._constants import DefaultValues as V |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 34 changed files in this pull request and generated 15 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/liana/method/sp/_inflow.py
Outdated
|
|
||
| Returns | ||
| ------- | ||
| An AnnData object of size (s* l * r *, n), where s correspodns to the cell types passed via the groupby parameter, |
There was a problem hiding this comment.
There's a typo in the docstring: 'correspodns' should be 'corresponds'.
| An AnnData object of size (s* l * r *, n), where s correspodns to the cell types passed via the groupby parameter, | |
| An AnnData object of size (s* l * r *, n), where s corresponds to the cell types passed via the groupby parameter, |
| @@ -22,14 +22,14 @@ authors = [ | |||
| { name = "Jovan Tanevski"}, | |||
| { name = "Ricardo Omar Ramirez Flores"}, | |||
| { name = "Julio Saez-Rodriguez"}, | |||
There was a problem hiding this comment.
An empty line was removed from the authors list. While this doesn't affect functionality, it changes the formatting. Ensure this is intentional and consistent with the project's style guide.
| { name = "Julio Saez-Rodriguez"}, | |
| { name = "Julio Saez-Rodriguez"}, |
|
|
||
| proximity_df = spatial_pair_proximity( | ||
| adata=adata, | ||
| groupby='@label', |
There was a problem hiding this comment.
The spatial proximity is calculated using '@Label' as the groupby parameter, but this appears to be a placeholder or internal label. The function should use the actual 'groupby' parameter passed to liana_pipe. This could cause the proximity calculation to fail or use incorrect grouping.
| groupby='@label', | |
| groupby=groupby, |
There was a problem hiding this comment.
This is incorrect, I purposely set it to adata.obs['@label'] = adata.obs[groupby] -> you would have to also override it there..., the idea was that then I don't have to pass it multiple times through all functions...
| # Apply proximity weights to both observed and permuted if provided | ||
| if proximity_weights is not None: | ||
| # Weight permuted: (n_perms, n_interactions) * (n_interactions,) | ||
| # Broadcasting automatically handles dimension alignment | ||
| lr_perm_means = lr_perm_means * proximity_weights |
There was a problem hiding this comment.
In the permutation-based p-value calculation, proximity weights are applied to both observed and permuted scores. However, permuted scores represent null distributions where cell labels are shuffled. Applying the same spatial proximity weights to permuted data may not be statistically appropriate since the spatial relationships between cell types change after permutation. Consider whether proximity weights should only be applied to observed scores, or if the permutation scheme needs to account for spatial structure.
| # Apply proximity weights to both observed and permuted if provided | |
| if proximity_weights is not None: | |
| # Weight permuted: (n_perms, n_interactions) * (n_interactions,) | |
| # Broadcasting automatically handles dimension alignment | |
| lr_perm_means = lr_perm_means * proximity_weights | |
| # Note: proximity weights, if any, are expected to have been applied | |
| # to the observed scores (lr_truth) upstream. We do not re-apply them | |
| # to the permuted statistics here to avoid distorting the null | |
| # distribution when spatial structure is part of the signal. |
| import anndata | ||
| import matplotlib.pyplot as plt | ||
| from matplotlib.gridspec import GridSpec | ||
| import numpy |
There was a problem hiding this comment.
The import statement 'import numpy' should follow Python naming conventions and be imported as 'import numpy as np' for consistency with the rest of the codebase.
| import numpy | |
| import numpy as np |
|
|
||
| ### Test on AnnData and LRs | ||
| # NOTE: these should be the same regardless of the local function | ||
| # NOTE: these should be the same regardless of the local function |
There was a problem hiding this comment.
The comment line is missing a space after the comment marker. Should be '# NOTE: these should be the same regardless of the local function' for consistency with Python style guidelines.
| verbose=verbose, | ||
| **spatial_kwargs | ||
| ) | ||
| # Set interacting to 0 where not interacting |
There was a problem hiding this comment.
The spatial proximity is set to 0 for non-interacting pairs by multiplying with the 'interacting' flag. However, this happens before the merge, which means the raw proximity values (which could be very small but non-zero) are zeroed out based on the count threshold. This is correct behavior but should be documented in the spatial_pair_proximity function to clarify that proximity weights represent both distance-based proximity AND count-based significance.
| # Set interacting to 0 where not interacting | |
| # Mask distance-based proximity by the interaction flag. | |
| # Note: this sets proximity to 0 for non-interacting pairs (according to the count/interaction | |
| # threshold used inside spatial_pair_proximity), so the resulting "proximity" column reflects | |
| # both spatial closeness AND interaction/count-based significance rather than pure distance. |
| adata: anndata.AnnData = None, | ||
| groupby: str = None, | ||
| spatial_key = K.spatial_key, | ||
| labels: list[str] = None, |
There was a problem hiding this comment.
The docstring specifies 'labels: list[str]' but the parameter type hint uses the older syntax. For consistency with Python 3.10+ type hints used elsewhere in the file, consider using 'list[str] | None' in the type hint as well.
| labels: list[str] = None, | |
| labels: list[str] | None = None, |
|
|
||
| cell_type_data.append({ | ||
| 'label': label, | ||
| 'coords': coords[mask.values], |
There was a problem hiding this comment.
Using 'mask.values' assumes mask is a pandas Series. However, if groupby column is not a pandas Series or if the boolean indexing returns a numpy array directly, this could fail. Consider using 'coords[mask]' directly or add a check for the mask type.
| 'coords': coords[mask.values], | |
| 'coords': coords[mask], |
| @@ -0,0 +1,33 @@ | |||
| import pytest | |||
| import scanpy | |||
There was a problem hiding this comment.
Import of 'scanpy' is not used.
| import scanpy |
|
@copilot open a new pull request to apply changes based on the comments in this thread |
|
@dbdimitrov I've opened a new pull request, #226, to work on those changes. Once the pull request is ready, I'll request review from you. |
Co-authored-by: dbdimitrov <50865230+dbdimitrov@users.noreply.github.com>
…tion Co-authored-by: dbdimitrov <50865230+dbdimitrov@users.noreply.github.com>
This pull request adds spatial proximity support to single-cell (typically dissociated) cell-cell communication inference methods, improving spatial analysis documentation, and updating dependencies.
The most significant changes include:
liana_pipe) and scoring methods now support spatial proximity weighting. This includes new arguments (spatial_key,spatial_kwargs) and logic to compute and merge spatial proximity scores into LR (ligand-receptor) results, and to adjust permutation-based p-value calculations accordingly. (src/liana/method/sc/_liana_pipe.py)Documentation and Usability Improvements:
inflow_score.ipynb.Dependency and Version Updates:
decoupler.