Skip to content

Add pathway-informed TCGA-BRCA multi-omics tutorial - #206

Merged
ilia-kats merged 6 commits into
mainfrom
tcga_tutorial
Jun 28, 2026
Merged

Add pathway-informed TCGA-BRCA multi-omics tutorial#206
ilia-kats merged 6 commits into
mainfrom
tcga_tutorial

Conversation

@arberqoku

@arberqoku arberqoku commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Adds a pathway-informed TCGA-BRCA multi-omics tutorial, plus the supporting plotting/loading changes the tutorial relies on:

  • pl.variance_explained: add a factor_filter predicate to plot only factors whose names satisfy it (e.g. the annotation-informed factors of an InformedHorseshoe prior, dropping the dense uninformed ones).
  • pl.factor_significance: rank factors by the variance explained within the selected views/groups, rather than the overall variance, so restricting views reorders the plot accordingly.
  • MOFAFLEX.load: when map_location is omitted, fall back to the device the model was trained on (stored in the file) instead of the live default, so methods that need the device (e.g. pl.factor_significance/PCGSE, GP priors) work on reloaded models.

Note: the pl.top_weights per-facet ordering fix was dropped from this PR — it's addressed more cleanly by #174 (once plotnine 0.16 lands).

Testing

  • New plot baseline variance_explained_factor-filter covering the factor_filter predicate.
  • Integration test asserting MOFAFLEX.load without map_location reloads onto the serialized training device (incl. a GP-prior case via test_load_uses_training_device_for_gp), and that PCGSE (get_significant_annotations) works on the reloaded model.

@arberqoku
arberqoku requested a review from ilia-kats June 21, 2026 22:16
@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.60%. Comparing base (7fa7f05) to head (2d0d42d).

Files with missing lines Patch % Lines
src/mofaflex/pl/_plotting.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #206      +/-   ##
==========================================
- Coverage   90.60%   90.60%   -0.01%     
==========================================
  Files          56       56              
  Lines        5739     5746       +7     
==========================================
+ Hits         5200     5206       +6     
- Misses        539      540       +1     
Files with missing lines Coverage Δ
src/mofaflex/_core/mofaflex.py 95.17% <100.00%> (+0.01%) ⬆️
src/mofaflex/pl/_plotting.py 81.69% <88.88%> (+0.02%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ilia-kats ilia-kats left a comment

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.

Awesome, thanks!

Comment thread src/mofaflex/_core/terms/mofaflex.py Outdated
self._device = map_location
# map_location may be None (e.g. MOFAFLEX.load without an explicit device); fall back to the
# default device so methods that need it (e.g. PCGSE in get_significant_annotations) still work.
self._device = default_torch_device(map_location)

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 don't think this works. map_location is currently only used by the GP prior for the GP state (required for get_gps with new covariates). If map_location=None, the GP state will be loaded on GPU, but self._device will be CPU, so get_gps will fail. I think a better solution is setting map_location=state["train_opts"]["device"] in _core/mofaflex.py:554

Comment thread src/mofaflex/pl/_plotting.py Outdated
model: MOFAFLEX,
group_by: Literal["group", "view"] = "group",
term: str | None = None,
annotated_only: bool = False,

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.

Can we generalize that? For example, passing in a predicate function that filters factors by name?

Comment thread src/mofaflex/pl/_plotting.py Outdated
):
df = df.assign(feature=lambda x: x.feature.str + "_" + x.view.str)
df = df.assign(feature=lambda x: pd.Categorical(x.feature, categories=x.feature.unique()))
# A feature can be among the top features of several factors. With a single global feature category, those

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.

this is addressed in a cleaner way by #174. There doesn't seem to be a timeline for plotnine 0.16 release, but if we decide to release mofaflex 0.2 before that, worst case we can depend on plotnine>=0.16a10 (or whatever the current pre-release will be by then). Or we can finalize and merge #174 now, with the caveat that we may need to regenerate the test baseline images a few times before the plotnine 0.16 final release.

Comment thread tests/test_mofaflex_integration.py Outdated
seed=42,
batch_size=batch_size,
n_particles=n_particles,
save_path=save_path,

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.

in that case, there's no need for the with chdir... context

Fix `map_location`
Replace `annotated_only` with `factor_filter`
Comment thread src/mofaflex/_core/terms/mofaflex.py Outdated
def _results_to_df(
self,
results: Mapping[str, np.ndarray],
results: Mapping[str, np.ndarray | pd.DataFrame],

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.

why these changes? This method is explicitly meant to convert arrays to data frames, and every dynamic API function returning factors (marked by has_factors=True in its API properties) should be returning an array. If that is not the case somewhere, that should be changed in the dynamic API of the respective prior.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Its a slip up from the other branch I'm working on related GPs over features, will fix right away..

@ilia-kats ilia-kats left a comment

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.

Just a few tweaks to the changelog, and then it's good to go.

Comment thread CHANGELOG.md Outdated
### Fixed
- `pl.factor_significance` now ranks factors by the variance they explain within the selected `views`/`groups`,
rather than the overall variance, so restricting `views` reorders the plot accordingly.
- `pl.top_weights` orders features per facet, fixing the scrambled ordering when a feature is among the top

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.

no longer true with this PR.

Comment thread CHANGELOG.md
- Training with sparse inputs and minibatching is about 1.5 times faster.

### Fixed
- `pl.factor_significance` now ranks factors by the variance they explain within the selected `views`/`groups`,

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 would put this in Changed.

@ilia-kats
ilia-kats enabled auto-merge (squash) June 28, 2026 09:43
@ilia-kats
ilia-kats merged commit b89f6ad into main Jun 28, 2026
9 checks passed
@ilia-kats
ilia-kats deleted the tcga_tutorial branch June 28, 2026 09:45
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.

2 participants