Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 18 additions & 20 deletions README.md

Large diffs are not rendered by default.

157 changes: 154 additions & 3 deletions cytepool/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,41 @@
"""Statistics on pseudobulk and bulk omics data."""
"""Statistics on pseudobulk and bulk omics data.

``import cytepool`` gives the functions and classes an analysis starts from, by the
question they answer, the default first:

- Cubes, tables and files: :class:`Cube`, :class:`CubeCollection`, :class:`Table`,
:func:`from_cells`, :func:`from_bulk`, :func:`read_cube`, :func:`write_cube`,
:func:`from_anndata`, :func:`to_anndata`, :func:`from_mudata`, :func:`to_mudata`.
- Designs: :class:`Design`.
- Which genes change in each cell type: :func:`limma_voom`; for repeated measures,
:func:`dream_voom`; :func:`limma_trend`; :class:`DifferentialExpressionResult`,
:class:`GroupFit`.
- Which cell types expand or contract: :func:`propeller`, :class:`CompositionResult`.
- What drives the variation between samples: :func:`variance_partitioning`,
:class:`VariancePartitioningResult`, :func:`principal_components`,
:class:`PrincipalComponents`.
- Gene sets and networks: :class:`GeneSets`, :func:`read_gmt`, :func:`write_gmt`,
:class:`Network`, :func:`collectri`, :func:`progeny`.
- Pathways for one contrast: :func:`camera`, :func:`fry`, :func:`roast`,
:func:`mroast`, :func:`romer`.
- Pathways along a ranking, or among the changed genes: :func:`gsea`,
:func:`over_representation`.
- Pathway scores per sample: :func:`gsva`, :func:`ssgsea`, :func:`combined_z_scores`,
:func:`plage`, :class:`PathwayScores`.
- Regulator activity: :func:`ulm`, :func:`mlm`, :func:`weighted_aggregate`,
:class:`Activities`.
- Testing scores with a design: :func:`limma`.
- Several studies: :func:`analyse_each_study`, :class:`StudyResults`; combining them,
:func:`meta_analysis`, :class:`MetaAnalysisResult`; replication, :func:`sumrank`,
:class:`SumRankResult`, :func:`replication`, :class:`ReplicationResult`,
:func:`held_out_prediction`, :class:`HeldOutPrediction`.

The building blocks, which work on arrays, are in ``cytepool.stats`` (linear and
mixed models, empirical Bayes moderation, voom, count models, multiple testing,
combined p-values and the distributions) and :mod:`cytepool.normalization`; the parts
of a design are in :mod:`cytepool.design`, and the figures in
:mod:`cytepool.plotting`, which needs matplotlib.
"""

from importlib.metadata import PackageNotFoundError as _PackageNotFoundError
from importlib.metadata import version as _distribution_version
Expand All @@ -18,6 +55,120 @@ def _installed_version() -> str:
return version


__version__ = _installed_version()
# Set before the modules below are imported: some of them record it.
__version__: str = _installed_version()

from .activity import Activities, mlm, ulm, weighted_aggregate # noqa: E402
from .composition import CompositionResult, propeller # noqa: E402
from .cube import Cube, CubeCollection, from_bulk, from_cells # noqa: E402
from .design import Design # noqa: E402
from .differential_expression import ( # noqa: E402
DifferentialExpressionResult,
GroupFit,
dream_voom,
limma_trend,
limma_voom,
)
from .gene_set_enrichment import gsea # noqa: E402
from .gene_set_tests import camera, fry # noqa: E402
from .gene_sets import GeneSets, read_gmt, write_gmt # noqa: E402
from .held_out_studies import HeldOutPrediction, held_out_prediction # noqa: E402
from .io import read_cube, write_cube # noqa: E402
from .io.anndata import from_anndata, from_mudata, to_anndata, to_mudata # noqa: E402
from .meta_analysis_of_studies import MetaAnalysisResult, meta_analysis # noqa: E402
from .networks import Network, collectri, progeny # noqa: E402
from .over_representation_analysis import over_representation # noqa: E402
from .pathway_scores import ( # noqa: E402
PathwayScores,
combined_z_scores,
gsva,
plage,
ssgsea,
)
from .principal_component_analysis import ( # noqa: E402
PrincipalComponents,
principal_components,
)
from .replication_across_studies import ReplicationResult, replication # noqa: E402
from .rotation_gene_set_tests import mroast, romer, roast # noqa: E402
from .score_tests import limma # noqa: E402
from .study_results import StudyResults, analyse_each_study # noqa: E402
from .sumrank_across_studies import SumRankResult, sumrank # noqa: E402
from .table import Table # noqa: E402
from .variance_components import ( # noqa: E402
VariancePartitioningResult,
variance_partitioning,
)

__all__ = ["__version__"]
__all__ = [
# Cubes, tables and files.
"Cube",
"CubeCollection",
"Table",
"from_cells",
"from_bulk",
"read_cube",
"write_cube",
"from_anndata",
"to_anndata",
"from_mudata",
"to_mudata",
# Designs.
"Design",
# Which genes change in each cell type?
"limma_voom",
"dream_voom",
"limma_trend",
"DifferentialExpressionResult",
"GroupFit",
# Which cell types expand or contract?
"propeller",
"CompositionResult",
# What drives the variation between samples?
"variance_partitioning",
"VariancePartitioningResult",
"principal_components",
"PrincipalComponents",
# Gene sets and networks.
"GeneSets",
"read_gmt",
"write_gmt",
"Network",
"collectri",
"progeny",
# Pathways for one contrast.
"camera",
"fry",
"roast",
"mroast",
"romer",
# Pathways along a ranking, or among the changed genes.
"gsea",
"over_representation",
# Pathway scores per sample.
"gsva",
"ssgsea",
"combined_z_scores",
"plage",
"PathwayScores",
# Regulator activity.
"ulm",
"mlm",
"weighted_aggregate",
"Activities",
# Testing scores with a design.
"limma",
# Several studies.
"analyse_each_study",
"StudyResults",
"meta_analysis",
"MetaAnalysisResult",
"sumrank",
"SumRankResult",
"replication",
"ReplicationResult",
"held_out_prediction",
"HeldOutPrediction",
# The version.
"__version__",
]
63 changes: 63 additions & 0 deletions cytepool/_analysis_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,69 @@ def only_key(value: Any, available: list[str], argument: str, what: str) -> Any:
)


def absence(result: Any, group: str, contrast: str) -> str:
"""Why a differential-expression result has no table of a group and contrast, in
the words of its own ``table`` method."""
try:
result.table(group, contrast)
except KeyError as error:
return str(error.args[0])
raise AssertionError("a table that is not in result.tables") # pragma: no cover


def study_keys(
results: Mapping[str, Any], group: Any, contrast: Any
) -> tuple[Any, Any]:
"""The group and contrast of the studies' differential-expression results asked
for, or, for one left out, the only one that the studies analysed.

Raises:
ValueError: If a key is left out and the studies analysed several, or none.
"""
return (
only_study_key(results, group, "group", "groups"),
only_study_key(results, contrast, "contrast", "contrasts"),
)


def only_study_key(
results: Mapping[str, Any], value: Any, argument: str, what: str
) -> Any:
"""``value`` when given, else the only group (``what="groups"``), or contrast
(``what="contrasts"``), that the studies' results analysed.

Raises:
ValueError: If ``value`` is None and the studies analysed several, or none.
"""
if value is not None:
return value
available = study_union(results, what)
if len(available) != 1:
raise ValueError(
f"the studies analysed {len(available)} {what}; name one with "
f"{argument}, one of {quoted(available)}"
)
return available[0]


def study_union(results: Mapping[str, Any], what: str) -> list[str]:
"""The groups (``what="groups"``), or the contrasts and F-tests, of any study's
result, in the order in which the studies first have them."""
if what == "groups":
return list(
dict.fromkeys(
group for result in results.values() for group in result.groups
)
)
return list(
dict.fromkeys(
name
for result in results.values()
for name in (*result.contrasts.names, *result.f_tests)
)
)


def software_versions() -> dict[str, str]:
"""The versions of CytePool, numpy, numba and Python that run an analysis."""
return {
Expand Down
Loading