Skip to content

Commit

Permalink
semantic updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mvinyard committed Oct 15, 2022
1 parent a6ac14a commit 4654b2c
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 2 deletions.
5 changes: 4 additions & 1 deletion annoyance/_core/__init__.py
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"

5 changes: 4 additions & 1 deletion annoyance/_core/_idx_funcs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
from ._build import build
from ._query import query
from ._save import save
from ._load import load
from ._load import load
# specify version: -----------------------------------------------------------------------
__version__ = "0.0.18"

4 changes: 4 additions & 0 deletions annoyance/_interactive_funcs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions annoyance/_map/__init__.py
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
21 changes: 21 additions & 0 deletions annoyance/_map/_annotate_adata_bool_idx.py
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)
85 changes: 85 additions & 0 deletions annoyance/_map/_iterative_kNN_smoothing.py
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
103 changes: 103 additions & 0 deletions annoyance/_map/_kNN_map_source_to_target.py
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)

0 comments on commit 4654b2c

Please sign in to comment.