{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Simple FRAP script\n", "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ome/omero-guide-python/blob/master/notebooks/SimpleFRAP.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This script analyzes a fluorescence time-lapse image, measuring the intensity in a named Channel within a ROI. The intensity is plotted over time." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Install dependencies if required\n", "The cell below will install dependencies if you choose to run the notebook in [Google Colab](https://colab.research.google.com/notebooks/intro.ipynb#recent=true). " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Ice Python binding\n", "%pip install https://github.com/glencoesoftware/zeroc-ice-py-linux-x86_64/releases/download/20240202/zeroc_ice-3.6.5-cp310-cp310-manylinux_2_28_x86_64.whl\n", "# Package required to interact with IDR or OMERO\n", "%pip install omero-py==5.19.2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import packages" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from omero.gateway import BlitzGateway, MapAnnotationWrapper\n", "from omero.model import EllipseI\n", "from PIL import Image\n", "import numpy as np\n", "import matplotlib\n", "from matplotlib import pyplot as plt\n", "from getpass import getpass\n", "# only used in the Jupyter notebook context for displaying a plot:\n", "from IPython.display import Image as ipImage, display\n", "import ipywidgets as widgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a connection to the OMERO Server\n", "\n", "You will be asked to enter username and password when running the next cell. Please press Enter after each. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdin", "output_type": "stream", "text": [ "Username: trainer-1\n", "OMERO Password: ········\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Connected as trainer-1\n" ] } ], "source": [ "def connect(hostname, username, password):\n", " \"\"\"\n", " Connect to an OMERO server\n", " :param hostname: Host name\n", " :param username: User\n", " :param password: Password\n", " :return: Connected BlitzGateway\n", " \"\"\"\n", " conn = BlitzGateway(username, password,\n", " host=hostname, secure=True)\n", " conn.connect()\n", " conn.c.enableKeepAlive(60)\n", " return conn\n", "\n", "HOST = 'wss://workshop.openmicroscopy.org/omero-ws'\n", "conn = connect(HOST, input(\"Username: \"), getpass(\"OMERO Password: \"))\n", "print(\"Connected as {}\".format(conn.getUser().getName()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load Image" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdin", "output_type": "stream", "text": [ "Image ID: 28662\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Image U20S-RCC1.10_R3D_FRAP.dv loaded\n" ] } ], "source": [ "image_id = input(\"Image ID: \")\n", "img = conn.getObject(\"Image\", image_id)\n", "print(\"Image {} loaded\".format(img.getName()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Select the relevant channel" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "564b1660b844403abf684ed971035e4f", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Dropdown(description='Name: ', options=('528.0', '1', '2'), value='528.0')" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def dropdown_widget(values,\n", " dropdown_widget_name,\n", " displaywidget=False):\n", "\n", " alg_sel = widgets.Dropdown(\n", " options=values,\n", " value=values[0],\n", " description=dropdown_widget_name,\n", " disabled=False,\n", " )\n", " if displaywidget is True:\n", " display(alg_sel)\n", " return alg_sel\n", "\n", "labels = img.getChannelLabels()\n", "channel_name = dropdown_widget(\n", " img.getChannelLabels(),\n", " 'Name: ', True\n", ")" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Channel index: 0\n" ] } ], "source": [ "channel_idx = labels.index(channel_name.value)\n", "print(\"Channel index: {}\".format(channel_idx))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Get the ellipse ROI:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Shape ID: 2067304\n" ] } ], "source": [ "def get_ellipse_roi(conn, image):\n", " \"\"\"\n", " Get the first ellipse ROI found in the image\n", " :param conn: The BlitzGateway\n", " :param image: The Image\n", " :return: The shape ID of the first ellipse ROI found\n", " \"\"\"\n", " roi_service = conn.getRoiService()\n", " result = roi_service.findByImage(image.getId(), None)\n", " shape_id = None\n", " for roi in result.rois:\n", " for s in roi.copyShapes():\n", " if type(s) == EllipseI:\n", " shape_id = s.id.val\n", " return shape_id\n", "\n", "ellipse_id = get_ellipse_roi(conn, img)\n", "print(\"Shape ID: {}\".format(ellipse_id))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Get the mean intensities" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[287.48524234169406, 276.46646941335575, 270.09629821777344, 139.07519551327354, 152.9218312815616, 160.5943051388389, 167.5860084734465, 173.7293785496762, 178.01229025188246, 182.5849669607062, 187.2157184199283, 190.51632288882607, 194.66981717159874, 197.61024485136332, 200.80241956208883, 202.45595620807848, 204.38025655244527, 207.00919251692923, 208.20408770912573, 211.28397078263131, 213.07126978824013, 216.4378325813695, 218.38828458284078, 218.68307103608785, 220.4650041680587, 220.1416809684352, 222.28871134707802, 223.28039560819926, 222.75595524436548, 224.35019633644507, 224.09511184692383, 225.55639799017655, 227.83410905536851, 227.41890415392425, 228.06322690060264, 227.3284357974404, 227.09195739344545, 228.9166102158396, 228.779549749274, 229.96900719090513, 229.15343425148413, 230.5665205905312, 231.55242417988023, 230.12088976408305, 231.9381594406931, 233.1758010261937, 231.51929674650492, 231.6885616904811, 231.0371178074887, 228.50869911595396, 230.09624872709574, 227.5530776977539, 229.17863504510177, 230.55075585214715, 228.91431155957673, 227.15299726787367, 226.99042139555277, 226.8221617246929, 224.5750632035105, 224.84449406674034, 223.3046942259136, 224.13170402928404, 224.28872429697137, 224.19471339175576]\n" ] } ], "source": [ "def get_mean_intensities(conn, image, the_c, shape_id):\n", " \"\"\"\n", " Get the mean pixel intensities of a ROI in a time series image\n", " :param conn: The BlitzGateway\n", " :param image: The image\n", " :param the_c: The channel index\n", " :param shape_id: The ROI shape id\n", " :return: List of mean intensity values (one for each timepoint)\n", " \"\"\"\n", " roi_service = conn.getRoiService()\n", " the_z = 0\n", " size_t = image.getSizeT()\n", " meanvalues = []\n", " for t in range(size_t):\n", " stats = roi_service.getShapeStatsRestricted([shape_id],\n", " the_z, t, [the_c])\n", " meanvalues.append(stats[0].mean[0])\n", " return meanvalues\n", "\n", "values = get_mean_intensities(conn, img, channel_idx, ellipse_id)\n", "print(values)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the data" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def plot(values, plot_filename):\n", " \"\"\"\n", " Create a simple plot of the given values\n", " and saves it.\n", " :param values: The values\n", " :param plot_filename: The file name\n", " :return: Nothing\n", " \"\"\"\n", " matplotlib.use('Agg')\n", " fig = plt.figure()\n", " plt.subplot(111)\n", " plt.plot(values)\n", " fig.canvas.draw()\n", " fig.savefig(plot_filename)\n", " pil_img = Image.open(plot_filename)\n", " pil_img.show()\n", "\n", "plot(values, \"plot.png\")\n", "display(ipImage(\"plot.png\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Save the results" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Values saved.\n" ] } ], "source": [ "def save_values(conn, image, values):\n", " \"\"\"\n", " Attach the values as map annotation to the image\n", " :param conn: The BlitzGateway\n", " :param image: The image\n", " :param values: The values\n", " :return: Nothing\n", " \"\"\"\n", " namespace = \"demo.simple_frap_data\"\n", " key_value_data = [[str(t), str(value)] for t, value in enumerate(values)]\n", " map_ann = MapAnnotationWrapper(conn)\n", " map_ann.setNs(namespace)\n", " map_ann.setValue(key_value_data)\n", " map_ann.save()\n", " image.linkAnnotation(map_ann)\n", " \n", "save_values(conn, img, values)\n", "print(\"Values saved.\")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Plot saved.\n" ] } ], "source": [ "def save_plot(conn, image, plot_filename):\n", " \"\"\"\n", " Save the plot to OMERO\n", " :param conn: The BlitzGateway\n", " :param image: The image\n", " :param plot_filename: The path to the plot image\n", " :return: Nothing\n", " \"\"\"\n", " pil_img = Image.open(plot_filename)\n", " np_array = np.asarray(pil_img)\n", " red = np_array[::, ::, 0]\n", " green = np_array[::, ::, 1]\n", " blue = np_array[::, ::, 2]\n", " plane_gen = iter([red, green, blue])\n", " conn.createImageFromNumpySeq(plane_gen, plot_filename, sizeC=3,\n", " dataset=image.getParent())\n", " \n", "save_plot(conn, img, \"plot.png\")\n", "print(\"Plot saved.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Close the connection" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def disconnect(conn):\n", " \"\"\"\n", " Disconnect from an OMERO server\n", " :param conn: The BlitzGateway\n", " \"\"\"\n", " conn.close()\n", "\n", "disconnect(conn)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### License (BSD 2-Clause)\n", "Copyright (C) 2019-2024 University of Dundee. All Rights Reserved.\n", "\n", "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n", "\n", "Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n", "Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.18" } }, "nbformat": 4, "nbformat_minor": 4 }