Skip to content

DonorData integration - #173

Open
LArnoldt wants to merge 2 commits into
mainfrom
cellink_integration
Open

LArnoldt wants to merge 2 commits into
mainfrom
cellink_integration

Conversation

@LArnoldt

@LArnoldt LArnoldt commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 24.47257% with 179 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.33%. Comparing base (22d3d80) to head (6b1941f).

Files with missing lines Patch % Lines
src/patpy/tl/_base_sample_method.py 24.03% 98 Missing ⚠️
src/patpy/tl/supervised.py 9.75% 37 Missing ⚠️
src/patpy/tl/evaluation.py 34.48% 19 Missing ⚠️
src/patpy/tl/sample_representation.py 41.37% 17 Missing ⚠️
src/patpy/datasets/_datasets.py 11.11% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #173      +/-   ##
==========================================
- Coverage   42.49%   41.33%   -1.17%     
==========================================
  Files          20       20              
  Lines        2826     3019     +193     
==========================================
+ Hits         1201     1248      +47     
- Misses       1625     1771     +146     
Files with missing lines Coverage Δ
src/patpy/datasets/__init__.py 100.00% <ø> (ø)
src/patpy/tl/__init__.py 100.00% <ø> (ø)
src/patpy/datasets/_datasets.py 56.12% <11.11%> (-4.56%) ⬇️
src/patpy/tl/sample_representation.py 50.32% <41.37%> (-0.56%) ⬇️
src/patpy/tl/evaluation.py 54.72% <34.48%> (-1.98%) ⬇️
src/patpy/tl/supervised.py 13.89% <9.75%> (+0.07%) ⬆️
src/patpy/tl/_base_sample_method.py 49.49% <24.03%> (-18.87%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@VladimirShitov VladimirShitov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall, I think it's great idea to bring a specialised data structure to back up patpy. Print output of DonorData objects look great and I like the MIL loader. However, this PR needs restructuring and better use cases. Now it looks like a lot of extra code with unclear benefits. Here ar esome suggestions (besides inline comments):

  1. Can you add a small code example (or a tutorial) on using DonorData? How to use it, what is stored where and why is it more convenient than separate objects?
  2. Is donor / sample division necessary? It brings quite some extra engineering, but I don't see where it helps. In fact, it can make things worse, e.g. by biasing evaluation metrics with repeated samples. So far, in patpy, I followed approach "everything is a sample" and let the users define what it actually is – e.g. donor. I would suggest following the same approach and removing additional level of complexity on everythign regarding "units" in code.

return adata


def as_donordata(adata: AnnData, info: DatasetInfo, meta_adata: AnnData | None = None, keep_in_cells: bool = True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not the right place for it: datasets module contains a collection of datasets, not the other functionality. Feel free to create io module or put this into pp

Parameters
----------
adata
Cells of a dataset loaded with patpy.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Cells of a dataset loaded with patpy.
Annotated data object containing cells

adata
Cells of a dataset loaded with patpy.
info
The ``DatasetInfo`` of the dataset, whose ``sample_key`` names the samples and whose

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Chain of dependencies becomes a bit long - a user must create dataset info, then donordata. Let's just follow DatasetInfo interface here. Make sample_key and sample_metadata_columns arguments of this function. Users can then easily provide them from DatasetInfo or just enter manually


Returns
-------
donordata.DonorData

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A description of what exactly it is (e.g. how to access cells and donors) would be nice

Examples
--------
>>> adata, info = patpy.datasets.stephenson(return_dataset_info=True)
>>> dd = patpy.datasets.as_donordata(adata, info)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's go with ddata at least. I don't like variables that are difficult to understand without context

known = {c for _, table in self._unit_tables() for c in table.columns}
return [c for c in columns if c in known and c != self.sample_key]

def _unit_table(self, columns=None) -> pd.DataFrame:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why is it needed?

return pd.Series(adata[:, col].X.toarray().flatten(), index=adata.obs_names)


def _representation_distances(meta_adata, representation: str):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I do not think this function is needed and it's only used once

"""Return *meta_adata*, or the samples of a DonorData as units when its representations live there.

A DonorData with a sample level keeps sample representations in ``obsm`` and ``obsp`` of its
samples. :meth:`~donordata.DonorData.flatten` turns the samples into the units, with the donor

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hmm, I'm wondering if this will lead to problems in some metrics by repeating the same information several times

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In any case, _evaluation module is the wrong place for that. In general, because it's very DonorData-specific, I would suggest putting it to DonorData package

trainer.fit(self._pascient_model, train_dataloaders=train_dl, val_dataloaders=val_dl)
self._pascient_model.eval()

def _training_loaders(self, adata: sc.AnnData, label_key: str, y_map: dict, task: str, batch_cls):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is really cool!

Comment thread pyproject.toml
"sphinxext-opengraph",
]
optional-dependencies.donordata = [
"donordata @ git+https://github.com/theislab/donordata.git",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will unfortunately not make it to the pypi package. Git links are not allowed. Please do either:

  1. Upload your package to pypi and add pypi dependency
  2. Remove dependency from here and add a suggestion to install it on iomort, e.g.:
try:
    import donordata
except ImportError:
    print("Import error. Please install donordata: `git+https://github.com/theislab/donordata.git@main`")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I pinged @LArnoldt for the release, which he was very thankful for

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @eroell !

rep = pd.DataFrame(rep, index=self.samples)
return rep

def to_donordata(self, key: str | None = None, donor_data=None):

@eroell eroell Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I gotta double-check Lucas' latest activities on donordata updates.

The rough functionality here could be shouldered on cellink/donordata site I think though, if a major issue for Vlad is to avoid code overhead.

This branch has not been deployed

No deployments
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