{ "cells": [ { "cell_type": "markdown", "id": "5fad9226-7ffa-41fc-a6d8-55dcdd1c9eb5", "metadata": {}, "source": [ "# CyCIF PYTHON PIPELINE" ] }, { "cell_type": "raw", "id": "8337a11b-813a-4abd-8a5e-45a1dcde430f", "metadata": {}, "source": [ "This sequence of Jupiter Notebooks is designed to run the CyCIF analysis after the ASHLAR registratiom step.\n", "When a '*' is on a part name (see the table of content to your left), it means the user have an input to give.\n", "The pipeline is composed of 5 Notebooks (see README file)." ] }, { "cell_type": "markdown", "id": "87b047ee-225e-415d-a0ae-17f30c0d5f35", "metadata": {}, "source": [ "# I. QC/EDA NOTEBOOK" ] }, { "cell_type": "raw", "id": "fbb817d5-aee1-447a-a8dd-786bbd3cc381", "metadata": {}, "source": [ "10/01/24\n", "Modifications by ZoƩ Gerber\n", "from an original code from Marilyne Labrie" ] }, { "cell_type": "raw", "id": "a48dc9ff-3dd1-4f86-bbb5-68bc6254b787", "metadata": {}, "source": [ "I.1. PACKAGES IMPORT\n", "I.2. DIRECTORIES\n", "I.3. FILES\n", " I.3.1. DATA\n", " I.3.2. NOT_INTENSITIES\n", "I.4. QC CHECKS\n", "I.5. COLUMNS OF INTERESTS\n", "I.6. EXPOSURE TIME\n", "I.7. COLORS WORKFLOW\n", " I.7.1. CHANNELS COLORS\n", " I.7.2. ROUNDS COLORS\n", " I.7.3. SAMPLES COLORS\n", " I.7.4. CLUSTERS COLORS\n", "I.8. SAVE" ] }, { "cell_type": "markdown", "id": "46755cfd-7896-4ca0-ba50-6792612e7650", "metadata": {}, "source": [ "## I.1. PACKAGES IMPORT" ] }, { "cell_type": "code", "execution_count": 4, "id": "d52f4de4-6db2-4590-9574-326ccf5bc97e", "metadata": {}, "outputs": [], "source": [ "import warnings\n", "import os\n", "import plotly as plt\n", "import seaborn as sb\n", "\n", "from my_modules import *" ] }, { "cell_type": "code", "execution_count": 5, "id": "da8aaae9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: panel in /opt/anaconda3/lib/python3.11/site-packages (1.3.8)\n", "Requirement already satisfied: watchfiles in /opt/anaconda3/lib/python3.11/site-packages (0.21.0)\n", "Requirement already satisfied: bokeh<3.4.0,>=3.2.0 in /opt/anaconda3/lib/python3.11/site-packages (from panel) (3.3.4)\n", "Requirement already satisfied: param<3.0,>=2.0.0 in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2.0.2)\n", "Requirement already satisfied: pyviz-comms>=2.0.0 in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2.3.0)\n", "Requirement already satisfied: xyzservices>=2021.09.1 in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2022.9.0)\n", "Requirement already satisfied: markdown in /opt/anaconda3/lib/python3.11/site-packages (from panel) (3.4.1)\n", "Requirement already satisfied: markdown-it-py in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2.2.0)\n", "Requirement already satisfied: linkify-it-py in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2.0.0)\n", "Requirement already satisfied: mdit-py-plugins in /opt/anaconda3/lib/python3.11/site-packages (from panel) (0.3.0)\n", "Requirement already satisfied: requests in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2.31.0)\n", "Requirement already satisfied: tqdm>=4.48.0 in /opt/anaconda3/lib/python3.11/site-packages (from panel) (4.65.0)\n", "Requirement already satisfied: bleach in /opt/anaconda3/lib/python3.11/site-packages (from panel) (4.1.0)\n", "Requirement already satisfied: typing-extensions in /opt/anaconda3/lib/python3.11/site-packages (from panel) (4.9.0)\n", "Requirement already satisfied: pandas>=1.2 in /opt/anaconda3/lib/python3.11/site-packages (from panel) (2.1.4)\n", "Requirement already satisfied: anyio>=3.0.0 in /opt/anaconda3/lib/python3.11/site-packages (from watchfiles) (4.2.0)\n", "Requirement already satisfied: idna>=2.8 in /opt/anaconda3/lib/python3.11/site-packages (from anyio>=3.0.0->watchfiles) (3.4)\n", "Requirement already satisfied: sniffio>=1.1 in /opt/anaconda3/lib/python3.11/site-packages (from anyio>=3.0.0->watchfiles) (1.3.0)\n", "Requirement already satisfied: Jinja2>=2.9 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (3.1.3)\n", "Requirement already satisfied: contourpy>=1 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (1.2.0)\n", "Requirement already satisfied: numpy>=1.16 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (1.26.4)\n", "Requirement already satisfied: packaging>=16.8 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (23.1)\n", "Requirement already satisfied: pillow>=7.1.0 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (10.2.0)\n", "Requirement already satisfied: PyYAML>=3.10 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (6.0.1)\n", "Requirement already satisfied: tornado>=5.1 in /opt/anaconda3/lib/python3.11/site-packages (from bokeh<3.4.0,>=3.2.0->panel) (6.3.3)\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/anaconda3/lib/python3.11/site-packages (from pandas>=1.2->panel) (2.8.2)\n", "Requirement already satisfied: pytz>=2020.1 in /opt/anaconda3/lib/python3.11/site-packages (from pandas>=1.2->panel) (2023.3.post1)\n", "Requirement already satisfied: tzdata>=2022.1 in /opt/anaconda3/lib/python3.11/site-packages (from pandas>=1.2->panel) (2023.3)\n", "Requirement already satisfied: six>=1.9.0 in /opt/anaconda3/lib/python3.11/site-packages (from bleach->panel) (1.16.0)\n", "Requirement already satisfied: webencodings in /opt/anaconda3/lib/python3.11/site-packages (from bleach->panel) (0.5.1)\n", "Requirement already satisfied: uc-micro-py in /opt/anaconda3/lib/python3.11/site-packages (from linkify-it-py->panel) (1.0.1)\n", "Requirement already satisfied: mdurl~=0.1 in /opt/anaconda3/lib/python3.11/site-packages (from markdown-it-py->panel) (0.1.0)\n", "Requirement already satisfied: charset-normalizer<4,>=2 in /opt/anaconda3/lib/python3.11/site-packages (from requests->panel) (2.0.4)\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/anaconda3/lib/python3.11/site-packages (from requests->panel) (2.0.7)\n", "Requirement already satisfied: certifi>=2017.4.17 in /opt/anaconda3/lib/python3.11/site-packages (from requests->panel) (2024.2.2)\n", "Requirement already satisfied: MarkupSafe>=2.0 in /opt/anaconda3/lib/python3.11/site-packages (from Jinja2>=2.9->bokeh<3.4.0,>=3.2.0->panel) (2.1.3)\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "pip install panel watchfiles" ] }, { "cell_type": "code", "execution_count": 6, "id": "efdf3910", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: pygments in /opt/anaconda3/lib/python3.11/site-packages (2.15.1)\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "pip install pygments" ] }, { "cell_type": "code", "execution_count": 7, "id": "1e483a15", "metadata": {}, "outputs": [], "source": [ "import plotly.express as px\n", "import panel as pn\n", "import holoviews as hv\n", "import hvplot.pandas\n", "from my_modules import apply_header_changes, apply_df_changes, compare_headers, add_metadata_location, shorten_feature_names" ] }, { "cell_type": "code", "execution_count": 8, "id": "9936cc24-34f7-41b5-b184-94a8f2237b05", "metadata": { "tags": [] }, "outputs": [], "source": [ "#Silence FutureWarnings & UserWarnings\n", "warnings.filterwarnings('ignore', category= FutureWarning)\n", "warnings.filterwarnings('ignore', category= UserWarning)" ] }, { "cell_type": "code", "execution_count": 9, "id": "73290289", "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " var force = true;\n", " var py_version = '3.3.4'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", " var reloading = true;\n", " var Bokeh = root.Bokeh;\n", "\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks;\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", " if (js_modules == null) js_modules = [];\n", " if (js_exports == null) js_exports = {};\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", "\n", " if (root._bokeh_is_loading > 0) {\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " }\n", " if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", " run_callbacks();\n", " return null;\n", " }\n", " if (!reloading) {\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " }\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", " window._bokeh_on_load = on_load\n", "\n", " function on_error() {\n", " console.error(\"failed to load \" + url);\n", " }\n", "\n", " var skip = [];\n", " if (window.requirejs) {\n", " window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n", " require([\"jspanel\"], function(jsPanel) {\n", "\twindow.jsPanel = jsPanel\n", "\ton_load()\n", " })\n", " require([\"jspanel-modal\"], function() {\n", "\ton_load()\n", " })\n", " require([\"jspanel-tooltip\"], function() {\n", "\ton_load()\n", " })\n", " require([\"jspanel-hint\"], function() {\n", "\ton_load()\n", " })\n", " require([\"jspanel-layout\"], function() {\n", "\ton_load()\n", " })\n", " require([\"jspanel-contextmenu\"], function() {\n", "\ton_load()\n", " })\n", " require([\"jspanel-dock\"], function() {\n", "\ton_load()\n", " })\n", " require([\"gridstack\"], function(GridStack) {\n", "\twindow.GridStack = GridStack\n", "\ton_load()\n", " })\n", " require([\"notyf\"], function() {\n", "\ton_load()\n", " })\n", " root._bokeh_is_loading = css_urls.length + 9;\n", " } else {\n", " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", " }\n", "\n", " var existing_stylesheets = []\n", " var links = document.getElementsByTagName('link')\n", " for (var i = 0; i < links.length; i++) {\n", " var link = links[i]\n", " if (link.href != null) {\n", "\texisting_stylesheets.push(link.href)\n", " }\n", " }\n", " for (var i = 0; i < css_urls.length; i++) {\n", " var url = css_urls[i];\n", " if (existing_stylesheets.indexOf(url) !== -1) {\n", "\ton_load()\n", "\tcontinue;\n", " }\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n", " var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n", " for (var i = 0; i < urls.length; i++) {\n", " skip.push(urls[i])\n", " }\n", " } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n", " var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n", " for (var i = 0; i < urls.length; i++) {\n", " skip.push(urls[i])\n", " }\n", " } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n", " var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n", " for (var i = 0; i < urls.length; i++) {\n", " skip.push(urls[i])\n", " }\n", " } var existing_scripts = []\n", " var scripts = document.getElementsByTagName('script')\n", " for (var i = 0; i < scripts.length; i++) {\n", " var script = scripts[i]\n", " if (script.src != null) {\n", "\texisting_scripts.push(script.src)\n", " }\n", " }\n", " for (var i = 0; i < js_urls.length; i++) {\n", " var url = js_urls[i];\n", " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", "\tif (!window.requirejs) {\n", "\t on_load();\n", "\t}\n", "\tcontinue;\n", " }\n", " var element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " for (var i = 0; i < js_modules.length; i++) {\n", " var url = js_modules[i];\n", " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", "\tif (!window.requirejs) {\n", "\t on_load();\n", "\t}\n", "\tcontinue;\n", " }\n", " var element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " element.type = \"module\";\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " for (const name in js_exports) {\n", " var url = js_exports[name];\n", " if (skip.indexOf(url) >= 0 || root[name] != null) {\n", "\tif (!window.requirejs) {\n", "\t on_load();\n", "\t}\n", "\tcontinue;\n", " }\n", " var element = document.createElement('script');\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.type = \"module\";\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " element.textContent = `\n", " import ${name} from \"${url}\"\n", " window.${name} = ${name}\n", " window._bokeh_on_load()\n", " `\n", " document.head.appendChild(element);\n", " }\n", " if (!js_urls.length && !js_modules.length) {\n", " on_load()\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " var js_urls = [];\n", " var js_modules = [];\n", " var js_exports = {};\n", " var css_urls = [];\n", " var inline_js = [ function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", "function(Bokeh) {} // ensure no trailing comma for IE\n", " ];\n", "\n", " function run_inline_js() {\n", " if ((root.Bokeh !== undefined) || (force === true)) {\n", " for (var i = 0; i < inline_js.length; i++) {\n", "\ttry {\n", " inline_js[i].call(root, root.Bokeh);\n", "\t} catch(e) {\n", "\t if (!reloading) {\n", "\t throw e;\n", "\t }\n", "\t}\n", " }\n", " // Cache old bokeh versions\n", " if (Bokeh != undefined && !reloading) {\n", "\tvar NewBokeh = root.Bokeh;\n", "\tif (Bokeh.versions === undefined) {\n", "\t Bokeh.versions = new Map();\n", "\t}\n", "\tif (NewBokeh.version !== Bokeh.version) {\n", "\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", "\t}\n", "\troot.Bokeh = Bokeh;\n", " }} else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!root._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " root._bokeh_failed_load = true;\n", " }\n", " root._bokeh_is_initializing = false\n", " }\n", "\n", " function load_or_wait() {\n", " // Implement a backoff loop that tries to ensure we do not load multiple\n", " // versions of Bokeh and its dependencies at the same time.\n", " // In recent versions we use the root._bokeh_is_initializing flag\n", " // to determine whether there is an ongoing attempt to initialize\n", " // bokeh, however for backward compatibility we also try to ensure\n", " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", " // before older versions are fully initialized.\n", " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", " root._bokeh_is_initializing = false;\n", " root._bokeh_onload_callbacks = undefined;\n", " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", " load_or_wait();\n", " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", " setTimeout(load_or_wait, 100);\n", " } else {\n", " root._bokeh_is_initializing = true\n", " root._bokeh_onload_callbacks = []\n", " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", " if (!reloading && !bokeh_loaded) {\n", "\troot.Bokeh = undefined;\n", " }\n", " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", "\trun_inline_js();\n", " });\n", " }\n", " }\n", " // Give older versions of the autoload script a head-start to ensure\n", " // they initialize before we start loading newer version.\n", " setTimeout(load_or_wait, 100)\n", "}(window));" ], "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.4'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = true;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "\n", "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", "}\n", "\n", "\n", " function JupyterCommManager() {\n", " }\n", "\n", " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", " comm_manager.register_target(comm_id, function(comm) {\n", " comm.on_msg(msg_handler);\n", " });\n", " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", " comm.onMsg = msg_handler;\n", " });\n", " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", " var messages = comm.messages[Symbol.asyncIterator]();\n", " function processIteratorResult(result) {\n", " var message = result.value;\n", " console.log(message)\n", " var content = {data: message.data, comm_id};\n", " var buffers = []\n", " for (var buffer of message.buffers || []) {\n", " buffers.push(new DataView(buffer))\n", " }\n", " var metadata = message.metadata || {};\n", " var msg = {content, buffers, metadata}\n", " msg_handler(msg);\n", " return messages.next().then(processIteratorResult);\n", " }\n", " return messages.next().then(processIteratorResult);\n", " })\n", " }\n", " }\n", "\n", " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", " if (comm_id in window.PyViz.comms) {\n", " return window.PyViz.comms[comm_id];\n", " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", " if (msg_handler) {\n", " comm.on_msg(msg_handler);\n", " }\n", " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", " comm.open();\n", " if (msg_handler) {\n", " comm.onMsg = msg_handler;\n", " }\n", " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", " comm_promise.then((comm) => {\n", " window.PyViz.comms[comm_id] = comm;\n", " if (msg_handler) {\n", " var messages = comm.messages[Symbol.asyncIterator]();\n", " function processIteratorResult(result) {\n", " var message = result.value;\n", " var content = {data: message.data};\n", " var metadata = message.metadata || {comm_id};\n", " var msg = {content, metadata}\n", " msg_handler(msg);\n", " return messages.next().then(processIteratorResult);\n", " }\n", " return messages.next().then(processIteratorResult);\n", " }\n", " }) \n", " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", " return comm_promise.then((comm) => {\n", " comm.send(data, metadata, buffers, disposeOnDone);\n", " });\n", " };\n", " var comm = {\n", " send: sendClosure\n", " };\n", " }\n", " window.PyViz.comms[comm_id] = comm;\n", " return comm;\n", " }\n", " window.PyViz.comm_manager = new JupyterCommManager();\n", " \n", "\n", "\n", "var JS_MIME_TYPE = 'application/javascript';\n", "var HTML_MIME_TYPE = 'text/html';\n", "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", "var CLASS_NAME = 'output';\n", "\n", "/**\n", " * Render data to the DOM node\n", " */\n", "function render(props, node) {\n", " var div = document.createElement(\"div\");\n", " var script = document.createElement(\"script\");\n", " node.appendChild(div);\n", " node.appendChild(script);\n", "}\n", "\n", "/**\n", " * Handle when a new output is added\n", " */\n", "function handle_add_output(event, handle) {\n", " var output_area = handle.output_area;\n", " var output = handle.output;\n", " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", " return\n", " }\n", " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", " if (id !== undefined) {\n", " var nchildren = toinsert.length;\n", " var html_node = toinsert[nchildren-1].children[0];\n", " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", " var scripts = [];\n", " var nodelist = html_node.querySelectorAll(\"script\");\n", " for (var i in nodelist) {\n", " if (nodelist.hasOwnProperty(i)) {\n", " scripts.push(nodelist[i])\n", " }\n", " }\n", "\n", " scripts.forEach( function (oldScript) {\n", " var newScript = document.createElement(\"script\");\n", " var attrs = [];\n", " var nodemap = oldScript.attributes;\n", " for (var j in nodemap) {\n", " if (nodemap.hasOwnProperty(j)) {\n", " attrs.push(nodemap[j])\n", " }\n", " }\n", " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", " oldScript.parentNode.replaceChild(newScript, oldScript);\n", " });\n", " if (JS_MIME_TYPE in output.data) {\n", " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", " }\n", " output_area._hv_plot_id = id;\n", " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", " window.PyViz.plot_index[id] = Bokeh.index[id];\n", " } else {\n", " window.PyViz.plot_index[id] = null;\n", " }\n", " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", " var bk_div = document.createElement(\"div\");\n", " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", " var script_attrs = bk_div.children[0].attributes;\n", " for (var i = 0; i < script_attrs.length; i++) {\n", " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", " }\n", " // store reference to server id on output_area\n", " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", " }\n", "}\n", "\n", "/**\n", " * Handle when an output is cleared or removed\n", " */\n", "function handle_clear_output(event, handle) {\n", " var id = handle.cell.output_area._hv_plot_id;\n", " var server_id = handle.cell.output_area._bokeh_server_id;\n", " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", " if (server_id !== null) {\n", " comm.send({event_type: 'server_delete', 'id': server_id});\n", " return;\n", " } else if (comm !== null) {\n", " comm.send({event_type: 'delete', 'id': id});\n", " }\n", " delete PyViz.plot_index[id];\n", " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", " var doc = window.Bokeh.index[id].model.document\n", " doc.clear();\n", " const i = window.Bokeh.documents.indexOf(doc);\n", " if (i > -1) {\n", " window.Bokeh.documents.splice(i, 1);\n", " }\n", " }\n", "}\n", "\n", "/**\n", " * Handle kernel restart event\n", " */\n", "function handle_kernel_cleanup(event, handle) {\n", " delete PyViz.comms[\"hv-extension-comm\"];\n", " window.PyViz.plot_index = {}\n", "}\n", "\n", "/**\n", " * Handle update_display_data messages\n", " */\n", "function handle_update_output(event, handle) {\n", " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", " handle_add_output(event, handle)\n", "}\n", "\n", "function register_renderer(events, OutputArea) {\n", " function append_mime(data, metadata, element) {\n", " // create a DOM node to render to\n", " var toinsert = this.create_output_subarea(\n", " metadata,\n", " CLASS_NAME,\n", " EXEC_MIME_TYPE\n", " );\n", " this.keyboard_manager.register_events(toinsert);\n", " // Render to node\n", " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", " render(props, toinsert[0]);\n", " element.append(toinsert);\n", " return toinsert\n", " }\n", "\n", " events.on('output_added.OutputArea', handle_add_output);\n", " events.on('output_updated.OutputArea', handle_update_output);\n", " events.on('clear_output.CodeCell', handle_clear_output);\n", " events.on('delete.Cell', handle_clear_output);\n", " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", "\n", " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", " safe: true,\n", " index: 0\n", " });\n", "}\n", "\n", "if (window.Jupyter !== undefined) {\n", " try {\n", " var events = require('base/js/events');\n", " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", " register_renderer(events, OutputArea);\n", " }\n", " } catch(err) {\n", " }\n", "}\n" ], "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ] }, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "8e44b995-9262-4ec8-9602-2f43b99d97ac" } }, "output_type": "display_data" } ], "source": [ "# Initialize Panel extension\n", "pn.extension()" ] }, { "cell_type": "markdown", "id": "b179f303-c098-4c30-b4b9-df10db6c485a", "metadata": {}, "source": [ "## I.2. *DIRECTORIES" ] }, { "cell_type": "code", "execution_count": 10, "id": "849b1dd3-c940-4c7a-8cf6-2fd5b4dc43f4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431\n" ] } ], "source": [ "# Set base directory\n", "\n", "directorio_actual = os.getcwd()\n", "print(directorio_actual)\n", "\n", "##### MAC WORKSTATION #####\n", "#base_dir = r'/Volumes/LaboLabrie/Projets/OC_TMA_Pejovic/Temp/Zoe/CyCIF_pipeline/'\n", "###########################\n", "\n", "##### WINDOWS WORKSTATION #####\n", "#base_dir = r'C:\\Users\\LaboLabrie\\gerz2701\\cyCIF-pipeline\\Set_B'\n", "###############################\n", "\n", "##### LOCAL WORKSTATION #####\n", "base_dir = r'/Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/'\n", "#############################\n", "\n", "#set_name = 'Set_A'\n", "set_name = 'test'" ] }, { "cell_type": "raw", "id": "1f68584f-c1f6-49cd-99f8-5a7cc8aae26e", "metadata": {}, "source": [ "The project is organized as :\n", "main dir \n", " code\n", " proj_data > all input csv files\n", " proj_metadata > exposure time csv file, images dir,...\n", " proj_qc_eda > csv after the QC/EDA step" ] }, { "cell_type": "code", "execution_count": 11, "id": "e8a4b389-1136-4470-9898-29fd39baf1f5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/ directory already exists !\n", "The /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_data directory already exists !\n", "The /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda directory already exists !\n", "The /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda/images directory already exists !\n", "The /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_metadata directory already exists !\n", "The /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_metadata/images directory already exists !\n" ] } ], "source": [ "project_name = set_name # Project name\n", "step_suffix = 'qc_eda' # Curent part (here part I)\n", "previous_step_suffix_long = \"\" # Previous part (here empty)\n", "\n", "# Initial input data directory\n", "input_data_dir = os.path.join(base_dir, project_name + \"_data\")\n", "\n", "# QC/EDA output directories\n", "# global output\n", "output_data_dir = os.path.join(base_dir, project_name + \"_\" + step_suffix)\n", "# images subdirectory\n", "output_images_dir = os.path.join(output_data_dir,\"images\")\n", "\n", "# Data and Metadata directories\n", "# global data\n", "metadata_dir = os.path.join(base_dir, project_name + \"_metadata\")\n", "# images subdirectory\n", "metadata_images_dir = os.path.join(metadata_dir,\"images\")\n", "\n", "# Create directories if they don't already exist\n", "for d in [base_dir, input_data_dir, output_data_dir, output_images_dir, metadata_dir, metadata_images_dir]:\n", " if not os.path.exists(d):\n", " print(\"Creation of the\" , d, \"directory...\")\n", " os.makedirs(d)\n", " else :\n", " print(\"The\", d, \"directory already exists !\")\n", "\n", "os.chdir(input_data_dir)" ] }, { "cell_type": "code", "execution_count": 12, "id": "b6e9df25-588a-41b4-a1f5-45bb81f012ff", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "base_dir : /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/\n", "input_data_dir : /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_data\n", "output_data_dir : /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda\n", "output_images_dir : /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda/images\n", "metadata_dir : /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_metadata\n", "metadata_images_dir : /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_metadata/images\n" ] } ], "source": [ "# Verify paths\n", "print('base_dir :', base_dir)\n", "print('input_data_dir :', input_data_dir)\n", "print('output_data_dir :', output_data_dir)\n", "print('output_images_dir :', output_images_dir)\n", "print('metadata_dir :', metadata_dir)\n", "print('metadata_images_dir :', metadata_images_dir)" ] }, { "cell_type": "markdown", "id": "44ebdb24-d428-4948-8d9d-485e4591212b", "metadata": {}, "source": [ "## I.3. FILES" ] }, { "cell_type": "raw", "id": "b81abd9c-2501-4b31-8c71-aa191c518b31", "metadata": {}, "source": [ "Don't forget to put your data in the projname_data directory !" ] }, { "cell_type": "code", "execution_count": 13, "id": "b2569b34-ef84-4af6-836d-befe3bdda706", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The following CSV files were detected:\n", "\n", " ['DD3S1.csv', 'DD3S2.csv', 'DD3S3.csv', 'TMA.csv'] \n", "\n", "in /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_data directory.\n" ] } ], "source": [ "# Listing all the .csv files in the metadata/data directory\n", "# Don't forget to move the csv files into the proj_data directory\n", "# if the data dir is empty it's not going to work \n", "ls_samples = [sample for sample in os.listdir(input_data_dir) if sample.endswith(\".csv\")]\n", "\n", "print(\"The following CSV files were detected:\\n\\n\",[sample for sample in ls_samples], \"\\n\\nin\", input_data_dir, \"directory.\")\n", "\n", "#print(ls_samples[0])" ] }, { "cell_type": "code", "execution_count": 14, "id": "591d76f3-8b5b-4dfc-a71a-0d3ec6eeb93e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "df :\n", " Cell Size Nuc X Nuc Y Inv ROI index Nucleus Size \\\n", "Cell Id \n", "1@1 339 1484.771729 16632.205078 0 127 \n", "\n", " Nucleus Roundness AF488 Cell Intensity Average \\\n", "Cell Id \n", "1@1 0.95504 2385.867188 \n", "\n", " AF488 Cytoplasm Intensity Average AF488 Nucleus Intensity Average \\\n", "Cell Id \n", "1@1 2356.6604 2434.62207 \n", "\n", " AF555 Cell Intensity Average ... r7c2 Nucleus Intensity Average \\\n", "Cell Id ... \n", "1@1 1358.528076 ... 290.582672 \n", "\n", " r8c2 Cell Intensity Average r8c2 Cytoplasm Intensity Average \\\n", "Cell Id \n", "1@1 341.790558 337.82547 \n", "\n", " r8c2 Nucleus Intensity Average Sting Cell Intensity Average \\\n", "Cell Id \n", "1@1 348.409454 1567.100342 \n", "\n", " Sting Cytoplasm Intensity Average Sting Nucleus Intensity Average \\\n", "Cell Id \n", "1@1 1533.22168 1623.653564 \n", "\n", " Vimentin Cell Intensity Average \\\n", "Cell Id \n", "1@1 7279.144531 \n", "\n", " Vimentin Cytoplasm Intensity Average \\\n", "Cell Id \n", "1@1 7040.108398 \n", "\n", " Vimentin Nucleus Intensity Average \n", "Cell Id \n", "1@1 7678.165527 \n", "\n", "[1 rows x 141 columns] \n", "\n", "df's columns :\n", " Index(['Cell Size', 'Nuc X', 'Nuc Y Inv', 'ROI index', 'Nucleus Size',\n", " 'Nucleus Roundness', 'AF488 Cell Intensity Average',\n", " 'AF488 Cytoplasm Intensity Average', 'AF488 Nucleus Intensity Average',\n", " 'AF555 Cell Intensity Average',\n", " ...\n", " 'r7c2 Nucleus Intensity Average', 'r8c2 Cell Intensity Average',\n", " 'r8c2 Cytoplasm Intensity Average', 'r8c2 Nucleus Intensity Average',\n", " 'Sting Cell Intensity Average', 'Sting Cytoplasm Intensity Average',\n", " 'Sting Nucleus Intensity Average', 'Vimentin Cell Intensity Average',\n", " 'Vimentin Cytoplasm Intensity Average',\n", " 'Vimentin Nucleus Intensity Average'],\n", " dtype='object', length=141) \n", "\n", "df's index :\n", " Index(['1@1'], dtype='object', name='Cell Id') \n", "\n", "df's index name :\n", " Cell Id\n" ] } ], "source": [ "# First gather information on expected headers using first file in ls_samples\n", "# Read in the first row of the file corresponding to the first sample (index = 0) in ls_samples\n", "df = pd.read_csv(os.path.join(input_data_dir, ls_samples[0]) , index_col = 0, nrows = 1)\n", "\n", "\n", "# Make sure the file was imported correctly\n", "print(\"df :\\n\", df.head(), \"\\n\")\n", "print(\"df's columns :\\n\", df.columns, \"\\n\")\n", "print(\"df's index :\\n\", df.index, \"\\n\")\n", "print(\"df's index name :\\n\", df.index.name)" ] }, { "cell_type": "code", "execution_count": 15, "id": "7caa2335-ea22-4973-b50c-7087349c2dc6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Expected the first column in input file (index_col = 0) to be 'ID'. \n", "This column will be used to set the index names (cell number for each sample). \n", "It appears that the column 'Cell Id' was actually the imported as the index column.\n", "A new index name (first column) will be given ('ID') to replace the current one 'Cell Id'\n", "\n", "['Cell_Size' 'Nuc_X' 'Nuc_Y_Inv' 'ROI_index' 'Nucleus_Size'\n", " 'Nucleus_Roundness' 'AF488_Cell_Intensity_Average'\n", " 'AF488_Cytoplasm_Intensity_Average' 'AF488_Nucleus_Intensity_Average'\n", " 'AF555_Cell_Intensity_Average' 'AF555_Cytoplasm_Intensity_Average'\n", " 'AF555_Nucleus_Intensity_Average' 'AF647_Cell_Intensity_Average'\n", " 'AF647_Cytoplasm_Intensity_Average' 'AF647_Nucleus_Intensity_Average'\n", " 'AF750_Cell_Intensity_Average' 'AF750_Cytoplasm_Intensity_Average'\n", " 'AF750_Nucleus_Intensity_Average' 'aSMA_Cell_Intensity_Average'\n", " 'aSMA_Cytoplasm_Intensity_Average' 'aSMA_Nucleus_Intensity_Average'\n", " 'AXL_Cell_Intensity_Average' 'AXL_Cytoplasm_Intensity_Average'\n", " 'AXL_Nucleus_Intensity_Average' 'B7H4_Cell_Intensity_Average'\n", " 'B7H4_Cytoplasm_Intensity_Average' 'B7H4_Nucleus_Intensity_Average'\n", " 'CA9_Cell_Intensity_Average' 'CA9_Cytoplasm_Intensity_Average'\n", " 'CA9_Nucleus_Intensity_Average' 'CD4_Cell_Intensity_Average'\n", " 'CD4_Cytoplasm_Intensity_Average' 'CD4_Nucleus_Intensity_Average'\n", " 'CD8_Cell_Intensity_Average' 'CD8_Cytoplasm_Intensity_Average'\n", " 'CD8_Nucleus_Intensity_Average' 'CD11b_Cell_Intensity_Average'\n", " 'CD11b_Cytoplasm_Intensity_Average' 'CD11b_Nucleus_Intensity_Average'\n", " 'CD11c_Cell_Intensity_Average' 'CD11c_Cytoplasm_Intensity_Average'\n", " 'CD11c_Nucleus_Intensity_Average' 'CD20_Cell_Intensity_Average'\n", " 'CD20_Cytoplasm_Intensity_Average' 'CD20_Nucleus_Intensity_Average'\n", " 'CD31_Cell_Intensity_Average' 'CD31_Cytoplasm_Intensity_Average'\n", " 'CD31_Nucleus_Intensity_Average' 'CD44_Cell_Intensity_Average'\n", " 'CD44_Cytoplasm_Intensity_Average' 'CD44_Nucleus_Intensity_Average'\n", " 'CD45_Cell_Intensity_Average' 'CD45_Cytoplasm_Intensity_Average'\n", " 'CD45_Nucleus_Intensity_Average' 'CD68_Cell_Intensity_Average'\n", " 'CD68_Cytoplasm_Intensity_Average' 'CD68_Nucleus_Intensity_Average'\n", " 'CD163_Cell_Intensity_Average' 'CD163_Cytoplasm_Intensity_Average'\n", " 'CD163_Nucleus_Intensity_Average' 'CKs_Cell_Intensity_Average'\n", " 'CKs_Cytoplasm_Intensity_Average' 'CKs_Nucleus_Intensity_Average'\n", " 'ColVI_Cell_Intensity_Average' 'ColVI_Cytoplasm_Intensity_Average'\n", " 'ColVI_Nucleus_Intensity_Average' 'DAPI0_Cell_Intensity_Average'\n", " 'DAPI0_Cytoplasm_Intensity_Average' 'DAPI0_Nucleus_Intensity_Average'\n", " 'DAPI1_Cell_Intensity_Average' 'DAPI1_Cytoplasm_Intensity_Average'\n", " 'DAPI1_Nucleus_Intensity_Average' 'DAPI2_Cell_Intensity_Average'\n", " 'DAPI2_Cytoplasm_Intensity_Average' 'DAPI2_Nucleus_Intensity_Average'\n", " 'DAPI3_Cell_Intensity_Average' 'DAPI3_Cytoplasm_Intensity_Average'\n", " 'DAPI3_Nucleus_Intensity_Average' 'DAPI4_Cell_Intensity_Average'\n", " 'DAPI4_Cytoplasm_Intensity_Average' 'DAPI4_Nucleus_Intensity_Average'\n", " 'DAPI5_Cell_Intensity_Average' 'DAPI5_Cytoplasm_Intensity_Average'\n", " 'DAPI5_Nucleus_Intensity_Average' 'DAPI6_Cell_Intensity_Average'\n", " 'DAPI6_Cytoplasm_Intensity_Average' 'DAPI6_Nucleus_Intensity_Average'\n", " 'DAPI7_Cell_Intensity_Average' 'DAPI7_Cytoplasm_Intensity_Average'\n", " 'DAPI7_Nucleus_Intensity_Average' 'DAPI8_Cell_Intensity_Average'\n", " 'DAPI8_Cytoplasm_Intensity_Average' 'DAPI8_Nucleus_Intensity_Average'\n", " 'Desmin_Cell_Intensity_Average' 'Desmin_Cytoplasm_Intensity_Average'\n", " 'Desmin_Nucleus_Intensity_Average' 'Ecad_Cell_Intensity_Average'\n", " 'Ecad_Cytoplasm_Intensity_Average' 'Ecad_Nucleus_Intensity_Average'\n", " 'Fibronectin_Cell_Intensity_Average'\n", " 'Fibronectin_Cytoplasm_Intensity_Average'\n", " 'Fibronectin_Nucleus_Intensity_Average' 'FOXP3_Cell_Intensity_Average'\n", " 'FOXP3_Cytoplasm_Intensity_Average' 'FOXP3_Nucleus_Intensity_Average'\n", " 'GATA3_Cell_Intensity_Average' 'GATA3_Cytoplasm_Intensity_Average'\n", " 'GATA3_Nucleus_Intensity_Average' 'HLA_Cell_Intensity_Average'\n", " 'HLA_Cytoplasm_Intensity_Average' 'HLA_Nucleus_Intensity_Average'\n", " 'Ki67_Cell_Intensity_Average' 'Ki67_Cytoplasm_Intensity_Average'\n", " 'Ki67_Nucleus_Intensity_Average' 'MMP9_Cell_Intensity_Average'\n", " 'MMP9_Cytoplasm_Intensity_Average' 'MMP9_Nucleus_Intensity_Average'\n", " 'PD1_Cell_Intensity_Average' 'PD1_Cytoplasm_Intensity_Average'\n", " 'PD1_Nucleus_Intensity_Average' 'PDGFR_Cell_Intensity_Average'\n", " 'PDGFR_Cytoplasm_Intensity_Average' 'PDGFR_Nucleus_Intensity_Average'\n", " 'PDL1_Cell_Intensity_Average' 'PDL1_Cytoplasm_Intensity_Average'\n", " 'PDL1_Nucleus_Intensity_Average' 'r5c2_Cell_Intensity_Average'\n", " 'r5c2_Cytoplasm_Intensity_Average' 'r5c2_Nucleus_Intensity_Average'\n", " 'r7c2_Cell_Intensity_Average' 'r7c2_Cytoplasm_Intensity_Average'\n", " 'r7c2_Nucleus_Intensity_Average' 'r8c2_Cell_Intensity_Average'\n", " 'r8c2_Cytoplasm_Intensity_Average' 'r8c2_Nucleus_Intensity_Average'\n", " 'Sting_Cell_Intensity_Average' 'Sting_Cytoplasm_Intensity_Average'\n", " 'Sting_Nucleus_Intensity_Average' 'Vimentin_Cell_Intensity_Average'\n", " 'Vimentin_Cytoplasm_Intensity_Average'\n", " 'Vimentin_Nucleus_Intensity_Average']\n", "\n", "df :\n", " Cell_Size Nuc_X Nuc_Y_Inv ROI_index Nucleus_Size \\\n", "ID \n", "1@1 339 1484.771729 16632.205078 0 127 \n", "\n", " Nucleus_Roundness AF488_Cell_Intensity_Average \\\n", "ID \n", "1@1 0.95504 2385.867188 \n", "\n", " AF488_Cytoplasm_Intensity_Average AF488_Nucleus_Intensity_Average \\\n", "ID \n", "1@1 2356.6604 2434.62207 \n", "\n", " AF555_Cell_Intensity_Average ... r7c2_Nucleus_Intensity_Average \\\n", "ID ... \n", "1@1 1358.528076 ... 290.582672 \n", "\n", " r8c2_Cell_Intensity_Average r8c2_Cytoplasm_Intensity_Average \\\n", "ID \n", "1@1 341.790558 337.82547 \n", "\n", " r8c2_Nucleus_Intensity_Average Sting_Cell_Intensity_Average \\\n", "ID \n", "1@1 348.409454 1567.100342 \n", "\n", " Sting_Cytoplasm_Intensity_Average Sting_Nucleus_Intensity_Average \\\n", "ID \n", "1@1 1533.22168 1623.653564 \n", "\n", " Vimentin_Cell_Intensity_Average Vimentin_Cytoplasm_Intensity_Average \\\n", "ID \n", "1@1 7279.144531 7040.108398 \n", "\n", " Vimentin_Nucleus_Intensity_Average \n", "ID \n", "1@1 7678.165527 \n", "\n", "[1 rows x 141 columns] \n", "\n", "df's columns :\n", " Index(['Cell_Size', 'Nuc_X', 'Nuc_Y_Inv', 'ROI_index', 'Nucleus_Size',\n", " 'Nucleus_Roundness', 'AF488_Cell_Intensity_Average',\n", " 'AF488_Cytoplasm_Intensity_Average', 'AF488_Nucleus_Intensity_Average',\n", " 'AF555_Cell_Intensity_Average',\n", " ...\n", " 'r7c2_Nucleus_Intensity_Average', 'r8c2_Cell_Intensity_Average',\n", " 'r8c2_Cytoplasm_Intensity_Average', 'r8c2_Nucleus_Intensity_Average',\n", " 'Sting_Cell_Intensity_Average', 'Sting_Cytoplasm_Intensity_Average',\n", " 'Sting_Nucleus_Intensity_Average', 'Vimentin_Cell_Intensity_Average',\n", " 'Vimentin_Cytoplasm_Intensity_Average',\n", " 'Vimentin_Nucleus_Intensity_Average'],\n", " dtype='object', length=141) \n", "\n", "df's index :\n", " Index(['1@1'], dtype='object', name='ID') \n", "\n", "df's index name :\n", " ID\n" ] } ], "source": [ "# Verify that the ID column in input file became the index\n", "# Verify that the index name column is \"ID\", if not, rename it\n", "if df.index.name != \"ID\":\n", " print(\"Expected the first column in input file (index_col = 0) to be 'ID'. \\n\"\n", " \"This column will be used to set the index names (cell number for each sample). \\n\"\n", " \"It appears that the column '\" + df.index.name + \"' was actually the imported as the index column.\")\n", " #df.index.name = 'ID'\n", " print(\"A new index name (first column) will be given ('ID') to replace the current one '\" + df.index.name + \"'\\n\")\n", "\n", "# Apply the changes to the headers as specified with apply_header_changes() function (in my_modules.py)\n", "# Apply the changes to the dataframe rows as specified with apply_df_changes() function (in my_modules.py)\n", "df = apply_header_changes(df)\n", "df = apply_df_changes(df)\n", "\n", "# Set variable to hold default header values\n", "expected_headers = df.columns.values\n", "print(expected_headers)\n", "\n", "# Make sure the file is now formated correctly\n", "print(\"\\ndf :\\n\", df.head(), \"\\n\")\n", "print(\"df's columns :\\n\", df.columns, \"\\n\")\n", "print(\"df's index :\\n\", df.index, \"\\n\")\n", "print(\"df's index name :\\n\", df.index.name)" ] }, { "cell_type": "code", "execution_count": 16, "id": "1e7448a1-b156-4d5e-9698-e94ebe9ef7b4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Used DD3S1.csv to determine the expected and corrected headers for all files.\n", "\n", "These headers are: \n", "Cell_Size, Nuc_X, Nuc_Y_Inv, ROI_index, Nucleus_Size, Nucleus_Roundness, AF488_Cell_Intensity_Average, AF488_Cytoplasm_Intensity_Average, AF488_Nucleus_Intensity_Average, AF555_Cell_Intensity_Average, AF555_Cytoplasm_Intensity_Average, AF555_Nucleus_Intensity_Average, AF647_Cell_Intensity_Average, AF647_Cytoplasm_Intensity_Average, AF647_Nucleus_Intensity_Average, AF750_Cell_Intensity_Average, AF750_Cytoplasm_Intensity_Average, AF750_Nucleus_Intensity_Average, aSMA_Cell_Intensity_Average, aSMA_Cytoplasm_Intensity_Average, aSMA_Nucleus_Intensity_Average, AXL_Cell_Intensity_Average, AXL_Cytoplasm_Intensity_Average, AXL_Nucleus_Intensity_Average, B7H4_Cell_Intensity_Average, B7H4_Cytoplasm_Intensity_Average, B7H4_Nucleus_Intensity_Average, CA9_Cell_Intensity_Average, CA9_Cytoplasm_Intensity_Average, CA9_Nucleus_Intensity_Average, CD4_Cell_Intensity_Average, CD4_Cytoplasm_Intensity_Average, CD4_Nucleus_Intensity_Average, CD8_Cell_Intensity_Average, CD8_Cytoplasm_Intensity_Average, CD8_Nucleus_Intensity_Average, CD11b_Cell_Intensity_Average, CD11b_Cytoplasm_Intensity_Average, CD11b_Nucleus_Intensity_Average, CD11c_Cell_Intensity_Average, CD11c_Cytoplasm_Intensity_Average, CD11c_Nucleus_Intensity_Average, CD20_Cell_Intensity_Average, CD20_Cytoplasm_Intensity_Average, CD20_Nucleus_Intensity_Average, CD31_Cell_Intensity_Average, CD31_Cytoplasm_Intensity_Average, CD31_Nucleus_Intensity_Average, CD44_Cell_Intensity_Average, CD44_Cytoplasm_Intensity_Average, CD44_Nucleus_Intensity_Average, CD45_Cell_Intensity_Average, CD45_Cytoplasm_Intensity_Average, CD45_Nucleus_Intensity_Average, CD68_Cell_Intensity_Average, CD68_Cytoplasm_Intensity_Average, CD68_Nucleus_Intensity_Average, CD163_Cell_Intensity_Average, CD163_Cytoplasm_Intensity_Average, CD163_Nucleus_Intensity_Average, CKs_Cell_Intensity_Average, CKs_Cytoplasm_Intensity_Average, CKs_Nucleus_Intensity_Average, ColVI_Cell_Intensity_Average, ColVI_Cytoplasm_Intensity_Average, ColVI_Nucleus_Intensity_Average, DAPI0_Cell_Intensity_Average, DAPI0_Cytoplasm_Intensity_Average, DAPI0_Nucleus_Intensity_Average, DAPI1_Cell_Intensity_Average, DAPI1_Cytoplasm_Intensity_Average, DAPI1_Nucleus_Intensity_Average, DAPI2_Cell_Intensity_Average, DAPI2_Cytoplasm_Intensity_Average, DAPI2_Nucleus_Intensity_Average, DAPI3_Cell_Intensity_Average, DAPI3_Cytoplasm_Intensity_Average, DAPI3_Nucleus_Intensity_Average, DAPI4_Cell_Intensity_Average, DAPI4_Cytoplasm_Intensity_Average, DAPI4_Nucleus_Intensity_Average, DAPI5_Cell_Intensity_Average, DAPI5_Cytoplasm_Intensity_Average, DAPI5_Nucleus_Intensity_Average, DAPI6_Cell_Intensity_Average, DAPI6_Cytoplasm_Intensity_Average, DAPI6_Nucleus_Intensity_Average, DAPI7_Cell_Intensity_Average, DAPI7_Cytoplasm_Intensity_Average, DAPI7_Nucleus_Intensity_Average, DAPI8_Cell_Intensity_Average, DAPI8_Cytoplasm_Intensity_Average, DAPI8_Nucleus_Intensity_Average, Desmin_Cell_Intensity_Average, Desmin_Cytoplasm_Intensity_Average, Desmin_Nucleus_Intensity_Average, Ecad_Cell_Intensity_Average, Ecad_Cytoplasm_Intensity_Average, Ecad_Nucleus_Intensity_Average, Fibronectin_Cell_Intensity_Average, Fibronectin_Cytoplasm_Intensity_Average, Fibronectin_Nucleus_Intensity_Average, FOXP3_Cell_Intensity_Average, FOXP3_Cytoplasm_Intensity_Average, FOXP3_Nucleus_Intensity_Average, GATA3_Cell_Intensity_Average, GATA3_Cytoplasm_Intensity_Average, GATA3_Nucleus_Intensity_Average, HLA_Cell_Intensity_Average, HLA_Cytoplasm_Intensity_Average, HLA_Nucleus_Intensity_Average, Ki67_Cell_Intensity_Average, Ki67_Cytoplasm_Intensity_Average, Ki67_Nucleus_Intensity_Average, MMP9_Cell_Intensity_Average, MMP9_Cytoplasm_Intensity_Average, MMP9_Nucleus_Intensity_Average, PD1_Cell_Intensity_Average, PD1_Cytoplasm_Intensity_Average, PD1_Nucleus_Intensity_Average, PDGFR_Cell_Intensity_Average, PDGFR_Cytoplasm_Intensity_Average, PDGFR_Nucleus_Intensity_Average, PDL1_Cell_Intensity_Average, PDL1_Cytoplasm_Intensity_Average, PDL1_Nucleus_Intensity_Average, r5c2_Cell_Intensity_Average, r5c2_Cytoplasm_Intensity_Average, r5c2_Nucleus_Intensity_Average, r7c2_Cell_Intensity_Average, r7c2_Cytoplasm_Intensity_Average, r7c2_Nucleus_Intensity_Average, r8c2_Cell_Intensity_Average, r8c2_Cytoplasm_Intensity_Average, r8c2_Nucleus_Intensity_Average, Sting_Cell_Intensity_Average, Sting_Cytoplasm_Intensity_Average, Sting_Nucleus_Intensity_Average, Vimentin_Cell_Intensity_Average, Vimentin_Cytoplasm_Intensity_Average, Vimentin_Nucleus_Intensity_Average\n" ] } ], "source": [ "print(\"Used \" + ls_samples[0] + \" to determine the expected and corrected headers for all files.\\n\")\n", "print(\"These headers are: \\n\" + \", \".join([h for h in expected_headers]))" ] }, { "cell_type": "code", "execution_count": 17, "id": "d0e4670c-acd0-4183-ad09-4b0442abb2ef", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DD3S1.csv file is processed !\n", "\n", "DD3S2.csv file is processed !\n", "\n", "DD3S3.csv file is processed !\n", "\n", "TMA.csv file is processed !\n", "\n" ] } ], "source": [ "# Import all the others files\n", "dfs = {}\n", "\n", "###############################\n", "# !! This may take a while !! #\n", "###############################\n", "for sample in ls_samples:\n", " file_path = os.path.join(input_data_dir,sample)\n", " \n", " try:\n", " # Read the CSV file\n", " df = pd.read_csv(file_path, index_col=0)\n", " # Check if the DataFrame is empty, if so, don't continue trying to process df and remove it\n", " \n", " if not df.empty:\n", " # Manipulations necessary for concatenation\n", " df = apply_header_changes(df)\n", " df = apply_df_changes(df)\n", " # Reorder the columns to match the expected headers list\n", " df = df.reindex(columns=expected_headers)\n", " print(sample, \"file is processed !\\n\")\n", " #print(df) \n", " \n", " # Compare df's header df against what is expected\n", " compare_headers(expected_headers, df.columns.values, sample)\n", " #print(df.columns.values)\n", " # Add a new colunm to identify the csv file (sample) where the df comes from\n", " df['Sample_ID'] = sample \n", " \n", " except pd.errors.EmptyDataError:\n", " print(f'\\nEmpty data error in {sample} file. Removing from analysis...')\n", " ls_samples.remove(sample) \n", " \n", " # Add df to dfs \n", " dfs[sample] = df\n", "\n", "#print(dfs)" ] }, { "cell_type": "code", "execution_count": 18, "id": "69a6106c-8106-427c-8d53-abc26c9db6e1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Cell_Size Nuc_X Nuc_Y_Inv ROI_index Nucleus_Size \\\n", "ID \n", "1@1 339 1484.771729 16632.205078 0 127 \n", "2@1 344 1426.250000 16627.384766 0 112 \n", "3@1 422 1531.110474 16622.238281 0 181 \n", "4@1 278 1518.907593 16623.007812 0 119 \n", "5@1 502 1488.051758 16616.375000 0 232 \n", "\n", " Nucleus_Roundness AF488_Cell_Intensity_Average \\\n", "ID \n", "1@1 0.955040 2385.867188 \n", "2@1 0.966643 2818.250000 \n", "3@1 0.721534 2162.047363 \n", "4@1 0.587196 2422.715820 \n", "5@1 0.655828 2265.306885 \n", "\n", " AF488_Cytoplasm_Intensity_Average AF488_Nucleus_Intensity_Average \\\n", "ID \n", "1@1 2356.660400 2434.622070 \n", "2@1 2884.366455 2681.294678 \n", "3@1 2124.817383 2211.618896 \n", "4@1 2411.867920 2437.210205 \n", "5@1 2154.796387 2393.918213 \n", "\n", " AF555_Cell_Intensity_Average ... r8c2_Cell_Intensity_Average \\\n", "ID ... \n", "1@1 1358.528076 ... 341.790558 \n", "2@1 1472.325562 ... 365.531982 \n", "3@1 1289.054443 ... 320.874420 \n", "4@1 1397.992798 ... 343.320129 \n", "5@1 1288.657349 ... 326.241028 \n", "\n", " r8c2_Cytoplasm_Intensity_Average r8c2_Nucleus_Intensity_Average \\\n", "ID \n", "1@1 337.825470 348.409454 \n", "2@1 369.340515 357.642853 \n", "3@1 315.605804 327.889496 \n", "4@1 338.679260 349.520996 \n", "5@1 314.748138 339.616394 \n", "\n", " Sting_Cell_Intensity_Average Sting_Cytoplasm_Intensity_Average \\\n", "ID \n", "1@1 1567.100342 1533.221680 \n", "2@1 1508.014526 1565.086182 \n", "3@1 1841.360229 1772.647339 \n", "4@1 1723.863281 1688.094360 \n", "5@1 1711.464111 1629.670410 \n", "\n", " Sting_Nucleus_Intensity_Average Vimentin_Cell_Intensity_Average \\\n", "ID \n", "1@1 1623.653564 7279.144531 \n", "2@1 1389.794678 6123.456543 \n", "3@1 1932.850830 4252.185059 \n", "4@1 1771.655518 6178.647461 \n", "5@1 1806.655151 5208.479980 \n", "\n", " Vimentin_Cytoplasm_Intensity_Average Vimentin_Nucleus_Intensity_Average \\\n", "ID \n", "1@1 7040.108398 7678.165527 \n", "2@1 6734.603516 4857.508789 \n", "3@1 4473.178223 3957.933594 \n", "4@1 5316.924316 7330.025391 \n", "5@1 4386.700195 6164.862305 \n", "\n", " Sample_ID \n", "ID \n", "1@1 DD3S1.csv \n", "2@1 DD3S1.csv \n", "3@1 DD3S1.csv \n", "4@1 DD3S1.csv \n", "5@1 DD3S1.csv \n", "\n", "[5 rows x 142 columns]\n" ] } ], "source": [ "# Merge dfs into one df\n", "df = pd.concat(dfs.values(), ignore_index=False , sort = False)\n", "#del dfs\n", "\n", "print(df.head())" ] }, { "cell_type": "code", "execution_count": 19, "id": "5c724db9-eb76-4af1-8fe3-8beff43d8940", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Cell_Size Nuc_X Nuc_Y_Inv ROI_index Nucleus_Size \\\n", "DD3S1_Cell_0 339 1484.771729 16632.205078 0 127 \n", "DD3S1_Cell_1 344 1426.250000 16627.384766 0 112 \n", "DD3S1_Cell_2 422 1531.110474 16622.238281 0 181 \n", "DD3S1_Cell_3 278 1518.907593 16623.007812 0 119 \n", "DD3S1_Cell_4 502 1488.051758 16616.375000 0 232 \n", "\n", " Nucleus_Roundness AF488_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 0.955040 2385.867188 \n", "DD3S1_Cell_1 0.966643 2818.250000 \n", "DD3S1_Cell_2 0.721534 2162.047363 \n", "DD3S1_Cell_3 0.587196 2422.715820 \n", "DD3S1_Cell_4 0.655828 2265.306885 \n", "\n", " AF488_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 2356.660400 \n", "DD3S1_Cell_1 2884.366455 \n", "DD3S1_Cell_2 2124.817383 \n", "DD3S1_Cell_3 2411.867920 \n", "DD3S1_Cell_4 2154.796387 \n", "\n", " AF488_Nucleus_Intensity_Average AF555_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 2434.622070 1358.528076 \n", "DD3S1_Cell_1 2681.294678 1472.325562 \n", "DD3S1_Cell_2 2211.618896 1289.054443 \n", "DD3S1_Cell_3 2437.210205 1397.992798 \n", "DD3S1_Cell_4 2393.918213 1288.657349 \n", "\n", " ... r8c2_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 ... 341.790558 \n", "DD3S1_Cell_1 ... 365.531982 \n", "DD3S1_Cell_2 ... 320.874420 \n", "DD3S1_Cell_3 ... 343.320129 \n", "DD3S1_Cell_4 ... 326.241028 \n", "\n", " r8c2_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 337.825470 \n", "DD3S1_Cell_1 369.340515 \n", "DD3S1_Cell_2 315.605804 \n", "DD3S1_Cell_3 338.679260 \n", "DD3S1_Cell_4 314.748138 \n", "\n", " r8c2_Nucleus_Intensity_Average Sting_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 348.409454 1567.100342 \n", "DD3S1_Cell_1 357.642853 1508.014526 \n", "DD3S1_Cell_2 327.889496 1841.360229 \n", "DD3S1_Cell_3 349.520996 1723.863281 \n", "DD3S1_Cell_4 339.616394 1711.464111 \n", "\n", " Sting_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 1533.221680 \n", "DD3S1_Cell_1 1565.086182 \n", "DD3S1_Cell_2 1772.647339 \n", "DD3S1_Cell_3 1688.094360 \n", "DD3S1_Cell_4 1629.670410 \n", "\n", " Sting_Nucleus_Intensity_Average \\\n", "DD3S1_Cell_0 1623.653564 \n", "DD3S1_Cell_1 1389.794678 \n", "DD3S1_Cell_2 1932.850830 \n", "DD3S1_Cell_3 1771.655518 \n", "DD3S1_Cell_4 1806.655151 \n", "\n", " Vimentin_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 7279.144531 \n", "DD3S1_Cell_1 6123.456543 \n", "DD3S1_Cell_2 4252.185059 \n", "DD3S1_Cell_3 6178.647461 \n", "DD3S1_Cell_4 5208.479980 \n", "\n", " Vimentin_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 7040.108398 \n", "DD3S1_Cell_1 6734.603516 \n", "DD3S1_Cell_2 4473.178223 \n", "DD3S1_Cell_3 5316.924316 \n", "DD3S1_Cell_4 4386.700195 \n", "\n", " Vimentin_Nucleus_Intensity_Average Sample_ID \n", "DD3S1_Cell_0 7678.165527 DD3S1.csv \n", "DD3S1_Cell_1 4857.508789 DD3S1.csv \n", "DD3S1_Cell_2 3957.933594 DD3S1.csv \n", "DD3S1_Cell_3 7330.025391 DD3S1.csv \n", "DD3S1_Cell_4 6164.862305 DD3S1.csv \n", "\n", "[5 rows x 142 columns]\n" ] } ], "source": [ "# Set index to Sample_ID + cell number : \n", "# create a new custom index for df based on the sample names and integer cell numbers, and then remove the temporary columns 'level_0' and 'index' that were introduced during the operations\n", "\n", "# Creates a copy of the DataFrame df and resets its index without creating a new column for the old index\n", "# This essentially removes the old index column and replaces it with a default integer index\n", "df = df.copy().reset_index(drop=True)\n", "\n", "#print(df)\n", "\n", "# Initializing an empty list index to store the new index labels for the DataFrame\n", "index = []\n", "\n", "for sample in ls_samples:\n", " # Extract a chunk of data from the original df where the 'Sample_ID' column matches the current sample name\n", " # This chunk is stored in the df_chunk df, which is a subset of the original data for that specific sample\n", " df_chunk = df.loc[df['Sample_ID'] == sample,:].copy()\n", " old_index = df_chunk.index\n", " # Reset the index of the df_chunk df, removing the old index and replacing it with a default integer index\n", " df_chunk = df_chunk.reset_index(drop=True)\n", " # A new index is created for the df_chunk df. It combines the sample name with 'Cell_' and the integer index values, converting them to strings\n", " # This new index will have labels like 'SampleName_Cell_0', 'SampleName_Cell_1', and so on.\n", " sample = sample.split('.')[0]\n", " df_chunk = df_chunk.set_index(f'{sample}_Cell_' + df_chunk.index.astype(str))\n", " # The index values of df_chunk are then added to the index list\n", " index = index + df_chunk.index.values.tolist()\n", "\n", "# After processing all the samples in the loop, assign the index list as the new index of the original df.\n", "df.index = index\n", "# Remove the 'level_0' and 'index' columns from df\n", "df = df.loc[:,~df.columns.isin(['level_0','index'])]\n", "\n", "print(df.head())" ] }, { "cell_type": "markdown", "id": "c95a292d-72df-4f1e-8a9d-a3de84d99057", "metadata": {}, "source": [ "### I.3.2. NOT_INTENSITIES" ] }, { "cell_type": "code", "execution_count": 20, "id": "8e4bb227-2a4f-477b-a435-e85178d1003a", "metadata": {}, "outputs": [], "source": [ "# not_intensities is the list of the columns unrelated to the markers fluorescence intensities\n", "# Can include items that aren't in a given header.\n", "#not_intensitiehttp://localhost:8888/lab/tree/Downloads/wetransfer_data-zip_2024-05-17_1431/1_qc_eda.ipynb\n", "#I.3.2.-NOT_INTENSITIESs = ['Nuc_X', 'Nuc_X_Inv', 'Nuc_Y', 'Nuc_Y_Inv', 'Nucleus_Roundness', 'Nucleus_Size', 'Cell_Size', \n", "# 'ROI_index', 'Sample_ID', 'replicate_ID', 'Cell_ID','cell_type', 'cell_subtype', 'cluster','ID', \n", "# 'Cytoplasm_Size', 'immune_checkpoint', 'Unique_ROI_index', 'Patient', 'Primary_chem(1)_vs_surg(0)']" ] }, { "cell_type": "code", "execution_count": 21, "id": "3a0b81d8-1fa0-45da-92ab-2ee59ef9d51d", "metadata": {}, "outputs": [], "source": [ "# not_intensities is the list of the columns unrelated to the markers fluorescence intensities\n", "# Can include items that aren't in a given header.\n", "not_intensities = ['Nuc_X', 'Nuc_X_Inv', 'Nuc_Y', 'Nuc_Y_Inv', 'Nucleus_Roundness', 'Nucleus_Size', 'Cell_Size', \n", " 'ROI_index', 'Sample_ID', 'replicate_ID', 'Cell_ID','cell_type', 'cell_subtype', 'cluster','ID', \n", " 'Cytoplasm_Size', 'immune_checkpoint', 'Unique_ROI_index', 'Patient', 'Primary_chem(1)_vs_surg(0)']\n" ] }, { "cell_type": "code", "execution_count": 22, "id": "26669861-4eef-43f5-82f8-532f83bd7f9b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'not_intensities.csv' already exists.\n", "Reconciling file and Jupyter notebook lists.\n" ] } ], "source": [ "path_not_intensities = os.path.join(metadata_dir,\"not_intensities.csv\")\n", "\n", "# If this file already exists, add only not_intensities items of the list not already present in file\n", "if os.path.exists(path_not_intensities):\n", " print(\"'not_intensities.csv' already exists.\")\n", " print(\"Reconciling file and Jupyter notebook lists.\")\n", " file_not_intensities = open(path_not_intensities, \"r\")\n", " file_ni = file_not_intensities.read().splitlines()\n", " # Set difference to identify items not already in file\n", " to_add = set(not_intensities) - set(file_ni)\n", " # We want not_intensities to the a complete list\n", " not_intensities = list(set(file_ni) | set(not_intensities))\n", " file_not_intensities.close()\n", " file_not_intensities = open(path_not_intensities, \"a\")\n", " for item in to_add:\n", " file_not_intensities.write(item +\"\\n\")\n", " file_not_intensities.close()\n", "\n", "else:\n", " # The file does not yet exist\n", " print(\"Could not find \" + path_not_intensities + \". Creating now.\")\n", " file_not_intensities = open(path_not_intensities, \"w\")\n", " for item in not_intensities:\n", " file_not_intensities.write(item + \"\\n\")\n", " file_not_intensities.close()" ] }, { "cell_type": "code", "execution_count": 23, "id": "175ef4cd-600f-47d6-8e16-583f4a1a0abf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['ROI_index',\n", " 'Nuc_Y',\n", " 'Nuc_Y_Inv',\n", " 'Nuc_X_Inv',\n", " 'cell_subtype',\n", " 'Cell_ID',\n", " 'Cytoplasm_Size',\n", " 'ID',\n", " 'replicate_ID',\n", " 'Nucleus_Roundness',\n", " 'Patient',\n", " 'Primary_chem(1)_vs_surg(0)',\n", " 'cell_type',\n", " 'immune_checkpoint',\n", " 'Cell_Size',\n", " 'Sample_ID',\n", " 'Nucleus_Size',\n", " 'Nuc_X',\n", " 'cluster',\n", " 'Unique_ROI_index',\n", " 'AF488_Cell_Intensity_Average',\n", " 'AF488_Cytoplasm_Intensity_Average',\n", " 'AF488_Nucleus_Intensity_Average',\n", " 'AF555_Cell_Intensity_Average',\n", " 'AF555_Cytoplasm_Intensity_Average',\n", " 'AF555_Nucleus_Intensity_Average',\n", " 'AF647_Cell_Intensity_Average',\n", " 'AF647_Cytoplasm_Intensity_Average',\n", " 'AF647_Nucleus_Intensity_Average',\n", " 'AF750_Cell_Intensity_Average',\n", " 'AF750_Cytoplasm_Intensity_Average',\n", " 'AF750_Nucleus_Intensity_Average',\n", " 'aSMA_Cell_Intensity_Average',\n", " 'aSMA_Cytoplasm_Intensity_Average',\n", " 'aSMA_Nucleus_Intensity_Average',\n", " 'AXL_Cell_Intensity_Average',\n", " 'AXL_Cytoplasm_Intensity_Average',\n", " 'AXL_Nucleus_Intensity_Average',\n", " 'B7H4_Cell_Intensity_Average',\n", " 'B7H4_Cytoplasm_Intensity_Average',\n", " 'B7H4_Nucleus_Intensity_Average',\n", " 'CA9_Cell_Intensity_Average',\n", " 'CA9_Cytoplasm_Intensity_Average',\n", " 'CA9_Nucleus_Intensity_Average',\n", " 'CD4_Cell_Intensity_Average',\n", " 'CD4_Cytoplasm_Intensity_Average',\n", " 'CD4_Nucleus_Intensity_Average',\n", " 'CD8_Cell_Intensity_Average',\n", " 'CD8_Cytoplasm_Intensity_Average',\n", " 'CD8_Nucleus_Intensity_Average',\n", " 'CD11b_Cell_Intensity_Average',\n", " 'CD11b_Cytoplasm_Intensity_Average',\n", " 'CD11b_Nucleus_Intensity_Average',\n", " 'CD11c_Cell_Intensity_Average',\n", " 'CD11c_Cytoplasm_Intensity_Average',\n", " 'CD11c_Nucleus_Intensity_Average',\n", " 'CD20_Cell_Intensity_Average',\n", " 'CD20_Cytoplasm_Intensity_Average',\n", " 'CD20_Nucleus_Intensity_Average',\n", " 'CD31_Cell_Intensity_Average',\n", " 'CD31_Cytoplasm_Intensity_Average',\n", " 'CD31_Nucleus_Intensity_Average',\n", " 'CD44_Cell_Intensity_Average',\n", " 'CD44_Cytoplasm_Intensity_Average',\n", " 'CD44_Nucleus_Intensity_Average',\n", " 'CD45_Cell_Intensity_Average',\n", " 'CD45_Cytoplasm_Intensity_Average',\n", " 'CD45_Nucleus_Intensity_Average',\n", " 'CD68_Cell_Intensity_Average',\n", " 'CD68_Cytoplasm_Intensity_Average',\n", " 'CD68_Nucleus_Intensity_Average',\n", " 'CD163_Cell_Intensity_Average',\n", " 'CD163_Cytoplasm_Intensity_Average',\n", " 'CD163_Nucleus_Intensity_Average',\n", " 'CKs_Cell_Intensity_Average',\n", " 'CKs_Cytoplasm_Intensity_Average',\n", " 'CKs_Nucleus_Intensity_Average',\n", " 'ColVI_Cell_Intensity_Average',\n", " 'ColVI_Cytoplasm_Intensity_Average',\n", " 'ColVI_Nucleus_Intensity_Average',\n", " 'DAPI0_Cell_Intensity_Average',\n", " 'DAPI0_Cytoplasm_Intensity_Average',\n", " 'DAPI0_Nucleus_Intensity_Average',\n", " 'DAPI1_Cell_Intensity_Average',\n", " 'DAPI1_Cytoplasm_Intensity_Average',\n", " 'DAPI1_Nucleus_Intensity_Average',\n", " 'DAPI2_Cell_Intensity_Average',\n", " 'DAPI2_Cytoplasm_Intensity_Average',\n", " 'DAPI2_Nucleus_Intensity_Average',\n", " 'DAPI3_Cell_Intensity_Average',\n", " 'DAPI3_Cytoplasm_Intensity_Average',\n", " 'DAPI3_Nucleus_Intensity_Average',\n", " 'DAPI4_Cell_Intensity_Average',\n", " 'DAPI4_Cytoplasm_Intensity_Average',\n", " 'DAPI4_Nucleus_Intensity_Average',\n", " 'DAPI5_Cell_Intensity_Average',\n", " 'DAPI5_Cytoplasm_Intensity_Average',\n", " 'DAPI5_Nucleus_Intensity_Average',\n", " 'DAPI6_Cell_Intensity_Average',\n", " 'DAPI6_Cytoplasm_Intensity_Average',\n", " 'DAPI6_Nucleus_Intensity_Average',\n", " 'DAPI7_Cell_Intensity_Average',\n", " 'DAPI7_Cytoplasm_Intensity_Average',\n", " 'DAPI7_Nucleus_Intensity_Average',\n", " 'DAPI8_Cell_Intensity_Average',\n", " 'DAPI8_Cytoplasm_Intensity_Average',\n", " 'DAPI8_Nucleus_Intensity_Average',\n", " 'Desmin_Cell_Intensity_Average',\n", " 'Desmin_Cytoplasm_Intensity_Average',\n", " 'Desmin_Nucleus_Intensity_Average',\n", " 'Ecad_Cell_Intensity_Average',\n", " 'Ecad_Cytoplasm_Intensity_Average',\n", " 'Ecad_Nucleus_Intensity_Average',\n", " 'Fibronectin_Cell_Intensity_Average',\n", " 'Fibronectin_Cytoplasm_Intensity_Average',\n", " 'Fibronectin_Nucleus_Intensity_Average',\n", " 'FOXP3_Cell_Intensity_Average',\n", " 'FOXP3_Cytoplasm_Intensity_Average',\n", " 'FOXP3_Nucleus_Intensity_Average',\n", " 'GATA3_Cell_Intensity_Average',\n", " 'GATA3_Cytoplasm_Intensity_Average',\n", " 'GATA3_Nucleus_Intensity_Average',\n", " 'HLA_Cell_Intensity_Average',\n", " 'HLA_Cytoplasm_Intensity_Average',\n", " 'HLA_Nucleus_Intensity_Average',\n", " 'Ki67_Cell_Intensity_Average',\n", " 'Ki67_Cytoplasm_Intensity_Average',\n", " 'Ki67_Nucleus_Intensity_Average',\n", " 'MMP9_Cell_Intensity_Average',\n", " 'MMP9_Cytoplasm_Intensity_Average',\n", " 'MMP9_Nucleus_Intensity_Average',\n", " 'PD1_Cell_Intensity_Average',\n", " 'PD1_Cytoplasm_Intensity_Average',\n", " 'PD1_Nucleus_Intensity_Average',\n", " 'PDGFR_Cell_Intensity_Average',\n", " 'PDGFR_Cytoplasm_Intensity_Average',\n", " 'PDGFR_Nucleus_Intensity_Average',\n", " 'PDL1_Cell_Intensity_Average',\n", " 'PDL1_Cytoplasm_Intensity_Average',\n", " 'PDL1_Nucleus_Intensity_Average',\n", " 'r5c2_Cell_Intensity_Average',\n", " 'r5c2_Cytoplasm_Intensity_Average',\n", " 'r5c2_Nucleus_Intensity_Average',\n", " 'r7c2_Cell_Intensity_Average',\n", " 'r7c2_Cytoplasm_Intensity_Average',\n", " 'r7c2_Nucleus_Intensity_Average',\n", " 'r8c2_Cell_Intensity_Average',\n", " 'r8c2_Cytoplasm_Intensity_Average',\n", " 'r8c2_Nucleus_Intensity_Average',\n", " 'Sting_Cell_Intensity_Average',\n", " 'Sting_Cytoplasm_Intensity_Average',\n", " 'Sting_Nucleus_Intensity_Average',\n", " 'Vimentin_Cell_Intensity_Average',\n", " 'Vimentin_Cytoplasm_Intensity_Average',\n", " 'Vimentin_Nucleus_Intensity_Average']" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Columns we want to keep: not_intensities, and any intensity column that contains 'Intensity_Average' (drop any intensity marker column that is not a mean intensity)\n", "to_keep = not_intensities + [x for x in df.columns.values[~df.columns.isin(not_intensities)] if 'Intensity_Average' in x]\n", "\n", "to_keep" ] }, { "cell_type": "code", "execution_count": 24, "id": "7ecf0c10-605d-486e-9b9e-f3cbb2a349cc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ROI_index Nuc_Y_Inv Nucleus_Roundness Cell_Size \\\n", "DD3S1_Cell_0 0 16632.205078 0.955040 339 \n", "DD3S1_Cell_1 0 16627.384766 0.966643 344 \n", "DD3S1_Cell_2 0 16622.238281 0.721534 422 \n", "DD3S1_Cell_3 0 16623.007812 0.587196 278 \n", "DD3S1_Cell_4 0 16616.375000 0.655828 502 \n", "\n", " Sample_ID Nucleus_Size Nuc_X \\\n", "DD3S1_Cell_0 DD3S1.csv 127 1484.771729 \n", "DD3S1_Cell_1 DD3S1.csv 112 1426.250000 \n", "DD3S1_Cell_2 DD3S1.csv 181 1531.110474 \n", "DD3S1_Cell_3 DD3S1.csv 119 1518.907593 \n", "DD3S1_Cell_4 DD3S1.csv 232 1488.051758 \n", "\n", " AF488_Cell_Intensity_Average AF488_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 2385.867188 2356.660400 \n", "DD3S1_Cell_1 2818.250000 2884.366455 \n", "DD3S1_Cell_2 2162.047363 2124.817383 \n", "DD3S1_Cell_3 2422.715820 2411.867920 \n", "DD3S1_Cell_4 2265.306885 2154.796387 \n", "\n", " AF488_Nucleus_Intensity_Average ... \\\n", "DD3S1_Cell_0 2434.622070 ... \n", "DD3S1_Cell_1 2681.294678 ... \n", "DD3S1_Cell_2 2211.618896 ... \n", "DD3S1_Cell_3 2437.210205 ... \n", "DD3S1_Cell_4 2393.918213 ... \n", "\n", " r7c2_Nucleus_Intensity_Average r8c2_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 290.582672 341.790558 \n", "DD3S1_Cell_1 304.133942 365.531982 \n", "DD3S1_Cell_2 271.353577 320.874420 \n", "DD3S1_Cell_3 292.134460 343.320129 \n", "DD3S1_Cell_4 284.642242 326.241028 \n", "\n", " r8c2_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 337.825470 \n", "DD3S1_Cell_1 369.340515 \n", "DD3S1_Cell_2 315.605804 \n", "DD3S1_Cell_3 338.679260 \n", "DD3S1_Cell_4 314.748138 \n", "\n", " r8c2_Nucleus_Intensity_Average Sting_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 348.409454 1567.100342 \n", "DD3S1_Cell_1 357.642853 1508.014526 \n", "DD3S1_Cell_2 327.889496 1841.360229 \n", "DD3S1_Cell_3 349.520996 1723.863281 \n", "DD3S1_Cell_4 339.616394 1711.464111 \n", "\n", " Sting_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 1533.221680 \n", "DD3S1_Cell_1 1565.086182 \n", "DD3S1_Cell_2 1772.647339 \n", "DD3S1_Cell_3 1688.094360 \n", "DD3S1_Cell_4 1629.670410 \n", "\n", " Sting_Nucleus_Intensity_Average \\\n", "DD3S1_Cell_0 1623.653564 \n", "DD3S1_Cell_1 1389.794678 \n", "DD3S1_Cell_2 1932.850830 \n", "DD3S1_Cell_3 1771.655518 \n", "DD3S1_Cell_4 1806.655151 \n", "\n", " Vimentin_Cell_Intensity_Average \\\n", "DD3S1_Cell_0 7279.144531 \n", "DD3S1_Cell_1 6123.456543 \n", "DD3S1_Cell_2 4252.185059 \n", "DD3S1_Cell_3 6178.647461 \n", "DD3S1_Cell_4 5208.479980 \n", "\n", " Vimentin_Cytoplasm_Intensity_Average \\\n", "DD3S1_Cell_0 7040.108398 \n", "DD3S1_Cell_1 6734.603516 \n", "DD3S1_Cell_2 4473.178223 \n", "DD3S1_Cell_3 5316.924316 \n", "DD3S1_Cell_4 4386.700195 \n", "\n", " Vimentin_Nucleus_Intensity_Average \n", "DD3S1_Cell_0 7678.165527 \n", "DD3S1_Cell_1 4857.508789 \n", "DD3S1_Cell_2 3957.933594 \n", "DD3S1_Cell_3 7330.025391 \n", "DD3S1_Cell_4 6164.862305 \n", "\n", "[5 rows x 142 columns]\n" ] } ], "source": [ "# However, our to_keep list contains items that might not be in our df headers!\n", "# These items are from our not_intensities list. So let's ask for only those items from to_keep that are actually found in our df\n", "# Retains only the columns from the to_keep list that are found in the df's headers (columns). \n", "# This ensures that we are only keeping the columns that exist in your df, avoiding any potential issues with non-existent column names. \n", "# The result is a df containing only the specified columns.\n", "df = df[[x for x in to_keep if x in df.columns.values]]\n", "\n", "print(df.head())" ] }, { "cell_type": "markdown", "id": "284c8270-e13e-4f93-839b-5774a7fc9f4d", "metadata": {}, "source": [ "## I.4. QC CHECKS" ] }, { "cell_type": "code", "execution_count": 25, "id": "91d9bebf-3c62-408e-923e-00447527ae3c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['DD3S1_Cell_0', 'DD3S1_Cell_1', 'DD3S1_Cell_2', 'DD3S1_Cell_3',\n", " 'DD3S1_Cell_4', 'DD3S1_Cell_5', 'DD3S1_Cell_6', 'DD3S1_Cell_7',\n", " 'DD3S1_Cell_8', 'DD3S1_Cell_9',\n", " ...\n", " 'TMA_Cell_115751', 'TMA_Cell_115752', 'TMA_Cell_115753',\n", " 'TMA_Cell_115754', 'TMA_Cell_115755', 'TMA_Cell_115756',\n", " 'TMA_Cell_115757', 'TMA_Cell_115758', 'TMA_Cell_115759',\n", " 'TMA_Cell_115760'],\n", " dtype='object', length=433976)" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Let's take a look at a few features to make sure our dataframe is as expected\n", "df.index" ] }, { "cell_type": "code", "execution_count": 26, "id": "fe138d0d-7b02-48ac-af9e-caf85c4d3b73", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(433976, 142)" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.shape" ] }, { "cell_type": "code", "execution_count": 27, "id": "e1f30957-ab09-416b-8ed5-41b99a5c0b51", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Check for NaN entries (should not be any unless columns do not align)\n", "# False means no NaN entries \n", "# True means NaN entries \n", "df.isnull().any().any()" ] }, { "cell_type": "code", "execution_count": 28, "id": "86e29b98-4758-4014-b976-db155fa9205f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "All expected filenames are present in big df Sample_ID column.\n", "DD3S1_Cell_0 DD3S1.csv\n", "DD3S1_Cell_1 DD3S1.csv\n", "DD3S1_Cell_2 DD3S1.csv\n", "DD3S1_Cell_3 DD3S1.csv\n", "DD3S1_Cell_4 DD3S1.csv\n", " ... \n", "TMA_Cell_115756 TMA.csv\n", "TMA_Cell_115757 TMA.csv\n", "TMA_Cell_115758 TMA.csv\n", "TMA_Cell_115759 TMA.csv\n", "TMA_Cell_115760 TMA.csv\n", "Name: Sample_ID, Length: 433976, dtype: object\n" ] } ], "source": [ "# Check that all expected files were imported into final dataframe\n", "if sorted(df.Sample_ID.unique()) == sorted(ls_samples):\n", " print(\"All expected filenames are present in big df Sample_ID column.\")\n", "else:\n", " compare_headers(['no samples'], df.Sample_ID.unique(), \"big df Sample_ID column\")\n", "\n", "print(df.Sample_ID)" ] }, { "cell_type": "code", "execution_count": 29, "id": "66e0487d-8a29-400d-bde6-afde02985fdb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "df.shape before removing 0 mean values: (433976, 142)\n", "No zero intensity values found in the DataFrame.\n" ] } ], "source": [ "# Delete rows that have 0 value mean intensities for intensity columns\n", "print(\"df.shape before removing 0 mean values: \", df.shape)\n", "\n", "# We use the apply method on df to calculate the mean intensity for each row. It's done this by applying a lambda function to each row. \n", "# The lambda function excludes the columns listed in the not_intensities list (which are not to be considered for mean intensity calculations) \n", "# and calculates the mean of the remaining values in each row.\n", "###############################\n", "# !! This may take a while !! #\n", "###############################\n", "# Calculate mean intensity excluding 'not_intensities' columns\n", "mean_intensity = df.loc[:, ~df.columns.isin(not_intensities)].mean(axis=1)\n", "\n", "# Check if there are any 0 mean intensity values\n", "if (mean_intensity == 0).any():\n", " df = df.loc[mean_intensity > 0, :]\n", " print(\"df.shape after removing 0 mean values: \", df.shape)\n", "else:\n", " print(\"No zero intensity values found in the DataFrame.\")" ] }, { "cell_type": "code", "execution_count": 30, "id": "93ff0fac-33ac-4120-b1cf-f3d413489b58", "metadata": {}, "outputs": [], "source": [ "# Get quantiles (5th, 50th, 95th)\n", "# List of nucleus size percentiles to extract \n", "qs = [0.05,0.50,0.95] " ] }, { "cell_type": "code", "execution_count": 31, "id": "86b0158b-6cb1-4ff8-815b-26aeed908b4b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.05 42.0\n", "0.50 88.0\n", "0.95 217.0\n", "Name: Nucleus_Size, dtype: float64" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"Nucleus_Size\"].quantile(q=qs)" ] }, { "cell_type": "code", "execution_count": 32, "id": "d7d6bf19-f83c-47b6-8e3a-a32d78e64a5c", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA20AAAIhCAYAAADdH1JpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAACbyklEQVR4nOzdeXhM1/8H8PdkkpnsQ8giliSIJWKnJEqiEbEERS2NxlKlrSpBWkWLKGIN/VZbWiqKil0RSxTVqi3Voqi1dolYYiJ7MnN+f8wvl8meSDoT3q/nmSd37j333s+9c2YynznnnisTQggQERERERGRUTIxdABERERERERUMCZtRERERERERoxJGxERERERkRFj0kZERERERGTEmLQREREREREZMSZtRERERERERoxJGxERERERkRFj0kZERERERGTEmLQREREREREZMSZtRiwyMhIymUx6mJubw8nJCR07dkR4eDgSEhLyrDN9+nTIZLIS7Sc1NRXTp0/HL7/8UqL18tuXq6srAgMDS7Sdovz4449YvHhxvstkMhmmT59epvsra/v370erVq1gZWUFmUyGbdu25Vvu+vXr0msdFRWVZ3nO+X7w4EG5xVoRzmeO48ePo3fv3qhVqxaUSiUcHR3h5eWFCRMm6JXz9fWFr6+vYYIsAzmfA9evXzd0KEahItXR4nJ1dcXQoUOl53fv3sX06dNx6tSpPGWHDh0Ka2vr59pXWX9GF+SXX36BTCYr8f+Wslba/3HPyvl8joyMLLRczjFv2rSp1PsyJoXVxYJkZWUhLCwMrq6uUCqVaNCgAb788stir5+cnIyQkBA4OzvD3NwczZo1y/d/4tChQ/W+I+U8GjRoUOx9/RdK8j4o7rEXZO/evWjXrh0sLCygUqnQo0cPnDt3Lk85X1/ffM9dly5dSnJoRu38+fOYPn16vv87hw4dCldXV715uT+HjZGpoQOgoq1cuRINGjRAVlYWEhIScPjwYcydOxcLFizA+vXr0alTJ6nsO++8U+I3XWpqKsLCwgCgRF9uS7Ov0vjxxx9x9uxZhISE5Fl29OhR1KhRo9xjKC0hBPr374969eph+/btsLKyQv369Ytcb8qUKejbty/MzMz+gygrnujoaPTs2RO+vr6YN28eqlWrhri4OPzxxx+IiorCwoULpbJff/21ASMlKtrWrVtha2srPb97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IiIiIiPGpI2IiIiIiMiIMWkjIiIiIioCx+6j0iqLusOkjYiIiIioADn3Knv2RtNEJZFTd569711JcSASIiIiIqICyOVyVKpUCQkJCQAAS0tLyGQyA0dFFYEQAqmpqUhISEClSpX07iNdUkzaCACgNTXD6YkzpGmiF42Z3AzzOs2TpomIiIrLyckJAKTEjagkKlWqJNWh0uLNtf9jRntz7XLAm2sTERHRi0Sj0SArK8vQYVAFYmZmVmgLG2+uTURERERUhuRy+XN1cSMqLSZtpKPRoPK50wCAxEZNAX4g0QtGo9Xgz7g/AQAtqrWA3IR1nIiIiCoGJm0EAJBnpKNTn9cAAFvO3IHG0srAERGVrfTsdLyy/BUAQPKkZFgpWMeJiIioYuCQ/0REREREREaMSRsREREREZERY9JGRERERERkxJi0ERERERERGTEmbUREREREREaMSRsREREREZER45D/BADQmprh3IcTpWmiF42Z3AzTfKZJ00REREQVhUwIIQwdxMskKSkJKpUKarUatra2hg4HG6+qy23b/eqoym3bREREREQVXXFzA3aPJCIiIiIiMmLsHkk6Wi1sr1wEACTVrQ+YMJ+nF4tWaPHP/X8AAA3tG8JExjpOREREFQOTNgIAyNPTENDNCwCw5cwdaCytDBwRUdlKy0qD5zeeAIDkScmwUrCOExERUcXAn5qJiIiIiIiMGJM2IiIiIiIiI8akjYiIiIiIyIgxaSMiIiIiIjJiTNqIiIiIiIiMGEePpHJTnjfuBnjzbiIiIiJ6OTBpIwCA1tQMF9/5UJometGYyc0Q6hUqTRMRERFVFDIhhDB0EC+TpKQkqFQqqNVq2NraGjqccm8NK09saSMiIiKiiqy4uQGvaSMiIiIiIjJi7B5JOlotLO/eAgCkOtcETJjP04tFK7S4qb4JAKilqgUTGes4ERERVQxM2ggAIE9PQ3ffpgCALWfuQGNpZeCIiMpWWlYa3L5wAwAkT0qGlYJ1nIiIiCoG/tRMRERERERkxJi0ERERERERGTEmbUREREREREaMSRsREREREZERY9JGRERERERkxJi0ERERERERGTEO+U8AACE3xZVB70jTRC8aUxNTjGo1SpomIiIiqij4zYUAAFqlEn+FLTB0GETlRmmqxFfdvzJ0GEREREQlxu6RRERERERERowtbaQjBBSPHgIAMu2qADKZgQMiKltCCDxIfQAAqGpZFTLWcSIiIqogmLQRAECelopebeoCALacuQONpZWBIyIqW6lZqXBY4AAASJ6UDCsF6zgRERFVDOweSUREREREZMSYtBERERERERkxJm1ERERERERGjEkbERERERGREWPSRkREREREZMSYtBERERERERkxDvlPAAAhN8X1Pm9K00QvGlMTUwxpOkSaJiIiIqoo+M2FAABapRKx874xdBhE5UZpqkTk65GGDoOIiIioxNg9koiIiIiIyIixpY10hIA8LRUAoLGwBGQyAwdEVLaEEEjN0tVxSzNLyFjHiYiIqIJgSxsBAORpqejTpDr6NKkuJW9EL5LUrFRYh1vDOtxaSt6IiIiIKgImbUREREREREaMSRsREREREZERY9JGRERERERkxJi0ERERERERGTEmbUREREREREaMSRsREREREZER433aCAAg5HLc6tJLmiZ60chN5HjD4w1pmoiIiKiiYNJGAACt0hzHlqwydBhE5cbc1Bwb+200dBhEREREJcbukUREREREREaMSRsREREREZERY9JGAAB5agr61a2EfnUrQZ6aYuhwiMpcSmYKZGEyyMJkSMlkHSciIqKKg0kbERERERGREWPSRkREREREZMSYtBERERERERkxJm1ERERERERGjEkbERERERGREWPSRkREREREZMSMOmnLzs7Gp59+Cjc3N1hYWKB27dqYMWMGtFqtVEYIgenTp8PZ2RkWFhbw9fXFuXPn9LaTkZGBDz/8EFWrVoWVlRV69uyJ27dv65VJTExEcHAwVCoVVCoVgoOD8fjxY70yN2/eRI8ePWBlZYWqVatizJgxyMzMLLfj/y8JuRxxvp0R59sZQi43dDhEZU5uIkc3927o5t4NchPWcSIiIqo4TA0dQGHmzp2LpUuXYtWqVWjUqBH++OMPDBs2DCqVCmPHjgUAzJs3DxEREYiMjES9evUwc+ZM+Pv74+LFi7CxsQEAhISEYMeOHYiKikKVKlUwYcIEBAYG4uTJk5D/f4ISFBSE27dvY8+ePQCAkSNHIjg4GDt27AAAaDQadO/eHfb29jh8+DAePnyIIUOGQAiBL7/80gBnp2xpleY4vHyDocMgKjfmpuaIDoo2dBhEREREJSYTQghDB1GQwMBAODo6YsWKFdK8vn37wtLSEqtXr4YQAs7OzggJCcHEiRMB6FrVHB0dMXfuXLz77rtQq9Wwt7fH6tWrMWDAAADA3bt3UbNmTezatQsBAQH4559/4OHhgWPHjqFNmzYAgGPHjsHLywsXLlxA/fr1sXv3bgQGBuLWrVtwdnYGAERFRWHo0KFISEiAra1tsY4pKSkJKpUKarW62OuUp41X1YYOodT61VEZOgQiIiIiolIrbm5g1N0jX331Vezfvx+XLl0CAJw+fRqHDx9Gt27dAADXrl1DfHw8OnfuLK2jVCrh4+ODI0eOAABOnjyJrKwsvTLOzs7w9PSUyhw9ehQqlUpK2ACgbdu2UKlUemU8PT2lhA0AAgICkJGRgZMnTxZ4DBkZGUhKStJ7EBERERERFZdRd4+cOHEi1Go1GjRoALlcDo1Gg1mzZuHNN98EAMTHxwMAHB0d9dZzdHTEjRs3pDIKhQKVK1fOUyZn/fj4eDg4OOTZv4ODg16Z3PupXLkyFAqFVCY/4eHhCAsLK8lhG4Q8NQU927gDALYfvwyNpZWBIyIqWymZKXBYoHufJ4QmwErBOk5EREQVg1G3tK1fvx5r1qzBjz/+iD///BOrVq3CggULsGrVKr1yMplM77kQIs+83HKXya98acrkNmnSJKjVaulx69atQuMyJNO0VJimpRo6DKJyk5qVitQs1nEiIiKqWIy6pe2jjz7CJ598goEDBwIAGjdujBs3biA8PBxDhgyBk5MTAF0rWLVq1aT1EhISpFYxJycnZGZmIjExUa+1LSEhAd7e3lKZe/fu5dn//fv39bZz/PhxveWJiYnIysrK0wL3LKVSCaVSWZrDJyIiIiIiMu6WttTUVJiY6Icol8ulIf/d3Nzg5OSEffv2ScszMzNx6NAhKSFr2bIlzMzM9MrExcXh7NmzUhkvLy+o1WqcOHFCKnP8+HGo1Wq9MmfPnkVcXJxUJiYmBkqlEi1btizjIyciIiIiItIx6pa2Hj16YNasWahVqxYaNWqEv/76CxEREXj77bcB6LorhoSEYPbs2XB3d4e7uztmz54NS0tLBAUFAQBUKhWGDx+OCRMmoEqVKrCzs0NoaCgaN26MTp06AQAaNmyILl26YMSIEVi2bBkA3ZD/gYGBqF+/PgCgc+fO8PDwQHBwMObPn49Hjx4hNDQUI0aMMIpRIImIiIiI6MVk1Enbl19+ic8++wyjRo1CQkICnJ2d8e6772Lq1KlSmY8//hhpaWkYNWoUEhMT0aZNG8TExEj3aAOARYsWwdTUFP3790daWhr8/PwQGRkp3aMNANauXYsxY8ZIo0z27NkTS5YskZbL5XJER0dj1KhRaNeuHSwsLBAUFIQFCxb8B2eCiIiIiIheVkZ9n7YXkbHep02emoI+TaoDALacuVMhRo/kfdqoJFIyU2Adbg0ASJ6UzNEjiYiIyOCKmxsYdUsb/XeEiQkSXmknTRO9aExkJvBx8ZGmiYiIiCoKJm0EANCaW+DQj9GGDoOo3FiYWeCXob8YOgwiIiKiEuPPzUREREREREaMSRsREREREZERY9JGAHQDkfRsXQc9W9eBPDXF0OEQlbmUzBTYz7eH/Xx7pGSyjhMREVHFwWvaSKJMfGjoEIjK1YPUB4YOgYiIiKjE2NJGRERERERkxJi0ERERERERGTEmbUREREREREaMSRsREREREZERY9JGRERERERkxDh6JAEAhIkJHjVuLk0TvWhMZCZo5dxKmiYiIiKqKJi0EQBAa26B/VsPGjoMonJjYWaB2BGxhg6DiIiIqMT4czMREREREZERY9JGRERERERkxJi0EQBAnpaKbj6N0c2nMeRpqYYOh6jMpWalwnWxK1wXuyI1i3WciIiIKg5e00Y6QsDqzi1pmuhFI4TADfUNaZqIiIioomBLGxERERERkRFj0kZERERERGTEmLQREREREREZMV7TRhXWxqvqctt2vzqqcts2EREREVFJsKWNiIiIiIjIiLGljXRkMqjrNpCmiV40MpkMHvYe0jQRERFRRcGkjQAAGgtLxOw5ZugwiMqNpZklzo06Z+gwiIiIiEqM3SOJiIiIiIiMGJM2IiIiIiIiI8akjQAA8rRUdO7SFp27tIU8LdXQ4RCVudSsVDT6uhEafd0IqVms40RERFRx8Jo20hECqisXpGmiF40QAufvn5emiYiIiCoKtrQREREREREZMSZtRERERERERoxJGxERERERkRFj0kZERERERGTEmLQREREREREZMY4eSToyGVKq15SmiV40MpkMLioXaZqIiIioomDSRgAAjYUldh3629BhEJUbSzNLXA+5bugwiIiIiEqM3SOJiIiIiIiMGJM2IiIiIiIiI8akjQAAJulp8OvdEX69O8IkPc3Q4RCVubSsNLT+rjVaf9caaVms40RERFRx8Jo2AgDItFrY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xOzfZgMAJrefDIWcdZyIiIgMq7i5QakGIklKSsK9e/fyzE9ISMCTJ09Ks0kyMJPsLDT6ci4afTkXJtlZhg6HqMxlabIQdigMYYfCkKVhHSciIqKKo1RJW+/evTFs2DBs2rQJt2/fxu3bt7Fp0yYMHz4cffr0KesYiYiIiIiIXlqluqZt6dKlCA0NxVtvvYWsLN0v1qamphg+fDjmz59fpgESERERERG9zEqVtFlaWuLrr7/G/PnzcfXqVQghULduXVhZWZV1fERERERERC+157q5dlxcHOLi4lCvXj1YWVmhFGOaEBERERERUSFKlbQ9fPgQfn5+qFevHrp164a4uDgAwDvvvMPh/omIiIiIiMpQqZK2cePGwczMDDdv3oSlpaU0f8CAAdizZ0+ZBUdERERERPSyK9U1bTExMdi7dy9q1KihN9/d3R03btwok8Dov6VRmuPnLQekaaIXjbmpOU68c0KaJiIiIqooSpW0paSk6LWw5Xjw4AGUSuVzB0UGIJcjsUkLQ0dBVG7kJnK0rt7a0GEQERERlVipukd26NABP/zwg/RcJpNBq9Vi/vz56NixY5kFR0RERERE9LIrVUvb/Pnz4evriz/++AOZmZn4+OOPce7cOTx69Ai///57WcdI/wFZZibcVy0FAFwe8h6EQmHgiIjKVqYmE18c+wIAMLbtWCjkrONERERUMZQqafPw8MCZM2fwzTffQC6XIyUlBX369MEHH3yAatWqlXWM9B8wyc5C07lTAQBXBw2HhkkbvWCyNFn4+OePAQCjWo9i0kZEREQVRomTtqysLHTu3BnLli1DWFhYecRERERERERE/6/E17SZmZnh7NmzkMlk5REPERERERERPaNUA5EMHjwYK1asKOtYiIiIiIiIKJdSXdOWmZmJ5cuXY9++fWjVqhWsrKz0lkdERJRJcERERERERC+7EiVt//77L1xdXXH27Fm0aKG7p9elS5f0yrDbJBERERERUdkpUdLm7u6OuLg4HDx4EAAwYMAA/O9//4Ojo2O5BEdERERERPSyK1HSJoTQe757926kpKSUaUBkGBqlOX5Zs0OaJnrRmJua4+CQg9I0ERERUUVRqmvacuRO4qgCk8txv217Q0dBVG7kJnL4uvoaOgwiIiKiEivR6JEymSzPNWu8ho2IiIiIiKj8lLh75NChQ6FUKgEA6enpeO+9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QPsRAwAAW87cgYZJG71gMrIzELguEACQPCkZpgrWcSIiIqoY+K2FyAByWjjLA1vxiIiIiF4sRj16JBERERER0cuOSRsREREREZERY9JGRERERERkxJi0ERERERERGTEmbUREREREREaMo0cSAEBrpsCf0+ZL00QvGoVcgSVdl0jTRERERBUFkzYCAAgzM1wNHmHoMIjKjZncDB+88oGhwyAiIiIqMXaPJCIiIiIiMmJsaSMdjQb2sUcAAPdbewNyuYEDIipbGq0Gv938DQDQvlZ7yE1Yx4mIiKhiYNJGAAB5Rjp83+oBANhy5g40llYGjoiobKVnp6Pjqo4AgORJybBSsI4TERFRxcDukUREREREREaMSRsREREREZERY9JGRERERERkxJi0ERERERERGTEmbUREREREREaMSRsREREREZER45D/BADQmprh9MQZ0jTRi8ZMboZ5neZJ00REREQVBZM2AgAIhQKXRowxdBhE5UYhV+Cjdh8ZOgwiIiKiEmP3SCIiIiIiIiPGljbS0WhQ+dxpAEBio6aAXG7ggIjKlkarwZ9xfwIAWlRrAbkJ6zgRERFVDEzaCAAgz0hHpz6vAQC2nLkDjaWVgSMiKlvp2el4ZfkrAIDkScmwUrCOExERUcXA7pFERERERERGjEkbERERERGREWPSRkREREREZMSYtBERERERERkxJm1ERERERERGjEkbERERERGREeOQ/wQA0Jqa4dyHE6VpoheNmdwM03ymSdNEREREFYVMCCEMHcTLJCkpCSqVCmq1Gra2toYOBxuvqg0dApWxfnVUhg6BiIiIiIqhuLkBu0cSEREREREZMXaPJB2tFrZXLgIAkurWB0yYz9OLRSu0+Of+PwCAhvYNYSJjHSciIqKKgUkbAQDk6WkI6OYFANhy5g40llYGjoiobKVlpcHzG08AQPKkZFgpWMeJiIioYuBPzUREREREREaMSRsREREREZERY9JGRERERERkxJi0ERERERERGTEmbUREREREREaMSRsREREREZER45D/BADQmprh4jsfStNELxozuRlCvUKlaSIiIqKKQiaEEIYO4mWSlJQElUoFtVoNW1tbQ4eDjVfVhg6Byli/OipDh0BERERExVDc3IDdI4mIiIiIiIwYu0eSjlYLy7u3AACpzjUBE+bz9GLRCi1uqm8CAGqpasFExjpO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UJDCw8M1duxYHTx40Op/9913lZCQIJfLpebNm2vQoEEqKys75/sKAFciijYAwGXh6+urp556SgsXLtS333570evJzMzU5MmTdc899yg/P18rVqxQmzZtTju2vLxc/fv3V1BQkD7++GNt2rRJQUFBuvbaa1VVVXVe29u2bZvuu+8+zZkzR19++aVWrVqlvn37nvN1QUFBCgoK0vLly1VZWXle23rwwQdVXFxsPf70pz+pcePGSkpKkiTNmjVLWVlZyszM1M6dO3X//ffrjjvuUG5u7mnXd6pIzcrK8mjPyspSeHi4hg4dquPHj2vYsGFat26dduzYoSFDhmjkyJEqKio6r5hPp7i4WMnJyercubO2bdumVatW6fvvv9fNN99s9Y8ZM0bjx4/XF198oZycHN1www0yxlz0NgGgIfPzdgAAgCvHqFGj1LlzZ82ePVuvvPLKRa3jiSee0AMPPKBp06ZZbd27dz/t2KVLl8rHx0cvv/yyde9cVlaWmjRpopycHKWkpJxze0VFRQoMDNSIESMUHBysmJgYdenS5Zyv8/Pz02uvvaa7775bL7zwgrp27ark5GTdeuut6tSp02lfc6rQk6QtW7Zo1qxZWrJkiTp27KiysjLNnz9f69evV8+ePSVJcXFx2rRpk1588UUlJyefdp3jx4/XsGHDtHfvXsXFxckYo9dee01paWny9fVVYmKiEhMTrfFPPPGEsrOztWLFirOewTybzMxMde3aVU899ZTV9uqrryo6Olq7du3S8ePHVV1drRtuuEExMTGSTt5/BwA4Pc60AQAuq6efflpLlixRQUHBBb+2pKRE3333nQYOHHhe47dv366vvvpKwcHBVkHUrFkzVVRUaM+ePee1jsGDBysmJkZxcXEaO3as3nzzzdPeI3Y6N954o7777jutWLFCQ4YMUU5Ojrp27Wpd7ngmRUVFuv766/Xggw9aZ6cKCgpUUVGhwYMHW/sSFBSk119//az7kpKSopYtW1pn29avX6/CwkLdddddkqSysjL94Q9/UHx8vJo0aaKgoCD997///VVn2rZv364NGzZ4xNm+fXtJ0p49e5SYmKiBAwcqISFBo0eP1uLFi6+oex0B4EJRtAEALqu+fftqyJAhevTRR2v1+fj41LpE7qeffrKWXS7XBW3L7XarW7duysvL83js2rVLt91223ltMzg4WJ9++qneeustRUZG6rHHHlNiYqKOHDlyXjEEBARo8ODBeuyxx7R582alpaVp9uzZZxxfVlam6667Tj179tScOXM89kWSPvjgA499KSgoOOt9bT4+PkpLS9OSJUvkdruVlZWlvn37qm3btpKkhx56SO+9956efPJJbdy4UXl5eUpISDjj5aM+Pif/dPj5e/bz9+tUrCNHjqz1vu/evVt9+/aVr6+v1q5dq5UrVyo+Pl4LFy5Uu3bttG/fvnO8mwBwZaJoAwBcdnPnztX777+vzZs3e7SHhobqwIEDHgXBzye8CA4OVmxsrD766KPz2k7Xrl21e/duhYWFqU2bNh6PkJAQa5vFxcXWa2pqavT55597rMfPz0+DBg3SvHnz9Nlnn6mwsFDr16+/0N2WJMXHx59xwg1jjO644w653W799a9/9fg5hPj4eDmdThUVFdXal+jo6LNu86677tK3336rZcuWadmyZZowYYLVt3HjRqWlpWnUqFFKSEhQRESEx0QtvxQaGipJHu/Zz3MknXzfd+7cqdjY2FqxBgYGSjo5AUvv3r31+OOPa8eOHWrUqJGys7PPuh8AcKXinjYAwGWXkJCg22+/XQsXLvRo79evn3744QfNmzdPN910k1atWqWVK1fqqquussakp6dr0qRJCgsL09ChQ1VaWqpPPvlEU6dOrbWd22+/Xc8884xSU1M1Z84ctWzZUkVFRVq2bJkeeughtWzZUgMGDNCMGTP0wQcfqHXr1nr22Wc9zqL94x//0N69e9W3b181bdpUH374odxut9q1a3fWfTx06JBGjx6t8ePHq1OnTgoODta2bds0b948paamnvY16enpWrdundasWaPjx4/r+PHjkqSQkBAFBwfrwQcf1P333y+3260+ffro2LFj2rx5s4KCgjRu3LgzxtKqVSsNGDBA99xzj/z9/T1mv2zTpo2WLVumkSNHyuFw6I9//KN1Vu90XC6XevTooblz5yo2NlYHDx7UrFmzPMZMnjxZixcv1pgxY/TQQw+pRYsW+uqrr7R06VItXrxY27Zt00cffaSUlBSFhYXpX//6l3744Qddc801Z31PAeCKZQAAqGPjxo0zqampHm2FhYXG6XSaX34VZWZmmujoaBMYGGjuvPNO8+STT5qYmBiPMS+88IJp166d8ff3N5GRkWbq1KlWnySTnZ1tPS8uLjZ33nmnadGihXE6nSYuLs7cfffd5ujRo8YYY6qqqsy9995rmjVrZsLCwkxGRoZJTU0148aNM8YYs3HjRpOcnGyaNm1qXC6X6dSpk3n77bfPuc8VFRXmkUceMV27djUhISGmcePGpl27dmbWrFmmvLz8tPEmJycbSbUeWVlZxhhj3G63ee6556x9Dw0NNUOGDDG5ubnnjOdvf/ubkWTuuecej/Z9+/aZ/v37G5fLZaKjo83zzz9vkpOTzbRp06wxMTEx5tlnn7WeFxQUmB49ehiXy2U6d+5s1qxZYySZDRs2WGN27dplRo0aZZo0aWJcLpdp3769mT59unG73aagoMAMGTLEhIaGGqfTaX7zm9+YhQsXnnMfAOBK5TCG+XUBAAAAwK64pw0AAAAAbIyiDQCAi1BUVOQxpf0vH79mynwAAH6OyyMBALgI1dXVZ51lMTY2Vn5+zPcFAPj1KNoAAAAAwMa4PBIAAAAAbIyiDQAAAABsjKINAAAAAGyMog0AAAAAbIyiDQAAAABsjKINAAAAAGyMog0AAAAAbOz/AU3o+iGropfUAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "The plot is saved at: /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda/images/Nucleus_Size_Distribution.png\n" ] } ], "source": [ "# Plot the distribution of the Nucleus_Size column\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "ax.hist(df['Nucleus_Size'], bins=30, alpha=0.7, color='skyblue')\n", "\n", "# Add horizontal bars for the 0.05 and 0.95 quantiles\n", "quantile_05 = df['Nucleus_Size'].quantile(0.05)\n", "quantile_95 = df['Nucleus_Size'].quantile(0.95)\n", "ax.axvline(x=quantile_05, color='r', linestyle='--', label='Quantile 0.05')\n", "ax.axvline(x=quantile_95, color='g', linestyle='--', label='Quantile 0.95')\n", "\n", "# Add titles and labels\n", "ax.set_title('Distribution of Nucleus_Size column values with horizontal bars at 0.05 and 0.95 quantiles')\n", "ax.set_xlabel('Nucleus_Size Values')\n", "ax.set_ylabel('Frequency')\n", "ax.legend()\n", "\n", "# Display quantiles values\n", "ax.text(quantile_05, ax.get_ylim()[1], f' 5th Quantile: {quantile_05:.2f}', color='r', verticalalignment='top')\n", "ax.text(quantile_95, ax.get_ylim()[1], f' 95th Quantile: {quantile_95:.2f}', color='g', verticalalignment='top')\n", "\n", "# Display the plot\n", "plt.show()\n", "\n", "# Save the plot in the output_images_dir directory using fig.savefig\n", "plot_file_path = os.path.join(output_images_dir, \"Nucleus_Size_Distribution.png\")\n", "fig.savefig(plot_file_path)\n", "print(f\"The plot is saved at: {plot_file_path}\")" ] }, { "cell_type": "code", "execution_count": 33, "id": "fe562d2b-5026-4a88-8117-4ec910dd1242", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.05 1019.689148\n", "0.50 1346.929932\n", "0.95 2622.449524\n", "Name: AF555_Cell_Intensity_Average, dtype: float64\n" ] } ], "source": [ "print(df[\"AF555_Cell_Intensity_Average\"].quantile(q=qs))" ] }, { "cell_type": "code", "execution_count": 34, "id": "8b53dced-802d-4bfd-8e37-de33ffec9c7a", "metadata": {}, "outputs": [ { "data": { "image/png": "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ItIrTFSJiIiIiIhIrzBRJSIiIiIiIr1SqrenIf0g5IaI6fme9FxXDA0MMajeIOk5ERERERGRNpg9ELKUSkTNXqLzcpWGSoR2D9V5uURERERE9GZj118iIiIiIiLSK2xRJUAIyF88BwCoTUwBmUxHxQo8z8gu19TIFDIdlUtERERERG82tqgS5C+eo2fdiuhZt6KUsOrC84znMJ9hDvMZ5lLCSkREREREVBQmqkRERERERKRXmKgSERERERGRXmGiSkRERERERHqFiSoRERERERHpFSaqREREREREpFeYqBIREREREZFe4X1UCUIux+323aTnuiI3kKOXay/pORERERERkTaYqBKylMaIXLRC5+UaGxpjU+9NOi+XiIiIiIjebOz6S0RERERERHqFiSoRERERERHpFSaqBPnzFPSuXga9q5eB/HmKzspNSU+BbIoMsikypKTrrlwiIiIiInqzMVElIiIiIiIivcJElYiIiIiIiPQKE1UiIiIiIiLSK0xUiYiIiIiISK8wUSUiIiIiIiK9wkSViIiIiIiI9IphaVeASp+QyxHX2kd6rityAzk61ugoPSciIiIiItIGE1VCltIYx3/eqPNyjQ2Nsctvl87LJSIiIiKiNxu7/hIREREREZFeYaJKREREREREeoWJKkH+PAU96tijRx17yJ+n6KzclPQUmE03g9l0M6Sk665cIiIiIiJ6s/EaVQIAGL54/lrKfZ7xesolIiIiIqI3F1tUiYiIiIiISK8wUSUiIiIiIiK9wkSViIiIiIiI9AoTVSIiIiIiItIrTFSJiIiIiIhIr3DUX4IwMEBCkxbSc10xkBnA09FTek5ERERERKQNJqqELGMTHFm7S+flmhiZ4HDAYZ2XS0REREREbzY2cxEREREREZFeYaJKREREREREeoWJKkH+PAVdG1dD18bVIH+eorNyU9JTUGFOBVSYUwEp6borl4iIiIiI3mylmqguWbIEdevWhaWlJSwtLeHh4YHdu3dL84UQmDx5Muzt7WFiYoLWrVvj4sWLGmWkpaXh448/Rvny5WFmZoauXbvizp07GjGJiYnw9/eHSqWCSqWCv78/njx5ohETGxuLLl26wMzMDOXLl8eoUaOQnp6uEXPhwgV4enrCxMQEFStWxDfffAMhhG53SilRJj6CMvGRzst9+PwhHj5/qPNyiYiIiIjozVWq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iYiIiIj+6/QtN9AnJer626pVK6xcuVJ6LZPJkJWVhTlz5qBNmzY6qxwRERERERG9fUrU9XfOnDlo3bo1fv/9d6Snp+PTTz/FxYsX8fjxY5w4cULXdaTXTJaejhorfgQAXB/0IYRCoZNy09XpWBC5AAAwutloKOS6KZeIiIiIiN5sJer6C2TfMmbJkiU4c+YMsrKy0LBhQ4wYMQJ2dna6ruMbRd+a9zfdSIL8eQp61q0IANh6/i7UpiW/H+7LOjoYwnyGOQDg2YRnMFPoplwiIiIiojeBvuUG+qTYLaoZGRnw8fHB0qVLMWXKlNdRJyIiIiIiInqLFfsaVSMjI0RHR/N2LERERERERPRalGgwpYEDB2L58uW6rgsRERERERFRyQZTSk9Px88//4x9+/bB3d0dZmaa1x4GBwfrpHJERERERET09ilWovr333/DyckJ0dHRaNiwIQDg2rVrGjHsEkxERERERESvoliJao0aNRAXF4dDhw4BAPr27Yvvv/8eNjY2r6VyRERERERE9PYpVqKa+042u3fvRkpKik4rRP8+tdIYh1fvkJ7rirGhMQ4NOiQ9JyIiIiIi0kaJrlHNUcJbsJK+kcvxoFlL3RdrIEdrp9Y6L5eIiIiIiN5sxRr1VyaT5bkGldekEhERERERkS4Vu+tvQEAAlEolACA1NRUffvhhnlF/t27dqrsa0msny8hA1fWhAIC/+wVAGBnppNwMdQaWnVkGAPig0QcwkuumXCIiIiIierMVK1EdNGiQxusBAwbotDJUOgwy0tFwyicAgJh3/aDWUaKark7HyN0jAQAB9QOYqBIRERERkVaKlaiGhIS8rnoQERERERERASjmNapERERERERErxsTVSIiIiIiItIrTFSJiIiIiIhIrzBRJSIiIiIiIr3CRJWIiIiIiIj0SrFG/aU3U5ZCiWM/bZCe64rSUImd7+2UnhMREREREWmDiSpBGBoivo2vzss1NDBEJ+dOOi+XiIiIiIjebOz6S0RERERERHqFLaoEWUYGKv+6EQAQ27UPhJGRTsrNUGdgzYU1AID+dfrDSK6bcomIiIiI6M3GRJVgkJGOJp+NAADc6dAdah0lqunqdAzePhgA0Nu1NxNVIiIiIiLSCrv+EhERERERkV5hokpERERERER6hYkqERERERER6RUmqkRERERERKRXmKgSERERERGR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sdvtNTqORx55RHv37tWmTZs0cuRItW3bVpdddpnGjBmjzMxMNWrUSJJUWlqqBx98UM2bN1dAQIC6dOmi1atX1+g9fqlRo0bppptu0qxZsxQeHq6mTZvqvvvuU1lZmSTp+uuv1759+/TAAw9YM8inrF+/Xtddd52cTqciIyM1YcIEFRUVWe1RUVGaMWOG7rzzTjVu3FgXXnih3njjDau9tLRU48aNU3h4uBo0aKCoqCjNnDnTav/5qb+tWrWSJF155ZWy2Wy6/vrr9dVXX8nPz085OTluxzR58mRdd911Nf4M5s+fr2HDhikpKUlvvfWWNbP9+uuvq3nz5qqsrHSLHzBggEaOHGk9/+STTxQTE6MGDRrooosu0hNPPKHy8nK343jttdc0cOBABQQE6KmnnlJFRYVGjx6tVq1ayel0qnXr1vrLX/7i9j7l5eWaMGGCmjRpoqZNm+qhhx7SyJEjddNNN1kxxhg999xzuuiii+R0OtWxY0f9/e9/P+OxJiUlqaSkRB9++KHb/v379+vLL7/U6NGjtXv3bg0cOFChoaFq1KiROnfurJUrV54xZ3Wz3UePHpXNZnMbtzt27NCNN96oRo0aKTQ0VElJSTpy5IjV/ve//13t27eX0+lU06ZN1atXL7fxBACoikIVAOrQ+++/r9atW6t169YaMWKEkpOTf9VpsuPGjVNwcLA6d+6s1157rUoBIp0sQkJCQtS9e/cz/sF/5ZVXKjw8XD179tSqVatq9N6VlZVavHixhg8froiIiCrtjRo1kq/vyRN47rjjDv3zn//U4sWLtXXrVg0ePFh9+vTRd9999wuOtuZWrVql3bt3a9WqVXr77be1YMEC68eApUuXqkWLFpo+fbqys7OVnZ0tScrKylJCQoIGDRqkrVu36v3339e6des0btw4t9wvvPCCOnXqpIyMDI0dO1b33nuvdar0Sy+9pI8//lgffPCBdu3apXfffVdRUVHV9nHz5s2STs54Z2dna+nSpbruuut00UUXaeHChVZceXm53n33Xd1xxx01OvZjx47pww8/1IgRI9S7d28VFRVZxdXgwYN15MgRt+84Ly9Pn3/+uYYPHy5J+vzzzzVixAhNmDBBO3bs0Ouvv64FCxbo6aefdnufadOmaeDAgcrKytKdd96pyspKtWjRQh988IF27Nihxx57TI888og++OAD6zXPPvusFi1apOTkZP3zn/9UQUFBlWt2//SnPyk5OVmvvvqqtm/frgceeEAjRozQmjVrqj3epk2bauDAgUpOTnbbn5ycrNDQUPXt21eFhYW68cYbtXLlSmVkZCghIUH9+/fX/v37a/SZVic7O1txcXG64oor9PXXX2vFihU6dOiQhgwZYrXffvvtuvPOO7Vz506tXr1agwYN+k1OhweA3zUDAKgz3bp1M3PmzDHGGFNWVmaCg4NNamqq1b5nzx4jyTidThMQEGA9tmzZYsU8+eSTZv369SYjI8PMmjXLNGzY0Dz55JNW++HDh83s2bPNpk2bTFpamvnzn/9sfHx8zMKFC62Yb775xrzxxhsmPT3drF+/3tx7773GZrOZNWvWnPMYDh06ZCSZ2bNnnzXu+++/NzabzRw8eNBtf8+ePc3UqVONMcYkJycbl8tltU2bNs107NjxnH2oLnbkyJGmZcuWpry83No3ePBgM3ToUOt5y5YtzYsvvuiWJykpydx9991u+9auXWt8fHxMcXGx9boRI0ZY7ZWVlSYkJMS8+uqrxhhjxo8fb2644QZTWVlZbV8lmWXLlhlj/u87zsjIcIt59tlnTZs2baznH330kWnUqJEpLCw8+wfxv9544w1zxRVXWM/vv/9+M3z4cOv5gAEDzJ133mk9f/31101YWJj1eV177bVmxowZbjkXLlxowsPD3Y5j4sSJ5+zL2LFjzS233GI9Dw0NNc8//7z1vLy83Fx44YVm4MCBxhhjCgsLTYMGDcz69evd8owePdrcfvvtZ3yfzz77zNhsNrN7925jzMnvJSoqyhpf1Wnbtq15+eWXrec/HxPVfTd5eXlGklm1apUxxpg///nPJj4+3i3ngQMHjCSza9cuk56ebiSZvXv3nrEPAICquEYVAOrIrl27tHnzZi1dulSS5Ovrq6FDh+qtt95Sr1693GLff/99tWnTxnoeGRlpbf/pT3+ytk8tJjR9+nRrf3BwsB544AErplOnTsrLy9Nzzz1nLcp0alb3lNjYWB04cECzZs0656mm5n9nhn5+6mx1tmzZImOMLrvsMrf9JSUlatq06Vlf+2u1a9fO7fTl8PBwZWVlnfU16enp+v7777Vo0SJrnzFGlZWV2rNnj/U9dOjQwWq32WwKCwtTbm6upJOnHffu3VutW7dWnz59lJiYqPj4+F/U91GjRulPf/qTNm7cqK5du+qtt97SkCFDFBAQUKPXz58/323RrREjRui6667T0aNH1aRJEw0fPlx33323XnnlFTkcDi1atEi33Xab9Xmlp6crLS3NbQa1oqJCJ06c0PHjx63rQDt16lTlvV977TW9+eab2rdvn4qLi1VaWmqNzfz8fB06dEhXX321FW+32xUTE2OdCbBjxw6dOHFCvXv3dstbWlqqK6+88ozHHB8frxYtWig5OVlPPvmkvvzyS+3du9eahS4qKtITTzyhf/zjH/rxxx9VXl6u4uLi/2pGNT09XatWrbJOb/+53bt3Kz4+Xj179lT79u2VkJCg+Ph43XrrrQoKCvrV7wkA5wMKVQCoI/Pnz1d5ebmaN29u7TPGyM/PT3l5eW5/yEZGRuqSSy6pUd6uXbuqoKBAhw4dOuPiMV27dtWbb755zjzvvvvuOd+vWbNmCgoK0s6dO88aV1lZKbvdrvT09CrXvlb3R74nnL6wj81mq/a06J+rrKzUPffcowkTJlRp+/lCV2fLfdVVV2nPnj367LPPtHLlSg0ZMkS9evU66zWWpwsJCVH//v2VnJysiy66SJ9++mmNr+fdsWOHNm3apLS0ND300EPW/oqKCr333nu699571b9/f1VWVmr58uXq3Lmz1q5dq9mzZ7t9Dk888YQGDRpUJX+DBg2s7dML5w8++EAPPPCAXnjhBcXGxqpx48Z6/vnntWnTJre403/YMD87FfbU57h8+XK3/z4kyeFwnPG4fXx8NGrUKC1YsEBPPPGEkpOTdd111+nSSy+VJP3xj3/U559/rlmzZumSSy6R0+nUrbfeqtLS0jPmO71vp65x/nlf+/fvr2effbbK68PDw2W325Wamqr169crJSVFL7/8sh599FFt2rTJuj4ZAFAVhSoA1IHy8nK98847euGFF6rMtN1yyy1atGhRlWsiayojI0MNGjQ46yq7GRkZCg8PP2eec8VIJ/+YHzp0qBYuXKhp06ZVuU61qKhIDodDV155pSoqKpSbm6trr722RsdS2/z9/VVRUeG276qrrtL27dtr/MPAmQQGBmro0KEaOnSobr31VvXp00f/+c9/qqy2fGpRq9P7IUl33XWXbrvtNrVo0UIXX3yxunfvXqP3nj9/vq677jr99a9/ddu/cOFCzZ8/X/fee6+cTqcGDRqkRYsW6fvvv9dll12mmJgYK/aqq67Srl27fvHnsHbtWnXr1k1jx4619u3evdvadrlcCg0N1ebNm61xUFFRoYyMDGvWtW3btnI4HNq/f7/i4uJ+0fvfcccdeuqpp7R06VItXbrU7VZNa9eu1ahRo3TzzTdLkgoLC7V3794z5jq16nV2drY1k3v6bYSuuuoqLVmyRFFRUda12Kez2Wzq3r27unfvrscee0wtW7bUsmXLNGnSpF90bABwPqFQBYA68I9//EN5eXkaPXp0lRV8b731Vs2fP79Gheonn3yinJwcxcbGyul0atWqVXr00Ud19913WzNPb7/9tvz8/HTllVfKx8dHn3zyiV566SW3GaA5c+YoKipK7dq1U2lpqd59910tWbJES5YsqdHxzJgxQ6tXr1aXLl309NNPq1OnTvLz89PatWs1c+ZMpaWl6bLLLtPw4cP1//7f/9MLL7ygK6+8UkeOHNGXX36p9u3b68Ybb/wFn6BnREVF6auvvtJtt90mh8Oh4OBgPfTQQ+ratavuu+8+jRkzRgEBAdq5c6dSU1P18ssv1yjviy++qPDwcF1xxRXy8fHRhx9+qLCwsGp/PAgJCZHT6dSKFSvUokULNWjQwBoTCQkJcrlceuqppzR9+vQavXdZWZkWLlyo6dOnKzo62q3trrvu0nPPPad//etf6tixo4YPH67+/ftr+/btbqcJS9Jjjz2mxMRERUZGavDgwfLx8dHWrVuVlZWlp5566ozvf8kll+idd97R559/rlatWmnhwoVKS0tzmz0cP368Zs6cqUsuuUSXX365Xn75ZeXl5VmzrI0bN9aUKVP0wAMPqLKyUtdcc40KCgq0fv16NWrUyG1l4tO1atVKN9xwg+6++275+fnp1ltvdevb0qVL1b9/f9lsNv35z38+6wy70+lU165d9cwzzygqKkpHjhxxO9Veku677z7NmzdPt99+u/74xz8qODhY33//vRYvXqx58+bp66+/1hdffKH4+HiFhIRo06ZNOnz4sNup/ACAatTlBbIAcL5KTEw0N954Y7VtpxZfSU9PP+NCO6d89tln5oorrjCNGjUyDRs2NNHR0WbOnDmmrKzMilmwYIFp06aNadiwoWncuLGJiYlxW0jJmJML91x88cWmQYMGJigoyFxzzTVm+fLlv+iYjh49ah5++GFz6aWXGn9/fxMaGmp69eplli1bZi0qVFpaah577DETFRVl/Pz8TFhYmLn55pvN1q1bjTGeX0zp1OI8p9x///0mLi7Oer5hwwbToUMH43A4zM//l7h582bTu3dv06hRIxMQEGA6dOhgnn76aau9ukWYOnbsaKZNm2aM+b+FjAICAkxgYKDp2bOn2wJY+tliSsYYM2/ePBMZGWl8fHzc+mfMycV67Ha7+fHHH2v0Ofz97383Pj4+Jicnp9r29u3bm/HjxxtjTi5iFB4ebiRZCxD93IoVK0y3bt2M0+k0gYGB5uqrrzZvvPHGGY/DGGNOnDhhRo0aZVwul2nSpIm59957zcMPP+z23ZSVlZlx48aZwMBAExQUZB566CEzePBgc9ttt1kxlZWV5i9/+Ytp3bq18fPzM82aNTMJCQk1WuDrb3/7m5FUZVGsPXv2mB49ehin02kiIyPN3LlzTVxcnLn//vutmNO/2x07dpiuXbsap9NprrjiCpOSkuK2mJIxxnz77bfm5ptvNk2aNDFOp9NcfvnlZuLEiaaystLs2LHDJCQkmGbNmhmHw2Euu+wyt8WbAADVsxnD+ugAAHirMWPG6NChQ/r444/ruiu1prKyUm3atNGQIUP05JNP1nV3AABegFN/AQDwQvn5+UpLS9OiRYv0P//zP3XdHY/at2+fUlJSFBcXp5KSEs2dO1d79uzRsGHD6rprAAAv4VPXHQAAeL9GjRqd8bF27drzpg+/pYEDB2rAgAG65557qtympW/fvmf8LGbMmFFHPa45Hx8fLViwQJ07d1b37t2VlZWllStXct0mAMDCqb8AgHP6/vvvz9jWvHlzOZ3O86IP3uLgwYMqLi6utu2CCy6osrIwAAC/NxSqAAAAAACvwqm/AAAAAACvQqEKAAAAAPAqFKoAAAAAAK9CoQoAAAAA8CoUqgAAAAAAr0KhCgAAAADwKhSqAAAAAACv8v8B75FiJyxFAAEAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "The plot is saved at: /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda/images/AF555_Cell_Intensity_Average_Distribution.png\n" ] } ], "source": [ "# Plot the distribution of the Nucleus_Size column\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "ax.hist(df['AF555_Cell_Intensity_Average'], bins=30, alpha=0.7, color='skyblue')\n", "\n", "# Add horizontal bars for the 0.05 and 0.95 quantiles\n", "quantile_05 = df['AF555_Cell_Intensity_Average'].quantile(0.05)\n", "quantile_95 = df['AF555_Cell_Intensity_Average'].quantile(0.95)\n", "ax.axvline(x=quantile_05, color='r', linestyle='--', label='Quantile 0.05')\n", "ax.axvline(x=quantile_95, color='g', linestyle='--', label='Quantile 0.95')\n", "\n", "# Add titles and labels\n", "ax.set_title('Distribution of AF555_Cell_Intensity_Average column values with horizontal bars at 0.05 and 0.95 quantiles')\n", "ax.set_xlabel('AF555_Cell_Intensity_Average Values')\n", "ax.set_ylabel('Frequency')\n", "ax.legend()\n", "\n", "# Display quantiles values\n", "ax.text(quantile_05, ax.get_ylim()[1], f' 5th Quantile: {quantile_05:.2f}', color='r', verticalalignment='top')\n", "ax.text(quantile_95, ax.get_ylim()[1], f' 95th Quantile: {quantile_95:.2f}', color='g', verticalalignment='top')\n", "\n", "# Display the plot\n", "plt.show()\n", "\n", "# Save the plot in the output_images_dir directory using fig.savefig\n", "plot_file_path = os.path.join(output_images_dir, \"AF555_Cell_Intensity_Average_Distribution.png\")\n", "fig.savefig(plot_file_path)\n", "print(f\"The plot is saved at: {plot_file_path}\")" ] }, { "cell_type": "code", "execution_count": 35, "id": "116f1ba5-5a9b-4161-8fab-d5ecb8524179", "metadata": { "tags": [] }, "outputs": [ { "data": { "image/png": "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FAjuFKztMIiIiIjeehz2noiIiIiISEvYQkbFJwSQnKyeNjQEODxsmSOEQHKGug4Y6htyiGAiIiKiEmILGRVfcjJgbKx+ZCdmVKYkZyTDeLoxjKcbS4kZERERERUfW8joP7E7OjHfZa3tjf/DSIiIiIiI3hxsISMiIiIiItISJmRERERERERawoSMiIiIiIhIS5iQERERERERaQkTMiIiIiIiIi3hKItUfLq6QJcuL6apzNHV0UUX9y7SNBERERGVDBMyKj4DA2DDBm1HQVpkoGeADZ+wDhARERG9KnZZJCIiIiIi0hImZERERERERFrChIyKLykJkMnUj6QkbUdDWpCUngTZJBlkk2RISmcdICIiIiopJmRERERERERawoSMiIiIiIhIS5iQERERERERaQkTMiIiIiIiIi1hQkZERERERKQlTMiIiIiIiIi0RE/bAdBbSFcXaNv2xTSVObo6umjr0laaJiIiIqKSYUJGxWdgAOzYoe0oSIsM9AywowfrABEREdGrYpdFIiIiIiIiLWELGWnd7ujEfJe1tjf+DyMhIiIiIvpvsYWMii8pCTAyUj+SkrQdDWlBUnoSjKYZwWiaEZLSWQeIiIiISootZFQyycnajoC0LDmDdYCIiIjoVbGFjIiIiIiISEuYkBEREREREWkJuyxSseyOToRuchJa/vt8751EZBkKrcZERERERPS2YgsZERERERGRljAhIyIiIiIi0hJ2WaRiEzo6eNqoiTRNZY+OTAfeDt7SNBERERGVDBMyKjaVgRLH1+3SdhikRUp9JUL9Q7UdBhEREdFbjz9tExERERERaQkTMiIiIiIiIi1hQkbFppuchA/qOuKDuo7QTU7SdjikBUnpSbCcZQnLWZZISmcdICIiIiopXkNGJSJ/+kTbIZCWPU5+rO0QiIiIiN56bCEjIiIiIiLSEiZkREREREREWsKEjIiIiIiISEuYkBEREREREWkJEzIiIiIiIiIt4SiLVGxCRwfxtepJ01T26Mh00MCugTRNRERERCXzxnyTmj59OmQyGUaOHCnNE0IgMDAQdnZ2UCqVaN68OS5evKixXlpaGr788ktYWFjAyMgIH374Ie7evatRJi4uDr1794apqSlMTU3Ru3dvPHv2TKNMdHQ0OnToACMjI1hYWGD48OFIT09/XYf7VlMZKBG+LQzh28KgMlBqOxzSAqW+EhEDIxAxMAJKfdYBIiIiopJ6IxKyiIgI/Pbbb6hVq5bG/JkzZ2Lu3LlYsGABIiIiYGNjg5YtW+L58+dSmZEjR2LLli1Yu3YtDh8+jMTERLRv3x5ZWVlSmR49euDMmTPYvXs3du/ejTNnzqB3797S8qysLLRr1w5JSUk4fPgw1q5di02bNmHMmDGv/+CJiIiIiKjM0npClpiYiJ49e2Lp0qUwMzOT5gshMH/+fHz33Xf46KOPULNmTSxfvhzJycn4448/AADx8fH4/fffMWfOHLRo0QJ169bFqlWrcP78eezbtw8AcPnyZezevRv/+9//4OnpCU9PTyxduhTbt2/H1atXAQAhISG4dOkSVq1ahbp166JFixaYM2cOli5dioSEhHxjT0tLQ0JCgsaDiIiIiIioqLSekA0dOhTt2rVDixYtNObfvn0bsbGxaNWqlTRPoVDA29sbR44cAQCcPHkSGRkZGmXs7OxQs2ZNqUx4eDhMTU3RsGFDqUyjRo1gamqqUaZmzZqws7OTyvj5+SEtLQ0nT57MN/bp06dL3SBNTU1RuXLlVzgTbw+dlGR4N64B78Y1oJOSrO1wSAuSM5LhON8RjvMdkZzBOkBERERUUlod1GPt2rU4deoUIiIici2LjY0FAFhbW2vMt7a2RlRUlFRGLpdrtKxll8lePzY2FlZWVrm2b2VlpVEm537MzMwgl8ulMnkZN24cRo8eLT1PSEgoE0mZTAgo70ZL01T2CCEQFR8lTRMRERFRyWgtIbtz5w5GjBiBkJAQGBgY5FtOJpNpPBdC5JqXU84yeZUvSZmcFAoFFApFgbEQERERERHlR2tdFk+ePImHDx+ifv360NPTg56eHsLCwvDzzz9DT09ParHK2UL18OFDaZmNjQ3S09MRFxdXYJkHDx7k2v+jR480yuTcT1xcHDIyMnK1nBEREREREZUWrSVkvr6+OH/+PM6cOSM9GjRogJ49e+LMmTOoUqUKbGxssHfvXmmd9PR0hIWFwcvLCwBQv3596Ovra5SJiYnBhQsXpDKenp6Ij4/H8ePHpTLHjh1DfHy8RpkLFy4gJiZGKhMSEgKFQoH69eu/1vNARERERERll9a6LJqYmKBmzZoa84yMjGBubi7NHzlyJKZNmwYXFxe4uLhg2rRpMDQ0RI8ePQAApqam6N+/P8aMGQNzc3NUqFABAQEB8PDwkAYJcXNzQ+vWrTFw4EAsWbIEAPD555+jffv2cHV1BQC0atUK7u7u6N27N2bNmoWnT58iICAAAwcORLly5f6rU0JERERERGWMVgf1KMzYsWORkpKCIUOGIC4uDg0bNkRISAhMTEykMvPmzYOenh66du2KlJQU+Pr6Ijg4GLq6ulKZ1atXY/jw4dJojB9++CEWLFggLdfV1cWOHTswZMgQNG7cGEqlEj169MDs2bP/u4MlIiIiIqIyRyY4RFqpSUhIgKmpKeLj49/ZlrXd0YnQSUmGZwdvAED4tjColIavbX+t7Y0BAOlJ6ZhuPB0AMC5xHORG8qJtIDMJWK/eBromAnpGryPMMic5IxnvLX0PABAxMAKG+q+vDhARERG9jYqaG7zRLWT0ZlIpDfHPvty3KqCyw1DfEBeHXNR2GERERERvPa3fGJqIiIiIiKisYkJGRERERESkJUzIqNh0UpLRuMV7aNziPeikJGs7HNKC5Ixk1FhYAzUW1kByBusAERERUUnxGjIqNpkQMLl+RZqmskcIgUuPLknTRERERFQybCEjIiIiIiLSEiZkREREREREWsKEjIiIiIiISEuYkBEREREREWkJEzIiIiIiIiIt4SiLVGxCJkNKJXtpmsoemUwGB1MHaZqIiIiISoYJGRWbSmmIsH8uajsM0iJDfUNEjozUdhhEREREbz12WSQiIiIiItISJmRERERERERawoSMik0nNQWeHbzh2cEbOqkp2g6HtCAlIwXvLX0P7y19DykZrANEREREJcVryKjYZCoVTM+dkqap7FEJFU7cPyFNExEREVHJsIWMiIiIiIhIS5iQERERERERaQkTMiIiIiIiIi1hQkZERERERKQlTMiIiIiIiIi0hKMsUomkVzDXdgikZRaGFtoOgYiIiOitx4SMii3L0AgHTkdqOwzSIiO5ER599UjbYRARERG99dhlkYiIiIiISEuYkBEREREREWkJEzIqNp3UFLzfrQ3e79YGOqkp2g6HtCAlIwXNg5ujeXBzpGSwDhARERGVFK8ho2KTqVSocPSwNP067Y5OBABkJWdI8/beSYKuYTpa2xu/1n1T/lRChbCoMGmaiIiIiEqGLWRERERERERawoSMiIiIiIhIS5iQERERERERaQkTMiIiIiIiIi1hQkZERERERKQlHGWRSiRTaajtEEjLDPVZB4iI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vfeeqVWrlrXepk0brybmdKc+6C5fvtzaNnv2bCPJahqMMebuu+82vXv3Puc5T3e2huzaa6/1iunQoYO57777rPXTP3yfct1115Vqjt98801Tt25dr9f97W9/s9azs7ONw+Ewn332mTHGmIEDB5q//OUvZ83z9IbMmLN/6DfGmHvuucf07dvXWp8/f75p0qSJ1/fofB544AEzZMgQa33w4MHmwQcftNbbtm1rHnnkEWt9xowZpkOHDtZ6VFSUefvtt72O+fe//93ExsZ6Xcf8+fN/M5d+/fqZqVOnGmOMOXbsmPHz8zPvv/++tf/o0aMmICDAqt0ff/zROBwOc/DgQa/jdO/e3cyYMeOc53nxxRetX1AYY8zx48dNYGCgeemll84aX1RUZIKDg81HH31kbStrQxYXF2fuuusur+N+9dVXxsfHx+Tl5ZX75wKAyw+3LALAWZj/3JLncDguKL5Xr17KycnR448/Xmpfz5491bBhQzVp0kRxcXFatGjRBd1uV5Yc7rzzTuvWt4yMDH3yySe64447zvua7du3KzY21uv4Xbp0UXZ2tg4cOGBt69Spk1dMbGysdu7cqeLi4rMed+XKlerZs6fq1aun4OBgjRgxQocPH7Zu1Zo0aZIeffRRdenSRTNnztTmzZtLHaNt27bWcnh4uAICAtSkSROvbRkZGee9vvM5/fiSVLdu3d88XnJysh555BEFBQVZX2PGjFFaWprX9/P0YwcGBio4ONg69j333KPFixfryiuv1PTp07V27doy5z5mzBglJibq4MGDkk7ePjhq1KgLqpPi4mK9/vrrGj58uLVt+PDhev31163v57Bhw7Ro0SJJJ2vwnXfe0bBhwyRJhw4d0v79+zV69Giv9+HRRx/VTz/95HWu9u3blzr3Y489prZt26pWrVoKCgpSYmKi9u3bJ0natWuXCgsL1bFjR+s1Ho9HLVq0sNZTUlJkjFHz5s29zr9q1apS5z/d7bffrpKSEr377ruSpHfffVfGGP35z3+WdPLfzNixY9W8eXN5PB55PB5lZ2dbuZVHcnKyFi5c6JVn7969VVJSot27d5f75wKAyw8NGQCcRbNmzeRwOLR9+/YLiu/evbuWLVuml19+WRMnTvTaFxwcrJSUFL3zzjuqW7euHnroIbVr1+43Z88rSw4jRozQrl27tG7dOr311ltq1KiRrrvu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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "The plot is saved at: /Users/harshithakolipaka/Downloads/wetransfer_data-zip_2024-05-17_1431/test_qc_eda/images/CKs_Cytoplasm_Intensity_Average_Distribution.png\n" ] } ], "source": [ "# Plot the distribution of the Nucleus_Size column\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "ax.hist(df['CKs_Cytoplasm_Intensity_Average'], bins=100, alpha=0.6, color='skyblue') # Augmented number of bins\n", "\n", "# Calculate mean and median\n", "mean_value = df['CKs_Cytoplasm_Intensity_Average'].mean()\n", "median_value = df['CKs_Cytoplasm_Intensity_Average'].median()\n", "\n", "# Add vertical lines for mean and median\n", "ax.axvline(x=mean_value, color='orange', linestyle='-', label='Mean')\n", "ax.axvline(x=median_value, color='purple', linestyle='-', label='Median')\n", "\n", "# Add horizontal bars for the 0.05 and 0.95 quantiles\n", "quantile_05 = df['CKs_Cytoplasm_Intensity_Average'].quantile(0.05)\n", "quantile_95 = df['CKs_Cytoplasm_Intensity_Average'].quantile(0.95)\n", "ax.axvline(x=quantile_05, color='r', linestyle='--', label='Quantile 0.05')\n", "ax.axvline(x=quantile_95, color='g', linestyle='--', label='Quantile 0.95')\n", "\n", "# Add titles and labels\n", "ax.set_title('Distribution of CKs_Cytoplasm_Intensity_Average with Quantiles, Mean, and Median')\n", "ax.set_xlabel('CKs_Cytoplasm_Intensity_Average Values')\n", "ax.set_ylabel('Frequency')\n", "ax.legend()\n", "\n", "# Display quantile values\n", "ax.text(quantile_05, ax.get_ylim()[1], f' 5th Quantile: {quantile_05:.2f}', color='r', verticalalignment='top')\n", "ax.text(quantile_95, ax.get_ylim()[1], f' 95th Quantile: {quantile_95:.2f}', color='g', verticalalignment='top')\n", "\n", "# Display mean and median values\n", "ax.text(mean_value, ax.get_ylim()[1]*0.9, f' Mean: {mean_value:.2f}', color='orange', verticalalignment='top')\n", "ax.text(median_value, ax.get_ylim()[1]*0.85, f' Median: {median_value:.2f}', color='purple', verticalalignment='top')\n", "\n", "# Display the plot\n", "plt.show()\n", "\n", "# Save the plot\n", "plot_file_path = os.path.join(output_images_dir, \"CKs_Cytoplasm_Intensity_Average_Distribution.png\")\n", "fig.savefig(plot_file_path)\n", "print(f\"The plot is saved at: {plot_file_path}\")" ] }, { "cell_type": "code", "execution_count": 36, "id": "90c21233-43da-4692-bbf0-c90e037c035c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.05 1603.137970\n", "0.50 3559.484741\n", "0.95 10239.075195\n", "Name: CKs_Cytoplasm_Intensity_Average, dtype: float64" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"CKs_Cytoplasm_Intensity_Average\"].quantile(q=qs)" ] }, { "cell_type": "markdown", "id": "4a3e399c-684e-4c40-9963-1e96bb3fcffe", "metadata": {}, "source": [ "## I.5. COLUMNS OF INTERESTS" ] }, { "cell_type": "code", "execution_count": 37, "id": "fdcf65d1-0d91-4688-9903-25a003d755b6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Columns are now...\n", "['ROI_index', 'Nuc_Y_Inv', 'Nucleus_Roundness', 'Cell_Size', 'Sample_ID', 'Nucleus_Size', 'Nuc_X', 'AF488_Cell_Intensity_Average', 'AF488_Cytoplasm_Intensity_Average', 'AF488_Nucleus_Intensity_Average', 'AF555_Cell_Intensity_Average', 'AF555_Cytoplasm_Intensity_Average', 'AF555_Nucleus_Intensity_Average', 'AF647_Cell_Intensity_Average', 'AF647_Cytoplasm_Intensity_Average', 'AF647_Nucleus_Intensity_Average', 'AF750_Cell_Intensity_Average', 'AF750_Cytoplasm_Intensity_Average', 'AF750_Nucleus_Intensity_Average', 'aSMA_Cell_Intensity_Average', 'aSMA_Cytoplasm_Intensity_Average', 'aSMA_Nucleus_Intensity_Average', 'AXL_Cell_Intensity_Average', 'AXL_Cytoplasm_Intensity_Average', 'AXL_Nucleus_Intensity_Average', 'B7H4_Cell_Intensity_Average', 'B7H4_Cytoplasm_Intensity_Average', 'B7H4_Nucleus_Intensity_Average', 'CA9_Cell_Intensity_Average', 'CA9_Cytoplasm_Intensity_Average', 'CA9_Nucleus_Intensity_Average', 'CD4_Cell_Intensity_Average', 'CD4_Cytoplasm_Intensity_Average', 'CD4_Nucleus_Intensity_Average', 'CD8_Cell_Intensity_Average', 'CD8_Cytoplasm_Intensity_Average', 'CD8_Nucleus_Intensity_Average', 'CD11b_Cell_Intensity_Average', 'CD11b_Cytoplasm_Intensity_Average', 'CD11b_Nucleus_Intensity_Average', 'CD11c_Cell_Intensity_Average', 'CD11c_Cytoplasm_Intensity_Average', 'CD11c_Nucleus_Intensity_Average', 'CD20_Cell_Intensity_Average', 'CD20_Cytoplasm_Intensity_Average', 'CD20_Nucleus_Intensity_Average', 'CD31_Cell_Intensity_Average', 'CD31_Cytoplasm_Intensity_Average', 'CD31_Nucleus_Intensity_Average', 'CD44_Cell_Intensity_Average', 'CD44_Cytoplasm_Intensity_Average', 'CD44_Nucleus_Intensity_Average', 'CD45_Cell_Intensity_Average', 'CD45_Cytoplasm_Intensity_Average', 'CD45_Nucleus_Intensity_Average', 'CD68_Cell_Intensity_Average', 'CD68_Cytoplasm_Intensity_Average', 'CD68_Nucleus_Intensity_Average', 'CD163_Cell_Intensity_Average', 'CD163_Cytoplasm_Intensity_Average', 'CD163_Nucleus_Intensity_Average', 'CKs_Cell_Intensity_Average', 'CKs_Cytoplasm_Intensity_Average', 'CKs_Nucleus_Intensity_Average', 'ColVI_Cell_Intensity_Average', 'ColVI_Cytoplasm_Intensity_Average', 'ColVI_Nucleus_Intensity_Average', 'Desmin_Cell_Intensity_Average', 'Desmin_Cytoplasm_Intensity_Average', 'Desmin_Nucleus_Intensity_Average', 'Ecad_Cell_Intensity_Average', 'Ecad_Cytoplasm_Intensity_Average', 'Ecad_Nucleus_Intensity_Average', 'Fibronectin_Cell_Intensity_Average', 'Fibronectin_Cytoplasm_Intensity_Average', 'Fibronectin_Nucleus_Intensity_Average', 'FOXP3_Cell_Intensity_Average', 'FOXP3_Cytoplasm_Intensity_Average', 'FOXP3_Nucleus_Intensity_Average', 'GATA3_Cell_Intensity_Average', 'GATA3_Cytoplasm_Intensity_Average', 'GATA3_Nucleus_Intensity_Average', 'HLA_Cell_Intensity_Average', 'HLA_Cytoplasm_Intensity_Average', 'HLA_Nucleus_Intensity_Average', 'Ki67_Cell_Intensity_Average', 'Ki67_Cytoplasm_Intensity_Average', 'Ki67_Nucleus_Intensity_Average', 'MMP9_Cell_Intensity_Average', 'MMP9_Cytoplasm_Intensity_Average', 'MMP9_Nucleus_Intensity_Average', 'PD1_Cell_Intensity_Average', 'PD1_Cytoplasm_Intensity_Average', 'PD1_Nucleus_Intensity_Average', 'PDGFR_Cell_Intensity_Average', 'PDGFR_Cytoplasm_Intensity_Average', 'PDGFR_Nucleus_Intensity_Average', 'PDL1_Cell_Intensity_Average', 'PDL1_Cytoplasm_Intensity_Average', 'PDL1_Nucleus_Intensity_Average', 'r5c2_Cell_Intensity_Average', 'r5c2_Cytoplasm_Intensity_Average', 'r5c2_Nucleus_Intensity_Average', 'r7c2_Cell_Intensity_Average', 'r7c2_Cytoplasm_Intensity_Average', 'r7c2_Nucleus_Intensity_Average', 'r8c2_Cell_Intensity_Average', 'r8c2_Cytoplasm_Intensity_Average', 'r8c2_Nucleus_Intensity_Average', 'Sting_Cell_Intensity_Average', 'Sting_Cytoplasm_Intensity_Average', 'Sting_Nucleus_Intensity_Average', 'Vimentin_Cell_Intensity_Average', 'Vimentin_Cytoplasm_Intensity_Average', 'Vimentin_Nucleus_Intensity_Average']\n" ] } ], "source": [ "# Remove columns containing \"DAPI\"\n", "df = df[[x for x in df.columns.values if 'DAPI' not in x]]\n", "\n", "print(\"Columns are now...\")\n", "print([c for c in df.columns.values])" ] }, { "cell_type": "code", "execution_count": 38, "id": "17741329-f501-4eec-af23-ed5026b13a94", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'AF488_Cell': 'AF488_Cell_Intensity_Average',\n", " 'AF488_Cytoplasm': 'AF488_Cytoplasm_Intensity_Average',\n", " 'AF488_Nucleus': 'AF488_Nucleus_Intensity_Average',\n", " 'AF555_Cell': 'AF555_Cell_Intensity_Average',\n", " 'AF555_Cytoplasm': 'AF555_Cytoplasm_Intensity_Average',\n", " 'AF555_Nucleus': 'AF555_Nucleus_Intensity_Average',\n", " 'AF647_Cell': 'AF647_Cell_Intensity_Average',\n", " 'AF647_Cytoplasm': 'AF647_Cytoplasm_Intensity_Average',\n", " 'AF647_Nucleus': 'AF647_Nucleus_Intensity_Average',\n", " 'AF750_Cell': 'AF750_Cell_Intensity_Average',\n", " 'AF750_Cytoplasm': 'AF750_Cytoplasm_Intensity_Average',\n", " 'AF750_Nucleus': 'AF750_Nucleus_Intensity_Average',\n", " 'aSMA_Cell': 'aSMA_Cell_Intensity_Average',\n", " 'aSMA_Cytoplasm': 'aSMA_Cytoplasm_Intensity_Average',\n", " 'aSMA_Nucleus': 'aSMA_Nucleus_Intensity_Average',\n", " 'AXL_Cell': 'AXL_Cell_Intensity_Average',\n", " 'AXL_Cytoplasm': 'AXL_Cytoplasm_Intensity_Average',\n", " 'AXL_Nucleus': 'AXL_Nucleus_Intensity_Average',\n", " 'B7H4_Cell': 'B7H4_Cell_Intensity_Average',\n", " 'B7H4_Cytoplasm': 'B7H4_Cytoplasm_Intensity_Average',\n", " 'B7H4_Nucleus': 'B7H4_Nucleus_Intensity_Average',\n", " 'CA9_Cell': 'CA9_Cell_Intensity_Average',\n", " 'CA9_Cytoplasm': 'CA9_Cytoplasm_Intensity_Average',\n", " 'CA9_Nucleus': 'CA9_Nucleus_Intensity_Average',\n", " 'CD4_Cell': 'CD4_Cell_Intensity_Average',\n", " 'CD4_Cytoplasm': 'CD4_Cytoplasm_Intensity_Average',\n", " 'CD4_Nucleus': 'CD4_Nucleus_Intensity_Average',\n", " 'CD8_Cell': 'CD8_Cell_Intensity_Average',\n", " 'CD8_Cytoplasm': 'CD8_Cytoplasm_Intensity_Average',\n", " 'CD8_Nucleus': 'CD8_Nucleus_Intensity_Average',\n", " 'CD11b_Cell': 'CD11b_Cell_Intensity_Average',\n", " 'CD11b_Cytoplasm': 'CD11b_Cytoplasm_Intensity_Average',\n", " 'CD11b_Nucleus': 'CD11b_Nucleus_Intensity_Average',\n", " 'CD11c_Cell': 'CD11c_Cell_Intensity_Average',\n", " 'CD11c_Cytoplasm': 'CD11c_Cytoplasm_Intensity_Average',\n", " 'CD11c_Nucleus': 'CD11c_Nucleus_Intensity_Average',\n", " 'CD20_Cell': 'CD20_Cell_Intensity_Average',\n", " 'CD20_Cytoplasm': 'CD20_Cytoplasm_Intensity_Average',\n", " 'CD20_Nucleus': 'CD20_Nucleus_Intensity_Average',\n", " 'CD31_Cell': 'CD31_Cell_Intensity_Average',\n", " 'CD31_Cytoplasm': 'CD31_Cytoplasm_Intensity_Average',\n", " 'CD31_Nucleus': 'CD31_Nucleus_Intensity_Average',\n", " 'CD44_Cell': 'CD44_Cell_Intensity_Average',\n", " 'CD44_Cytoplasm': 'CD44_Cytoplasm_Intensity_Average',\n", " 'CD44_Nucleus': 'CD44_Nucleus_Intensity_Average',\n", " 'CD45_Cell': 'CD45_Cell_Intensity_Average',\n", " 'CD45_Cytoplasm': 'CD45_Cytoplasm_Intensity_Average',\n", " 'CD45_Nucleus': 'CD45_Nucleus_Intensity_Average',\n", " 'CD68_Cell': 'CD68_Cell_Intensity_Average',\n", " 'CD68_Cytoplasm': 'CD68_Cytoplasm_Intensity_Average',\n", " 'CD68_Nucleus': 'CD68_Nucleus_Intensity_Average',\n", " 'CD163_Cell': 'CD163_Cell_Intensity_Average',\n", " 'CD163_Cytoplasm': 'CD163_Cytoplasm_Intensity_Average',\n", " 'CD163_Nucleus': 'CD163_Nucleus_Intensity_Average',\n", " 'CKs_Cell': 'CKs_Cell_Intensity_Average',\n", " 'CKs_Cytoplasm': 'CKs_Cytoplasm_Intensity_Average',\n", " 'CKs_Nucleus': 'CKs_Nucleus_Intensity_Average',\n", " 'ColVI_Cell': 'ColVI_Cell_Intensity_Average',\n", " 'ColVI_Cytoplasm': 'ColVI_Cytoplasm_Intensity_Average',\n", " 'ColVI_Nucleus': 'ColVI_Nucleus_Intensity_Average',\n", " 'Desmin_Cell': 'Desmin_Cell_Intensity_Average',\n", " 'Desmin_Cytoplasm': 'Desmin_Cytoplasm_Intensity_Average',\n", " 'Desmin_Nucleus': 'Desmin_Nucleus_Intensity_Average',\n", " 'Ecad_Cell': 'Ecad_Cell_Intensity_Average',\n", " 'Ecad_Cytoplasm': 'Ecad_Cytoplasm_Intensity_Average',\n", " 'Ecad_Nucleus': 'Ecad_Nucleus_Intensity_Average',\n", " 'Fibronectin_Cell': 'Fibronectin_Cell_Intensity_Average',\n", " 'Fibronectin_Cytoplasm': 'Fibronectin_Cytoplasm_Intensity_Average',\n", " 'Fibronectin_Nucleus': 'Fibronectin_Nucleus_Intensity_Average',\n", " 'FOXP3_Cell': 'FOXP3_Cell_Intensity_Average',\n", " 'FOXP3_Cytoplasm': 'FOXP3_Cytoplasm_Intensity_Average',\n", " 'FOXP3_Nucleus': 'FOXP3_Nucleus_Intensity_Average',\n", " 'GATA3_Cell': 'GATA3_Cell_Intensity_Average',\n", " 'GATA3_Cytoplasm': 'GATA3_Cytoplasm_Intensity_Average',\n", " 'GATA3_Nucleus': 'GATA3_Nucleus_Intensity_Average',\n", " 'HLA_Cell': 'HLA_Cell_Intensity_Average',\n", " 'HLA_Cytoplasm': 'HLA_Cytoplasm_Intensity_Average',\n", " 'HLA_Nucleus': 'HLA_Nucleus_Intensity_Average',\n", " 'Ki67_Cell': 'Ki67_Cell_Intensity_Average',\n", " 'Ki67_Cytoplasm': 'Ki67_Cytoplasm_Intensity_Average',\n", " 'Ki67_Nucleus': 'Ki67_Nucleus_Intensity_Average',\n", " 'MMP9_Cell': 'MMP9_Cell_Intensity_Average',\n", " 'MMP9_Cytoplasm': 'MMP9_Cytoplasm_Intensity_Average',\n", " 'MMP9_Nucleus': 'MMP9_Nucleus_Intensity_Average',\n", " 'PD1_Cell': 'PD1_Cell_Intensity_Average',\n", " 'PD1_Cytoplasm': 'PD1_Cytoplasm_Intensity_Average',\n", " 'PD1_Nucleus': 'PD1_Nucleus_Intensity_Average',\n", " 'PDGFR_Cell': 'PDGFR_Cell_Intensity_Average',\n", " 'PDGFR_Cytoplasm': 'PDGFR_Cytoplasm_Intensity_Average',\n", " 'PDGFR_Nucleus': 'PDGFR_Nucleus_Intensity_Average',\n", " 'PDL1_Cell': 'PDL1_Cell_Intensity_Average',\n", " 'PDL1_Cytoplasm': 'PDL1_Cytoplasm_Intensity_Average',\n", " 'PDL1_Nucleus': 'PDL1_Nucleus_Intensity_Average',\n", " 'r5c2_Cell': 'r5c2_Cell_Intensity_Average',\n", " 'r5c2_Cytoplasm': 'r5c2_Cytoplasm_Intensity_Average',\n", " 'r5c2_Nucleus': 'r5c2_Nucleus_Intensity_Average',\n", " 'r7c2_Cell': 'r7c2_Cell_Intensity_Average',\n", " 'r7c2_Cytoplasm': 'r7c2_Cytoplasm_Intensity_Average',\n", " 'r7c2_Nucleus': 'r7c2_Nucleus_Intensity_Average',\n", " 'r8c2_Cell': 'r8c2_Cell_Intensity_Average',\n", " 'r8c2_Cytoplasm': 'r8c2_Cytoplasm_Intensity_Average',\n", " 'r8c2_Nucleus': 'r8c2_Nucleus_Intensity_Average',\n", " 'Sting_Cell': 'Sting_Cell_Intensity_Average',\n", " 'Sting_Cytoplasm': 'Sting_Cytoplasm_Intensity_Average',\n", " 'Sting_Nucleus': 'Sting_Nucleus_Intensity_Average',\n", " 'Vimentin_Cell': 'Vimentin_Cell_Intensity_Average',\n", " 'Vimentin_Cytoplasm': 'Vimentin_Cytoplasm_Intensity_Average',\n", " 'Vimentin_Nucleus': 'Vimentin_Nucleus_Intensity_Average'}" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create lists of full names and shortened names to use in plotting\n", "full_to_short_names, short_to_full_names = \\\n", " shorten_feature_names(df.columns.values[~df.columns.isin(not_intensities)])\n", "\n", "short_to_full_names" ] }, { "cell_type": "code", "execution_count": 39, "id": "dfdd64a5-8705-4ed6-b94f-c42379faefd7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The full_to_short_column_names.csv file was created !\n" ] } ], "source": [ "# Save this data to a metadata file\n", "filename = os.path.join(metadata_dir, \"full_to_short_column_names.csv\")\n", "fh = open(filename, \"w\")\n", "fh.write(\"full_name,short_name\\n\")\n", "for k,v in full_to_short_names.items():\n", " fh.write(k + \",\" + v + \"\\n\")\n", " \n", "fh.close()\n", "print(\"The full_to_short_column_names.csv file was created !\")" ] }, { "cell_type": "code", "execution_count": 40, "id": "b4e26e25-620a-4700-b091-928c6ba08a00", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The short_to_full_column_names.csv file was created !\n" ] } ], "source": [ "# Save this data to a metadata file\n", "filename = os.path.join(metadata_dir, \"short_to_full_column_names.csv\")\n", "fh = open(filename, \"w\")\n", "fh.write(\"short_name,full_name\\n\")\n", "for k,v in short_to_full_names.items():\n", " fh.write(k + \",\" + v + \"\\n\")\n", " \n", "fh.close()\n", "print(\"The short_to_full_column_names.csv file was created !\")" ] }, { "cell_type": "markdown", "id": "4c5da27d-39a6-411b-a71f-0cd82ce2b728", "metadata": {}, "source": [ "## I.6. EXPOSURE TIME" ] }, { "cell_type": "code", "execution_count": 41, "id": "2e0c99c9-b254-41c7-b264-58441252c976", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Round Target Exp Channel\n", "0 R0 AF488 300 c2\n", "1 R0 AF555 1500 c3\n", "2 R0 AF647 1500 c4\n", "3 R0 AF750 1500 c5\n", "4 R1 ColVI 300 c2\n", "df's shape: (36, 4)\n", "\n", "No null values detected.\n" ] } ], "source": [ "# Here, we want to end up with a data structure that incorporates metadata on each intensity marker column used in our big dataframe in an easy-to-use format. \n", "# This is going to include the full name of the intensity marker columns in the big data frame, \n", "# the corresponding round and channel, \n", "# the target protein (e.g., CD45), \n", "# and the segmentation localization information (cell, cytoplasm, nucleus)\n", "\n", "# We can use this data structure to assign unique colors to all channels and rounds, for example, for use in later visualizations\n", "# Exposure_time file from ASHLAR analysis\n", "filename = \"Exposure_Time.csv\"\n", "filename = os.path.join(metadata_dir, filename)\n", "exp_df = pd.read_csv(filename)\n", "\n", "print(exp_df.head())\n", "\n", "# Verify file imported correctly\n", "# File length\n", "print(\"df's shape: \", exp_df.shape)\n", "# Headers\n", "expected_headers =['Round','Target','Exp','Channel']\n", "compare_headers(expected_headers, exp_df.columns.values, \"Imported metadata file\")\n", "\n", "# Missingness\n", "if exp_df.isnull().any().any():\n", " print(\"\\nexp_df has null value(s) in row(s):\")\n", " print(exp_df[exp_df.isna().any(axis=1)])\n", "else:\n", " print(\"\\nNo null values detected.\")" ] }, { "cell_type": "code", "execution_count": 42, "id": "17501193-977f-4b30-bbb8-5afdae4a0356", "metadata": {}, "outputs": [], "source": [ "if len(exp_df['Target']) > len(exp_df['Target'].unique()):\n", " print(\"One or more non-unique Target values in exp_df. Currently not supported.\")\n", "exp_df = exp_df.drop_duplicates(subset = 'Target').reindex()" ] }, { "cell_type": "code", "execution_count": 43, "id": "90d1feb7-2459-4a02-a526-ddc64082345b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
RoundTargetExpChannel
0R0AF488300c2
1R0AF5551500c3
2R0AF6471500c4
3R0AF7501500c5
17R4AXL1500c3
\n", "
" ], "text/plain": [ " Round Target Exp Channel\n", "0 R0 AF488 300 c2\n", "1 R0 AF555 1500 c3\n", "2 R0 AF647 1500 c4\n", "3 R0 AF750 1500 c5\n", "17 R4 AXL 1500 c3" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# sort exp_df by the values in the 'Target' column in ascending order and then retrieve the first few rows of the sorted df\n", "exp_df.sort_values(by = ['Target']).head()" ] }, { "cell_type": "code", "execution_count": 44, "id": "b7373851-14bb-4813-be00-7f8c4e1f4ebf", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
RoundTargetExpChanneltarget_lower
0R0AF488300c2af488
1R0AF5551500c3af555
2R0AF6471500c4af647
3R0AF7501500c5af750
4R1ColVI300c2colvi
\n", "
" ], "text/plain": [ " Round Target Exp Channel target_lower\n", "0 R0 AF488 300 c2 af488\n", "1 R0 AF555 1500 c3 af555\n", "2 R0 AF647 1500 c4 af647\n", "3 R0 AF750 1500 c5 af750\n", "4 R1 ColVI 300 c2 colvi" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create lowercase version of target\n", "exp_df['target_lower'] = exp_df['Target'].str.lower()\n", "exp_df.head()" ] }, { "cell_type": "code", "execution_count": 45, "id": "4722fdb1-cd93-45a0-b196-89d50918b2e2", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
full_column
0AF488_Cell_Intensity_Average
1AF488_Cytoplasm_Intensity_Average
2AF488_Nucleus_Intensity_Average
3AF555_Cell_Intensity_Average
4AF555_Cytoplasm_Intensity_Average
\n", "
" ], "text/plain": [ " full_column\n", "0 AF488_Cell_Intensity_Average\n", "1 AF488_Cytoplasm_Intensity_Average\n", "2 AF488_Nucleus_Intensity_Average\n", "3 AF555_Cell_Intensity_Average\n", "4 AF555_Cytoplasm_Intensity_Average" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create df that contains marker intensity columns in our df that aren't in not_intensities\n", "intensities = pd.DataFrame({'full_column':df.columns.values[~df.columns.isin(not_intensities)]})\n", "\n", "intensities.head()" ] }, { "cell_type": "code", "execution_count": 46, "id": "f88ef6d6-8160-4fa4-a0ed-942e4127414e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
full_columnmarkermarker_lower
0AF488_Cell_Intensity_AverageAF488af488
1AF488_Cytoplasm_Intensity_AverageAF488af488
2AF488_Nucleus_Intensity_AverageAF488af488
3AF555_Cell_Intensity_AverageAF555af555
4AF555_Cytoplasm_Intensity_AverageAF555af555
\n", "
" ], "text/plain": [ " full_column marker marker_lower\n", "0 AF488_Cell_Intensity_Average AF488 af488\n", "1 AF488_Cytoplasm_Intensity_Average AF488 af488\n", "2 AF488_Nucleus_Intensity_Average AF488 af488\n", "3 AF555_Cell_Intensity_Average AF555 af555\n", "4 AF555_Cytoplasm_Intensity_Average AF555 af555" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Extract the marker information from the `full_column`, which corresponds to full column in big dataframe\n", "# Use regular expressions (regex) to isolate the part of the field that begins (^) with an alphanumeric value (W), and ends with an underscore (_)\n", "# '$' is end of line\n", "intensities['marker'] = intensities['full_column'].str.extract(r'([^\\W_]+)')\n", "# convert to lowercase\n", "intensities['marker_lower'] = intensities['marker'].str.lower()\n", "\n", "intensities.head()" ] }, { "cell_type": "code", "execution_count": 47, "id": "2b9ff02b-a33b-4f42-95c0-4b4132e2aa25", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
full_columnmarkermarker_lower
0AF488_Cell_Intensity_AverageAF488af488
1AF488_Cytoplasm_Intensity_AverageAF488af488
2AF488_Nucleus_Intensity_AverageAF488af488
3AF555_Cell_Intensity_AverageAF555af555
4AF555_Cytoplasm_Intensity_AverageAF555af555
\n", "
" ], "text/plain": [ " full_column marker marker_lower\n", "0 AF488_Cell_Intensity_Average AF488 af488\n", "1 AF488_Cytoplasm_Intensity_Average AF488 af488\n", "2 AF488_Nucleus_Intensity_Average AF488 af488\n", "3 AF555_Cell_Intensity_Average AF555 af555\n", "4 AF555_Cytoplasm_Intensity_Average AF555 af555" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Subset the intensities df to exclude any column pertaining to DAPI\n", "intensities = intensities.loc[intensities['marker_lower'] != 'dapi']\n", "\n", "intensities.head()" ] }, { "cell_type": "code", "execution_count": 48, "id": "fa1340aa-1c86-4b0f-82a2-ded1892dea6e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
RoundTargetExpChanneltarget_lowerfull_columnmarker
0R0AF488300c2af488AF488_Cell_Intensity_AverageAF488
1R0AF488300c2af488AF488_Cytoplasm_Intensity_AverageAF488
2R0AF488300c2af488AF488_Nucleus_Intensity_AverageAF488
3R0AF5551500c3af555AF555_Cell_Intensity_AverageAF555
4R0AF5551500c3af555AF555_Cytoplasm_Intensity_AverageAF555
........................
103R8Sting1000c4stingSting_Cytoplasm_Intensity_AverageSting
104R8Sting1000c4stingSting_Nucleus_Intensity_AverageSting
105R8CD11b1500c5cd11bCD11b_Cell_Intensity_AverageCD11b
106R8CD11b1500c5cd11bCD11b_Cytoplasm_Intensity_AverageCD11b
107R8CD11b1500c5cd11bCD11b_Nucleus_Intensity_AverageCD11b
\n", "

108 rows Ɨ 7 columns

\n", "
" ], "text/plain": [ " Round Target Exp Channel target_lower \\\n", "0 R0 AF488 300 c2 af488 \n", "1 R0 AF488 300 c2 af488 \n", "2 R0 AF488 300 c2 af488 \n", "3 R0 AF555 1500 c3 af555 \n", "4 R0 AF555 1500 c3 af555 \n", ".. ... ... ... ... ... \n", "103 R8 Sting 1000 c4 sting \n", "104 R8 Sting 1000 c4 sting \n", "105 R8 CD11b 1500 c5 cd11b \n", "106 R8 CD11b 1500 c5 cd11b \n", "107 R8 CD11b 1500 c5 cd11b \n", "\n", " full_column marker \n", "0 AF488_Cell_Intensity_Average AF488 \n", "1 AF488_Cytoplasm_Intensity_Average AF488 \n", "2 AF488_Nucleus_Intensity_Average AF488 \n", "3 AF555_Cell_Intensity_Average AF555 \n", "4 AF555_Cytoplasm_Intensity_Average AF555 \n", ".. ... ... \n", "103 Sting_Cytoplasm_Intensity_Average Sting \n", "104 Sting_Nucleus_Intensity_Average Sting \n", "105 CD11b_Cell_Intensity_Average CD11b \n", "106 CD11b_Cytoplasm_Intensity_Average CD11b \n", "107 CD11b_Nucleus_Intensity_Average CD11b \n", "\n", "[108 rows x 7 columns]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Merge the intensities andexp_df together to create metadata\n", "metadata = pd.merge(exp_df, intensities, how = 'left', left_on = 'target_lower',right_on = 'marker_lower')\n", "metadata = metadata.drop(columns = ['marker_lower'])\n", "metadata = metadata.dropna()\n", "\n", "# Target is the capitalization from the Exposure_Time.csv\n", "# target_lower is Target in small caps\n", "# marker is the extracted first component of the full column in segmentation data, with corresponding capitalization\n", "metadata" ] }, { "cell_type": "code", "execution_count": 49, "id": "75378ca2-3ecb-4c60-a7d4-da997f851066", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
RoundTargetExpChanneltarget_lowerfull_columnmarkerlocalisation
0R0AF488300c2af488AF488_Cell_Intensity_AverageAF488cell
1R0AF488300c2af488AF488_Cytoplasm_Intensity_AverageAF488cytoplasm
2R0AF488300c2af488AF488_Nucleus_Intensity_AverageAF488nucleus
3R0AF5551500c3af555AF555_Cell_Intensity_AverageAF555cell
4R0AF5551500c3af555AF555_Cytoplasm_Intensity_AverageAF555cytoplasm
...........................
103R8Sting1000c4stingSting_Cytoplasm_Intensity_AverageStingcytoplasm
104R8Sting1000c4stingSting_Nucleus_Intensity_AverageStingnucleus
105R8CD11b1500c5cd11bCD11b_Cell_Intensity_AverageCD11bcell
106R8CD11b1500c5cd11bCD11b_Cytoplasm_Intensity_AverageCD11bcytoplasm
107R8CD11b1500c5cd11bCD11b_Nucleus_Intensity_AverageCD11bnucleus
\n", "

108 rows Ɨ 8 columns

\n", "
" ], "text/plain": [ " Round Target Exp Channel target_lower \\\n", "0 R0 AF488 300 c2 af488 \n", "1 R0 AF488 300 c2 af488 \n", "2 R0 AF488 300 c2 af488 \n", "3 R0 AF555 1500 c3 af555 \n", "4 R0 AF555 1500 c3 af555 \n", ".. ... ... ... ... ... \n", "103 R8 Sting 1000 c4 sting \n", "104 R8 Sting 1000 c4 sting \n", "105 R8 CD11b 1500 c5 cd11b \n", "106 R8 CD11b 1500 c5 cd11b \n", "107 R8 CD11b 1500 c5 cd11b \n", "\n", " full_column marker localisation \n", "0 AF488_Cell_Intensity_Average AF488 cell \n", "1 AF488_Cytoplasm_Intensity_Average AF488 cytoplasm \n", "2 AF488_Nucleus_Intensity_Average AF488 nucleus \n", "3 AF555_Cell_Intensity_Average AF555 cell \n", "4 AF555_Cytoplasm_Intensity_Average AF555 cytoplasm \n", ".. ... ... ... \n", "103 Sting_Cytoplasm_Intensity_Average Sting cytoplasm \n", "104 Sting_Nucleus_Intensity_Average Sting nucleus \n", "105 CD11b_Cell_Intensity_Average CD11b cell \n", "106 CD11b_Cytoplasm_Intensity_Average CD11b cytoplasm \n", "107 CD11b_Nucleus_Intensity_Average CD11b nucleus \n", "\n", "[108 rows x 8 columns]" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Add a column to signify marker target localisation.\n", "# Use a lambda to determine segmented location of intensity marker column and update metadata accordingly\n", "# Using the add_metadata_location() function in my_modules.py\n", "metadata['localisation'] = metadata.apply(\n", " lambda row: add_metadata_location(row), axis = 1)\n", "\n", "metadata" ] }, { "cell_type": "code", "execution_count": 50, "id": "9779567d-bd63-468a-acdb-e30901c71e03", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The marker_intensity_metadata.csv file was created !\n" ] } ], "source": [ "# Save this data structure to the metadata folder\n", "# don't want to add color in because that's better off treating color the same for round, channel, and sample\n", "filename = \"marker_intensity_metadata.csv\"\n", "filename = os.path.join(metadata_dir, filename)\n", "\n", "metadata.to_csv(filename, index = False)\n", "print(\"The marker_intensity_metadata.csv file was created !\")" ] }, { "cell_type": "markdown", "id": "d371ebc6-4aee-4b43-914e-933e3f9abbd5", "metadata": {}, "source": [ "## I.7. COLORS WORKFLOW" ] }, { "cell_type": "markdown", "id": "0f4e010e-149b-4fe9-8a58-7f9f872d2be9", "metadata": {}, "source": [ "### I.7.1. CHANNELS COLORS" ] }, { "cell_type": "code", "execution_count": 51, "id": "fb818967-a0b7-4bd0-9b81-32fd1bfefde1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unique channels are: ['c2' 'c3' 'c4' 'c5']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUoAAABlCAYAAAArpKpSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAACs0lEQVR4nO3ZQWoTYRzG4X9CawI6CXQZEjc9hSdw4QW8gndQ2nt5Affuu+hADtC0UKR0XIgKgnmnqWEa+zzrb/HyBX7MZEZd13UFwF+Nhx4A8NQJJUAglACBUAIEQgkQCCVAIJQAwVGfQ/f397Ver6tpmhqNRvveBLB3XdfVZrOpxWJR4/H2Z8ZeoVyv17Varf7JOICnpG3bWi6XW8/0CmXTNFVVdf71vKbN9PHLnokPnz4PPeEwvf849IKD8+718dATDs7d9U19efP2V9+26RXKn6/b02Za05lQ9jV70et6+dPLV0MvODhHjVDuqs/fiT7mAARCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRHfQ51XVdVVbeb272O+d9cfbsbesJhurkeesHBudscDz3h4Nxd31TV775tM+p6nLq4uKjT09PHLwN4Ytq2reVyufVMryfKk5OTqqq6vLys+Xz++GXPxNXVVa1Wq2rbtmaz2dBzDoI72417e7iu62qz2dRisYhne4VyPP7xV+Z8Pvcj7GA2m7m3B3Jnu3FvD9P3wc/HHIBAKAGCXqGcTCZ1dnZWk8lk33v+K+7t4dzZbtzbfvX66g3wnHn1BgiEEiAQSoBAKAECoQQIhBIgEEqAQCgBgu+VwWR6hdDVcgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUoAAABlCAYAAAArpKpSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAACpklEQVR4nO3Zv2rbUBjG4WNj0FLLkNHYU4bupXTp2KV3lYvrPXTMEIHnYgVKIfh0CKFd6ld2ahQlz7PYwxk+Ppsf+jOrtdYCwD/Nxx4A4KUTSoBAKAECoQQIhBIgEEqAQCgBgsWQQ4fDoex2u7JcLstsNrv0TAAXV2stfd+X9Xpd5vPj14yDQrnb7cp2u/0vwwG8JF3Xlc1mc/TMoFAul8vHL5+6Mlu0zx7srfjxeTX2CJP0/uvHsUeYnG9fvo89wuT0pZYP5eefvh0xKJRPt9uzRSuUJ2ibsSeYpvm7QX9L/rIsHomda8jjRC9zAAKhBAiEEiAQSoBAKAECoQQIhBIgEEqAQCgBAqEECIQSIBBKgEAoAQKhBAiEEiAQSoBAKAECoQQIhBIgEEqAQCgBAqEECIQSIBBKgEAoAQKhBAiEEiAQSoBAKAECoQQIhBIgEEqAQCgBAqEECIQSIBBKgEAoAQKhBAiEEiAQSoBAKAECoQQIhBIgEEqAQCgBAqEECIQSIBBKgEAoAQKhBAiEEiAQSoBAKAECoQQIhBIgEEqAQCgBAqEECIQSIBBKgEAoAQKhBAiEEiAQSoBAKAECoQQIhBIgEEqAQCgBAqEECIQSIBBKgEAoAYLFkEO11sfPh/1Fh3lt9r/GnmCaDvcPY48wOX2pY48wOU87e+rbMbM64NTt7W25vr5+/mQAL0zXdWWz2Rw9M+iK8urqqpRSyt3dXVmtVs+f7I3Y7/dlu92WrutK27ZjjzMJdnYeeztdrbX0fV/W63U8OyiU8/njo8zVauVHOEPbtvZ2Ijs7j72dZuiFn5c5AIFQAgSDQtk0Tbm5uSlN01x6nlfF3k5nZ+ext8sa9NYb4C1z6w0QCCVAIJQAgVACBEIJEAglQCCUAIFQAgS/AVPOYnIQS7DnAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# we want colors that are categorical, since Channel is a non-ordered category (yes, they are numbered, but arbitrarily). \n", "# A categorical color palette will have dissimilar colors.\n", "# Get those unique colors\n", "if len(metadata.Channel.unique()) > 10:\n", " print(\"WARNING: There are more unique channel values than \\\n", " there are colors to choose from. Select different palette, e.g., \\\n", " continuous palette 'husl'.\")\n", "channel_color_values = sb.color_palette(\"bright\",n_colors = len(metadata.Channel.unique()))\n", "# chose 'colorblind' because it is categorical and we're unlikely to have > 10\n", "\n", "# You can customize the colors for each channel here\n", "custom_colors = {\n", " 'c2': 'lightgreen',\n", " 'c3': 'tomato',\n", " 'c4': 'pink',\n", " 'c5': 'turquoise'\n", "}\n", "\n", "custom_colors_values = sb.palplot(sb.color_palette([custom_colors.get(ch, 'blue') for ch in metadata.Channel.unique()]))\n", "\n", "# Display those unique customs colors\n", "print(\"Unique channels are:\", metadata.Channel.unique())\n", "sb.palplot(sb.color_palette(channel_color_values))" ] }, { "cell_type": "code", "execution_count": 52, "id": "e7aa9d2e-94b5-461b-859f-fadfa2ccc0c5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'c2': array([0.00784314, 0.24313725, 1. ]),\n", " 'c3': array([1. , 0.48627451, 0. ]),\n", " 'c4': array([0.10196078, 0.78823529, 0.21960784]),\n", " 'c5': array([0.90980392, 0. , 0.04313725])}" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Store in a dictionary\n", "channel_color_dict = dict(zip(metadata.Channel.unique(), channel_color_values))\n", "channel_color_dict\n", "for k,v in channel_color_dict.items():\n", " channel_color_dict[k] = np.float64(v)\n", "\n", "channel_color_dict" ] }, { "cell_type": "code", "execution_count": 53, "id": "aa2d6cf5-2126-4df4-a54f-c6926c2c06a1", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
rgbhexChannel
c2(0.00784313725490196, 0.24313725490196078, 1.0)#023effc2
c3(1.0, 0.48627450980392156, 0.0)#ff7c00c3
c4(0.10196078431372549, 0.788235294117647, 0.219...#1ac938c4
c5(0.9098039215686274, 0.0, 0.043137254901960784)#e8000bc5
\n", "
" ], "text/plain": [ " rgb hex Channel\n", "c2 (0.00784313725490196, 0.24313725490196078, 1.0) #023eff c2\n", "c3 (1.0, 0.48627450980392156, 0.0) #ff7c00 c3\n", "c4 (0.10196078431372549, 0.788235294117647, 0.219... #1ac938 c4\n", "c5 (0.9098039215686274, 0.0, 0.043137254901960784) #e8000b c5" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "color_df_channel = color_dict_to_df(channel_color_dict, \"Channel\")\n", "\n", "# Save to file in metadatadirectory\n", "filename = \"channel_color_data.csv\"\n", "filename = os.path.join(metadata_dir, filename)\n", "color_df_channel.to_csv(filename, index = False)\n", "\n", "color_df_channel" ] }, { "cell_type": "code", "execution_count": 54, "id": "d8117d2d-c60e-477c-bef4-dc89d18fa6aa", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Legend of channel info only\n", "g = plt.figure(figsize = (1,1)).add_subplot(111)\n", "g.axis('off')\n", "handles = []\n", "for item in channel_color_dict.keys():\n", " h = g.bar(0,0, color = channel_color_dict[item],\n", " label = item, linewidth =0)\n", " handles.append(h)\n", "first_legend = plt.legend(handles=handles, loc='upper right', title = 'Channel'),\n", " # bbox_to_anchor=(10,10), \n", " # bbox_transform=plt.gcf().transFigure)\n", "\n", "filename = \"Channel_legend.png\"\n", "filename = os.path.join(metadata_images_dir, filename)\n", "plt.savefig(filename, bbox_inches = 'tight')" ] }, { "cell_type": "markdown", "id": "b5d587ec-809c-4312-acda-3747fc63fd83", "metadata": {}, "source": [ "### I.7.2. ROUNDS COLORS" ] }, { "cell_type": "code", "execution_count": 55, "id": "40bedb40-5740-4956-aa97-a95ac9fb341a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['R0' 'R1' 'R2' 'R3' 'R4' 'R5' 'R6' 'R7' 'R8']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAs0AAABlCAYAAAC2n94rAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAD40lEQVR4nO3cwU5jBRiG4b+lUBDbzmAmUUJNTLwDvQB3XoAXxK25NvEipAk7NpQKQeG4MGqchPnOOQ6eOcPzbGnIn4+SvpDCpGmapgAAgCdNhz4AAAA+dKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQzNo86PHxsS4vL2uxWNRkMnnumwAA4H/RNE1tt9s6PT2t6fTp3ye3iubLy8tar9fv7TgAAPiQbDabOjs7e/LjraJ5sVhUVdV3629qNt17P5e9AJ+9/nroE0bp+M1XQ58wOvt+qO1l7+z10CeM0uHZ0dAnjM6rL1q93PKWz9/YrasvX30y9Amjs7vZ1Q/ffv937z6l1bPxr7dkzKZ7tT/1BG7rYO9g6BNG6WD/cOgTRmf/QMT0MTv04tLH/MhuXR0ee+3s4+hTu3V1vDge+oTRSm9B9oeAAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQiGYAAAhEMwAABKIZAAAC0QwAAIFoBgCAQDQDAEAgmgEAIBDNAAAQzNo8qGmaqqr6/fHhWY/52Nw/3A99wijt/3Y39Amj09zfDn3CKD3c/Tr0CaM0uW2GPmF07natXm55y+2N3brazXx/drW72VXVP737lFbPxqurq6qq+nHz838864X55aehLwAAoIXtdlur1erJj7eK5pOTk6qquri4eOcn49+ur69rvV7XZrOp5XI59DmjYLN+7NadzfqxW3c268du3dmsn6Zparvd1unp6Tsf1yqap9M/3/q8Wq18EXpYLpd268hm/ditO5v1Y7fubNaP3bqzWXdtfinsDwEBACAQzQAAELSK5vl8Xufn5zWfz5/7no+K3bqzWT92685m/ditO5v1Y7fubPa8Jk36/xoAAPDCeXsGAAAEohkAAALRDAAAgWgGAIBANAMAQCCaAQAgEM0AABCIZgAACP4AgRCVeH0RRYAAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# we want colors that are sequential, since Round is an ordered category. \n", "# We can still generate colors that are easy to distinguish. Also, many of the categorical palettes cap at at about 10 or so unique colors, and repeat from there. \n", "# We do not want any repeats!\n", "round_color_values = sb.cubehelix_palette(\n", " len(metadata.Round.unique()), start=1, rot= -0.75, dark=0.19, light=.85, reverse=True)\n", "# round_color_values = sb.color_palette(\"cubehelix\",n_colors = len(metadata.Round.unique()))\n", "# chose 'cubehelix' because it is sequential, and round is a continuous process\n", "# each color value is a tuple of three values: (R, G, B)\n", "print(metadata.Round.unique())\n", "\n", "sb.palplot(sb.color_palette(round_color_values))\n", "\n", "## TO-DO: write what these parameters mean" ] }, { "cell_type": "code", "execution_count": 56, "id": "4372b4f0-2242-4d76-8881-a78fba5fd814", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'R0': array([0.28685356, 0.13009829, 0.23110332]),\n", " 'R1': array([0.36541462, 0.2025447 , 0.3769331 ]),\n", " 'R2': array([0.40867533, 0.29407612, 0.51667119]),\n", " 'R3': array([0.42890614, 0.40822902, 0.63353489]),\n", " 'R4': array([0.44444629, 0.5264665 , 0.70563219]),\n", " 'R5': array([0.47707206, 0.64270618, 0.74184779]),\n", " 'R6': array([0.54144549, 0.74667592, 0.75729058]),\n", " 'R7': array([0.64147101, 0.83215511, 0.7746773 ]),\n", " 'R8': array([0.76842569, 0.89926671, 0.81713833])}" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Store in a dictionary\n", "round_color_dict = dict(zip(metadata.Round.unique(), round_color_values))\n", "\n", "for k,v in round_color_dict.items():\n", " round_color_dict[k] = np.float64(v)\n", "\n", "round_color_dict" ] }, { "cell_type": "code", "execution_count": 57, "id": "3a6053ce-d87c-4137-8c70-a6772208fc37", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
rgbhexRound
R0(0.28685356234627135, 0.13009829239513535, 0.2...#49213bR0
R1(0.36541462435986094, 0.2025447048359916, 0.37...#5d3460R1
R2(0.40867533458903105, 0.2940761173840091, 0.51...#684b84R2
R3(0.42890613750051265, 0.4082290173220481, 0.63...#6d68a2R3
R4(0.4444462906865238, 0.5264664993764805, 0.705...#7186b4R4
R5(0.47707206309601013, 0.6427061780374552, 0.74...#7aa4bdR5
R6(0.5414454866716836, 0.7466759172596551, 0.757...#8abec1R6
R7(0.6414710091647722, 0.8321551072276492, 0.774...#a4d4c6R7
R8(0.7684256891219349, 0.8992667116749021, 0.817...#c4e5d0R8
\n", "
" ], "text/plain": [ " rgb hex Round\n", "R0 (0.28685356234627135, 0.13009829239513535, 0.2... #49213b R0\n", "R1 (0.36541462435986094, 0.2025447048359916, 0.37... #5d3460 R1\n", "R2 (0.40867533458903105, 0.2940761173840091, 0.51... #684b84 R2\n", "R3 (0.42890613750051265, 0.4082290173220481, 0.63... #6d68a2 R3\n", "R4 (0.4444462906865238, 0.5264664993764805, 0.705... #7186b4 R4\n", "R5 (0.47707206309601013, 0.6427061780374552, 0.74... #7aa4bd R5\n", "R6 (0.5414454866716836, 0.7466759172596551, 0.757... #8abec1 R6\n", "R7 (0.6414710091647722, 0.8321551072276492, 0.774... #a4d4c6 R7\n", "R8 (0.7684256891219349, 0.8992667116749021, 0.817... #c4e5d0 R8" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "color_df_round = color_dict_to_df(round_color_dict, \"Round\")\n", "\n", "# Save to file in metadatadirectory\n", "filename = \"round_color_data.csv\"\n", "filename = os.path.join(metadata_dir, filename)\n", "color_df_round.to_csv(filename, index = False)\n", "\n", "color_df_round" ] }, { "cell_type": "code", "execution_count": 58, "id": "977a7e45-64df-4bd6-ab21-cecd44d76fd9", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Legend of round info only\n", "\n", "round_legend = plt.figure(figsize = (1,1)).add_subplot(111)\n", "round_legend.axis('off')\n", "handles = []\n", "for item in round_color_dict.keys():\n", " h = round_legend.bar(0,0, color = round_color_dict[item],\n", " label = item, linewidth =0)\n", " handles.append(h)\n", "first_legend = plt.legend(handles=handles, loc='upper right', title = 'Round'),\n", " # bbox_to_anchor=(10,10), \n", " # bbox_transform=plt.gcf().transFigure)\n", "\n", "filename = \"Round_legend.png\"\n", "filename = os.path.join(metadata_images_dir, filename)\n", "plt.savefig(filename, bbox_inches = 'tight')" ] }, { "cell_type": "markdown", "id": "34b81c62-58a4-432c-876a-dfa5df0bbe9e", "metadata": {}, "source": [ "### I.7.3. SAMPLES COLORS" ] }, { "cell_type": "code", "execution_count": 59, "id": "3ccb74da-fb1d-4fda-9116-bf6b6a6d868b", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUoAAABlCAYAAAArpKpSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAACuUlEQVR4nO3ZMWsTcRzG8V9SaVohCXQMydTB2ffhu3BxEFzduvhWuvqGhA49yAvogSmCPQdRJ/NcW8P17Ocz/4eHf+DLXW7SdV1XAPzVdOgBAE+dUAIEQgkQCCVAIJQAgVACBEIJELzoc+ju7q62223N5/OaTCaH3gRwcF3XVdu2tVqtajrd/8zYK5Tb7bY2m80/GQfwlDRNU+v1eu+ZXqGcz+dVVfXl7ceaH588ftkzcfn689ATRuny5P3QE0bn3fWboSeMzu62rQ+fXv3u2z69QvnrdXt+fFKLmVD2dXp6NPSEUTo6fTn0hNE5PVkMPWG0+vyd6GMOQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQCCUAIFQAgRCCRAIJUAglACBUAIEQgkQCCVAIJQAgVACBEIJEAglQPCiz6Gu66qqqv12e9Ax/5vd7vvQE0bpe/d16Amjs7u9GXrC6Oxu26r607d9Jl2PU1dXV3V+fv74ZQBPTNM0tV6v957p9UR5dnZWVVXX19e1XC4fv+yZuLm5qc1mU03T1GKxGHrOKLizh3Fv99d1XbVtW6vVKp7tFcrp9Odfmcvl0o/wAIvFwr3dkzt7GPd2P30f/HzMAQiEEiDoFcrZbFYXFxc1m80Ovee/4t7uz509jHs7rF5fvQGeM6/eAIFQAgRCCRAIJUAglACBUAIEQgkQCCVA8ANJyGd00cXSZwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# we want colors that are neither sequential nor categorical. \n", "# Categorical would be ideal if we could generate an arbitrary number of colors, but I do not think that we can. \n", "# Hense, we will choose `n` colors from a continuous palette. First we will generate the right number of colors. Later, we will assign TMA samples to gray.\n", "\n", "# Get those unique colors\n", "color_values = sb.color_palette(\"husl\",n_colors = len(ls_samples))#'HLS'\n", "# each color value is a tuple of three values: (R, G, B)\n", "\n", "# Display those unique colors\n", "sb.palplot(sb.color_palette(color_values))" ] }, { "cell_type": "code", "execution_count": 60, "id": "441a57fe-d55a-49e1-8593-0f1939472b89", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGEAAABlCAYAAABdl421AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABwUlEQVR4nO3dP2oCQRxH8e9KYGzWBUtv6Qk8gie0ccELWNk4KcIGUqiDRnyJ7wPTuTDM2z92v67WWqOXmr16AzICghEAjABgBAAjABgB4KPlR+fzOYfDIX3fp+u6Z+/p36i15ng8ZrVaZTa7cr/XBuM41iSuO9c4jlfPt+lJ6Ps+SbJer1NKablESU6nU7bb7ff5XdIUYXoFlVIyn88f392bufUK98MMYAQAIwAYAcAIAEYAMAKAEQCMAGAEACMAGAHACABGADACgBEAjABgBAAjABgBwAgARgAwAoARAIwAYAQAIwAYAcAIAEYAMAKAEQCMAGAEACMAGAHACABGADACgBEAjABgBAAjABgBwAgARgAwAoARAIwAYAQAIwAYAcAIAEYAMAKAEQCMAGAEACMAGAHACABGADACgBEAjABgBAAjABgBwAgARgAwAoARAIwA0DRxsNaa5GuModpN5zWd30UtA1B3u93Lh4j+5fUrA1CXy2WSZL/fZxiGlkuU/BgFfE1ThGmW8DAMWSwWj+/ujbTctH6YAYwA0BShlJLNZuNA7Cfp6s3/T3o2X0cARgAwAoARAIwAYAQAIwAYAeATtddd94S3hxMAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "TMA_samples = [s for s in df.Sample_ID.unique() if 'TMA' in s]\n", "TMA_color_values = sb.color_palette(n_colors = len(TMA_samples),palette = \"gray\")\n", "sb.palplot(sb.color_palette(TMA_color_values))" ] }, { "cell_type": "code", "execution_count": 61, "id": "18dbf741-983e-4652-97d1-d55e87eba4fb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'DD3S1.csv': (0.9677975592919913, 0.44127456009157356, 0.5358103155058701),\n", " 'DD3S2.csv': (0.5920891529639701, 0.6418467016378244, 0.1935069134991043),\n", " 'DD3S3.csv': (0.21044753832183283, 0.6773105080456748, 0.6433941168468681),\n", " 'TMA.csv': (0.5019607843137255, 0.5019607843137255, 0.5019607843137255)}" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Store in a dictionary\n", "color_dict = dict()\n", "color_dict = dict(zip(df.Sample_ID.unique(), color_values))\n", "\n", "# Replace all TMA samples' colors with gray\n", "i = 0\n", "for key in color_dict.keys():\n", " if 'TMA' in key:\n", " color_dict[key] = TMA_color_values[i]\n", " i +=1\n", "\n", "color_dict" ] }, { "cell_type": "code", "execution_count": 62, "id": "807f2bb5-6d19-4086-81c1-98836e850dcd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
rgbhexSample_ID
DD3S1.csv(0.9677975592919913, 0.44127456009157356, 0.53...#f77189DD3S1.csv
DD3S2.csv(0.5920891529639701, 0.6418467016378244, 0.193...#97a431DD3S2.csv
DD3S3.csv(0.21044753832183283, 0.6773105080456748, 0.64...#36ada4DD3S3.csv
TMA.csv(0.5019607843137255, 0.5019607843137255, 0.501...#808080TMA.csv
\n", "
" ], "text/plain": [ " rgb hex \\\n", "DD3S1.csv (0.9677975592919913, 0.44127456009157356, 0.53... #f77189 \n", "DD3S2.csv (0.5920891529639701, 0.6418467016378244, 0.193... #97a431 \n", "DD3S3.csv (0.21044753832183283, 0.6773105080456748, 0.64... #36ada4 \n", "TMA.csv (0.5019607843137255, 0.5019607843137255, 0.501... #808080 \n", "\n", " Sample_ID \n", "DD3S1.csv DD3S1.csv \n", "DD3S2.csv DD3S2.csv \n", "DD3S3.csv DD3S3.csv \n", "TMA.csv TMA.csv " ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "color_df_sample = color_dict_to_df(color_dict, \"Sample_ID\")\n", "\n", "# Save to file in metadatadirectory\n", "filename = \"sample_color_data.csv\"\n", "filename = os.path.join(metadata_dir, filename)\n", "color_df_sample.to_csv(filename, index = False)\n", "\n", "color_df_sample" ] }, { "cell_type": "code", "execution_count": 63, "id": "39b6afdb-2e37-471e-86a0-e55ab7667e39", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Legend of sample info only\n", "g = plt.figure(figsize = (1,1)).add_subplot(111)\n", "g.axis('off')\n", "handles = []\n", "for item in color_dict.keys():\n", " h = g.bar(0,0, color = color_dict[item],\n", " label = item, linewidth =0)\n", " handles.append(h)\n", "first_legend = plt.legend(handles=handles, loc='upper right', title = 'Sample')\n", "\n", "filename = \"Sample_legend.png\"\n", "filename = os.path.join(metadata_images_dir, filename)\n", "plt.savefig(filename, bbox_inches = 'tight')" ] }, { "cell_type": "markdown", "id": "e3cf0dea-43db-41fa-952e-bbba53e89cdb", "metadata": {}, "source": [ "### I.7.4. CLUSTERS COLORS" ] }, { "cell_type": "code", "execution_count": 64, "id": "d37c61d7-de64-4b7c-8d01-86ee16ac67c4", "metadata": {}, "outputs": [], "source": [ "if 'cluster' in df.columns:\n", " cluster_color_values = sb.color_palette(\"hls\",n_colors = len(df.cluster.unique()))\n", "\n", " print(sorted(test_df.cluster.unique()))\n", " # Display those unique colors\n", " sb.palplot(sb.color_palette(cluster_color_values))\n", " \n", " cluster_color_dict = dict(zip(sorted(test_df.cluster.unique()), cluster_color_values))\n", " print(cluster_color_dict)\n", " \n", " # Create dataframe\n", " cluster_color_df = color_dict_to_df(cluster_color_dict, \"cluster\")\n", " cluster_color_df.head()\n", "\n", " # Save to file in metadatadirectory\n", " filename = \"cluster_color_data.csv\"\n", " filename = os.path.join(metadata_dir, filename)\n", " cluster_color_df.to_csv(filename, index = False)" ] }, { "cell_type": "code", "execution_count": 65, "id": "c9215452-fdb6-4963-9f56-31f16e0483bb", "metadata": {}, "outputs": [], "source": [ "# Legend of cluster info only\n", "\n", "if 'cluster' in df.columns:\n", " g = plt.figure(figsize = (1,1)).add_subplot(111)\n", " g.axis('off')\n", " handles = []\n", " for item in sorted(cluster_color_dict.keys()):\n", " h = g.bar(0,0, color = cluster_color_dict[item],\n", " label = item, linewidth =0)\n", " handles.append(h)\n", " first_legend = plt.legend(handles=handles, loc='upper right', title = 'Cluster'),\n", "\n", "\n", " filename = \"Clustertype_legend.png\"\n", " filename = os.path.join(metadata_images_dir, filename)\n", " plt.savefig(filename, bbox_inches = 'tight')" ] }, { "cell_type": "code", "execution_count": 66, "id": "715409aa", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
RoundTargetExpChanneltarget_lowerfull_columnmarkerlocalisationround_colorchannel_color
0R0AF488300c2af488AF488_Cell_Intensity_AverageAF488cell[0.28685356234627135, 0.13009829239513535, 0.2...[0.00784313725490196, 0.24313725490196078, 1.0]
1R0AF488300c2af488AF488_Cytoplasm_Intensity_AverageAF488cytoplasm[0.28685356234627135, 0.13009829239513535, 0.2...[0.00784313725490196, 0.24313725490196078, 1.0]
2R0AF488300c2af488AF488_Nucleus_Intensity_AverageAF488nucleus[0.28685356234627135, 0.13009829239513535, 0.2...[0.00784313725490196, 0.24313725490196078, 1.0]
3R0AF5551500c3af555AF555_Cell_Intensity_AverageAF555cell[0.28685356234627135, 0.13009829239513535, 0.2...[1.0, 0.48627450980392156, 0.0]
4R0AF5551500c3af555AF555_Cytoplasm_Intensity_AverageAF555cytoplasm[0.28685356234627135, 0.13009829239513535, 0.2...[1.0, 0.48627450980392156, 0.0]
.................................
103R8Sting1000c4stingSting_Cytoplasm_Intensity_AverageStingcytoplasm[0.7684256891219349, 0.8992667116749021, 0.817...[0.10196078431372549, 0.788235294117647, 0.219...
104R8Sting1000c4stingSting_Nucleus_Intensity_AverageStingnucleus[0.7684256891219349, 0.8992667116749021, 0.817...[0.10196078431372549, 0.788235294117647, 0.219...
105R8CD11b1500c5cd11bCD11b_Cell_Intensity_AverageCD11bcell[0.7684256891219349, 0.8992667116749021, 0.817...[0.9098039215686274, 0.0, 0.043137254901960784]
106R8CD11b1500c5cd11bCD11b_Cytoplasm_Intensity_AverageCD11bcytoplasm[0.7684256891219349, 0.8992667116749021, 0.817...[0.9098039215686274, 0.0, 0.043137254901960784]
107R8CD11b1500c5cd11bCD11b_Nucleus_Intensity_AverageCD11bnucleus[0.7684256891219349, 0.8992667116749021, 0.817...[0.9098039215686274, 0.0, 0.043137254901960784]
\n", "

108 rows Ɨ 10 columns

\n", "
" ], "text/plain": [ " Round Target Exp Channel target_lower \\\n", "0 R0 AF488 300 c2 af488 \n", "1 R0 AF488 300 c2 af488 \n", "2 R0 AF488 300 c2 af488 \n", "3 R0 AF555 1500 c3 af555 \n", "4 R0 AF555 1500 c3 af555 \n", ".. ... ... ... ... ... \n", "103 R8 Sting 1000 c4 sting \n", "104 R8 Sting 1000 c4 sting \n", "105 R8 CD11b 1500 c5 cd11b \n", "106 R8 CD11b 1500 c5 cd11b \n", "107 R8 CD11b 1500 c5 cd11b \n", "\n", " full_column marker localisation \\\n", "0 AF488_Cell_Intensity_Average AF488 cell \n", "1 AF488_Cytoplasm_Intensity_Average AF488 cytoplasm \n", "2 AF488_Nucleus_Intensity_Average AF488 nucleus \n", "3 AF555_Cell_Intensity_Average AF555 cell \n", "4 AF555_Cytoplasm_Intensity_Average AF555 cytoplasm \n", ".. ... ... ... \n", "103 Sting_Cytoplasm_Intensity_Average Sting cytoplasm \n", "104 Sting_Nucleus_Intensity_Average Sting nucleus \n", "105 CD11b_Cell_Intensity_Average CD11b cell \n", "106 CD11b_Cytoplasm_Intensity_Average CD11b cytoplasm \n", "107 CD11b_Nucleus_Intensity_Average CD11b nucleus \n", "\n", " round_color \\\n", "0 [0.28685356234627135, 0.13009829239513535, 0.2... \n", "1 [0.28685356234627135, 0.13009829239513535, 0.2... \n", "2 [0.28685356234627135, 0.13009829239513535, 0.2... \n", "3 [0.28685356234627135, 0.13009829239513535, 0.2... \n", "4 [0.28685356234627135, 0.13009829239513535, 0.2... \n", ".. ... \n", "103 [0.7684256891219349, 0.8992667116749021, 0.817... \n", "104 [0.7684256891219349, 0.8992667116749021, 0.817... \n", "105 [0.7684256891219349, 0.8992667116749021, 0.817... \n", "106 [0.7684256891219349, 0.8992667116749021, 0.817... \n", "107 [0.7684256891219349, 0.8992667116749021, 0.817... \n", "\n", " channel_color \n", "0 [0.00784313725490196, 0.24313725490196078, 1.0] \n", "1 [0.00784313725490196, 0.24313725490196078, 1.0] \n", "2 [0.00784313725490196, 0.24313725490196078, 1.0] \n", "3 [1.0, 0.48627450980392156, 0.0] \n", "4 [1.0, 0.48627450980392156, 0.0] \n", ".. ... \n", "103 [0.10196078431372549, 0.788235294117647, 0.219... \n", "104 [0.10196078431372549, 0.788235294117647, 0.219... \n", "105 [0.9098039215686274, 0.0, 0.043137254901960784] \n", "106 [0.9098039215686274, 0.0, 0.043137254901960784] \n", "107 [0.9098039215686274, 0.0, 0.043137254901960784] \n", "\n", "[108 rows x 10 columns]" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Add in the color information in both RGB (range 0-1) and hex values, for use in visualizations\n", "metadata['round_color'] = metadata.apply(lambda row: round_color_dict[row['Round']], axis = 1)\n", "metadata['channel_color'] = metadata.apply(lambda row: channel_color_dict[row['Channel']], axis = 1)\n", "\n", "metadata" ] }, { "cell_type": "code", "execution_count": 78, "id": "9cca88fa", "metadata": {}, "outputs": [], "source": [ "import hvplot.pandas\n", "import numpy as np\n", "import pandas as pd\n", "import panel as pn\n", "\n", "PRIMARY_COLOR = \"#0072B5\"\n", "SECONDARY_COLOR = \"#B54300\"\n", "CSV_FILE = (\n", " \"https://raw.githubusercontent.com/holoviz/panel/main/examples/assets/occupancy.csv\"\n", ")" ] }, { "cell_type": "code", "execution_count": 79, "id": "3c7402e9", "metadata": {}, "outputs": [], "source": [ "def transform_data(variable, window, sigma):\n", " \"\"\"Calculates the rolling average and identifies outliers\"\"\"\n", " avg = metadata[variable].rolling(window=window).mean()\n", " residual = metadata[variable] - avg\n", " std = residual.rolling(window=window).std()\n", " outliers = np.abs(residual) > std * sigma\n", " return avg, avg[outliers]\n", "\n", "\n", "def get_plot(variable=\"Exp\", window=30, sigma=10):\n", " \"\"\"Plots the rolling average and the outliers\"\"\"\n", " avg, highlight = transform_data(variable, window, sigma)\n", " return avg.hvplot(\n", " height=300, legend=False, color=PRIMARY_COLOR\n", " ) * highlight.hvplot.scatter(color=SECONDARY_COLOR, padding=0.1, legend=False)" ] }, { "cell_type": "code", "execution_count": 80, "id": "38636bb3", "metadata": {}, "outputs": [], "source": [ "variable_widget = pn.widgets.Select(name=\"Target\", value=\"Exp\", options=list(metadata.columns))\n", "window_widget = pn.widgets.IntSlider(name=\"window\", value=30, start=1, end=60)\n", "sigma_widget = pn.widgets.IntSlider(name=\"sigma\", value=10, start=0, end=20)" ] }, { "cell_type": "code", "execution_count": 81, "id": "a4785336", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":Overlay\n", " .Curve.Exp :Curve [index] (Exp)\n", " .Scatter.Exp :Scatter [index] (Exp)" ] }, "execution_count": 81, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "8c06a97e-378a-4028-a51c-8b8fbb1cf019" } }, "output_type": "execute_result" } ], "source": [ "get_plot(variable='Exp', window=20, sigma=10)" ] }, { "cell_type": "code", "execution_count": 82, "id": "39f7b3e6", "metadata": {}, "outputs": [], "source": [ "bound_plot = pn.bind(\n", " get_plot, variable=variable_widget, window=window_widget, sigma=sigma_widget\n", ")" ] }, { "cell_type": "code", "execution_count": 83, "id": "c58b4fb2", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ "Column\n", " [0] Column(sizing_mode='fixed', width=300)\n", " [0] Select(name='Target', options=['Round', 'Target', ...], value='Exp')\n", " [1] IntSlider(end=60, name='window', start=1, value=30)\n", " [2] IntSlider(end=20, name='sigma', value=10)\n", " [1] ParamFunction(function, _pane=HoloViews, defer_load=False)" ] }, "execution_count": 83, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "31cb1aa6-32cb-4971-9559-0aecc17d32d4" } }, "output_type": "execute_result" } ], "source": [ "widgets = pn.Column(variable_widget, window_widget, sigma_widget, sizing_mode=\"fixed\", width=300)\n", "pn.Column(widgets, bound_plot)" ] }, { "cell_type": "markdown", "id": "f0642911-7a0b-49f6-9598-c8975b188807", "metadata": {}, "source": [ "## I.8. SAVE" ] }, { "cell_type": "code", "execution_count": 68, "id": "67b33926-3ecf-415d-b67e-09d1054eab62", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Do you want to overwrite all existing files without confirmation? (yes/no): \n" ] }, { "ename": "KeyboardInterrupt", "evalue": "Interrupted by user", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[68], line 13\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFile \u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m+\u001b[39m filename \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m was overwritten!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 12\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m---> 13\u001b[0m user_response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28minput\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFile by name \u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m+\u001b[39m filename \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m already exists. Do you want to overwrite it? (yes/no): \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 14\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m user_response\u001b[38;5;241m.\u001b[39mlower()\u001b[38;5;241m.\u001b[39mstrip() \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124myes\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 15\u001b[0m df_save \u001b[38;5;241m=\u001b[39m df\u001b[38;5;241m.\u001b[39mloc[df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mSample_ID\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m sample, :]\n", "File \u001b[0;32m/opt/anaconda3/lib/python3.11/site-packages/ipykernel/kernelbase.py:1262\u001b[0m, in \u001b[0;36mKernel.raw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 1260\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mraw_input was called, but this frontend does not support input requests.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 1261\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m StdinNotImplementedError(msg)\n\u001b[0;32m-> 1262\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_input_request(\n\u001b[1;32m 1263\u001b[0m \u001b[38;5;28mstr\u001b[39m(prompt),\n\u001b[1;32m 1264\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_parent_ident[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mshell\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[1;32m 1265\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mget_parent(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mshell\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 1266\u001b[0m password\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[1;32m 1267\u001b[0m )\n", "File \u001b[0;32m/opt/anaconda3/lib/python3.11/site-packages/ipykernel/kernelbase.py:1305\u001b[0m, in \u001b[0;36mKernel._input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 1302\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[1;32m 1303\u001b[0m \u001b[38;5;66;03m# re-raise KeyboardInterrupt, to truncate traceback\u001b[39;00m\n\u001b[1;32m 1304\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInterrupted by user\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1305\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m(msg) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1306\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m:\n\u001b[1;32m 1307\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlog\u001b[38;5;241m.\u001b[39mwarning(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid Message:\u001b[39m\u001b[38;5;124m\"\u001b[39m, exc_info\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", "\u001b[0;31mKeyboardInterrupt\u001b[0m: Interrupted by user" ] } ], "source": [ "overwrite_all = input(\"Do you want to overwrite all existing files without confirmation? (yes/no): \")\n", "overwrite_all = overwrite_all.lower().strip()\n", "\n", "for sample in ls_samples:\n", " sample_id = sample.split('.csv')[0]\n", " filename = os.path.join(output_data_dir, sample_id + \"_\" + step_suffix + \".csv\")\n", " if os.path.exists(filename):\n", " if overwrite_all == 'yes':\n", " df_save = df.loc[df['Sample_ID'] == sample, :]\n", " df_save.to_csv(filename, index=True, index_label='ID', mode='w') # 'mode='w'' overwrites the file\n", " print(\"File \" + filename + \" was overwritten!\")\n", " else:\n", " user_response = input(\"File by name \" + filename + \" already exists. Do you want to overwrite it? (yes/no): \")\n", " if user_response.lower().strip() == 'yes':\n", " df_save = df.loc[df['Sample_ID'] == sample, :]\n", " df_save.to_csv(filename, index=True, index_label='ID', mode='w') # 'mode='w'' overwrites the file\n", " print(\"File \" + filename + \" was overwritten!\")\n", " else:\n", " print(\"File was not overwritten. Moving to the next sample.\")\n", " else:\n", " df_save = df.loc[df['Sample_ID'] == sample, :]\n", " df_save.to_csv(filename, index=True, index_label='ID') # Save normally if the file doesn't exist\n", " print(\"File \" + filename + \" was created and saved !\")\n" ] }, { "cell_type": "code", "execution_count": null, "id": "e41a9fb8", "metadata": {}, "outputs": [], "source": [] } ], "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.11.7" } }, "nbformat": 4, "nbformat_minor": 5 }