diff --git a/.travis.yml b/.travis.yml
index e508941c6..1a6f6235a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -78,6 +78,9 @@ jobs:
- name: Simulation Notebook
if: type = push and (branch = master or branch =~ /-alltest/)
script: make install-dev notebooks/py/Starfish_simulation.py
+ - name: Graph-based Decoding Notebook
+ if: type = push and (branch = master or branch =~ /-alltest/)
+ script: make install-dev notebooks/py/graph_decoding.py
- name: ISS Notebook
if: type = push and (branch = master or branch =~ /-alltest/)
script: make install-dev notebooks/py/ISS.py
diff --git a/notebooks/graph_decoding.ipynb b/notebooks/graph_decoding.ipynb
new file mode 100644
index 000000000..ce571c22d
--- /dev/null
+++ b/notebooks/graph_decoding.ipynb
@@ -0,0 +1,1338 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Graph-based Decoding\n",
+ "\n",
+ "This notebook walks through how to use a Graph-based decoding approach [1] to process spatial transcriptomic data. Graph-based decoding can only be applied to assays with one-hot-encoding codebooks (i.e. a single fluorescent channel active per round). We will first see how the graph-based decoding module works with some toy examples, and after we apply it on a real application with in situ sequencing data.\n",
+ "\n",
+ "The graph based decoding module ```LocalGraphBlobDetector``` builds a graph out of the candidate spots detected by an arbitrary spot finder algorithm (please see [documentation](https://spacetx-starfish.readthedocs.io/en/stable/) for a list of spot finder algorithms included in the module). Nodes of the graph representing detected spots are then connected with edges based on spatial distances. Cost weights proportional to the distance and quality of the detected spots are then assigned to each edge connecting a pair of nodes. Genes are finally decoded by optimizing the graph with respect to the edge costs providing the best spots configuration with higher qualities and smaller distances.\n",
+ "\n",
+ "In details, ```LocalGraphBlobDetector``` first finds spots for every channel and round. Four possible spot detectors are integrated from [scikit-image](https://scikit-image.org/), two based local maxima and two blob detection algorithms. Secondly, overlapping spots are merged across channels within each round in order to handle fluorescent bleed-trough. Next, a quality score is assigned for each detected spot (maximum channel intensity divided by channel intensity vector l2-norm). Detected spots belonging to different sequencing rounds and closer than `search_radius` are connected in a graph, forming connected components of spot detections. Next, for each connected component, edges between not connected spots belonging to consecutive rounds are forced if they are closer than `search_radius_max`. Finally, all the edges that connect spots not belonging to consecutive rounds are removed and each connected component is solved by maximum flow minimum cost algorithm. Where, costs are proportional to spot quality and distances. \n",
+ "\n",
+ "[1] Partel, G. et al. Identification of spatial compartments in tissue from in situ sequencing data. BioRxiv, https://doi.org/10.1101/765842, (2019)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib inline\n",
+ "\n",
+ "import numpy as np\n",
+ "import os\n",
+ "import pandas as pd\n",
+ "import matplotlib\n",
+ "import matplotlib.pyplot as plt\n",
+ "import pprint\n",
+ "from scipy.ndimage.filters import gaussian_filter\n",
+ "from starfish.core.spots.DetectSpots.local_graph_blob_detector import LocalGraphBlobDetector\n",
+ "from starfish.core.spots.DetectSpots.local_search_blob_detector import LocalSearchBlobDetector\n",
+ "\n",
+ "\n",
+ "from starfish import data, FieldOfView, ImageStack\n",
+ "from starfish.types import Features, Axes\n",
+ "from starfish.util.plot import imshow_plane"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 1\n",
+ "We first see an example on how to tune two important parameters, `search_radius` and `search_radius_max`, that define the graph connections of detected spots. We start by creating three synthetic spots laying in two channels and three sequential rounds (color coded with red, green and blue colors). Each of the spot has 3px shift in x,y respect to the spot in the previous round."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Create synthetic data\n",
+ "img = np.zeros((3, 2, 1, 50, 50), dtype=np.float32)\n",
+ "\n",
+ "# code 1\n",
+ "# round 1\n",
+ "img[0, 0, 0, 35, 35] = 10\n",
+ "# round 2\n",
+ "img[1, 1, 0, 32, 32] = 10\n",
+ "# round 3\n",
+ "img[2, 0, 0, 29, 29] = 10\n",
+ "\n",
+ "# blur points\n",
+ "gaussian_filter(img, (0, 0, 0, 1.5, 1.5), output=img)\n",
+ "stack = ImageStack.from_numpy(img)\n",
+ "\n",
+ "plt.imshow(np.moveaxis(np.amax(np.squeeze(img),axis=1),0,-1))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We now decode the sequence with `LocalGraphBlobDetector` setting `search_radius` to an approximate value representing the euclidean distance between two spots belonging to different sequencing rounds, and `search_radius_max` to a value representing the maximum euclidean distance between all the spots of the same sequence."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 6/6 [00:00<00:00, 374.49it/s]\n",
+ "100%|██████████| 3/3 [00:00<00:00, 279.30it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 219.77it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 19.25it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 181.48it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n",
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[0.70737, 0. , 0.70737],\n",
+ " [0. , 0.70737, 0. ]]])\n",
+ "Coordinates:\n",
+ " radius (features) int64 0\n",
+ " z (features) int64 0\n",
+ " y (features) int64 35\n",
+ " x (features) int64 35\n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 0.0007143\n",
+ " yc (features) float64 0.0007143\n",
+ " zc (features) float64 0.0\n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# search_radius=5, search_radius_max=10\n",
+ "lgbd = LocalGraphBlobDetector(search_radius=5, search_radius_max=10, h=0.5)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "# One sequence decoded\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 3/3 [00:00<00:00, 275.43it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 349.61it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 33.28it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 288.84it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n",
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([], shape=(0, 2, 3), dtype=float64)\n",
+ "Coordinates:\n",
+ " radius (features) int64 \n",
+ " z (features) int64 \n",
+ " y (features) int64 \n",
+ " x (features) int64 \n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 \n",
+ " yc (features) float64 \n",
+ " zc (features) float64 \n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# search_radius=5, search_radius_max=5\n",
+ "lgbd = LocalGraphBlobDetector(search_radius=5, search_radius_max=5, h=0.5)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "# Zero sequence decoded\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 2\n",
+ "We now change the distances between the spots such that the 3rd round spot (blue) lay between the other two, and compare the results with other decoding approaches."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Create synthetic data\n",
+ "img = np.zeros((3, 2, 1, 50, 50), dtype=np.float32)\n",
+ "\n",
+ "# code 1\n",
+ "# round 1\n",
+ "img[0, 0, 0, 35, 35] = 10\n",
+ "# round 2\n",
+ "img[1, 1, 0, 29, 29] = 10\n",
+ "# round 3\n",
+ "img[2, 0, 0, 32, 32] = 10\n",
+ "\n",
+ "# blur points\n",
+ "gaussian_filter(img, (0, 0, 0, 1.5, 1.5), output=img)\n",
+ "stack = ImageStack.from_numpy(img)\n",
+ "\n",
+ "plt.imshow(np.moveaxis(np.amax(np.squeeze(img),axis=1),0,-1))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 6/6 [00:00<00:00, 396.28it/s]\n",
+ "100%|██████████| 3/3 [00:00<00:00, 274.14it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 361.83it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 22.56it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 175.95it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n",
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[0.70737, 0. , 0.70737],\n",
+ " [0. , 0.70737, 0. ]]])\n",
+ "Coordinates:\n",
+ " radius (features) int64 0\n",
+ " z (features) int64 0\n",
+ " y (features) int64 35\n",
+ " x (features) int64 35\n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 0.0007143\n",
+ " yc (features) float64 0.0007143\n",
+ " zc (features) float64 0.0\n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# LocalGraphBlobDetector\n",
+ "lgbd = LocalGraphBlobDetector(\n",
+ " search_radius=5,\n",
+ " search_radius_max=10,\n",
+ " detector_method='blob_log',\n",
+ " min_sigma=(0.4, 1.2, 1.2),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.1,\n",
+ " overlap=0.5)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`LocalSearchBlobDetector` decode the correct sequence only if `anchor_round` is set to the round of the spot lying in the middle, otherwise will fail to connect all the spots."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[0.70737, nan, 0.70737],\n",
+ " [ nan, nan, nan]]])\n",
+ "Coordinates:\n",
+ " radius (features) float64 1.333\n",
+ " z (features) int64 0\n",
+ " y (features) int64 35\n",
+ " x (features) int64 35\n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 0.0007143\n",
+ " yc (features) float64 0.0007143\n",
+ " zc (features) float64 0.0\n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# LocalSearchBlobDetector\n",
+ "# Anchor round: 1st round\n",
+ "lgbd = LocalSearchBlobDetector(\n",
+ " search_radius=5,\n",
+ " min_sigma=(0.4, 1.2, 1.2),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.1,\n",
+ " overlap=0.5,\n",
+ " anchor_round=0)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[0.70737, nan, 0.70737],\n",
+ " [ nan, 0.70737, nan]]])\n",
+ "Coordinates:\n",
+ " radius (features) float64 1.333\n",
+ " z (features) int64 0\n",
+ " y (features) int64 32\n",
+ " x (features) int64 32\n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 0.0006531\n",
+ " yc (features) float64 0.0006531\n",
+ " zc (features) float64 0.0\n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# LocalSearchBlobDetector\n",
+ "# Anchor round: 3rd round\n",
+ "lgbd = LocalSearchBlobDetector(\n",
+ " search_radius=5,\n",
+ " min_sigma=(0.4, 1.2, 1.2),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.1,\n",
+ " overlap=0.5,\n",
+ " anchor_round=2)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 3\n",
+ "Let's now add some noise and multiple possible decoding choices. Specifically, the second round has two possible spot candidates one a bit weaker than the other, both equally spaced respect from the spots of the other rounds. `LocalGraphBlobDetector` provides the best possible decoding solution choosing the spot with highest quality for the second round since distance costs are equivalent. The results of `LocalSearchBlobDetector` strongly depends from the initialization of the anchor round (i.e. from where to start the search), providing different solutions for each initialization. \n",
+ "(Please note that when anchor round is set to the second round, two sequences are decoded, the correct one plus a false positive.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPsAAAD6CAYAAABnLjEDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO2daahl2XXf/+uMd773DTV1V8ndjhUZZbBMOsLGIRg5AkU2lj6YYBOCAoL+koCME2wlgYAhH5QEEvtDYiNskw4Yy5PAQhiC4sgYGyNL1mBbEpJaLam7ql7Vq/fuu/Nwpp0P9UrvrrV2d5Wqum+90lk/aPqdU2fYZ5+zz7nrv9dAzjkYhvHdT/C4G2AYxnawwW4YNcEGu2HUBBvshlETbLAbRk2wwW4YNeGRBjsRvYuIvkJELxLRB1+vRhmG8fpDDzvPTkQhgK8CeCeA6wA+DeBnnHNfetV9AnKbrxeq9LvGgbcnCPhyBVL7BMS3oVIft3QVW44i/u9FGap9EtE3BVVqG8ndbtk4b1XKLTx7pWwpwIot++5QItq/9mwUiVMVhedAgvu9/SnQ7a9EP8lHKkKi9imQizX6AgLZGnGf5bMCAE7exkK0l0THAYBqCycMPc9T8drPgqebUInm0gM8y6XcJvLcaNF855zvIYPvyh+UtwN40Tn3EgAQ0UcAvAfAqw52BEDQP+u4dN5Um6zFoGx21mx5SXxgAEAz5Nuko5baZlQs2PJgh//7cNpX+zyd8dFxGM74Bp4ujdIOW57OxT6I9U54li218BW27BujT+/x5W95ntc98YzeGcot9AU0xHIgBlTa1o/MQvTTWrRlD1fUPndwW6zJ1DZN8OeDEr7NutIDrtwRg+GO6O90V+0Dd8iXxWF7PdkrwHi45CtEX7c8b82FuJEh9AemlfKPw7zg21QX5ccDwMHGv3v65FWa+B3xNIBXNpavn64zDOMc8ihf9geCiJ4H8DwAkwMN4zHyKIP9BoBrG8tXT9cxnHMfBvBhAKCEXLDxyywa6Z/k64D/7E1G/Of1sqFtlt0d/jN+0V6obTDmP1mzE37pzUr/Dr7embNladbvR8IWADCdnrBl+UOtjPU+YX6HLavWe+7SN056bLlFE7XNUHTvYMBNjGjKrw8A1sKmrRLeLyfOY1S8WSzf5It3Rq9A0urw+0Gew847/KdyOuTm2aWKaxsAMGzxa1wNxBdmIc0HoCksiEyaHTPdtxIp51SV/ul/scvbO27rn+TuFjc7doRBPvQ0pYWzZ2GO6au28VG+tZ8G8GYiepaIEgA/DeBjj3A8wzDeQB76y+6cK4joXwP4P7j7AfsN59wXX7eWGYbxuvJINrtz7g8B/OHr1BbDMN5ATDIzjJrw0E41D3UyCl0QtL+9HEELREXAVaXmU1zIiY/0+2nS5ZJWdKettil6Yh59IlQkrncBAJIJP3cTl9jyGGriGuhwtScR0+xZU8+tPp1z0e52ccSWC8987FNi3S2tBwFr3pYq5D/keg2tilWry2y5LMdsOWzquflZJiTFHj/G9y51P7207PIVgZ5nD9/EO688FM45CRdmAYAWXOBy8YCfZu5xSGiM2GI35H1LgRbSphF/xsqIP8vRHS0+Fylf117r4xZNLuKtl9zXINnRomQ2OrvmqlzCudLrVGNfdsOoCTbYDaMm2GA3jJqwXZs9CFwQndkXUaD9eNs5tyvLBrfl0o72YT85EsEz0J4HaZfbYdGUO06MW9fVPt0FtxGnJGysi9rPOiHu1NAecxtrtdRBIUnKDe5xIeyyUNt20o50K+1z3xMOGXPubwKfZbcjfDJG3ORFxM1bAEB+iQse8THv/zzV35Qk4TZ7pF2JsDrh7ZeRFPNL2i5uzIUdLzQTbfECaAlbmvh507m+Z/EFfqRjIfrEc/0MluISs4YWWijlNyUR4yEOtdNMMT3bZ1WVKF8lEMa+7IZRE2ywG0ZNsMFuGDVhy/Ps5ILg7P3SxlXPVjyWJu3z9k3G2k7rC3v8eKnnUgcic0MBbjMu4AlKEH4AYmYY04ae/3YdrkP0jrilOfHEbeNv8eN0SpGMY6W1jeQWn5sP+3rO/LDD+yEQsfW+YI32hL//pS093pO9AHRm3I7M1tzGpYHup3DEg1x86SPytrjXOT9uGmv7VSbx6AmXi4bHNeLwMre3+wUPuMkKHTyzHIkTiccn8PhtOCEYkJYCEHe4jb6e8vvazrTT6yo802uK1RJVafPshlFrbLAbRk2wwW4YNcEGu2HUhK0KdCGFrr2Rqmal0hsC1yKe6WUkdKfRvufAQt3pjvVxm7FI3LfHxbeJJ7lNR/hFzIReFHpy+y0b3NEm7okgi6FWboYFvwdhyJWccqUDPiCcL9qeTKup4/1wSbTtldyT9sRx55ws5NtkDeGZA2D/mKtTR1KEbHv0IuGoknjSagYi2IfARb22zleKoUjhGva5V1DzkAf2AMBCOCjF4j5HS33PpiS8dZxojMcRCqW8jw8y9ng/NTxR6fmGiFpUFSpzqjGMemOD3TBqgg12w6gJ23WqiUIXdM5svv5U2x+ZsGMiEbqw2te2XX50Tay5qbbRRQgu8MXwDhQ7IuhGCggexwksRUIOoSd0PNVR1hW3pbvRLbY8zUQ0CoBCaAHOY35fEGbknYDb442mdmVZrYVNnnHbNEx08E/phKeK8KG5II8JoBjw45542r8nHGKyI+7sMnVaaHlGdNVNUcshK7SDTxSLTL2OO+u4tX5Op8RPFA2O+TE8STKWwvkrP9YOSrjEn9P9E36N7T3dlm9NzoK6qvkBXLk2m90w6owNdsOoCTbYDaMm2GA3jJqwVYEuInL9jfK3cXJBbZPFXCgbL7mo1E+1KjaTlV9znU5llYryy3NRhimV1VaBuMdFluqIizIXQn2ecYurSqsWF+yCW1ogaggHGdrj2xS3tffOquTrPLVJEQmx83DAvUVoJtQrAE6IYv1xKP7dkzVHyEFj3ZUanoAW6S3tLZWDZ9mVvjlTj0AqezcRDjJLjyiMAT9Qs+CC4yrQkZbuNneQ6XUusuWFR6Cr2txhrJr5UgJzmsKJZnlNd254cqbEFjOLejOM2mOD3TBqgg12w6gJW7XZg4hcY3Bmg5QnnuyyDW4fjVWwg34/hSfc9mxc1plW53eEDVVymz3d07Z0LCqZzFaiQkyiIzH6K25T3ZI+NK09tc+VEXfimII78ySe7DYr4Wy08ARVDCCqo3S5vT2eenKtRsIrpeK6xAXdTZhL3xDhILOMnlb7BCF3fErzltomz7jeUfX49dDE46yTCk2hye9HMNIlszsBf34mLdEvnoCb+A5/DvdEIM+4qa8nXfJtJm3tYFU5/vz3F9xZxxPjhWCjuUVVwVkgjGHUGxvshlETbLAbRk3YcvKKwLU25iwX0LZ1e8ANpHzEbRbnSXiR/4CYL37FY2RVfJu3iCnyr/heeyJApd3hNvzcN58cicyqCdclWoUO5JmX3PZslsLObOoJ5VVDJK840UEhE3D7NGnzbVpzPc9eijSpUzHPu9vQ89TDlbCTI66PRNCBPI0dbo/npOey40JkwxX9vch0tV6AH2dPVNodyYl3AHHFnxfqcY1kXekxUo1ERVxw3WUGbbNXl4UpfUv3/y7x5yVwXCQ58jz/uHbWD9XBEdw6N5vdMOqMDXbDqAk22A2jJtx3sBPRbxDRIRH9zca6XSL6BBF97fT/evLSMIxzxX0FOiL6x7hb+PZ/O+f+7um6/wJg6Jz7EBF9EMCOc+4X7nsyClwQbAgMlzxZUycycoG/jzp7WtSYTYQY4osDaIgMMpFwbsk8/RAI54oVF2XapN+V85KLU0+1uCB3c6EFrqglAl8y7pXS9WRXKUVACgU66wlNuWgUCbFttKPFQoiuS4f8GpueTDvTARe0ypFMz+r5FhSHbDH0aG1uzlfGQjyMZD1mAEHKg6uqnAdWLRq6LW7BhcuGcD5yDZkJCVjPv8mW+wv+/OgctlAZgbGnn7n9m7x/xxHfJw/eovZpZF/+9t+rKkPpqocT6JxzfwJAVsh6D4AXTv9+AcB773ccwzAeL554vwfiknPu4PTvWwAuvdqGRPQ8gOdPlx7ydIZhPCqPLNC5u3bAq9oCzrkPO+eec84996jnMgzj4XnYL/ttIrrinDsgoisADu+7BwAihyQ+s9NzT51et5R2PHdsWZ5oZ4WGE/a40846uUiWUL7Ej5Mmr6h9wph3T1nxfeYiuQIA5SZ0U8T6xInWKfKQ/+LpF9yuzEWVHADoznlbjqCDWkRBGHzfiu+zlJlwAYSiOsoi4e/xZlefp7vkdvK4xe3kpNI6y1rIBUnRV9ssRWretSgf3fYE5QzXXKdoPsP/3X1T92WwwzuqccIbN8q/qfYJWzzZxnjBrfRBUwcvjVIeELR/67o+7vfwZ6HxLaFBBF9T+yQbz/bakyT5Hg/7Zf8YgPed/v0+AH/wkMcxDGNLPMjU228B+HMAbyGi60T0fgAfAvBOIvoagH9yumwYxjnmvj/jnXM/8yr/9GOvc1sMw3gD2W5FmIBc0Nj4MeGZZm82+dyqE3ZlGuggF5dwG2ux0qp/SwSkLAtuxOeptis7BbcRi5xvs/IGz4gkmvvc7txb6NInswGfI49m3P6bF1qnuFrya74e6ACJvYD3ZVXwBs/6PMgIAKpEVJAteH8nTt+0TCXEFHP+0RQKYbP3PRkieinvu9vrN/HzQhuosXiochIncvqmNRp8m0zsUnncEWLhF9AkISAEOjFLKnTso4luSxLx/cKCq0CrnieRZXX2za5mOVz5kPPshmF8d2CD3TBqgg12w6gJNtgNoyZsvSJMJzh7vzQHejLgUJRFjkRd5CLwqHqVWEc6qqLluJPDQpTP3S20E8Qi56LRquDiSeMpLZbQird/ORTi2o7OKNMSmVISITKlnpSiY+FgUng8TIo5z4DTucCFv9VQB7UUgVjnRBaaUguZotgOMlGXxUGLVbgid/J8d074ukaLL8dLfc+mTf5MJTN+P4pI91MV82vsykvU3YQi405AxT4XXpOxHleR0M2m5MmA0xdCZYffwyDT1xwdnP29riaoXGECnWHUGRvshlETbLAbRk142ECYh6ICYRGc2UxF2xMZW9xgi7TiDhl9T6bPsTTR57rS6DJ9hi3vzL/FloeVtos7TwmHHpGRdqVjKiCLt6Qi4ULlsb8XxI1E2uXZWOcdnaQhz/k2z6y058cq4jb6rTu80mgaaGeXIhH1YEuuDaSFtr/X4hrDLneqcVPdUdEB1zKknQ8A10TQUDHjAUIHvdtqH/S5gR0J750s08+G1HhWolJLLm88gN2h0JZK/lxOPUE6ldDHYk/AVveY9+/RMTe/Q0+AaRqe6QW58+gjp9iX3TBqgg12w6gJNtgNoyZst4prGLqoeTaPmJKeM1+IxH1diKSDLW3zDkWl0RbpoIoq4/ZpLF5zU88+yEQ1F5GaopLRHADyDg8kacy4n8BKljgF4BJh44rklxH03HbeFNuQttUaIs/ErMVt0as9vc/RCTc2V+LU/St6n+wWb4sTUSKrUqdfbIsiN/O1TgRJmdhPBPI46Iq4A5GEctQTz7fTfg67wl1i0uIBN8h5xVkACBIud2UkbOuRfk7Lgl9P4PE/kGtSkdNjPbsISRieHbdYr1BVFghjGLXGBrth1AQb7IZRE2ywG0ZN2G6mGiIXbATCRBe1KFacCEUo4KIYeZwvnCyGkuvMLoEMdJlzsSr1ZGethFyyFhViKNHt32vw9i9X38eXqxfVPkLbQSzEq5UnY2ggcvA3PCWCl8IBo7fDRaXZib73ZcgFrjDk/V+WOhAjlLEysbhHuXZkaQlHqIUv7U+D93/X8aCQ6UJfc9zjIpgTgVPxSgtn65zf17TNz7Nca6emjsjGEw34NY+OtXh7pcP78qDt8cq6wZ2lSDxP8b5HFL5+puKV1QjOWclmw6g1NtgNoybYYDeMmrBdmz0MXdA6s4eCSNtCVSUyBcgEBaW2kxNROSTretKBzri9tN/gy0eeQBL0RJyQCArBjFcFAYBYVImRl5NqkxfY4Xba4kQEXuzoaintFreD52Pdl5C5NSJhKHuSMtAJ3ykQjkQXA50Y5KCSjip8eS/SziPHhYzB0tskwqEqa4ugKF3QBrFIdpKJzBoTX6bbBrfjk2MR2NPXSUryMf9OUsrbf8WTY2XR5Pf5aKmfubjF76N85PqJ/j67DeevcVWhcM5sdsOoMzbYDaMm2GA3jJqw3UCYhFy8f/Z+odu7apu0w+dJZyIRYUuW6wCQPMvtv2KkbazZjM/J9kW1F9fV772i5LZyJAIzJqknUYCw1RoimeSq9BjKqvbrkC2RJ/jHxbz9rbE20+Rc8CoRSRFj6aAAHK3FBSQiwUimJ/27oopPNuXtD2RGSgBBk/ftfKSDZdDi97UtDlMsde6V9Y7wlxB2/SWPNHO7y+38YM37qfL4U2DC5797Io4nGonKQAAmooJN0dLP/0AkZ1kv+Vz8MvFkxdiYVq/KHM5ZIIxh1Bob7IZRE2ywG0ZNsMFuGDVhq9llXRGg2qiQUgkhCgBy6RvS4A4OS+hMHTvHXMS4gafUNmH/gC1PRbBMa6UzmCDmYlUUCHFkdkXtkoBnx11FXCtpJlpsW2aHbDkIuXBTJTpTDUa8LQtPRZgs52pUlYkSzpl2MLkmUsi8MufbdAMttk2FCNYQATjLNQ8sAYDLayHq9XQgUj7lYmbQ5h5J5a7OzooZP86ecEK5nWntqtniglww5sMiuqj7dhHx52cy5PdoH/o8JWQ/6Ky1yZI/HzPhJISm7ifsbAjFR/qf72FfdsOoCTbYDaMm3HewE9E1IvokEX2JiL5IRB84Xb9LRJ8goq+d/l9nDDQM49xwX6caIroC4Ipz7rNE1AXwlwDeC+BfAhg65z5ERB8EsOOc+4XXPFYQuiA9c1AIPA4yVcTX9Qr+Dpl4srMOOtz+c7l20FjJfAoiA2p/rO2yScTt+DKWNrpuC0TFkQshf5/eyT37CPOuI6WBSidpaHR421aeQietmB+4XPF7nYVac3BzYQeH3AiMCr3PDr7Jlo9TbptWa32fB8LbZaRjioAJ1y6ijGs8SVfbxcGUX+MM3HknuaSfjYYoLDMTtnUVaT0nEZVxMkgtRjt2gfhN6u/qikhZyO14OuK6USvR10wbTkvHkwp58ZCBMM65A+fcZ0//ngL4MoCnAbwHwAunm72Auy8AwzDOKd+RzU5EzwD4QQCfAnDJOXdP4r4FwFO4zTCM88IDT70RUQfA7wP4WefchDYSpznnHJGnsvzd/Z4H8Pzp0qO01TCMR+CBvuxEFOPuQP9N59xHT1ffPrXn79n1h759nXMfds4955x7TmVWNAxjazyIQEe4a5MPnXM/u7H+vwI43hDodp1zP/9axwqIXLSRXbb0ZERFg4shJF4QLve0d0+8REY6m0o75w4Zc1EKqVvpTC+rBRcHCdx5J+vpqCV0uIgUu5QtN0udwmQifIv2k7/NlmeLV9Q+kXCiCUrd/q7QiG6UIsqtrZ1qoj3eL/3bvN+GMgoOAKY8mivd5eLVaqjLNDUH/J7FI+0N0uzw5+O2KHHcWmhno4BEKiAR2TfPdaRid184yCz49VwItPPOnYl8dkXfDrTDWDLi9548EWxxg7d/NuFOZN2u/qZON7qhyiu4yi/QPcjP+B8B8C8A/DURff503b8H8CEAv0NE7wfwLQD/7AGOZRjGY+K+g90596d4dWP7x17f5hiG8UZhHnSGURO2GgiDMETYOXPsp7m25arVS3wXIfLnlzxNHgunjQs6WGB+xO3rds5tn+laH7chSkq3Hff8aE60nXl9zTOIlsLBJ4s92XEH3PYcH32VLeeeS95Zchsx8yTAOVbyBjfie/On1T7LNg/kmYkMr26pnVJIZIYVvjtI93XjWhkPTDpWWwBtWV5Z3OY40Jl25n3elmIuNJJK9//6kNvoMpfvrKEdZMKU37NQnKZd6TTCJ/IHcl9v0xvyDDfrnmibxyer6J45AS092s097MtuGDXBBrth1AQb7IZRE7ZbESYgF0Rn75fNiq73SIVdsxSVW1pTvU/e5sZcLiu2AsCaz1d2mtxm9yQdxSrg+zTm3H7KPFPOnQWfVy+n3EZc7OjKnfsRt2nvnPD295xO/jBJuG32jCcQRs70ZgEP1li1PYkQjqXvANcgGjiAZA1uv3bb/Homc08W3pDf5z14KvoKu3i84rZz6AkQCi5yOz+evpktr3Y9JXGPefBJJSq9BtDPUyWrCbf5NcZz/ZzKOKrFUPdLY81vZPAs14lWB57sFBtdV4wquIcNhDEM47sDG+yGURNssBtGTbDBbhg1YbvlnwJyyYZA56tkM5dlkoUecdnjuTts8HdWZ+Up/yT8OtpcR0PS0mLJVPgnhF3hMHNLnycAF1gicBFs5HGQIdE2Wb0naOp7JKo/IfNoYG3hjeNEFiA4j4iEZ9nyqPt1fkyPU8dcOKrsCMHu5KreB0O+z76nfHFGfF0w4JlWq6Gu2TwRUmuyy8W2bOjJIBPzfogLvo1viEg5UWqFq119o+mQt81lWngtVSkweWO1U1OwkYG2qKZwrjCBzjDqjA12w6gJNtgNoyZs1WaPiNxgw5Fmqgu3gG7y4Jgq5vZTGWmjMVzzdxZV2oC9KEyhWxW3qWjX41YTccusvMWP23bak6Vq8uNkIbczS4/m0Heicsuc2/kzlbkUSEV21gQ6qGja5MkpGsKRpTHTbQmJn/ukxft24PFXmoqEELGIJPFUVkY156JJSjqpBxG/7kbG27Yo9Lcqk8Z0lwfLpCOdsKMjBI9pzPsyy/V9bolqLpnISNv0BGMtTvg2pScDbafg91WGtfgKfucb3VAWFZwzpxrDqDU22A2jJthgN4yasP1AmI2qmi2PZbGsuC3nAm4kDhqehAURt2yangCDUMyrt4TtecNpa6gvAiBCYZflcoIcQHWRzzHPwRNEROtvqH26wpZeti7zYx7p4JmgFEEtpU7/EHS4sRxmfJ9qqRMdSOt0IK458QSFLEVl11nFvyHtQNvjRcWTeeaeiqZlKLNg8MQOV5c6KGQinudSaDV9jzRzU5wmbnDRoalKCwMTIUxcyvk1h6W2x3NRFXjZ1FrMbMLn0Vspb9xirb/PwcY3u6hyOOmo8e3tDMOoBTbYDaMm2GA3jJpgg90wasJ2BToiF25mp0l0dtNuxrObUpeLGOOpdlaQvjkr6EotM5G3JRPOFm2P50dWcLkqB++rZN/j1DEUAouoCLOIPQ4aHa4a0ZBHVWQdXTI4nvN+Wfjuo2xeX0QejbWQ2XFcRApjHhhTJDfVPlksHGROeB/48p3GohpQDn2NTXFLmtw/CcOhvs+DlDvNjNZcq7rc0Qrdesb7ZdUVTk6Z7ttGi+8zroQS6DxZgCZclESoRbyWqExUdflx3URXp0miM9F0lucoKhPoDKPW2GA3jJpgg90wasJ2bfaIXNA9e7+kOvcA1pfFCm7Co+mp/BqA25l5qrNiZGtuV1LCbTuX6eO2e9x2SxNu4w5PtFNN0Oa2p/AvwWCkbS7pTnJZBEhMhEMQACwCbtAma0/yB+EQIxuTNj02+5pf0yLgWsdS+4HgSpM7mBw4brO3h7pv+31+oOFKOw6tljwgpSUymSxSrbMMBjxTxijkGkN4Rz/vpci6iw7fplfofWZj/vC2I97X60IrFU1h5+cL/SzEItnJWD7Kpb4BrY3DLLIVyqo0m90w6owNdsOoCTbYDaMmbD3hZGMjOeTakxev0eXtiVbcHnS7OqhifpMHSOx3XlHbHM243XhFzOseBNrOb1eyGgpPnHESegJh2mIyOBIVVGSZFkClpljhGbY8wDfVPiNZkaSh7dcr4poqcc0nHvs7E69/GnJb1IXaFg1ifh+rVIgMgSd7hRAi+qVOpDiuLog1t9hSBx77O+b974RfA4Xaz2E5laIIv69d6IQX0y63rdOQ29/rQNvjQcz3CZdaM8knMvsG128GO7r9bnQ2fz8pRyhcbja7YdQZG+yGURNssBtGTbjvYCeiBhH9BRF9gYi+SES/eLr+WSL6FBG9SES/TeTJ5GAYxrnhvgIdERGAtnNuRkQxgD8F8AEAPwfgo865jxDRrwL4gnPuV17rWAEFrhGciSFr7KhtUtxmy+Fl/j5az7SqVC658BSWnmocolJIkYrjrHXgwjNv4ss3XhYZaaO22qdRiHLFDa7IBZlH1Av5NV4U2UxLiHStAI5FP+2SFoSWkahsknOxLWpoR5xZyK+pn/EMOGNfeqG+qMgjyu1kc+1UE495X8YL3ZZxKYJjEp4lx6m8OkAqHGDKHi+7nUw9ZZL3+D7r2/yandOZexdCrG2mvK9XHvFTfg+bc33P2o5f46zB+3tRCAEYAFpnDknVqIDLHzIQxt3lngQbn/7nALwDwO+drn8BwHvvdyzDMB4fD2SzE1FIRJ8HcAjgEwC+DmDk3LcTnl8HoONV7+77PBF9hog+A89UiWEY2+GBBrtzrnTOvQ3AVQBvB/D9D3oC59yHnXPPOeeeg6dAgmEY28Hj7fDqOOdGRPRJAD8MYEBE0enX/SpUyIqG4BBsZCdtxbfVNgPhK7IQVVgW0E41DeVgou2/FfFkFbGojOpzQxiK5gUxtz2bsW7LqMntss6UnydLefZZAIjX/LiHwqkjfIuOhBnc4EbhaKU1h4siN8JQpJHIA605pDm3Vxfc5AU1tf0aXeS29bz3FrYcTLTNXoiUI+tcB8JE4M5RLuXLgfQAAhCI5A+0OuTLsRBiAAxvvcyWZRbhoKETa1wRz8+BaH5/rSu0zmI+3AaRvmfTJb9pudCoem3tlTWdb4yR8tV/PT+IGn+BiAanfzcBvBPAlwF8EsBPnW72PgB/cL9jGYbx+HiQL/sVAC8QUYi7L4ffcc59nIi+BOAjRPSfAHwOwK+/ge00DOMRue9gd879FYAf9Kx/CXftd8MwngDMg84wasJ3JNA9MhQgSM+Ei/laRvgAi5wLEI2Qb9PxRF21miLTZ6TfYfvHXEw7LrloFHlKEZcdfu5cZCGNPefBlHfpjIQTh0e4ISGcJT0uymRf4QISAGR73CEjyLWzzqoQ5c2P9iIAABNkSURBVKMj0ZaFJ1WQqJOVzrjjimvpMk2ux6MDg10u/DXbP6T2qe78PbbcC/5at0XWappwoazpREQhgJffyu9ZteCCqDvUonAqbklvxc9TrvR9PpDa2j/kCm/2VY9j15jvdCPWAp3cK4x5Xy7m2imIORe9hpOcfdkNoybYYDeMmmCD3TBqwnZt9gBAemaHpfvaWQEn3ObKAm7PNma6yVNRsaOEtmuOOtwob4qgisCTQWYeSTuYe06Qx6mjJUoaZyEPXCg8dtpa+Nk0RRxD6Hklt49FP+xoB5/1U6Lc8jdECeorHkecMb9m1+J9+XKmxY3O+hm2PBnyaw5ynvEVAPZEGuG3VB6nmsWX2PK4x497PdIlm9MT3ncyaW2/0I5EmXhcpiKoJYq0k5b0h+l9mvfbsK2z21wUN3K08Dg17fJneTrkTk5Nz7NQ0VllnMppTeUe9mU3jJpgg90waoINdsOoCVu12auSMJ+czSF3Jtq+WLX5/LcTgQAjTyKHaJcb3IUnc8DOnM+RnywmahsJjXjGU7cvqsqk2k6OjkQ21ojbboV3HpS/c5dzEcHiZJ1a4E5XVFP1JEKIS36NufBH2DnQ0T+LlB/njqjIiobeZ/Z1HqByucOrq2aL62qfvyMO+7b4jtrm4oBvdP0qnyP/84FOXpGNROXdSPg93NF6TiASQvQybugfe4KkwgG/z6F4nijQwUsnIgNt3tSaSXfI2xeIZyMZ6PYvRxvPv9P/fnYswzBqgQ12w6gJNtgNoybYYDeMmrBVgY4ARBt56GbQolJfOPqPIR0atCPF1RUXnr5Z6Ky1J04E0Ah/hp2ZztrpWlx0mR5xQc5XShkR3ycV4s6OJ/Zk3ObX3ImuseX1WHv8BFPulFLu6gCPcigy3rS5Q8wJ9AVci/m6RsYFr2Dh+T5kXIS8M/wKW76obzP6ARftLoa6ZNc/uMq32fsxfp+/+ox2dvnm14RA9WdcrB3MtSi8HvHjHlX8mqPLWqELb/H7fFRxZ7BwV4tvV0WQ1LKr238okvp0eKIdhHPdls6GE9bM41B2D/uyG0ZNsMFuGDXBBrth1ITtBsIkJXB5w1FCxz4Awv5ulNyuCTzpqE8C7qgShsdqm/Qi3295yI32E897b0A8KUMJYXB7ElEEObcRXcj3OYF25tlP+LmPVt/ixxzogIlqwssXD4b6Vo5E1AQJH6B2S7f/lVwEcPS5wR2NtCNLGfIDhyV3kFlXWqh4WWRafTbV9utn+yKJxC6/h5OL2kFpPeF9lYgAqJ1E3+dbxK+p1eXHWN/S7XfVm9lyCP7MBSc6i/D1p7ld72J93FQ4G0kLfLjWSUr222f978tH8u02vfo/GYbx3YQNdsOoCTbYDaMmbHeePQOSjalT53nVjGOZ1JH/e+KxWRpLvk9S6jlO1+HWzzLiE5rtQgSfABgJeSDp8G2ymba/+1eEjX5DJHvwBFUsJ7xtPeyz5SLT51kIY26l/BEALLlN657mQUTBSGsbfRGsMZ6KtqR6nvrSlPf3nUhUHl3pi77e4cbpn0EHL7XHXAtY3uAX/Q3pxABgcZ1X/lk5rm0c5qLEDYDI8cns+YT7XFRNbQhXC54ENG3wtu77rvk210OCfbUJEuEAkl8WCV5mOvhqszARvUY5RfuyG0ZNsMFuGDXBBrth1AQb7IZRE8i9RgWJ15uIYtcLzhxVAugAjxOZiGbM30fNgS7/C+HosfaUda7iK3yFzLhSaeEpFOV/W8JPItVaIZYitiTJuOAycx5HiowLjIuYX0+VayUnjLm4Vsb6Pg7E8nSfd275snaQiUW56Fh4PkU7+jyTCXcWSQPRt7kWTMM2F+RazpP15yoPaCouiHLSfd0W6ZQyE0lydnRCHIxE86oLvOeiTIufwVheE99m4Qn+aYruLj2aqrxpgXgs41jeVWCan93XqroB59YeGdi+7IZRG2ywG0ZNsMFuGDVhqzZ7QuQ2q2KMutqnJyNhyIjF0OPon4l31l5fB/BPhImVr3nG1j5EtlYA0xY3wOOC25VrT+VXWdi1dNweb3scQWbiIi8Iu38p7FAAWFzgy5UuQAKEYnnNHU6o69lJBCe5Hj9IVGnNpC00hvEJdwTxfVGI+AVEbZ2UpGoJpyBxWynSyTdcyR2fiowbz61YawML4VuUhFwrCAod1LK6KB4oUZA4eUW3bSASXAwTrROV2TP83A0eFBWt9HitNm5RVlSoKmc2u2HUGRvshlETHniwE1FIRJ8joo+fLj9LRJ8ioheJ6LeJyDMRZRjGeeGBbXYi+jkAzwHoOed+goh+B8BHnXMfIaJfBfAF59yv3OcYLgjO3i+dyzr4YXaH20JRye2coq/tp6gUtv9MT2A2RMxPAW57rqDnghUtbqTveqqjzIfcxi0Svk0r0wE3qza376o575cS+h7tiSQYYeua2uZwIefRuS7RUUY9MOvz9r4p4/1/PdDv9N6ciwqzpriepdZmeqIayrivnwUcc9u/2eIBKmtP/18SmsNa6CHTXNvJ2YB/83oZP24ZaX+EaMz7biWerzT2XI8Itko8Q2/U4SubTVF5d67bUizOgntm1RFKlz+8zU5EVwH8OIBfO10mAO8A8Hunm7wA4L0PcizDMB4PD/oz/pcA/DzOsuTsARg55+69Nq8DeNq3IxE9T0SfIaLPPFJLDcN4JO472InoJwAcOuf+8mFO4Jz7sHPuOefccw+zv2EYrw8PkrziRwD8JBG9G0ADQA/ALwMYEFF0+nW/CuDGG9dMwzAele/IqYaIfhTAvz0V6H4XwO9vCHR/5Zz7n6+5fxi5YCOjKZULtU2w5gJEKTKYpJd15RZZMSVeNtU2+VPCgeQmLyt82RM8M21wD55UlDweT7VYEoQi00jKPUGe8jhoCB0KQZufZ7nW55Gv6b2VFugAXiVmKkTJDrRY1d/j4trLJe+XC76KNjk/bhXwC1oLByAAgLz1gb5nrYj31WLInYKaPY8ONeHPcykrAfW0s0smPK4aJH7wXtFOWnnOtxGVodGY633G66tsmTq6lHXzWARF4RJbjj3OX5tXNKsqlO71d6r5BQA/R0Qv4q4N/+uPcCzDMN5gvqMcdM65Pwbwx6d/vwTg7a9/kwzDeCMwDzrDqAlbzS4boEQDZ7bzaq2dOkLhi1CuuM2Y5zrhRX/NHSfGMgEGADRFQESbH2fa1TbjXFTQjHOhJ+xwGwwA4iNuh6UXeBePb+rzRJe4bZqJ6qs7lbbzw5Dbnnmqq6COZf82uD077nB7EACqNbfzW1Pe3luhdj6KBnybxkgEo9zW9msK3pdhx5PJYcyP27zCryc/0JpDs8k1k5XMsBtpjerZlAe+fGPN9Z3uRJvA2Yy3X/hFYeipUHxJ9O1tz6c23OWaVFBwh6VcJxpG3jwbNNXy1Z3D7MtuGDXBBrth1AQb7IZRE7acvCJ0FzcqsRxUOvtDJGw3mXwgKnTl0TeJzA0HnvnXaMITTpYht5+Wnnn2sCMmiGOerTD25H4ICm4HByJZwirX9ndDbDOVsSYeO+2ub9MZqW8jYTbK6fqG59ZnQjOpluIg5En4uc87gkSFG7fWCTO7TZ6sQlaYBYC1aF98gd/72VBrPp2A9+/M8WfsQs7n6gHg5IKo1CKTUu7rb2Ia8H5ZHfFnhfb0HHpnxrdZlFp/2uPyAW7e5jdtb6ADkY5GZ9dUVSdwjxIIYxjGk48NdsOoCTbYDaMm2GA3jJqwVYEuCGMXtc4UiB2ZyhTAkeNCWoe440TlqfNcRVxgSVZaxAi6XKgZaW1E0xQOMDvcYaE10g4yzvFtYpFNttfSDiY3b/J70O/xzLcnGS87fPfAXEnrJjqoaCHLW8948E8EfdxcCE/thItgnZV22jgQ3wxq82vs625CccTFtgV0Bh/0uWpXTbnnypsSreq9HAsB0QlVcuFRAmVSGXGLkkpnnWnEvB+mc349TYgAHACZ0CnjiadjOrwvl2vR356gqM34rOWqQmnZZQ2j3thgN4yaYIPdMGrCVm12otQFwVmqujdDO5i82OLRJw1RDrPV0Lbd8Uq8syJd6TIUFWN3RNzFItJ2/kI4ZIjCJ4ihA0kK4dyShcIALHX7E2EkthvC8WOl7fET0ZjAUzVUFp9ZisQT7ad0HFR0k+80FrZ0JJw+AODKgvf/ichWkYe6/aWs3AKPmSmSV6DB79GFQDtlDSf8moKL/Ea7Q+2UVYigon7F7eSlp/LuvnRYEoEwsxkPyLkLv2fJRf0sFIf8Glcis/AleWIAC5w9L9PhbRR5Zja7YdQZG+yGURNssBtGTbDBbhg1YasCXZiQa1w+e7+sj3Q0lFvzaKjwChckGgc66moOns3Dl36nlXDBZLLDnSv2b+t+OGrzc1+Zc+HmwHcikWqnGwjni1TvFAjhJhXOOtdS7Qjy1ZwLOXGoxapOKjLrzPi7verpa56lfF0snI/yUms/icjyk625IJd6kuNmwpOlRZ4MK8LnRH6Zpp5Mt12xUdXkK+Yr7rAEAP1IREAuudqWpdpBJuT+SWje5o0tpbgIYFnJe+/pmII7MTWItyWVKjGAaGPdyTxDXlYm0BlGnbHBbhg1wQa7YdSErdrsMZEbbJRs1rlBgWZXZGDJuJPKcK0zjUQRt/cKny29wx0YusL0WR5pp5qmyKRDIjFKUmr7Lw95xY645Hb/CNrZohjwnmgvuOPHvKVt9rjNvVuqIx3ZM1jzcx1f5dpGj8sjAIDVituISU9kh5l40vO0eT91hC0deKqwTNb8mrqFJyikwdtPc97giU+diYS3VCi+Z2uP95Ho357wAZo8rU3gwQlv72SH71Td0OeJZYlsTxUc9EVQl8icnOmuRL48ExCq1QiutEw1hlFrbLAbRk2wwW4YNWGrFWEKkKiUoU2LNYlgAWGupp4kByQSQuwkOtnAHTEpLiuSzKEDJKbXuB2cvsJt9LynJ3qXchqUeHubgdZIREJUzFMx57zQOkUiqq40L+rjjofcRsd13gfLa/q47Vd4QpGRqPzaS7W2kS25zb7bkna+nkOPByLhRaHbMp1x+9UNhM+F089CuhKBPF0xIX5VCxXJEQ+cmos58ui2fp5GDX6NF27wfe5gT+2Th8dsuempYrw84Xa91InKpp5nT1dnz+mq0slR7mFfdsOoCTbYDaMm2GA3jJpgg90wasJ2M9WEgQvaGwJPpgWWp3IuhoxFpo75ri75E2Vc6CjmWlBpx8KpJuNi1S1P+afvFf4vQ6HHLT3yZjPm9aLHKy5e9bo6QCKbcIGoEM4XeUNn4Y1XIvACWiyMWjxTb5Yc8A2c9tBIxC3ZWXKnjqHM1gqgSdwRina4SLYaesonhXybuNQi3kSUsg5u8xuSkj7urMWdsKpK3MSOJ7usEOjgRNlkvKR2qaT+Jm7RoNJtG4nS0GF/rLa5OuXnfqXgz3bPo7+F5dkzdlIVyJ1llzWMWmOD3TBqgg12w6gJW84uS3cAfAvAPgBPGMa55ElqK/BktfdJaivwZLT3e5xzF3z/sNXB/u2TEn3GOffc1k/8EDxJbQWerPY+SW0Fnrz2SuxnvGHUBBvshlETHtdg//BjOu/D8CS1FXiy2vsktRV48trLeCw2u2EY28d+xhtGTdjqYCeidxHRV4joRSL64DbP/SAQ0W8Q0SER/c3Gul0i+gQRfe30/57ShtuHiK4R0SeJ6EtE9EUi+sDp+vPa3gYR/QURfeG0vb94uv5ZIvrU6TPx20SkA+YfE0QUEtHniOjjp8vntq0PwtYGOxGFAP4HgH8K4K0AfoaI3rqt8z8g/wvAu8S6DwL4I+fcmwH80enyeaAA8G+cc28F8EMA/tVpf57X9q4BvMM59wMA3gbgXUT0QwD+M4D/7pz7Ptz1MH//Y2yj5AMAvryxfJ7bel+2+WV/O4AXnXMvOecyAB8B8J4tnv++OOf+BIBM0/oeAC+c/v0CgPdutVGvgnPuwDn32dO/p7j7UD6N89te55y7V1olPv3PAXgHgN87XX9u2ktEVwH8OIBfO10mnNO2PijbHOxPA3hlY/n66brzziXn3L1wsVuApyj7Y4aIngHwgwA+hXPc3tOfxZ8HcAjgEwC+DmDknLsXWneenolfAvDzAO7Fme3h/Lb1gTCB7jvA3Z26OFfTF0TUAfD7AH7WOcfiO89be51zpXPubQCu4u4vve9/zE3yQkQ/AeDQOfeXj7stryfbTDh5A8C1jeWrp+vOO7eJ6Ipz7oCIruDuV+lcQEQx7g7033TOffR09blt7z2ccyMi+iSAHwYwIKLo9It5Xp6JHwHwk0T0bgANAD0Av4zz2dYHZptf9k8DePOpopkA+GkAH9vi+R+WjwF43+nf7wPwB4+xLd/m1Ib8dQBfds79t41/Oq/tvUBEg9O/mwDeibs6wycB/NTpZueivc65f+ecu+qcewZ3n9P/55z75ziHbf2OcM5t7T8A7wbwVdy11f7DNs/9gO37LQAHAHLctcnej7u22h8B+BqA/wtg93G387St/wh3f6L/FYDPn/737nPc3r8P4HOn7f0bAP/xdP33AvgLAC8C+F0A6eNuq2j3jwL4+JPQ1vv9Zx50hlETTKAzjJpgg90waoINdsOoCTbYDaMm2GA3jJpgg90waoINdsOoCTbYDaMm/H+zPmRJRHNnkgAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Create synthetic data\n",
+ "img = np.zeros((3, 2, 1, 50, 50), dtype=np.float32)\n",
+ "\n",
+ "# code 1\n",
+ "# round 1\n",
+ "img[0, 0, 0, 35, 32] = 1\n",
+ "# round 2\n",
+ "img[1, 1, 0, 36, 34] = 1\n",
+ "img[1, 0, 0, 32, 28] = 0.5 # Noise\n",
+ "# round 3\n",
+ "img[2, 0, 0, 33, 30] = 1\n",
+ "\n",
+ "# blur points\n",
+ "gaussian_filter(img, (0, 0, 0, 1.5, 1.5), output=img)\n",
+ "\n",
+ "# add camera noise\n",
+ "np.random.seed(6)\n",
+ "camera_noise = np.random.normal(scale=0.005, size=img.shape).astype(np.float32)\n",
+ "img = img + np.clip(camera_noise,0.001,None)\n",
+ "\n",
+ "stack = ImageStack.from_numpy(img)\n",
+ "\n",
+ "plt.imshow(np.moveaxis(np.amax(np.squeeze(img*10),axis=1),0,-1))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 6/6 [00:00<00:00, 383.08it/s]\n",
+ "100%|██████████| 3/3 [00:00<00:00, 265.38it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 529.45it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 28.86it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 238.64it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n",
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[0.077548, 0.001 , 0.073696],\n",
+ " [0.001542, 0.071737, 0.003175]]])\n",
+ "Coordinates:\n",
+ " radius (features) int64 0\n",
+ " z (features) int64 0\n",
+ " y (features) int64 35\n",
+ " x (features) int64 32\n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 0.0006531\n",
+ " yc (features) float64 0.0007143\n",
+ " zc (features) float64 0.0\n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# LocalGraphBlobDetector\n",
+ "lgbd = LocalGraphBlobDetector(\n",
+ " search_radius=5,\n",
+ " search_radius_max=5,\n",
+ " detector_method='blob_log',\n",
+ " min_sigma=(0.2, 0.5, 0.5),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.05,\n",
+ " overlap=0.5)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[ nan, 0.036368, 0.073696],\n",
+ " [ nan, nan, nan]],\n",
+ "\n",
+ " [[0.077548, nan, nan],\n",
+ " [ nan, 0.071737, nan]]])\n",
+ "Coordinates:\n",
+ " radius (features) float64 0.4 0.4\n",
+ " z (features) int64 0 0\n",
+ " y (features) int64 32 36\n",
+ " x (features) int64 28 34\n",
+ " * r (r) int64 0 1 2\n",
+ " * c (c) int64 0 1\n",
+ " xc (features) float64 0.0005714 0.0006939\n",
+ " yc (features) float64 0.0006531 0.0007347\n",
+ " zc (features) float64 0.0 0.0\n",
+ "Dimensions without coordinates: features\n",
+ "Attributes:\n",
+ " starfish: {\"log\": [{\"method\": \"LocalGraphBlobDetector\", \"arguments\": {\"i..."
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# LocalSearchBlobDetector\n",
+ "# Anchor round: 1st round\n",
+ "lgbd = LocalSearchBlobDetector(\n",
+ " search_radius=5,\n",
+ " min_sigma=(0.2, 0.5, 0.5),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.05,\n",
+ " overlap=0.5,\n",
+ " anchor_round=0)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# LocalSearchBlobDetector\n",
+ "# Anchor round: 2nd round\n",
+ "lgbd = LocalSearchBlobDetector(\n",
+ " search_radius=5,\n",
+ " min_sigma=(0.2, 0.5, 0.5),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.05,\n",
+ " overlap=0.5,\n",
+ " anchor_round=1)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# LocalSearchBlobDetector\n",
+ "# Anchor round: 3rd round\n",
+ "lgbd = LocalSearchBlobDetector(\n",
+ " search_radius=5,\n",
+ " min_sigma=(0.2, 0.5, 0.5),\n",
+ " max_sigma=(0.6, 1.7, 1.7),\n",
+ " num_sigma=3,\n",
+ " threshold=0.05,\n",
+ " overlap=0.5,\n",
+ " anchor_round=2)\n",
+ "intensity_table = lgbd.run(stack, n_processes=1)\n",
+ "intensity_table"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Reproduce In-situ Sequencing results with Starfish Graph-based Decoding\n",
+ "\n",
+ "Let's now see the `LocalGraphBlobDetector` applied to In Situ Sequencing (ISS). ISS is an image based transcriptomics technique that can spatially resolve hundreds RNA species and their expression levels in-situ. The protocol and data analysis are described in this [publication](https://www.ncbi.nlm.nih.gov/pubmed/23852452). Here we use the `LocalGraphBlobDetector` to process the raw images from an ISS experiment into a spatially resolved cell by gene expression matrix. And we verify that we can accurately reproduce the results from the authors' original [pipeline](https://cellprofiler.org/previous_examples/#sequencing-rna-molecules-in-situ-combining-cellprofiler-with-imagej-plugins)\n",
+ "\n",
+ "Please see [documentation](https://spacetx-starfish.readthedocs.io/en/stable/) for detailed descriptions of all the data structures and methods used here."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "matplotlib.rcParams[\"figure.dpi\"] = 150"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Load Data into Starfish from the Cloud\n",
+ "\n",
+ "The primary data from one field of view correspond to 16 images from 4 hybridization rounds (r) 4 color channels (c) one z plane (z). Each image is 1044 x 1390 (y, x). These data arise from human breast tissue. O(10) transcripts are barcoded for subsequent spatial resolution."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{ 'codebook': 'codebook.json',\n",
+ " 'extras': {},\n",
+ " 'images': { 'dots': 'dots.json',\n",
+ " 'nuclei': 'nuclei.json',\n",
+ " 'primary': 'primary_images.json'},\n",
+ " 'version': '5.0.0'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "use_test_data = os.getenv(\"USE_TEST_DATA\") is not None\n",
+ "\n",
+ "# An experiment contains a codebook, primary images, and auxiliary images\n",
+ "experiment = data.ISS(use_test_data=use_test_data)\n",
+ "pp = pprint.PrettyPrinter(indent=2)\n",
+ "pp.pprint(experiment._src_doc)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 1/1 [00:00<00:00, 37.32it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 32.41it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "fov = experiment.fov()\n",
+ "dots = fov.get_image(\"dots\")\n",
+ "dots_single_plane = dots.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)\n",
+ "nuclei = fov.get_image(\"nuclei\")\n",
+ "nuclei_single_plane = nuclei.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)\n",
+ "\n",
+ "# note the structure of the 5D tensor containing the raw imaging data\n",
+ "imgs = fov.get_image(FieldOfView.PRIMARY_IMAGES)\n",
+ "print(imgs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Visualize Codebook\n",
+ "\n",
+ "The ISS codebook maps each decoded barcode to a gene.This protocol asserts that genes are encoded with a length 4 quaternary barcode that can be read out from the images. Each round encodes a position in the codeword. The maximum signal in each color channel (columns in the above image) corresponds to a letter in the codeword. The channels, in order, correspond to the letters: 'T', 'G', 'C', 'A'. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\n",
+ "array([[[0, 1, 0, 0],\n",
+ " [1, 0, 0, 0],\n",
+ " [0, 0, 1, 0],\n",
+ " [0, 0, 0, 1]],\n",
+ "\n",
+ " [[0, 0, 1, 0],\n",
+ " [0, 0, 0, 1],\n",
+ " [0, 1, 0, 0],\n",
+ " [1, 0, 0, 0]],\n",
+ "\n",
+ " ...,\n",
+ "\n",
+ " [[1, 0, 0, 0],\n",
+ " [0, 1, 0, 0],\n",
+ " [0, 0, 0, 1],\n",
+ " [0, 0, 1, 0]],\n",
+ "\n",
+ " [[0, 0, 0, 1],\n",
+ " [1, 0, 0, 0],\n",
+ " [0, 1, 0, 0],\n",
+ " [0, 0, 1, 0]]], dtype=uint8)\n",
+ "Coordinates:\n",
+ " * target (target) object 'SCUBE2' 'MYBL2' 'ER' ... 'GAPDH' 'HER2' 'ACTB'\n",
+ " * c (c) int64 0 1 2 3\n",
+ " * r (r) int64 0 1 2 3"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "experiment.codebook"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Filter raw data before decoding into spatially resolved gene expression\n",
+ "\n",
+ "A White-Tophat filter can be used to enhance spots while minimizing background autoflourescence. The ```masking_radius``` parameter specifies the expected radius, in pixels, of each spot."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 16/16 [00:00<00:00, 55.28it/s]\n",
+ "16it [00:05, 6.55it/s]\n",
+ "1it [00:00, 10.96it/s]\n",
+ "1it [00:00, 9.98it/s]\n"
+ ]
+ }
+ ],
+ "source": [
+ "from starfish.image import Filter\n",
+ "\n",
+ "# filter raw data\n",
+ "masking_radius = 15\n",
+ "filt = Filter.WhiteTophat(masking_radius, is_volume=False)\n",
+ "\n",
+ "filtered_imgs = filt.run(imgs, verbose=True, in_place=False)\n",
+ "filt.run(dots, verbose=True, in_place=True)\n",
+ "filt.run(nuclei, verbose=True, in_place=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Register data\n",
+ "Images may have shifted between imaging rounds. This needs to be corrected for before decoding, since this shift in the images will corrupt the barcodes, thus hindering decoding accuracy. A simple procedure can correct for this shift. For each imaging round, the max projection across color channels should look like the dots stain. Below, we simply shift all images in each round to match the dots stain by learning the shift that maximizes the cross-correlation between the images and the dots stain. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 16/16 [00:00<00:00, 58.60it/s]\n",
+ "100%|██████████| 4/4 [00:00<00:00, 205.87it/s]\n"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "from starfish.image import ApplyTransform, LearnTransform\n",
+ "\n",
+ "learn_translation = LearnTransform.Translation(reference_stack=dots, axes=Axes.ROUND, upsampling=1000)\n",
+ "transforms_list = learn_translation.run(imgs.max_proj(Axes.CH, Axes.ZPLANE))\n",
+ "warp = ApplyTransform.Warp()\n",
+ "registered_imgs = warp.run(filtered_imgs, transforms_list=transforms_list, in_place=False, verbose=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Decode the processed data into spatially resolved gene expression profiles"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```LocalGraphBlobDetector``` instance using [Laplacian of Gaussian (LoG)](https://scikit-image.org/docs/dev/api/skimage.feature.html?highlight=blob_log#skimage.feature.blob_log) blob detection algorithm. Please refer to `scikit-image` documentation for a full parameter list."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\r",
+ " 0%| | 0/4 [00:00, ?it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 4/4 [00:01<00:00, 2.46it/s]\n",
+ "100%|██████████| 10063/10063 [00:07<00:00, 1398.80it/s]\n",
+ " 0%| | 1/4825 [00:00<11:08, 7.22it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 4825/4825 [07:52<00:00, 10.22it/s] \n",
+ "100%|██████████| 3982/3982 [00:46<00:00, 85.42it/s] \n"
+ ]
+ }
+ ],
+ "source": [
+ "from starfish.spots import DetectSpots\n",
+ "import warnings\n",
+ "\n",
+ "intensities_lgbd = []\n",
+ "import warnings\n",
+ "lgbd1 = DetectSpots.LocalGraphBlobDetector(\n",
+ " detector_method='blob_log',\n",
+ " min_sigma=(0,0.5,0.5),\n",
+ " max_sigma=(0,3,3),\n",
+ " num_sigma=10,\n",
+ " threshold=0.03,\n",
+ " search_radius=3,\n",
+ " search_radius_max=5\n",
+ ")\n",
+ "\n",
+ "intensities_lgbd.append(lgbd1.run(registered_imgs))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```LocalGraphBlobDetector``` instance using [`peak_local_max`](https://scikit-image.org/docs/dev/api/skimage.feature.html?highlight=peak_local_max#skimage.feature.peak_local_max) local maxima detection algorithm. Please refer to `scikit-image` documentation for a full parameter list."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\r",
+ " 0%| | 0/4 [00:00, ?it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 4/4 [00:01<00:00, 3.54it/s]\n",
+ "100%|██████████| 7286/7286 [00:04<00:00, 1595.02it/s]\n",
+ " 0%| | 0/3658 [00:00, ?it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 3658/3658 [05:41<00:00, 10.72it/s] \n",
+ "100%|██████████| 3024/3024 [00:17<00:00, 168.26it/s]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import warnings\n",
+ "lgbd2 = DetectSpots.LocalGraphBlobDetector(\n",
+ " detector_method='peak_local_max',\n",
+ " exclude_border=False,\n",
+ " threshold_abs=0.03,\n",
+ " search_radius=3,\n",
+ " search_radius_max=5\n",
+ ")\n",
+ "\n",
+ "intensities_lgbd.append(lgbd2.run(registered_imgs))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```LocalGraphBlobDetector``` instance using [`h_maxima`](https://scikit-image.org/docs/dev/api/skimage.morphology.html?highlight=h_maxima#skimage.morphology.h_maxima) local maxima detection algorithm. Please refer to `scikit-image` documentation for a full parameter list."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\r",
+ " 0%| | 0/4 [00:00, ?it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Generate Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 4/4 [00:00<00:00, 14.71it/s]\n",
+ "100%|██████████| 5680/5680 [00:03<00:00, 1756.42it/s]\n",
+ " 0%| | 3/2987 [00:00<01:54, 26.13it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Run Graph Model...\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 2987/2987 [01:44<00:00, 28.55it/s]\n",
+ "100%|██████████| 2775/2775 [00:08<00:00, 312.03it/s]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import warnings\n",
+ "connectivity=np.array([[[0, 0, 0],[0, 1, 0],[0, 0, 0]],[[0, 1, 0],[1, 1, 1],[0, 1, 0]],[[0, 0, 0],[0, 1, 0],[0, 0, 0]]]) #3D corss \n",
+ "lgbd3 = DetectSpots.LocalGraphBlobDetector(\n",
+ " detector_method='h_maxima',\n",
+ " h=0.015,\n",
+ " selem=connectivity,\n",
+ " search_radius=3,\n",
+ " search_radius_max=5\n",
+ ")\n",
+ "\n",
+ "intensities_lgbd.append(lgbd3.run(registered_imgs))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We now compare the results from the three decoding approaches used previously with `BlobDetector` algorithm. This spot detection finds spots, and record, for each spot, the maximum pixel intensities across rounds and channels."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 1/1 [00:00<00:00, 175.44it/s]\n"
+ ]
+ }
+ ],
+ "source": [
+ "bd = DetectSpots.BlobDetector(\n",
+ " min_sigma=0.5,\n",
+ " max_sigma=3,\n",
+ " num_sigma=10,\n",
+ " threshold=0.03,\n",
+ " measurement_type='max',\n",
+ ")\n",
+ "intensities_bd = bd.run(registered_imgs, blobs_image=dots, blobs_axes=(Axes.ROUND, Axes.ZPLANE))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To decode the resulting intensity tables, we simply match intensities to codewords in the codebook. This can be done by, for each round, selecting the color channel with the maximum intensity. This forms a potential quaternary code which serves as the key into a lookup in the codebook as to which gene this code corresponds to. Decoded genes are assigned to the target field in the decoded intensity table."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "decoded_lgbd = []\n",
+ "for i in range(3):\n",
+ " decoded_lgbd.append(experiment.codebook.decode_per_round_max(intensities_lgbd[i]))\n",
+ "\n",
+ "decoded_bd = experiment.codebook.decode_per_round_max(intensities_bd)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We now compare the results of the results from three ```LocalGraphBlobDetector``` instances with respect to `BlobDetector` results, plotting the correlation of decoded read counts. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAANQAAAEaCAYAAABpS3loAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO2deZgVxdW438PADJsoCij4CeOGMSooGVAjCkZMjEKM+ZKYKKigIiYxxiVIFBXXKCpxwQ31Y0/8uSsgGHFBRZTFiFFRQRZFEHBhx4GB8/uj6kLP9d47fYfbd5vzPs8801XV1X1ud5+uqtN1TomqYhhGZqiXawEMo5gwhTKMDGIKZRgZxBTKMDKIKZRhZBBTKMPIIPVzLUA+IiI9gL8DW4GPgQtU9bsk+3YGbgMa+L8/qepMXybA5cBpQGPgv8AAVd3gy0cB5XGH7Kmq63354cD9wDbgG+AcVf06cOyhQHfci/FOVR0bkOtL4KPAcd9Q1cG+rBdwEe7+7waMUtW7fVk58CqwOFB3H2CSqv5ZRIYAJwHB69EZOFZV30lSfp6qLhCR7sADwJeBsgOBO1R1WJLy4ar6RJLf1BL4VFV/4ctPAq4GSoBKf975gWvyY+AG3H1qAdyvqvf4sgOAe4BdgKbAlar6POmiqvYX+PM36SugvU+PBm5Lsm9z4Gugm0//ClgBNPXps4APcMokwDPAfYH6o1LIUQosAY736euAxwPlA4CXccrUwp+3Q8hjLwCO8Nt7+d9wqk+3BQbF7f9s4DcOAtrGXa+PAfHpIUB5kvN2Bc6Iy/tPbH/cy+GcFHLfF5e+Czjbbx8ArAMO9OlLgfeBej69LzATaOHTh+AUGZyCfRw41o+AjcHfGfr5yfUDnG9/wMXAy4H0scC3QEmCfXvj3pCxtHhlPNOnpwJXB8p7AeuBUp9O9dCfCiwMpPfBtZgtAw/iWYHyR4B7AulUx74kLv0EcG+SfXcH5scUJkH5n4AbAumkCpWg7qHAa4F0SoWKq1sCLAR28enBwEuB8l0ABY7x6XuAC5McqyuuRasfyJsDXJXu81NwYygR6S8ii0XkURF5SETeFZFXM3iKzlTvVnyI6xYdkGDfvXEKBIC6O7ESODxROa4VaYLr5gAgIg+IyOsiMllEjk8mh6p+jntrdhKRMqBDAjkrAumD/THfEJERItIicKx/xP2OhsCqBL8P4De4ljHZlJozgbFxedeKyGsiMlVEfpOkXqzuuLi8X4rIK/6aDBaRZMOSHsBbqrrOp+PvxTpgEzvuxQlAqYg8LyLTReR2EWkYqLtaVasCx18RqBuaghtDqeoIEWmD6/Ichuuu/D1+PxHZC3g0xaFuUdUpCfL3BD4PpFf7/61w3YIgS4E2gXOK3695oHzvwP57+f+x8nm41nCWH4u9IiJdVfVdL8eauPOt9sdvgevqrUlQFuMD4C+4btBQYLKIdIlXDBFphlPeP5KYM4ELEhWIyP64luuTQPYSYKaqPu/HJW+IyHeqOiGuruC6yEcGstcAM4A7cEo+EXetLksiV1CRl+Keh+DvasSOa12Oe2aO9ed5FrjT5y0FdheRhrpjrLwXbtyaHpnuMmXjD9eteDqiY78I3BzXtVDguAT7NsMp9G98+mxgC24gHbvpi3DjjFLcA6JARZJz/z/cQBngIeCfceWf48Zle/vjtA+UnUugixhXrwmuu3hkgrL7gT8mqdcOmJXiWl2DM8Kkup63ApMT5B8HPFFD3Z8DG4jrbuLGpAsIdMNxY6RNwFE+fa2/F5f79Faqd79/ijOc1PP3+CPgr76sO7AZmJju81NwXb4A8W/vTLES18WLsVsgvxqquhb4CXCOiEzHDXRfxr2lUdXxwO3A08Bk3FiFWHkCPsM9xInkiMmyEte12ZZAzu/J6OXYgHvbtgvmi0h/YIuq3ptEnjOA8UnKAH5L6l4AVP9NQRJ19xLVbYx7IQU5Ffewb41lqOoi4GTgRhF5A6dcn7DjWn+L68bFWAqU4YwUW4GfAV1E5E0v26Mkv0/JieItH/UfroUaVcM+e+HMv8n+TkpS7y9UH9zGjBL1Q8r2KfCjJGXHAv8NpAfGlY8BHvbbv6S6wSPeKPEu0CdQvt0ogVPyikBZKVAFdA3knQb8ix3WuQMTyPsusGeS31IBTEiQH/+brgemxuWV4gwdpXH5fwYaBtI/wRkLSuL2m5jsGgf2aYTrBu/p01OBwYHybomOHSh/CfjftJ/NXCjEzv6FUaidOHYrXAsQM7+OJGA2x/W7fx94MJ5mh2m2D/B8YN/Tgb6BfScDpwfKvwRa+e19ca1uN58uw70hY+lr+b7Z/CWcZXEPf6yOvuwcr2AxZbkMN/5r4NPHAa/4ek393+i469Ax+FsSXKd/AL9NkD8POMhv74Hr8p4dt8+pxJnAff4ovOUS1w17GhgZt08LYG6CuvtS/ZPE1XHp0/GfMHx6NPBIoPxpoJHf7oZ7mYR6iVaTI9fKUYsH/gzcR8cvgTERnaMHMAt4C9dqBN+aE4BL/XZ94AV/8d/0yrdrYN9uwHvAG7jBdv+481wOTAemAbMJtDi+/Ahf7w1/3j0CZYL7oDwLZ+INtlZtgf/z9aYDU6g+3voCNwYL/r0ad+6hxH0zCpTFxhwNE5SdDbyG6wXM8b8xfgz0GPDjBHWPAZ7HKfssYATQLG6fP+A+usbXbQW87q/jDJzCx7eAf/P3Y7q/PrsEykbjPrxPB54E9q7NsxN7gxmGkQEK2ShhGHmHKZRhZBBTKMPIIKZQhpFBTKEMI4MU3Fy+GC1atNDy8vJci2EUKXPmzPlKVeNnaNRIwSpUeXk5s2fPzrUYRpEiIulPO8K6fIaRUUyhDCODmEIZRgYxhTKMDGIKZRgZxBTKMDKIKZRRJ6msrOSTTz6pecc0MYUy6iSDBw/m8MMP5/PPP6955zQoOIUSkV4iMmLNmqhCShjFzquvvsodd9zBWWedxT777JPRYxesg2FFRYXaTAkjXVavXk2HDh1o2LAh//nPf2jSpEnC/URkjqpWJCxMQcFOPTKM2vCnP/2JZcuW8eabbyZVpp2h4Lp8hlFbHnvsMcaPH8/VV19Nly5dIjmHKZRRJ1i6dCkDBgzgyCOP5KqrrorsPKZQRtGzbds2+vbtS2VlJWPHjqV+/ehGOjaGMoqeu+++m6lTp/Lggw9y4IEH1lxhJ7AWyihqPvjgAwYNGkTPnj05//zzIz+fKZRRtFRWVnLmmWfSrFkzHn74YdyCH9FiXT6jaLnmmmuYO3cuzz33HHvuuWdWzmktlFGUvPbaa9x2222cf/759OrVK2vnNYUyio41a9Zw1llnsf/++zNs2LCsntu6fEbRcdFFF7F06VLeeOMNmjZtmtVzWwtlFBWPP/44Y8eO5aqrruKoo47K+vnzooUSkY64dV4b41aUuybHIhkFyBdffMGAAQPo3LkzgwcPzokMkSmUXzT6RtwiYJ0D+T1wixWvxC2cfp2qzhWRdbi1hJ6OSiajeInNhti0aRPjxo2jQYMGOZEjyi5fV9xK29uN/yLSGHgAuERVhwAdROQEAFVdCAzErcxnGGkxfPhwXnzxRYYNG0b79u1zJkdkCqWqTwDr4rKPBpaoaqVPTwdOEZGf+TrrgV2ikskoTj788EOuuOIKTj75ZC644IKcypLtMVQrqivZWp/XUkSuxK1sPipZZb9qeX+Atm3bRielUTB8s24jvx44jObd+/KLS/7Ahs1baVqWO9NAts+8kuotUDNgpaqOC1NZVUfg1l2loqKiMF2NjYwxa/E3/P6B19nc/iRKSxtx12tLufv1pYzq24XO5bvnRKZsm81nAO1EpMynjwEmpXMAiylhAKyvrKLPQzOooj71ShsBsHHzVjZUbuWckTPZUFmVE7kiUygR6Qb0AVqLyGARaaSqG4ELgbtF5EbgPVV9KZ3jquoEVe2/6667RiC1USg8/vZCvvvuu4RlqjDxvWVZlsgRWZdPVacB0xLkvwi8GNV5jbrB/z02AZr+IGHZxs1bWfzVxixL5Ci4mRLW5TOefPJJ3n3939Rna8LyxqUllLdonGWpHAWnUNblq9ssW7aM/v37c2DDdZSVlibcRwR6dmiTZckcBadQRt1FVenXrx+bNm3iX2NGMqpfF5qUldC4tARwLVOTshJG9e1CkxyZzvNiLp9hhOHee+/lhRde4N577+Wggw4CYOaVPZj43jIWf7WR8haN6dmhTc6UCQowcqyI9AJ6HXDAAefPnz8/1+IYWWLevHl06tSJ448/nkmTJkXuzl7byLEF1+WzMVTdY/PmzfTu3ZsmTZrwyCOPZCU2RG2xLp+R91x33XW88847PPXUU7Ru3TrX4qSk4Fooo24xffp0brnlFvr27ctpp52Wa3FqxMZQRt6ybt06OnbsCMDcuXPZZZfsOSLYGMooOi6++GKWLFnC2LFjs6pMO0PBKZRRN3jqqacYOXIkgwYN4phjjsm1OKExhTLyjuXLl9O/f386derEtddem2tx0sIUysgrVJVzzz2XDRs2MG7cOEqTTC/KV1KazUWkHOch2xb4DHhIVRdFL1ZKmWJGiVyKYWSA9ZVVTJy7jMVfb6B8jyb07NiGMY+MYPLkydxzzz0cfPDBuRYxbZJa+UTkQGAy8DiwBGgH/Bo4RVUzvx59mtgau4XNrMXfcM7Imag6d4vGpSWobmPZPwdz9IGtmDx5ck4/4Eaxxu5lQDdV/SJwknuAa7DIRMZOsL6yynvV7nC/2LjZbe926pUM//OReT0bIhWpxlArgsoEoKrLgNy4QhpFw8S5y0j2+bOsYUPmrCqsb6NBUilUYu8tyI2zvlE0LP56w/YWKZ7N2yRn3raZIFWX7wIR6RmXJ8BewM3RiZQaM0oUPuV7NKFxaUlCpWrUoF7OvG0zQSqF+jffj5EnQO/IpAmBqk4AJlRUVES/vqMRCT07tuH6iR8kLNu0ZRutd22UZYkyRyqFGqiqq+IzReT9COUx6gDzlq9lmwIogUjd27lw/BxmXtkjp46CtSXpGEpVV4nIoSKyN4CIXCwitwIlWZPOKDpiFr7vtmwjkTJBbsOA7SxJXwEiMhz4OVAmIuOBXYHlwF3A77IjnlFspLLwxchlGLCdJVWb2kxV9xeRRsATqnoKgIhcnx3RjGIklYUvRi7DgO0sqczmnwKo6ibg9UD+pkglMoqaRlXr2bY5ccTXGLkMA7azpGqhOovIH/z2kYHt7K+zaBQFW7ZsYezNlyBH/yXpPo1L6+U0DNjOkqqF2hu3TGdnYHVge+8syJUUixxbuNx4443MeWs6fzxMqsXTKy0RGpQIA7rtx6yrTszZyhmZINXk2BN9HPL4/J+o6suRS1YDNjm2sHjrrbfo2rUrZ5xxBmPGjGFDZVVexdOLp7aTY0PFlBCRUnz30K+gkXNMoQqH9evXc8QRR7Blyxbmzp1LIYQvyHhMCf/daZRPTgLWA+tE5LLaiWjUVS699FI+/fRTxowZUxDKtDOkGkN1BS7y21NVtR5QBhwZuVRG0fDcc8/x0EMPMXDgQI477rhcixM5qRTqQ1WNrYf7PICqVgEfRS6VURSsWLGC8847j8MPP5zrr68bny9TjQI3xzZU9b+J8g0jGarKeeedx9q1a3nllVcKLjZEbUmlUC1EpKmqro9liEgz3KrthpGSESNGMHHiRO68804OOeSQXIuTNVIp1H3ANBGZCnwJtAFOAH6bDcGMwmX+/Plceuml9OjRg4suuqjmCkVEqtnm84GfAiuA/XGu7yeq6oIsyWYUIFVVVfTp04eysjJGjRpFvXp1K1Jdyi9pqvo1MCyW9qb0jqraL3LJkmAeu/nNTTfdxNtvv82jjz7K3nvndFJNTkjr9aGqd+EnzeYKi22ev7z99tvccMMNnHnmmZx++um5Ficn1KY9LtyQNEZkbNiwgT59+tCmTRuGDx+ea3FyRqqZEmZ8MEJz2WWXsWDBAsaMGcNuu+2Wa3FyRqox1D9E5PK4vJxHPTJyS6LwydOmvsCDDz7I5ZdfTvfu3XMtYk5JN+oRQJ9oRDHynfjwyY0a1OOaZ99n48cz+MHJ/Rh09ZBci5hzUrlvtEwS9aiFqn4VuWQ1YLPNs8v6yiqOvHlqtfDJQcpKhPr1nXNgIfszxcj4bPNEyuTzc65MRvapKbhK5VZlQ+VWH7O87gYXrltf3Yxa88mKdTUGV4HCDgGWCWpUKBFpJiIWi68OM2vxN4x7e0mofQs5BFgmCNNCfQIU3spXRkaIBabcXBXu82MhhwDLBGEU6klV3R5+WUQ6RSiPkWeECUwZpJBDgGWCMFExykTkFmAebpZEL+A3kUpl5A01BaasX0+o2qY0Li1BhIIOAZYJwvzyHwHPAOU+Xfg2USM05Xs0oVGDemzasu17ZY0a1OPkw1rTapeGeRm5KBeE+fUXqupbsYRfe9eoI7TZrVFCZQKoV0+4/tRD67wSBQlzJd4RkYuABsDbwPxMCyEivwB+4M/xiao+nulzGOmzvrKKC8fPSVp+f+8fmTLFEcYoMQzXzWuLW33j2jAHFpG9RORhEZkVl99DRO4TkSEiEjvWHFUdCgwH6ua8/zwklUGiUYMSlq+2MPfxhFGoJap6HbBcVRcCn4U8dlfgWQKLAIlIY+AB4BJVHQJ0EJETAotjnwbcHlZ4I1pSGSQ2banb35uSEUah9hORMkBFpB6wT5gDq+oTwLq47KNxClrp09OB2DI5pwALgS9Igoj0F5HZIjJ71aqEM6OMDNJEN6JJVsqo69+bkhFGoV4AFgEX4z7yvrAT52tFdSVbC7QSkV8Cg4EzgFuSVVbVEapaoaoVLVu23AkxjJqoqqrin7dcTjJ/0rr+vSkZNY4oVfUZEXkVOABYoKqrd+J8K4FdAulmwEpVfQZnmjfyhFtvvZW3Xn+Vm/oMYPzSku0uG/a9KTU1XhER2Q34G3AI8KGI3KKq39TyfDOAdiJS5rt9x+DClYXGgrREz+zZsxkyZAi/+93vuPL807k4z1fKyCdqXH1DRJ7EmcsXAO2BI1X1tBoPLNINOAs4CbgfuENVN4nIicCvgVXAFm/wSBvzh4qGjRs30qlTJzZs2MB7771H8+bNcy1STqitP1SY18w8b9KOnWhoqp1jqOo0YFqC/BeB7607ZeQHAwcO5OOPP2bq1Kl1Vpl2hjBGiRV+4eqY2TunSwfaCobRMWXKFO69914uueQSTjjhhFyLU5CkcoFfhDPxlALNcV20VsAaVW2dNQmTYF2+zPLVV19x2GGH0aJFC2bNmkXDhg1zLVJOiaLLN1RV709wogvTPYmR36gqF1xwAd988w1Tpkyp88q0MyRVqETK5PkkIlmMHDF69Gieeuophg4dSseOHXMtTkETxsr3c+BCoCluGlFbVd0/C7IlkydmNj9//vyMz9OtcyxatIiOHTvSqVMnXnrpJUpKLNoBRGvl+xvwZ+BbnEKdne5JMomqTgAmVFRUnJ9LOQqNRAEqG9UX+vTpg4gwevRoU6YMEEahZqvqu7GEiDwboTxGBMQHqGxcWsINkz7khPofM336dMaMGUO7du1yLWZREEahZojINNyqGwIcBqTdFBrRkaj1aepnMsSCrAQDVMZmkD+ztg2/+u3v6d27d07kLkbCKNSluAmrsTl8OQ3FbFOPqpOs9YlFcE3l0yT16nHKhVcjIol3MNImzIfdmar6rKpO87Mfks4Gzwa2PtQOgq1PrNXZuHlrtQiuqXyapEFDVm0yZcokYVqo5iIymh0LrR0H9IhOJCMsqVqfWATX8j2a0Li0JKFSmU9T5gnTQu0LvAws8X87475hZJBUrU8sgmvPjm0wn6bsEaaF6htcqFpEJkcoT43YGGoHYVqfecvXsi2BPjVsUM98miIgTAu1WUTaxv6Av0QtVCpsDLWDnh3bkMyeIALHH9SKc0bO5LsEYcBKRPhh62YRS1j3CKNQ03ALr43Gdf1OilIgIzxNy+r7VqaExqXuo2zj0hKalJUwqm8XXv5oZfIxFnV7lYyoCNPe9/c+TACIyAURymOkSefy3Zl5ZY+EHrUvzVtR4xjLyCxhYkrEOwP+MCJZjFrSpKw+p3du+718s/BlnzDrQy0SkYWx/5iVr2CoaYxlFr7ME2YMdYuq7qeq+/r/oSLHRoV57IanpjGWWfgyT43uG9+rIHK8qr4SkTyhMY/d6qSaz7fBohalTW3dNwrOHyqGKdQOEs3ni8XOK4YV2XNBxleBDzAYuB7o6//GpHsSIzrCzOczskcYhXpHVWer6hJVXQyMjVgmIw3CzOczskeYjvReIjKeHbEkjsUmx0ZGqrFQon3mLV9r35ryiFAKBTwcSB8WkSx1npp8mxLtU1qS3P3CvjVln4KbHFuspPKsPWfkTGZe2QP128F9Nm9NblSyb03ZJ8xMiQVx6ZXRiVMzxTrbPMxYSJWk+wCUlgibt9qK7Lmk4K52sUY9CuPbVFm1Nek+AD/evwUHt25m35pySJjlbNqqathlQI1aUtO8O0UZ9/aSpPUbl5bw88P2Sjinz8geYczm/xSRH0cuSR0n1bw7UMbOWMLmKhsv5TthFGoEsK+I3C8ivUXE+hERkGre3VlHlydxYneU1Tfv23whjFFiDICITMCZz28SkQeBB3ZiJUMjAcl8m+55eX7KsVOfo9rZFKM8IcwY6hFgE/BzYDxu8WrBhRPrH6l0dZBEvk01ja8O3LNptsQzaiBMl68rMBv4oapeo6rLcWtF7RepZMZ2zK+pcAijUGeo6igCq7er6hagV1RCGdUxv6bCIcyd2ENElgNNRGQDcLaq/ltVN0UsmxEgVewII38IczcuBA5X1RUi0hpn9ft3tGIlp1hnSoQhWewII38I0+WbraorAPz46W0AEWkSpWDJsLh8Rj4TpoXaW0T6AQtxhoimInIcbhWOopr+Yxg7SxiFOhpohPODitEXc+MwjO8RRqH+rKqvx2eKyDERyGMYBU0oF3gRuVFEJojIDbGxk6pOj1g2wyg4wijUMGAtMBJYD/wjUokMo4AJ0+VbqKpDYwkRuSpCeeocYWJIGIVDmDv3PyJSoqpb/UzzvaMWqq4QJoaEUViEUaipwGIR+RrYHfhjtCIVL8HWqHWzhgx94WM2bE4eQ8JmQRQeYdw3nhWRacABwAJVtcUCakGiaEXJAqzEYkjYrIjCI8zqG/2Ak1V1NtBLRA6JXqziIlF011TRiiyeXuESxsrXBXjMbz8OnBedOMVJqohGibB4eoVLGIWar6pVAKr6HfBltCIVH6kiGiXCfJwKlzCj3h+KyK+BBcD+QPsoBPEWxCuAdqpaVJ7ArZs1TFneoETYYvH0ioIwd20wcAfQAXgX+GtEsjQBpuDcRYoKTR7OCICTD21Nm90amY9TERDGyrccOKM2BxeRvYAbgY6q2jmQ3wP4FbDSnUKvU9U13jRfdHy5JrUvZpvdGnHFz3+QJWmMKIn6VdgVeBY4PJYhIo2BB4BDVLVSRJ4UkRNU9aWIZUmbTM1isMWj6w6RKpSqPiEi3eOyjwaWqGqlT08HTgFqVCgR6Y+PtNS2bbTfaDI5i6FnxzbcMOnDhGVmgCguwlj5Mk0rYF0gvRZoJSICnA4cJCKdElVU1RGqWqGqFS1btoxMwEyvCmhBVuoOYeLy7YszSqwDJgFLVfXNnTjnSgIRlIBmwEp1i/3e6v9ySpiVMIKzGMJ0DS3ISt0gzN28ErgLOB54BvfA74xCzQDaiUiZ7/YdA9wXtnI2grSEWQkjRjpdQwuyUvyE6fJ9pKrTgI2qupk0PuyKSDdc7InWIjJYRBqp6kacafxuEbkReC8dg0Q2grTEjAiJCBoRbMFoI54wLVQHETkKaCgih+ImyYbCK+K0BPkvAi+GljLLhDUipNs1NIqfMC3UrTiv3YE4c/ftkUpUAyLSS0RGrFmzJrJzhDUipNM1NOoGYT7sfghsXx9KRPaIVKIayNYKhmGMCPZ9yYgnjJWvKXAiOyxzvYDfRClUvlCTEcG+LxnxhOnyTQROAPb1fzn1zc5Gly8sibqGjRqUUFa/Hj0O3pMJc5ex3gwTdQrRGhx1RGSkqvYNpPdV1UWRS1YDFRUVOnv27FyLAcCGyiomvreMGZ9+zfPvL6dEhE1btlWbPW4xIgoLEZmjqhXp1gvTQi0WkRNFpJ2ItAXOTl+84qZJWX1O6dCGF+etYHOVsmnLNsBM6HWRMGbzAUD3QLotMCQKYQoZM6EbEE6h/uYXXAO2u17kjHxdzsZM6AaE6PKp6igR6SAiJ4jI/xBiVniUZHM5m/WVVTw68zNumTyPR2d+ltLAEHZ2hVHchDGb/xU4GfgMGAVchHNVL2rSdd8wE7oB4YwSTVX1eOBDVX0FKPq4fLWZo2cuGgaEG0PF+jGxIXfTiGTJG2prYDAXDSPMnd4qIlOAxiLSBXgnYplSkm/uG/GYi0bdJoxR4lrc5NjngAdV9ebIpUotT964bxhGPGFd4D8Cnge+EJFGEcqTF/Ts2IZkkb8SGRjSsQYaxU3SLp+I3AwcoKq/BYbj1tSth7P0XZsV6XJEzMAQb+VLFITSlqQxgqQaQ5WzIx7fdFX9hQ+kMi5yqfKAMAaGoDUwhi1JU7dJdbc/jsU0B/4FLiKliCyIXqz8oCYDg003MuJJNYbaPhBQ1c8S5eeCfHLfsOlGRjypFKq5iFRb/tPPNs/pwCCbU49qwqyBRjypuny3A8+JyCJcpKM2uHFVzyzIVRDYdCMjnqQKpapfisixuDDJ+wGvApN8KLG8pDaxyFPVSVYWzO9zVDvGzFgMSEproFE3qNFjN1+J99hNZL6uyVs2VR0gYdkVJ/2AW6d8VD0f6HN0OwSx6UZFQm09dotCodZXVnHkzVOrma9jNCkrSWi+TlWncWk9BKm2QntNJDuPUZhE6QKf94QxX6dTp2qrsmXrtrRkSHYeo25RcAqVyGxeG/N1qjqbt2rKVdrTOY9Rtyg4hUpkNq+N+TpVndISobQk9TKeYc9j1C0KTqESke5k1prq1C8RGpSkd2nMTG5AkShUbbxlU9UZ3e9IRvVLXHb9qYeYV66RlKKw8sWIBZxMx1s2VZ1kZbU5j1FY1GmzuWFkmjptNjeMfMEUyjAyiCmUYS/IxUgAAAoISURBVGQQUyjDyCCmUIaRQQpOofLJY9cw4ik4hconj13DiKfgFMow8hlTKMPIIKZQhpFBTKEMI4OYQhlGBjGFMowMYgplGBnEFMowMogplGFkEFMow8ggplCGkUFMoQwjg9T5yCK1WWDAMJKRF0+OiDQGhgCfAStU9fFsnNfWxzUyTWRdPhHZS0QeFpFZcfk9ROQ+ERkiIrHFr38FzFLV4cCZUckUJLg+biwk88bNW9lQudXn20ruRvpEOYbqCjwLbI/P6luiB4BLVHUI0EFETgD2AVb53RpFKNN2arPAgGHURGQKpapPAOviso8GlqhqpU9Pxy3o9jnQ0udtSnZMEekvIrNFZPaqVauS7RYKWx/XiIJsW/laUV3J1vq8p4DOIvInYHyyyqo6QlUrVLWiZcuWyXYLha2Pa0RBthVqJbBLIN0MWKmqG1V1oKoOz5ZBojYLDBhGTWRboWYA7USkzKePASalc4BMBWmpzQIDhlETkcU2F5FuwFnAScD9wB2quklETgR+jTNCbFHV62pz/EzFNrfA/0YibLEAw8ggdWaxAIvLZ+QzBadQFpfPyGcKTqEMI58pOIWyLp+RzxSsUUJEVgGrgTXArnH/WwBfpXnIWN10yuLzg+lE27mQM5WMiWRLlJeunKlkrI2cYa9rJuVsp6rpzx5Q1YL9A0Yk+T+7tsdKpyw+P5hOtJ0LOVPJmEimTMiZSsbayJnGdc2onLX5K7guXxwTkvzfmWOlUxafP6GG7VzImUrGYDqVvOlSU7105Qx7XdNlZ+5DQgq2y5cKEZmttfiGkG1MzsySD3IWeguVjBG5FiAkJmdmybmcRdlCGUauKNYWyjBygimUYWQQUyjDyCB1wk8hV1GV0kVE6gNX4D4q9s+1PMkQkV8APwAaAJ/k4/UUkY5AZ6Ax0EJVr8nGeQtWoURkL+BGoKOqdg7k98BFUVoJqDp/q1hUpcdF5Bkg7x4ATxNgCnBhtk+c5vWco6rPiciuwCNk6XqmI6OqzhWRdcDlwNPZkA8KWKHYEVXp8FhGIKrSIapaKSJPBqIqzfC7ZSWqUkCmdB6CNSLydTblCxD6eqrqS36X04Db81VGVV0oIgOB0cCL2RCwYMdQGkFUpYhIJ5xazkjzeiIipwALgS/yUUYR+Zmvs57qcUwipZBbqESkiqo0RET2JEVUpShQ1SdEpHtcdrIH9SXyi4TXU0R+iRvrzcU9rFkJTpqEZPe8pYhcCWwDRmVLmGJTqKRRlYCBuREpIckeVAFOBw4SkU6q+k5OpNtBsuv5DPBMbkT6HslkHJcLYQq2y5eEnY6qlCWSPQSqqreq6rF5oExQGNczr2QsWIXyUZX6AK1FZLCINPIt0YXA3SJyI/BeYACdT+TVQwCFcT0LQkabyxctUYdTM/ILUyjDyCAF2+UzjHzEFMowMogplGFkEFMow8ggplCGkUFMoQwjg5hCGUYGyfu5fCLSGufTshooAQ4CFqvq33IqWJ4jIn8ABqpqeYaO1woYCvwUF12oCXAE0B/3cfpOoERVz0lxjKFAF1XtHpff3h+7PfAY7rncDbhZVVOuHi4i5wDPqOrqWvym3YBfquqodOsmJdORMzP5BzQEZgH7BPJKgSdyLVsh/OFePJk8XncC0VmBa4FhgbJRNdQvB15NUnZO8L4CHYEFwK41HPNVoLyWvyepPLX9y/cW6hTcQ/F5LENVN+Om7AAgItfj3mhbgXWqOlRE+gJ/Bx4E2gH7AT1Vda2IHIJzPfgvzo37JlVdGDypiLTBOQXOAw7Aefs+LCKnAicCS/0xL8O9pe8G3vL5nYH7gK+BfwLTVbWviJwNXACcoaqL/XkOBEYCX/q/Tl6eSSIyABikquUiEmsVuuPczkcCi4BvgS7AMJxLSGfg76oamxfYQEQuxs1uPxg4T1W/EZHTcFOhFvrrc6n/HfcDc4BKf43ba+o3f0sS+EOJyC44x8PY8V9Q1Wd98a4icjnQGtgTOFd3uLFsR53H7Wzg98ADInIhrnfyFS4m+UB/L8qBv4jIR6qacD9VVRHpH8g/CuiNa13LRWQIzlP6g0Ryi8itXo6Rvu48Vf1LwiuS67doDW+QvwL3BNLtgEG4ELrlwM+Af8e9rQ4PbP/Mb98L/K/fngH8OPBWfTrBef8F/NZvl/qL3xynMKU+/wpclwScv815fnsvnHII0A+4z+f3BromeTP/y293BiYEyhbH/bbyQJ2xfvuXwOt++4i4+puApgF5b/O/YznQyOcPAS4ObA/12x2ABnGydvfXYBBwF/Am0DpQNspv/x243G+X+TrN/T37DKjny+4H/hj4TU/Ene9W4Gbcy2AeO6bKjQJOTXBdEu7n898PHPfXOGUrJ9BCJZPbp7/zv6EE/4wVYgv1KXBkLKGqS4BbRGQx0BR30xuLyCC/S9AzF+AT/38VO9wlOgA/FZHjcO7w6xOctwPu4Yu1iONEpDPwjU+D6470C9RZ6Pf/UkSaeDn+CVztYy901eQ+OonkrIlP/f/Vge1v4+qvUuexGpO3G67FVeBi537F7lS/BvP873gvyXm/VNVbAETkaNybvWPcPh1wsSZQ55b+rT/vKtxLYltApkNS/MZ2OIU5FOcoeIWXeQvO5SWeZPsdir8/XqYnvPzNQ8o9Cxfc51u/37vJBM53hZoEXCUi5YFukuDeEuA8Ro8O3OCf4G5SjEQzf+cCT6nqe9594rQk++wPvCMijYDf4FrF3UWk1CvVgVS/sPsBL3sjykbcw6wiMh54mNSB6cPMUN4nxD7xtBSRpl6p2gMf4q7Pd8DtqlolIvsDbdKUJcbyuLoxYtcPEWmIe7PPxxka2olIPa9U7XFd7+8hIofiWuwBuFZ/U+A+d8IpC7iuvvj9P0yy3xZg38Cx/xd4LVbX53VMIXfo65LXCuXfEj1xb5xvcYp0AK4pX6Sq74tIFxH5O84DtjkwyLtGtAP6icgo4DjgMBGZBJwLXCYiC3D9+EQRey4HbhKRA3A382FV/VZE/ojzu1mK6y5cEqjTXkSuxvWxz1HfT8CNp94mgZu4d8nvBTT35+qNe+BigVDGisg9uL79OmCAiPwjUKc9zj+og394fuHrn4hT+LXAJSLSDPfwnut/xyXAXSLyub9O1/ljxa7T+6pabUVwEWlJwBfJZ/8QuMCPmWJy/BjXdRrm92uL69at9i7pG4BrRGR3XGv6sP/tvXCeyoNx3ew9gG7qxnCrReRBERmGa+XaADEr7xRcF7SBqvZLtJ+qrheRe0TkTtwYqp6qPikubNt3InIb8HEKuc/Djf0uVdVh8fex2nXacd+N2uKVdpSqvhqXX4rr+vVV1RtzIJqRZfK6hSoERKQrru/dR0TmqOo6n98Y181bhHuDGnUAa6EMI4PY1CPDyCCmUIaRQUyhDCODmEIZRgYxhTKMDGIKZRgZ5P8DMTSYdUXg0ucAAAAASUVORK5CYII=\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plt.rc('font', family='serif', size=10)\n",
+ "for i in range(3):\n",
+ " decoded_tmp = decoded_lgbd[i]\n",
+ " genes_lgbd, counts_lgbd = np.unique(decoded_tmp.loc[decoded_tmp[Features.PASSES_THRESHOLDS]][Features.TARGET], return_counts=True)\n",
+ " result_counts_lgbd = pd.Series(counts_lgbd, index=genes_lgbd)\n",
+ "\n",
+ " genes_bd, counts_bd = np.unique(decoded_bd.loc[decoded_bd[Features.PASSES_THRESHOLDS]][Features.TARGET], return_counts=True)\n",
+ " result_counts_bd = pd.Series(counts_bd, index=genes_bd)\n",
+ " \n",
+ " tmp = pd.concat([result_counts_lgbd, result_counts_bd], join='inner', axis=1).values\n",
+ "\n",
+ " r = np.corrcoef(tmp[:, 1], tmp[:, 0])[0, 1]\n",
+ " x = np.linspace(50, 2000)\n",
+ " \n",
+ " f = plt.figure()\n",
+ " ax = plt.subplot(1,2,1)\n",
+ " ax.scatter(tmp[:, 1], tmp[:, 0], 50, zorder=2)\n",
+ "\n",
+ " ax.plot(x, x, '-k', zorder=1)\n",
+ " plt.xlabel('Gene copy number BlobDetector')\n",
+ " plt.ylabel('Gene copy number LGBD')\n",
+ " plt.xscale('log')\n",
+ " plt.yscale('log')\n",
+ " plt.title(f'r = {r}');"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Compare to results from paper\n",
+ "This FOV was selected to make sure that we can visualize the tumor/stroma boundary, below this is described by pseudo-coloring HER2 (tumor) and vimentin (VIM, stroma). This distribution matches the one described in the original paper."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 1/1 [00:00<00:00, 128.09it/s]\n",
+ "100%|██████████| 1/1 [00:00<00:00, 161.47it/s]\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from skimage.color import rgb2gray\n",
+ "\n",
+ "decoded_lgbd = decoded_lgbd[2]\n",
+ "\n",
+ "GENE1 = 'HER2'\n",
+ "GENE2 = 'VIM'\n",
+ "\n",
+ "rgb = np.zeros(registered_imgs.tile_shape + (3,))\n",
+ "nuclei_mp = nuclei.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)\n",
+ "nuclei_numpy = nuclei_mp._squeezed_numpy(Axes.ROUND, Axes.CH, Axes.ZPLANE)\n",
+ "rgb[:,:,0] = nuclei_numpy\n",
+ "dots_mp = dots.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)\n",
+ "dots_mp_numpy = dots_mp._squeezed_numpy(Axes.ROUND, Axes.CH, Axes.ZPLANE)\n",
+ "rgb[:,:,1] = dots_mp_numpy\n",
+ "do = rgb2gray(rgb)\n",
+ "do = do/(do.max())\n",
+ "\n",
+ "plt.imshow(do,cmap='gray')\n",
+ "plt.axis('off');\n",
+ "\n",
+ "with warnings.catch_warnings():\n",
+ " warnings.simplefilter('ignore', FutureWarning)\n",
+ " is_gene1 = decoded_lgbd.where(decoded_lgbd[Features.AXIS][Features.TARGET] == GENE1, drop=True)\n",
+ " is_gene2 = decoded_lgbd.where(decoded_lgbd[Features.AXIS][Features.TARGET] == GENE2, drop=True)\n",
+ "\n",
+ "plt.plot(is_gene1.x, is_gene1.y, 'or', markersize=3)\n",
+ "plt.plot(is_gene2.x, is_gene2.y, 'ob', markersize=3)\n",
+ "plt.title(f'Red: {GENE1}, Blue: {GENE2}');"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.1"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/py/graph_decoding.py b/notebooks/py/graph_decoding.py
new file mode 100644
index 000000000..d4142f25f
--- /dev/null
+++ b/notebooks/py/graph_decoding.py
@@ -0,0 +1,482 @@
+#!/usr/bin/env python
+# coding: utf-8
+#
+# EPY: stripped_notebook: {"metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.1"}}, "nbformat": 4, "nbformat_minor": 2}
+
+# EPY: START markdown
+## Graph-based Decoding
+#
+#This notebook walks through how to use a Graph-based decoding approach [1] to process spatial transcriptomic data. Graph-based decoding can only be applied to assays with one-hot-encoding codebooks (i.e. a single fluorescent channel active per round). We will first see how the graph-based decoding module works with some toy examples, and after we apply it on a real application with in situ sequencing data.
+#
+#The graph based decoding module ```LocalGraphBlobDetector``` builds a graph out of the candidate spots detected by an arbitrary spot finder algorithm (please see [documentation](https://spacetx-starfish.readthedocs.io/en/stable/) for a list of spot finder algorithms included in the module). Nodes of the graph representing detected spots are then connected with edges based on spatial distances. Cost weights proportional to the distance and quality of the detected spots are then assigned to each edge connecting a pair of nodes. Genes are finally decoded by optimizing the graph with respect to the edge costs providing the best spots configuration with higher qualities and smaller distances.
+#
+#In details, ```LocalGraphBlobDetector``` first finds spots for every channel and round. Four possible spot detectors are integrated from [scikit-image](https://scikit-image.org/), two based local maxima and two blob detection algorithms. Secondly, overlapping spots are merged across channels within each round in order to handle fluorescent bleed-trough. Next, a quality score is assigned for each detected spot (maximum channel intensity divided by channel intensity vector l2-norm). Detected spots belonging to different sequencing rounds and closer than `search_radius` are connected in a graph, forming connected components of spot detections. Next, for each connected component, edges between not connected spots belonging to consecutive rounds are forced if they are closer than `search_radius_max`. Finally, all the edges that connect spots not belonging to consecutive rounds are removed and each connected component is solved by maximum flow minimum cost algorithm. Where, costs are proportional to spot quality and distances.
+#
+#[1] Partel, G. et al. Identification of spatial compartments in tissue from in situ sequencing data. BioRxiv, https://doi.org/10.1101/765842, (2019).
+# EPY: END markdown
+
+# EPY: START code
+# EPY: ESCAPE %matplotlib inline
+
+import numpy as np
+import os
+import pandas as pd
+import matplotlib
+import matplotlib.pyplot as plt
+import pprint
+from scipy.ndimage.filters import gaussian_filter
+from starfish.core.spots.DetectSpots.local_graph_blob_detector import LocalGraphBlobDetector
+from starfish.core.spots.DetectSpots.local_search_blob_detector import LocalSearchBlobDetector
+
+
+from starfish import data, FieldOfView, ImageStack
+from starfish.types import Features, Axes
+from starfish.util.plot import imshow_plane
+# EPY: END code
+
+# EPY: START markdown
+### Example 1
+#We first see an example on how to tune two important parameters, `search_radius` and `search_radius_max`, that define the graph connections of detected spots. We start by creating three synthetic spots laying in two channels and three sequential rounds (color coded with red, green and blue colors). Each of the spot has 3px shift in x,y respect to the spot in the previous round.
+# EPY: END markdown
+
+# EPY: START code
+# Create synthetic data
+img = np.zeros((3, 2, 1, 50, 50), dtype=np.float32)
+
+# code 1
+# round 1
+img[0, 0, 0, 35, 35] = 10
+# round 2
+img[1, 1, 0, 32, 32] = 10
+# round 3
+img[2, 0, 0, 29, 29] = 10
+
+# blur points
+gaussian_filter(img, (0, 0, 0, 1.5, 1.5), output=img)
+stack = ImageStack.from_numpy(img)
+
+plt.imshow(np.moveaxis(np.amax(np.squeeze(img),axis=1),0,-1))
+# EPY: END code
+
+# EPY: START markdown
+#We now decode the sequence with `LocalGraphBlobDetector` setting `search_radius` to an approximate value representing the euclidean distance between two spots belonging to different sequencing rounds, and `search_radius_max` to a value representing the maximum euclidean distance between all the spots of the same sequence.
+# EPY: END markdown
+
+# EPY: START code
+# search_radius=5, search_radius_max=10
+lgbd = LocalGraphBlobDetector(search_radius=5, search_radius_max=10, h=0.5)
+intensity_table = lgbd.run(stack, n_processes=1)
+# One sequence decoded
+intensity_table
+# EPY: END code
+
+# EPY: START code
+# search_radius=5, search_radius_max=5
+lgbd = LocalGraphBlobDetector(search_radius=5, search_radius_max=5, h=0.5)
+intensity_table = lgbd.run(stack, n_processes=1)
+# Zero sequence decoded
+intensity_table
+# EPY: END code
+
+# EPY: START markdown
+### Example 2
+#We now change the distances between the spots such that the 3rd round spot (blue) lay between the other two, and compare the results with other decoding approaches.
+# EPY: END markdown
+
+# EPY: START code
+# Create synthetic data
+img = np.zeros((3, 2, 1, 50, 50), dtype=np.float32)
+
+# code 1
+# round 1
+img[0, 0, 0, 35, 35] = 10
+# round 2
+img[1, 1, 0, 29, 29] = 10
+# round 3
+img[2, 0, 0, 32, 32] = 10
+
+# blur points
+gaussian_filter(img, (0, 0, 0, 1.5, 1.5), output=img)
+stack = ImageStack.from_numpy(img)
+
+plt.imshow(np.moveaxis(np.amax(np.squeeze(img),axis=1),0,-1))
+# EPY: END code
+
+# EPY: START code
+# LocalGraphBlobDetector
+lgbd = LocalGraphBlobDetector(
+ search_radius=5,
+ search_radius_max=10,
+ detector_method='blob_log',
+ min_sigma=(0.4, 1.2, 1.2),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.1,
+ overlap=0.5)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START markdown
+#`LocalSearchBlobDetector` decode the correct sequence only if `anchor_round` is set to the round of the spot lying in the middle, otherwise will fail to connect all the spots.
+# EPY: END markdown
+
+# EPY: START code
+# LocalSearchBlobDetector
+# Anchor round: 1st round
+lgbd = LocalSearchBlobDetector(
+ search_radius=5,
+ min_sigma=(0.4, 1.2, 1.2),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.1,
+ overlap=0.5,
+ anchor_round=0)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START code
+# LocalSearchBlobDetector
+# Anchor round: 3rd round
+lgbd = LocalSearchBlobDetector(
+ search_radius=5,
+ min_sigma=(0.4, 1.2, 1.2),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.1,
+ overlap=0.5,
+ anchor_round=2)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START markdown
+### Example 3
+#Let's now add some noise and multiple possible decoding choices. Specifically, the second round has two possible spot candidates one a bit weaker than the other, both equally spaced respect from the spots of the other rounds. `LocalGraphBlobDetector` provides the best possible decoding solution choosing the spot with highest quality for the second round since distance costs are equivalent. The results of `LocalSearchBlobDetector` strongly depends from the initialization of the anchor round (i.e. from where to start the search), providing different solutions for each initialization.
+#(Please note that when anchor round is set to the second round, two sequences are decoded, the correct one plus a false positive.)
+# EPY: END markdown
+
+# EPY: START code
+# Create synthetic data
+img = np.zeros((3, 2, 1, 50, 50), dtype=np.float32)
+
+# code 1
+# round 1
+img[0, 0, 0, 35, 32] = 1
+# round 2
+img[1, 1, 0, 36, 34] = 1
+img[1, 0, 0, 32, 28] = 0.5 # Noise
+# round 3
+img[2, 0, 0, 33, 30] = 1
+
+# blur points
+gaussian_filter(img, (0, 0, 0, 1.5, 1.5), output=img)
+
+# add camera noise
+np.random.seed(6)
+camera_noise = np.random.normal(scale=0.005, size=img.shape).astype(np.float32)
+img = img + np.clip(camera_noise,0.001,None)
+
+stack = ImageStack.from_numpy(img)
+
+plt.imshow(np.moveaxis(np.amax(np.squeeze(img*10),axis=1),0,-1))
+# EPY: END code
+
+# EPY: START code
+# LocalGraphBlobDetector
+lgbd = LocalGraphBlobDetector(
+ search_radius=5,
+ search_radius_max=5,
+ detector_method='blob_log',
+ min_sigma=(0.2, 0.5, 0.5),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.05,
+ overlap=0.5)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START code
+# LocalSearchBlobDetector
+# Anchor round: 1st round
+lgbd = LocalSearchBlobDetector(
+ search_radius=5,
+ min_sigma=(0.2, 0.5, 0.5),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.05,
+ overlap=0.5,
+ anchor_round=0)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START code
+# LocalSearchBlobDetector
+# Anchor round: 2nd round
+lgbd = LocalSearchBlobDetector(
+ search_radius=5,
+ min_sigma=(0.2, 0.5, 0.5),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.05,
+ overlap=0.5,
+ anchor_round=1)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START code
+# LocalSearchBlobDetector
+# Anchor round: 3rd round
+lgbd = LocalSearchBlobDetector(
+ search_radius=5,
+ min_sigma=(0.2, 0.5, 0.5),
+ max_sigma=(0.6, 1.7, 1.7),
+ num_sigma=3,
+ threshold=0.05,
+ overlap=0.5,
+ anchor_round=2)
+intensity_table = lgbd.run(stack, n_processes=1)
+intensity_table
+# EPY: END code
+
+# EPY: START markdown
+### Reproduce In-situ Sequencing results with Starfish Graph-based Decoding
+#
+#Let's now see the `LocalGraphBlobDetector` applied to In Situ Sequencing (ISS). ISS is an image based transcriptomics technique that can spatially resolve hundreds RNA species and their expression levels in-situ. The protocol and data analysis are described in this [publication](https://www.ncbi.nlm.nih.gov/pubmed/23852452). Here we use the `LocalGraphBlobDetector` to process the raw images from an ISS experiment into a spatially resolved cell by gene expression matrix. And we verify that we can accurately reproduce the results from the authors' original [pipeline](https://cellprofiler.org/previous_examples/#sequencing-rna-molecules-in-situ-combining-cellprofiler-with-imagej-plugins)
+#
+#Please see [documentation](https://spacetx-starfish.readthedocs.io/en/stable/) for detailed descriptions of all the data structures and methods used here.
+# EPY: END markdown
+
+# EPY: START code
+matplotlib.rcParams["figure.dpi"] = 150
+# EPY: END code
+
+# EPY: START markdown
+### Load Data into Starfish from the Cloud
+#
+#The primary data from one field of view correspond to 16 images from 4 hybridization rounds (r) 4 color channels (c) one z plane (z). Each image is 1044 x 1390 (y, x). These data arise from human breast tissue. O(10) transcripts are barcoded for subsequent spatial resolution.
+# EPY: END markdown
+
+# EPY: START code
+use_test_data = os.getenv("USE_TEST_DATA") is not None
+
+# An experiment contains a codebook, primary images, and auxiliary images
+experiment = data.ISS(use_test_data=use_test_data)
+pp = pprint.PrettyPrinter(indent=2)
+pp.pprint(experiment._src_doc)
+# EPY: END code
+
+# EPY: START code
+fov = experiment.fov()
+dots = fov.get_image("dots")
+dots_single_plane = dots.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)
+nuclei = fov.get_image("nuclei")
+nuclei_single_plane = nuclei.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)
+
+# note the structure of the 5D tensor containing the raw imaging data
+imgs = fov.get_image(FieldOfView.PRIMARY_IMAGES)
+print(imgs)
+# EPY: END code
+
+# EPY: START markdown
+### Visualize Codebook
+#
+#The ISS codebook maps each decoded barcode to a gene.This protocol asserts that genes are encoded with a length 4 quaternary barcode that can be read out from the images. Each round encodes a position in the codeword. The maximum signal in each color channel (columns in the above image) corresponds to a letter in the codeword. The channels, in order, correspond to the letters: 'T', 'G', 'C', 'A'.
+# EPY: END markdown
+
+# EPY: START code
+experiment.codebook
+# EPY: END code
+
+# EPY: START markdown
+### Filter raw data before decoding into spatially resolved gene expression
+#
+#A White-Tophat filter can be used to enhance spots while minimizing background autoflourescence. The ```masking_radius``` parameter specifies the expected radius, in pixels, of each spot.
+# EPY: END markdown
+
+# EPY: START code
+from starfish.image import Filter
+
+# filter raw data
+masking_radius = 15
+filt = Filter.WhiteTophat(masking_radius, is_volume=False)
+
+filtered_imgs = filt.run(imgs, verbose=True, in_place=False)
+filt.run(dots, verbose=True, in_place=True)
+filt.run(nuclei, verbose=True, in_place=True)
+# EPY: END code
+
+# EPY: START markdown
+### Register data
+#Images may have shifted between imaging rounds. This needs to be corrected for before decoding, since this shift in the images will corrupt the barcodes, thus hindering decoding accuracy. A simple procedure can correct for this shift. For each imaging round, the max projection across color channels should look like the dots stain. Below, we simply shift all images in each round to match the dots stain by learning the shift that maximizes the cross-correlation between the images and the dots stain.
+# EPY: END markdown
+
+# EPY: START code
+
+from starfish.image import ApplyTransform, LearnTransform
+
+learn_translation = LearnTransform.Translation(reference_stack=dots, axes=Axes.ROUND, upsampling=1000)
+transforms_list = learn_translation.run(imgs.max_proj(Axes.CH, Axes.ZPLANE))
+warp = ApplyTransform.Warp()
+registered_imgs = warp.run(filtered_imgs, transforms_list=transforms_list, in_place=False, verbose=True)
+# EPY: END code
+
+# EPY: START markdown
+### Decode the processed data into spatially resolved gene expression profiles
+# EPY: END markdown
+
+# EPY: START markdown
+#```LocalGraphBlobDetector``` instance using [Laplacian of Gaussian (LoG)](https://scikit-image.org/docs/dev/api/skimage.feature.html?highlight=blob_log#skimage.feature.blob_log) blob detection algorithm. Please refer to `scikit-image` documentation for a full parameter list.
+# EPY: END markdown
+
+# EPY: START code
+from starfish.spots import DetectSpots
+import warnings
+
+intensities_lgbd = []
+import warnings
+lgbd1 = DetectSpots.LocalGraphBlobDetector(
+ detector_method='blob_log',
+ min_sigma=(0,0.5,0.5),
+ max_sigma=(0,3,3),
+ num_sigma=10,
+ threshold=0.03,
+ search_radius=3,
+ search_radius_max=5
+)
+
+intensities_lgbd.append(lgbd1.run(registered_imgs))
+# EPY: END code
+
+# EPY: START markdown
+#```LocalGraphBlobDetector``` instance using [`peak_local_max`](https://scikit-image.org/docs/dev/api/skimage.feature.html?highlight=peak_local_max#skimage.feature.peak_local_max) local maxima detection algorithm. Please refer to `scikit-image` documentation for a full parameter list.
+# EPY: END markdown
+
+# EPY: START code
+import warnings
+lgbd2 = DetectSpots.LocalGraphBlobDetector(
+ detector_method='peak_local_max',
+ exclude_border=False,
+ threshold_abs=0.03,
+ search_radius=3,
+ search_radius_max=5
+)
+
+intensities_lgbd.append(lgbd2.run(registered_imgs))
+# EPY: END code
+
+# EPY: START markdown
+#```LocalGraphBlobDetector``` instance using [`h_maxima`](https://scikit-image.org/docs/dev/api/skimage.morphology.html?highlight=h_maxima#skimage.morphology.h_maxima) local maxima detection algorithm. Please refer to `scikit-image` documentation for a full parameter list.
+# EPY: END markdown
+
+# EPY: START code
+import warnings
+connectivity=np.array([[[0, 0, 0],[0, 1, 0],[0, 0, 0]],[[0, 1, 0],[1, 1, 1],[0, 1, 0]],[[0, 0, 0],[0, 1, 0],[0, 0, 0]]]) #3D corss
+lgbd3 = DetectSpots.LocalGraphBlobDetector(
+ detector_method='h_maxima',
+ h=0.015,
+ selem=connectivity,
+ search_radius=3,
+ search_radius_max=5
+)
+
+intensities_lgbd.append(lgbd3.run(registered_imgs))
+# EPY: END code
+
+# EPY: START markdown
+#We now compare the results from the three decoding approaches used previously with `BlobDetector` algorithm. This spot detection finds spots, and record, for each spot, the maximum pixel intensities across rounds and channels.
+# EPY: END markdown
+
+# EPY: START code
+bd = DetectSpots.BlobDetector(
+ min_sigma=0.5,
+ max_sigma=3,
+ num_sigma=10,
+ threshold=0.03,
+ measurement_type='max',
+)
+intensities_bd = bd.run(registered_imgs, blobs_image=dots, blobs_axes=(Axes.ROUND, Axes.ZPLANE))
+# EPY: END code
+
+# EPY: START markdown
+#To decode the resulting intensity tables, we simply match intensities to codewords in the codebook. This can be done by, for each round, selecting the color channel with the maximum intensity. This forms a potential quaternary code which serves as the key into a lookup in the codebook as to which gene this code corresponds to. Decoded genes are assigned to the target field in the decoded intensity table.
+# EPY: END markdown
+
+# EPY: START code
+decoded_lgbd = []
+for i in range(3):
+ decoded_lgbd.append(experiment.codebook.decode_per_round_max(intensities_lgbd[i]))
+
+decoded_bd = experiment.codebook.decode_per_round_max(intensities_bd)
+# EPY: END code
+
+# EPY: START markdown
+#We now compare the results of the results from three ```LocalGraphBlobDetector``` instances with respect to `BlobDetector` results, plotting the correlation of decoded read counts.
+# EPY: END markdown
+
+# EPY: START code
+plt.rc('font', family='serif', size=10)
+for i in range(3):
+ decoded_tmp = decoded_lgbd[i]
+ genes_lgbd, counts_lgbd = np.unique(decoded_tmp.loc[decoded_tmp[Features.PASSES_THRESHOLDS]][Features.TARGET], return_counts=True)
+ result_counts_lgbd = pd.Series(counts_lgbd, index=genes_lgbd)
+
+ genes_bd, counts_bd = np.unique(decoded_bd.loc[decoded_bd[Features.PASSES_THRESHOLDS]][Features.TARGET], return_counts=True)
+ result_counts_bd = pd.Series(counts_bd, index=genes_bd)
+
+ tmp = pd.concat([result_counts_lgbd, result_counts_bd], join='inner', axis=1).values
+
+ r = np.corrcoef(tmp[:, 1], tmp[:, 0])[0, 1]
+ x = np.linspace(50, 2000)
+
+ f = plt.figure()
+ ax = plt.subplot(1,2,1)
+ ax.scatter(tmp[:, 1], tmp[:, 0], 50, zorder=2)
+
+ ax.plot(x, x, '-k', zorder=1)
+ plt.xlabel('Gene copy number BlobDetector')
+ plt.ylabel('Gene copy number LGBD')
+ plt.xscale('log')
+ plt.yscale('log')
+ plt.title(f'r = {r}');
+# EPY: END code
+
+# EPY: START markdown
+### Compare to results from paper
+#This FOV was selected to make sure that we can visualize the tumor/stroma boundary, below this is described by pseudo-coloring HER2 (tumor) and vimentin (VIM, stroma). This distribution matches the one described in the original paper.
+# EPY: END markdown
+
+# EPY: START code
+from skimage.color import rgb2gray
+
+decoded_lgbd = decoded_lgbd[2]
+
+GENE1 = 'HER2'
+GENE2 = 'VIM'
+
+rgb = np.zeros(registered_imgs.tile_shape + (3,))
+nuclei_mp = nuclei.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)
+nuclei_numpy = nuclei_mp._squeezed_numpy(Axes.ROUND, Axes.CH, Axes.ZPLANE)
+rgb[:,:,0] = nuclei_numpy
+dots_mp = dots.max_proj(Axes.ROUND, Axes.CH, Axes.ZPLANE)
+dots_mp_numpy = dots_mp._squeezed_numpy(Axes.ROUND, Axes.CH, Axes.ZPLANE)
+rgb[:,:,1] = dots_mp_numpy
+do = rgb2gray(rgb)
+do = do/(do.max())
+
+plt.imshow(do,cmap='gray')
+plt.axis('off');
+
+with warnings.catch_warnings():
+ warnings.simplefilter('ignore', FutureWarning)
+ is_gene1 = decoded_lgbd.where(decoded_lgbd[Features.AXIS][Features.TARGET] == GENE1, drop=True)
+ is_gene2 = decoded_lgbd.where(decoded_lgbd[Features.AXIS][Features.TARGET] == GENE2, drop=True)
+
+plt.plot(is_gene1.x, is_gene1.y, 'or', markersize=3)
+plt.plot(is_gene2.x, is_gene2.y, 'ob', markersize=3)
+plt.title(f'Red: {GENE1}, Blue: {GENE2}');
+# EPY: END code
diff --git a/starfish/core/spots/DetectSpots/__init__.py b/starfish/core/spots/DetectSpots/__init__.py
index 126b1b715..cf6408614 100644
--- a/starfish/core/spots/DetectSpots/__init__.py
+++ b/starfish/core/spots/DetectSpots/__init__.py
@@ -1,5 +1,6 @@
from ._base import DetectSpotsAlgorithm
from .blob import BlobDetector
+from .local_graph_blob_detector import LocalGraphBlobDetector
from .local_max_peak_finder import LocalMaxPeakFinder
from .local_search_blob_detector import LocalSearchBlobDetector
from .trackpy_local_max_peak_finder import TrackpyLocalMaxPeakFinder
diff --git a/starfish/core/spots/DetectSpots/local_graph_blob_detector.py b/starfish/core/spots/DetectSpots/local_graph_blob_detector.py
new file mode 100644
index 000000000..6e85f21ca
--- /dev/null
+++ b/starfish/core/spots/DetectSpots/local_graph_blob_detector.py
@@ -0,0 +1,812 @@
+import itertools
+from collections import defaultdict
+from typing import Any, Dict, Hashable, List, Mapping, Optional, Sequence, Tuple, Union
+
+import networkx as nx
+import numpy as np
+import pandas as pd
+import xarray as xr
+from click import Choice
+from scipy.spatial import cKDTree as KDTree
+from scipy.spatial import distance
+from skimage import img_as_float
+from skimage.feature import peak_local_max
+from skimage.measure import label
+from skimage.morphology import h_maxima
+from tqdm import tqdm
+
+from starfish.core.compat import blob_dog, blob_log
+from starfish.core.image.Filter.util import determine_axes_to_group_by
+from starfish.core.imagestack.imagestack import ImageStack
+from starfish.core.intensity_table.intensity_table import IntensityTable
+from starfish.core.intensity_table.intensity_table_coordinates import \
+ transfer_physical_coords_to_intensity_table
+from starfish.core.types import Axes, Features, SpotAttributes
+from starfish.core.util import click
+from ._base import DetectSpotsAlgorithm
+
+detectors = {
+ 'h_maxima': h_maxima,
+ 'peak_local_max': peak_local_max,
+ 'blob_dog': blob_dog,
+ 'blob_log': blob_log
+}
+
+
+class LocalGraphBlobDetector(DetectSpotsAlgorithm):
+ """
+ Multi-dimensional spot detector.
+ This method includes four different spot detectors from skimage and merge the detected
+ spots across channels and rounds based on a graph-based decoding approach implemented in [1].
+
+ Parameters
+ ----------
+ detector_method : str ['h_maxima', 'peak_local_max', 'blob_dog', 'blob_log']
+ Name of the type of detection method used from skimage, default: h_maxima.
+ search_radius : int
+ Euclidean distance in pixels over which to search for spots in subsequent rounds.
+ search_radius_max : int
+ The maximum (euclidian) distance in pixels allowed between nodes belonging to the
+ same sequence
+ k_d : float
+ distance weight
+ detector_kwargs : Dict[str, Any]
+ Additional keyword arguments to pass to the detector_method.
+
+ Notes
+ -----
+ [1] Partel, G. et al. Identification of spatial compartments in tissue from in situ sequencing
+ data. BioRxiv, https://doi.org/10.1101/765842, (2019).
+ """
+
+ def __init__(
+ self,
+ detector_method: str='h_maxima',
+ search_radius: int=3,
+ search_radius_max: int=5,
+ k_d: float=0.33,
+ **detector_kwargs,
+ ) -> None:
+ self.is_volume = True # TODO test 2-d spot calling
+ self.search_radius = search_radius
+ self.search_radius_max = search_radius_max
+ self.k_d = k_d
+ self.anchor_round = 0
+ self.detector_kwargs = detector_kwargs
+ try:
+ self.detector_method = detectors[detector_method]
+ except ValueError:
+ raise ValueError(f"Detector method must be one of {list(detectors.keys())}")
+
+ def _spot_finder(self, data: xr.DataArray) -> pd.DataFrame:
+ """Find spots in a data volume.
+
+ Parameters
+ ----------
+ data : xr.DataArray
+ 3D (z, y, x) data volume in which spots will be identified.
+
+ Returns
+ -------
+ pd.DataFrame
+ DataFrame wrapping the output of skimage blob_log or blob_dog with named outputs.
+ """
+
+ results = self.detector_method(
+ img_as_float(data),
+ **self.detector_kwargs
+ )
+
+ if (self.detector_method == h_maxima):
+ label_h_max = label(results, neighbors=4)
+ # no maxima present in image
+ if (label_h_max == np.ones(label_h_max.shape)).all():
+ max_mask = np.zeros(data.shape)
+ else:
+ labels = pd.DataFrame(
+ data={'labels': np.sort(label_h_max[np.where(label_h_max != 0)])})
+ # find duplicates labels (=connected components)
+ dup = labels.index[labels.duplicated()].tolist()
+
+ # splitting connected regional maxima to get only one local maxima
+ max_mask = np.zeros(data.shape)
+ max_mask[label_h_max != 0] = 1
+
+ # Compute medoid for connected regional maxima
+ for i in range(len(dup)):
+ # find coord of points having the same label
+ z, r, c = np.where(label_h_max == labels.loc[dup[i], 'labels'])
+ meanpoint_x = np.mean(c)
+ meanpoint_y = np.mean(r)
+ meanpoint_z = np.mean(z)
+ dist = [distance.euclidean([meanpoint_z, meanpoint_y, meanpoint_x],
+ [z[j], r[j], c[j]]) for j in range(len(r))]
+ ind = dist.index(min(dist))
+ # delete values at ind position.
+ z, r, c = np.delete(z, ind), np.delete(r, ind), np.delete(c, ind)
+ max_mask[z, r, c] = 0 # set to 0 points != medoid coordinates
+ results = max_mask.nonzero()
+ results = np.vstack(results).T
+
+ # if spots were detected
+ if results.shape[0]:
+ # measure intensities
+ z_inds = results[:, 0].astype(int)
+ y_inds = results[:, 1].astype(int)
+ x_inds = results[:, 2].astype(int)
+ intensities = data.values[tuple([z_inds, y_inds, x_inds])]
+
+ if (self.detector_method == blob_dog) | (self.detector_method == blob_log):
+ # collapse radius if sigma is non-scalar
+ if results.shape[1] > 3:
+ radius = np.mean(results[:, -3:], axis=1)
+ else:
+ radius = results[:, 3]
+ else:
+ radius = np.ones(results.shape[0])
+
+ # construct dataframe
+ spot_data = pd.DataFrame(
+ data={
+ "intensity": intensities,
+ Axes.ZPLANE: z_inds,
+ Axes.Y: y_inds,
+ Axes.X: x_inds,
+ Features.SPOT_RADIUS: radius
+ }
+ )
+
+ else:
+ spot_data = pd.DataFrame(
+ data=np.array(
+ [],
+ dtype=[
+ ('intensity', float), ('z', int), ('y', int), ('x', int),
+ (Features.SPOT_RADIUS, float)
+ ]
+ )
+ )
+
+ return spot_data
+
+ def _find_spots(
+ self,
+ data_stack: ImageStack,
+ verbose: bool=False,
+ n_processes: Optional[int]=None
+ ) -> Dict[Tuple[int, int], np.ndarray]:
+ """Find spots in all (z, y, x) volumes of an ImageStack.
+
+ Parameters
+ ----------
+ data_stack : ImageStack
+ Stack containing spots to find.
+
+ Returns
+ -------
+ Dict[Tuple[int, int], np.ndarray]
+ Dictionary mapping (round, channel) pairs to a spot table generated by skimage blob_log
+ or blob_dog.
+ """
+ # find spots in each (r, c) volume
+ transform_results = data_stack.transform(
+ self._spot_finder,
+ group_by=determine_axes_to_group_by(self.is_volume),
+ n_processes=n_processes,
+ )
+
+ # create output dictionary
+ spot_results = {}
+ for spot_calls, axes_dict in transform_results:
+ r = axes_dict[Axes.ROUND]
+ c = axes_dict[Axes.CH]
+ spot_results[r, c] = spot_calls
+
+ return spot_results
+
+ @staticmethod
+ def _merge_spots_by_round(
+ round_dataframes: Dict[int, pd.DataFrame], channels: Sequence[int], rounds: Sequence[int]
+ ) -> Dict[int, IntensityTable]:
+ """ For each round, find connected components of spots across channels and merge them
+ in a single feature.
+
+ Parameters
+ ----------
+ round_dataframes : Dict[int, pd.DataFrame]
+ Output from _merge_spots_by_round, contains mapping of image volumes from each round to
+ all the spots detected in them.
+ channels, rounds : Sequence[int]
+ Channels and rounds present in the ImageStack from which spots were detected.
+
+ Returns
+ -------
+ Dict[int, IntensityTable]
+ Dictionary mapping round to the relative IntensityTable.
+ """
+ intensity_tables = {}
+
+ # get spots matching across channels
+ for r, df in round_dataframes.items():
+ # Find connected components across channels
+ G = nx.Graph()
+ kdT = KDTree(df.loc[:, ['z', 'y', 'x']].values)
+ pairs = kdT.query_pairs(1, p=1)
+ G.add_nodes_from(df.index.values)
+ G.add_edges_from(pairs)
+ conn_comps = [list(i) for i in nx.connected_components(G)]
+ # for each connected component keep detection with highest intensity
+ refined_conn_comps = []
+ for i in range(len(conn_comps)):
+ df_tmp = df.loc[conn_comps[i], :]
+ kdT_tmp = KDTree(df_tmp.loc[:, ['z', 'y', 'x']].values)
+ # Check if all spots whitin a conn component are at most 1 pixels away
+ # from each other (Manhattan distance)
+ spot_pairs = len(list(itertools.combinations(np.arange(len(df_tmp)), 2)))
+ spots_connected = len(kdT_tmp.query_pairs(2, p=1)) # 2 could be a parameter
+ if spot_pairs == spots_connected:
+ # Merge spots
+ refined_conn_comps.append(conn_comps[i])
+ else:
+ # split non overlapping signals
+ for j, row in df_tmp.drop_duplicates(['z', 'y', 'x']).iterrows():
+ refined_conn_comps.append(df_tmp[(df_tmp.z == row.z)
+ & (df_tmp.y == row.y)
+ & (df_tmp.x == row.x)].index.values.tolist())
+
+ data = np.full((len(refined_conn_comps), len(channels), len(rounds)), fill_value=np.nan)
+ spot_radius = []
+ z = []
+ y = []
+ x = []
+ feature_index = []
+ f_idx = 0
+ channel_index = []
+ round_index = []
+ intensity_data = []
+ for s in refined_conn_comps:
+ df_tmp = df.loc[s]
+ anchor_s_idx = df_tmp.intensity.idxmax()
+ for i, row in df_tmp.iterrows():
+ data[f_idx, int(row.c), r] = row.intensity
+
+ spot_radius.append(df_tmp.loc[anchor_s_idx, 'radius'])
+ z.append(df_tmp.loc[anchor_s_idx, 'z'])
+ y.append(df_tmp.loc[anchor_s_idx, 'y'])
+ x.append(df_tmp.loc[anchor_s_idx, 'x'])
+ feature_index.append(f_idx)
+ f_idx += 1
+ channel_index.append(df_tmp.loc[anchor_s_idx, 'c'])
+ round_index.append(r)
+ intensity_data.append(df_tmp.loc[anchor_s_idx, 'intensity'])
+
+ # create IntensityTable
+ dims = (Features.AXIS, Axes.CH.value, Axes.ROUND.value)
+ coords: Mapping[Hashable, Tuple[str, Any]] = {
+ Features.SPOT_RADIUS: (Features.AXIS, feature_index),
+ Axes.ZPLANE.value: (Features.AXIS, z),
+ Axes.Y.value: (Features.AXIS, y),
+ Axes.X.value: (Features.AXIS, x),
+ Axes.ROUND.value: (Axes.ROUND.value, rounds),
+ Axes.CH.value: (Axes.CH.value, channels)
+ }
+ intensity_table = IntensityTable(data=data, dims=dims, coords=coords)
+
+ intensity_tables[r] = intensity_table
+
+ return intensity_tables
+
+ def _compute_spot_qualities(
+ self, data_stack: ImageStack, intensity_tables: Dict[int, IntensityTable]
+ ) -> Dict[int, IntensityTable]:
+ """Interate over the intesity tables of each round and assign to each feature a quality score
+
+ Parameters
+ ----------
+ data_stack : ImageStack
+ Stack containing spots to find.
+
+ Returns
+ -------
+ Dict[int,IntensityTable]:
+ Dictionary mapping round to the relative IntensityTable with quality coordinate Q
+ representing the quality score of each feature.
+ """
+ # Fill NaN values of intensity table with intensity values from ImageStack
+ for r in intensity_tables:
+ features_nan, c_nan = np.where(np.isnan(intensity_tables[r].values[:, :, r]))
+ for i in range(len(features_nan)):
+ z_nan = int(intensity_tables[r]['z'].values[features_nan[i]])
+ y_nan = int(intensity_tables[r]['y'].values[features_nan[i]])
+ x_nan = int(intensity_tables[r]['x'].values[features_nan[i]])
+ intensity_tables[r].values[features_nan[i],
+ c_nan[i], r] = data_stack.xarray.values[r,
+ c_nan[i],
+ z_nan,
+ y_nan,
+ x_nan]
+ intensity_tables[r] = intensity_tables[r]
+
+ for i in intensity_tables:
+ intensity_tables[i]['Q'] = (Features.AXIS,
+ np.divide(np.amax(intensity_tables[i].fillna(0).values,
+ axis=1),
+ np.linalg.norm(
+ intensity_tables[i].fillna(0).values,
+ 2, axis=1),
+ where=np.linalg.norm(
+ intensity_tables[i].fillna(0).values,
+ 2, axis=1) != 0)[:, i])
+ return intensity_tables
+
+ def _prob2Eng(self, p: float) -> float:
+ """Convert probability values into energy by inverse Gibbs distribution
+
+ Parameters
+ ----------
+ p : float
+ probability value
+
+ Returns
+ -------
+ float
+ energy value
+ """
+ return -1.0 * np.log(np.clip(p, 0.00001, 0.99999))
+
+ def _runMaxFlowMinCost(
+ self, data: pd.DataFrame,
+ l: int, d_th: float,
+ k_d: float, rounds: np.array,
+ dth_max: float) -> Dict:
+ """Build the graph model for the given connected component and solve the graph
+ with max flow min cost alghorithm
+
+ Parameters
+ ----------
+ data : pd.DataFrame
+ Dataframe of detected spots with probability values, with columns
+ [x, y, z, r, c, idx, p0, p1]
+ l : int
+ connected component index
+ d_th : float
+ maximum distance inside connected component between two connected spots
+ k_d : float
+ distance weight
+ rounds : np.array[int]
+ Channels and rounds present in the ImageStack from which spots were detected.
+ dth_max : float
+ maximum distance inside connected component between every pair of spots
+
+ Returns
+ -------
+ Dict[str, Any]
+ Dictionary mapping the decoded graph, Dataframe of detected spots with
+ probability values, Dataframe of connected spots
+ """
+
+ if len(data[data.conn_comp == l]):
+ if len(np.unique(data[data.conn_comp == l].r)) == len(rounds):
+ data_tmp = data[data.conn_comp == l].sort_values(['r']).copy()
+ data_tmp.reset_index(inplace=True, drop=True)
+ Dvar_tmp = data_tmp.loc[:, ['x', 'y', 'z', 'r', 'ch', 'feature_id']]
+ Dvar_tmp['E_0'] = data_tmp.p0.apply(self._prob2Eng)
+ Dvar_tmp['E_1'] = data_tmp.p1.apply(self._prob2Eng)
+ Dvar_tmp['X_idx'] = data_tmp.index.values
+
+ X_idx_tmp = len(Dvar_tmp)
+ Tvar_tmp = pd.DataFrame(
+ data={'x_idx': [],
+ 'anchestor_x_idx': [],
+ 'descendant_x_idx': [],
+ 'E_0': [],
+ 'E_1': [],
+ 'mu_d': []})
+ for h1 in rounds[:-1]:
+ h2 = h1 + 1
+
+ df1 = data_tmp[data_tmp.r == h1]
+ df2 = data_tmp[data_tmp.r == h2]
+ df1_coords = df1[['x', 'y', 'z']].values
+ df2_coords = df2[['x', 'y', 'z']].values
+
+ KDTree_h1 = KDTree(df1_coords)
+ KDTree_h2 = KDTree(df2_coords)
+ query = KDTree_h1.query_ball_tree(KDTree_h2, dth_max, p=2)
+ for i in range(len(query)):
+ if len(query[i]):
+ X_idx = [(X_idx_tmp + x) for x in range(len(query[i]))]
+ d = [np.linalg.norm(df1_coords[i] - df2_coords[x]) for x in query[i]]
+ mu_d = [1 / (1 + k_d * x) for x in d]
+
+ Tvar_tmp = Tvar_tmp.append(
+ pd.DataFrame(data={
+ 'x_idx': X_idx,
+ 'anchestor_x_idx': np.ones(len(query[i])) * df1.index[i],
+ 'descendant_x_idx': df2.index[query[i]].values,
+ 'E_0': [self._prob2Eng(1 - x) for x in mu_d],
+ 'E_1': [self._prob2Eng(x) for x in mu_d],
+ 'mu_d': mu_d}))
+ X_idx_tmp = X_idx[-1] + 1
+
+ Dvar_tmp.X_idx = Dvar_tmp.X_idx + 1
+ Tvar_tmp.anchestor_x_idx = Tvar_tmp.anchestor_x_idx + 1
+ Tvar_tmp.descendant_x_idx = Tvar_tmp.descendant_x_idx + 1
+
+ Dvar_tmp['X'] = np.arange(1, len(Dvar_tmp) + 1)
+
+ sink = Dvar_tmp.X.max() + 1
+
+ # Inizialize graph
+ G = nx.DiGraph()
+
+ E = [] # Edges
+ n = sink + 1
+
+ for h in rounds:
+ for idx, row in Dvar_tmp[(Dvar_tmp.r == h)].iterrows():
+ if h == 0:
+ E.append((0, row.X, {'capacity': 1, 'weight': 0}))
+ # Add detection edges
+ E.append((row.X, n, {
+ 'capacity': 1,
+ 'weight': np.round(row.E_1 * 1000000).astype(int)}))
+ n = n + 1
+
+ G.add_edges_from(E)
+ E = []
+ for idx, row in Tvar_tmp[(
+ Tvar_tmp.anchestor_x_idx.isin(
+ Dvar_tmp[Dvar_tmp.r == h].X_idx))].iterrows():
+ # Add transition edges
+ E.append((list(G.successors(row.anchestor_x_idx))[0], row.descendant_x_idx,
+ {'capacity': 1,
+ 'weight': np.round(row.E_1 * 1000000).astype(int)}))
+ G.add_edges_from(E)
+
+ # For each D of last cycle connect to sink
+ E = []
+ for idx, row in Dvar_tmp[(Dvar_tmp.r == rounds.max())].iterrows():
+ E.append((list(G.successors(row.X_idx))[0], sink, {'capacity': 1, 'weight': 0}))
+ G.add_edges_from(E)
+
+ # Prune graph removing leaf nodes
+ remove_nodes = []
+ for n in G.nodes:
+ n_set = nx.algorithms.descendants(G, n)
+ if sink not in n_set:
+ remove_nodes.append(n)
+ if n == 0: # source and sink are not connected
+ return {'G': None, 'Dvar': None, 'Tvar': None}
+
+ remove_nodes.remove(sink)
+ G.remove_nodes_from(remove_nodes)
+
+ MaxFlowMinCost = nx.max_flow_min_cost(G, 0, sink)
+ # Decode sequence
+ E = []
+ for n1 in MaxFlowMinCost:
+ for n2 in MaxFlowMinCost[n1]:
+ if MaxFlowMinCost[n1][n2] == 1:
+ E.append((int(n1), n2, {}))
+ G = nx.Graph()
+ G.add_edges_from(E)
+ G.remove_node(0)
+ G.remove_node(sink)
+
+ return {'G': G, 'Dvar': Dvar_tmp, 'Tvar': Tvar_tmp}
+ else:
+ return {'G': None, 'Dvar': None, 'Tvar': None}
+ else:
+ return {'G': None, 'Dvar': None, 'Tvar': None}
+
+ def _runGraphDecoder(self,
+ data: pd.DataFrame,
+ d_th: float,
+ k_d: float,
+ dth_max: float) -> list:
+ """Find connected components of detected spots across rounds and call the graph
+ decoder for each connected component instance.
+
+ Parameters
+ ----------
+ data : pd.DataFrame
+ Dataframe of detected spots with probability values, with columns
+ [x, y, z, r, c, idx, p0, p1, feature_id]
+ d_th : flaot
+ maximum distance inside connected component between two connected spots
+ k_d : float
+ distance weight
+ dth_max : float
+ maximum distance inside connected component between every pair of spots
+
+ Returns
+ -------
+ list[Dict[str,Any]]
+ List of dictionaries output of _runMaxFlowMinCost
+ """
+ print("Generate Graph Model...\n")
+ num_hyb = np.arange(0, int(np.amax(data.r)) + 1)
+ data.sort_values('r', inplace=True)
+ data = data.reset_index(drop=True)
+ # Graphical Model Data Structures
+ # Generate connected components
+ G = nx.Graph()
+ G.add_nodes_from(data.index.values)
+ for h1 in tqdm(num_hyb):
+ KDTree_h1 = KDTree(data[data.r == h1][['x', 'y', 'z']])
+ for h2 in num_hyb[h1:]:
+ if h1 != h2:
+ KDTree_h2 = KDTree(data[data.r == h2][['x', 'y', 'z']])
+ query = KDTree_h1.query_ball_tree(KDTree_h2, d_th, p=2)
+ E = []
+ offset1 = data.index[data.r == h1].min()
+ offset2 = data.index[data.r == h2].min()
+ for i, e1 in enumerate(query):
+ if e1:
+ for e2 in e1:
+ E.append((i + offset1, e2 + offset2))
+ G.add_edges_from(E)
+
+ conn_comps = [list(c) for c in nx.connected_components(G)]
+ for c in tqdm(range(len(conn_comps))):
+ data.loc[conn_comps[c], 'conn_comp'] = c
+
+ # Drop conn components with less than n_hybs elements
+ gr = data.groupby('conn_comp')
+ for i, group in gr:
+ if len(group) < len(num_hyb):
+ data = data.drop(group.index)
+ labels = np.unique(data.conn_comp)
+
+ if labels.size > 0:
+ print("Run Graph Model...\n")
+ res = []
+ for l in tqdm(np.nditer(labels), total=len(labels)):
+ res.append(self._runMaxFlowMinCost(data, int(l), d_th, k_d, num_hyb, dth_max))
+ # return maxFlowMinCost
+ return [x for x in res if x['G'] is not None]
+ else:
+ return []
+
+ def _baseCalling(self, data: list, rounds: Sequence[int], search_radius_max: int) -> np.ndarray:
+ """Extract intensity table feature indeces and channels from each connected component graph
+
+ Parameters
+ ----------
+ data : list
+ Output from _runGraphDecoder, contains decoded spots
+ rounds : Sequence[int]
+ Rounds present in the ImageStack from which spots were detected
+ search_radius_max : int
+ The maximum (euclidian) distance in pixels allowed between nodes belonging
+ to the same sequence
+
+ Returns
+ -------
+ np.ndarray
+ feature indeces arrays of _merge_spots_by_round output intensity tables ordered by round
+ """
+ idx = []
+ if data:
+ for graph in tqdm(data):
+ G = graph['G']
+ Dvar = graph['Dvar']
+ for c in nx.connected_components(G):
+ c = np.array(list(c))
+ c = c[c <= Dvar.X_idx.max()]
+ Dvar_c = Dvar[(Dvar.X_idx.isin(c))]
+ if len(Dvar_c) == len(rounds):
+ k1 = KDTree(Dvar_c[['x', 'y', 'z']].values)
+ max_d = np.amax(list(k1.sparse_distance_matrix(k1, np.inf).values()))
+ if max_d <= search_radius_max:
+ idx.append(Dvar[
+ (Dvar.X_idx.isin(c))].sort_values(['r']).feature_id.values)
+ return np.array(idx).astype(np.uint)
+
+ def _decode_spots(self,
+ intensity_tables: Dict[int, IntensityTable],
+ channels: Sequence[int],
+ rounds: Sequence[int],
+ search_radius: int,
+ search_radius_max: int,
+ k_d: float,
+ anchor_round: int
+ ) -> IntensityTable:
+ """Construct an intensity table from the results of a graph based search of detected spots
+
+ Parameters
+ ----------
+ intensity_tables : Dict[int, IntensityTable]
+ Output from _merge_spots_by_round, contains mapping of intensity tables
+ from each round to all the spots detected in them.
+ channels, rounds : Sequence[int]
+ Channels and rounds present in the ImageStack from which spots were detected.
+ search_radius : int
+ Euclidean distance in pixels over which to search for spots in subsequent rounds.
+ search_radius_max : int
+ The maximum (euclidian) distance in pixels allowed between nodes belonging
+ to the same sequence
+ k_d : float
+ distance weight
+ anchor_round : int
+ The imaging round to seed the search from.
+
+ Returns
+ -------
+ IntensityTable
+ Intensity table from the results of a graph based search of detected spots
+ """
+
+ anchor_intensity_table = intensity_tables[anchor_round]
+ data = pd.DataFrame()
+ for i in intensity_tables:
+ data = data.append(
+ pd.DataFrame({'x': intensity_tables[i]['x'].values,
+ 'y': intensity_tables[i]['y'].values,
+ 'z': intensity_tables[i]['z'].values,
+ 'ch': np.argmax(intensity_tables[i].fillna(0).values, axis=1)[:, i],
+ 'r': i,
+ 'Imax_gf': np.amax(intensity_tables[i].fillna(0).values,
+ axis=1)[:, i],
+ 'p1': intensity_tables[i]['Q'].values,
+ 'p0': 1 - intensity_tables[i]['Q'].values,
+ 'feature_id': intensity_tables[i].features.values}),
+ ignore_index=True)
+
+ res = self._runGraphDecoder(data, search_radius, k_d, search_radius_max)
+ idx = self._baseCalling(res, rounds, search_radius_max)
+
+ # Initialize IntensityTable with anchor round IntensityTable
+ intensity_table = anchor_intensity_table.drop('Q')
+
+ # fill IntensityTable
+ if len(idx):
+ for r in rounds:
+ # need numpy indexing to set values in vectorized manner
+ intensity_table.values[
+ idx[:, anchor_round], :, r] = intensity_tables[r].values[idx[:, r], :, r]
+
+ return IntensityTable(intensity_table)
+
+ def run(self,
+ primary_image: ImageStack,
+ blobs_image: Optional[ImageStack] = None,
+ blobs_axes: Optional[Tuple[Axes, ...]] = None,
+ verbose: bool = False,
+ n_processes: Optional[int] = None,
+ *args,
+ ) -> IntensityTable:
+ """Find 1-hot coded spots in data.
+
+ Parameters
+ ----------
+ primary_image : ImageStack
+ Image data containing coded spots.
+ verbose : bool
+ If True, report on progress of spot finding.
+ n_processes : Optional[int]
+ Number of processes to devote to spot finding. If None, will use the number of available
+ cpus (Default None).
+
+ Notes
+ -----
+ blobs_image is an unused parameter that is included for testing purposes. It should not
+ be passed to this method. If it is passed, the method will trigger a ValueError.
+
+ Returns
+ -------
+ IntensityTable
+ Contains detected coded spots.
+ """
+
+ if blobs_image is not None:
+ raise ValueError(
+ "blobs_image shouldn't be set for LocalGraphBlobDetector. This is likely a usage "
+ "error."
+ )
+
+ per_tile_spot_results = self._find_spots(
+ primary_image, verbose=verbose, n_processes=n_processes)
+
+ if np.all([v.empty for k, v in per_tile_spot_results.items()]):
+ channels = primary_image.xarray[Axes.CH.value].values
+ rounds = primary_image.xarray[Axes.ROUND.value].values
+ data = np.full((0, len(channels), len(rounds)), fill_value=np.nan)
+ dims = (Features.AXIS, Axes.CH.value, Axes.ROUND.value)
+ coords: Mapping[Hashable, Tuple[str, Any]] = {
+ Features.SPOT_RADIUS: (Features.AXIS, []),
+ Axes.ZPLANE.value: (Features.AXIS, []),
+ Axes.Y.value: (Features.AXIS, []),
+ Axes.X.value: (Features.AXIS, []),
+ Axes.ROUND.value: (Axes.ROUND.value, rounds),
+ Axes.CH.value: (Axes.CH.value, channels)
+ }
+ intensity_table = IntensityTable(data=data, dims=dims, coords=coords)
+
+ return intensity_table
+ else:
+ round_data: Mapping[int, List] = defaultdict(list)
+ for (r, c), df in per_tile_spot_results.items():
+ df[Axes.CH.value] = np.full(df.shape[0], c)
+ round_data[r].append(df)
+
+ # create one dataframe per round
+ round_dataframes = {
+ k: pd.concat(v, axis=0).reset_index().drop('index', axis=1)
+ for k, v in round_data.items()
+ }
+
+ intensity_tables = self._merge_spots_by_round(
+ round_dataframes,
+ channels=primary_image.xarray[Axes.CH.value].values,
+ rounds=primary_image.xarray[Axes.ROUND.value].values)
+
+ intensity_tables = self._compute_spot_qualities(
+ primary_image,
+ intensity_tables)
+
+ intensity_table = self._decode_spots(
+ intensity_tables=intensity_tables,
+ channels=primary_image.xarray[Axes.CH.value].values,
+ rounds=primary_image.xarray[Axes.ROUND.value].values,
+ search_radius=self.search_radius,
+ search_radius_max=self.search_radius_max,
+ k_d=self.k_d,
+ anchor_round=self.anchor_round)
+
+ # Drop intensities with empty rounds
+ drop = [np.any(np.all(np.isnan(intensity_table.values[x, :, :]), axis=0))
+ for x in range(intensity_table.shape[0])]
+ intensity_table = IntensityTable(
+ intensity_table[np.arange(intensity_table.shape[0])[np.invert(drop)]])
+
+ transfer_physical_coords_to_intensity_table(
+ image_stack=primary_image, intensity_table=intensity_table
+ )
+
+ return intensity_table
+
+ def image_to_spots(self, data_image: Union[np.ndarray, xr.DataArray]) -> SpotAttributes:
+ # LocalGraphBlobDetector does not follow the same contract as the remaining spot detectors.
+ # TODO: (ambrosejcarr) Rationalize the spot detectors by contract and then remove this hack.
+ raise NotImplementedError()
+
+ @staticmethod
+ @click.command("LocalGraphBlobDetector")
+ @click.option(
+ "--min-sigma", default=4, type=int, help="Minimum spot size (in standard deviation).")
+ @click.option(
+ "--max-sigma", default=6, type=int, help="Maximum spot size (in standard deviation).")
+ @click.option(
+ "--threshold", default=.01, type=float, help="Dots threshold.")
+ @click.option(
+ "--overlap", default=0.5, type=float,
+ help="Dots with overlap of greater than this fraction are combined.")
+ @click.option(
+ "--detector-method", default='blob_log', type=Choice(['blob_log', 'blob_dog']),
+ help="Name of the type of the skimage blob detection method.")
+ @click.option(
+ "--search-radius", default=3, type=int,
+ help="Euclidean distance in pixels over which to search for spots in subsequent rounds.")
+ @click.option(
+ "--search-radius-max", default=5, type=int,
+ help="""The maximum (euclidian) distance in pixels allowed between nodes
+ belonging to the same sequence.""")
+ @click.option(
+ "--kd", default=0.33, type=int,
+ help="""Cost distance weight parameter""")
+ @click.pass_context
+ def _cli(
+ ctx, min_sigma, max_sigma, threshold, overlap, show, detector_method,
+ search_radius, search_radius_max, k_d
+ ) -> None:
+ instance = LocalGraphBlobDetector(detector_method=detector_method,
+ search_radius=search_radius,
+ search_radius_max=search_radius_max,
+ k_d=k_d,
+ min_sigma=min_sigma,
+ max_sigma=max_sigma,
+ threshold=threshold,
+ overlap=overlap)
+ ctx.obj["component"]._cli_run(ctx, instance)
diff --git a/starfish/core/spots/DetectSpots/test/test_local_graph_blob_detector.py b/starfish/core/spots/DetectSpots/test/test_local_graph_blob_detector.py
new file mode 100644
index 000000000..256ff8c41
--- /dev/null
+++ b/starfish/core/spots/DetectSpots/test/test_local_graph_blob_detector.py
@@ -0,0 +1,364 @@
+import numpy as np
+from scipy.ndimage.filters import gaussian_filter
+
+from starfish import ImageStack
+from starfish.core.spots.DetectSpots.local_graph_blob_detector import LocalGraphBlobDetector
+from starfish.core.types import Axes
+
+
+def traversing_code() -> ImageStack:
+ """this code walks in a sequential direction"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # code 1
+ img[0, 0, 5, 35, 35] = 10
+ img[1, 1, 5, 32, 32] = 10
+ img[2, 0, 5, 29, 29] = 10
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def empty_data() -> ImageStack:
+ """this code walks in a sequential direction"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ return ImageStack.from_numpy(img)
+
+
+def multiple_possible_neighbors() -> ImageStack:
+ """last round has more spots"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # round 1
+ img[0, 0, 5, 20, 40] = 10
+ img[0, 0, 5, 40, 20] = 10
+
+ # round 2
+ img[1, 1, 5, 20, 40] = 10
+ img[1, 1, 5, 40, 20] = 10
+
+ # round 3
+ img[2, 0, 5, 20, 40] = 10
+ img[2, 0, 5, 35, 35] = 10
+ img[2, 0, 5, 40, 20] = 10
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def multiple_possible_neighbors_with_jitter() -> ImageStack:
+ """last round has more spots and spots have some jitter <= 10px"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # round 1
+ img[0, 0, 5, 20, 40] = 10
+ img[0, 0, 5, 40, 10] = 10
+
+ # round 2
+ img[1, 1, 5, 20, 45] = 10
+ img[1, 1, 5, 40, 30] = 10
+
+ # round 3
+ img[2, 0, 5, 20, 40] = 10
+ img[2, 0, 5, 40, 20] = 10
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def multiple_possible_neighbors_with_jitter_with_noise() -> ImageStack:
+ """last round has more spots and spots have some jitter <= 10px"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # round 1
+ img[0, 0, 5, 20, 40] = 10
+ img[0, 1, 5, 40, 20] = 10
+
+ # round 2
+ img[1, 1, 5, 20, 45] = 10
+ img[1, 1, 5, 30, 30] = 10
+
+ # round 3
+ img[2, 0, 5, 20, 40] = 10
+ img[2, 0, 5, 30, 20] = 10
+ img[2, 1, 5, 40, 30] = 1
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def channels_crosstalk() -> ImageStack:
+ """this code has spots with intensity crosstalk between channels of the same round"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # round 1
+ img[0, 0, 5, 20, 40] = 10
+ img[0, 1, 5, 20, 40] = 5
+
+ # round 2
+ img[1, 0, 4, 20, 40] = 5
+ img[1, 1, 5, 20, 40] = 10
+
+ # round 3
+ img[2, 0, 5, 20, 40] = 10
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def jitter_code() -> ImageStack:
+ """this code has some minor jitter <= 3px at the most distant point"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # code 1
+ img[0, 0, 5, 35, 35] = 10
+ img[1, 1, 5, 34, 35] = 10
+ img[2, 0, 6, 35, 33] = 10
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def two_perfect_codes() -> ImageStack:
+ """this code has no jitter"""
+ img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)
+
+ # code 1
+ img[0, 0, 5, 20, 35] = 10
+ img[1, 1, 5, 20, 35] = 10
+ img[2, 0, 5, 20, 35] = 10
+
+ # code 1
+ img[0, 0, 5, 40, 45] = 10
+ img[1, 1, 5, 40, 45] = 10
+ img[2, 0, 5, 40, 45] = 10
+
+ # blur points
+ gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)
+
+ return ImageStack.from_numpy(img)
+
+
+def local_graph_blob_detector(
+ search_radius: int,
+ search_radius_max: int,
+ detector_method='h_maxima'
+) -> LocalGraphBlobDetector:
+
+ if detector_method == 'h_maxima':
+ return LocalGraphBlobDetector(
+ detector_method=detector_method,
+ search_radius=search_radius,
+ search_radius_max=search_radius_max,
+ k_d=0.33,
+ h=0.5
+ )
+ elif detector_method == 'peak_local_max':
+ return LocalGraphBlobDetector(
+ detector_method=detector_method,
+ search_radius=search_radius,
+ search_radius_max=search_radius_max,
+ k_d=0.33
+ )
+ elif detector_method == 'blob_dog' or detector_method == 'blob_log':
+ return LocalGraphBlobDetector(
+ detector_method=detector_method,
+ search_radius=search_radius,
+ search_radius_max=search_radius_max,
+ k_d=0.33,
+ min_sigma=(0.4, 1.2, 1.2),
+ max_sigma=(0.6, 1.7, 1.7),
+ threshold=0.1,
+ overlap=0.5
+ )
+ else:
+ return LocalGraphBlobDetector(
+ detector_method=detector_method,
+ search_radius=search_radius,
+ search_radius_max=search_radius_max,
+ k_d=0.33,
+ h=0.5
+ )
+
+
+def test_local_graph_blob_detector_empty_data():
+ stack = empty_data()
+ lgbd = local_graph_blob_detector(
+ search_radius=1, search_radius_max=1, detector_method='h_maxima')
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (0, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0]))
+ assert np.all(c == np.array([0]))
+ assert np.all(r == np.array([0]))
+
+
+def test_local_graph_blob_detector_two_codes():
+ stack = two_perfect_codes()
+ # Find spots with 'h-maxima'
+ lgbd = local_graph_blob_detector(
+ search_radius=1, search_radius_max=1, detector_method='h_maxima')
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ assert np.all(intensity_table[0][Axes.X.value] == 35)
+ assert np.all(intensity_table[0][Axes.Y.value] == 20)
+ assert np.all(intensity_table[0][Axes.ZPLANE.value] == 5)
+
+ # Find spots with 'peak_local_max'
+ lgbd = local_graph_blob_detector(
+ search_radius=1, search_radius_max=1, detector_method='peak_local_max')
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ assert np.all(intensity_table[0][Axes.X.value] == 45)
+ assert np.all(intensity_table[0][Axes.Y.value] == 40)
+ assert np.all(intensity_table[0][Axes.ZPLANE.value] == 5)
+
+ # Find spots with 'blob_dog'
+ lgbd = local_graph_blob_detector(
+ search_radius=1, search_radius_max=1, detector_method='blob_dog')
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ assert np.all(intensity_table[0][Axes.X.value] == 45)
+ assert np.all(intensity_table[0][Axes.Y.value] == 40)
+ assert np.all(intensity_table[0][Axes.ZPLANE.value] == 5)
+
+ # Find spots with 'blob_log'
+ lgbd = local_graph_blob_detector(
+ search_radius=1, search_radius_max=1, detector_method='blob_log')
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ assert np.all(intensity_table[0][Axes.X.value] == 45)
+ assert np.all(intensity_table[0][Axes.Y.value] == 40)
+ assert np.all(intensity_table[0][Axes.ZPLANE.value] == 5)
+
+
+def test_local_graph_blob_detector_jitter_code():
+ stack = jitter_code()
+ lgbd = local_graph_blob_detector(search_radius=3, search_radius_max=3)
+ intensity_table = lgbd.run(stack, n_processes=1)
+ assert intensity_table.shape == (1, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0, 0, 0]))
+ assert np.all(c == np.array([0, 0, 1]))
+ assert np.all(r == np.array([0, 2, 1]))
+
+ # test again with smaller search radius
+ lgbd = local_graph_blob_detector(search_radius=1, search_radius_max=3)
+ intensity_table = lgbd.run(stack, n_processes=1)
+ assert intensity_table.shape == (0, 2, 3)
+ f, c, r = np.where(~intensity_table.isnull())
+ assert np.all(f == np.array([0]))
+ assert np.all(c == np.array([0]))
+ assert np.all(r == np.array([0]))
+
+ # test again with smaller search radius max
+ lgbd = local_graph_blob_detector(search_radius=3, search_radius_max=1)
+ intensity_table = lgbd.run(stack, n_processes=1)
+ assert intensity_table.shape == (0, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0]))
+ assert np.all(c == np.array([0]))
+ assert np.all(r == np.array([0]))
+
+
+def test_local_graph_blob_detector_traversing_code():
+ stack = traversing_code()
+ lgbd = local_graph_blob_detector(search_radius=5, search_radius_max=10)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (1, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0, 0, 0]))
+ assert np.all(c == np.array([0, 0, 1]))
+ assert np.all(r == np.array([0, 2, 1]))
+
+ lgbd = local_graph_blob_detector(search_radius=5, search_radius_max=5)
+ intensity_table = lgbd.run(stack, n_processes=1)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0]))
+ assert np.all(c == np.array([0]))
+ assert np.all(r == np.array([0]))
+
+
+def test_local_graph_blob_detector_multiple_neighbors():
+ stack = multiple_possible_neighbors()
+ lgbd = local_graph_blob_detector(search_radius=4, search_radius_max=4)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(intensity_table[Axes.ZPLANE.value] == (5, 5))
+ assert np.all(intensity_table[Axes.Y.value] == (20, 40))
+ assert np.all(intensity_table[Axes.X.value] == (40, 20))
+
+ lgbd = local_graph_blob_detector(search_radius=15, search_radius_max=20)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(intensity_table[Axes.ZPLANE.value] == (5, 5))
+ assert np.all(intensity_table[Axes.Y.value] == (20, 40))
+ assert np.all(intensity_table[Axes.X.value] == (40, 20))
+
+
+def test_local_graph_blob_detector_multiple_neighbors_with_jitter():
+ stack = multiple_possible_neighbors_with_jitter()
+ lgbd = local_graph_blob_detector(search_radius=10, search_radius_max=20)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(intensity_table[Axes.ZPLANE.value] == (5, 5))
+ assert np.all(intensity_table[Axes.Y.value] == (20, 40))
+ assert np.all(intensity_table[Axes.X.value] == (40, 10))
+
+ lgbd = local_graph_blob_detector(search_radius=15, search_radius_max=15)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (1, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(intensity_table[Axes.ZPLANE.value] == (5))
+ assert np.all(intensity_table[Axes.Y.value] == (20))
+ assert np.all(intensity_table[Axes.X.value] == (40))
+
+
+def test_local_graph_blob_detector_multiple_neighbors_with_jitter_with_noise():
+ stack = multiple_possible_neighbors_with_jitter_with_noise()
+ lgbd = local_graph_blob_detector(search_radius=10, search_radius_max=20)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (2, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0, 0, 0, 1, 1, 1]))
+ assert np.all(c == np.array([0, 0, 1, 0, 1, 1]))
+ assert np.all(r == np.array([0, 2, 1, 2, 0, 1]))
+
+
+def test_local_graph_blob_detector_channels_crosstalk():
+ stack = channels_crosstalk()
+ lgbd = local_graph_blob_detector(search_radius=3, search_radius_max=5)
+ intensity_table = lgbd.run(stack, n_processes=1)
+
+ assert intensity_table.shape == (1, 2, 3)
+ f, c, r = np.nonzero(intensity_table.values)
+ assert np.all(f == np.array([0, 0, 0, 0, 0]))
+ assert np.all(c == np.array([0, 0, 0, 1, 1]))
+ assert np.all(r == np.array([0, 1, 2, 0, 1]))