From c5785e49820e62eee473f9909729e6c93b8b2801 Mon Sep 17 00:00:00 2001 From: csowers Date: Mon, 17 Jul 2023 10:23:36 -0700 Subject: [PATCH 1/8] check resolutions helper function --- src/toffy/json_utils.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/toffy/json_utils.py b/src/toffy/json_utils.py index 18a2be5b..2dc051e0 100644 --- a/src/toffy/json_utils.py +++ b/src/toffy/json_utils.py @@ -3,6 +3,7 @@ import os import warnings +import pandas as pd from alpineer import io_utils @@ -194,3 +195,22 @@ def check_for_empty_files(bin_file_dir): # return the list of fov names return empty_json_files + + +def check_fov_resolutions(bin_file_dir, run_name, save_path=""): + run_file_path = os.path.join(bin_file_dir, run_name + ".json") + run_metadata = read_json_file(run_file_path, encoding="utf-8") + + fov_names, resolutions = [], [] + for fov in run_metadata.get("fovs", ()): + fov_number = fov.get("runOrder") + fov_names.append(f"fov-{fov_number}-scan-1") + + # retrieve pixel and micron specs + fov_pixel_length = fov.get("frameSizePixels")["width"] + fov_micron_length = fov.get("fovSizeMicrons") + + resolutions.append(fov_micron_length / fov_pixel_length) + + resolution_data = pd.DataFrame({"fov": fov_names, "resolution": resolutions}) + resolution_data.to_csv(save_path, index=False) From 0062c70e148f035bc12d21284c2de4b5f33be856 Mon Sep 17 00:00:00 2001 From: csowers Date: Mon, 17 Jul 2023 11:41:08 -0700 Subject: [PATCH 2/8] tests --- src/toffy/json_utils.py | 17 +++++++++++++++-- tests/json_utils_test.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/toffy/json_utils.py b/src/toffy/json_utils.py index 2dc051e0..3fc0fafe 100644 --- a/src/toffy/json_utils.py +++ b/src/toffy/json_utils.py @@ -197,12 +197,23 @@ def check_for_empty_files(bin_file_dir): return empty_json_files -def check_fov_resolutions(bin_file_dir, run_name, save_path=""): +def check_fov_resolutions(bin_file_dir, run_name): + """Use the run metadata to calculate the resolution of each fov + Args: + bin_file_dir (str): directory containing the run json file + run_name (str): name of the run and corresponding run file + + Returns: + pd.DataFrame: details fov names and corresponding resolution value + """ + # read in run metadata run_file_path = os.path.join(bin_file_dir, run_name + ".json") + io_utils.validate_paths([run_file_path]) run_metadata = read_json_file(run_file_path, encoding="utf-8") fov_names, resolutions = [], [] for fov in run_metadata.get("fovs", ()): + # get fov names fov_number = fov.get("runOrder") fov_names.append(f"fov-{fov_number}-scan-1") @@ -210,7 +221,9 @@ def check_fov_resolutions(bin_file_dir, run_name, save_path=""): fov_pixel_length = fov.get("frameSizePixels")["width"] fov_micron_length = fov.get("fovSizeMicrons") + # calculate and save fov resolution resolutions.append(fov_micron_length / fov_pixel_length) resolution_data = pd.DataFrame({"fov": fov_names, "resolution": resolutions}) - resolution_data.to_csv(save_path, index=False) + + return resolution_data diff --git a/tests/json_utils_test.py b/tests/json_utils_test.py index c169c824..de8db5b9 100644 --- a/tests/json_utils_test.py +++ b/tests/json_utils_test.py @@ -184,3 +184,41 @@ def test_check_for_empty_files(): empty_files = json_utils.check_for_empty_files(temp_dir) assert empty_files == ["empty_file"] + + +def test_check_fov_resolutions(): + with tempfile.TemporaryDirectory() as temp_dir: + run_data = { + "fovs": [ + { + "runOrder": 1, + "scanCount": 1, + "frameSizePixels": {"width": 32, "height": 32}, + "fovSizeMicrons": 100, + }, + { + "runOrder": 2, + "scanCount": 1, + "frameSizePixels": {"width": 32, "height": 32}, + "fovSizeMicrons": 100, + }, + { + "runOrder": 3, + "scanCount": 1, + "frameSizePixels": {"width": 16, "height": 16}, + "fovSizeMicrons": 100, + }, + ], + } + + json_utils.write_json_file(os.path.join(temp_dir, "test_run.json"), run_data) + + # test successful resolution check + resolution_data = json_utils.check_fov_resolutions(temp_dir, "test_run") + + assert len(resolution_data) == 3 + assert ( + np.array(["fov-1-scan-1", "fov-2-scan-1", "fov-3-scan-1"]) == resolution_data["fov"] + ).all() + assert resolution_data["resolution"].iloc[0] == resolution_data["resolution"].iloc[1] + assert resolution_data["resolution"].iloc[0] != resolution_data["resolution"].iloc[2] From 7313a67df771450e77e263ae54dba3fa481cf67c Mon Sep 17 00:00:00 2001 From: csowers Date: Mon, 17 Jul 2023 13:35:43 -0700 Subject: [PATCH 3/8] notebook --- templates/check_resolutions.ipynb | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 templates/check_resolutions.ipynb diff --git a/templates/check_resolutions.ipynb b/templates/check_resolutions.ipynb new file mode 100644 index 00000000..03b61ac7 --- /dev/null +++ b/templates/check_resolutions.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4857c47b-f476-4494-9a0d-742ef35c0a85", + "metadata": {}, + "source": [ + "# Check FOV Resolutions\n", + "This notebook will use the run file to check the image resolution for each FOV in the run. Consistent resolution level is important for downstream processing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "353ffbc5-4784-49e1-9fd5-f1344d7892da", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from toffy.json_utils import check_fov_resolutions" + ] + }, + { + "cell_type": "markdown", + "id": "cd7ff391-2d75-4098-bd9d-4d98e07d45ba", + "metadata": {}, + "source": [ + "## Required variables\n", + "You will need to define the following argument for this notebook.\n", + " - `run_name` should contain the exact name of the MIBI run to extract from" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b81ca96-e7dc-4603-87ce-284edeb2d423", + "metadata": {}, + "outputs": [], + "source": [ + "# set up args for current run\n", + "run_name = 'YYYY-MM-DD_run_name'\n", + "\n", + "bin_file_dir = os.path.join('D:\\\\Data', run_name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b30a4058-4976-4bdc-9714-f9babe056d85", + "metadata": {}, + "outputs": [], + "source": [ + "# check resolutions \n", + "check_fov_resolutions(bin_file_dir, run_name)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "toffy_env", + "language": "python", + "name": "toffy_env" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From f1ede5051009a365888800cc126bb87698aa20fd Mon Sep 17 00:00:00 2001 From: csowers Date: Mon, 17 Jul 2023 13:54:39 -0700 Subject: [PATCH 4/8] print fov resolution in loop --- src/toffy/json_utils.py | 9 +++++++-- templates/check_resolutions.ipynb | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/toffy/json_utils.py b/src/toffy/json_utils.py index 3fc0fafe..b10a05ce 100644 --- a/src/toffy/json_utils.py +++ b/src/toffy/json_utils.py @@ -215,14 +215,19 @@ def check_fov_resolutions(bin_file_dir, run_name): for fov in run_metadata.get("fovs", ()): # get fov names fov_number = fov.get("runOrder") - fov_names.append(f"fov-{fov_number}-scan-1") + name = f"fov-{fov_number}-scan-1" + fov_names.append(name) # retrieve pixel and micron specs fov_pixel_length = fov.get("frameSizePixels")["width"] fov_micron_length = fov.get("fovSizeMicrons") # calculate and save fov resolution - resolutions.append(fov_micron_length / fov_pixel_length) + fov_resolution = fov_micron_length / fov_pixel_length + resolutions.append(fov_resolution) + + # output values + print(f"{name}: {fov_resolution}") resolution_data = pd.DataFrame({"fov": fov_names, "resolution": resolutions}) diff --git a/templates/check_resolutions.ipynb b/templates/check_resolutions.ipynb index 03b61ac7..3ef537a4 100644 --- a/templates/check_resolutions.ipynb +++ b/templates/check_resolutions.ipynb @@ -51,7 +51,7 @@ "outputs": [], "source": [ "# check resolutions \n", - "check_fov_resolutions(bin_file_dir, run_name)" + "resolution_data = check_fov_resolutions(bin_file_dir, run_name)" ] } ], From 75d65164ec67ae5d993ce276ecc047a9103a7e20 Mon Sep 17 00:00:00 2001 From: csowers Date: Tue, 18 Jul 2023 15:31:40 -0700 Subject: [PATCH 5/8] pixels per 400 microns --- src/toffy/json_utils.py | 16 ++++++++++------ templates/check_resolutions.ipynb | 2 +- tests/json_utils_test.py | 16 +++++++++++++--- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/toffy/json_utils.py b/src/toffy/json_utils.py index b10a05ce..176c1178 100644 --- a/src/toffy/json_utils.py +++ b/src/toffy/json_utils.py @@ -197,11 +197,12 @@ def check_for_empty_files(bin_file_dir): return empty_json_files -def check_fov_resolutions(bin_file_dir, run_name): +def check_fov_resolutions(bin_file_dir, run_name, save_path=None): """Use the run metadata to calculate the resolution of each fov Args: bin_file_dir (str): directory containing the run json file run_name (str): name of the run and corresponding run file + save_path (str): path to save data to, default None doesn't write data out Returns: pd.DataFrame: details fov names and corresponding resolution value @@ -222,13 +223,16 @@ def check_fov_resolutions(bin_file_dir, run_name): fov_pixel_length = fov.get("frameSizePixels")["width"] fov_micron_length = fov.get("fovSizeMicrons") - # calculate and save fov resolution - fov_resolution = fov_micron_length / fov_pixel_length - resolutions.append(fov_resolution) + # calculate and save fov resolution per 400 microns + mult = 400 / fov_micron_length + pixels_adj = int(mult * fov_pixel_length) # output values - print(f"{name}: {fov_resolution}") + print(f"{name}: {pixels_adj} x {400}") + resolutions.append(pixels_adj) - resolution_data = pd.DataFrame({"fov": fov_names, "resolution": resolutions}) + resolution_data = pd.DataFrame({"fov": fov_names, "pixels / 400 microns": resolutions}) + if save_path: + resolution_data.to_csv(save_path, index=False) return resolution_data diff --git a/templates/check_resolutions.ipynb b/templates/check_resolutions.ipynb index 3ef537a4..a1e65105 100644 --- a/templates/check_resolutions.ipynb +++ b/templates/check_resolutions.ipynb @@ -51,7 +51,7 @@ "outputs": [], "source": [ "# check resolutions \n", - "resolution_data = check_fov_resolutions(bin_file_dir, run_name)" + "resolution_data = check_fov_resolutions(bin_file_dir, run_name, save_path=None)" ] } ], diff --git a/tests/json_utils_test.py b/tests/json_utils_test.py index de8db5b9..95893548 100644 --- a/tests/json_utils_test.py +++ b/tests/json_utils_test.py @@ -214,11 +214,21 @@ def test_check_fov_resolutions(): json_utils.write_json_file(os.path.join(temp_dir, "test_run.json"), run_data) # test successful resolution check - resolution_data = json_utils.check_fov_resolutions(temp_dir, "test_run") + resolution_data = json_utils.check_fov_resolutions( + temp_dir, "test_run", save_path=os.path.join(temp_dir, "resolution_data.csv") + ) assert len(resolution_data) == 3 assert ( np.array(["fov-1-scan-1", "fov-2-scan-1", "fov-3-scan-1"]) == resolution_data["fov"] ).all() - assert resolution_data["resolution"].iloc[0] == resolution_data["resolution"].iloc[1] - assert resolution_data["resolution"].iloc[0] != resolution_data["resolution"].iloc[2] + assert ( + resolution_data["pixels / 400 microns"].iloc[0] + == resolution_data["pixels / 400 microns"].iloc[1] + ) + assert ( + resolution_data["pixels / 400 microns"].iloc[0] + != resolution_data["pixels / 400 microns"].iloc[2] + ) + + assert os.path.exists(os.path.join(temp_dir, "resolution_data.csv")) From 09539a51484ea50f7d544f88bc6f603744e36fe7 Mon Sep 17 00:00:00 2001 From: csowers Date: Tue, 18 Jul 2023 15:33:43 -0700 Subject: [PATCH 6/8] number notebook --- templates/{check_resolutions.ipynb => 3f_check_resolutions.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename templates/{check_resolutions.ipynb => 3f_check_resolutions.ipynb} (100%) diff --git a/templates/check_resolutions.ipynb b/templates/3f_check_resolutions.ipynb similarity index 100% rename from templates/check_resolutions.ipynb rename to templates/3f_check_resolutions.ipynb From 0fed494ac6a324fe2b1d1593954660b9a2d6a350 Mon Sep 17 00:00:00 2001 From: csowers Date: Tue, 18 Jul 2023 15:36:54 -0700 Subject: [PATCH 7/8] units!! --- src/toffy/json_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toffy/json_utils.py b/src/toffy/json_utils.py index 176c1178..f7b2fdad 100644 --- a/src/toffy/json_utils.py +++ b/src/toffy/json_utils.py @@ -228,7 +228,7 @@ def check_fov_resolutions(bin_file_dir, run_name, save_path=None): pixels_adj = int(mult * fov_pixel_length) # output values - print(f"{name}: {pixels_adj} x {400}") + print(f"{name}: {pixels_adj} pixels x {400} microns") resolutions.append(pixels_adj) resolution_data = pd.DataFrame({"fov": fov_names, "pixels / 400 microns": resolutions}) From 5e03c9f07098adc72182ea35ba851b746401c5b2 Mon Sep 17 00:00:00 2001 From: csowers Date: Wed, 19 Jul 2023 09:54:16 -0700 Subject: [PATCH 8/8] add user defined fov name --- src/toffy/json_utils.py | 14 +++++++++----- tests/json_utils_test.py | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/toffy/json_utils.py b/src/toffy/json_utils.py index f7b2fdad..f0bbd562 100644 --- a/src/toffy/json_utils.py +++ b/src/toffy/json_utils.py @@ -212,12 +212,14 @@ def check_fov_resolutions(bin_file_dir, run_name, save_path=None): io_utils.validate_paths([run_file_path]) run_metadata = read_json_file(run_file_path, encoding="utf-8") - fov_names, resolutions = [], [] + fov_names, custom_names, resolutions = [], [], [] for fov in run_metadata.get("fovs", ()): # get fov names fov_number = fov.get("runOrder") - name = f"fov-{fov_number}-scan-1" - fov_names.append(name) + default_name = f"fov-{fov_number}-scan-1" + custom_name = fov.get("name") + fov_names.append(default_name) + custom_names.append(custom_name) # retrieve pixel and micron specs fov_pixel_length = fov.get("frameSizePixels")["width"] @@ -228,10 +230,12 @@ def check_fov_resolutions(bin_file_dir, run_name, save_path=None): pixels_adj = int(mult * fov_pixel_length) # output values - print(f"{name}: {pixels_adj} pixels x {400} microns") + print(f"{default_name} ({custom_name}): {pixels_adj} pixels x {400} microns") resolutions.append(pixels_adj) - resolution_data = pd.DataFrame({"fov": fov_names, "pixels / 400 microns": resolutions}) + resolution_data = pd.DataFrame( + {"fov": fov_names, "name": custom_names, "pixels / 400 microns": resolutions} + ) if save_path: resolution_data.to_csv(save_path, index=False) diff --git a/tests/json_utils_test.py b/tests/json_utils_test.py index 95893548..444bc092 100644 --- a/tests/json_utils_test.py +++ b/tests/json_utils_test.py @@ -218,7 +218,7 @@ def test_check_fov_resolutions(): temp_dir, "test_run", save_path=os.path.join(temp_dir, "resolution_data.csv") ) - assert len(resolution_data) == 3 + assert resolution_data.shape == (3, 3) assert ( np.array(["fov-1-scan-1", "fov-2-scan-1", "fov-3-scan-1"]) == resolution_data["fov"] ).all()