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": "iVBORw0KGgoAAAANSUhEUgAAAPsAAAD6CAYAAABnLjEDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAMpElEQVR4nO3dX6hl5XnH8e8vM+MfSBM1hmGYmVSL0uBFqyBiSC5EEKwJ0QsJhlxMQZibFgwpJKaFlkAvmpuYXJSWIUrmokStKVWEEqyZkvbG/yZVB+NEkFFGh2A0Uaw6ztOLs0xm1tlzzp5zzj5nn3m+H9ic/b577b0ehv2bd71rr3fvVBWSznwf2egCJK0Pwy41YdilJgy71IRhl5ow7FITqwp7kuuTPJ/kUJLb16ooSWsvK/2cPckW4BfAdcDLwGPAl6vquSWe44f60oxVVSb1r2Zkvwo4VFUvVtV7wN3Ajat4PUkztJqw7wQOn9B+eeiTNIe2znoHSfYCe2e9H0lLW03YXwF2n9DeNfSdpKr2AfvAObu0kVZzGP8YcGmSi5OcBdwCPLA2ZUlaayse2avqWJK/BH4MbAHuqqpn16wySWtqxR+9rWhnHsZLMzeLj94kbSKGXWrCsEtNGHapCcMuNWHYpSYMu9SEYZeaMOxSE4ZdasKwS00YdqkJwy41YdilJgy71IRhl5ow7FIThl1qwrBLTRh2qQnDLjVh2KUmDLvUhGGXmjDsUhOGXWrCsEtNGHapCcMuNWHYpSYMu9SEYZeaMOxSE4ZdasKwS00sG/YkdyU5muSZE/ouSPJQkheGv+fPtkxJqzXNyP4D4PpR3+3Aw1V1KfDw0JY0x5YNe1X9FHh91H0jsH+4vx+4aY3rkrTGtq7wedur6shw/1Vg+6k2TLIX2LvC/UhaIysN++9UVSWpJR7fB+wDWGo7SbO10rPxryXZATD8Pbp2JUmahZWG/QFgz3B/D3D/2pQjaVZStfSRdZIfAtcAFwKvAX8H/DtwL/Ap4CXgS1U1Pok36bU8jJdmrKoyqX/ZsK8lwy7N3qnC7hV0UhOGXWrCsEtNGHapCcMuNWHYpSYMu9SEYZeaMOxSE4ZdasKwS00YdqkJwy41YdilJgy71IRhl5ow7FIThl1qwrBLTRh2qQnDLjVh2KUmDLvUhGGXmjDsUhOGXWrCsEtNGHapCcMuNWHYpSYMu9SEYZeaMOxSE4ZdamLZsCfZneRAkueSPJvktqH/giQPJXlh+Hv+7MuVtFKpqqU3SHYAO6rqySR/ADwB3AT8OfB6Vf1DktuB86vqG8u81tI7k7RqVZVJ/cuO7FV1pKqeHO7/FjgI7ARuBPYPm+1n4T8ASXPqtObsSS4CrgAeAbZX1ZHhoVeB7WtamaQ1tXXaDZN8FPgR8NWq+k3y+yOFqqpTHaIn2QvsXW2hklZn2Tk7QJJtwIPAj6vqO0Pf88A1VXVkmNf/V1X98TKv45xdmrEVz9mzMITfCRz8MOiDB4A9w/09wP2rLVLS7ExzNv5zwH8D/wscH7r/moV5+73Ap4CXgC9V1evLvJYjuzRjpxrZpzqMXyuGXZq9FR/GSzozGHapCcMuNWHYpSYMu9SEYZeaMOxSE4ZdasKwS00YdqkJwy41YdilJgy71IRhl5qY+muppFMaDxnj9qQFl+PFzscnbDOpTyvmyC41YdilJgy71IRzdp2eLRP6zh61zx21t014zvuj9jsTtnl31P5gibq0LEd2qQnDLjVh2KUmDLvUhCfotLTxcDA+GQdw4ai9e9T++ITnvDlqH56wza9G7f8btb3o5rQ4sktNGHapCcMuNeGcXUsbDwfjC2Zg8Rz96mUeBzi83OoZ4O3RCpr3Rqtnjrt65nQ4sktNGHapCcMuNeGcXUsbf/HEpEUt48/Rx3P0S6ZYPXNwwsmAbaOdxdUzq+HILjVh2KUmDLvUxLJhT3JOkkeT/CzJs0m+NfRfnOSRJIeS3JPkrNmXK2mlpjlB9y5wbVW9lWQb8D9J/gP4GnBHVd2d5J+BW4F/mmGt2gjjb4EdnyODCYtaplg9c3i0eubNCVfevD8681eunlmNZUf2WvDW0Nw23Aq4Frhv6N8P3DSTCiWtianm7Em2JHkaOAo8BPwSeKOqjg2bvAzsPMVz9yZ5PMnja1GwpJWZKuxV9UFVXQ7sAq4CPj3tDqpqX1VdWVVXrrBGSWvgtC6qqao3khwAPgOcl2TrMLrvAl6ZRYHaYOMp7qTrWBZNnUdjyKQLZsZz9MPj1TPAOydv85HjJ+9o0kgV3j6pXbx3Uvv4hDl7l1n8NGfjP5nkvOH+ucB1wEHgAHDzsNke4P5ZFSlp9aYZ2XcA+5NsYeE/h3ur6sEkzwF3J/l74CngzhnWKWmVlg17Vf0cuGJC/4sszN8lbQJeQSc14ao3LW189mq8qAwWX8cy/oaZ8eo1WHzBzDuLL6rZ8u4lJ7XPHtVyLgcXPWfbaFne+6Nle53XyTmyS00YdqkJwy414Zxdp2fShHa81mT8LbCLvmGGRYtaxhfMwOI5+oWjq3d2L1qBAx8frdR5c7SSp/PSGUd2qQnDLjVh2KUmnLNr9caT2kW/1LL86plJo874c/TxHP3qCTPw3aN9HZ5ixv32qP3eqO2cXdKmYtilJgy71IRhl5rwBJ1m4PRXz4y/YQYWL2oZXzAzPhkHcMmifZ1cy+KlM4t/0Wr8i1dnCkd2qQnDLjVh2KUmnLNrHSy/emb8LbCw+IsnFi9qmXS5y/HRNidbvHRm8Y/cjH8E50zhyC41YdilJgy71IRzdm2Q46PW4vn3+FP0SV88MTb+HH2a330d7+dMWfgy5sguNWHYpSYMu9SEYZeaSNX6XUKQ5Ey9XkEzsGXUPnvUnvBD0IsWtYwvmOnwizBVNXEtjyO71IRhl5ow7FITztm1aYxHpkkj1XiyOn7DLb90ZvNzzi41Z9ilJqYOe5ItSZ5K8uDQvjjJI0kOJbknyVmzK1PSap3OyH4bJ68z+DZwR1VdAvwauHUtC5PGjo9uxybc3h/dxo+PX+NMm68vZaqwJ9kFfB74/tAOcC1w37DJfuCmWRQoaW1MO7J/F/g6v/+P8BPAG1V1bGi/DOyc9MQke5M8nuTxVVUqaVWWDXuSLwBHq+qJleygqvZV1ZVVdeVKni9pbUzz5RWfBb6Y5AbgHOBjwPeA85JsHUb3XcArsytT0motO7JX1TeraldVXQTcAvykqr4CHABuHjbbA9w/syolrdpqPmf/BvC1JIdYmMPfuTYlSZoFL5eVzjBeLis1Z9ilJgy71IRhl5ow7FIThl1qwrBLTRh2qQnDLjVh2KUmDLvUhGGXmjDsUhOGXWrCsEtNGHapCcMuNWHYpSYMu9SEYZeaMOxSE4ZdasKwS00YdqkJwy41YdilJgy71IRhl5ow7FIThl1qwrBLTRh2qQnDLjVh2KUmDLvUhGGXmti6zvv7FfAScOFwfzPYTLXC5qp3M9UKm6PePzzVA6mq9SxkYafJ41V15brveAU2U62wuerdTLXC5qt3zMN4qQnDLjWxUWHft0H7XYnNVCtsrno3U62w+eo9yYbM2SWtPw/jpSbWNexJrk/yfJJDSW5fz31PI8ldSY4meeaEvguSPJTkheHv+RtZ44eS7E5yIMlzSZ5NctvQP6/1npPk0SQ/G+r91tB/cZJHhvfEPUnO2uhaP5RkS5Knkjw4tOe21mmsW9iTbAH+Efgz4DLgy0kuW6/9T+kHwPWjvtuBh6vqUuDhoT0PjgF/VVWXAVcDfzH8e85rve8C11bVnwKXA9cnuRr4NnBHVV0C/Bq4dQNrHLsNOHhCe55rXdZ6juxXAYeq6sWqeg+4G7hxHfe/rKr6KfD6qPtGYP9wfz9w07oWdQpVdaSqnhzu/5aFN+VO5rfeqqq3hua24VbAtcB9Q//c1JtkF/B54PtDO8xprdNaz7DvBA6f0H556Jt326vqyHD/VWD7RhYzSZKLgCuAR5jjeofD4qeBo8BDwC+BN6rq2LDJPL0nvgt8HTg+tD/B/NY6FU/QnYZa+Ohirj6+SPJR4EfAV6vqNyc+Nm/1VtUHVXU5sIuFI71Pb3BJEyX5AnC0qp7Y6FrW0npeG/8KsPuE9q6hb969lmRHVR1JsoOFUWkuJNnGQtD/par+beie23o/VFVvJDkAfAY4L8nWYcScl/fEZ4EvJrkBOAf4GPA95rPWqa3nyP4YcOlwRvMs4BbggXXc/0o9AOwZ7u8B7t/AWn5nmEPeCRysqu+c8NC81vvJJOcN988FrmPhPMMB4OZhs7mot6q+WVW7quoiFt6nP6mqrzCHtZ6Wqlq3G3AD8AsW5mp/s577nrK+HwJHgPdZmJPdysJc7WHgBeA/gQs2us6h1s+xcIj+c+Dp4XbDHNf7J8BTQ73PAH879P8R8ChwCPhX4OyNrnVU9zXAg5uh1uVuXkEnNeEJOqkJwy41YdilJgy71IRhl5ow7FIThl1qwrBLTfw/XXvGfNubz/MAAAAASUVORK5CYII=\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": "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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, 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" + ] + }, + "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]))