Skip to content

v1.7.0#225

Merged
dbdimitrov merged 52 commits intomainfrom
inflow_merge
Jan 7, 2026
Merged

v1.7.0#225
dbdimitrov merged 52 commits intomainfrom
inflow_merge

Conversation

@dbdimitrov
Copy link
Collaborator

@dbdimitrov dbdimitrov commented Jan 7, 2026

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:

  • Inflow implementation and tutorial Feature/inflow score #221 by @AtheerAS
  • Global specificity calculation Feature/inflow score #221 by @AtheerAS
  • The integration of spatial proximity weighting ligand-receptor methods, new user-facing parameters for spatial analysis, and enhancements to the documentation to reflect these features. Spatial weighting for sc liana methods #222. The main cell-cell communication pipeline (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:

  • Expanded docstrings and parameter documentation to cover new spatial analysis arguments, including detailed descriptions of spatial proximity options and kernel/bandwidth settings.
  • Updated the notebook index and documentation to reference new spatial analysis notebooks, such as inflow_score.ipynb.
  • Properly check if a passed (cell type) labels in plotting are a string Fix: Incorrect type check for labelsvariable in plotting module #220
  • Fixed an issue where MetalinksDB download would fail due to User-Agent restrictions.

Dependency and Version Updates:

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_key and spatial_kwargs parameters
  • Implementation of two new spatial methods: inflow for trivariate (source cell type, ligand, receptor) spatial metrics and compute_global_specificity for 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.


xy_stats.rename(columns={xy_stats.columns[0]: 'gene'}, inplace=True)

# Merge these stats into the resource; TODO: add to .var?
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment formatting is inconsistent. The comment should be '# NOTE: add to .var?' with a space after '#' and before 'NOTE'.

Suggested change
# Merge these stats into the resource; TODO: add to .var?
# Merge these stats into the resource
# NOTE: add to .var?

Copilot uses AI. Check for mistakes.
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}]')
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The typo 'founds' should be 'found' in the error message.

Copilot uses AI. Check for mistakes.
Comment on lines 117 to 119
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.
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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.

Copilot uses AI. Check for mistakes.

final_df = final_df.sort_values('pval', ascending=True)

#Save result
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comment marker. The comment should be '# Save result' with a space after '#'.

Suggested change
#Save result
# Save result

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,33 @@
import pytest
import scanpy
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
import scanpy

Copilot uses AI. Check for mistakes.
**kwargs
)

# NOTE There are some repetitiions with bivariate scores
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment has a typo: 'repetitiions' should be 'repetitions'.

Suggested change
# NOTE There are some repetitiions with bivariate scores
# NOTE There are some repetitions with bivariate scores

Copilot uses AI. Check for mistakes.
original_groupby_labels = adata.obs[groupby].astype('category')
groups_order = list(original_groupby_labels.cat.categories)

#Compute observed statistic
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comment marker. The comment should be '# Compute observed statistic' with a space after '#'.

Copilot uses AI. Check for mistakes.
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
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comment marker. The comment should be '# Convert results to array' with a space after '#'.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,136 @@
import anndata
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'GridSpec' is not used.

Suggested change
from matplotlib.gridspec import GridSpec

Copilot uses AI. Check for mistakes.
from matplotlib.gridspec import GridSpec
import numpy
import itertools
from liana._constants import DefaultValues as V
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'V' is not used.

Suggested change
from liana._constants import DefaultValues as V

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.


Returns
-------
An AnnData object of size (s* l * r *, n), where s correspodns to the cell types passed via the groupby parameter,
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo in the docstring: 'correspodns' should be 'corresponds'.

Suggested change
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,

Copilot uses AI. Check for mistakes.
@@ -22,14 +22,14 @@ authors = [
{ name = "Jovan Tanevski"},
{ name = "Ricardo Omar Ramirez Flores"},
{ name = "Julio Saez-Rodriguez"},
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
{ name = "Julio Saez-Rodriguez"},
{ name = "Julio Saez-Rodriguez"},

Copilot uses AI. Check for mistakes.

proximity_df = spatial_pair_proximity(
adata=adata,
groupby='@label',
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
groupby='@label',
groupby=groupby,

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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...

Comment on lines 140 to 144
# 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
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# 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.

Copilot uses AI. Check for mistakes.
import anndata
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
import numpy
import numpy as np

Copilot uses AI. Check for mistakes.

### 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
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
verbose=verbose,
**spatial_kwargs
)
# Set interacting to 0 where not interacting
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# 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.

Copilot uses AI. Check for mistakes.
adata: anndata.AnnData = None,
groupby: str = None,
spatial_key = K.spatial_key,
labels: list[str] = None,
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
labels: list[str] = None,
labels: list[str] | None = None,

Copilot uses AI. Check for mistakes.

cell_type_data.append({
'label': label,
'coords': coords[mask.values],
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
'coords': coords[mask.values],
'coords': coords[mask],

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,33 @@
import pytest
import scanpy
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'scanpy' is not used.

Suggested change
import scanpy

Copilot uses AI. Check for mistakes.
@dbdimitrov
Copy link
Collaborator Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Jan 7, 2026

@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.

Copilot AI and others added 3 commits January 7, 2026 18:56
Co-authored-by: dbdimitrov <50865230+dbdimitrov@users.noreply.github.com>
…tion

Co-authored-by: dbdimitrov <50865230+dbdimitrov@users.noreply.github.com>
@dbdimitrov dbdimitrov merged commit 180c6d2 into main Jan 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants