├── LICENSE ├── README.md ├── basic-data-handling-BAND ├── Book_01.ipynb ├── Book_02.ipynb ├── Book_03.ipynb ├── Book_04.ipynb ├── Book_05.ipynb ├── Book_06.ipynb ├── Book_07.ipynb ├── README.md ├── data │ ├── Results_01.csv │ ├── Results_02.csv │ └── TrackMate-edgeTable.csv ├── environment.yml └── images │ ├── TrackMate-image_01.png │ └── TrackMate-image_02.png ├── basic-data-handling ├── Book_01.ipynb ├── Book_02.ipynb ├── Book_03.ipynb ├── Book_04.ipynb ├── Book_05.ipynb ├── Book_06.ipynb ├── Book_07.ipynb ├── README.md ├── data │ ├── Results_01.csv │ ├── Results_02.csv │ └── TrackMate-edgeTable.csv ├── environment.yml └── images │ ├── TrackMate-image_01.png │ └── TrackMate-image_02.png ├── short-lectures-demos ├── data │ ├── 100x_A_ckitneg_02.oib │ └── rice.tif ├── pyBIAS_2h_240926 │ ├── .ipynb_checkpoints │ │ ├── book-01-rice-example-checkpoint.ipynb │ │ ├── book-02-quick-example-BIAS-checkpoint.ipynb │ │ └── environment-checkpoint.yml │ ├── LICENSE │ ├── README.md │ ├── book-01-rice-example.ipynb │ ├── book-02-quick-example-BIAS.ipynb │ ├── environment.yml │ └── imshow-test.py ├── quick_demo_220503 │ ├── 01_napari_from_script.py │ ├── 02_napari_load_view.ipynb │ ├── 03_segmentation.ipynb │ ├── 04_filtering.ipynb │ ├── 05_quantification.ipynb │ ├── 06_assitant-example.ipynb │ └── environment.yml └── quick_demo_220928 │ ├── 01_napari_from_script.py │ ├── 02_napari_load_view.ipynb │ ├── 03_segmentation.ipynb │ ├── 04_filtering.ipynb │ ├── README.md │ ├── data │ ├── rice.tif │ ├── rice_lbl.tif │ └── rice_mask.tif │ └── environment.yml └── short_examples ├── alignment ├── fast_alignment.ipynb └── im_data.png ├── webknossos └── wk-datasets-annotation-101.ipynb └── zarr-from-tiles ├── data ├── t01.tif ├── t02.tif ├── t03.tif ├── t04.tif ├── t05.tif └── tile_centre.csv └── zarr-minimal-example-tiles.ipynb /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rafael Camacho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | 3 | # Teaching Bioimage Analysis with Python 4 | 5 | List of resources used during different courses, workshops, events, etc. 6 | 7 | ## Basic Introduction to Data Hanlding in Python 8 | 9 | * Material for Data Hanlding in Python, PhD Course SC00028: Introductory course to Image Analysis in Life Science [here](./basic-data-handling-BAND/). 10 | 11 | ## Quick demo on image analysis using Python 12 | 13 | * 2024-09-26 2h Demo for python programming course at GU [here](./short-lectures-demos/pyBIAS_2h_240926/) 14 | * 2022-09-28 Demo for python programming course at GU [here](./short-lectures-demos/quick_demo_220928/) 15 | * 2022-05-03 Demo for CF [here](./short-lectures-demos/quick_demo_220503/) 16 | -------------------------------------------------------------------------------- /basic-data-handling-BAND/Book_01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c7754642", 6 | "metadata": {}, 7 | "source": [ 8 | "# Book 1: How to read a csv file into a data table\n", 9 | "\n", 10 | "Here we will go over how to use ```pandas``` to read ```.csv``` files into panda´s **data_frames**, and how to make simple statistics\n", 11 | "\n", 12 | "## Simple math with just Python\n", 13 | "\n", 14 | "We will create 2 numeric variables ```a``` and ```b``` and then ```print``` their sum." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "id": "34faf413", 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "name": "stdout", 25 | "output_type": "stream", 26 | "text": [ 27 | "8\n" 28 | ] 29 | } 30 | ], 31 | "source": [ 32 | "a = 3\n", 33 | "b = 5\n", 34 | "\n", 35 | "print(a+b)" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "511c9b4d", 41 | "metadata": {}, 42 | "source": [ 43 | "Lest play a bit with strings" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 2, 49 | "id": "bc852d1d", 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "name": "stdout", 54 | "output_type": "stream", 55 | "text": [ 56 | "I am having fun\n", 57 | "I am able to do basic math, and I am having fun\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "str_1 = \"I am \"\n", 63 | "str_2 = \"having fun\"\n", 64 | "\n", 65 | "# this works very much similar to IJ Macros\n", 66 | "print(str_1 + str_2)\n", 67 | "\n", 68 | "# so called f-strings are a cool way of controlling better what info you print\n", 69 | "print(f\"{str_1} able to do basic math, and I am {str_2}\")" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "id": "d3af30eb", 75 | "metadata": {}, 76 | "source": [ 77 | "As you can se above, using numeric data and strings in Python is simple and is familar to the way we write in IJ macros. In fact IJ has a language called Jython, which you can use it to program your macros. \n", 78 | "\n", 79 | "So why to learn Python? because it is order of magnitudes better than IJ macros when doing data science operations, such as, statistics, data cleaning, modeling and plotting. The purpose of this module is just to show you how you can start working with Python and we take as an example how to load ```.csv``` files into Python and work with them.\n", 80 | "\n", 81 | "## Using Pandas to read csv files into data tables\n", 82 | "\n", 83 | "Now we will use a well known package called [pandas](https://pandas.pydata.org/) to load ```.csv``` files into data tables called **data frames**. To install ```pandas``` you can follow this [link](https://anaconda.org/conda-forge/pandas). But basically:\n", 84 | "\n", 85 | "* Go to the Anaconda Prompt\n", 86 | "* activate your conda environment:\n", 87 | "\n", 88 | "```\n", 89 | "> conda activate bias-env\n", 90 | "```\n", 91 | "* run the command: ```conda install -c conda-forge pandas```\n", 92 | "* say yes via ```y```" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 3, 98 | "id": "258031f7", 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "data": { 103 | "text/html": [ 104 | "
\n", 105 | "\n", 118 | "\n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | "
LabelAreaPerim.Circ.ARRoundSolidity
01blobs.gif42590.426410.653142.066700.483860.88542
12blobs.gif18155.213200.746111.777490.562590.94517
23blobs.gif65696.526910.884741.064720.939210.96970
34blobs.gif43079.112700.863351.061560.942010.95662
45blobs.gif47786.041630.809681.568050.637730.96657
\n", 190 | "
" 191 | ], 192 | "text/plain": [ 193 | " Label Area Perim. Circ. AR Round Solidity\n", 194 | "0 1 blobs.gif 425 90.42641 0.65314 2.06670 0.48386 0.88542\n", 195 | "1 2 blobs.gif 181 55.21320 0.74611 1.77749 0.56259 0.94517\n", 196 | "2 3 blobs.gif 656 96.52691 0.88474 1.06472 0.93921 0.96970\n", 197 | "3 4 blobs.gif 430 79.11270 0.86335 1.06156 0.94201 0.95662\n", 198 | "4 5 blobs.gif 477 86.04163 0.80968 1.56805 0.63773 0.96657" 199 | ] 200 | }, 201 | "execution_count": 3, 202 | "metadata": {}, 203 | "output_type": "execute_result" 204 | } 205 | ], 206 | "source": [ 207 | "# by using the import command I make the pandas library available to me, the \"as pd\" is\n", 208 | "# a good practice. This way if I wan to use a function/method from pandas I always start\n", 209 | "# by pd.\n", 210 | "import pandas as pd \n", 211 | "\n", 212 | "# load csv file into a data_frame, think of it as a table of spread sheet\n", 213 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 214 | "\n", 215 | "# there is a nice command for you to explore what is inside a data_frame, its called head.\n", 216 | "df1.head()" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "id": "7f98f459", 222 | "metadata": {}, 223 | "source": [ 224 | "## dtypes:\n", 225 | "Tells you if your table was loaded \"properly\"\n", 226 | "\n", 227 | "object -> string or mixed\n", 228 | "\n", 229 | "int64 -> integer\n", 230 | "\n", 231 | "float64 -> float\n", 232 | "\n", 233 | "bool -> logical true/false" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": 4, 239 | "id": "a8036b14", 240 | "metadata": {}, 241 | "outputs": [ 242 | { 243 | "data": { 244 | "text/plain": [ 245 | " int64\n", 246 | "Label object\n", 247 | "Area int64\n", 248 | "Perim. float64\n", 249 | "Circ. float64\n", 250 | "AR float64\n", 251 | "Round float64\n", 252 | "Solidity float64\n", 253 | "dtype: object" 254 | ] 255 | }, 256 | "execution_count": 4, 257 | "metadata": {}, 258 | "output_type": "execute_result" 259 | } 260 | ], 261 | "source": [ 262 | "df1.dtypes" 263 | ] 264 | }, 265 | { 266 | "cell_type": "markdown", 267 | "id": "a8734237", 268 | "metadata": {}, 269 | "source": [ 270 | "# Getting basic statistics\n", 271 | "\n", 272 | "Now that we have tabular data, then we can do classical operations like calculating the mean value of a particular column. See the example below but also type your own so you see the power of auto completion." 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 5, 278 | "id": "e87889d4", 279 | "metadata": {}, 280 | "outputs": [ 281 | { 282 | "data": { 283 | "text/plain": [ 284 | "np.float64(355.4754098360656)" 285 | ] 286 | }, 287 | "execution_count": 5, 288 | "metadata": {}, 289 | "output_type": "execute_result" 290 | } 291 | ], 292 | "source": [ 293 | "# very basic way of gettng the mean\n", 294 | "df1[\"Area\"].mean()" 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "id": "39f1f193", 300 | "metadata": {}, 301 | "source": [ 302 | "Now if you want to have better control when printing values I recommend that you get familiar with f-strings. It is a very nice way of controlling how you print the information to the user. Below an exampe:" 303 | ] 304 | }, 305 | { 306 | "cell_type": "code", 307 | "execution_count": 6, 308 | "id": "8687e69d", 309 | "metadata": {}, 310 | "outputs": [ 311 | { 312 | "name": "stdout", 313 | "output_type": "stream", 314 | "text": [ 315 | "The mean value of Area is: 355.475.\n" 316 | ] 317 | } 318 | ], 319 | "source": [ 320 | "# Let us store the mean value into a variable called val\n", 321 | "val = df1[\"Area\"].mean()\n", 322 | "# then I can use a f-string to print the value, and also format the way it will be printed\n", 323 | "# the format is indicated by the text after the :, in this example :.3f means than only\n", 324 | "# 3 numbers will be printed after the decimal point\n", 325 | "print(f\"The mean value of Area is: {val:.3f}.\")" 326 | ] 327 | }, 328 | { 329 | "cell_type": "markdown", 330 | "id": "61779d43", 331 | "metadata": {}, 332 | "source": [ 333 | "We can also get a simple summary of statistics" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": 7, 339 | "id": "b07f98d4", 340 | "metadata": {}, 341 | "outputs": [ 342 | { 343 | "data": { 344 | "text/plain": [ 345 | "count 61.000000\n", 346 | "mean 355.475410\n", 347 | "std 208.090173\n", 348 | "min 14.000000\n", 349 | "25% 202.000000\n", 350 | "50% 368.000000\n", 351 | "75% 500.000000\n", 352 | "max 886.000000\n", 353 | "Name: Area, dtype: float64" 354 | ] 355 | }, 356 | "execution_count": 7, 357 | "metadata": {}, 358 | "output_type": "execute_result" 359 | } 360 | ], 361 | "source": [ 362 | "df1[\"Area\"].describe()" 363 | ] 364 | } 365 | ], 366 | "metadata": { 367 | "kernelspec": { 368 | "display_name": "phd-bias-env", 369 | "language": "python", 370 | "name": "python3" 371 | }, 372 | "language_info": { 373 | "codemirror_mode": { 374 | "name": "ipython", 375 | "version": 3 376 | }, 377 | "file_extension": ".py", 378 | "mimetype": "text/x-python", 379 | "name": "python", 380 | "nbconvert_exporter": "python", 381 | "pygments_lexer": "ipython3", 382 | "version": "3.10.14" 383 | } 384 | }, 385 | "nbformat": 4, 386 | "nbformat_minor": 5 387 | } 388 | -------------------------------------------------------------------------------- /basic-data-handling-BAND/Book_05.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Book 5: Statistical tests using Pandas and Scipy\n", 8 | "\n", 9 | "Here we will go over how to use ```pandas``` to read several ```.csv``` files, **concatenate** them into a single table, and then use ```scipy``` for statistical tests.\n", 10 | "\n", 11 | "## Load the data\n", 12 | "Let us use what we learned before to load the ```.csv``` table into a data frame" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [ 20 | { 21 | "data": { 22 | "text/html": [ 23 | "
\n", 24 | "\n", 37 | "\n", 38 | " \n", 39 | " \n", 40 | " \n", 41 | " \n", 42 | " \n", 43 | " \n", 44 | " \n", 45 | " \n", 46 | " \n", 47 | " \n", 48 | " \n", 49 | " \n", 50 | " \n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | "
LabelAreaPerim.Circ.ARRoundSolidityStudent
20blobs.gif14844.870060.923761.187250.842280.9250001
101blobs.gif16748.041630.909271.290540.774870.9329602
13blobs.gif8834.384780.935321.224060.816950.9214701
29blobs.gif53386.083260.903861.207890.827890.9517901
75blobs.gif44878.426410.915301.207340.828270.9471502
\n", 109 | "
" 110 | ], 111 | "text/plain": [ 112 | " Label Area Perim. Circ. AR Round Solidity Student\n", 113 | "20 blobs.gif 148 44.87006 0.92376 1.18725 0.84228 0.92500 01\n", 114 | "101 blobs.gif 167 48.04163 0.90927 1.29054 0.77487 0.93296 02\n", 115 | "13 blobs.gif 88 34.38478 0.93532 1.22406 0.81695 0.92147 01\n", 116 | "29 blobs.gif 533 86.08326 0.90386 1.20789 0.82789 0.95179 01\n", 117 | "75 blobs.gif 448 78.42641 0.91530 1.20734 0.82827 0.94715 02" 118 | ] 119 | }, 120 | "execution_count": 2, 121 | "metadata": {}, 122 | "output_type": "execute_result" 123 | } 124 | ], 125 | "source": [ 126 | "import pandas as pd\n", 127 | "\n", 128 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 129 | "df1['Student'] = '01'\n", 130 | "\n", 131 | "df2 = pd.read_csv('./data/Results_02.csv')\n", 132 | "df2['Student'] = '02'\n", 133 | "\n", 134 | "# concatenate\n", 135 | "df = pd.concat([df1, df2])\n", 136 | "df.reset_index(drop=True, inplace=True)\n", 137 | "df.drop(' ', axis=1, inplace=True)\n", 138 | "df.sample(5)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 3, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "data": { 148 | "text/plain": [ 149 | "" 150 | ] 151 | }, 152 | "execution_count": 3, 153 | "metadata": {}, 154 | "output_type": "execute_result" 155 | }, 156 | { 157 | "data": { 158 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAAHNCAYAAAATwgHBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA3XUlEQVR4nO3de1yUdf7//+fIDMPBI6iMGCqaeQjLU1lqK6WibeZWa25ZmWVlarWsp7LDqn1KyvLw3Vx1LVNXM9taLddVA00tU4tozbSyk3lIiNUIRBAHfP/+8MdsIx5AkME3j/vtxg2v97yv97yu65pr5ul1GBzGGCMAAACL1Ah0AQAAABWNgAMAAKxDwAEAANYh4AAAAOsQcAAAgHUIOAAAwDoEHAAAYB0CDgAAsA4BBwAAWIeAg2phwYIFcjgcfj8NGjRQfHy8Vq5cGejyfJo1a6YhQ4aUeb68vDxNnDhRGzZsqPCabBUfH6/4+Piz9nM4HHrooYfOez379u3TiBEjdMkllyg0NFQRERFq166d7r//fu3bt8/Xb9WqVZo4ceJ5qWHixIlyOBznZexiBw4c0MSJE7Vt27bz+jwAAQfVyvz587VlyxZt3rxZc+fOVVBQkG688Ub961//CnRp5ZKXl6dJkyYRcC5Q+/fvV8eOHZWSkqJRo0Zp1apVevXVV3X77bcrNTVV33//va/vqlWrNGnSpABWWz4HDhzQpEmTCDg475yBLgCoTHFxcercubNvum/fvqpXr55ef/113XjjjQGs7MKSl5ensLCwQJdhjZdfflkHDx7Uxx9/rNjYWF/7TTfdpMcff1zHjx8PYHXAhYkjOKjWQkJCFBwcLJfL5df+888/a8SIEWrcuLGCg4PVvHlzPfHEEyooKJAkHT16VB06dNDFF1+s7Oxs33wZGRnyeDyKj49XUVGRJGnIkCGqWbOmdu7cqZ49eyo8PFwNGjTQQw89pLy8vLPWuHfvXt15551q2LCh3G632rRpo6lTp/o+9H744Qc1aNBAkjRp0iTfKbiznerauXOnEhISFBYWpgYNGmjkyJH697//LYfD4XckKD4+XnFxcXr//ffVtWtXhYWF6d577y1VbZK0YcOGEmMW1+1wOLRgwQJfW1nWlTFGs2bNUvv27RUaGqp69eppwIABfkc7ivtNmTJFTZs2VUhIiDp27KjVq1efdb2f7G9/+5suueQSud1utW3bVkuXLvVbFqfTqaSkpBLzvf/++3I4HHrzzTdPO/ahQ4dUo0YNNWzY8JSP16hx4q16yJAh+utf/ypJfqdbf/jhh1Ouz2IOh6PEaa1///vfat++vdxut2JjY/Xiiy+e8rlLu56LXyepqam65pprFBYWpubNm+u5557zvR42bNigK664QpJ0zz33+Oo/X6fcUM0ZoBqYP3++kWS2bt1qvF6vOXbsmNm3b5955JFHTI0aNcyaNWt8ffPz881ll11mwsPDzYsvvmiSk5PNU089ZZxOp/ntb3/r6/f111+bWrVqmVtuucUYY0xRUZG57rrrTMOGDc2BAwd8/e6++24THBxsmjRpYp599lmTnJxsJk6caJxOp+nXr59fnU2bNjV33323bzozM9M0btzYNGjQwMyZM8esWbPGPPTQQ0aSGT58uDHGmKNHj5o1a9YYSWbo0KFmy5YtZsuWLebbb7897fo4cOCAiYyMNE2aNDELFiwwq1atMnfddZdp1qyZkWTWr1/v69ujRw8TERFhYmJizEsvvWTWr19vNm7cWKrajDFm/fr1JcY0xpjdu3cbSWb+/PnntK7uv/9+43K5zOjRo82aNWvMkiVLTOvWrU1UVJTJyMjw9ZswYYJv3axevdrMnTvXNG7c2Hg8HtOjR4/TrqNikkxMTIxp27atef31182KFStM3759jSTz5ptv+vrdfPPNpkmTJqawsNBv/ltvvdVER0cbr9d72udYvHixkWQSEhLMmjVrTHZ29in7ffvtt2bAgAFGkm87b9myxRw9evSU6/PXyzBhwgTf9Nq1a01QUJDp3r27WbZsmXnzzTfNFVdcYZo0aWJO/lgo7Xru0aOHiYyMNC1btjRz5swxKSkpZsSIEUaSWbhwoTHGmOzsbN+++OSTT/rq37dv32nXDXCuCDioForfVE/+cbvdZtasWX5958yZYySZf/zjH37tzz//vJFkkpOTfW1vvPGGkWRmzJhh/vznP5saNWr4PW7MiQ9tSeb//b//59f+7LPPGklm06ZNvraTA85jjz1mJJmPPvrIb97hw4cbh8Nhdu3aZYwx5r///W+JD7EzGTt2rHE4HGbnzp1+7X369DllwJFk1q1b59e3tLWVNeCUZl1t2bLFSDJTp07167dv3z4TGhpqxo0bZ4wxJisry4SEhJibb77Zr9+HH35oJJU64ISGhvp9mBcWFprWrVubiy++2NdWvJzLly/3tf3444/G6XSaSZMmnfE5jh8/boYNG2Zq1KhhJBmHw2HatGlj/vSnP5ndu3f79R05cmSJEGLMqdfnr5fh16+NLl26mOjoaJOfn+9ry8nJMREREX5jl3Y9G/O/18nJr4e2bduaPn36+KZTU1NPWydQkThFhWrl73//u1JTU5WamqrVq1fr7rvv1siRIzVz5kxfn/fee0/h4eEaMGCA37zFp3zWrVvnaxs4cKCGDx+usWPH6plnntHjjz+u3r17n/K577jjDr/pQYMGSZLWr19/2nrfe+89tW3bVldeeWWJWowxeu+9986+0KewceNGxcXFqW3btn7tt99++yn716tXT9ddd12l1CadfV2tXLlSDodDd955pwoLC30/Ho9Hl19+ue902JYtW3T06NES43Xt2lVNmzYtdT09e/ZUVFSUbzooKEh/+MMf9O2332r//v2STpyiufzyy32nkCRpzpw5cjgceuCBB844vsPh0Jw5c/T9999r1qxZuueee+T1ejV9+nRdeuml2rhxY6lrPZsjR44oNTVVt9xyi0JCQnzttWrVKnEdWmnXczGPx1Pi9XDZZZdpz549FVY/UFpcZIxqpU2bNiUuMt6zZ4/GjRunO++8U3Xr1tWhQ4fk8XhK3C7bsGFDOZ1OHTp0yK/93nvv1ezZsxUcHKxHHnnklM/rdDoVGRnp1+bxeCSpxHi/dujQITVr1qxEe3R09FnnPZNDhw75Xcxa7Ncf4r/WqFGjSqutNOvqp59+kjHmtPU2b97cr3/x/KcaszTONP+hQ4d00UUXSZIeeeQR3Xfffdq1a5eaN2+ul19+WQMGDCj1czVt2lTDhw/3Tf/jH//Q7bffrrFjx+rjjz8udb1nkpWVpePHj5dqnZR2PRc7ebtJktvtVn5+fjkqBs4NAQfV3mWXXaZ3331XX3/9ta688kpFRkbqo48+kjHGL+RkZmaqsLBQ9evX97UdOXJEd911ly655BL99NNPuu+++/TOO++UeI7CwkIdOnTI7wMgIyND0qk/FIpFRkYqPT29RPuBAwckya+WsoiMjNRPP/1Uor24ppOd6rtRSltb8VGC4gu0ix08ePCUz1WadVW/fn05HA598MEHcrvdJcYobivuf6rlysjIOGVAO5XTzf/r55BOHGl69NFH9de//lVXXXWVMjIyNHLkyFI9x6kMHDhQSUlJ2rFjx1n7nm49nxw069WrJ4fDccZlKlba9QxURZyiQrVX/H0cxXci9ezZU7m5uXr77bf9+v3973/3PV7swQcf1N69e7Vs2TLNmzdPK1as0PTp00/5PK+99prf9JIlSyTpjF8217NnT33xxRf69NNPS9TicDh07bXXSvrfB01p/6fco0cP7dixQ1988YVf+6/vDDqb0tZWHCK2b9/u12/FihWnHfts66pfv34yxujHH39U586dS/y0a9dOknTVVVcpJCSkxHibN28u02mTdevW+QXCoqIivfHGG2rRooXv6I10ImQ88MADWrhwoaZNm6b27durW7duZx3/VEFRknJzc7Vv3z7fUTHp9Ns6KipKISEhJdbzyYE7PDxcV155pZYtW6ajR4/62g8fPlzi+6BKu57LoqyvVeCcBfD6H6DSFF9kPH/+fN+dGytXrjT33nuvkeR3EWrxXVS1atUy06ZNMykpKWbChAnG5XL53UX18ssvl7hY8qGHHjIul8vvQssz3Rl0/fXX+9V5uruoPB6PmTt3rnn33XfNI488YhwOhxkxYkSJeVu1amXeffddk5qaWuLi1F/78ccf/e6iWr16tbnrrrtM06ZNjSSzceNGX98ePXqYSy+9tMQYZamtV69epl69eubll182ycnJ5tFHHzUtW7Ys011UJ6+rBx54wISFhZmxY8eaf/3rX+a9994zr732mhk+fLjfheNPPvmk7y6qNWvWmJdffrnC7qJaunRpif779+83TqfTSDKvvPLKWcc35sSFw+3btzdJSUlm9erVZsOGDWb+/PmmU6dORpJ59dVXfX2LX8sTJkwwW7duNampqaagoMAYY8x9991nQkJCzNSpU83atWvN5MmTTVxcXImLjJOTk02NGjVM9+7dzfLly81bb71lrrjiChMTE1PiAubSrufTvU7uvvtu07RpU9/0kSNHTGhoqOnWrZtZv369SU1NNT/++GOp1hNQFgQcVAunuouqTp06pn379mbatGnm6NGjfv0PHTpkHnzwQdOoUSPjdDpN06ZNzfjx4339tm/fbkJDQ/3CiDEnbtnu1KmTadasmcnKyjLGnHiDDw8PN9u3bzfx8fEmNDTUREREmOHDh5vc3Fy/+U8OOMYYs2fPHjNo0CATGRlpXC6XadWqlXnhhRdMUVGRX7+1a9eaDh06GLfbbSSVGOdkO3bsML169TIhISEmIiLCDB061CxcuNBIMp999pmv3+k+uMpSW3p6uhkwYICJiIgwderUMXfeeaf55JNPThlwSruujDHm1VdfNV26dDHh4eEmNDTUtGjRwgwePNh88sknvj7Hjx83SUlJJiYmxgQHB5vLLrvM/Otf/zI9evQodcAZOXKkmTVrlmnRooVxuVymdevW5rXXXjvtPPHx8SYiIsLk5eWddXxjjNm6dasZOXKkufzyy01ERIQJCgoyDRo0MH379jWrVq3y61tQUGDuu+8+06BBA+NwOIwkX5jNzs429913n4mKijLh4eHmxhtvND/88MMp77BbsWKFueyyy3yB8rnnnvPdUn+y0qzn0gYcY4x5/fXXTevWrY3L5SrT3X9AWTiMMabSDhcB1dCQIUP01ltvKTc3N9ClnNUDDzyg119/XYcOHVJwcHClP/+FtK5OJzMzU02bNtXDDz+sKVOmBLocoNriImOgmnr66acVHR2t5s2bKzc3VytXrtQrr7yiJ598MiDh5kK3f/9+ff/993rhhRdUo0YN/fGPfwx0SUC1RsABqimXy6UXXnhB+/fvV2FhoVq2bKlp06bxwXyOXnnlFT399NNq1qyZXnvtNTVu3DjQJQHVGqeoAACAdbhNHAAAWIeAAwAArEPAARAQf/nLX+RwOBQXFxfoUgBYiIADICBeffVVSdLOnTv10UcfBbgaALYh4ACodJ988ok+++wz3XDDDZKkefPmnXWeoqKiEn9nCQBOh4ADoNIVB5rnnntOXbt21dKlS5WXl+d7/IcffpDD4dCUKVP0zDPPKDY2Vm63W+vXr5d0IiD1799fERERCgkJUYcOHfSPf/zD7zn++9//asSIEWrbtq1q1qyphg0b6rrrrtMHH3xQeQsKIGAIOAAqVX5+vl5//XVdccUViouL07333qvDhw/rzTffLNH3L3/5i9577z29+OKLWr16tVq3bq3169erW7du+uWXXzRnzhy98847at++vf7whz9owYIFvnl//vlnSdKECRP073//W/Pnz1fz5s0VHx+vDRs2VNLSAggUvgcHQKVatGiRBg8erDlz5mjYsGHKzc1Vo0aN1KFDB73//vuSThzBiY2NVYsWLfTll1/K5XL55m/Tpo1CQ0P18ccfy+n833eV3njjjUpLS9P+/ftVo0bJ/7sVFRXJGKO+ffuqdu3aWrZs2flfWAABwxEcAJVq3rx5Cg0N1W233SZJqlmzpm699VZ98MEH+uabb/z69u/f3y/cfPvtt/rqq690xx13SJIKCwt9P7/97W+Vnp6uXbt2+frPmTNHHTt2VEhIiJxOp1wul9atW6cvv/yyEpYUQCARcABUmm+//Vbvv/++brjhBhlj9Msvv+iXX37RgAEDJP3vzqpijRo18pv+6aefJEljxoyRy+Xy+xkxYoQk6eDBg5KkadOmafjw4erSpYv++c9/auvWrUpNTVXfvn2Vn59/vhcVQIDxt6gAVJpXX31Vxhi99dZbeuutt0o8vnDhQj3zzDO+aYfD4fd4/fr1JUnjx4/XLbfccsrnaNWqlSRp8eLFio+P1+zZs/0eP3z4cLmWAcCFgYADoFIUFRVp4cKFatGihV555ZUSj69cuVJTp07V6tWrT/vlf61atVLLli312WefafLkyWd8PofDIbfb7de2fft2bdmyRTExMee+IAAuCAQcAJVi9erVOnDggJ5//nnFx8eXeDwuLk4zZ87UvHnzNH369NOO87e//U3XX3+9+vTpoyFDhqhx48b6+eef9eWXX+rTTz/13Y3Vr18//d///Z8mTJigHj16aNeuXXr66acVGxurwsLC87WYAKoIrsEBUCnmzZun4OBg3XPPPad8vH79+rr55pu1cuVK37U2p3Lttdfq448/Vt26dZWYmKhevXpp+PDhWrt2rXr16uXr98QTT2j06NGaN2+ebrjhBr3yyiuaM2eOunfvXuHLBqDq4TZxAABgHY7gAAAA6xBwAACAdQg4AADAOgQcAABgHQIOAACwDgEHAABY54L8or/jx4/rwIEDqlWrVomvcgcAAHYyxujw4cOKjo5WjRpnPkZzQQacAwcO8FXrAABUU/v27dNFF110xj4XZMCpVauWpBMLWLt27QBXg8rm9XqVnJyshIQEuVyuQJcDoBKx/1dvOTk5iomJ8eWAM7kgA07xaanatWsTcKohr9ersLAw1a5dmzc4oJph/4ekUl2ewkXGAADAOgQcAABgHQIOAACwDgEHAABYh4ADAACsQ8ABAADWIeAAAADrEHAAAIB1CDgAAMA6BBwAAGAdAg4AALAOAQcAAFjngvxjmwAA++Tl5emrr746Y5/c/AJt/vw71av/iWqGus86ZuvWrRUW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W7duevzxx7V9+3ZJUoMGDSRJdevWlcfj8U2fTW5urubNm6cXX3xRvXv3Vrt27bRw4UIVFRX5+nz33Xd6/fXX9eabb+qaa65RixYtNGbMGHXv3l3z58/39fN6vZozZ446d+6sjh076qGHHtK6desknQhooaGhvmuHPB6PgoODK2r1AKhEBBwAFer3v/+9Dhw4oBUrVqhPnz7asGGDOnbsqAULFpzzmN99952OHTumq6++2tcWERGhVq1a+aY//fRTGWN0ySWX+I4k1axZUxs3btR3333n6xcWFqYWLVr4phs1aqTMzMxzrg1A1cRFxgAqXEhIiHr37q3evXvrz3/+s+677z5NmDBBQ4YMOWX/GjVqyBjj1+b1en3/PvmxUzl+/LiCgoKUlpamoKAgv8dq1qzp+7fL5fJ7zOFwlGp8ABcWjuAAOO/atm2rI0eOSDoRMH59akk6ceqq+ELfYtu2bfP9++KLL5bL5dLWrVt9bVlZWfr666990x06dFBRUZEyMzN18cUX+/14PJ5S1xocHFyiPgAXHgIOgApz6NAhXXfddVq8eLG2b9+u3bt3680339SUKVP0u9/9TpLUrFkzrVu3ThkZGcrKypIkXXfddfrkk0/097//Xd98840mTJigHTt2+MatWbOmhg4dqrFjx2rdunXasWOHhgwZoho1/vcWdskll+iOO+7Q4MGDtWzZMu3evVupqal6/vnntWrVqlIvQ7NmzbR9+3bt2rVLBw8e9DuSBODCQcABUGFq1qypLl26aPr06frNb36juLg4PfXUU7r//vs1c+ZMSdLUqVOVkpKimJgYdejQQZLUp08fPfXUUxo3bpyuuOIKHT58WIMHD/Yb+4UXXtBvfvMb9e/fX7169VL37t3VqVMnvz7z58/X4MGDNXr0aLVq1Ur9+/fXRx99pJiYmFIvw/33369WrVqpc+fOatCggT788MNyrhUAgeAwnHwGAACW4QgOAACwDgEHAABYh4ADAACsQ8ABAADWIeAAAADrEHAAAIB1CDgAAMA6BBwAAGAdAg4AALAOAQcAAFiHgAMAAKzz/wEHrxGfgSUudwAAAABJRU5ErkJggg==", 159 | "text/plain": [ 160 | "
" 161 | ] 162 | }, 163 | "metadata": {}, 164 | "output_type": "display_data" 165 | } 166 | ], 167 | "source": [ 168 | "# simple box plot, to vissualy inspect if there are big differences between both groups\n", 169 | "df.boxplot(column=\"Area\",by=\"Student\")" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "## Using Scipy for Statistical Testing\n", 177 | "\n", 178 | "When performing a **statistical test**, we start with a **null hypothesis (H0)** and aim to **falsify** it. The **null hypothesis (H0)** typically posits that there is no relationship (or difference) between the distributions being tested. To evaluate whether **H0** is false, we use the **p-value**. The **p-value** estimates how likely it is to observe the differences between the two sets if the null hypothesis were true. For example, a p-value of 0.04 means there is a 4% chance that **H0** is true, which suggests that we report a statistically significant relationship (or difference) between the distributions. Note that the p-value does not indicate the importance or biological relevance of the observed relationship.\n", 179 | "\n", 180 | "## Scipy\n", 181 | "\n", 182 | "[Scipy](https://scipy.org/) is a comprehensive package for scientific computing widely used in Python. It is included in our virtual environment due to previously installed packages. To check if it is installed, try running the block below. If you encounter issues, you can [install Scipy](https://anaconda.org/conda-forge/scipy) using the following command:" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 4, 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [ 191 | "# this time I am loading part of the library, the part called stats\n", 192 | "from scipy import stats \n", 193 | "# as this runs, we are good to continue" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": {}, 199 | "source": [ 200 | "For clarity let us get out the numbers of interest from the data table by using the ```query``` method of pandas data_frames. ```query``` allows us to extract values from a column while filtering based ob the values of another. Bellow, I ```query``` for the **Area** values that belong to **Student 01** and **02** respectively." 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 5, 206 | "metadata": {}, 207 | "outputs": [], 208 | "source": [ 209 | "Area_s1=df.query(\"Student == '01'\")['Area']\n", 210 | "Area_s2=df.query(\"Student == '02'\")['Area']" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "One of the most common mistakes while doing statistical testing is to use a particular method, e.g. t-test, whitout checkig first that the underlying assumptions of the test are true. In general we must check the following to know what tests we can use:\n", 218 | "\n", 219 | "* Independence: each meassurement of the variables is independent of each other\n", 220 | "\n", 221 | "* Normality: the data follows a normal distribution (Gaussian distribution)\n", 222 | "\n", 223 | "* Homogeneous variance: the variance (spread around the mean) within each group being compared is similar\n", 224 | "\n", 225 | "\n", 226 | "## Homogeneity\n", 227 | "Lets us first test for homogeneous variance " 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 6, 233 | "metadata": {}, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/plain": [ 238 | "LeveneResult(statistic=np.float64(0.1985044133097972), pvalue=np.float64(0.65671395315861))" 239 | ] 240 | }, 241 | "execution_count": 6, 242 | "metadata": {}, 243 | "output_type": "execute_result" 244 | } 245 | ], 246 | "source": [ 247 | "# homogeneity\n", 248 | "stats.levene(Area_s1, Area_s2)" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "metadata": {}, 254 | "source": [ 255 | "Interpretation:\n", 256 | "* Levene's Test Statistic: 0.1985: This value by itself doesn't tell us much. It's used to calculate the p-value.\n", 257 | "* P-value: 0.6567: This is the key value for interpretation. The p-value is much larger than the typical significance levels (0.05 or 0.01).\n", 258 | "\n", 259 | "How to interpret:\n", 260 | "1. Null Hypothesis (H0): The variances of the two groups (Area_s1 and Area_s2) are equal (homogeneous).\n", 261 | "2. Alternative Hypothesis (Ha): The variances of the two groups are not equal (heterogeneous).\n", 262 | "3. Decision Rule:\n", 263 | " * If p-value < significance level (usually 0.05), reject the null hypothesis.\n", 264 | " * If p-value ≥ significance level, fail to reject the null hypothesis.\n", 265 | "4. Interpretation:\n", 266 | " * Since the p-value (0.6567) is much larger than 0.05, we fail to reject the null hypothesis.\n", 267 | " * This means we do not have sufficient evidence to conclude that the variances are significantly different.\n", 268 | " * In other words, we can assume that the variances are homogeneous.\n", 269 | "\n", 270 | "Conclusion:\n", 271 | "Based on Levene's test, we can conclude that there is no significant difference in the variances of Area_s1 and Area_s2. The assumption of homogeneity of variances is met." 272 | ] 273 | }, 274 | { 275 | "cell_type": "markdown", 276 | "metadata": {}, 277 | "source": [ 278 | "## Normality\n", 279 | "\n", 280 | "Now we check is the distributions to test are normal - aka Gaussian" 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": 7, 286 | "metadata": {}, 287 | "outputs": [ 288 | { 289 | "data": { 290 | "text/plain": [ 291 | "ShapiroResult(statistic=np.float64(0.9708005068493674), pvalue=np.float64(0.15260880873570404))" 292 | ] 293 | }, 294 | "execution_count": 7, 295 | "metadata": {}, 296 | "output_type": "execute_result" 297 | } 298 | ], 299 | "source": [ 300 | "# Shapiro-Wilk test for normality\n", 301 | "stats.shapiro(Area_s1)" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "metadata": {}, 307 | "source": [ 308 | "Interpretation:\n", 309 | "1. Shapiro-Wilk Test Statistic: 0.9708\n", 310 | " * This value ranges from 0 to 1.\n", 311 | " * Values closer to 1 indicate a higher likelihood of normal distribution.\n", 312 | " * 0.9708 is fairly close to 1, suggesting the data might be normally distributed.\n", 313 | "2. P-value: 0.1526\n", 314 | " * This is the key value for interpretation.\n", 315 | " * The p-value is larger than the typical significance levels (0.05 or 0.01).\n", 316 | "\n", 317 | "How to interpret:\n", 318 | "1. Null Hypothesis (H0): The sample data (Area_s1) is normally distributed.\n", 319 | "2. Alternative Hypothesis (Ha): The sample data is not normally distributed.\n", 320 | "3. Decision Rule:\n", 321 | " * If p-value < significance level (usually 0.05), reject the null hypothesis.\n", 322 | " * If p-value ≥ significance level, fail to reject the null hypothesis.\n", 323 | "4. Interpretation:\n", 324 | " * Since the p-value (0.1526) is larger than 0.05, we fail to reject the null hypothesis.\n", 325 | " * This means we do not have sufficient evidence to conclude that the data is not normally distributed.\n", 326 | " * In other words, we can assume that Area_s1 is approximately normally distributed.\n", 327 | "\n", 328 | "Conclusion:\n", 329 | "Based on the Shapiro-Wilk test, we can conclude that there is no significant evidence against the normality of Area_s1. The data appears to be consistent with a normal distribution." 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 8, 335 | "metadata": {}, 336 | "outputs": [ 337 | { 338 | "data": { 339 | "text/plain": [ 340 | "ShapiroResult(statistic=np.float64(0.9699967276382352), pvalue=np.float64(0.12092209473947735))" 341 | ] 342 | }, 343 | "execution_count": 8, 344 | "metadata": {}, 345 | "output_type": "execute_result" 346 | } 347 | ], 348 | "source": [ 349 | "# Shapiro-Wilk test for normality\n", 350 | "stats.shapiro(Area_s2)" 351 | ] 352 | }, 353 | { 354 | "cell_type": "markdown", 355 | "metadata": {}, 356 | "source": [ 357 | "## The actual t-test\n", 358 | "\n", 359 | "Now that all seems to be good then we can run the t-test" 360 | ] 361 | }, 362 | { 363 | "cell_type": "code", 364 | "execution_count": 9, 365 | "metadata": {}, 366 | "outputs": [ 367 | { 368 | "data": { 369 | "text/plain": [ 370 | "TtestResult(statistic=np.float64(0.20792518265523485), pvalue=np.float64(0.8356312727307184), df=np.float64(123.0))" 371 | ] 372 | }, 373 | "execution_count": 9, 374 | "metadata": {}, 375 | "output_type": "execute_result" 376 | } 377 | ], 378 | "source": [ 379 | "# Independent t-test\n", 380 | "stats.ttest_ind(Area_s1, Area_s2)" 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": {}, 386 | "source": [ 387 | "The independent samples t-test is used to determine whether there is a statistically significant difference between the means of two unrelated groups.\n", 388 | "\n", 389 | "Interpretation:\n", 390 | "1. T-statistic: 0.2079\n", 391 | " * This value represents the difference between the two group means in units of standard error.\n", 392 | " * The closer this value is to 0, the more similar the group means are.\n", 393 | "2. P-value: 0.8356\n", 394 | " * This is the key value for interpretation.\n", 395 | " * The p-value is much larger than the typical significance levels (0.05 or 0.01).\n", 396 | "3. Degrees of Freedom (df): 123\n", 397 | " * This represents the sample size and complexity of the test.\n", 398 | " * It's used in calculating the p-value and critical values.\n", 399 | "\n", 400 | "How to interpret:\n", 401 | "1. Null Hypothesis (H0): There is no significant difference between the means of Area_s1 and Area_s2.\n", 402 | "2. Alternative Hypothesis (Ha): There is a significant difference between the means of Area_s1 and Area_s2.\n", 403 | "3. Decision Rule:\n", 404 | " * If p-value < significance level (usually 0.05), reject the null hypothesis.\n", 405 | " * If p-value ≥ significance level, fail to reject the null hypothesis.\n", 406 | "4. Interpretation:\n", 407 | " * Since the p-value (0.8356) is much larger than 0.05, we fail to reject the null hypothesis.\n", 408 | " * This means we do not have sufficient evidence to conclude that there is a significant difference between the means of Area_s1 and Area_s2.\n", 409 | "\n", 410 | "Conclusion:\n", 411 | "Based on the t-test results, we can conclude that there is no statistically significant difference between the means of Area_s1 and Area_s2. \n", 412 | "The observed difference between the sample means is not convincing enough to say that the average Areas differ between the two groups in the population.\n", 413 | "\n", 414 | "Practical Implications:\n", 415 | "* The two groups (s1 and s2) appear to have similar average Areas.\n", 416 | "* Any observed differences in the sample means are likely due to random chance rather than a true difference in the populations.\n", 417 | "* This result suggests that the factor distinguishing s1 and s2 (e.g., different treatments, groups, etc.) does not significantly affect the Area measurement.\n", 418 | "\n", 419 | "Remember:\n", 420 | "* Failing to reject the null hypothesis doesn't prove that the means are exactly equal, just that we don't have enough evidence to conclude they're different." 421 | ] 422 | } 423 | ], 424 | "metadata": { 425 | "kernelspec": { 426 | "display_name": "phd-bias-env", 427 | "language": "python", 428 | "name": "python3" 429 | }, 430 | "language_info": { 431 | "codemirror_mode": { 432 | "name": "ipython", 433 | "version": 3 434 | }, 435 | "file_extension": ".py", 436 | "mimetype": "text/x-python", 437 | "name": "python", 438 | "nbconvert_exporter": "python", 439 | "pygments_lexer": "ipython3", 440 | "version": "3.10.14" 441 | }, 442 | "orig_nbformat": 4 443 | }, 444 | "nbformat": 4, 445 | "nbformat_minor": 2 446 | } 447 | -------------------------------------------------------------------------------- /basic-data-handling-BAND/Book_06.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Quick example of a pivot table\n", 8 | "\n", 9 | "Inspired in the last excercise of JY we can pick up where he left and see an exaple of a pivot table\n", 10 | "\n", 11 | "A pivot table is a powerful tool that helps you summarize and analyze data quickly and easily. Imagine you have a large dataset, like a list of students and their scores in different subjects. Instead of manually calculating averages or totals, a pivot table allows you to group the data by specific categories, such as each student, and automatically calculate metrics like the sum and mean of their scores. This way, you can quickly see how each student is performing without getting lost in the details of the raw data. It's like having a smart organizer that helps you find insights and patterns in your information effortlessly!" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 3, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "name": "stdout", 21 | "output_type": "stream", 22 | "text": [ 23 | "number of cols: 125, number of rows: 9\n" 24 | ] 25 | }, 26 | { 27 | "data": { 28 | "text/html": [ 29 | "
\n", 30 | "\n", 43 | "\n", 44 | " \n", 45 | " \n", 46 | " \n", 47 | " \n", 48 | " \n", 49 | " \n", 50 | " \n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | "
Unnamed: 0LabelAreaPerim.Circ.ARRoundSolidityStudent
00blobs.gif42590.426410.653142.066700.483860.885421
11blobs.gif18155.213200.746111.777490.562590.945171
22blobs.gif65696.526910.884741.064720.939210.969701
33blobs.gif43079.112700.863351.061560.942010.956621
44blobs.gif47786.041630.809681.568050.637730.966571
\n", 121 | "
" 122 | ], 123 | "text/plain": [ 124 | " Unnamed: 0 Label Area Perim. Circ. AR Round Solidity \\\n", 125 | "0 0 blobs.gif 425 90.42641 0.65314 2.06670 0.48386 0.88542 \n", 126 | "1 1 blobs.gif 181 55.21320 0.74611 1.77749 0.56259 0.94517 \n", 127 | "2 2 blobs.gif 656 96.52691 0.88474 1.06472 0.93921 0.96970 \n", 128 | "3 3 blobs.gif 430 79.11270 0.86335 1.06156 0.94201 0.95662 \n", 129 | "4 4 blobs.gif 477 86.04163 0.80968 1.56805 0.63773 0.96657 \n", 130 | "\n", 131 | " Student \n", 132 | "0 1 \n", 133 | "1 1 \n", 134 | "2 1 \n", 135 | "3 1 \n", 136 | "4 1 " 137 | ] 138 | }, 139 | "execution_count": 3, 140 | "metadata": {}, 141 | "output_type": "execute_result" 142 | } 143 | ], 144 | "source": [ 145 | "import pandas as pd \n", 146 | "\n", 147 | "df = pd.read_csv('./data/Results_total.csv')\n", 148 | "print(f\"number of cols: {df.shape[0]}, number of rows: {df.shape[1]}\")\n", 149 | "\n", 150 | "df.head()" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "The pivot table. For some simple examples look at: https://www.machinelearningplus.com/pandas/pandas-pivot-table-in-python/" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 4, 163 | "metadata": {}, 164 | "outputs": [ 165 | { 166 | "name": "stdout", 167 | "output_type": "stream", 168 | "text": [ 169 | " sum mean\n", 170 | " AR AR\n", 171 | "Student \n", 172 | "1 98.33391 1.612031\n", 173 | "2 103.37781 1.615278\n" 174 | ] 175 | } 176 | ], 177 | "source": [ 178 | "output = pd.pivot_table(data=df, \n", 179 | " index=['Student'], \n", 180 | " #columns=['Categorical'], \n", 181 | " values='AR',\n", 182 | " aggfunc=['sum', 'mean'])\n", 183 | "\n", 184 | "print(output.head())" 185 | ] 186 | } 187 | ], 188 | "metadata": { 189 | "kernelspec": { 190 | "display_name": "Python 3.9.13 ('bias-env')", 191 | "language": "python", 192 | "name": "python3" 193 | }, 194 | "language_info": { 195 | "codemirror_mode": { 196 | "name": "ipython", 197 | "version": 3 198 | }, 199 | "file_extension": ".py", 200 | "mimetype": "text/x-python", 201 | "name": "python", 202 | "nbconvert_exporter": "python", 203 | "pygments_lexer": "ipython3", 204 | "version": "3.10.14" 205 | }, 206 | "orig_nbformat": 4, 207 | "vscode": { 208 | "interpreter": { 209 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 210 | } 211 | } 212 | }, 213 | "nbformat": 4, 214 | "nbformat_minor": 2 215 | } 216 | -------------------------------------------------------------------------------- /basic-data-handling-BAND/README.md: -------------------------------------------------------------------------------- 1 | # Basic Data Handling in Python 2 | 3 | In this session, we will focus on what to do after obtaining result tables (e.g., `.csv`) from FIJI or any other image analysis software. Many people would typically load these tables into spreadsheet programs, such as Microsoft Excel, to generate figures and perform statistical analysis. Here, we will explore an alternative workflow using Python, combined with Jupyter Notebooks, for these tasks. 4 | 5 | ## Learning Outcomes 6 | 7 | By the end of this session, you will: 8 | 9 | - Develop a basic understanding of Python for data exploration. 10 | - Learn how to load `.csv` files into Python. 11 | - Understand how to concatenate (combine) data tables. 12 | - Gain the ability to export data tables into `.csv` files or Excel sheets. 13 | - Be able to create basic plots, such as scatter plots, bar charts, and violin plots. 14 | - Perform basic data analysis and statistical tests. 15 | 16 | ### Extra information for self-study: 17 | - Learn how to install Data Science packages using conda environments. 18 | - Use VS Code to run and create Jupyter Notebooks. 19 | - Understand how to store and share your environment via `.yml` files. 20 | 21 | 22 | ## Prerequisites 23 | 24 | This year we will benefit from BAND the Bioimage ANalysis Desktop - a Desktop-as-a-Service cloub-based platform that generates a desktop environment packed with bioimage analysis tools. This will simplify the installation procedures and let us concentrate on the content of the course. Moreover I provide below a full guide on how to install the required programs on your own computer. 25 | 26 | ## What is Python? 27 | 28 | Rather than reinvent the wheel, it's best to consult established resources for an introduction to Python. You can start by exploring [this essay on the official Python website](https://www.python.org/doc/essays/blurb/) for a broad overview. 29 | 30 | For our course, the key question is: [Why is Python so widely used in data science?](https://learnpython.com/blog/why-python-used-for-science/) This resource dives into the reasons Python has become the go-to language for data analysis and scientific computing. 31 | 32 | By the end of this session, you'll gain an understanding of why so many people choose Python for data analysis, ranging from basic tasks to more advanced, complex workflows. 33 | 34 | ## Use Cases 35 | 36 | Please note that we will be skipping the installation procedure outlined below, as we will be using BAND for this course. However, interested students are encouraged to try the installation on their own laptops during the week and bring them to the session on Friday. During coffee breaks, we can discuss any issues you might encounter while installing Jupyter Notebooks on your machine. 37 | 38 | 1. [Book 1:](./Book_01.ipynb) How to read a CSV file into a data table. 39 | 2. [Book 2:](./Book_02.ipynb) How to create simple plots with Pandas and Seaborn. 40 | 3. [Book 3:](./Book_03.ipynb) How to concatenate data frames. 41 | 4. [Book 4:](./Book_04.ipynb) How to create more elaborate plots using Seaborn. 42 | 5. [Book 5:](./Book_05.ipynb) Statistical tests using Pandas and SciPy. 43 | 6. [Book 6:](./Book_06.ipynb) A quick example of creating a pivot table. 44 | 7. [Book 7:](./Book_07.ipynb) A TrackMate example: Plotting Mean Speed Over Time for a Movie. 45 | 46 | 47 | ## Installation guide 48 | 49 | We recommend using **Miniforge**, a minimal conda installer that helps avoid the overhead of the full Anaconda distribution. Miniforge allows you to install only the necessary tools and packages, providing a lightweight and efficient setup. You can follow the installation guide here: [Miniforge Installation](https://github.com/conda-forge/miniforge). 50 | 51 | Optionally, you might want to install the following programs by following the official guides: 52 | - [VS Code](https://code.visualstudio.com/docs) (for running and editing Jupyter Notebooks) 53 | - [Git](https://github.com/git-guides/install-git) (command line tools for version control - **optional**) 54 | 55 | Each of these tools has excellent online tutorials and documentation to guide you through the installation process. 56 | 57 | 58 | ## How to Install Python via Conda 59 | 60 | To make things easier, we will be using [Conda](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html) to install Python and manage our virtual environments. 61 | 62 | Think of a [virtual environment](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) as a "box" (or directory) that contains a specific collection of tools (e.g., Python + packages) that you have installed. The great thing about virtual environments is that you can have multiple boxes/environments, each tailored to a specific task or project. If you change or update one environment, your other environments remain unaffected. 63 | 64 | To work within a specific environment, we will "activate" the box we want to use. 65 | 66 | If you've worked with FIJI before, the concept of virtual environments is similar to having multiple versions of FIJI, where each copy resides in a different folder, allowing you to manage versions independently. 67 | 68 | ## Step 1: Creating a Conda Environment with Python 3.10 69 | 70 | **Prerequisite:** To follow these steps, you need to have Conda installed, and access to the Miniforge prompt on your computer. 71 | 72 | ### S1.1 Open the Miniforge Prompt: 73 | * On Windows: Click the Windows icon, search for "miniforge", and select **Miniforge Prompt**. 74 | 75 | ### S1.2 Create a new Conda environment with Python 3.10: 76 | 77 | Run the following command in the Miniforge Prompt to create a new Conda environment named `bias-env`: 78 | 79 | ```bash 80 | conda create -y -n bias-env -c conda-forge python=3.10 81 | ``` 82 | 83 | After ```Conda``` has done its job, you have successfully created a new "box" (environment) containing a copy of Python version 3.10. The name of this environment is `bias-env`, and the Conda channel we used is `conda-forge`. 84 | 85 | Think of a Conda channel like choosing a specific shop to buy your products from. In this case, `conda-forge` is the shop we are using to get the packages we need. It’s a popular channel with a large collection of up-to-date and well-maintained packages. While this is a useful concept, going deeper into Conda channels is a bit out of the scope of this session. 86 | 87 | S1.3 Now activate your conda environment: 88 | 89 | ```bash 90 | conda activate bias-env 91 | ``` 92 | 93 | S1.4 Let us check the enviornment, by asking what python is available. Use the command: 94 | 95 | ```bash 96 | python --version 97 | Python 3.10.14 98 | ``` 99 | 100 | S1.5 Activate Python. Use the command: 101 | 102 | ```bash 103 | python 104 | ``` 105 | 106 | S1.6 lets do some basic math 107 | 108 | ```python 109 | >>> a = 3 110 | >>> b = 6 111 | >>> a+b 112 | 9 113 | ``` 114 | 115 | S1.7 lets do some basic print statements 116 | ```python 117 | >>> print("Hello") 118 | Hello 119 | >>> name = "Rafa" 120 | >>> print("Hello " + name) 121 | Hello Rafa 122 | 123 | ``` 124 | This should remind you of the way we worked with strings in IJ Macro language 125 | 126 | S1.8 lets get out of python 127 | 128 | ```python 129 | >>> quit() 130 | ``` 131 | 132 | ## OPTIONAL: VS Code 133 | 134 | VS Code is a lightweight source code editor which runs on your desktop and is available for Windows, macOS and Linux. Using its extensions it is a great tool for Python and Jupyter books. 135 | 136 | How to install it (not live): please follow the [instructions here to install VS Code](https://code.visualstudio.com/docs/setup/setup-overview), and the [nice documentation here to have it ready for python.](https://code.visualstudio.com/docs/languages/python). 137 | 138 | ## Step 2 Open VS Code and create a Python file 139 | 140 | **Prerequisite** I assume you already have VS Code installed. 141 | 142 | S2.1 Open VS Code: 143 | 144 | * Go to Windows icon -> search for ```Code``` -> open Visual Studio Code 145 | 146 | S2.2 Cereate a new folder so we can work on it: 147 | 148 | * you can use cmd, or windows file explorer for this. 149 | 150 | S2.3 Open the folder in VS Code using 151 | 152 | * File -> open folder -> Yes, It trust 153 | 154 | S2.4 Create a new python file by: 155 | 156 | * create **New File** -> name it ```hello.py``` 157 | * Install the [recommended extensions](https://code.visualstudio.com/docs/languages/python) 158 | * in the file write: ```print("hello students")``` 159 | * run the file via the arrow on the top right 160 | * look at the terminal 161 | 162 | S2.5 Select an interpreter (aka virtual environment) 163 | 164 | * use Ctr + Shift + P to open the command pallete 165 | * look for ```interpreter``` 166 | * choose ```Python: Select Interpreter``` 167 | * look for the ```bias-env``` 168 | 169 | S2.6 Run again the file 170 | 171 | ## What is a Jupyter Notebook? 172 | 173 | Jupyter notebooks are an excellent tool for interactive programming in Data Science. You can explore this [informative article](https://towardsdatascience.com/the-complete-guide-to-jupyter-notebooks-for-data-science-8ff3591f69a4) to dive deeper into its benefits. Think of them as interactive notebooks where you can "attach" a Python environment and execute pieces of code in real-time, making it easy to visualize outputs and explore data. Let's do a small demo to better understand how they work. 174 | 175 | ## Installing jupyterlab in our virtual environment 176 | 177 | This step can be skiped in this demo because we already have jupyterlab installed in our base conda environment. However, if this is not the case you might have to install it separately via: 178 | 179 | * Go to the Anaconda Prompt 180 | * If you closed it, then activate again the bias-env. Follow steps S1.1 and S1.3 181 | 182 | ```bash 183 | conda install -c conda-forge jupyterlab 184 | ``` 185 | 186 | To test that it is properly installed you can run this in the command line 187 | 188 | ```bash 189 | where jupyter 190 | ``` 191 | 192 | ### Make the virtual environment available to JupyterLab 193 | To make our current environment (kernel) available to JupyterLab we can use: 194 | 195 | ```bash 196 | ipython kernel install --user --name=bias-env 197 | ``` 198 | ## Using Jupyter Notebooks 199 | 200 | You are now ready to use Jupyter notebooks via Jupyter Lab. Simply open your terminal and run the following command: 201 | 202 | ```bash 203 | jupyter lab 204 | ``` 205 | A new tab will open in your web browser, and that's it—you’re good to go! 206 | 207 | If you prefer to use VS Code instead of Jupyter Lab, please follow the instructions provided below. 208 | 209 | 210 | ## Step 3 Using VS Code to create and run Jupyter Notebooks 211 | 212 | You can go over [this guide to get many details on how to use Jupyter notebooks in VS Code](https://code.visualstudio.com/docs/datascience/jupyter-notebooks). Below a practical example. 213 | 214 | S3.1 Crete new jupyter book in VS Code 215 | 216 | * Create a new notebook by creating a new ```.ipynb``` file in your workspace. The extension resembles Ipython NoteBook 217 | 218 | * Alternatively 219 | * use Ctr + Shift + P to open the command palleteinter 220 | * look for ```jupyter``` 221 | * choose ```Python: Create: New Jupyter Notebook``` 222 | * use: File -> Save to save the file with ```.ipynb``` extension 223 | * Select your kernel AKA virtual environment 224 | * Create a cell with simple math: 225 | 226 | ```python 227 | a = 3 228 | b = 6 229 | a+b 230 | ``` 231 | 232 | * Try to run the cell. 233 | 234 | **Note** If you forgot the ipython kernel step you will notice a complaint from VS Code. In this case make sure you have ```ipykernel``` installed. 235 | 236 | 237 | S3.2 Optional Installing ```ipykernel``` 238 | 239 | * Go to the Anaconda Prompt 240 | * If you closed it, then activate again the bias-env. Follow steps S1.1 and S1.3 241 | * run the command: ```conda install ipykernel``` 242 | * say yes via ```y``` 243 | 244 | Then we make the current environment available as a jupyter kernel 245 | 246 | ```bash 247 | ipython kernel install --user --name=bias-env 248 | ``` 249 | 250 | S3.3 Run the Jupyter Notebook in VS Code once again 251 | 252 | 253 | ## Where to go next 254 | 255 | Now you are set to a great start. Feel free to play with this notebooks with basic Python if you want to get familiar with the language. There are many cool websites and videos including. 256 | 257 | * YouTube series by google team on Python: [day 1 link](https://youtu.be/tKTZoB2Vjuk) 258 | * [RealPython website](https://realpython.com/) 259 | * YouTube series by Neubias Academy on using [Python for image analysis](https://youtu.be/2KF8vBrp3Zw) 260 | * PoL Dresden [course on BioImage analysis using Python](https://github.com/BiAPoL/Bio-image_Analysis_with_Python) -------------------------------------------------------------------------------- /basic-data-handling-BAND/data/Results_01.csv: -------------------------------------------------------------------------------- 1 | ,Label,Area,Perim.,Circ.,AR,Round,Solidity 2 | 1,blobs.gif,425,90.42641,0.65314,2.06670,0.48386,0.88542 3 | 2,blobs.gif,181,55.21320,0.74611,1.77749,0.56259,0.94517 4 | 3,blobs.gif,656,96.52691,0.88474,1.06472,0.93921,0.96970 5 | 4,blobs.gif,430,79.11270,0.86335,1.06156,0.94201,0.95662 6 | 5,blobs.gif,477,86.04163,0.80968,1.56805,0.63773,0.96657 7 | 6,blobs.gif,276,60.52691,0.94672,1.11738,0.89495,0.94845 8 | 7,blobs.gif,70,29.79899,0.99061,1.13553,0.88065,0.90909 9 | 8,blobs.gif,265,61.35534,0.88461,1.38821,0.72035,0.93146 10 | 9,blobs.gif,220,54.52691,0.92985,1.12587,0.88820,0.92827 11 | 10,blobs.gif,26,26.48528,0.46577,3.84899,0.25981,0.86667 12 | 11,blobs.gif,492,82.08326,0.91763,1.07144,0.93333,0.94798 13 | 12,blobs.gif,650,96.91169,0.86970,1.33339,0.74997,0.95308 14 | 13,blobs.gif,220,54.52691,0.92985,1.13619,0.88013,0.93418 15 | 14,blobs.gif,88,34.38478,0.93532,1.22406,0.81695,0.92147 16 | 15,blobs.gif,441,77.84062,0.91461,1.20597,0.82920,0.94635 17 | 16,blobs.gif,391,85.49747,0.67217,2.45579,0.40720,0.90614 18 | 17,blobs.gif,511,83.25483,0.92643,1.17220,0.85310,0.95514 19 | 18,blobs.gif,417,76.42641,0.89714,1.43396,0.69737,0.94989 20 | 19,blobs.gif,257,59.11270,0.92423,1.33803,0.74737,0.95009 21 | 20,blobs.gif,347,68.76955,0.92203,1.16649,0.85727,0.94166 22 | 21,blobs.gif,148,44.87006,0.92376,1.18725,0.84228,0.92500 23 | 22,blobs.gif,403,73.59798,0.93494,1.08942,0.91792,0.95047 24 | 23,blobs.gif,413,84.42641,0.72812,1.80288,0.55467,0.87686 25 | 24,blobs.gif,252,58.52691,0.92448,1.14850,0.87070,0.93680 26 | 25,blobs.gif,500,87.94113,0.81245,1.66888,0.59921,0.96525 27 | 26,blobs.gif,277,61.11270,0.93202,1.12438,0.88938,0.94863 28 | 27,blobs.gif,667,102.08326,0.80432,1.48078,0.67532,0.92897 29 | 28,blobs.gif,171,53.21320,0.75887,1.75976,0.56826,0.94475 30 | 29,blobs.gif,352,68.76955,0.93532,1.21557,0.82266,0.95135 31 | 30,blobs.gif,533,86.08326,0.90386,1.20789,0.82789,0.95179 32 | 31,blobs.gif,598,109.63961,0.62514,2.74660,0.36409,0.85429 33 | 32,blobs.gif,629,103.39697,0.73934,1.93744,0.51614,0.89474 34 | 33,blobs.gif,182,49.69848,0.92597,1.15164,0.86833,0.92386 35 | 34,blobs.gif,583,88.66905,0.93182,1.08956,0.91780,0.95574 36 | 35,blobs.gif,14,13.89949,0.91063,1.31046,0.76309,0.84848 37 | 36,blobs.gif,263,59.69848,0.92734,1.26047,0.79335,0.94946 38 | 37,blobs.gif,886,129.98276,0.65898,2.51057,0.39832,0.91199 39 | 38,blobs.gif,469,87.25483,0.77411,1.72164,0.58084,0.94177 40 | 39,blobs.gif,231,55.94113,0.92760,1.18693,0.84251,0.93333 41 | 40,blobs.gif,157,46.28427,0.92096,1.26314,0.79168,0.92082 42 | 41,blobs.gif,403,75.01219,0.90002,1.36989,0.72998,0.94824 43 | 42,blobs.gif,404,73.59798,0.93726,1.24846,0.80099,0.95735 44 | 43,blobs.gif,234,55.69848,0.94785,1.13093,0.88423,0.94545 45 | 44,blobs.gif,368,70.76955,0.92335,1.27705,0.78305,0.95213 46 | 45,blobs.gif,642,93.25483,0.92769,1.11644,0.89570,0.96396 47 | 46,blobs.gif,369,70.18377,0.94138,1.13980,0.87735,0.95226 48 | 47,blobs.gif,566,87.84062,0.92180,1.04905,0.95325,0.95689 49 | 48,blobs.gif,63,36.14214,0.60607,2.94685,0.33935,0.92647 50 | 49,blobs.gif,156,45.69848,0.93871,1.26978,0.78754,0.92308 51 | 50,blobs.gif,460,86.66905,0.76955,2.01700,0.49579,0.93401 52 | 51,blobs.gif,600,91.39697,0.90260,1.34527,0.74334,0.95087 53 | 52,blobs.gif,535,86.08326,0.90725,1.31821,0.75860,0.95280 54 | 53,blobs.gif,202,62.87006,0.64220,2.22498,0.44944,0.93519 55 | 54,blobs.gif,541,84.66905,0.94833,1.06895,0.93549,0.96007 56 | 55,blobs.gif,848,112.91169,0.83585,1.55261,0.64408,0.95227 57 | 56,blobs.gif,268,60.52691,0.91928,1.30449,0.76658,0.94533 58 | 57,blobs.gif,206,52.52691,0.93824,1.27810,0.78241,0.93213 59 | 58,blobs.gif,84,45.55635,0.50862,3.84539,0.26005,0.93855 60 | 59,blobs.gif,74,39.55635,0.59430,3.31582,0.30158,0.93671 61 | 60,blobs.gif,48,31.55635,0.60573,2.82144,0.35443,0.88889 62 | 61,blobs.gif,45,32.72792,0.52794,4.13762,0.24168,0.88235 63 | -------------------------------------------------------------------------------- /basic-data-handling-BAND/data/Results_02.csv: -------------------------------------------------------------------------------- 1 | ,Label,Area,Perim.,Circ.,AR,Round,Solidity 2 | 1,blobs.gif,433,92.91169,0.63031,2.07469,0.48200,0.85998 3 | 2,blobs.gif,185,55.21320,0.76260,1.77847,0.56228,0.95116 4 | 3,blobs.gif,658,97.35534,0.87240,1.06829,0.93607,0.96694 5 | 4,blobs.gif,434,78.52691,0.88443,1.06364,0.94017,0.95912 6 | 5,blobs.gif,477,85.45584,0.82081,1.56967,0.63708,0.96755 7 | 6,blobs.gif,285,62.18377,0.92619,1.15337,0.86703,0.93750 8 | 7,blobs.gif,81,32.38478,0.97054,1.20425,0.83039,0.92571 9 | 8,blobs.gif,278,63.94113,0.85446,1.38868,0.72011,0.91901 10 | 9,blobs.gif,231,55.69848,0.93570,1.14066,0.87668,0.94094 11 | 10,blobs.gif,30,30.48528,0.40565,4.33842,0.23050,0.86957 12 | 11,blobs.gif,501,82.66905,0.92122,1.07476,0.93044,0.94797 13 | 12,blobs.gif,660,98.32590,0.85786,1.33708,0.74790,0.95169 14 | 13,blobs.gif,99,35.79899,0.97074,1.26942,0.78776,0.94286 15 | 14,blobs.gif,228,55.69848,0.92354,1.14208,0.87560,0.94021 16 | 15,blobs.gif,448,78.42641,0.91530,1.20734,0.82827,0.94715 17 | 16,blobs.gif,401,87.49747,0.65821,2.49878,0.40020,0.89012 18 | 17,blobs.gif,520,84.66905,0.91152,1.18202,0.84601,0.95151 19 | 18,blobs.gif,425,77.84062,0.88143,1.45068,0.68933,0.95291 20 | 19,blobs.gif,271,62.18377,0.88069,1.34761,0.74205,0.92177 21 | 20,blobs.gif,350,68.76955,0.93001,1.16836,0.85590,0.94340 22 | 21,blobs.gif,159,46.28427,0.93270,1.22497,0.81634,0.92982 23 | 22,blobs.gif,412,75.59798,0.90591,1.10584,0.90429,0.94495 24 | 23,blobs.gif,426,87.49747,0.69924,1.80993,0.55251,0.86939 25 | 24,blobs.gif,260,59.94113,0.90935,1.15347,0.86695,0.93190 26 | 25,blobs.gif,506,87.94113,0.82220,1.67725,0.59621,0.96106 27 | 26,blobs.gif,289,62.76955,0.92174,1.13124,0.88398,0.93528 28 | 27,blobs.gif,676,104.32590,0.78050,1.48251,0.67453,0.90860 29 | 28,blobs.gif,175,53.21320,0.77662,1.76336,0.56710,0.95109 30 | 29,blobs.gif,361,70.18377,0.92097,1.22205,0.81830,0.94503 31 | 30,blobs.gif,545,86.91169,0.90667,1.22458,0.81661,0.94865 32 | 31,blobs.gif,610,112.56854,0.60493,2.74836,0.36385,0.84840 33 | 32,blobs.gif,14,12.48528,1.00000,1.01986,0.98052,0.93333 34 | 33,blobs.gif,641,106.56854,0.70927,1.93591,0.51655,0.88414 35 | 34,blobs.gif,195,51.11270,0.93797,1.14730,0.87161,0.92857 36 | 35,blobs.gif,593,89.25483,0.93541,1.08955,0.91781,0.96032 37 | 36,blobs.gif,22,17.31371,0.92226,1.46402,0.68305,0.86275 38 | 37,blobs.gif,268,59.94113,0.93734,1.29382,0.77291,0.95374 39 | 38,blobs.gif,902,132.22540,0.64832,2.51688,0.39732,0.90836 40 | 39,blobs.gif,473,87.25483,0.78071,1.74310,0.57369,0.94600 41 | 40,blobs.gif,239,57.11270,0.92075,1.21333,0.82418,0.93910 42 | 41,blobs.gif,167,48.04163,0.90927,1.29054,0.77487,0.93296 43 | 42,blobs.gif,413,76.76955,0.88061,1.37460,0.72748,0.95052 44 | 43,blobs.gif,415,77.59798,0.86608,1.24613,0.80249,0.93679 45 | 44,blobs.gif,244,57.94113,0.91333,1.13768,0.87898,0.92952 46 | 45,blobs.gif,377,72.52691,0.90064,1.28529,0.77803,0.95202 47 | 46,blobs.gif,652,94.42641,0.91890,1.11493,0.89692,0.96165 48 | 47,blobs.gif,379,72.18377,0.91405,1.14859,0.87063,0.94750 49 | 48,blobs.gif,578,89.01219,0.91672,1.05028,0.95212,0.95616 50 | 49,blobs.gif,69,38.97056,0.57093,2.96497,0.33727,0.88462 51 | 50,blobs.gif,170,47.69848,0.93897,1.35798,0.73639,0.93151 52 | 51,blobs.gif,472,89.25483,0.74454,2.04163,0.48981,0.92188 53 | 52,blobs.gif,613,94.22540,0.86763,1.35367,0.73873,0.94163 54 | 53,blobs.gif,543,86.66905,0.90841,1.32019,0.75747,0.95347 55 | 54,blobs.gif,204,62.87006,0.64856,2.22133,0.45018,0.93793 56 | 55,blobs.gif,555,87.25483,0.91606,1.07320,0.93180,0.95361 57 | 56,blobs.gif,858,113.74012,0.83343,1.56432,0.63926,0.94912 58 | 57,blobs.gif,281,62.76955,0.89623,1.32189,0.75649,0.92739 59 | 58,blobs.gif,215,54.52691,0.90871,1.30704,0.76509,0.92873 60 | 59,blobs.gif,3,5.65685,1.00000,1.46385,0.68313,0.85714 61 | 60,blobs.gif,1,2.82843,1.00000,1.00000,1.00000,1.00000 62 | 61,blobs.gif,81,42.38478,0.56660,3.08249,0.32441,0.91011 63 | 62,blobs.gif,90,49.55635,0.46053,4.09479,0.24421,0.93264 64 | 63,blobs.gif,53,35.55635,0.52681,2.85939,0.34973,0.89076 65 | 64,blobs.gif,49,36.72792,0.45647,4.27743,0.23379,0.88288 66 | -------------------------------------------------------------------------------- /basic-data-handling-BAND/environment.yml: -------------------------------------------------------------------------------- 1 | name: phd-bias-env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python=3.10 7 | - ipykernel 8 | - jupyterlab 9 | - pandas 10 | - matplotlib 11 | - seaborn 12 | - scipy -------------------------------------------------------------------------------- /basic-data-handling-BAND/images/TrackMate-image_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/basic-data-handling-BAND/images/TrackMate-image_01.png -------------------------------------------------------------------------------- /basic-data-handling-BAND/images/TrackMate-image_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/basic-data-handling-BAND/images/TrackMate-image_02.png -------------------------------------------------------------------------------- /basic-data-handling/Book_01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c7754642", 6 | "metadata": {}, 7 | "source": [ 8 | "# Book 1: How to read a csv file into a data table\n", 9 | "\n", 10 | "Here we will go over how to use ```pandas``` to read ```.csv``` files into panda´s **data_frames**, and how to make simple statistics\n", 11 | "\n", 12 | "## Simple math with just Python\n", 13 | "\n", 14 | "We will create 2 numeric variables ```a``` and ```b``` and then ```print``` their sum." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "id": "34faf413", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "a = 3\n", 25 | "b = 5\n", 26 | "\n", 27 | "print(a+b)" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "id": "511c9b4d", 33 | "metadata": {}, 34 | "source": [ 35 | "Lest play a bit with strings" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "id": "bc852d1d", 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "str_1 = \"I am \"\n", 46 | "str_2 = \"having fun\"\n", 47 | "\n", 48 | "# this works very much similar to IJ Macros\n", 49 | "print(str_1 + str_2)\n", 50 | "\n", 51 | "# so called f-strings are a cool way of controlling better what info you print\n", 52 | "print(f\"{str_1} able to do basic math, and I am {str_2}\")" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "id": "d3af30eb", 58 | "metadata": {}, 59 | "source": [ 60 | "As you can se above, using numeric data and strings in Python is simple and is familar to the way we write in IJ macros. In fact IJ has a language called Jython, which you can use it to program your macros. \n", 61 | "\n", 62 | "So why to learn Python? because it is order of magnitudes better than IJ macros when doing data science operations, such as, statistics, data cleaning, modeling and plotting. The purpose of this module is just to show you how you can start working with Python and we take as an example how to load ```.csv``` files into Python and work with them.\n", 63 | "\n", 64 | "## Using Pandas to read csv files into data tables\n", 65 | "\n", 66 | "Now we will use a well known package called [pandas](https://pandas.pydata.org/) to load ```.csv``` files into data tables called **data frames**. To install ```pandas``` you can follow this [link](https://anaconda.org/conda-forge/pandas). But basically:\n", 67 | "\n", 68 | "* Go to the Anaconda Prompt\n", 69 | "* activate your conda environment:\n", 70 | "\n", 71 | "```\n", 72 | "> conda activate bias-env\n", 73 | "```\n", 74 | "* run the command: ```conda install -c conda-forge pandas```\n", 75 | "* say yes via ```y```" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "id": "258031f7", 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "# by using the import command I make the pandas library available to me, the \"as pd\" is\n", 86 | "# a good practice. This way if I wan to use a function/method from pandas I always start\n", 87 | "# by pd.\n", 88 | "import pandas as pd \n", 89 | "\n", 90 | "# load csv file into a data_frame, think of it as a table of spread sheet\n", 91 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 92 | "\n", 93 | "# there is a nice command for you to explore what is inside a data_frame, its called head.\n", 94 | "df1.head()" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "id": "7f98f459", 100 | "metadata": {}, 101 | "source": [ 102 | "## dtypes:\n", 103 | "Tells you if your table was loaded \"properly\"\n", 104 | "\n", 105 | "object -> string or mixed\n", 106 | "\n", 107 | "int64 -> integer\n", 108 | "\n", 109 | "float64 -> float\n", 110 | "\n", 111 | "bool -> logical true/false" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "id": "a8036b14", 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "df1.dtypes" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "id": "a8734237", 127 | "metadata": {}, 128 | "source": [ 129 | "# Getting basic statistics\n", 130 | "\n", 131 | "Now that we have tabular data, then we can do classical operations like calculating the mean value of a particular column. See the example below but also type your own so you see the power of auto completion." 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "id": "e87889d4", 138 | "metadata": {}, 139 | "outputs": [], 140 | "source": [ 141 | "# very basic way of gettng the mean\n", 142 | "df1[\"Area\"].mean()" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "id": "39f1f193", 148 | "metadata": {}, 149 | "source": [ 150 | "Now if you want to have better control when printing values I recommend that you get familiar with f-strings. It is a very nice way of controlling how you print the information to the user. Below an exampe:" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": null, 156 | "id": "8687e69d", 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "# Let us store the mean value into a variable called val\n", 161 | "val = df1[\"Area\"].mean()\n", 162 | "# then I can use a f-string to print the value, and also format the way it will be printed\n", 163 | "# the format is indicated by the text after the :, in this example :.3f means than only\n", 164 | "# 3 numbers will be printed after the decimal point\n", 165 | "print(f\"The mean value of Area is: {val:.3f}.\")" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "id": "61779d43", 171 | "metadata": {}, 172 | "source": [ 173 | "We can also get a simple summary of statistics" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "id": "b07f98d4", 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "df1[\"Area\"].describe()" 184 | ] 185 | } 186 | ], 187 | "metadata": { 188 | "kernelspec": { 189 | "display_name": "bias-env", 190 | "language": "python", 191 | "name": "bias-env" 192 | }, 193 | "language_info": { 194 | "codemirror_mode": { 195 | "name": "ipython", 196 | "version": 3 197 | }, 198 | "file_extension": ".py", 199 | "mimetype": "text/x-python", 200 | "name": "python", 201 | "nbconvert_exporter": "python", 202 | "pygments_lexer": "ipython3", 203 | "version": "3.9.18" 204 | }, 205 | "vscode": { 206 | "interpreter": { 207 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 208 | } 209 | } 210 | }, 211 | "nbformat": 4, 212 | "nbformat_minor": 5 213 | } 214 | -------------------------------------------------------------------------------- /basic-data-handling/Book_02.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Book 2: How to do simple plots with Pandas\n", 8 | "\n", 9 | "Here we will go over how to use ```pandas``` to read ```.csv``` files and then make a simple plot\n", 10 | "\n", 11 | "## Load the data\n", 12 | "Let us use what we learned before to load the ```.csv``` table into a data frame" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "import pandas as pd \n", 22 | "\n", 23 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 24 | "\n", 25 | "df1.head()" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "## Using Pandas to make basic plots\n", 33 | "\n", 34 | "Pandas can be used to do many statistical operations but also to do basic plots easily. To do this we will need to install another well known package called [matplotlib](https://matplotlib.org/). To install ```matplotlib``` you can follow this [link](https://anaconda.org/conda-forge/matplotlib). But basically:\n", 35 | "\n", 36 | "* Go to the Anaconda Prompt\n", 37 | "* activate your conda environment:\n", 38 | "\n", 39 | "```\n", 40 | "> conda activate bias-env\n", 41 | "```\n", 42 | "* run the command: ```conda install -c conda-forge matplotlib```\n", 43 | "* say yes via ```y```\n", 44 | "\n", 45 | "As an exercise you can try to run the cell below before and after intalling ```matplotlib```" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "# simple histogram\n", 55 | "ax = df1.hist(column='Area')\n", 56 | "ax0 = ax[0,0]\n", 57 | "ax0.set_ylabel('occurence')" 58 | ] 59 | } 60 | ], 61 | "metadata": { 62 | "kernelspec": { 63 | "display_name": "bias-env", 64 | "language": "python", 65 | "name": "bias-env" 66 | }, 67 | "language_info": { 68 | "codemirror_mode": { 69 | "name": "ipython", 70 | "version": 3 71 | }, 72 | "file_extension": ".py", 73 | "mimetype": "text/x-python", 74 | "name": "python", 75 | "nbconvert_exporter": "python", 76 | "pygments_lexer": "ipython3", 77 | "version": "3.9.18" 78 | }, 79 | "orig_nbformat": 4, 80 | "vscode": { 81 | "interpreter": { 82 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 83 | } 84 | } 85 | }, 86 | "nbformat": 4, 87 | "nbformat_minor": 2 88 | } 89 | -------------------------------------------------------------------------------- /basic-data-handling/Book_03.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Book 3: How to concatenate data frames\n", 8 | "\n", 9 | "Here we will go over how to use ```pandas``` to read several ```.csv``` files and then **concatenate** them into a single table. This is very useful to load the results of different conditions, or biological replicates, and to **tag** these conditions so we can later use them to compare results and do statistical tests.\n", 10 | "\n", 11 | "## Load the data\n", 12 | "Let us use what we learned before to load the ```.csv``` table into a data frame" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "import pandas as pd \n", 22 | "\n", 23 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 24 | "\n", 25 | "df1.head()" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "Lets add a colum to describe the \"student\" that made the analysis" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "df1['Student'] = '01'\n", 42 | "# Now I use \"sample\" to get 10 random examples from the table\n", 43 | "df1.sample(10)" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "Now we can read a second dataset, and add an extra \"student\" 02 tag" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "df2 = pd.read_csv('./data/Results_02.csv')\n", 60 | "df2['Student'] = '02'\n", 61 | "df2.head()" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "Lets see if there are small differences or not" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "val = df1[\"Area\"].mean()\n", 78 | "print(f\"The mean value of Area for Student 1 is: {val:.3f}.\")\n", 79 | "df1.hist(column='Area')\n", 80 | "\n", 81 | "val = df2[\"Area\"].mean()\n", 82 | "print(f\"The mean value of Area for Student 2 is: {val:.3f}.\")\n", 83 | "df2.hist(column='Area')" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "Now instead of keeping track of different data frames is easier if we put these tables together. This operation is called concatenation." 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "# concatenate\n", 100 | "df = pd.concat([df1, df2])\n", 101 | "df.sample(10)" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "Now let us do a basic boxplot to see if the results of both students are significantly different from one another. Here we benefit from the **Student** tag, we can ask the boxplot to sort the results based on this column value using the ```by=``` variable." 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "df.boxplot(column=\"Area\",by=\"Student\")" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "# How to save data frames into new .csv files\n", 125 | "\n", 126 | "Now that we have concatenated all our tables into a new more pratical one we can then save this new table." 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "# writting the table\n", 136 | "df.to_csv('./data/Results_total.csv')" 137 | ] 138 | } 139 | ], 140 | "metadata": { 141 | "kernelspec": { 142 | "display_name": "bias-env", 143 | "language": "python", 144 | "name": "bias-env" 145 | }, 146 | "language_info": { 147 | "codemirror_mode": { 148 | "name": "ipython", 149 | "version": 3 150 | }, 151 | "file_extension": ".py", 152 | "mimetype": "text/x-python", 153 | "name": "python", 154 | "nbconvert_exporter": "python", 155 | "pygments_lexer": "ipython3", 156 | "version": "3.9.18" 157 | }, 158 | "orig_nbformat": 4, 159 | "vscode": { 160 | "interpreter": { 161 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 162 | } 163 | } 164 | }, 165 | "nbformat": 4, 166 | "nbformat_minor": 2 167 | } 168 | -------------------------------------------------------------------------------- /basic-data-handling/Book_04.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Book 4: How to do more ellaborated plots using seaborn\n", 8 | "\n", 9 | "Here we will go over how to use ```pandas``` to read several ```.csv``` files, **concatenate** them into a single table, and then use ```seaborn``` for plotting.\n", 10 | "\n", 11 | "## Install seaborn\n", 12 | "Full instructions [here](https://anaconda.org/conda-forge/seaborn)\n", 13 | "\n", 14 | "* Go to the Anaconda Prompt\n", 15 | "* activate your conda environment:\n", 16 | "\n", 17 | "```\n", 18 | "> conda activate bias-env\n", 19 | "```\n", 20 | "* run the command: ```conda install -c conda-forge seaborn```\n", 21 | "* say yes via ```y```\n", 22 | "\n", 23 | "## Load the data\n", 24 | "Let us use what we learned before to load the ```.csv``` table into a data frame" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import pandas as pd\n", 34 | "import seaborn as sns\n", 35 | "\n", 36 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 37 | "df1['Student'] = '01'\n", 38 | "\n", 39 | "df2 = pd.read_csv('./data/Results_02.csv')\n", 40 | "df2['Student'] = '02'\n", 41 | "\n", 42 | "# concatenate\n", 43 | "df = pd.concat([df1, df2])\n", 44 | "df.sample(10)\n" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "Lets use seaborn" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "sns.violinplot(x='Student', y='Area', data=df)" 61 | ] 62 | } 63 | ], 64 | "metadata": { 65 | "kernelspec": { 66 | "display_name": "Python 3.9.13 ('bias-env')", 67 | "language": "python", 68 | "name": "python3" 69 | }, 70 | "language_info": { 71 | "codemirror_mode": { 72 | "name": "ipython", 73 | "version": 3 74 | }, 75 | "file_extension": ".py", 76 | "mimetype": "text/x-python", 77 | "name": "python", 78 | "nbconvert_exporter": "python", 79 | "pygments_lexer": "ipython3", 80 | "version": "3.9.18" 81 | }, 82 | "orig_nbformat": 4, 83 | "vscode": { 84 | "interpreter": { 85 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 86 | } 87 | } 88 | }, 89 | "nbformat": 4, 90 | "nbformat_minor": 2 91 | } 92 | -------------------------------------------------------------------------------- /basic-data-handling/Book_05.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Book 5: Statistical tests using Pandas and Scipy\n", 8 | "\n", 9 | "Here we will go over how to use ```pandas``` to read several ```.csv``` files, **concatenate** them into a single table, and then use ```scipy``` for statistical tests.\n", 10 | "\n", 11 | "## Load the data\n", 12 | "Let us use what we learned before to load the ```.csv``` table into a data frame" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "import pandas as pd\n", 22 | "\n", 23 | "df1 = pd.read_csv('./data/Results_01.csv')\n", 24 | "df1['Student'] = '01'\n", 25 | "\n", 26 | "df2 = pd.read_csv('./data/Results_02.csv')\n", 27 | "df2['Student'] = '02'\n", 28 | "\n", 29 | "# concatenate\n", 30 | "df = pd.concat([df1, df2])\n", 31 | "print(df.sample(10))\n", 32 | "\n", 33 | "# simple box plot, to vissualy inspect if there are big differences between both groups\n", 34 | "df.boxplot(column=\"Area\",by=\"Student\")" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "## Using Scipy for statistical testing\n", 42 | "\n", 43 | "When we do a **statistical test** we assume a **null hypotesis - H0** and our objective is to try and **falsify** that hypotesis. In most cases the **H0** poses that there is no relationship (or difference) between the **distributions** being tested. To determine if **H0** is false we use the now famous **p-value**. The **p-value** The estimates how probable it is that you would see the differences between the two sets if the null hypothesis were true. Therefore, a p-value of 0.04 means that you have a 4% chance that **H0** is true and thus we report a statistically significant relationship (or difference) between the input and target distributions. Note that it does not say anything a obout how important or biologically relevant it is!\n", 44 | "\n", 45 | "## Scipy\n", 46 | "[Scipy](https://scipy.org/) is a big package for scientific computing commonly used in Python, it is already included in our virtual environment due to packages previously installed. To test that this is the case try to run the block bellow. If you run into problems then [install scipy](https://anaconda.org/conda-forge/scipy) by: ```conda install -c conda-forge scipy```" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "# this time I am loading part of the library, the part called stats\n", 56 | "from scipy import stats \n", 57 | "# as this runs, we are good to continue" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "For clarity let us get out the numbers of interest from the data table by using the ```query``` method of pandas data_frames. ```query``` allows us to extract values from a column while filtering based ob the values of another. Bellow, I ```query``` for the **Area** values that belong to **Student 01** and **02** respectively." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "Area_s1=df.query(\"Student == '01'\")['Area']\n", 74 | "Area_s2=df.query(\"Student == '02'\")['Area']" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "One of the most common mistakes while doing statistical testing is to use a particular method, e.g. t-test, whitout checkig first that the underlying assumptions of the test are true. In general we must check the following to know what tests we can use:\n", 82 | "\n", 83 | "* Independence: each meassurement of the variables is independent of each other\n", 84 | "\n", 85 | "* Normality: the data follows a normal distribution (Gaussian distribution)\n", 86 | "\n", 87 | "* Homogeneous variance: the variance (spread around the mean) within each group being compared is similar\n", 88 | "\n", 89 | "\n", 90 | "## Homogeneity\n", 91 | "Lets us first test for homogeneous variance " 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "# homogeneity\n", 101 | "stats.levene(Area_s1, Area_s2)" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "## Normality\n", 109 | "\n", 110 | "Now we check is the distributions to test are normal - aka Gaussian" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "# Shapiro-Wilk test for normality\n", 120 | "stats.shapiro(Area_s1)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": null, 126 | "metadata": {}, 127 | "outputs": [], 128 | "source": [ 129 | "# Shapiro-Wilk test for normality\n", 130 | "stats.shapiro(Area_s2)" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "## The actual t-test\n", 138 | "\n", 139 | "Now that all seems to be good then we can run the t-test" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "# Independent t-test\n", 149 | "stats.ttest_ind(Area_s1, Area_s2)" 150 | ] 151 | } 152 | ], 153 | "metadata": { 154 | "kernelspec": { 155 | "display_name": "bias-env", 156 | "language": "python", 157 | "name": "bias-env" 158 | }, 159 | "language_info": { 160 | "codemirror_mode": { 161 | "name": "ipython", 162 | "version": 3 163 | }, 164 | "file_extension": ".py", 165 | "mimetype": "text/x-python", 166 | "name": "python", 167 | "nbconvert_exporter": "python", 168 | "pygments_lexer": "ipython3", 169 | "version": "3.9.18" 170 | }, 171 | "orig_nbformat": 4, 172 | "vscode": { 173 | "interpreter": { 174 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 175 | } 176 | } 177 | }, 178 | "nbformat": 4, 179 | "nbformat_minor": 2 180 | } 181 | -------------------------------------------------------------------------------- /basic-data-handling/Book_06.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Quick example of a pivot table\n", 8 | "\n", 9 | "Inspired in the last excercise of JY we can pick up where he left and see an exaple of a pivot table" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import pandas as pd \n", 19 | "\n", 20 | "df = pd.read_csv('./data/Results_total.csv')\n", 21 | "\n", 22 | "print(df.head())\n", 23 | "print(f\"number of cols: {df.shape[0]}, number of rows: {df.shape[1]}\")" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "The pivot table. For some simple examples look at: https://www.machinelearningplus.com/pandas/pandas-pivot-table-in-python/" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "output = pd.pivot_table(data=df, \n", 40 | " index=['Student'], \n", 41 | " #columns=['Categorical'], \n", 42 | " values='AR',\n", 43 | " aggfunc=['sum', 'mean'])\n", 44 | "\n", 45 | "print(output.head())" 46 | ] 47 | } 48 | ], 49 | "metadata": { 50 | "kernelspec": { 51 | "display_name": "Python 3.9.13 ('bias-env')", 52 | "language": "python", 53 | "name": "python3" 54 | }, 55 | "language_info": { 56 | "codemirror_mode": { 57 | "name": "ipython", 58 | "version": 3 59 | }, 60 | "file_extension": ".py", 61 | "mimetype": "text/x-python", 62 | "name": "python", 63 | "nbconvert_exporter": "python", 64 | "pygments_lexer": "ipython3", 65 | "version": "3.9.18" 66 | }, 67 | "orig_nbformat": 4, 68 | "vscode": { 69 | "interpreter": { 70 | "hash": "a02576cc11b8a30283279cac21081ca45fa867e2bd6a6ef9b059d3b132dd7208" 71 | } 72 | } 73 | }, 74 | "nbformat": 4, 75 | "nbformat_minor": 2 76 | } 77 | -------------------------------------------------------------------------------- /basic-data-handling/README.md: -------------------------------------------------------------------------------- 1 | # Basic data handling in python 2 | 3 | Throughout this session we will concentrate on what to do after we get results tables (e.g. ".csv") form FIJI or any other image analysis software. Most people would take the tables, load them in a spreadsheet program, such as Microsfots Excel, and then continue from there with figure generation and statistical testing. Here I showcase the option of using Python, in combination with Jupyter Notebooks for these tasks. 4 | 5 | ## Learning outcome 6 | 7 | * Basic understanding of Python for data exploration 8 | 9 | * How to install Data Science packages using conda environments 10 | 11 | * How to use VS Code to run and create Jupyter Notebooks 12 | 13 | * How to store and share your environment via ```.yml``` files 14 | 15 | * How to load ```.csv``` files 16 | 17 | * How to concatenate (combine) data tables 18 | 19 | * How to export data tables into ```.csv``` files or Excel sheets 20 | 21 | * How to do basic plots, e.g. scatter, bars and violin plots 22 | 23 | ## Prerequisites 24 | 25 | To save time during the session, students will hace access to a work station with already installed [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html) (Anaconda Prompt), [VS Code](https://code.visualstudio.com/docs), and [git](https://github.com/git-guides/install-git) command line tools. However, we write some instructions for those following off site. 26 | 27 | ## What is python? 28 | 29 | This is better answered by looking at online resources such as: https://www.python.org/doc/essays/blurb/ 30 | 31 | In the context of our course the most important question is [why is python used in data science?](https://learnpython.com/blog/why-python-used-for-science/) 32 | 33 | I hope that by the end of the session you will understand why so many people are moving to Python to do data analysis tasks, from the most basic to the most advanced. 34 | 35 | ## How to install Python via conda 36 | 37 | To make things easier we will be using [conda to install python and manage our virtual environments.](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html) Think of a [virtual environment](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) as a box (directory) that contains a specific collection tools (e.g. Python + packages) that you have installed. The good thing is that you can have different boxes/environments, and if you change one environment, your other environments are not affected. To work with them we will then "activate" the box we want to use. 38 | 39 | After working with FIJI during the course, the concept of virtual environments is very similar as having multiple versions of FIJI by keeping different copies in different folders. 40 | 41 | ## Step 1: Creating a conda env with python 3.9 42 | 43 | **Prerequisite** to go over these steps you need to have installed ```conda```, and the anaconda prompt on your computer. 44 | 45 | S1.1 Open an Anaconda Promt: 46 | 47 | * Go to Windows icon -> search for "anaconda" -> open Anaconda Prompt (Anaconda 3) 48 | 49 | S1.2 Create a new conda environment for Python using this command in the promt: 50 | 51 | ``` 52 | > conda create -y -n bias-env -c conda-forge python=3.9 53 | ``` 54 | 55 | After ```conda``` has done its job you have created a new "box" containing a copy of Python version 3.9. The name of this environment is ```bias-env``` and as ```conda```channel we have used ```conda-forge```. Think of a conda channel as buying your products from a specific shop. ```conda-forge``` is my favorite store, but this discussion is a bit out of the scope of the session. 56 | 57 | S1.3 Now activate your conda environment: 58 | 59 | ``` 60 | > conda activate bias-env 61 | ``` 62 | 63 | S1.4 Let us check the enviornment, by asking what python is available. Use the command: 64 | 65 | ``` 66 | > which python 67 | 68 | Python 3.9.xx | packaged by conda-forge |... 69 | 70 | > python --version 71 | 72 | ``` 73 | 74 | S1.5 Activate Python. Use the command: 75 | 76 | ``` 77 | > python 78 | ``` 79 | 80 | S1.6 lets do some basic math 81 | 82 | ```python 83 | >>> a = 3 84 | >>> b = 6 85 | >>> a+b 86 | 9 87 | ``` 88 | 89 | S1.7 lets do some basic print statements 90 | ```python 91 | >>> print("Hello") 92 | Hello 93 | >>> name = "Rafa" 94 | >>> print("Hello " + name) 95 | Hello Rafa 96 | 97 | ``` 98 | This should remind you of the way we worked with strings in IJ Macro language 99 | 100 | S1.8 lets get out of python 101 | 102 | ```python 103 | >>> quit() 104 | ``` 105 | 106 | ## VS Code 107 | 108 | VS Code is a lightweight source code editor which runs on your desktop and is available for Windows, macOS and Linux. Using its extensions it is a great tool for Python and Jupyter books. 109 | 110 | How to install it (not live): please follow the [instructions here to install VS Code](https://code.visualstudio.com/docs/setup/setup-overview), and the [nice documentation here to have it ready for python.](https://code.visualstudio.com/docs/languages/python). 111 | 112 | ## Step 2 Open VS Code and create a Python file 113 | 114 | **Prerequisite** I assume you already have VS Code installed. 115 | 116 | S2.1 Open VS Code: 117 | 118 | * Go to Windows icon -> search for ```Code``` -> open Visual Studio Code 119 | 120 | S2.2 Cereate a new folder so we can work on it: 121 | 122 | * you can use cmd, or windows file explorer for this. 123 | 124 | S2.3 Open the folder in VS Code using 125 | 126 | * File -> open folder -> Yes, It trust 127 | 128 | S2.4 Create a new python file by: 129 | 130 | * create **New File** -> name it ```hello.py``` 131 | * Install the [recommended extensions](https://code.visualstudio.com/docs/languages/python) 132 | * in the file write: ```print("hello students")``` 133 | * run the file via the arrow on the top right 134 | * look at the terminal 135 | 136 | S2.5 Select an interpreter (aka virtual environment) 137 | 138 | * use Ctr + Shift + P to open the command pallete 139 | * look for ```interpreter``` 140 | * choose ```Python: Select Interpreter``` 141 | * look for the ```bias-env``` 142 | 143 | S2.6 Run again the file 144 | 145 | ## What is a Jupyter Notebook 146 | 147 | Jupyter notebooks are a great tool for interactive programming in Data Science. [Look at this great article.](https://towardsdatascience.com/the-complete-guide-to-jupyter-notebooks-for-data-science-8ff3591f69a4) You can think of them as interactive books where we can "attach" a Python environment and interactively run pieces of code. Lets do a small demo so it is easier to understand. 148 | 149 | ## Installing jupyterlab in our virtual environment 150 | 151 | This step can be skiped in this demo because we already have jupyterlab installed in our base conda environment. However, if this is not the case you might have to install it separately via: 152 | 153 | * Go to the Anaconda Prompt 154 | * If you closed it, then activate again the bias-env. Follow steps S1.1 and S1.3 155 | 156 | ```conda install -c conda-forge jupyterlab``` 157 | 158 | To test that it is properly installed you can run this in the command line 159 | 160 | ```where jupyter``` 161 | 162 | ### Make the virtual environment available to JupyterLab 163 | To make our current environment (kernel) available to JupyterLab we can use: 164 | 165 | ```ipython kernel install --user --name=bias-env``` 166 | 167 | ## Step 3 Using VS Code to create and run Jupyter Notebooks 168 | 169 | You can go over [this guide to get many details on how to use Jupyter notebooks in VS Code](https://code.visualstudio.com/docs/datascience/jupyter-notebooks). Below a practical example. 170 | 171 | S3.1 Crete new jupyter book in VS Code 172 | 173 | * Create a new notebook by creating a new ```.ipynb``` file in your workspace. The extension resembles Ipython NoteBook 174 | 175 | * Alternatively 176 | * use Ctr + Shift + P to open the command palleteinter 177 | * look for ```jupyter``` 178 | * choose ```Python: Create: New Jupyter Notebook``` 179 | * use: File -> Save to save the file with ```.ipynb``` extension 180 | * Select your kernel AKA virtual environment 181 | * Create a cell with simple math: 182 | 183 | ```python 184 | a = 3 185 | b = 6 186 | a+b 187 | ``` 188 | 189 | * Try to run the cell. 190 | 191 | **Note** If you forgot the ipython kernel step you will notice a complaint from VS Code. In this case make sure you have ```ipykernel``` installed. 192 | 193 | 194 | S3.2 Optional Installing ```ipykernel``` 195 | 196 | * Go to the Anaconda Prompt 197 | * If you closed it, then activate again the bias-env. Follow steps S1.1 and S1.3 198 | * run the command: ```conda install ipykernel``` 199 | * say yes via ```y``` 200 | 201 | Then we make the current environment available as a jupyter kernel 202 | 203 | ```ipython kernel install --user --name=bias-env``` 204 | 205 | S3.3 Run the Jupyter Notebook in VS Code once again 206 | 207 | ## To continue working on our use case 208 | 209 | Now lets move to the example books in this repo. 210 | 211 | ## Where to go next 212 | 213 | Now you are set to a great start. Feel free to play with this notebooks with basic Python if you want to get familiar with the language. There are many cool websites and videos including. 214 | 215 | * YouTube series by google team on Python: [day 1 link](https://youtu.be/tKTZoB2Vjuk) 216 | * [RealPython website](https://realpython.com/) 217 | * YouTube series by Neubias Academy on using [Python for image analysis](https://youtu.be/2KF8vBrp3Zw) 218 | * PoL Dresden [course on BioImage analysis using Python](https://github.com/BiAPoL/Bio-image_Analysis_with_Python) -------------------------------------------------------------------------------- /basic-data-handling/data/Results_01.csv: -------------------------------------------------------------------------------- 1 | ,Label,Area,Perim.,Circ.,AR,Round,Solidity 2 | 1,blobs.gif,425,90.42641,0.65314,2.06670,0.48386,0.88542 3 | 2,blobs.gif,181,55.21320,0.74611,1.77749,0.56259,0.94517 4 | 3,blobs.gif,656,96.52691,0.88474,1.06472,0.93921,0.96970 5 | 4,blobs.gif,430,79.11270,0.86335,1.06156,0.94201,0.95662 6 | 5,blobs.gif,477,86.04163,0.80968,1.56805,0.63773,0.96657 7 | 6,blobs.gif,276,60.52691,0.94672,1.11738,0.89495,0.94845 8 | 7,blobs.gif,70,29.79899,0.99061,1.13553,0.88065,0.90909 9 | 8,blobs.gif,265,61.35534,0.88461,1.38821,0.72035,0.93146 10 | 9,blobs.gif,220,54.52691,0.92985,1.12587,0.88820,0.92827 11 | 10,blobs.gif,26,26.48528,0.46577,3.84899,0.25981,0.86667 12 | 11,blobs.gif,492,82.08326,0.91763,1.07144,0.93333,0.94798 13 | 12,blobs.gif,650,96.91169,0.86970,1.33339,0.74997,0.95308 14 | 13,blobs.gif,220,54.52691,0.92985,1.13619,0.88013,0.93418 15 | 14,blobs.gif,88,34.38478,0.93532,1.22406,0.81695,0.92147 16 | 15,blobs.gif,441,77.84062,0.91461,1.20597,0.82920,0.94635 17 | 16,blobs.gif,391,85.49747,0.67217,2.45579,0.40720,0.90614 18 | 17,blobs.gif,511,83.25483,0.92643,1.17220,0.85310,0.95514 19 | 18,blobs.gif,417,76.42641,0.89714,1.43396,0.69737,0.94989 20 | 19,blobs.gif,257,59.11270,0.92423,1.33803,0.74737,0.95009 21 | 20,blobs.gif,347,68.76955,0.92203,1.16649,0.85727,0.94166 22 | 21,blobs.gif,148,44.87006,0.92376,1.18725,0.84228,0.92500 23 | 22,blobs.gif,403,73.59798,0.93494,1.08942,0.91792,0.95047 24 | 23,blobs.gif,413,84.42641,0.72812,1.80288,0.55467,0.87686 25 | 24,blobs.gif,252,58.52691,0.92448,1.14850,0.87070,0.93680 26 | 25,blobs.gif,500,87.94113,0.81245,1.66888,0.59921,0.96525 27 | 26,blobs.gif,277,61.11270,0.93202,1.12438,0.88938,0.94863 28 | 27,blobs.gif,667,102.08326,0.80432,1.48078,0.67532,0.92897 29 | 28,blobs.gif,171,53.21320,0.75887,1.75976,0.56826,0.94475 30 | 29,blobs.gif,352,68.76955,0.93532,1.21557,0.82266,0.95135 31 | 30,blobs.gif,533,86.08326,0.90386,1.20789,0.82789,0.95179 32 | 31,blobs.gif,598,109.63961,0.62514,2.74660,0.36409,0.85429 33 | 32,blobs.gif,629,103.39697,0.73934,1.93744,0.51614,0.89474 34 | 33,blobs.gif,182,49.69848,0.92597,1.15164,0.86833,0.92386 35 | 34,blobs.gif,583,88.66905,0.93182,1.08956,0.91780,0.95574 36 | 35,blobs.gif,14,13.89949,0.91063,1.31046,0.76309,0.84848 37 | 36,blobs.gif,263,59.69848,0.92734,1.26047,0.79335,0.94946 38 | 37,blobs.gif,886,129.98276,0.65898,2.51057,0.39832,0.91199 39 | 38,blobs.gif,469,87.25483,0.77411,1.72164,0.58084,0.94177 40 | 39,blobs.gif,231,55.94113,0.92760,1.18693,0.84251,0.93333 41 | 40,blobs.gif,157,46.28427,0.92096,1.26314,0.79168,0.92082 42 | 41,blobs.gif,403,75.01219,0.90002,1.36989,0.72998,0.94824 43 | 42,blobs.gif,404,73.59798,0.93726,1.24846,0.80099,0.95735 44 | 43,blobs.gif,234,55.69848,0.94785,1.13093,0.88423,0.94545 45 | 44,blobs.gif,368,70.76955,0.92335,1.27705,0.78305,0.95213 46 | 45,blobs.gif,642,93.25483,0.92769,1.11644,0.89570,0.96396 47 | 46,blobs.gif,369,70.18377,0.94138,1.13980,0.87735,0.95226 48 | 47,blobs.gif,566,87.84062,0.92180,1.04905,0.95325,0.95689 49 | 48,blobs.gif,63,36.14214,0.60607,2.94685,0.33935,0.92647 50 | 49,blobs.gif,156,45.69848,0.93871,1.26978,0.78754,0.92308 51 | 50,blobs.gif,460,86.66905,0.76955,2.01700,0.49579,0.93401 52 | 51,blobs.gif,600,91.39697,0.90260,1.34527,0.74334,0.95087 53 | 52,blobs.gif,535,86.08326,0.90725,1.31821,0.75860,0.95280 54 | 53,blobs.gif,202,62.87006,0.64220,2.22498,0.44944,0.93519 55 | 54,blobs.gif,541,84.66905,0.94833,1.06895,0.93549,0.96007 56 | 55,blobs.gif,848,112.91169,0.83585,1.55261,0.64408,0.95227 57 | 56,blobs.gif,268,60.52691,0.91928,1.30449,0.76658,0.94533 58 | 57,blobs.gif,206,52.52691,0.93824,1.27810,0.78241,0.93213 59 | 58,blobs.gif,84,45.55635,0.50862,3.84539,0.26005,0.93855 60 | 59,blobs.gif,74,39.55635,0.59430,3.31582,0.30158,0.93671 61 | 60,blobs.gif,48,31.55635,0.60573,2.82144,0.35443,0.88889 62 | 61,blobs.gif,45,32.72792,0.52794,4.13762,0.24168,0.88235 63 | -------------------------------------------------------------------------------- /basic-data-handling/data/Results_02.csv: -------------------------------------------------------------------------------- 1 | ,Label,Area,Perim.,Circ.,AR,Round,Solidity 2 | 1,blobs.gif,433,92.91169,0.63031,2.07469,0.48200,0.85998 3 | 2,blobs.gif,185,55.21320,0.76260,1.77847,0.56228,0.95116 4 | 3,blobs.gif,658,97.35534,0.87240,1.06829,0.93607,0.96694 5 | 4,blobs.gif,434,78.52691,0.88443,1.06364,0.94017,0.95912 6 | 5,blobs.gif,477,85.45584,0.82081,1.56967,0.63708,0.96755 7 | 6,blobs.gif,285,62.18377,0.92619,1.15337,0.86703,0.93750 8 | 7,blobs.gif,81,32.38478,0.97054,1.20425,0.83039,0.92571 9 | 8,blobs.gif,278,63.94113,0.85446,1.38868,0.72011,0.91901 10 | 9,blobs.gif,231,55.69848,0.93570,1.14066,0.87668,0.94094 11 | 10,blobs.gif,30,30.48528,0.40565,4.33842,0.23050,0.86957 12 | 11,blobs.gif,501,82.66905,0.92122,1.07476,0.93044,0.94797 13 | 12,blobs.gif,660,98.32590,0.85786,1.33708,0.74790,0.95169 14 | 13,blobs.gif,99,35.79899,0.97074,1.26942,0.78776,0.94286 15 | 14,blobs.gif,228,55.69848,0.92354,1.14208,0.87560,0.94021 16 | 15,blobs.gif,448,78.42641,0.91530,1.20734,0.82827,0.94715 17 | 16,blobs.gif,401,87.49747,0.65821,2.49878,0.40020,0.89012 18 | 17,blobs.gif,520,84.66905,0.91152,1.18202,0.84601,0.95151 19 | 18,blobs.gif,425,77.84062,0.88143,1.45068,0.68933,0.95291 20 | 19,blobs.gif,271,62.18377,0.88069,1.34761,0.74205,0.92177 21 | 20,blobs.gif,350,68.76955,0.93001,1.16836,0.85590,0.94340 22 | 21,blobs.gif,159,46.28427,0.93270,1.22497,0.81634,0.92982 23 | 22,blobs.gif,412,75.59798,0.90591,1.10584,0.90429,0.94495 24 | 23,blobs.gif,426,87.49747,0.69924,1.80993,0.55251,0.86939 25 | 24,blobs.gif,260,59.94113,0.90935,1.15347,0.86695,0.93190 26 | 25,blobs.gif,506,87.94113,0.82220,1.67725,0.59621,0.96106 27 | 26,blobs.gif,289,62.76955,0.92174,1.13124,0.88398,0.93528 28 | 27,blobs.gif,676,104.32590,0.78050,1.48251,0.67453,0.90860 29 | 28,blobs.gif,175,53.21320,0.77662,1.76336,0.56710,0.95109 30 | 29,blobs.gif,361,70.18377,0.92097,1.22205,0.81830,0.94503 31 | 30,blobs.gif,545,86.91169,0.90667,1.22458,0.81661,0.94865 32 | 31,blobs.gif,610,112.56854,0.60493,2.74836,0.36385,0.84840 33 | 32,blobs.gif,14,12.48528,1.00000,1.01986,0.98052,0.93333 34 | 33,blobs.gif,641,106.56854,0.70927,1.93591,0.51655,0.88414 35 | 34,blobs.gif,195,51.11270,0.93797,1.14730,0.87161,0.92857 36 | 35,blobs.gif,593,89.25483,0.93541,1.08955,0.91781,0.96032 37 | 36,blobs.gif,22,17.31371,0.92226,1.46402,0.68305,0.86275 38 | 37,blobs.gif,268,59.94113,0.93734,1.29382,0.77291,0.95374 39 | 38,blobs.gif,902,132.22540,0.64832,2.51688,0.39732,0.90836 40 | 39,blobs.gif,473,87.25483,0.78071,1.74310,0.57369,0.94600 41 | 40,blobs.gif,239,57.11270,0.92075,1.21333,0.82418,0.93910 42 | 41,blobs.gif,167,48.04163,0.90927,1.29054,0.77487,0.93296 43 | 42,blobs.gif,413,76.76955,0.88061,1.37460,0.72748,0.95052 44 | 43,blobs.gif,415,77.59798,0.86608,1.24613,0.80249,0.93679 45 | 44,blobs.gif,244,57.94113,0.91333,1.13768,0.87898,0.92952 46 | 45,blobs.gif,377,72.52691,0.90064,1.28529,0.77803,0.95202 47 | 46,blobs.gif,652,94.42641,0.91890,1.11493,0.89692,0.96165 48 | 47,blobs.gif,379,72.18377,0.91405,1.14859,0.87063,0.94750 49 | 48,blobs.gif,578,89.01219,0.91672,1.05028,0.95212,0.95616 50 | 49,blobs.gif,69,38.97056,0.57093,2.96497,0.33727,0.88462 51 | 50,blobs.gif,170,47.69848,0.93897,1.35798,0.73639,0.93151 52 | 51,blobs.gif,472,89.25483,0.74454,2.04163,0.48981,0.92188 53 | 52,blobs.gif,613,94.22540,0.86763,1.35367,0.73873,0.94163 54 | 53,blobs.gif,543,86.66905,0.90841,1.32019,0.75747,0.95347 55 | 54,blobs.gif,204,62.87006,0.64856,2.22133,0.45018,0.93793 56 | 55,blobs.gif,555,87.25483,0.91606,1.07320,0.93180,0.95361 57 | 56,blobs.gif,858,113.74012,0.83343,1.56432,0.63926,0.94912 58 | 57,blobs.gif,281,62.76955,0.89623,1.32189,0.75649,0.92739 59 | 58,blobs.gif,215,54.52691,0.90871,1.30704,0.76509,0.92873 60 | 59,blobs.gif,3,5.65685,1.00000,1.46385,0.68313,0.85714 61 | 60,blobs.gif,1,2.82843,1.00000,1.00000,1.00000,1.00000 62 | 61,blobs.gif,81,42.38478,0.56660,3.08249,0.32441,0.91011 63 | 62,blobs.gif,90,49.55635,0.46053,4.09479,0.24421,0.93264 64 | 63,blobs.gif,53,35.55635,0.52681,2.85939,0.34973,0.89076 65 | 64,blobs.gif,49,36.72792,0.45647,4.27743,0.23379,0.88288 66 | -------------------------------------------------------------------------------- /basic-data-handling/environment.yml: -------------------------------------------------------------------------------- 1 | name: bias-env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python=3.9 7 | - ipykernel 8 | - jupyterlab 9 | - pandas 10 | - matplotlib 11 | - seaborn 12 | - scipy7 -------------------------------------------------------------------------------- /basic-data-handling/images/TrackMate-image_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/basic-data-handling/images/TrackMate-image_01.png -------------------------------------------------------------------------------- /basic-data-handling/images/TrackMate-image_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/basic-data-handling/images/TrackMate-image_02.png -------------------------------------------------------------------------------- /short-lectures-demos/data/100x_A_ckitneg_02.oib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short-lectures-demos/data/100x_A_ckitneg_02.oib -------------------------------------------------------------------------------- /short-lectures-demos/data/rice.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short-lectures-demos/data/rice.tif -------------------------------------------------------------------------------- /short-lectures-demos/pyBIAS_2h_240926/.ipynb_checkpoints/environment-checkpoint.yml: -------------------------------------------------------------------------------- 1 | name: pybias-env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python=3.9 7 | # image processing 8 | - scikit-image 9 | - scipy 10 | # related to jupyter notebooks 11 | - jupyterlab 12 | - ipykernel 13 | - stackview 14 | # data handling and plotting 15 | - pandas 16 | - matplotlib 17 | - seaborn 18 | # pip packages 19 | - pip: 20 | - oiffile[all] -------------------------------------------------------------------------------- /short-lectures-demos/pyBIAS_2h_240926/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Rafael Camacho 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /short-lectures-demos/pyBIAS_2h_240926/README.md: -------------------------------------------------------------------------------- 1 | [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) 2 | 3 | # Python for bioimage analysis 2h lecture + demo 4 | 5 | ## Presentation 6 | About 20m minutes: 7 | * Image based quantitative biology 8 | * Automated microscopy - HCS 9 | * Smart microscopy - Feedback Microscopy 10 | * BioImage Analysis - BIAS 11 | * Why python 12 | * Demo 13 | 14 | ## Python & JupyterLab Installation using virtual environments 15 | 16 | The Jupyter Notebook is available as a part of JupyterLab, so my recommendation is to install JupyterLab as it is the latest generation of the Jupyter project. While JupyterLab is itself a useful development environment, other Integrated Development Environments have great support for Jupyter Notebooks and allow for customization and ease of use, such as [PyCharm](https://www.jetbrains.com/help/pycharm/jupyter-notebook-support.html) and [VSCode](https://code.visualstudio.com/docs/datascience/jupyter-notebooks). To keep the demo simple we will use Jupyter's web interface. 17 | 18 | ### Python virtual environments 19 | There are many ways to install Python [e.g.1](https://wiki.python.org/moin/BeginnersGuide/Download) & [e.g.2](https://realpython.com/installing-python/), but in a nutshell, there is something to keep in mind: different projects might need different flavours of Python with different sets of libraries. This is why it is strongly recommended that you manage your Python installations via “virtual environments”. You can think of virtual environments as an isolated set-up of Python that you wish to use including libraries and their versions. They can easily be created, modified and shared. It is for this reason that we suggest an installation workflow that includes the installation of [miniconda](https://docs.conda.io/en/latest/miniconda.html), a tool that can manage multiple virtual environments. Anohter good recomedation is the use of [mamba](https://mamba.readthedocs.io/en/latest/index.html) a fast and corss-platform package manager. 20 | 21 | ### Examples 22 | 1) [Book 1](./book-01-rice-example.ipynb) Rice Example From the article: ["Jupyter Notebooks for Generating and Distributing Bioimage Analysis Workflows"](https://analyticalscience.wiley.com/do/10.1002/was.0004000374) 23 | 24 | 2) [Book 2](./book-02-quick-example-BIAS.ipynb) based on data from one of the students from 2023 25 | 26 | ### Instalation 27 | ### 1.1) Installing miniforge: 28 | Miniforge is a free minimal installer for conda. The latest installation instructions can be found at: 29 | https://github.com/conda-forge/miniforge 30 | 31 | Once installed you should have access to the “Miniforge Prompt”. To test your installation, simply open the Miniforge Prompt, and then write the command: 32 | ``` 33 | > Python 34 | ``` 35 | This should open Python in your terminal. Notice the “>>>” in the prompt. To exit Python you can run the command: 36 | ``` 37 | >>> quit() 38 | ``` 39 | ### 1.2) Create a virtual environment that will be used to install Jupyter Lab. 40 | **Note** that we will use python 3.9 to be compatible with Napari. Go to the Anaconda Prompt and run the command: 41 | ``` 42 | > conda create -y -n pybias-env -c conda-forge python=3.9 43 | ``` 44 | ### 1.3) Activate environment 45 | Once the virtual environment with the name pybias-env is created, then you can activate it to install the desired packages. 46 | ``` 47 | > conda activate pybias-env 48 | ``` 49 | **Note** how the terminal now starts with (pybias-env) 50 | ### 1.4) Install JupyterLab 51 | Now we install JupyterLab in the environment using 52 | ``` 53 | > conda install -c conda-forge jupyterlab 54 | ``` 55 | ### 1.5) Make virtual environment available to JupyterLab 56 | To make our current environment (kernel) available to JupyterLab we use: 57 | ``` 58 | > ipython kernel install --user --name=pybias-env 59 | ``` 60 | ## JupyterLab’s web interface 61 | When we launch a Jupyter Notebook, we use the “IPython Kernel” in the background, a library that offers an interactive command line interface. You can think of IPython Kernel as the computer engine that runs the code contained in a Notebook document. ipykernel is installed alongside JupyterLab, and that is why we can use it directly. 62 | 63 | ### 2) Starting JupyterLab’s web interface 64 | Starting JupyterLab is very simple. 65 | ### 2.1) Open the anaconda prompt 66 | Open the anaconda prompt and navigate to the desired folder. Below is an example using an empty folder named “jlab” in my “Documents” folder. 67 | ``` 68 | > cd Documents/jlab 69 | ``` 70 | ### 2.2) Activate appropiate environment 71 | Make sure you have activated the ```pybias-env``` environment (see above installation procedure). Then run the command: 72 | ``` 73 | > jupyter lab 74 | ``` 75 | A web browser should open with the address: http://localhost:8888/lab 76 | 77 | ## 3) Creating a new Jupyter Notebook 78 | You can find great documentation on [how to create Notebooks using JupyterLab](https://jupyterlab.readthedocs.io/en/stable/user/notebook.html). Bellow is a minimal example: 79 | 80 | 3.1) Go to the JupyterLab web interface. 81 | 82 | 3.2) Go to File > New > Notebook 83 | 84 | 3.3) Select the Kernel we have created: ```pybias-env``` 85 | 86 | 3.4) Go to File > Save Notebook to rename your file as desired: e.g., ```Example.ipynb``` 87 | 88 | ## 4) Notebook Cells 89 | A Notebook’s cell can contain either live code, or documentation information in the form of formatted text via [Markdown](https://daringfireball.net/projects/markdown/), see for example Figure 02 of the manuscript. To start exploring Notebook Cells write the following on the first cell of your example notebook: 90 | ``` 91 | [ ] print(‘Hi bioimage analyst’) 92 | ``` 93 | Then you can use “ctr + enter” to run the current cell. 94 | 95 | ## 5) Simple BIAS Python setup 96 | A bare Jupyter Notebook is not going to take us very far if we try to solve a BIAS problem. To follow the examples depicted in Figures 1-3 of the article we must install ```scikit-image```, which is a collection of algorithms for image processing written in Python, ```matplotlib``` for creating figures, and ```pandas``` to handle tabular data. 97 | 98 | 5.1) Go to the Anaconda Prompt 99 | 100 | 5.2) Activate the pybias-env 101 | ``` 102 | > conda activate pybias-env 103 | ``` 104 | 105 | 5.3) Install scikit-image, matplotlib, and pandas by 106 | 107 | ``` 108 | > conda install -c conda-forge scikit-image matplotlib pandas 109 | ``` 110 | 5.4) Go to the desired path, and start JupyterLab 111 | ``` 112 | > jupyter lab 113 | ``` 114 | 115 | ## 6 Sharing your virtual environment with others 116 | 117 | 6.1) Activate the environment to export, e.g. our Jupyter.env 118 | ``` 119 | > conda activate pybias-env 120 | ``` 121 | 6.2) Export the active environment to a file 122 | ``` 123 | > conda env export > environment.yml 124 | ``` 125 | 6.3) Email a copy of this file together with the Notebook file. 126 | 127 | 6.4) Instruct your collaborator to create the environment locally from the environment.yml file via: 128 | ``` 129 | > conda env create -f environment.yml 130 | ``` 131 | 132 | The managing of environments is an interesting topic in its own right and good documentation can be found at the [anaconda site](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html). 133 | 134 | ## 7) Importing microscopy images and metadata into python 135 | One critical aspect when handling microscopy images is the import of data from proprietary file formats and the correct handling of image metadata. Here, we can recommend to look at [AICSImageIO](https://github.com/AllenCellModeling/aicsimageio) a library to handle image reading, metadata conversion, and image writing for microscopy images in python. A minimal example can be found in their [quickstart](https://github.com/AllenCellModeling/aicsimageio#quickstart) 136 | 137 | ## 8) Python resources for bioimage analysis 138 | 139 | ### The Image.sc Forum 140 | A scientific community forum for discussing image analysis software: [link to the Forum](https://forum.image.sc/). Many bioimage analysts and developers are available at the forum and it is a great place to ask Python BIAS-related questions. 141 | ### scikit-image 142 | A collection of algorithms for image processing written in Python [project site](https://scikit-image.org/). It has great documentation, implementation examples, and an active community that can be reached via its website, or the Image.sc forum. 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /short-lectures-demos/pyBIAS_2h_240926/environment.yml: -------------------------------------------------------------------------------- 1 | name: pybias-env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python=3.9 7 | # image processing 8 | - scikit-image 9 | - scipy 10 | # related to jupyter notebooks 11 | - jupyterlab 12 | - ipykernel 13 | - stackview 14 | # data handling and plotting 15 | - pandas 16 | - matplotlib 17 | - seaborn 18 | # pip packages 19 | - pip: 20 | - oiffile[all] -------------------------------------------------------------------------------- /short-lectures-demos/pyBIAS_2h_240926/imshow-test.py: -------------------------------------------------------------------------------- 1 | # based on a question by a students that uses Matplotlib and Seaborn 2 | # 3 | # simple code that shows how to leave matplotlib and seaborn figures open 4 | # while running a script. 5 | 6 | import skimage.io as skio 7 | import matplotlib.pyplot as plt 8 | import seaborn as sns 9 | from pathlib import Path 10 | 11 | # loading the file into memory 12 | script_path = Path(__file__) 13 | tif_path = script_path.parents[1].joinpath("data","rice.tif") 14 | print(tif_path) 15 | img = skio.imread(tif_path, plugin="tifffile") 16 | 17 | # check image size 18 | print(img.shape) 19 | 20 | # create figure using Matplotlib 21 | plt.figure(figsize=(4, 4), dpi=300) 22 | plt.imshow(img, cmap="gray") 23 | plt.colorbar() 24 | plt.title('Rice image') 25 | plt.axis('off') 26 | # this creates the figure and continues running the script 27 | plt.draw() 28 | 29 | # seaborn example using data from their examples 30 | sns.set_theme(style="ticks") 31 | 32 | # Load the example dataset for Anscombe's quartet 33 | df = sns.load_dataset("anscombe") 34 | 35 | # Show the results of a linear regression within each dataset 36 | sns.lmplot( 37 | data=df, x="x", y="y", col="dataset", hue="dataset", 38 | col_wrap=2, palette="muted", ci=None, 39 | height=4, scatter_kws={"s": 50, "alpha": 1} 40 | ) 41 | # this shows the image and keep them open, for the script 42 | # to continue you have to close the iamges 43 | plt.show() -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220503/01_napari_from_script.py: -------------------------------------------------------------------------------- 1 | import napari 2 | from skimage.data import astronaut 3 | 4 | # create the viewer and display the image 5 | viewer = napari.Viewer() 6 | new_layer = viewer.add_image(astronaut(), rgb=True) 7 | napari.run() -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220503/06_assitant-example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "674df785", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "from skimage.io import imread\n", 11 | "import pyclesperanto_prototype as cle\n", 12 | "import napari_simpleitk_image_processing as nsitk\n", 13 | "import napari\n", 14 | "viewer = napari.Viewer()" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "id": "d14f1dc1", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "image0_C1c = imread(\n", 25 | " \"C:/Users/CCI/Documents/Image_Processing/quick_demo/data/telomeres/C2-condition_1_crop.tif\")\n", 26 | "viewer.add_image(image0_C1c, name=\"C2-condition_1_crop\")" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "id": "3eed2c99", 32 | "metadata": {}, 33 | "source": [ 34 | "## gaussian blur" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "id": "6c8ad3b8", 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "image1_gb = cle.gaussian_blur(image0_C1c, None, 5.0, 5.0, 0.0)\n", 45 | "viewer.add_image(image1_gb, name='Result of gaussian_blur (clesperanto)')\n", 46 | "napari.utils.nbscreenshot(viewer)" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "id": "0ca56e68", 52 | "metadata": {}, 53 | "source": [ 54 | "## gradient magnitude" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "id": "112f5089", 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "image2_G = nsitk.gradient_magnitude(image1_gb)\n", 65 | "viewer.add_image(image2_G, name='Result of Gradient magnitude (n-SimpleITK)')\n", 66 | "napari.utils.nbscreenshot(viewer)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "id": "bafafa08", 72 | "metadata": {}, 73 | "source": [ 74 | "## threshold otsu" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "id": "71a7582d", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "image3_to = cle.threshold_otsu(image1_gb)\n", 85 | "viewer.add_labels(image3_to, name='Result of threshold_otsu (clesperanto)')\n", 86 | "napari.utils.nbscreenshot(viewer)" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "id": "f7db50ee", 92 | "metadata": {}, 93 | "source": [ 94 | "## voronoi otsu labeling" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "id": "5319aaf2", 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "image4_vol = cle.voronoi_otsu_labeling(image3_to, None, 10.0, -5.0)\n", 105 | "viewer.add_labels(\n", 106 | " image4_vol, name='Result of voronoi_otsu_labeling (clesperanto)')\n", 107 | "napari.utils.nbscreenshot(viewer)" 108 | ] 109 | } 110 | ], 111 | "metadata": { 112 | "jupytext": { 113 | "cell_metadata_filter": "-all", 114 | "main_language": "python", 115 | "notebook_metadata_filter": "-all" 116 | }, 117 | "language_info": { 118 | "name": "python" 119 | } 120 | }, 121 | "nbformat": 4, 122 | "nbformat_minor": 5 123 | } 124 | -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220503/environment.yml: -------------------------------------------------------------------------------- 1 | name: demo-env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - alabaster=0.7.12=py_0 7 | - anyio=3.5.0=py39hcbf5309_0 8 | - aom=3.3.0=h0e60522_1 9 | - appdirs=1.4.4=pyh9f0ad1d_0 10 | - argon2-cffi=21.3.0=pyhd8ed1ab_0 11 | - argon2-cffi-bindings=21.2.0=py39hb82d6ee_2 12 | - asciitree=0.3.3=py_2 13 | - asttokens=2.0.5=pyhd8ed1ab_0 14 | - attrs=21.4.0=pyhd8ed1ab_0 15 | - babel=2.9.1=pyh44b312d_0 16 | - backcall=0.2.0=pyh9f0ad1d_0 17 | - backports=1.0=py_2 18 | - backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0 19 | - beautifulsoup4=4.11.1=pyha770c72_0 20 | - bleach=5.0.0=pyhd8ed1ab_0 21 | - blosc=1.21.1=hcbbf2c4_0 22 | - bokeh=2.4.2=py39hcbf5309_1 23 | - brotli=1.0.9=h8ffe710_7 24 | - brotli-bin=1.0.9=h8ffe710_7 25 | - brotlipy=0.7.0=py39hb82d6ee_1004 26 | - bzip2=1.0.8=h8ffe710_4 27 | - c-blosc2=2.0.4=h09319c2_1 28 | - ca-certificates=2021.10.8=h5b45459_0 29 | - cachey=0.2.1=pyh9f0ad1d_0 30 | - certifi=2021.10.8=py39hcbf5309_2 31 | - cffi=1.15.0=py39h0878f49_0 32 | - cfitsio=4.1.0=h5a969a9_0 33 | - charls=2.3.4=h39d44d4_0 34 | - charset-normalizer=2.0.12=pyhd8ed1ab_0 35 | - click=8.1.3=py39hcbf5309_0 36 | - cloudpickle=2.0.0=pyhd8ed1ab_0 37 | - colorama=0.4.4=pyh9f0ad1d_0 38 | - cryptography=36.0.2=py39h7bc7c5c_1 39 | - cycler=0.11.0=pyhd8ed1ab_0 40 | - cytoolz=0.11.2=py39hb82d6ee_2 41 | - dask=2022.4.2=pyhd8ed1ab_0 42 | - dask-core=2022.4.2=pyhd8ed1ab_0 43 | - debugpy=1.6.0=py39h415ef7b_0 44 | - decorator=5.1.1=pyhd8ed1ab_0 45 | - defusedxml=0.7.1=pyhd8ed1ab_0 46 | - distributed=2022.4.2=pyhd8ed1ab_0 47 | - docstring_parser=0.13=pyhd8ed1ab_0 48 | - docutils=0.15.2=py39hcbf5309_3 49 | - entrypoints=0.4=pyhd8ed1ab_0 50 | - executing=0.8.3=pyhd8ed1ab_0 51 | - fasteners=0.17.3=pyhd8ed1ab_0 52 | - flit-core=3.7.1=pyhd8ed1ab_0 53 | - fonttools=4.33.3=py39hb82d6ee_0 54 | - freetype=2.10.4=h546665d_1 55 | - freetype-py=2.3.0=pyhd8ed1ab_0 56 | - fsspec=2022.3.0=pyhd8ed1ab_0 57 | - giflib=5.2.1=h8d14728_2 58 | - heapdict=1.0.1=py_0 59 | - hsluv=5.0.2=pyh44b312d_0 60 | - icu=69.1=h0e60522_0 61 | - idna=3.3=pyhd8ed1ab_0 62 | - imagecodecs=2022.2.22=py39hc1e9cd8_4 63 | - imageio=2.18.0=pyhcf75d05_0 64 | - imagesize=1.3.0=pyhd8ed1ab_0 65 | - importlib-metadata=4.11.3=py39hcbf5309_1 66 | - importlib_metadata=4.11.3=hd8ed1ab_1 67 | - importlib_resources=5.7.1=pyhd8ed1ab_0 68 | - intel-openmp=2022.0.0=h57928b3_3663 69 | - intervaltree=3.0.2=py_0 70 | - ipykernel=6.13.0=py39h832f523_0 71 | - ipython=8.3.0=py39hcbf5309_0 72 | - ipython_genutils=0.2.0=py_1 73 | - jbig=2.1=h8d14728_2003 74 | - jedi=0.18.1=py39hcbf5309_1 75 | - jinja2=3.0.3=pyhd8ed1ab_0 76 | - jpeg=9e=h8ffe710_1 77 | - json5=0.9.5=pyh9f0ad1d_0 78 | - jsonschema=4.4.0=pyhd8ed1ab_0 79 | - jupyter_client=7.3.0=pyhd8ed1ab_0 80 | - jupyter_core=4.9.2=py39hcbf5309_0 81 | - jupyter_server=1.17.0=pyhd8ed1ab_0 82 | - jupyterlab=3.3.4=pyhd8ed1ab_0 83 | - jupyterlab_pygments=0.2.2=pyhd8ed1ab_0 84 | - jupyterlab_server=2.13.0=pyhd8ed1ab_1 85 | - jxrlib=1.1=h8ffe710_2 86 | - kiwisolver=1.4.2=py39h2e07f2f_1 87 | - krb5=1.19.3=h1176d77_0 88 | - lcms2=2.12=h2a16943_0 89 | - lerc=3.0=h0e60522_0 90 | - libaec=1.0.6=h39d44d4_0 91 | - libavif=0.10.1=h8ffe710_0 92 | - libblas=3.9.0=14_win64_mkl 93 | - libbrotlicommon=1.0.9=h8ffe710_7 94 | - libbrotlidec=1.0.9=h8ffe710_7 95 | - libbrotlienc=1.0.9=h8ffe710_7 96 | - libcblas=3.9.0=14_win64_mkl 97 | - libclang=13.0.1=default_h81446c8_0 98 | - libcurl=7.83.0=h789b8ee_0 99 | - libdeflate=1.10=h8ffe710_0 100 | - libffi=3.4.2=h8ffe710_5 101 | - liblapack=3.9.0=14_win64_mkl 102 | - libpng=1.6.37=h1d00b33_2 103 | - libsodium=1.0.18=h8d14728_1 104 | - libssh2=1.10.0=h680486a_2 105 | - libtiff=4.3.0=hc4061b1_3 106 | - libwebp=1.2.2=h57928b3_0 107 | - libwebp-base=1.2.2=h8ffe710_1 108 | - libxcb=1.13=hcd874cb_1004 109 | - libzlib=1.2.11=h8ffe710_1014 110 | - libzopfli=1.0.3=h0e60522_0 111 | - locket=1.0.0=pyhd8ed1ab_0 112 | - lz4=4.0.0=py39h0878066_1 113 | - lz4-c=1.9.3=h8ffe710_1 114 | - m2w64-gcc-libgfortran=5.3.0=6 115 | - m2w64-gcc-libs=5.3.0=7 116 | - m2w64-gcc-libs-core=5.3.0=7 117 | - m2w64-gmp=6.1.0=2 118 | - m2w64-libwinpthread-git=5.0.0.4634.697f757=2 119 | - magicgui=0.4.0=pyhd8ed1ab_0 120 | - markupsafe=2.1.1=py39hb82d6ee_1 121 | - matplotlib-base=3.5.1=py39h581301d_0 122 | - matplotlib-inline=0.1.3=pyhd8ed1ab_0 123 | - mistune=0.8.4=py39hb82d6ee_1005 124 | - mkl=2022.0.0=h0e2418a_796 125 | - msgpack-python=1.0.3=py39h2e07f2f_1 126 | - msys2-conda-epoch=20160418=1 127 | - munkres=1.1.4=pyh9f0ad1d_0 128 | - napari=0.4.14=pyhd8ed1ab_0 129 | - napari-console=0.0.4=pyhd8ed1ab_1 130 | - napari-plugin-engine=0.2.0=pyhd8ed1ab_2 131 | - napari-svg=0.1.5=pyhd8ed1ab_0 132 | - nbclassic=0.3.7=pyhd8ed1ab_0 133 | - nbclient=0.6.0=pyhd8ed1ab_0 134 | - nbconvert=6.5.0=pyhd8ed1ab_0 135 | - nbconvert-core=6.5.0=pyhd8ed1ab_0 136 | - nbconvert-pandoc=6.5.0=pyhd8ed1ab_0 137 | - nbformat=5.3.0=pyhd8ed1ab_0 138 | - nest-asyncio=1.5.5=pyhd8ed1ab_0 139 | - networkx=2.8=pyhd8ed1ab_0 140 | - notebook=6.4.11=pyha770c72_0 141 | - notebook-shim=0.1.0=pyhd8ed1ab_0 142 | - npe2=0.3.0=pyhd8ed1ab_0 143 | - numcodecs=0.9.1=py39h415ef7b_2 144 | - numpy=1.22.3=py39h0948cea_2 145 | - numpydoc=1.3.1=pyhd8ed1ab_0 146 | - openjpeg=2.4.0=hb211442_1 147 | - openssl=1.1.1n=h8ffe710_0 148 | - packaging=21.3=pyhd8ed1ab_0 149 | - pandas=1.4.2=py39h2e25243_1 150 | - pandoc=2.18=h57928b3_0 151 | - pandocfilters=1.5.0=pyhd8ed1ab_0 152 | - parso=0.8.3=pyhd8ed1ab_0 153 | - partd=1.2.0=pyhd8ed1ab_0 154 | - pickleshare=0.7.5=py_1003 155 | - pillow=9.1.0=py39ha53f419_2 156 | - pint=0.19.2=pyhd8ed1ab_0 157 | - pip=22.0.4=pyhd8ed1ab_0 158 | - pooch=1.6.0=pyhd8ed1ab_0 159 | - prometheus_client=0.14.1=pyhd8ed1ab_0 160 | - prompt-toolkit=3.0.29=pyha770c72_0 161 | - psutil=5.9.0=py39hb82d6ee_1 162 | - psygnal=0.3.3=py39h2e07f2f_0 163 | - pthread-stubs=0.4=hcd874cb_1001 164 | - pure_eval=0.2.2=pyhd8ed1ab_0 165 | - pycparser=2.21=pyhd8ed1ab_0 166 | - pydantic=1.9.0=py39hb82d6ee_1 167 | - pygments=2.12.0=pyhd8ed1ab_0 168 | - pyopengl=3.1.6=pyh6c4a22f_0 169 | - pyopenssl=22.0.0=pyhd8ed1ab_0 170 | - pyparsing=3.0.8=pyhd8ed1ab_0 171 | - pyqt=5.12.3=py39hcbf5309_8 172 | - pyqt-impl=5.12.3=py39h415ef7b_8 173 | - pyqt5-sip=4.19.18=py39h415ef7b_8 174 | - pyqtchart=5.12=py39h415ef7b_8 175 | - pyqtwebengine=5.12.1=py39h415ef7b_8 176 | - pyrsistent=0.18.1=py39hb82d6ee_1 177 | - pysocks=1.7.1=py39hcbf5309_5 178 | - python=3.9.12=h9a09f29_1_cpython 179 | - python-dateutil=2.8.2=pyhd8ed1ab_0 180 | - python-fastjsonschema=2.15.3=pyhd8ed1ab_0 181 | - python_abi=3.9=2_cp39 182 | - pytomlpp=1.0.11=py39h1f6ef14_0 183 | - pytz=2022.1=pyhd8ed1ab_0 184 | - pywavelets=1.3.0=py39h5d4886f_1 185 | - pywin32=303=py39hb82d6ee_0 186 | - pywinpty=2.0.5=py39h99910a6_1 187 | - pyyaml=6.0=py39hb82d6ee_4 188 | - pyzmq=22.3.0=py39he46f08e_2 189 | - qt=5.12.9=h556501e_6 190 | - qtconsole-base=5.3.0=pyhd8ed1ab_0 191 | - qtpy=2.0.1=pyhd8ed1ab_0 192 | - requests=2.27.1=pyhd8ed1ab_0 193 | - scikit-image=0.19.2=py39h2e25243_0 194 | - scipy=1.8.0=py39hc0c34ad_1 195 | - send2trash=1.8.0=pyhd8ed1ab_0 196 | - setuptools=62.1.0=py39hcbf5309_0 197 | - shellingham=1.4.0=pyh44b312d_0 198 | - six=1.16.0=pyh6c4a22f_0 199 | - snappy=1.1.8=ha925a31_3 200 | - sniffio=1.2.0=py39hcbf5309_3 201 | - snowballstemmer=2.2.0=pyhd8ed1ab_0 202 | - sortedcontainers=2.4.0=pyhd8ed1ab_0 203 | - soupsieve=2.3.1=pyhd8ed1ab_0 204 | - sphinx=4.5.0=pyh6c4a22f_0 205 | - sphinxcontrib-applehelp=1.0.2=py_0 206 | - sphinxcontrib-devhelp=1.0.2=py_0 207 | - sphinxcontrib-htmlhelp=2.0.0=pyhd8ed1ab_0 208 | - sphinxcontrib-jsmath=1.0.1=py_0 209 | - sphinxcontrib-qthelp=1.0.3=py_0 210 | - sphinxcontrib-serializinghtml=1.1.5=pyhd8ed1ab_2 211 | - sqlite=3.38.3=h8ffe710_0 212 | - stack_data=0.2.0=pyhd8ed1ab_0 213 | - superqt=0.3.1=pyhd8ed1ab_0 214 | - tbb=2021.5.0=h2d74725_1 215 | - tblib=1.7.0=pyhd8ed1ab_0 216 | - terminado=0.13.3=py39hcbf5309_1 217 | - tifffile=2022.4.28=pyhd8ed1ab_0 218 | - tinycss2=1.1.1=pyhd8ed1ab_0 219 | - tk=8.6.12=h8ffe710_0 220 | - toolz=0.11.2=pyhd8ed1ab_0 221 | - tornado=6.1=py39hb82d6ee_3 222 | - tqdm=4.64.0=pyhd8ed1ab_0 223 | - traitlets=5.1.1=pyhd8ed1ab_0 224 | - typer=0.4.1=pyhd8ed1ab_0 225 | - typing-extensions=4.2.0=hd8ed1ab_1 226 | - typing_extensions=4.2.0=pyha770c72_1 227 | - tzdata=2022a=h191b570_0 228 | - ucrt=10.0.20348.0=h57928b3_0 229 | - unicodedata2=14.0.0=py39hb82d6ee_1 230 | - urllib3=1.26.9=pyhd8ed1ab_0 231 | - vc=14.2=hb210afc_6 232 | - vispy=0.10.0=py39h5d4886f_0 233 | - vs2015_runtime=14.29.30037=h902a5da_6 234 | - wcwidth=0.2.5=pyh9f0ad1d_2 235 | - webencodings=0.5.1=py_1 236 | - websocket-client=1.3.2=pyhd8ed1ab_0 237 | - wheel=0.37.1=pyhd8ed1ab_0 238 | - win_inet_pton=1.1.0=py39hcbf5309_4 239 | - winpty=0.4.3=4 240 | - wrapt=1.14.0=py39hb82d6ee_1 241 | - xorg-libxau=1.0.9=hcd874cb_0 242 | - xorg-libxdmcp=1.1.3=hcd874cb_0 243 | - xz=5.2.5=h62dcd97_1 244 | - yaml=0.2.5=h8ffe710_2 245 | - zarr=2.11.3=pyhd8ed1ab_0 246 | - zeromq=4.3.4=h0e60522_1 247 | - zfp=0.5.5=h0e60522_8 248 | - zict=2.2.0=pyhd8ed1ab_0 249 | - zipp=3.8.0=pyhd8ed1ab_0 250 | - zlib=1.2.11=h8ffe710_1014 251 | - zstd=1.5.2=h6255e5f_0 252 | prefix: C:\Users\CCI\.conda\envs\demo-env 253 | -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220928/01_napari_from_script.py: -------------------------------------------------------------------------------- 1 | # super simple example of runing napari from a python 2 | # script. date: 2022-sep 3 | # github: camachodejay 4 | from skimage import data 5 | import napari 6 | 7 | # start the viewer and add the image data 8 | viewer = napari.view_image(data.astronaut(), rgb=True) 9 | napari.run() # start the event loop and show viewer -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220928/README.md: -------------------------------------------------------------------------------- 1 | # Quick demo on image processing using python 2 | 3 | I will show case how to do a basic image analysis pipeline using Python packages such as skimage and napari. 4 | 5 | ## Learning outcome 6 | 7 | * Basic understanding of Napari as an image viewer 8 | 9 | * How to install image processing packages 10 | 11 | * How to do a basic image analysis pipeline including 12 | * Image loading 13 | * Image exploration 14 | * Thresholding 15 | * Filtering - background substraction 16 | * Basic quantification based on image mask/labels 17 | 18 | ## Prerequisites 19 | 20 | To save time during the session, I assume that students have access to a computer with already installed [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html) (Anaconda Prompt), and [git](https://github.com/git-guides/install-git) command line tools. Further, I will be using [VS Code](https://code.visualstudio.com/docs) to go over the material. 21 | 22 | ## How to install required packages 23 | 24 | To make things easier we will be using [conda to install python and manage our virtual environments.](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html) Think of a [virtual environment](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) as a box (directory) that contains a specific collection tools (e.g. Python + packages) that you have installed. The good thing is that you can have different boxes/environments, and if you change one environment, your other environments are not affected. To work with them we will then "activate" the box we want to use. 25 | 26 | ## Creating a conda env via a yml file 27 | 28 | **Prerequisite** to go over these steps you need to have installed ```conda```, and the anaconda prompt on your computer. 29 | 30 | S1.1 Open an Anaconda Promt: 31 | 32 | * Open Anaconda Prompt (Anaconda 3) 33 | 34 | S1.2 Create a new conda environment for Python using this command in the promt. First navigate to the folder **quick_demo_220928**, then: 35 | 36 | ``` 37 | > conda env create -f environment.yml 38 | ``` 39 | 40 | After ```conda``` has done its job you have created a new "box" containing a copy of Python version 3.9. The name of this environment is ```demo-env``` and as ```conda```channel we have used ```conda-forge```. Think of a conda channel as buying your products from a specific shop. ```conda-forge``` is my favorite store, but this discussion is a bit out of the scope of the session. 41 | 42 | S1.3 Now activate your conda environment: 43 | 44 | ``` 45 | > conda activate demo-env 46 | ``` 47 | 48 | S1.4 Test python 49 | ``` 50 | > python --version 51 | ``` 52 | 53 | ## VS Code 54 | 55 | VS Code is a lightweight source code editor which runs on your desktop and is available for Windows, macOS and Linux. Using its extensions it is a great tool for Python and Jupyter books. 56 | 57 | How to install it (not live): please follow the [instructions here to install VS Code](https://code.visualstudio.com/docs/setup/setup-overview), and the [nice documentation here to have it ready for python.](https://code.visualstudio.com/docs/languages/python). 58 | 59 | ## What is a Jupyter Notebook 60 | 61 | Jupyter notebooks are a great tool for interactive programming in Data Science. [Look at this great article.](https://towardsdatascience.com/the-complete-guide-to-jupyter-notebooks-for-data-science-8ff3591f69a4) You can think of them as interactive books where we can "attach" a Python environment and interactively run pieces of code. Lets do a small demo so it is easier to understand. 62 | 63 | ## Installing jupyterlab 64 | 65 | This step can be skiped in this demo because we already have jupyterlab installed in our ```demo-env```. However, if this is not the case you might have to install it separately via: 66 | 67 | * Go to the Anaconda Prompt 68 | 69 | ``` 70 | > conda install -c conda-forge jupyterlab 71 | ``` 72 | 73 | ## Step 3 Using VS Code to create and run Jupyter Notebooks 74 | 75 | You can go over [this guide to get many details on how to use Jupyter notebooks in VS Code](https://code.visualstudio.com/docs/datascience/jupyter-notebooks). Below a practical example. 76 | 77 | S3.1 Crete new jupyter book in VS Code 78 | 79 | * Create a new notebook by creating a new ```.ipynb``` file in your workspace. The extension resembles Ipython NoteBook 80 | 81 | * Alternatively 82 | * use Ctr + Shift + P to open the command palleteinter 83 | * look for ```jupyter``` 84 | * choose ```Python: Create: New Jupyter Notebook``` 85 | * use: File -> Save to save the file with ```.ipynb``` extension 86 | * Select your kernel AKA virtual environment 87 | * Create a cell with simple math: 88 | 89 | ```python 90 | a = 3 91 | b = 6 92 | a+b 93 | ``` 94 | 95 | * Try to run the cell and you might notice a complaint from VS Code. Make sure you installed ```ipykernel```. This is already done in the demo-env 96 | 97 | ## To continue working on our use case 98 | 99 | Now lets move to the example books in this repo. 100 | 101 | ## Where to go next 102 | 103 | Now you are set to a great start. Feel free to play with this notebooks with basic Python if you want to get familiar with the language. There are many cool websites and videos including. 104 | 105 | * YouTube series by google team on Python: [day 1 link](https://youtu.be/tKTZoB2Vjuk) 106 | * [RealPython website](https://realpython.com/) 107 | * YouTube series by Neubias Academy on using [Python for image analysis](https://youtu.be/2KF8vBrp3Zw) 108 | * PoL Dresden [course on BioImage analysis using Python](https://github.com/BiAPoL/Bio-image_Analysis_with_Python) -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220928/data/rice.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short-lectures-demos/quick_demo_220928/data/rice.tif -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220928/data/rice_lbl.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short-lectures-demos/quick_demo_220928/data/rice_lbl.tif -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220928/data/rice_mask.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short-lectures-demos/quick_demo_220928/data/rice_mask.tif -------------------------------------------------------------------------------- /short-lectures-demos/quick_demo_220928/environment.yml: -------------------------------------------------------------------------------- 1 | name: demo-env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python=3.9 7 | # image viever: napari, also includes skimage 8 | - napari 9 | # related to jupyter notebooks 10 | - ipykernel 11 | - jupyterlab 12 | # data handling and plotting 13 | - pandas 14 | - matplotlib -------------------------------------------------------------------------------- /short_examples/alignment/im_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short_examples/alignment/im_data.png -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/data/t01.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short_examples/zarr-from-tiles/data/t01.tif -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/data/t02.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short_examples/zarr-from-tiles/data/t02.tif -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/data/t03.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short_examples/zarr-from-tiles/data/t03.tif -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/data/t04.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short_examples/zarr-from-tiles/data/t04.tif -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/data/t05.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CamachoDejay/teaching-bioimage-analysis-python/6dce120f5cb13bd8cf54361dbe58b895b5243608/short_examples/zarr-from-tiles/data/t05.tif -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/data/tile_centre.csv: -------------------------------------------------------------------------------- 1 | 51, 51 2 | 132, 51 3 | 213, 51 4 | 100, 132 5 | 181,132 -------------------------------------------------------------------------------- /short_examples/zarr-from-tiles/zarr-minimal-example-tiles.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# Simple tile 2 zarr creation using centre positions\n", 9 | "\n", 10 | "**NOTE**: All tiltes have same dimentions, they have been pre stitched and there is no overlap between them. The arrangement of the tiles does not have to follow the clasical checkboard structure." 11 | ] 12 | }, 13 | { 14 | "attachments": {}, 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "## Loading centre position metadata from CVS file using pandas" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "import pandas as pd\n", 28 | "from pathlib import Path\n", 29 | "import numpy as np\n", 30 | "import skimage.io as skio" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "data": { 40 | "text/html": [ 41 | "
\n", 42 | "\n", 55 | "\n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | "
centre_xcentre_y
05151
113251
221351
3100132
4181132
\n", 91 | "
" 92 | ], 93 | "text/plain": [ 94 | " centre_x centre_y\n", 95 | "0 51 51\n", 96 | "1 132 51\n", 97 | "2 213 51\n", 98 | "3 100 132\n", 99 | "4 181 132" 100 | ] 101 | }, 102 | "execution_count": 2, 103 | "metadata": {}, 104 | "output_type": "execute_result" 105 | } 106 | ], 107 | "source": [ 108 | "csv_p = Path(r\"./data/tile_centre.csv\")\n", 109 | "df = pd.read_csv(csv_p, header=None, names=[\"centre_x\", \"centre_y\"])\n", 110 | "df" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 3, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "name": "stderr", 120 | "output_type": "stream", 121 | "text": [ 122 | "TiffPage 0: TypeError: read_bytes() missing 3 required positional arguments: 'dtype', 'count', and 'offsetsize'\n" 123 | ] 124 | }, 125 | { 126 | "name": "stdout", 127 | "output_type": "stream", 128 | "text": [ 129 | "there are 5 tiles in the csv file\n", 130 | "in this example each tile is 81x81 pixels\n" 131 | ] 132 | } 133 | ], 134 | "source": [ 135 | "n_tiles = len(df.index)\n", 136 | "print(f\"there are {n_tiles} tiles in the csv file\")\n", 137 | "\n", 138 | "# reading first tile to get size, in this case we assume that the size is homogeneous\n", 139 | "tile_idx = 0\n", 140 | "tile_0 = skio.imread(f\"./data/t0{tile_idx+1}.tif\", plugin=\"tifffile\")\n", 141 | "\n", 142 | "tile_shape = tile_0.shape\n", 143 | "tile_type = tile_0.dtype\n", 144 | "print(f\"in this example each tile is {tile_shape[0]}x{tile_shape[1]} pixels\")" 145 | ] 146 | }, 147 | { 148 | "attachments": {}, 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "# Add corner information\n", 153 | "For this we need to know each tile dimention" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 4, 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/html": [ 164 | "
\n", 165 | "\n", 178 | "\n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | "
centre_xcentre_ysize_xsize_y
051518181
1132518181
2213518181
31001328181
41811328181
\n", 226 | "
" 227 | ], 228 | "text/plain": [ 229 | " centre_x centre_y size_x size_y\n", 230 | "0 51 51 81 81\n", 231 | "1 132 51 81 81\n", 232 | "2 213 51 81 81\n", 233 | "3 100 132 81 81\n", 234 | "4 181 132 81 81" 235 | ] 236 | }, 237 | "execution_count": 4, 238 | "metadata": {}, 239 | "output_type": "execute_result" 240 | } 241 | ], 242 | "source": [ 243 | "df['size_x'] = tile_shape[0]\n", 244 | "df['size_y'] = tile_shape[1]\n", 245 | "df" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 5, 251 | "metadata": {}, 252 | "outputs": [ 253 | { 254 | "data": { 255 | "text/html": [ 256 | "
\n", 257 | "\n", 270 | "\n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | "
centre_xcentre_ysize_xsize_ycorner_xcorner_y
0515181811010
11325181819110
221351818117210
310013281815991
4181132818114091
\n", 330 | "
" 331 | ], 332 | "text/plain": [ 333 | " centre_x centre_y size_x size_y corner_x corner_y\n", 334 | "0 51 51 81 81 10 10\n", 335 | "1 132 51 81 81 91 10\n", 336 | "2 213 51 81 81 172 10\n", 337 | "3 100 132 81 81 59 91\n", 338 | "4 181 132 81 81 140 91" 339 | ] 340 | }, 341 | "execution_count": 5, 342 | "metadata": {}, 343 | "output_type": "execute_result" 344 | } 345 | ], 346 | "source": [ 347 | "def simple_shift(val, shift):\n", 348 | " # simple helper function\n", 349 | " return val-shift\n", 350 | "\n", 351 | "df['corner_x'] = df.apply(lambda x: int(x['centre_x']- x['size_x']/2), axis=1)\n", 352 | "df['corner_y'] = df.apply(lambda x: int(x['centre_y']- x['size_y']/2), axis=1)\n", 353 | "\n", 354 | "df" 355 | ] 356 | }, 357 | { 358 | "attachments": {}, 359 | "cell_type": "markdown", 360 | "metadata": {}, 361 | "source": [ 362 | "# Translation of the image to 0,0\n", 363 | "We do not want to have a large empty area." 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": 6, 369 | "metadata": {}, 370 | "outputs": [], 371 | "source": [ 372 | "def translation00(df):\n", 373 | " # simple helper function that translates the array to 0,0\n", 374 | " df00 = df.copy()\n", 375 | " min_x = df.min()[\"corner_x\"]\n", 376 | " min_y = df.min()[\"corner_y\"]\n", 377 | "\n", 378 | " df00['corner_x'] = df00.apply(lambda x: x[\"corner_x\"] - min_x, axis=1)\n", 379 | " df00['centre_x'] = df00.apply(lambda x: x[\"centre_x\"] - min_x, axis=1)\n", 380 | " df00['corner_y'] = df00.apply(lambda x: x[\"corner_y\"] - min_y, axis=1)\n", 381 | " df00['centre_y'] = df00.apply(lambda x: x[\"centre_y\"] - min_y, axis=1)\n", 382 | "\n", 383 | " return df00" 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": 7, 389 | "metadata": {}, 390 | "outputs": [ 391 | { 392 | "data": { 393 | "text/html": [ 394 | "
\n", 395 | "\n", 408 | "\n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | "
centre_xcentre_ysize_xsize_ycorner_xcorner_y
04141818100
1122418181810
22034181811620
39012281814981
4171122818113081
\n", 468 | "
" 469 | ], 470 | "text/plain": [ 471 | " centre_x centre_y size_x size_y corner_x corner_y\n", 472 | "0 41 41 81 81 0 0\n", 473 | "1 122 41 81 81 81 0\n", 474 | "2 203 41 81 81 162 0\n", 475 | "3 90 122 81 81 49 81\n", 476 | "4 171 122 81 81 130 81" 477 | ] 478 | }, 479 | "execution_count": 7, 480 | "metadata": {}, 481 | "output_type": "execute_result" 482 | } 483 | ], 484 | "source": [ 485 | "df00 = translation00(df)\n", 486 | "df00" 487 | ] 488 | }, 489 | { 490 | "attachments": {}, 491 | "cell_type": "markdown", 492 | "metadata": {}, 493 | "source": [ 494 | "## Check size of array \n", 495 | "This is to make it compatible with downscaling later own" 496 | ] 497 | }, 498 | { 499 | "cell_type": "code", 500 | "execution_count": 8, 501 | "metadata": {}, 502 | "outputs": [], 503 | "source": [ 504 | "def optimal_size(current_size, res_levels):\n", 505 | " # helper function that asses the best size given the desired resolution level\n", 506 | " \n", 507 | " div_factor = np.power(2,res_levels)\n", 508 | " rem = np.remainder(current_size, div_factor)\n", 509 | "\n", 510 | " print(f'current size: {current_size}, factor: {div_factor}, reminder: {rem}')\n", 511 | "\n", 512 | " if rem > 0:\n", 513 | " extra = div_factor-rem\n", 514 | " else:\n", 515 | " extra = 0\n", 516 | "\n", 517 | " print(f'we need to add: {extra}, so new size is: {current_size+extra}')\n", 518 | "\n", 519 | " return current_size+extra\n" 520 | ] 521 | }, 522 | { 523 | "cell_type": "code", 524 | "execution_count": 9, 525 | "metadata": {}, 526 | "outputs": [ 527 | { 528 | "name": "stdout", 529 | "output_type": "stream", 530 | "text": [ 531 | "current size: 243, factor: 2, reminder: 1\n", 532 | "we need to add: 1, so new size is: 244\n", 533 | "current size: 162, factor: 2, reminder: 0\n", 534 | "we need to add: 0, so new size is: 162\n" 535 | ] 536 | } 537 | ], 538 | "source": [ 539 | "x_size_tmp = (df00['corner_x']+df00[\"size_x\"]).max()\n", 540 | "total_x = int(optimal_size(x_size_tmp, 1))\n", 541 | "\n", 542 | "y_size_tmp = (df00['corner_y']+df00[\"size_y\"]).max()\n", 543 | "total_y = int(optimal_size(y_size_tmp, 1))\n" 544 | ] 545 | }, 546 | { 547 | "cell_type": "code", 548 | "execution_count": 10, 549 | "metadata": {}, 550 | "outputs": [], 551 | "source": [ 552 | "import matplotlib.pyplot as plt\n", 553 | "from matplotlib.patches import Rectangle" 554 | ] 555 | }, 556 | { 557 | "cell_type": "code", 558 | "execution_count": 11, 559 | "metadata": {}, 560 | "outputs": [ 561 | { 562 | "data": { 563 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAGxCAYAAABMeZ2uAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAvjElEQVR4nO3de3AUZb7/8c9AkkmgwkASmcloAnFPFDCIAoqCSlggGA2olKILsliHdVGENXKTyKKDq4nmuJhdsmChLiAsB61a4Oi6CwTlIgYVuYhcymuEoJlfhMVcuCQh6d8fHOY4JECCM5kn8f2q6oJ++unu7zw8MB+6ezI2y7IsAQAAGKhNqAsAAAA4F4IKAAAwFkEFAAAYi6ACAACMRVABAADGIqgAAABjEVQAAICxCCoAAMBYBBUAAGAsggpgGJvN1qhl48aNeuCBB9S1a1e//bt27aoHHngg6HWmpqYqNTXVt/7NN9/IZrNp8eLFTTrO8uXLlZeX16R9GjqXx+ORzWbT4cOHm3Ss89m3b588Ho+++eabetsaGnsAgRcW6gIA+Nu6davf+h/+8Adt2LBB7777rl97jx49lJCQoEcffbQ5yzun+Ph4bd26Vb/4xS+atN/y5cu1Z88eZWZmBv1cTbVv3z7NmTNHqamp9ULJ7NmzjRl7oDUjqACGueGGG/zWL7nkErVp06ZeuyR16NChucq6ILvd3mCNgVRbW6tTp041y7kuJNghCcBp3PoBWrDG3n4oLy/XtGnTlJSUpIiICF166aXKzMzUsWPHLrivZVnKzc1Vly5dFBkZqd69e+tf//pXvX4N3Y75/vvv9dvf/lYJCQmy2+265JJLNGDAAK1fv17S6dtHb7/9tg4cOOB3W+vHx8vNzdUzzzyjpKQk2e12bdiw4by3mYqLizVy5Eh16NBBDodD999/v77//nu/PjabTR6Pp96+P75ttnjxYt1zzz2SpEGDBvlqO3POhsb+5MmTysrK8hvnRx55RD/88EO982RkZGjNmjXq3bu3oqKi1K1bN/31r389x58C8PPFFRWglTt+/LgGDhyoQ4cO6YknntDVV1+tvXv36sknn9Snn36q9evX+8JBQ+bMmaM5c+Zo/Pjxuvvuu1VcXKwHH3xQtbW1uvLKK8977rFjx2rHjh169tlndcUVV+iHH37Qjh07dOTIEUnS/Pnz9dvf/lZfffWVVq1a1eAx/vznP+uKK67QCy+8oA4dOig5Ofm857zrrrs0atQoPfTQQ9q7d69mz56tffv26cMPP1R4ePgFRuv/3H777crOztYTTzyhv/zlL+rdu7ekc19JsSxLd955p9555x1lZWXp5ptv1u7du/XUU09p69at2rp1q+x2u6//J598oqlTp2rmzJlyOp165ZVXNH78eP3Hf/yHbrnllkbXCbR2BBWglfvzn/+s3bt368MPP1Tfvn0lSYMHD9all16qu+++W2vWrFF6enqD+/7www96/vnnddddd+mVV17xtV911VUaMGDABYPK+++/r9/85jd68MEHfW133HGH7/c9evRQx44dz3srJzIyUmvXrvULGQ093HrGyJEjlZubK0lKS0uT0+nUmDFj9MYbb2jMmDHnrffHLrnkEl8o6tGjxwVvNa1bt05r165Vbm6upk+fLkkaOnSoEhISdO+99+q1117zG4fDhw/r/fffV2JioiTplltu0TvvvKPly5cTVIAf4dYP0Mr94x//UEpKiq655hqdOnXKtwwbNsz36aFz2bp1q06ePFnvDb5///7q0qXLBc99/fXXa/HixXrmmWf0wQcfqKampsn1jxgxoklXQs6uddSoUQoLC9OGDRuafO6mOPOw89mfuLrnnnvUvn17vfPOO37t11xzjS+kSKcD2RVXXKEDBw4EtU6gpSGoAK3c//t//0+7d+9WeHi43xIdHS3Lss77cd4zt2hcLle9bQ21ne3111/XuHHj9Morr+jGG29UTEyMfv3rX8vr9Ta6/vj4+Eb3baiusLAwxcbG+l5LsBw5ckRhYWG65JJL/NptNptcLle988fGxtY7ht1u14kTJ4JaJ9DScOsHaOXi4uIUFRV1zgc14+LizrnvmTfThoKF1+u94IO8cXFxysvLU15eng4ePKg333xTM2fOVGlpqdasWdOo+s/3/ExDvF6vLr30Ut/6qVOndOTIEb9gYLfbVVVVVW/fnxJmYmNjderUKX3//fd+YcWyLHm9Xl133XUXfWzg54wrKkArl5GRoa+++kqxsbHq27dvveV8YeOGG25QZGSk/va3v/m1FxYWNvkWRWJioiZNmqShQ4dqx44dvvZAX0U4u9Y33nhDp06d8vvhdF27dtXu3bv9+r377ruqrKz0azvz8Gtj6hs8eLAkadmyZX7tf//733Xs2DHfdgBNwxUVoJXLzMzU3//+d91yyy167LHHdPXVV6uurk4HDx7UunXrNHXqVPXr16/BfTt16qRp06bpmWee0W9+8xvdc889Ki4ulsfjueCtn7KyMg0aNEijR49Wt27dFB0drW3btmnNmjUaOXKkr1/Pnj21cuVKLViwQH369FGbNm18D/1ejJUrVyosLExDhw71feqnV69eGjVqlK/P2LFjNXv2bD355JMaOHCg9u3bp/z8fDkcDr9jpaSkSJIWLlyo6OhoRUZGKikpqcHbNkOHDtWwYcP0+OOPq7y8XAMGDPB96ufaa6/V2LFjL/o1AT9nBBWglWvfvr3ee+89Pffcc1q4cKGKiooUFRWlxMREDRky5IK3b55++mm1b99e8+fP19KlS9WtWze99NJLeuGFF867X2RkpPr166elS5fqm2++UU1NjRITE/X4449rxowZvn6PPvqo9u7dqyeeeEJlZWWyLEuWZV306125cqU8Ho8WLFggm82m4cOHKy8vTxEREb4+06dPV3l5uRYvXqwXXnhB119/vd544w2/TyRJUlJSkvLy8vSnP/1Jqampqq2t1aJFixr8igKbzabVq1fL4/Fo0aJFevbZZxUXF6exY8cqOzvb76PJABrPZv2UfxEAAACCiGdUAACAsQgqAADAWAQVAABgLIIKAAAwFkEFAAAYi6ACAACMRVABAADGIqgAAABjEVR+ZP78+UpKSlJkZKT69Omj9957L9QltQoej0c2m81v+fGPX7csSx6PR263W1FRUUpNTdXevXtDWHHLs3nzZg0fPlxut9v3E1J/rDFjXFVVpcmTJysuLk7t27fXiBEjdOjQoWZ8FS3Hhcb7gQceqDfnb7jhBr8+jHfj5eTk6LrrrlN0dLQ6d+6sO++8U5999plfH+Z4YDVmzJtrnhNU/tfrr7+uzMxMzZo1Szt37tTNN9+s9PR0HTx4MNSltQpXXXWVSkpKfMunn37q25abm6u5c+cqPz9f27Ztk8vl0tChQ1VRURHCiluWY8eOqVevXsrPz29we2PGODMzU6tWrdKKFSu0ZcsWVVZWKiMjQ7W1tc31MlqMC423JN16661+c/6f//yn33bGu/E2bdqkRx55RB988IEKCgp06tQppaWl6dixY74+zPHAasyYS800zy1YlmVZ119/vfXQQw/5tXXr1s2aOXNmiCpqPZ566imr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5hVaoiY/o1JZWakvv/zSt15UVKRdu3YpJiZGbrdbd999t3bs2KF//OMfqq2t9T13EhMTo4iICDkcDo0fP15Tp05VbGysYmJiNG3aNPXs2dP3KSDg56604txvJhfTD5CYV2iZmhxUPv74Yw0aNMi3PmXKFEnSuHHj5PF49Oabb0qSrrnmGr/9NmzYoNTUVEnSiy++qLCwMI0aNUonTpzQ4MGDtXjxYrVt2/YiXwbQunSOjgxoP0BiXqFlanJQSU1NlWWd+/7l+badERkZqXnz5mnevHlNPT3ws3B9UoziHZHylp1s8HkCmySX4/RHSoHGYl6hJeK7fgADtW1j01PDe0g6/ebxY2fWnxreg597gSZhXqElIqgAhro1JV4L7u8tl8P/MrzLEakF9/fm513gojCv0NIE/SfTArh4t6bEa2gPFz9BFAHFvEJLQlABDNe2jU03/iL2wh2BJmBeoaXg1g8AADAWQQUAABiLoAIAAIxFUAEAAMYiqAAAAGMRVAAAgLEIKgAAwFgEFQAAYCyCCgAAMBZBBQAAGIugAgAAjEVQAQAAxiKoAAAAYxFUAACAsQgqAADAWAQVAABgLIIKAAAwFkEFAAAYi6ACAACMRVABAADGIqgAAABjEVQAAICxCCoAAMBYBBUAAGAsggoAADAWQQUAABiLoAIAAIzV5KCyefNmDR8+XG63WzabTatXrz5n3wkTJshmsykvL8+vvaqqSpMnT1ZcXJzat2+vESNG6NChQ00tBQAAtHJNDirHjh1Tr169lJ+ff95+q1ev1ocffii3211vW2ZmplatWqUVK1Zoy5YtqqysVEZGhmpra5taDgAAaMXCmrpDenq60tPTz9vn22+/1aRJk7R27VrdfvvtftvKysr06quvaunSpRoyZIgkadmyZUpISND69es1bNiwppYEAABaqYA/o1JXV6exY8dq+vTpuuqqq+pt3759u2pqapSWluZrc7vdSklJUWFhYYPHrKqqUnl5ud8CAABav4AHleeff15hYWH63e9+1+B2r9eriIgIderUya/d6XTK6/U2uE9OTo4cDodvSUhICHTZAADAQAENKtu3b9ef/vQnLV68WDabrUn7WpZ1zn2ysrJUVlbmW4qLiwNRLgAAMFxAg8p7772n0tJSJSYmKiwsTGFhYTpw4ICmTp2qrl27SpJcLpeqq6t19OhRv31L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", 564 | "text/plain": [ 565 | "
" 566 | ] 567 | }, 568 | "metadata": {}, 569 | "output_type": "display_data" 570 | } 571 | ], 572 | "source": [ 573 | "#define Matplotlib figure and axis\n", 574 | "fig, ax = plt.subplots()\n", 575 | "\n", 576 | "#create simple line plot\n", 577 | "ax.scatter(df00[\"centre_x\"].to_numpy(), df00[\"centre_y\"].to_numpy())\n", 578 | "\n", 579 | "#add rectangle to plot\n", 580 | "for index, row in df00.iterrows():\n", 581 | " c_x = row[\"corner_x\"]\n", 582 | " c_y = row[\"corner_y\"]\n", 583 | " \n", 584 | " ax.add_patch(Rectangle((c_x, c_y), row[\"size_x\"], row[\"size_y\"],\n", 585 | " edgecolor = 'red',\n", 586 | " fill=False))\n", 587 | "\n", 588 | "ax.add_patch(Rectangle((0, 0), total_x, total_y,\n", 589 | " edgecolor = 'blue',\n", 590 | " fill=False))\n", 591 | "\n", 592 | "# axis as in image\n", 593 | "ax.set_ylim(ax.get_ylim()[::-1]) \n", 594 | "ax.xaxis.tick_top() \n", 595 | "ax.yaxis.tick_left() \n", 596 | "\n", 597 | "#display plot\n", 598 | "plt.title(\"Tile distribution\")\n", 599 | "plt.show()" 600 | ] 601 | }, 602 | { 603 | "attachments": {}, 604 | "cell_type": "markdown", 605 | "metadata": {}, 606 | "source": [ 607 | "## ZARR array" 608 | ] 609 | }, 610 | { 611 | "cell_type": "code", 612 | "execution_count": 12, 613 | "metadata": {}, 614 | "outputs": [], 615 | "source": [ 616 | "import zarr" 617 | ] 618 | }, 619 | { 620 | "cell_type": "code", 621 | "execution_count": 13, 622 | "metadata": {}, 623 | "outputs": [ 624 | { 625 | "name": "stdout", 626 | "output_type": "stream", 627 | "text": [ 628 | "Chunk size: 81,81\n" 629 | ] 630 | }, 631 | { 632 | "data": { 633 | "text/plain": [ 634 | "" 635 | ] 636 | }, 637 | "execution_count": 13, 638 | "metadata": {}, 639 | "output_type": "execute_result" 640 | } 641 | ], 642 | "source": [ 643 | "store = zarr.DirectoryStore('./data/basic-array.zarr')\n", 644 | "chunk_size = np.max(tile_shape)\n", 645 | "print(f'Chunk size: {chunk_size},{chunk_size}')\n", 646 | "z = zarr.creation.open_array(store=store, mode='a', shape=(total_y, total_x), chunks=(chunk_size,chunk_size), dtype=tile_type)\n", 647 | "z" 648 | ] 649 | }, 650 | { 651 | "attachments": {}, 652 | "cell_type": "markdown", 653 | "metadata": {}, 654 | "source": [ 655 | "## Dynamically fill in values" 656 | ] 657 | }, 658 | { 659 | "cell_type": "code", 660 | "execution_count": 14, 661 | "metadata": {}, 662 | "outputs": [ 663 | { 664 | "name": "stderr", 665 | "output_type": "stream", 666 | "text": [ 667 | "TiffPage 0: TypeError: read_bytes() missing 3 required positional arguments: 'dtype', 'count', and 'offsetsize'\n", 668 | "TiffPage 0: TypeError: read_bytes() missing 3 required positional arguments: 'dtype', 'count', and 'offsetsize'\n", 669 | "TiffPage 0: TypeError: read_bytes() missing 3 required positional arguments: 'dtype', 'count', and 'offsetsize'\n", 670 | "TiffPage 0: TypeError: read_bytes() missing 3 required positional arguments: 'dtype', 'count', and 'offsetsize'\n", 671 | "TiffPage 0: TypeError: read_bytes() missing 3 required positional arguments: 'dtype', 'count', and 'offsetsize'\n" 672 | ] 673 | }, 674 | { 675 | "name": "stdout", 676 | "output_type": "stream", 677 | "text": [ 678 | "0\n", 679 | "Tile 1 centre: 41, 41 goes to: x:[0:81], y:[0:81]\n", 680 | "1\n", 681 | "Tile 2 centre: 122, 41 goes to: x:[81:162], y:[0:81]\n", 682 | "2\n", 683 | "Tile 3 centre: 203, 41 goes to: x:[162:243], y:[0:81]\n", 684 | "3\n", 685 | "Tile 4 centre: 90, 122 goes to: x:[49:130], y:[81:162]\n", 686 | "4\n", 687 | "Tile 5 centre: 171, 122 goes to: x:[130:211], y:[81:162]\n" 688 | ] 689 | } 690 | ], 691 | "source": [ 692 | "for tile_idx, row in df00.iterrows():\n", 693 | " print(tile_idx)\n", 694 | " tile = skio.imread(f\"./data/t0{tile_idx+1}.tif\", plugin=\"tifffile\")\n", 695 | " x1 = row[\"corner_x\"]\n", 696 | " x2 = x1+row[\"size_x\"]\n", 697 | " y1 = row[\"corner_y\"]\n", 698 | " y2 = y1+row[\"size_y\"]\n", 699 | " \n", 700 | " print(f\"Tile {tile_idx+1} centre: {row['centre_x']}, {row['centre_y']} goes to: x:[{x1}:{x2}], y:[{y1}:{y2}]\")\n", 701 | " z[y1:y2,x1:x2] = tile\n", 702 | " \n", 703 | " " 704 | ] 705 | }, 706 | { 707 | "attachments": {}, 708 | "cell_type": "markdown", 709 | "metadata": {}, 710 | "source": [ 711 | "## To open in napari\n", 712 | "\n", 713 | "This iamge can be now opened in Napari by drag a drop and using ```napari builtins```\n", 714 | "\n", 715 | "## Changing now to ome-zarr\n", 716 | "\n", 717 | "However, I want to add ome-zarr support. For that I need some minimal metadata, and optionally some resolution levels\n", 718 | "\n", 719 | "For downsampling I will use ```dask-array``` as suggested in [this discussion](https://forum.image.sc/t/creating-an-ome-zarr-dynamically-from-tiles-stored-as-a-series-of-images-list-of-centre-positions-using-python/81657/12?u=camachodejay) " 720 | ] 721 | }, 722 | { 723 | "cell_type": "code", 724 | "execution_count": 15, 725 | "metadata": {}, 726 | "outputs": [], 727 | "source": [ 728 | "import dask.array as da" 729 | ] 730 | }, 731 | { 732 | "cell_type": "code", 733 | "execution_count": 16, 734 | "metadata": {}, 735 | "outputs": [], 736 | "source": [ 737 | "# like numpy.mean, but maintains dtype, helper function\n", 738 | "def mean_dtype(arr, **kwargs):\n", 739 | " return np.mean(arr, **kwargs).astype(arr.dtype)" 740 | ] 741 | }, 742 | { 743 | "cell_type": "code", 744 | "execution_count": 17, 745 | "metadata": {}, 746 | "outputs": [ 747 | { 748 | "data": { 749 | "text/html": [ 750 | "\n", 751 | " \n", 752 | " \n", 785 | " \n", 809 | " \n", 810 | "
\n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | "
Array Chunk
Bytes 38.60 kiB 6.25 kiB
Shape (162, 244) (80, 80)
Dask graph 12 chunks in 3 graph layers
Data type uint8 numpy.ndarray
\n", 784 | "
\n", 786 | " \n", 787 | "\n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | "\n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | "\n", 801 | " \n", 802 | " \n", 803 | "\n", 804 | " \n", 805 | " 244\n", 806 | " 162\n", 807 | "\n", 808 | "
" 811 | ], 812 | "text/plain": [ 813 | "dask.array" 814 | ] 815 | }, 816 | "execution_count": 17, 817 | "metadata": {}, 818 | "output_type": "execute_result" 819 | } 820 | ], 821 | "source": [ 822 | "# it is still not quite clear to me why, but we need to rechunk de data at this stage\n", 823 | "# if not zarr writting later on will fail\n", 824 | "d0 = da.from_zarr(store).rechunk(80,80)\n", 825 | "d0" 826 | ] 827 | }, 828 | { 829 | "cell_type": "code", 830 | "execution_count": 18, 831 | "metadata": {}, 832 | "outputs": [ 833 | { 834 | "data": { 835 | "text/html": [ 836 | "\n", 837 | " \n", 838 | " \n", 871 | " \n", 895 | " \n", 896 | "
\n", 839 | " \n", 840 | " \n", 841 | " \n", 842 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 846 | " \n", 847 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 851 | " \n", 852 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 856 | " \n", 857 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 862 | " \n", 863 | " \n", 864 | " \n", 865 | " \n", 866 | " \n", 867 | " \n", 868 | " \n", 869 | "
Array Chunk
Bytes 9.65 kiB 1.56 kiB
Shape (81, 122) (40, 40)
Dask graph 12 chunks in 4 graph layers
Data type uint8 numpy.ndarray
\n", 870 | "
\n", 872 | " \n", 873 | "\n", 874 | " \n", 875 | " \n", 876 | " \n", 877 | " \n", 878 | " \n", 879 | "\n", 880 | " \n", 881 | " \n", 882 | " \n", 883 | " \n", 884 | " \n", 885 | " \n", 886 | "\n", 887 | " \n", 888 | " \n", 889 | "\n", 890 | " \n", 891 | " 122\n", 892 | " 81\n", 893 | "\n", 894 | "
" 897 | ], 898 | "text/plain": [ 899 | "dask.array" 900 | ] 901 | }, 902 | "execution_count": 18, 903 | "metadata": {}, 904 | "output_type": "execute_result" 905 | } 906 | ], 907 | "source": [ 908 | "d1 = da.coarsen(mean_dtype, d0, {0:2,1:2}).rechunk(40,40)\n", 909 | "d1" 910 | ] 911 | }, 912 | { 913 | "cell_type": "code", 914 | "execution_count": 19, 915 | "metadata": {}, 916 | "outputs": [], 917 | "source": [ 918 | "from ome_zarr.io import parse_url\n", 919 | "from ome_zarr.writer import write_multiscale\n", 920 | "from ome_zarr.writer import write_multiscales_metadata" 921 | ] 922 | }, 923 | { 924 | "cell_type": "code", 925 | "execution_count": 20, 926 | "metadata": {}, 927 | "outputs": [], 928 | "source": [ 929 | "# I can probably build this programmatically, for the moment I take a shortcut. \n", 930 | "# This assumes an image with full resolution and one downscale by 2x2\n", 931 | "coordtfs = [\n", 932 | " [{'type': 'scale', 'scale': [1,1]},\n", 933 | " {'type': 'translation', 'translation': [0, 0]}],\n", 934 | " [{'type': 'scale', 'scale': [2,2]},\n", 935 | " {'type': 'translation', 'translation': [0, 0]}],\n", 936 | " ]\n", 937 | "axes = [{'name': 'y', 'type': 'space', 'unit': 'micrometer'},\n", 938 | " {'name': 'x', 'type': 'space', 'unit': 'micrometer'}]" 939 | ] 940 | }, 941 | { 942 | "cell_type": "code", 943 | "execution_count": 21, 944 | "metadata": {}, 945 | "outputs": [ 946 | { 947 | "data": { 948 | "text/plain": [ 949 | "[]" 950 | ] 951 | }, 952 | "execution_count": 21, 953 | "metadata": {}, 954 | "output_type": "execute_result" 955 | } 956 | ], 957 | "source": [ 958 | "# Open the zarr group manually\n", 959 | "path = './data/ome-example.zarr'\n", 960 | "store = parse_url(path, mode='w').store\n", 961 | "root = zarr.group(store=store)\n", 962 | "\n", 963 | "# Use OME write multiscale; this actually computes the dask arrays but does so\n", 964 | "# in a memory-efficient way. ❤️ 🚀\n", 965 | "write_multiscale([d0, d1],\n", 966 | " group=root, axes=axes, coordinate_transformations=coordtfs\n", 967 | " )" 968 | ] 969 | }, 970 | { 971 | "cell_type": "code", 972 | "execution_count": 22, 973 | "metadata": {}, 974 | "outputs": [], 975 | "source": [ 976 | "# add omero metadata: the napari ome-zarr plugin uses this to pass rendering\n", 977 | "# options to napari.\n", 978 | "root.attrs['omero'] = {\n", 979 | " 'channels': [{\n", 980 | " 'color': 'ffffff',\n", 981 | " 'label': 'blobs',\n", 982 | " 'active': True,\n", 983 | " }]\n", 984 | " }\n" 985 | ] 986 | }, 987 | { 988 | "attachments": {}, 989 | "cell_type": "markdown", 990 | "metadata": {}, 991 | "source": [ 992 | "## Open in napari using ome-zarr\n", 993 | "\n", 994 | "Now the date is good for opening in napari using the ```napari-ome-zarr``` plugin: https://github.com/ome/napari-ome-zarr\n" 995 | ] 996 | } 997 | ], 998 | "metadata": { 999 | "kernelspec": { 1000 | "display_name": "zarr-env", 1001 | "language": "python", 1002 | "name": "python3" 1003 | }, 1004 | "language_info": { 1005 | "codemirror_mode": { 1006 | "name": "ipython", 1007 | "version": 3 1008 | }, 1009 | "file_extension": ".py", 1010 | "mimetype": "text/x-python", 1011 | "name": "python", 1012 | "nbconvert_exporter": "python", 1013 | "pygments_lexer": "ipython3", 1014 | "version": "3.9.16" 1015 | }, 1016 | "orig_nbformat": 4 1017 | }, 1018 | "nbformat": 4, 1019 | "nbformat_minor": 2 1020 | } 1021 | --------------------------------------------------------------------------------