vima-spatial 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/PKG-INFO +5 -2
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/README.md +4 -1
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/pyproject.toml +4 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/setup.cfg +1 -1
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/__init__.py +7 -4
- vima_spatial-0.2.4/src/vima/_settings.py +200 -0
- vima_spatial-0.2.4/src/vima/cc.py +467 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/data/__init__.py +1 -0
- vima_spatial-0.2.4/src/vima/data/download.py +62 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/data/patchcollection.py +126 -27
- vima_spatial-0.2.4/src/vima/data/samples.py +87 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/fingerprints.py +95 -6
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/ingest/dimreduce.py +96 -25
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/ingest/ingest.py +124 -21
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/ingest/nonst.py +80 -12
- vima_spatial-0.2.4/src/vima/ingest/st.py +354 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/ingest/util.py +21 -4
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/models/__init__.py +23 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/models/simple_vae.py +3 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/models/vae.py +19 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/patchfeatures.py +109 -63
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/train/logging.py +3 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/train/training.py +119 -10
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/vis/features.py +46 -32
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/vis/patches.py +134 -65
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/vis/spatial.py +71 -4
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/vis/umaps.py +16 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima_spatial.egg-info/PKG-INFO +5 -2
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima_spatial.egg-info/SOURCES.txt +4 -2
- vima_spatial-0.2.4/tests/test_ra_regression.py +69 -0
- vima_spatial-0.2.2/MANIFEST.in +0 -1
- vima_spatial-0.2.2/src/vima/cc.py +0 -199
- vima_spatial-0.2.2/src/vima/data/samples.py +0 -43
- vima_spatial-0.2.2/src/vima/ingest/st.py +0 -227
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/ingest/__init__.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/models/resnet_vae.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/models/resnetlight_decoder.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/models/resnetlight_encoder.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/train/__init__.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/vis/__init__.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima/vis/patchexamples.py +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima_spatial.egg-info/dependency_links.txt +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima_spatial.egg-info/requires.txt +0 -0
- {vima_spatial-0.2.2 → vima_spatial-0.2.4}/src/vima_spatial.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vima-spatial
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: variational inference-based microniche analysis
|
|
5
5
|
Home-page: https://github.com/yakirr/vima
|
|
6
6
|
Author: Yakir Reshef
|
|
@@ -39,9 +39,12 @@ Variational inference-based microniche analysis is a method for conducting case-
|
|
|
39
39
|
```
|
|
40
40
|
pip install vima-spatial
|
|
41
41
|
```
|
|
42
|
+
Note that `vima` requires `pytorch` and `harmonypy`. These should install automatically through `pip`, but if you have trouble, try installing them first, verifying that they work, and then installing `vima`.
|
|
42
43
|
|
|
43
44
|
## demo
|
|
44
|
-
|
|
45
|
+
To get started with an example analysis on a toy spatial transcriptomics dataset, take a look at our brief demo. You can see a [completed read-only version](https://github.com/yakirr/vima/blob/main/demo/demo_ST_minimal.ipynb) or run an [interactive version](https://colab.research.google.com/github/yakirr/tpae/blob/main/demo/demo_ST_minimal.ipynb) yourself on a Google Colab GPU (though this requires Colab Pro due to insufficient memory provided on the free tier.)
|
|
46
|
+
|
|
47
|
+
To see how to apply `vima` to a stain-based modality like CODEX, immunohistochemistry, or immunofluorescence, look at our [immunofluorescence demo](https://github.com/yakirr/vima/blob/main/demo/demo_IF.ipynb).
|
|
45
48
|
|
|
46
49
|
## citation
|
|
47
50
|
If you use `vima`, please cite:
|
|
@@ -6,9 +6,12 @@ Variational inference-based microniche analysis is a method for conducting case-
|
|
|
6
6
|
```
|
|
7
7
|
pip install vima-spatial
|
|
8
8
|
```
|
|
9
|
+
Note that `vima` requires `pytorch` and `harmonypy`. These should install automatically through `pip`, but if you have trouble, try installing them first, verifying that they work, and then installing `vima`.
|
|
9
10
|
|
|
10
11
|
## demo
|
|
11
|
-
|
|
12
|
+
To get started with an example analysis on a toy spatial transcriptomics dataset, take a look at our brief demo. You can see a [completed read-only version](https://github.com/yakirr/vima/blob/main/demo/demo_ST_minimal.ipynb) or run an [interactive version](https://colab.research.google.com/github/yakirr/tpae/blob/main/demo/demo_ST_minimal.ipynb) yourself on a Google Colab GPU (though this requires Colab Pro due to insufficient memory provided on the free tier.)
|
|
13
|
+
|
|
14
|
+
To see how to apply `vima` to a stain-based modality like CODEX, immunohistochemistry, or immunofluorescence, look at our [immunofluorescence demo](https://github.com/yakirr/vima/blob/main/demo/demo_IF.ipynb).
|
|
12
15
|
|
|
13
16
|
## citation
|
|
14
17
|
If you use `vima`, please cite:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from ._settings import settings, Verbosity
|
|
1
2
|
from . import data as d
|
|
2
3
|
from . import cc
|
|
3
4
|
from . import train as t
|
|
@@ -7,12 +8,14 @@ from . import models
|
|
|
7
8
|
|
|
8
9
|
from .data.patchcollection import PatchCollection
|
|
9
10
|
from .data.samples import read_samples, reindex_by_sid
|
|
11
|
+
from .data.download import download_zenodo
|
|
10
12
|
from .train.training import train, fit, set_seed
|
|
11
|
-
from .cc import latentreps, association
|
|
13
|
+
from .cc import latentreps, association, compute_mams
|
|
12
14
|
from .fingerprints import Fingerprints
|
|
13
15
|
from .patchfeatures import cell_type_counts, expression_profiles, test_features
|
|
14
16
|
|
|
15
|
-
__all__ = ['
|
|
16
|
-
'
|
|
17
|
-
'
|
|
17
|
+
__all__ = ['settings', 'Verbosity',
|
|
18
|
+
'd', 'cc', 't', 'pp', 'v', 'models',
|
|
19
|
+
'PatchCollection', 'read_samples', 'reindex_by_sid', 'download_zenodo',
|
|
20
|
+
'train', 'fit', 'set_seed', 'latentreps', 'association', 'compute_mams',
|
|
18
21
|
'Fingerprints', 'cc', 'cell_type_counts', 'expression_profiles', 'test_features']
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Unified output control for vima.
|
|
2
|
+
|
|
3
|
+
All informational output in the package flows through a single ``logging``
|
|
4
|
+
logger (``vima._settings.logger``, named ``"vima"``) and a single progress-bar
|
|
5
|
+
helper (``settings.progress``). User-facing controls live on the module-level
|
|
6
|
+
``settings`` object, exposed as ``vima.settings``.
|
|
7
|
+
|
|
8
|
+
Three independent knobs:
|
|
9
|
+
|
|
10
|
+
* ``settings.verbosity`` -- how much informational output to emit. Three levels:
|
|
11
|
+
|
|
12
|
+
================== === ================ ==================================
|
|
13
|
+
name int logging level what is shown
|
|
14
|
+
================== === ================ ==================================
|
|
15
|
+
``"minimal"`` 0 ``WARNING`` warnings/errors, progress bars,
|
|
16
|
+
and results only (e.g. the
|
|
17
|
+
``association`` p-value)
|
|
18
|
+
``"default"`` 1 ``INFO`` + high-level progress messages
|
|
19
|
+
``"verbose"`` 2 ``DEBUG`` + detailed diagnostics
|
|
20
|
+
================== === ================ ==================================
|
|
21
|
+
|
|
22
|
+
* ``settings.diagnostic_plots`` -- how many diagnostic plots to draw, on the same
|
|
23
|
+
three-level scale as ``verbosity``: ``"minimal"`` draws none, ``"default"`` draws
|
|
24
|
+
the plots historically shown by default (QC, mean-variance, embeddings), and
|
|
25
|
+
``"verbose"`` additionally draws the more detailed plots. Until it is set
|
|
26
|
+
explicitly, it *tracks* ``verbosity`` -- so setting ``verbosity`` alone also
|
|
27
|
+
controls the plots; assigning ``diagnostic_plots`` decouples the two.
|
|
28
|
+
|
|
29
|
+
* ``settings.progress_bars`` -- whether tqdm progress bars are shown. Orthogonal
|
|
30
|
+
to verbosity (bars stay on even at ``"minimal"``); set ``False`` for batch or
|
|
31
|
+
cluster runs.
|
|
32
|
+
|
|
33
|
+
Guidelines for package code:
|
|
34
|
+
|
|
35
|
+
* ``logger.info(...)`` -- normal progress messages (visible at ``default``).
|
|
36
|
+
* ``logger.debug(...)`` -- detailed diagnostics (visible only at ``verbose``).
|
|
37
|
+
* ``logger.warning(...)`` -- warnings the user should see at every level.
|
|
38
|
+
* ``settings.result(...)`` -- user-facing results shown at every level.
|
|
39
|
+
* ``settings.progress(iterable, name=...)`` -- wrap any loop needing a bar.
|
|
40
|
+
* ``if settings.show_plots(...):`` -- guard a diagnostic plot. Pass ``"verbose"``
|
|
41
|
+
for the detailed plots; the default level guards the standard ones.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
import sys
|
|
45
|
+
import logging
|
|
46
|
+
from enum import IntEnum
|
|
47
|
+
|
|
48
|
+
from tqdm.auto import tqdm
|
|
49
|
+
|
|
50
|
+
__all__ = ["Verbosity", "settings", "logger"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Verbosity(IntEnum):
|
|
54
|
+
"""Amount of informational output emitted by vima."""
|
|
55
|
+
|
|
56
|
+
minimal = 0 # warnings + progress bars + results only
|
|
57
|
+
default = 1 # + high-level info messages (the historical default)
|
|
58
|
+
verbose = 2 # + detailed diagnostics
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def parse(cls, value):
|
|
62
|
+
"""Coerce an int, name string, or Verbosity into a Verbosity."""
|
|
63
|
+
if isinstance(value, cls):
|
|
64
|
+
return value
|
|
65
|
+
if isinstance(value, str):
|
|
66
|
+
try:
|
|
67
|
+
return cls[value]
|
|
68
|
+
except KeyError:
|
|
69
|
+
raise ValueError(
|
|
70
|
+
f"unknown verbosity {value!r}; "
|
|
71
|
+
f"expected one of {[v.name for v in cls]} or 0/1/2"
|
|
72
|
+
)
|
|
73
|
+
return cls(value)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
_LOGGING_LEVELS = {
|
|
77
|
+
Verbosity.minimal: logging.WARNING,
|
|
78
|
+
Verbosity.default: logging.INFO,
|
|
79
|
+
Verbosity.verbose: logging.DEBUG,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
logger = logging.getLogger("vima")
|
|
83
|
+
|
|
84
|
+
# ANSI colors: debug messages are grayed out, results are green.
|
|
85
|
+
_GRAY, _GREEN, _RESET = "\033[90m", "\033[32m", "\033[0m"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class _ColorFormatter(logging.Formatter):
|
|
89
|
+
"""Format log records, graying out DEBUG-level messages."""
|
|
90
|
+
|
|
91
|
+
def format(self, record):
|
|
92
|
+
msg = super().format(record)
|
|
93
|
+
if record.levelno == logging.DEBUG:
|
|
94
|
+
return f"{_GRAY}{msg}{_RESET}"
|
|
95
|
+
return msg
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class _TqdmLoggingHandler(logging.StreamHandler):
|
|
99
|
+
"""Route log records through ``tqdm.write`` so they never corrupt an active
|
|
100
|
+
progress bar. When no bar is live, ``tqdm.write`` degrades to a plain write
|
|
101
|
+
to the stream, so logging in loops without a bar is unaffected. This keeps
|
|
102
|
+
the two output channels fully decoupled: progress bars honor
|
|
103
|
+
``settings.progress_bars`` and log messages honor ``settings.verbosity``,
|
|
104
|
+
independent of each other.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
def emit(self, record):
|
|
108
|
+
try:
|
|
109
|
+
msg = self.format(record)
|
|
110
|
+
tqdm.write(msg, file=self.stream, end=self.terminator)
|
|
111
|
+
except Exception:
|
|
112
|
+
self.handleError(record)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Settings:
|
|
116
|
+
"""Global vima output settings; access via the ``vima.settings`` singleton."""
|
|
117
|
+
|
|
118
|
+
def __init__(self):
|
|
119
|
+
# Attach a single stdout handler and keep our records off the root
|
|
120
|
+
# logger so vima's output is independent of any host logging config.
|
|
121
|
+
# The "vima" logger is a process-global singleton that survives module
|
|
122
|
+
# reloads, so clear any handler we previously attached before adding a
|
|
123
|
+
# new one; otherwise re-importing vima (e.g. importlib.reload in a
|
|
124
|
+
# notebook) accumulates handlers and every message prints N times.
|
|
125
|
+
# Match by class *name*, not isinstance: each reload defines a fresh
|
|
126
|
+
# _TqdmLoggingHandler class, so handlers left by earlier reloads are
|
|
127
|
+
# instances of a different (stale) class object and would fail an
|
|
128
|
+
# isinstance check against the current class.
|
|
129
|
+
for h in list(logger.handlers):
|
|
130
|
+
if type(h).__name__ == "_TqdmLoggingHandler":
|
|
131
|
+
logger.removeHandler(h)
|
|
132
|
+
handler = _TqdmLoggingHandler(sys.stdout)
|
|
133
|
+
handler.setFormatter(_ColorFormatter("%(message)s"))
|
|
134
|
+
logger.addHandler(handler)
|
|
135
|
+
logger.propagate = False
|
|
136
|
+
|
|
137
|
+
self.progress_bars = True
|
|
138
|
+
self._verbosity = None
|
|
139
|
+
# ``diagnostic_plots`` tracks ``verbosity`` until the user sets it.
|
|
140
|
+
self._diagnostic_plots = None
|
|
141
|
+
self._diagnostic_plots_explicit = False
|
|
142
|
+
self.verbosity = Verbosity.default
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def verbosity(self):
|
|
146
|
+
"""Current :class:`Verbosity` level (see module docstring)."""
|
|
147
|
+
return self._verbosity
|
|
148
|
+
|
|
149
|
+
@verbosity.setter
|
|
150
|
+
def verbosity(self, value):
|
|
151
|
+
self._verbosity = Verbosity.parse(value)
|
|
152
|
+
logger.setLevel(_LOGGING_LEVELS[self._verbosity])
|
|
153
|
+
if not self._diagnostic_plots_explicit:
|
|
154
|
+
self._diagnostic_plots = self._verbosity
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def diagnostic_plots(self):
|
|
158
|
+
""":class:`Verbosity` level controlling how many diagnostic plots are drawn.
|
|
159
|
+
|
|
160
|
+
Tracks :attr:`verbosity` until assigned; assigning it decouples the two.
|
|
161
|
+
"""
|
|
162
|
+
return self._diagnostic_plots
|
|
163
|
+
|
|
164
|
+
@diagnostic_plots.setter
|
|
165
|
+
def diagnostic_plots(self, value):
|
|
166
|
+
self._diagnostic_plots = Verbosity.parse(value)
|
|
167
|
+
self._diagnostic_plots_explicit = True
|
|
168
|
+
|
|
169
|
+
def show_plots(self, level=Verbosity.default):
|
|
170
|
+
"""Whether diagnostic plots at ``level`` should be drawn.
|
|
171
|
+
|
|
172
|
+
``level`` is anything :meth:`Verbosity.parse` accepts (default the
|
|
173
|
+
standard-plot level); pass ``"verbose"`` for the more detailed plots.
|
|
174
|
+
"""
|
|
175
|
+
return self._diagnostic_plots >= Verbosity.parse(level)
|
|
176
|
+
|
|
177
|
+
def progress(self, iterable=None, name=None, total=None, ncols=100, desc=None, **kwargs):
|
|
178
|
+
"""tqdm wrapper honoring ``settings.progress_bars``.
|
|
179
|
+
|
|
180
|
+
Central replacement for the per-module ``pb = lambda ...`` helpers.
|
|
181
|
+
``name`` is a brief label for the loop, shown as the tqdm ``desc``
|
|
182
|
+
prefix (``desc`` is still accepted as an alias; ``name`` wins).
|
|
183
|
+
"""
|
|
184
|
+
using_widget = any(
|
|
185
|
+
cls.__module__ == "tqdm.notebook"
|
|
186
|
+
for cls in tqdm.mro()
|
|
187
|
+
)
|
|
188
|
+
return tqdm(
|
|
189
|
+
iterable, desc=name if name is not None else desc, total=total,
|
|
190
|
+
ncols=ncols * (7 if using_widget else 1),
|
|
191
|
+
bar_format='{l_bar}{bar}{r_bar}',
|
|
192
|
+
disable=not self.progress_bars, **kwargs,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def result(self, message):
|
|
196
|
+
"""Emit a user-facing result, shown at every verbosity level."""
|
|
197
|
+
tqdm.write(f"{_GREEN}{message}{_RESET}", file=sys.stdout)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
settings = Settings()
|