-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
mvinyard
committed
Oct 15, 2022
1 parent
a6ac14a
commit 4654b2c
Showing
7 changed files
with
235 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
|
||
from . import _idx_funcs as idx | ||
from . import _idx_funcs as idx | ||
# specify version: ----------------------------------------------------------------------- | ||
__version__ = "0.0.18" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,10 @@ | |
__email__ = ", ".join(["[email protected]",]) | ||
|
||
|
||
|
||
# specify version: ----------------------------------------------------------------------- | ||
__version__ = "0.0.18" | ||
|
||
# ----------------------------------------------------------------------------- | ||
from ._binominal_test_train_assignment import binominal_test_train_assignment | ||
from ._count_obs_neighbors import count_obs_neighbors | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
__module_name__ = "__init__.py" | ||
__author__ = ", ".join(["Michael E. Vinyard"]) | ||
__email__ = ", ".join(["[email protected]",]) | ||
|
||
|
||
|
||
# specify version: ----------------------------------------------------------------------- | ||
__version__ = "0.0.18" | ||
|
||
# Modules and functions: ------------------------------------------------------ | ||
from ._kNN_map_source_to_target import map_source_to_target | ||
from ._iterative_kNN_smoothing import smooth | ||
from ._annotate_adata_bool_idx import add_bool_idx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import licorice_font | ||
import numpy as np | ||
|
||
def _print_key_added(key_added): | ||
|
||
note = licorice_font.font_format("NOTE", ["BLUE"]) | ||
key_print = licorice_font.font_format(key_added, ["BOLD"]) | ||
print(" - [{}] | obs_key added: {}".format(note, key_print)) | ||
|
||
|
||
|
||
def add_bool_idx(adata, idx, key_added="bool_idx", silent=False): | ||
|
||
# _annotate_adata_bool_idx | ||
|
||
tmp = np.zeros(len(adata)) | ||
tmp[idx] = 1 | ||
adata.obs[key_added] = tmp.astype(bool) | ||
|
||
if not silent: | ||
_print_key_added(key_added) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import anndata | ||
import pandas as pd | ||
import numpy as np | ||
from tqdm.notebook import tqdm | ||
import vinplots | ||
import matplotlib.pyplot as plt | ||
|
||
|
||
from .._core._SpotifyAnnoy import SpotifyAnnoy as kNN | ||
from ._annotate_adata_bool_idx import add_bool_idx | ||
|
||
def _plot_smoothing(adata, score_idx, scores, n_iters): | ||
|
||
X_umap = adata[score_idx].obsm["X_umap"] | ||
|
||
nplots = n_iters + 1 | ||
fig, axes = vinplots.quick_UMAP(nplots=nplots, ncols=nplots) | ||
|
||
c_idx = np.argsort(scores[0]) | ||
axes[0].scatter( | ||
X_umap[:, 0], X_umap[:, 1], c="lightgrey", s=2, rasterized=True, zorder=0 | ||
) | ||
axes[0].scatter( | ||
X_umap[c_idx, 0], | ||
X_umap[c_idx, 1], | ||
c=scores[0][c_idx], | ||
rasterized=True, | ||
zorder=1, | ||
) | ||
axes[0].set_title("Mapped (unsmoothed)") | ||
|
||
for i in range(1, nplots): | ||
axes[i].scatter( | ||
X_umap[:, 0], | ||
X_umap[:, 1], | ||
c="lightgrey", | ||
rasterized=True, | ||
zorder=0, | ||
) | ||
c_idx = np.argsort(scores[i]) | ||
axes[i].scatter( | ||
X_umap[c_idx, 0], | ||
X_umap[c_idx, 1], | ||
c=scores[i][c_idx], | ||
rasterized=True, | ||
zorder=1, | ||
) | ||
axes[i].set_title("iter: {}".format(i)) | ||
plt.show() | ||
|
||
|
||
def smooth( | ||
adata: anndata.AnnData, | ||
score: pd.Series, | ||
plot=False, | ||
n_iters: int = 5, | ||
n_neighbors: int = 20, | ||
func: bool = False, | ||
) -> np.ndarray: | ||
|
||
idx, score = score.index.astype(int), score.values.astype(float) | ||
curr = np.zeros(score.shape) | ||
scores, prev = [score], score | ||
|
||
add_bool_idx(adata, idx, key_added="tmp_bool", silent=True) | ||
|
||
kNN_Graph = kNN(adata) | ||
kNN_Graph.build(subset="tmp_bool") | ||
|
||
X_query = adata[idx].obsm["X_pca"] | ||
|
||
for _ in tqdm(range(n_iters)): | ||
X_nn = kNN_Graph.query(X_query) | ||
curr = prev[X_nn] | ||
if func: | ||
curr = func(curr) | ||
else: | ||
curr = curr.mean(1) | ||
prev = curr | ||
scores.append(curr) | ||
|
||
if plot: | ||
_plot_smoothing(adata, idx, scores, n_iters) | ||
|
||
return curr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
|
||
__module_name__ = "_kNN_map_source_to_target.py" | ||
__author__ = ", ".join(["Michael E. Vinyard"]) | ||
__email__ = ", ".join(["[email protected]",]) | ||
|
||
|
||
# import packages: ------------------------------------------------------------ | ||
import pandas as pd | ||
import numpy as np | ||
import anndata | ||
|
||
|
||
# import local dependencies: -------------------------------------------------- | ||
from .._core._SpotifyAnnoy import SpotifyAnnoy as kNN | ||
|
||
|
||
# Supporting functions: ------------------------------------------------------- | ||
def _add_source_target_exclude_col( | ||
adata, | ||
source_idx, | ||
target_idx, | ||
): | ||
|
||
tmp = np.full(len(adata), "exclude") | ||
tmp[source_idx] = "source" | ||
tmp[target_idx] = "target" | ||
|
||
adata.obs["kNN_mapping"] = pd.Categorical(tmp) | ||
|
||
adata.obs["source"] = adata.obs["kNN_mapping"] == "source" | ||
adata.obs["target"] = adata.obs["kNN_mapping"] == "target" | ||
|
||
adata.obs.drop("kNN_mapping", axis=1, inplace=True) | ||
|
||
|
||
def _source_target_query(adata, use_key): | ||
|
||
"""build and query kNN index""" | ||
|
||
G = kNN(adata) | ||
G.build(subset="source") | ||
X_query = adata[adata.obs["target"]].obsm[use_key].toarray() | ||
|
||
return G.query(X_query) | ||
|
||
|
||
def _merge_ref_map_values(adata, obs_key, X_nn): | ||
|
||
ref_values = adata[adata.obs["source"]].obs[obs_key].values | ||
map_values = ref_values[X_nn].mean(1) | ||
|
||
tmp = np.full(len(adata), None) | ||
tmp[adata.obs["source"]] = ref_values | ||
tmp[adata.obs["target"]] = map_values | ||
adata.obs["{}_mapped".format(obs_key)] = tmp | ||
|
||
adata.obs.drop(["source", "target"], axis=1, inplace=True) | ||
|
||
|
||
# Main module function: ------------------------------------------------------- | ||
def map_source_to_target( | ||
adata: anndata.AnnData, | ||
source_idx: pd.Index, | ||
target_idx: pd.Index, | ||
obs_key: str, | ||
use_key="X_pca", | ||
): | ||
|
||
""" | ||
Using a kNN graph, map a value in a source set of cells to a target set of cells. | ||
Parameters: | ||
----------- | ||
adata | ||
type: anndata.AnnData | ||
source_idx [ required ] | ||
type: pandas.Index | ||
target_idx [ required ] | ||
type: pandas.Index | ||
obs_key [ required ] | ||
type: str | ||
use_key | ||
type: str | ||
default: "X_pca" | ||
Returns: | ||
-------- | ||
None, updates adata.obs with "{obs_key}_mapped" | ||
Notes: | ||
------ | ||
(1) annotates source/target in the adata.obs table | ||
(2) build (based on the source) a kNN graph and query (using the target) | ||
(3) merge mapped / references values | ||
""" | ||
_add_source_target_exclude_col(adata, source_idx, target_idx) | ||
X_nn = _source_target_query(adata, use_key) | ||
_merge_ref_map_values(adata, obs_key, X_nn) | ||
|