From 7316d9204f5aae270253487701438f6ce16cb4cd Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 29 Dec 2023 16:06:00 +0100 Subject: [PATCH 01/13] Added new command line parameters --- graxpert/CommandLineTool.py | 2 +- graxpert/main.py | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/graxpert/CommandLineTool.py b/graxpert/CommandLineTool.py index dfc6001..2fb9bdd 100644 --- a/graxpert/CommandLineTool.py +++ b/graxpert/CommandLineTool.py @@ -18,7 +18,7 @@ def __init__(self, args): def execute(self): astro_Image = AstroImage(do_update_display=False) - astro_Image.set_from_file(self.args.filename) + astro_Image.set_from_file(self.args.filename, None, None) processed_Astro_Image = AstroImage(do_update_display=False) background_Astro_Image = AstroImage(do_update_display=False) diff --git a/graxpert/main.py b/graxpert/main.py index 0bd754b..f49ce8b 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -14,6 +14,7 @@ from packaging import version +from graxpert.version import release as graxpert_release, version as graxpert_version from graxpert.ai_model_handling import list_local_versions, list_remote_versions from graxpert.mp_logging import configure_logging @@ -176,14 +177,22 @@ def main(): ) parser.add_argument("-correction", "--correction", nargs="?", required=False, default="Subtraction", choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=0.0, type=float, help="Strength of smoothing between 0 and 1") + parser.add_argument("-output", "--output", nargs="?", required=False, type=str, help="Filename of the processed image") + parser.add_argument("-bg", "--bg", required=False, action="store_true", help="Also save the background model") + parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") + parser.add_argument('-v', '--version', action='version', version="GraXpert version: " + graxpert_version + " release: " + graxpert_release) + args = parser.parse_args() - - from graxpert.CommandLineTool import CommandLineTool - - clt = CommandLineTool(args) - clt.execute() - logging.shutdown() + + if (args.cli): + from graxpert.CommandLineTool import CommandLineTool + clt = CommandLineTool(args) + clt.execute() + logging.shutdown() + else: + ui_main() + else: ui_main() From b05b99e3711c6dbe65601cbb6bf718c8d5890476 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 29 Dec 2023 16:30:15 +0100 Subject: [PATCH 02/13] Moved check for newer version to end of initialization to avoid issues with the initial main window size on macOS --- graxpert/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graxpert/main.py b/graxpert/main.py index f49ce8b..710f668 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -132,7 +132,6 @@ def check_for_new_version(): logging.warning("Could not check for newest version") logging_thread = initialize_logging() - check_for_new_version() style() root = CTk() @@ -153,6 +152,7 @@ def check_for_new_version(): app = ApplicationFrame(root) app.grid(column=0, row=0, sticky=tk.NSEW) root.update() + check_for_new_version() eventbus.emit(UiEvents.DISPLAY_START_BADGE_REQUEST) root.mainloop() From 1a3baa76c7e9da26c4872353ef3e955c0ea46afd Mon Sep 17 00:00:00 2001 From: Michael Ring Date: Fri, 29 Dec 2023 16:19:30 +0100 Subject: [PATCH 03/13] Allow developers to run GraXpert without s3_secrets.py --- graxpert/ai_model_handling.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/graxpert/ai_model_handling.py b/graxpert/ai_model_handling.py index 310c029..2bc7be7 100644 --- a/graxpert/ai_model_handling.py +++ b/graxpert/ai_model_handling.py @@ -10,17 +10,22 @@ from minio import Minio from packaging import version -from graxpert.s3_secrets import bucket_name, endpoint, ro_access_key, ro_secret_key +try: + from graxpert.s3_secrets import bucket_name, endpoint, ro_access_key, ro_secret_key + client = Minio(endpoint, ro_access_key, ro_secret_key) +except Exception as e: + logging.exception(e) + client = None + from graxpert.ui.loadingframe import DynamicProgressThread ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "ai-models") os.makedirs(ai_models_dir, exist_ok=True) -client = Minio(endpoint, ro_access_key, ro_secret_key) - - # ui operations def list_remote_versions(): + if client is None: + return [] try: objects = client.list_objects(bucket_name) versions = [] From 73e06a80a52dd92892699275fae1f924963e2a56 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 30 Dec 2023 11:02:11 +0100 Subject: [PATCH 04/13] Updated AstroImage tests to account for new method signatures --- tests/test_AstroImage.py | 42 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/tests/test_AstroImage.py b/tests/test_AstroImage.py index 1a0759d..331863f 100644 --- a/tests/test_AstroImage.py +++ b/tests/test_AstroImage.py @@ -40,9 +40,7 @@ def get(self): def test_set_from_array_mono(): - stretch = DummyStretchOption() - saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage(do_update_display=False) a.set_from_array(array_mono) assert_array_almost_equal(a.img_array, array_mono, decimal=5) @@ -50,9 +48,7 @@ def test_set_from_array_mono(): assert a.height == 5 def test_set_from_array_color(): - stretch = DummyStretchOption() - saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage(do_update_display=False) a.set_from_array(array_color) assert_array_almost_equal(a.img_array, array_color, decimal=5) @@ -63,22 +59,18 @@ def test_set_from_array_color(): @pytest.mark.parametrize("img", test_images_mono) def test_set_from_file_mono(img): - stretch = DummyStretchOption() - saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage(do_update_display=False) - a.set_from_file("./tests/test_images/" + img) + a.set_from_file("./tests/test_images/" + img, None, None) assert_array_almost_equal(a.img_array, array_mono, decimal=5) assert a.width == 6 assert a.height == 5 @pytest.mark.parametrize("img", test_images_color) def test_set_from_file_color(img): - stretch = DummyStretchOption() - saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage(do_update_display=False) - a.set_from_file("./tests/test_images/" + img) + a.set_from_file("./tests/test_images/" + img, None, None) assert_array_almost_equal(a.img_array, array_color, decimal=5) assert a.width == 6 assert a.height == 5 @@ -88,20 +80,20 @@ def test_set_from_file_color(img): def test_update_display_mono(): stretch = DummyStretchOption() saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage(do_update_display=False) a.set_from_array(array_mono) - a.update_display() + a.update_display(stretch, saturation) assert np.asarray(a.img_display).shape == (5,6) assert np.asarray(a.img_display_saturated).shape == (5,6) def test_update_display_color(): stretch = DummyStretchOption() saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage(do_update_display=False) a.set_from_array(array_color) - a.update_display() + a.update_display(stretch, saturation) assert np.asarray(a.img_display).shape == (5,6,3) assert np.asarray(a.img_display_saturated).shape == (5,6,3) @@ -110,9 +102,9 @@ def test_update_display_color(): def test_save_mono(tmp_path, file_type): stretch = DummyStretchOption() saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage() - a.set_from_file("./tests/test_images/mono_32bit.fits") + a.set_from_file("./tests/test_images/mono_32bit.fits", stretch, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) a.save(file_dir, file_type) @@ -141,9 +133,9 @@ def test_save_mono(tmp_path, file_type): def test_save_color(tmp_path, file_type): stretch = DummyStretchOption() saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage() - a.set_from_file("./tests/test_images/color_32bit.fits") + a.set_from_file("./tests/test_images/color_32bit.fits", stretch, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) a.save(file_dir, file_type) @@ -171,9 +163,9 @@ def test_save_color(tmp_path, file_type): def test_save_stretched_mono(tmp_path, file_type): stretch = DummyStretchOption() saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage() - a.set_from_file("./tests/test_images/mono_32bit.fits") + a.set_from_file("./tests/test_images/mono_32bit.fits", stretch, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) a.save_stretched(file_dir, file_type) @@ -204,7 +196,7 @@ def test_save_stretched_color(tmp_path, file_type): saturation = DummySaturationOption() a = AstroImage(stretch,saturation) - a.set_from_file("./tests/test_images/color_32bit.fits") + a.set_from_file("./tests/test_images/color_32bit.fits", stretch, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) a.save_stretched(file_dir, file_type) From 5db3e2636a4cb144b6dcb127a3a8c9a3275dff58 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 30 Dec 2023 11:13:58 +0100 Subject: [PATCH 05/13] Updated AstroImage tests to account for new method signatures --- tests/test_AstroImage.py | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/tests/test_AstroImage.py b/tests/test_AstroImage.py index 331863f..1d5a72b 100644 --- a/tests/test_AstroImage.py +++ b/tests/test_AstroImage.py @@ -28,15 +28,9 @@ file_types = ["16 bit Fits", "32 bit Fits", "16 bit Tiff", "32 bit Tiff", "16 bit XISF", "32 bit XISF"] - -class DummyStretchOption: - def get(self): - return "30% Bg, 2 sigma" +saturation = 2.0 +stretch = "30% Bg, 2 sigma" -class DummySaturationOption: - def get(self): - return 2.0 - def test_set_from_array_mono(): @@ -78,8 +72,6 @@ def test_set_from_file_color(img): def test_update_display_mono(): - stretch = DummyStretchOption() - saturation = DummySaturationOption() a = AstroImage(do_update_display=False) a.set_from_array(array_mono) @@ -88,8 +80,6 @@ def test_update_display_mono(): assert np.asarray(a.img_display_saturated).shape == (5,6) def test_update_display_color(): - stretch = DummyStretchOption() - saturation = DummySaturationOption() a = AstroImage(do_update_display=False) a.set_from_array(array_color) @@ -100,8 +90,6 @@ def test_update_display_color(): @pytest.mark.parametrize("file_type", file_types) def test_save_mono(tmp_path, file_type): - stretch = DummyStretchOption() - saturation = DummySaturationOption() a = AstroImage() a.set_from_file("./tests/test_images/mono_32bit.fits", stretch, saturation) @@ -131,8 +119,6 @@ def test_save_mono(tmp_path, file_type): @pytest.mark.parametrize("file_type", file_types) def test_save_color(tmp_path, file_type): - stretch = DummyStretchOption() - saturation = DummySaturationOption() a = AstroImage() a.set_from_file("./tests/test_images/color_32bit.fits", stretch, saturation) @@ -161,14 +147,12 @@ def test_save_color(tmp_path, file_type): @pytest.mark.parametrize("file_type", file_types) def test_save_stretched_mono(tmp_path, file_type): - stretch = DummyStretchOption() - saturation = DummySaturationOption() a = AstroImage() a.set_from_file("./tests/test_images/mono_32bit.fits", stretch, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) - a.save_stretched(file_dir, file_type) + a.save_stretched(file_dir, file_type, stretch) if file_ending == "fits": hdul = fits.open(file_dir) @@ -192,14 +176,12 @@ def test_save_stretched_mono(tmp_path, file_type): @pytest.mark.parametrize("file_type", file_types) def test_save_stretched_color(tmp_path, file_type): - stretch = DummyStretchOption() - saturation = DummySaturationOption() - a = AstroImage(stretch,saturation) + a = AstroImage() a.set_from_file("./tests/test_images/color_32bit.fits", stretch, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) - a.save_stretched(file_dir, file_type) + a.save_stretched(file_dir, file_type, stretch) if file_ending == "fits": hdul = fits.open(file_dir) From f9edb49dcf8a7761db531ba81be54174b6b0c058 Mon Sep 17 00:00:00 2001 From: Michael Ring Date: Sat, 30 Dec 2023 00:23:15 +0100 Subject: [PATCH 06/13] Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points --- graxpert/CommandLineTool.py | 49 ++++++++++++++++++++++++++++++------- graxpert/main.py | 1 + 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/graxpert/CommandLineTool.py b/graxpert/CommandLineTool.py index 2fb9bdd..ad92200 100644 --- a/graxpert/CommandLineTool.py +++ b/graxpert/CommandLineTool.py @@ -1,6 +1,8 @@ import logging import os import sys +from pathlib import Path +import numpy as np from appdirs import user_config_dir @@ -10,7 +12,7 @@ from graxpert.astroimage import AstroImage from graxpert.background_extraction import extract_background from graxpert.preferences import load_preferences, save_preferences - +import json class CommandLineTool: def __init__(self, args): @@ -26,19 +28,48 @@ def execute(self): processed_Astro_Image.fits_header = astro_Image.fits_header background_Astro_Image.fits_header = astro_Image.fits_header - ai_version = self.get_ai_version() + interpol_type_option="AI" + RBF_kernel = "RBF" + background_points=[] + sample_size=50 + downscale_factor = 1 + spline_order=0 + + if (self.args.preferencesfile): + try: + preferencesfile = Path(self.args.preferencesfile) + if preferencesfile.is_file() and preferencesfile.suffix == ".json": + prefs=json.load(preferencesfile.open("r")) + background_points=prefs["background_points"] + sample_size=prefs["sample_size"] + spline_order=prefs["spline_order"] + RBF_kernel=prefs["RBF_kernel"] + interpol_type_option=prefs["interpol_type_option"] + if interpol_type_option == "Kriging" or interpol_type_option == "RBF": + downscale_factor = 4 + + except Exception as e: + logging.exception(e) + logging.shutdown() + sys.exit(1) + + if interpol_type_option == "AI": + ai_model_path_from_version(self.get_ai_version()) + else: + ai_model_path=None + background_Astro_Image.set_from_array( extract_background( astro_Image.img_array, - [], - "AI", + np.array(background_points), + interpol_type_option, self.args.smoothing, - 1, - 50, - "RBF", - 0, + downscale_factor, + sample_size, + RBF_kernel, + spline_order, self.args.correction, - ai_model_path_from_version(ai_version), + ai_model_path ) ) diff --git a/graxpert/main.py b/graxpert/main.py index 710f668..b969640 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -177,6 +177,7 @@ def main(): ) parser.add_argument("-correction", "--correction", nargs="?", required=False, default="Subtraction", choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=0.0, type=float, help="Strength of smoothing between 0 and 1") + parser.add_argument("-preferencesfile", "--preferencesfile", nargs="?", required=False, default="", type=str, help="Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points") parser.add_argument("-output", "--output", nargs="?", required=False, type=str, help="Filename of the processed image") parser.add_argument("-bg", "--bg", required=False, action="store_true", help="Also save the background model") parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") From e9a69f3c61a2168f67a5c88ad5d2b865c9f4444b Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 30 Dec 2023 12:29:37 +0100 Subject: [PATCH 07/13] support overwriting of preferences by cli arguments, code cleanup --- graxpert/CommandLineTool.py | 129 ++++++++++++++++++------------------ graxpert/main.py | 23 +++++-- 2 files changed, 81 insertions(+), 71 deletions(-) diff --git a/graxpert/CommandLineTool.py b/graxpert/CommandLineTool.py index ad92200..a3fdc13 100644 --- a/graxpert/CommandLineTool.py +++ b/graxpert/CommandLineTool.py @@ -1,18 +1,18 @@ +import json import logging import os import sys -from pathlib import Path -import numpy as np +import numpy as np from appdirs import user_config_dir -from graxpert.ai_model_handling import (ai_model_path_from_version, - download_version, latest_version, - list_local_versions) +from graxpert.ai_model_handling import ai_model_path_from_version, download_version, latest_version, list_local_versions from graxpert.astroimage import AstroImage from graxpert.background_extraction import extract_background -from graxpert.preferences import load_preferences, save_preferences -import json +from graxpert.preferences import Prefs, load_preferences, save_preferences + +user_preferences_filename = os.path.join(user_config_dir(appname="GraXpert"), "preferences.json") + class CommandLineTool: def __init__(self, args): @@ -21,127 +21,128 @@ def __init__(self, args): def execute(self): astro_Image = AstroImage(do_update_display=False) astro_Image.set_from_file(self.args.filename, None, None) - + processed_Astro_Image = AstroImage(do_update_display=False) background_Astro_Image = AstroImage(do_update_display=False) - + processed_Astro_Image.fits_header = astro_Image.fits_header background_Astro_Image.fits_header = astro_Image.fits_header - - interpol_type_option="AI" - RBF_kernel = "RBF" - background_points=[] - sample_size=50 + downscale_factor = 1 - spline_order=0 - if (self.args.preferencesfile): + if self.args.preferences_file: + preferences = Prefs() + preferences.interpol_type_option = "AI" try: - preferencesfile = Path(self.args.preferencesfile) - if preferencesfile.is_file() and preferencesfile.suffix == ".json": - prefs=json.load(preferencesfile.open("r")) - background_points=prefs["background_points"] - sample_size=prefs["sample_size"] - spline_order=prefs["spline_order"] - RBF_kernel=prefs["RBF_kernel"] - interpol_type_option=prefs["interpol_type_option"] - if interpol_type_option == "Kriging" or interpol_type_option == "RBF": - downscale_factor = 4 + preferences_file = os.path.abspath(self.args.preferences_file) + if os.path.isfile(preferences_file): + with open(preferences_file, "r") as f: + json_prefs = json.load(f) + preferences.background_points = json_prefs["background_points"] + preferences.sample_size = json_prefs["sample_size"] + preferences.spline_order = json_prefs["spline_order"] + preferences.RBF_kernel = json_prefs["RBF_kernel"] + preferences.interpol_type_option = json_prefs["interpol_type_option"] + preferences.ai_version = json_prefs["ai_version"] + + if preferences.interpol_type_option == "Kriging" or preferences.interpol_type_option == "RBF": + downscale_factor = 4 except Exception as e: logging.exception(e) logging.shutdown() sys.exit(1) + else: + preferences = load_preferences(user_preferences_filename) + preferences.interpol_type_option = "AI" + + if self.args.smoothing: + preferences.smoothing_option = self.args.smoothing + logging.info(f"Using user-supplied smoothing value {preferences.smoothing_option}.") + + if self.args.correction: + preferences.corr_type = self.args.correction + logging.info(f"Using user-supplied correction type {preferences.corr_type}.") - if interpol_type_option == "AI": - ai_model_path_from_version(self.get_ai_version()) + if preferences.interpol_type_option == "AI": + ai_model_path = ai_model_path_from_version(self.get_ai_version(preferences)) else: - ai_model_path=None + ai_model_path = None background_Astro_Image.set_from_array( extract_background( astro_Image.img_array, - np.array(background_points), - interpol_type_option, - self.args.smoothing, + np.array(preferences.background_points), + preferences.interpol_type_option, + preferences.smoothing_option, downscale_factor, - sample_size, - RBF_kernel, - spline_order, - self.args.correction, - ai_model_path + preferences.sample_size, + preferences.RBF_kernel, + preferences.spline_order, + preferences.corr_type, + ai_model_path, ) ) processed_Astro_Image.set_from_array(astro_Image.img_array) processed_Astro_Image.save(self.get_save_path(), self.get_output_file_format()) - if (self.args.bg): + if self.args.bg: background_Astro_Image.save(self.get_background_save_path(), self.get_output_file_format()) - - def get_ai_version(self): - prefs_filename = os.path.join( - user_config_dir(appname="GraXpert"), "preferences.json" - ) - prefs = load_preferences(prefs_filename) + def get_ai_version(self, prefs): + user_preferences = load_preferences(user_preferences_filename) ai_version = None if self.args.ai_version: ai_version = self.args.ai_version + logging.info(f"Using user-supplied AI version {ai_version}.") else: ai_version = prefs.ai_version if ai_version is None: ai_version = latest_version() - - logging.info( - "using AI version {}. you can change this by providing the argument '-ai_version'".format( - ai_version - ) - ) + logging.info(f"Using AI version {ai_version}. You can overwrite this by providing the argument '-ai_version'") if not ai_version in [v["version"] for v in list_local_versions()]: try: - logging.info( - "AI version {} not found locally, downloading...".format(ai_version) - ) + logging.info(f"AI version {ai_version} not found locally, downloading...") download_version(ai_version) - logging.info("download successful".format(ai_version)) + logging.info("download successful") except Exception as e: logging.exception(e) logging.shutdown() sys.exit(1) - prefs.ai_version = ai_version - save_preferences(prefs_filename, prefs) - + user_preferences.ai_version = ai_version + save_preferences(user_preferences_filename, user_preferences) + return ai_version - + def get_output_file_ending(self): file_ending = os.path.splitext(self.args.filename)[-1] - + if file_ending.lower() == ".xisf": return ".xisf" else: return ".fits" - + def get_output_file_format(self): output_file_ending = self.get_output_file_ending() if (output_file_ending) == ".xisf": return "32 bit XISF" else: return "32 bit Fits" - + def get_save_path(self): - if (self.args.output is not None): + if self.args.output is not None: base_path = os.path.dirname(self.args.filename) output_file_name = self.args.output + self.get_output_file_ending() return os.path.join(base_path, output_file_name) - + else: return os.path.splitext(self.args.filename)[0] + "_GraXpert" + self.get_output_file_ending() - + def get_background_save_path(self): save_path = self.get_save_path() return os.path.splitext(save_path)[0] + "_background" + self.get_output_file_ending() diff --git a/graxpert/main.py b/graxpert/main.py index b969640..0456315 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -14,9 +14,10 @@ from packaging import version -from graxpert.version import release as graxpert_release, version as graxpert_version from graxpert.ai_model_handling import list_local_versions, list_remote_versions from graxpert.mp_logging import configure_logging +from graxpert.version import release as graxpert_release +from graxpert.version import version as graxpert_version available_local_versions = [] available_remote_versions = [] @@ -177,23 +178,31 @@ def main(): ) parser.add_argument("-correction", "--correction", nargs="?", required=False, default="Subtraction", choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=0.0, type=float, help="Strength of smoothing between 0 and 1") - parser.add_argument("-preferencesfile", "--preferencesfile", nargs="?", required=False, default="", type=str, help="Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points") + parser.add_argument( + "-preferences_file", + "--preferences_file", + nargs="?", + required=False, + default="", + type=str, + help="Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points", + ) parser.add_argument("-output", "--output", nargs="?", required=False, type=str, help="Filename of the processed image") parser.add_argument("-bg", "--bg", required=False, action="store_true", help="Also save the background model") parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") - parser.add_argument('-v', '--version', action='version', version="GraXpert version: " + graxpert_version + " release: " + graxpert_release) - + parser.add_argument("-v", "--version", action="version", version=f"GraXpert version: {graxpert_version} release: {graxpert_release}") args = parser.parse_args() - - if (args.cli): + + if args.cli: from graxpert.CommandLineTool import CommandLineTool + clt = CommandLineTool(args) clt.execute() logging.shutdown() else: ui_main() - + else: ui_main() From 2404922646373f72c888848814870bbb069780ba Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 30 Dec 2023 14:31:59 +0100 Subject: [PATCH 08/13] fix handling of cli default values, improve logging --- graxpert/CommandLineTool.py | 59 ++++++++++++++++++++++++++++++------- graxpert/main.py | 8 +++-- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/graxpert/CommandLineTool.py b/graxpert/CommandLineTool.py index a3fdc13..4e7cef0 100644 --- a/graxpert/CommandLineTool.py +++ b/graxpert/CommandLineTool.py @@ -2,6 +2,7 @@ import logging import os import sys +from textwrap import dedent import numpy as np from appdirs import user_config_dir @@ -30,7 +31,7 @@ def execute(self): downscale_factor = 1 - if self.args.preferences_file: + if self.args.preferences_file is not None: preferences = Prefs() preferences.interpol_type_option = "AI" try: @@ -38,13 +39,18 @@ def execute(self): if os.path.isfile(preferences_file): with open(preferences_file, "r") as f: json_prefs = json.load(f) - preferences.background_points = json_prefs["background_points"] - preferences.sample_size = json_prefs["sample_size"] - preferences.spline_order = json_prefs["spline_order"] - preferences.RBF_kernel = json_prefs["RBF_kernel"] - preferences.interpol_type_option = json_prefs["interpol_type_option"] - preferences.ai_version = json_prefs["ai_version"] - + if "background_points" in json_prefs: + preferences.background_points = json_prefs["background_points"] + if "sample_size" in json_prefs: + preferences.sample_size = json_prefs["sample_size"] + if "spline_order" in json_prefs: + preferences.spline_order = json_prefs["spline_order"] + if "RBF_kernel" in json_prefs: + preferences.RBF_kernel = json_prefs["RBF_kernel"] + if "interpol_type_option" in json_prefs: + preferences.interpol_type_option = json_prefs["interpol_type_option"] + if "ai_version" in json_prefs: + preferences.ai_version = json_prefs["ai_version"] if preferences.interpol_type_option == "Kriging" or preferences.interpol_type_option == "RBF": downscale_factor = 4 @@ -53,22 +59,53 @@ def execute(self): logging.shutdown() sys.exit(1) else: - preferences = load_preferences(user_preferences_filename) + preferences = Prefs() preferences.interpol_type_option = "AI" - if self.args.smoothing: + if self.args.smoothing is not None: preferences.smoothing_option = self.args.smoothing logging.info(f"Using user-supplied smoothing value {preferences.smoothing_option}.") + else: + logging.info(f"Using stored smoothing value {preferences.smoothing_option}.") - if self.args.correction: + if self.args.correction is not None: preferences.corr_type = self.args.correction logging.info(f"Using user-supplied correction type {preferences.corr_type}.") + else: + logging.info(f"Using stored correction type {preferences.corr_type}.") if preferences.interpol_type_option == "AI": ai_model_path = ai_model_path_from_version(self.get_ai_version(preferences)) else: ai_model_path = None + if preferences.interpol_type_option == "AI": + logging.info( + dedent( + f"""\ + Excecuting background extraction with the following parameters: + interpolation type - {preferences.interpol_type_option} + smoothing - {preferences.smoothing_option} + correction type - {preferences.corr_type} + AI model path - {ai_model_path}""" + ) + ) + else: + logging.info( + dedent( + f"""\ + Excecuting background extraction with the following parameters: + interpolation type - {preferences.interpol_type_option} + background points - {preferences.background_points} + sample size - {preferences.sample_size} + kernel - {preferences.RBF_kernel} + spline order - {preferences.spline_order} + smoothing - {preferences.smoothing_option} + orrection type - {preferences.corr_type} + downscale_factor - {downscale_factor}""" + ) + ) + background_Astro_Image.set_from_array( extract_background( astro_Image.img_array, diff --git a/graxpert/main.py b/graxpert/main.py index 0456315..55a9bda 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -176,14 +176,14 @@ def main(): type=version_type, help='Version of the AI model, default: "latest"; available locally: [{}], available remotely: [{}]'.format(", ".join(available_local_versions), ", ".join(available_remote_versions)), ) - parser.add_argument("-correction", "--correction", nargs="?", required=False, default="Subtraction", choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") - parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=0.0, type=float, help="Strength of smoothing between 0 and 1") + parser.add_argument("-correction", "--correction", nargs="?", required=False, default=None, choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") + parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=None, type=float, help="Strength of smoothing between 0 and 1") parser.add_argument( "-preferences_file", "--preferences_file", nargs="?", required=False, - default="", + default=None, type=str, help="Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points", ) @@ -197,10 +197,12 @@ def main(): if args.cli: from graxpert.CommandLineTool import CommandLineTool + logging.info(f"Starting GraXpert CLI, version: {graxpert_version} release: {graxpert_release}") clt = CommandLineTool(args) clt.execute() logging.shutdown() else: + logging.info(f"Starting GraXpert UI, version: {graxpert_version} release: {graxpert_release}") ui_main() else: From 838a239ccc03edfc83977aaf957326105fcff514 Mon Sep 17 00:00:00 2001 From: Christian Gesse Date: Sat, 30 Dec 2023 18:53:35 +0100 Subject: [PATCH 09/13] Add run / debug configuration for VS Code --- .vscode/launch.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..82bada6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run GraXpert", + "type": "python", + "request": "launch", + "module": "graxpert.main", + "justMyCode": true + } + ] +} \ No newline at end of file From 4f3e49c144a8869f1a65f7b2ff654b2dead9c496 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 30 Dec 2023 20:06:27 +0100 Subject: [PATCH 10/13] fix: load smoothing and correction type parameters from given '-preferences_file' --- graxpert/CommandLineTool.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/graxpert/CommandLineTool.py b/graxpert/CommandLineTool.py index 4e7cef0..233141f 100644 --- a/graxpert/CommandLineTool.py +++ b/graxpert/CommandLineTool.py @@ -41,16 +41,21 @@ def execute(self): json_prefs = json.load(f) if "background_points" in json_prefs: preferences.background_points = json_prefs["background_points"] - if "sample_size" in json_prefs: - preferences.sample_size = json_prefs["sample_size"] - if "spline_order" in json_prefs: - preferences.spline_order = json_prefs["spline_order"] if "RBF_kernel" in json_prefs: preferences.RBF_kernel = json_prefs["RBF_kernel"] if "interpol_type_option" in json_prefs: preferences.interpol_type_option = json_prefs["interpol_type_option"] + if "smoothing_option" in json_prefs: + preferences.smoothing_option = json_prefs["smoothing_option"] + if "sample_size" in json_prefs: + preferences.sample_size = json_prefs["sample_size"] + if "spline_order" in json_prefs: + preferences.spline_order = json_prefs["spline_order"] + if "corr_type" in json_prefs: + preferences.corr_type = json_prefs["corr_type"] if "ai_version" in json_prefs: preferences.ai_version = json_prefs["ai_version"] + if preferences.interpol_type_option == "Kriging" or preferences.interpol_type_option == "RBF": downscale_factor = 4 From 2fd5d82bb91160718ce60e3649ddb5bc02cd7c6a Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 30 Dec 2023 20:16:26 +0100 Subject: [PATCH 11/13] fix error in background extraction when ai_model has not been configured yet --- graxpert/ai_model_handling.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/graxpert/ai_model_handling.py b/graxpert/ai_model_handling.py index 2bc7be7..6475e00 100644 --- a/graxpert/ai_model_handling.py +++ b/graxpert/ai_model_handling.py @@ -3,8 +3,6 @@ import re import shutil import zipfile -from queue import Empty, Queue -from threading import Thread from appdirs import user_data_dir from minio import Minio @@ -12,6 +10,7 @@ try: from graxpert.s3_secrets import bucket_name, endpoint, ro_access_key, ro_secret_key + client = Minio(endpoint, ro_access_key, ro_secret_key) except Exception as e: logging.exception(e) @@ -22,6 +21,7 @@ ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "ai-models") os.makedirs(ai_models_dir, exist_ok=True) + # ui operations def list_remote_versions(): if client is None: @@ -76,6 +76,9 @@ def latest_version(): def ai_model_path_from_version(local_version): + if local_version is None: + return None + return os.path.join(ai_models_dir, local_version, "bg_model") From 9cbb2a0d4e39b4432dfbf5403a3b446ae44fd90b Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 30 Dec 2023 22:57:04 +0100 Subject: [PATCH 12/13] enable maximized window after startup on Linux --- graxpert/main.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/graxpert/main.py b/graxpert/main.py index 55a9bda..ca78a23 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -1,4 +1,5 @@ import os +import platform import sys # ensure sys.stdout and sys.stderr are not None in PyInstaller environments @@ -89,7 +90,7 @@ def ui_main(): from graxpert.ui.ui_events import UiEvents from graxpert.version import release, version - def on_closing(root, logging_thread): + def on_closing(root: CTk, logging_thread): app_state_2_prefs(graxpert.prefs, graxpert.cmd.app_state) prefs_filename = os.path.join(user_config_dir(appname="GraXpert"), "preferences.json") @@ -136,11 +137,16 @@ def check_for_new_version(): style() root = CTk() + try: - root.state("zoomed") - except: - root.geometry("1024x768") + if "Linux" == platform.system(): + root.attributes("-zoomed", True) + else: + root.state("zoomed") + except Exception as e: root.state("normal") + logging.warning(e, stack_info=True) + root.title("GraXpert | Release: '{}' ({})".format(release, version)) root.iconbitmap() root.iconphoto(True, tk.PhotoImage(file=resource_path("img/Icon.png"))) From 849d2eee7a27300bdddb563ce0c7b3e891c618f5 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 30 Dec 2023 23:07:18 +0100 Subject: [PATCH 13/13] fix tooltip not closing properly during background extraction --- graxpert/ui/tooltip.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graxpert/ui/tooltip.py b/graxpert/ui/tooltip.py index 57f8850..aca67dd 100644 --- a/graxpert/ui/tooltip.py +++ b/graxpert/ui/tooltip.py @@ -3,6 +3,8 @@ from customtkinter import CTkFrame, CTkLabel, CTkToplevel +from graxpert.application.app_events import AppEvents +from graxpert.application.eventbus import eventbus from graxpert.localization import _ from graxpert.ui_scaling import get_scaling_factor @@ -49,6 +51,7 @@ def __init__(self, widget, *, pad=(5, 3, 5, 3), text="widget info", waittime=500 self.pad = pad self.id = None self.tw = None + eventbus.add_listener(AppEvents.CALCULATE_BEGIN, lambda e: self.hide()) def onEnter(self, event=None): self.schedule()