setiastrosuitepro 1.6.0__py3-none-any.whl → 1.6.4.post1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- setiastro/data/SASP_data.fits +0 -0
- setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
- setiastro/data/catalogs/astrobin_filters.csv +890 -0
- setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
- setiastro/data/catalogs/cali2.csv +63 -0
- setiastro/data/catalogs/cali2color.csv +65 -0
- setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
- setiastro/data/catalogs/celestial_catalog.csv +24031 -0
- setiastro/data/catalogs/detected_stars.csv +24784 -0
- setiastro/data/catalogs/fits_header_data.csv +46 -0
- setiastro/data/catalogs/test.csv +8 -0
- setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
- setiastro/images/Astro_Spikes.png +0 -0
- setiastro/images/Background_startup.jpg +0 -0
- setiastro/images/HRDiagram.png +0 -0
- setiastro/images/LExtract.png +0 -0
- setiastro/images/LInsert.png +0 -0
- setiastro/images/Oxygenation-atm-2.svg.png +0 -0
- setiastro/images/RGB080604.png +0 -0
- setiastro/images/abeicon.png +0 -0
- setiastro/images/aberration.png +0 -0
- setiastro/images/andromedatry.png +0 -0
- setiastro/images/andromedatry_satellited.png +0 -0
- setiastro/images/annotated.png +0 -0
- setiastro/images/aperture.png +0 -0
- setiastro/images/astrosuite.ico +0 -0
- setiastro/images/astrosuite.png +0 -0
- setiastro/images/astrosuitepro.icns +0 -0
- setiastro/images/astrosuitepro.ico +0 -0
- setiastro/images/astrosuitepro.png +0 -0
- setiastro/images/background.png +0 -0
- setiastro/images/background2.png +0 -0
- setiastro/images/benchmark.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
- setiastro/images/blaster.png +0 -0
- setiastro/images/blink.png +0 -0
- setiastro/images/clahe.png +0 -0
- setiastro/images/collage.png +0 -0
- setiastro/images/colorwheel.png +0 -0
- setiastro/images/contsub.png +0 -0
- setiastro/images/convo.png +0 -0
- setiastro/images/copyslot.png +0 -0
- setiastro/images/cosmic.png +0 -0
- setiastro/images/cosmicsat.png +0 -0
- setiastro/images/crop1.png +0 -0
- setiastro/images/cropicon.png +0 -0
- setiastro/images/curves.png +0 -0
- setiastro/images/cvs.png +0 -0
- setiastro/images/debayer.png +0 -0
- setiastro/images/denoise_cnn_custom.png +0 -0
- setiastro/images/denoise_cnn_graph.png +0 -0
- setiastro/images/disk.png +0 -0
- setiastro/images/dse.png +0 -0
- setiastro/images/exoicon.png +0 -0
- setiastro/images/eye.png +0 -0
- setiastro/images/fliphorizontal.png +0 -0
- setiastro/images/flipvertical.png +0 -0
- setiastro/images/font.png +0 -0
- setiastro/images/freqsep.png +0 -0
- setiastro/images/functionbundle.png +0 -0
- setiastro/images/graxpert.png +0 -0
- setiastro/images/green.png +0 -0
- setiastro/images/gridicon.png +0 -0
- setiastro/images/halo.png +0 -0
- setiastro/images/hdr.png +0 -0
- setiastro/images/histogram.png +0 -0
- setiastro/images/hubble.png +0 -0
- setiastro/images/imagecombine.png +0 -0
- setiastro/images/invert.png +0 -0
- setiastro/images/isophote.png +0 -0
- setiastro/images/isophote_demo_figure.png +0 -0
- setiastro/images/isophote_demo_image.png +0 -0
- setiastro/images/isophote_demo_model.png +0 -0
- setiastro/images/isophote_demo_residual.png +0 -0
- setiastro/images/jwstpupil.png +0 -0
- setiastro/images/linearfit.png +0 -0
- setiastro/images/livestacking.png +0 -0
- setiastro/images/mask.png +0 -0
- setiastro/images/maskapply.png +0 -0
- setiastro/images/maskcreate.png +0 -0
- setiastro/images/maskremove.png +0 -0
- setiastro/images/morpho.png +0 -0
- setiastro/images/mosaic.png +0 -0
- setiastro/images/multiscale_decomp.png +0 -0
- setiastro/images/nbtorgb.png +0 -0
- setiastro/images/neutral.png +0 -0
- setiastro/images/nuke.png +0 -0
- setiastro/images/openfile.png +0 -0
- setiastro/images/pedestal.png +0 -0
- setiastro/images/pen.png +0 -0
- setiastro/images/pixelmath.png +0 -0
- setiastro/images/platesolve.png +0 -0
- setiastro/images/ppp.png +0 -0
- setiastro/images/pro.png +0 -0
- setiastro/images/project.png +0 -0
- setiastro/images/psf.png +0 -0
- setiastro/images/redo.png +0 -0
- setiastro/images/redoicon.png +0 -0
- setiastro/images/rescale.png +0 -0
- setiastro/images/rgbalign.png +0 -0
- setiastro/images/rgbcombo.png +0 -0
- setiastro/images/rgbextract.png +0 -0
- setiastro/images/rotate180.png +0 -0
- setiastro/images/rotatearbitrary.png +0 -0
- setiastro/images/rotateclockwise.png +0 -0
- setiastro/images/rotatecounterclockwise.png +0 -0
- setiastro/images/satellite.png +0 -0
- setiastro/images/script.png +0 -0
- setiastro/images/selectivecolor.png +0 -0
- setiastro/images/simbad.png +0 -0
- setiastro/images/slot0.png +0 -0
- setiastro/images/slot1.png +0 -0
- setiastro/images/slot2.png +0 -0
- setiastro/images/slot3.png +0 -0
- setiastro/images/slot4.png +0 -0
- setiastro/images/slot5.png +0 -0
- setiastro/images/slot6.png +0 -0
- setiastro/images/slot7.png +0 -0
- setiastro/images/slot8.png +0 -0
- setiastro/images/slot9.png +0 -0
- setiastro/images/spcc.png +0 -0
- setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
- setiastro/images/spinner.gif +0 -0
- setiastro/images/stacking.png +0 -0
- setiastro/images/staradd.png +0 -0
- setiastro/images/staralign.png +0 -0
- setiastro/images/starnet.png +0 -0
- setiastro/images/starregistration.png +0 -0
- setiastro/images/starspike.png +0 -0
- setiastro/images/starstretch.png +0 -0
- setiastro/images/statstretch.png +0 -0
- setiastro/images/supernova.png +0 -0
- setiastro/images/uhs.png +0 -0
- setiastro/images/undoicon.png +0 -0
- setiastro/images/upscale.png +0 -0
- setiastro/images/viewbundle.png +0 -0
- setiastro/images/whitebalance.png +0 -0
- setiastro/images/wimi_icon_256x256.png +0 -0
- setiastro/images/wimilogo.png +0 -0
- setiastro/images/wims.png +0 -0
- setiastro/images/wrench_icon.png +0 -0
- setiastro/images/xisfliberator.png +0 -0
- setiastro/qml/ResourceMonitor.qml +126 -0
- setiastro/saspro/__main__.py +228 -67
- setiastro/saspro/_generated/build_info.py +2 -1
- setiastro/saspro/abe.py +76 -25
- setiastro/saspro/aberration_ai.py +14 -14
- setiastro/saspro/add_stars.py +15 -12
- setiastro/saspro/astrobin_exporter.py +61 -58
- setiastro/saspro/astrospike_python.py +3 -1
- setiastro/saspro/autostretch.py +4 -2
- setiastro/saspro/backgroundneutral.py +65 -14
- setiastro/saspro/batch_convert.py +8 -5
- setiastro/saspro/batch_renamer.py +39 -36
- setiastro/saspro/blemish_blaster.py +15 -12
- setiastro/saspro/blink_comparator_pro.py +605 -379
- setiastro/saspro/cheat_sheet.py +62 -17
- setiastro/saspro/clahe.py +34 -8
- setiastro/saspro/comet_stacking.py +103 -38
- setiastro/saspro/common_tr.py +107 -0
- setiastro/saspro/continuum_subtract.py +7 -7
- setiastro/saspro/convo.py +12 -9
- setiastro/saspro/copyastro.py +3 -0
- setiastro/saspro/cosmicclarity.py +77 -52
- setiastro/saspro/crop_dialog_pro.py +80 -45
- setiastro/saspro/curve_editor_pro.py +51 -33
- setiastro/saspro/debayer.py +6 -3
- setiastro/saspro/doc_manager.py +49 -19
- setiastro/saspro/exoplanet_detector.py +11 -11
- setiastro/saspro/fitsmodifier.py +48 -44
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/frequency_separation.py +18 -12
- setiastro/saspro/function_bundle.py +18 -16
- setiastro/saspro/generate_translations.py +3092 -0
- setiastro/saspro/ghs_dialog_pro.py +19 -16
- setiastro/saspro/graxpert.py +3 -0
- setiastro/saspro/gui/main_window.py +471 -126
- setiastro/saspro/gui/mixins/dock_mixin.py +123 -11
- setiastro/saspro/gui/mixins/file_mixin.py +25 -20
- setiastro/saspro/gui/mixins/geometry_mixin.py +115 -15
- setiastro/saspro/gui/mixins/header_mixin.py +6 -6
- setiastro/saspro/gui/mixins/mask_mixin.py +8 -8
- setiastro/saspro/gui/mixins/menu_mixin.py +62 -33
- setiastro/saspro/gui/mixins/toolbar_mixin.py +382 -226
- setiastro/saspro/gui/mixins/update_mixin.py +26 -26
- setiastro/saspro/gui/statistics_dialog.py +47 -0
- setiastro/saspro/halobgon.py +29 -3
- setiastro/saspro/header_viewer.py +21 -18
- setiastro/saspro/histogram.py +29 -26
- setiastro/saspro/history_explorer.py +2 -0
- setiastro/saspro/i18n.py +168 -0
- setiastro/saspro/image_combine.py +3 -0
- setiastro/saspro/image_peeker_pro.py +52 -44
- setiastro/saspro/imageops/stretch.py +5 -13
- setiastro/saspro/isophote.py +3 -0
- setiastro/saspro/legacy/numba_utils.py +64 -47
- setiastro/saspro/linear_fit.py +3 -0
- setiastro/saspro/live_stacking.py +13 -2
- setiastro/saspro/mask_creation.py +180 -22
- setiastro/saspro/mfdeconv.py +5 -0
- setiastro/saspro/morphology.py +38 -13
- setiastro/saspro/multiscale_decomp.py +713 -256
- setiastro/saspro/nbtorgb_stars.py +12 -2
- setiastro/saspro/numba_utils.py +149 -48
- setiastro/saspro/ops/scripts.py +77 -17
- setiastro/saspro/ops/settings.py +177 -100
- setiastro/saspro/perfect_palette_picker.py +25 -7
- setiastro/saspro/pixelmath.py +114 -110
- setiastro/saspro/plate_solver.py +118 -108
- setiastro/saspro/remove_green.py +24 -7
- setiastro/saspro/remove_stars.py +136 -162
- setiastro/saspro/remove_stars_preset.py +55 -13
- setiastro/saspro/resources.py +46 -15
- setiastro/saspro/rgb_combination.py +19 -18
- setiastro/saspro/rgbalign.py +11 -11
- setiastro/saspro/save_options.py +5 -4
- setiastro/saspro/selective_color.py +84 -25
- setiastro/saspro/sfcc.py +119 -72
- setiastro/saspro/shortcuts.py +345 -36
- setiastro/saspro/signature_insert.py +4 -1
- setiastro/saspro/stacking_suite.py +2066 -1119
- setiastro/saspro/star_alignment.py +291 -331
- setiastro/saspro/star_spikes.py +137 -53
- setiastro/saspro/star_stretch.py +47 -10
- setiastro/saspro/stat_stretch.py +52 -16
- setiastro/saspro/status_log_dock.py +1 -1
- setiastro/saspro/subwindow.py +97 -36
- setiastro/saspro/supernovaasteroidhunter.py +68 -61
- setiastro/saspro/swap_manager.py +77 -42
- setiastro/saspro/translations/all_source_strings.json +4726 -0
- setiastro/saspro/translations/ar_translations.py +4096 -0
- setiastro/saspro/translations/de_translations.py +3728 -0
- setiastro/saspro/translations/es_translations.py +4169 -0
- setiastro/saspro/translations/fr_translations.py +4090 -0
- setiastro/saspro/translations/hi_translations.py +3803 -0
- setiastro/saspro/translations/integrate_translations.py +271 -0
- setiastro/saspro/translations/it_translations.py +4728 -0
- setiastro/saspro/translations/ja_translations.py +3834 -0
- setiastro/saspro/translations/pt_translations.py +3847 -0
- setiastro/saspro/translations/ru_translations.py +3082 -0
- setiastro/saspro/translations/saspro_ar.qm +0 -0
- setiastro/saspro/translations/saspro_ar.ts +16019 -0
- setiastro/saspro/translations/saspro_de.qm +0 -0
- setiastro/saspro/translations/saspro_de.ts +14548 -0
- setiastro/saspro/translations/saspro_es.qm +0 -0
- setiastro/saspro/translations/saspro_es.ts +16202 -0
- setiastro/saspro/translations/saspro_fr.qm +0 -0
- setiastro/saspro/translations/saspro_fr.ts +15870 -0
- setiastro/saspro/translations/saspro_hi.qm +0 -0
- setiastro/saspro/translations/saspro_hi.ts +14855 -0
- setiastro/saspro/translations/saspro_it.qm +0 -0
- setiastro/saspro/translations/saspro_it.ts +19046 -0
- setiastro/saspro/translations/saspro_ja.qm +0 -0
- setiastro/saspro/translations/saspro_ja.ts +14980 -0
- setiastro/saspro/translations/saspro_pt.qm +0 -0
- setiastro/saspro/translations/saspro_pt.ts +15024 -0
- setiastro/saspro/translations/saspro_ru.qm +0 -0
- setiastro/saspro/translations/saspro_ru.ts +11835 -0
- setiastro/saspro/translations/saspro_sw.qm +0 -0
- setiastro/saspro/translations/saspro_sw.ts +15237 -0
- setiastro/saspro/translations/saspro_uk.qm +0 -0
- setiastro/saspro/translations/saspro_uk.ts +15248 -0
- setiastro/saspro/translations/saspro_zh.qm +0 -0
- setiastro/saspro/translations/saspro_zh.ts +15289 -0
- setiastro/saspro/translations/sw_translations.py +3897 -0
- setiastro/saspro/translations/uk_translations.py +3929 -0
- setiastro/saspro/translations/zh_translations.py +3910 -0
- setiastro/saspro/versioning.py +77 -0
- setiastro/saspro/view_bundle.py +20 -17
- setiastro/saspro/wavescale_hdr.py +54 -33
- setiastro/saspro/wavescale_hdr_preset.py +6 -5
- setiastro/saspro/wavescalede.py +54 -31
- setiastro/saspro/wavescalede_preset.py +9 -7
- setiastro/saspro/whitebalance.py +58 -22
- setiastro/saspro/widgets/common_utilities.py +12 -11
- setiastro/saspro/widgets/minigame/game.js +991 -0
- setiastro/saspro/widgets/minigame/index.html +53 -0
- setiastro/saspro/widgets/minigame/style.css +241 -0
- setiastro/saspro/widgets/preview_dialogs.py +8 -8
- setiastro/saspro/widgets/resource_monitor.py +263 -0
- setiastro/saspro/widgets/spinboxes.py +18 -0
- setiastro/saspro/widgets/wavelet_utils.py +52 -20
- setiastro/saspro/wimi.py +7996 -0
- setiastro/saspro/wims.py +578 -0
- setiastro/saspro/window_shelf.py +2 -2
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/METADATA +15 -3
- setiastrosuitepro-1.6.4.post1.dist-info/RECORD +368 -0
- setiastrosuitepro-1.6.0.dist-info/RECORD +0 -174
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/WHEEL +0 -0
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/entry_points.txt +0 -0
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/licenses/LICENSE +0 -0
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/licenses/license.txt +0 -0
setiastro/saspro/sfcc.py
CHANGED
|
@@ -195,7 +195,7 @@ def compute_gradient_map(sources, delta_flux, shape, method="poly2"):
|
|
|
195
195
|
class SaspViewer(QMainWindow):
|
|
196
196
|
def __init__(self, sasp_data_path: str, user_custom_path: str):
|
|
197
197
|
super().__init__()
|
|
198
|
-
self.setWindowTitle("SASP Viewer (Pickles + RGB Responses)")
|
|
198
|
+
self.setWindowTitle(self.tr("SASP Viewer (Pickles + RGB Responses)"))
|
|
199
199
|
|
|
200
200
|
self.base_hdul = fits.open(sasp_data_path, mode="readonly", memmap=False)
|
|
201
201
|
self.custom_hdul = fits.open(user_custom_path, mode="readonly", memmap=False)
|
|
@@ -220,24 +220,24 @@ class SaspViewer(QMainWindow):
|
|
|
220
220
|
vbox = QVBoxLayout(); central.setLayout(vbox)
|
|
221
221
|
|
|
222
222
|
row = QHBoxLayout(); vbox.addLayout(row)
|
|
223
|
-
row.addWidget(QLabel("Star Template:"))
|
|
223
|
+
row.addWidget(QLabel(self.tr("Star Template:")))
|
|
224
224
|
self.star_combo = QComboBox(); self.star_combo.addItems(self.pickles_templates); row.addWidget(self.star_combo)
|
|
225
|
-
row.addWidget(QLabel("R-Filter:"))
|
|
225
|
+
row.addWidget(QLabel(self.tr("R-Filter:")))
|
|
226
226
|
self.r_filter_combo = QComboBox(); self.r_filter_combo.addItems(self.rgb_filter_choices); row.addWidget(self.r_filter_combo)
|
|
227
|
-
row.addWidget(QLabel("G-Filter:"))
|
|
227
|
+
row.addWidget(QLabel(self.tr("G-Filter:")))
|
|
228
228
|
self.g_filter_combo = QComboBox(); self.g_filter_combo.addItems(self.rgb_filter_choices); row.addWidget(self.g_filter_combo)
|
|
229
|
-
row.addWidget(QLabel("B-Filter:"))
|
|
229
|
+
row.addWidget(QLabel(self.tr("B-Filter:")))
|
|
230
230
|
self.b_filter_combo = QComboBox(); self.b_filter_combo.addItems(self.rgb_filter_choices); row.addWidget(self.b_filter_combo)
|
|
231
231
|
|
|
232
232
|
row2 = QHBoxLayout(); vbox.addLayout(row2)
|
|
233
|
-
row2.addWidget(QLabel("LP/Cut Filter1:"))
|
|
233
|
+
row2.addWidget(QLabel(self.tr("LP/Cut Filter1:")))
|
|
234
234
|
self.lp_filter_combo = QComboBox(); self.lp_filter_combo.addItems(self.rgb_filter_choices); row2.addWidget(self.lp_filter_combo)
|
|
235
|
-
row2.addWidget(QLabel("LP/Cut Filter2:"))
|
|
235
|
+
row2.addWidget(QLabel(self.tr("LP/Cut Filter2:")))
|
|
236
236
|
self.lp_filter_combo2 = QComboBox(); self.lp_filter_combo2.addItems(self.rgb_filter_choices); row2.addWidget(self.lp_filter_combo2)
|
|
237
|
-
row2.addSpacing(20); row2.addWidget(QLabel("Sensor (QE):"))
|
|
237
|
+
row2.addSpacing(20); row2.addWidget(QLabel(self.tr("Sensor (QE):")))
|
|
238
238
|
self.sens_combo = QComboBox(); self.sens_combo.addItems(self.sensor_list); row2.addWidget(self.sens_combo)
|
|
239
239
|
|
|
240
|
-
self.plot_btn = QPushButton("Plot"); self.plot_btn.clicked.connect(self.update_plot); row.addWidget(self.plot_btn)
|
|
240
|
+
self.plot_btn = QPushButton(self.tr("Plot")); self.plot_btn.clicked.connect(self.update_plot); row.addWidget(self.plot_btn)
|
|
241
241
|
|
|
242
242
|
self.figure = Figure(figsize=(9, 6)); self.canvas = FigureCanvas(self.figure); vbox.addWidget(self.canvas)
|
|
243
243
|
self.update_plot()
|
|
@@ -309,22 +309,22 @@ class SaspViewer(QMainWindow):
|
|
|
309
309
|
mag_texts.append(f"{color[0].upper()}→{data['filter_name']}: {mag:.2f}")
|
|
310
310
|
else:
|
|
311
311
|
mag_texts.append(f"{color[0].upper()}→{data['filter_name']}: N/A")
|
|
312
|
-
title_text = " | ".join(mag_texts) if mag_texts else "No channels selected"
|
|
312
|
+
title_text = " | ".join(mag_texts) if mag_texts else self.tr("No channels selected")
|
|
313
313
|
|
|
314
314
|
self.figure.clf()
|
|
315
315
|
ax1 = self.figure.add_subplot(111)
|
|
316
316
|
ax1.plot(common_wl, fl_common, color="black", linewidth=1, label=f"{star_ext} SED")
|
|
317
317
|
for color, data in rgb_data.items():
|
|
318
318
|
if data is not None:
|
|
319
|
-
ax1.plot(common_wl, data["response"], color="gold", linewidth=1.5, label=
|
|
320
|
-
ax1.set_xlim(wl_min, wl_max); ax1.set_xlabel("Wavelength (Å)")
|
|
321
|
-
ax1.set_ylabel("Flux (erg s⁻¹ cm⁻² Å⁻¹)", color="black"); ax1.tick_params(axis="y", labelcolor="black")
|
|
319
|
+
ax1.plot(common_wl, data["response"], color="gold", linewidth=1.5, label=self.tr("{0} Response").format(color.upper()))
|
|
320
|
+
ax1.set_xlim(wl_min, wl_max); ax1.set_xlabel(self.tr("Wavelength (Å)"))
|
|
321
|
+
ax1.set_ylabel(self.tr("Flux (erg s⁻¹ cm⁻² Å⁻¹)"), color="black"); ax1.tick_params(axis="y", labelcolor="black")
|
|
322
322
|
|
|
323
323
|
ax2 = ax1.twinx()
|
|
324
|
-
ax2.set_ylabel("Relative Throughput", color="red"); ax2.tick_params(axis="y", labelcolor="red"); ax2.set_ylim(0.0, 1.0)
|
|
325
|
-
if rgb_data["red"] is not None: ax2.plot(common_wl, rgb_data["red"]["T_sys"], color="red", linestyle="--", linewidth=1, label="R filter×QE")
|
|
326
|
-
if rgb_data["green"] is not None: ax2.plot(common_wl, rgb_data["green"]["T_sys"], color="green", linestyle="--", linewidth=1, label="G filter×QE")
|
|
327
|
-
if rgb_data["blue"] is not None: ax2.plot(common_wl, rgb_data["blue"]["T_sys"], color="blue", linestyle="--", linewidth=1, label="B filter×QE")
|
|
324
|
+
ax2.set_ylabel(self.tr("Relative Throughput"), color="red"); ax2.tick_params(axis="y", labelcolor="red"); ax2.set_ylim(0.0, 1.0)
|
|
325
|
+
if rgb_data["red"] is not None: ax2.plot(common_wl, rgb_data["red"]["T_sys"], color="red", linestyle="--", linewidth=1, label=self.tr("R filter×QE"))
|
|
326
|
+
if rgb_data["green"] is not None: ax2.plot(common_wl, rgb_data["green"]["T_sys"], color="green", linestyle="--", linewidth=1, label=self.tr("G filter×QE"))
|
|
327
|
+
if rgb_data["blue"] is not None: ax2.plot(common_wl, rgb_data["blue"]["T_sys"], color="blue", linestyle="--", linewidth=1, label=self.tr("B filter×QE"))
|
|
328
328
|
|
|
329
329
|
ax1.grid(True, which="both", linestyle="--", alpha=0.3); self.figure.suptitle(title_text, fontsize=10)
|
|
330
330
|
lines1, labels1 = ax1.get_legend_handles_labels(); lines2, labels2 = ax2.get_legend_handles_labels()
|
|
@@ -345,7 +345,10 @@ class SFCCDialog(QDialog):
|
|
|
345
345
|
"""
|
|
346
346
|
def __init__(self, doc_manager, sasp_data_path, parent=None):
|
|
347
347
|
super().__init__(parent)
|
|
348
|
-
self.setWindowTitle("Spectral Flux Color Calibration")
|
|
348
|
+
self.setWindowTitle(self.tr("Spectral Flux Color Calibration"))
|
|
349
|
+
self.setWindowFlag(Qt.WindowType.Window, True)
|
|
350
|
+
self.setWindowModality(Qt.WindowModality.NonModal)
|
|
351
|
+
self.setModal(False)
|
|
349
352
|
self.setMinimumSize(800, 600)
|
|
350
353
|
|
|
351
354
|
self.doc_manager = doc_manager
|
|
@@ -353,7 +356,7 @@ class SFCCDialog(QDialog):
|
|
|
353
356
|
self.user_custom_path = self._ensure_user_custom_fits()
|
|
354
357
|
self.current_image = None
|
|
355
358
|
self.current_header = None
|
|
356
|
-
self.orientation_label = QLabel("Orientation: N/A")
|
|
359
|
+
self.orientation_label = QLabel(self.tr("Orientation: N/A"))
|
|
357
360
|
self.sasp_viewer_window = None
|
|
358
361
|
self.main_win = parent
|
|
359
362
|
|
|
@@ -457,19 +460,19 @@ class SFCCDialog(QDialog):
|
|
|
457
460
|
layout = QVBoxLayout(self)
|
|
458
461
|
|
|
459
462
|
row1 = QHBoxLayout(); layout.addLayout(row1)
|
|
460
|
-
self.fetch_stars_btn = QPushButton("Step 1: Fetch Stars from Current View")
|
|
463
|
+
self.fetch_stars_btn = QPushButton(self.tr("Step 1: Fetch Stars from Current View"))
|
|
461
464
|
f = self.fetch_stars_btn.font(); f.setBold(True); self.fetch_stars_btn.setFont(f)
|
|
462
465
|
self.fetch_stars_btn.clicked.connect(self.fetch_stars)
|
|
463
466
|
row1.addWidget(self.fetch_stars_btn)
|
|
464
467
|
|
|
465
|
-
self.open_sasp_btn = QPushButton("Open SASP Viewer")
|
|
468
|
+
self.open_sasp_btn = QPushButton(self.tr("Open SASP Viewer"))
|
|
466
469
|
self.open_sasp_btn.clicked.connect(self.open_sasp_viewer)
|
|
467
470
|
row1.addWidget(self.open_sasp_btn)
|
|
468
471
|
|
|
469
472
|
row1.addSpacing(20)
|
|
470
|
-
row1.addWidget(QLabel("Select White Reference:"))
|
|
473
|
+
row1.addWidget(QLabel(self.tr("Select White Reference:")))
|
|
471
474
|
self.star_combo = QComboBox()
|
|
472
|
-
self.star_combo.addItem("Vega (A0V)", userData="A0V")
|
|
475
|
+
self.star_combo.addItem(self.tr("Vega (A0V)"), userData="A0V")
|
|
473
476
|
for sed in getattr(self, "sed_list", []):
|
|
474
477
|
if sed.upper() == "A0V": continue
|
|
475
478
|
self.star_combo.addItem(sed, userData=sed)
|
|
@@ -478,32 +481,32 @@ class SFCCDialog(QDialog):
|
|
|
478
481
|
if idx_g2v >= 0: self.star_combo.setCurrentIndex(idx_g2v)
|
|
479
482
|
|
|
480
483
|
row2 = QHBoxLayout(); layout.addLayout(row2)
|
|
481
|
-
row2.addWidget(QLabel("R Filter:"))
|
|
484
|
+
row2.addWidget(QLabel(self.tr("R Filter:")))
|
|
482
485
|
self.r_filter_combo = QComboBox(); self.r_filter_combo.addItem("(None)"); self.r_filter_combo.addItems(self.filter_list); row2.addWidget(self.r_filter_combo)
|
|
483
|
-
row2.addSpacing(20); row2.addWidget(QLabel("G Filter:"))
|
|
486
|
+
row2.addSpacing(20); row2.addWidget(QLabel(self.tr("G Filter:")))
|
|
484
487
|
self.g_filter_combo = QComboBox(); self.g_filter_combo.addItem("(None)"); self.g_filter_combo.addItems(self.filter_list); row2.addWidget(self.g_filter_combo)
|
|
485
|
-
row2.addSpacing(20); row2.addWidget(QLabel("B Filter:"))
|
|
488
|
+
row2.addSpacing(20); row2.addWidget(QLabel(self.tr("B Filter:")))
|
|
486
489
|
self.b_filter_combo = QComboBox(); self.b_filter_combo.addItem("(None)"); self.b_filter_combo.addItems(self.filter_list); row2.addWidget(self.b_filter_combo)
|
|
487
490
|
|
|
488
491
|
row3 = QHBoxLayout(); layout.addLayout(row3)
|
|
489
492
|
row3.addStretch()
|
|
490
|
-
row3.addWidget(QLabel("Sensor (QE):"))
|
|
493
|
+
row3.addWidget(QLabel(self.tr("Sensor (QE):")))
|
|
491
494
|
self.sens_combo = QComboBox(); self.sens_combo.addItem("(None)"); self.sens_combo.addItems(self.sensor_list); row3.addWidget(self.sens_combo)
|
|
492
|
-
row3.addSpacing(20); row3.addWidget(QLabel("LP/Cut Filter1:"))
|
|
495
|
+
row3.addSpacing(20); row3.addWidget(QLabel(self.tr("LP/Cut Filter1:")))
|
|
493
496
|
self.lp_filter_combo = QComboBox(); self.lp_filter_combo.addItem("(None)"); self.lp_filter_combo.addItems(self.filter_list); row3.addWidget(self.lp_filter_combo)
|
|
494
|
-
row3.addSpacing(20); row3.addWidget(QLabel("LP/Cut Filter2:"))
|
|
497
|
+
row3.addSpacing(20); row3.addWidget(QLabel(self.tr("LP/Cut Filter2:")))
|
|
495
498
|
self.lp_filter_combo2 = QComboBox(); self.lp_filter_combo2.addItem("(None)"); self.lp_filter_combo2.addItems(self.filter_list); row3.addWidget(self.lp_filter_combo2)
|
|
496
499
|
row3.addStretch()
|
|
497
500
|
|
|
498
501
|
row4 = QHBoxLayout(); layout.addLayout(row4)
|
|
499
|
-
self.run_spcc_btn = QPushButton("Step 2: Run Color Calibration")
|
|
502
|
+
self.run_spcc_btn = QPushButton(self.tr("Step 2: Run Color Calibration"))
|
|
500
503
|
f2 = self.run_spcc_btn.font(); f2.setBold(True); self.run_spcc_btn.setFont(f2)
|
|
501
504
|
self.run_spcc_btn.clicked.connect(self.run_spcc)
|
|
502
505
|
row4.addWidget(self.run_spcc_btn)
|
|
503
506
|
|
|
504
|
-
self.neutralize_chk = QCheckBox("Background Neutralization"); self.neutralize_chk.setChecked(True); row4.addWidget(self.neutralize_chk)
|
|
507
|
+
self.neutralize_chk = QCheckBox(self.tr("Background Neutralization")); self.neutralize_chk.setChecked(True); row4.addWidget(self.neutralize_chk)
|
|
505
508
|
|
|
506
|
-
self.run_grad_btn = QPushButton("Run Gradient Extraction (Beta)")
|
|
509
|
+
self.run_grad_btn = QPushButton(self.tr("Run Gradient Extraction (Beta)"))
|
|
507
510
|
f3 = self.run_grad_btn.font(); f3.setBold(True); self.run_grad_btn.setFont(f3)
|
|
508
511
|
self.run_grad_btn.clicked.connect(self.run_gradient_extraction)
|
|
509
512
|
row4.addWidget(self.run_grad_btn)
|
|
@@ -512,7 +515,7 @@ class SFCCDialog(QDialog):
|
|
|
512
515
|
row4.addWidget(self.grad_method_combo)
|
|
513
516
|
|
|
514
517
|
row4.addSpacing(15)
|
|
515
|
-
row4.addWidget(QLabel("Star detect σ:"))
|
|
518
|
+
row4.addWidget(QLabel(self.tr("Star detect σ:")))
|
|
516
519
|
self.sep_thr_spin = QSpinBox()
|
|
517
520
|
self.sep_thr_spin.setRange(2, 50) # should be enough
|
|
518
521
|
self.sep_thr_spin.setValue(5) # our current hardcoded value
|
|
@@ -520,17 +523,17 @@ class SFCCDialog(QDialog):
|
|
|
520
523
|
row4.addWidget(self.sep_thr_spin)
|
|
521
524
|
|
|
522
525
|
row4.addStretch()
|
|
523
|
-
self.add_curve_btn = QPushButton("Add Custom Filter/Sensor Curve…")
|
|
526
|
+
self.add_curve_btn = QPushButton(self.tr("Add Custom Filter/Sensor Curve…"))
|
|
524
527
|
self.add_curve_btn.clicked.connect(self.add_custom_curve); row4.addWidget(self.add_curve_btn)
|
|
525
|
-
self.remove_curve_btn = QPushButton("Remove Filter/Sensor Curve…")
|
|
528
|
+
self.remove_curve_btn = QPushButton(self.tr("Remove Filter/Sensor Curve…"))
|
|
526
529
|
self.remove_curve_btn.clicked.connect(self.remove_custom_curve); row4.addWidget(self.remove_curve_btn)
|
|
527
530
|
row4.addStretch()
|
|
528
|
-
self.close_btn = QPushButton("Close"); self.close_btn.clicked.connect(self.close); row4.addWidget(self.close_btn)
|
|
531
|
+
self.close_btn = QPushButton(self.tr("Close")); self.close_btn.clicked.connect(self.close); row4.addWidget(self.close_btn)
|
|
529
532
|
|
|
530
533
|
self.count_label = QLabel(""); layout.addWidget(self.count_label)
|
|
531
534
|
|
|
532
535
|
self.figure = Figure(figsize=(6, 4)); self.canvas = FigureCanvas(self.figure); self.canvas.setVisible(False); layout.addWidget(self.canvas, stretch=1)
|
|
533
|
-
self.reset_btn = QPushButton("Reset View/Close"); self.reset_btn.clicked.connect(self.close); layout.addWidget(self.reset_btn)
|
|
536
|
+
self.reset_btn = QPushButton(self.tr("Reset View/Close")); self.reset_btn.clicked.connect(self.close); layout.addWidget(self.reset_btn)
|
|
534
537
|
|
|
535
538
|
# hide gradient controls by default (enable if you like)
|
|
536
539
|
self.run_grad_btn.hide(); self.grad_method_combo.hide()
|
|
@@ -610,9 +613,9 @@ class SFCCDialog(QDialog):
|
|
|
610
613
|
|
|
611
614
|
def get_calibration_points(self, rgb_img: np.ndarray):
|
|
612
615
|
print("\nClick three calibration points: BL (λmin,0), BR (λmax,0), TL (λmin,1)")
|
|
613
|
-
fig, ax = plt.subplots(figsize=(8, 5)); ax.imshow(rgb_img); ax.set_title("Click 3 points, then close")
|
|
616
|
+
fig, ax = plt.subplots(figsize=(8, 5)); ax.imshow(rgb_img); ax.set_title(self.tr("Click 3 points, then close"))
|
|
614
617
|
pts = plt.ginput(3, timeout=-1); plt.close(fig)
|
|
615
|
-
if len(pts) != 3: raise RuntimeError("Need exactly three clicks for calibration.")
|
|
618
|
+
if len(pts) != 3: raise RuntimeError(self.tr("Need exactly three clicks for calibration."))
|
|
616
619
|
return pts[0], pts[1], pts[2]
|
|
617
620
|
|
|
618
621
|
def build_transforms(self, px_bl, py_bl, px_br, py_br, px_tl, py_tl, λ_min, λ_max, resp_min, resp_max):
|
|
@@ -644,10 +647,10 @@ class SFCCDialog(QDialog):
|
|
|
644
647
|
return df.sort_values("wavelength_nm").reset_index(drop=True)
|
|
645
648
|
|
|
646
649
|
def _query_name_channel(self):
|
|
647
|
-
name_str, ok1 = QInputDialog.getText(self, "Curve Name", "Enter curve name (EXTNAME):")
|
|
650
|
+
name_str, ok1 = QInputDialog.getText(self, self.tr("Curve Name"), self.tr("Enter curve name (EXTNAME):"))
|
|
648
651
|
if not (ok1 and name_str.strip()): return False, None, None
|
|
649
652
|
extname = name_str.strip().upper().replace(" ", "_")
|
|
650
|
-
ch_str, ok2 = QInputDialog.getText(self, "Channel", "Enter channel (R,G,B or Q for sensor):")
|
|
653
|
+
ch_str, ok2 = QInputDialog.getText(self, self.tr("Channel"), self.tr("Enter channel (R,G,B or Q for sensor):"))
|
|
651
654
|
if not (ok2 and ch_str.strip()): return False, None, None
|
|
652
655
|
return True, extname, ch_str.strip().upper()
|
|
653
656
|
|
|
@@ -662,16 +665,16 @@ class SFCCDialog(QDialog):
|
|
|
662
665
|
hdul.append(new_hdu); hdul.flush()
|
|
663
666
|
|
|
664
667
|
def add_custom_curve(self):
|
|
665
|
-
msg = QMessageBox(self); msg.setWindowTitle("Add Custom Curve"); msg.setText("Choose how to add the curve:")
|
|
666
|
-
csv_btn = msg.addButton("Import CSV", QMessageBox.ButtonRole.AcceptRole)
|
|
667
|
-
img_btn = msg.addButton("Digitize Image", QMessageBox.ButtonRole.AcceptRole)
|
|
668
|
+
msg = QMessageBox(self); msg.setWindowTitle(self.tr("Add Custom Curve")); msg.setText(self.tr("Choose how to add the curve:"))
|
|
669
|
+
csv_btn = msg.addButton(self.tr("Import CSV"), QMessageBox.ButtonRole.AcceptRole)
|
|
670
|
+
img_btn = msg.addButton(self.tr("Digitize Image"), QMessageBox.ButtonRole.AcceptRole)
|
|
668
671
|
cancel_btn = msg.addButton(QMessageBox.StandardButton.Cancel)
|
|
669
672
|
msg.exec()
|
|
670
673
|
if msg.clickedButton() == csv_btn: self._import_curve_from_csv()
|
|
671
674
|
elif msg.clickedButton() == img_btn: self._digitize_curve_from_image()
|
|
672
675
|
|
|
673
676
|
def _import_curve_from_csv(self):
|
|
674
|
-
csv_path, _ = QFileDialog.getOpenFileName(self, "Select 2-column CSV (λ_nm, response)", "", "CSV Files (*.csv);;All Files (*)")
|
|
677
|
+
csv_path, _ = QFileDialog.getOpenFileName(self, self.tr("Select 2-column CSV (λ_nm, response)"), "", "CSV Files (*.csv);;All Files (*)")
|
|
675
678
|
if not csv_path: return
|
|
676
679
|
try:
|
|
677
680
|
df = (pd.read_csv(csv_path, comment="#", header=None).iloc[:, :2].dropna())
|
|
@@ -683,19 +686,19 @@ class SFCCDialog(QDialog):
|
|
|
683
686
|
df.columns = ["wavelength_nm","response"]
|
|
684
687
|
wl_nm = df["wavelength_nm"].astype(float).to_numpy(); tp = df["response"].astype(float).to_numpy()
|
|
685
688
|
except Exception as e2:
|
|
686
|
-
QMessageBox.critical(self, "CSV Error",
|
|
689
|
+
QMessageBox.critical(self, self.tr("CSV Error"), self.tr("Could not read CSV:\n{0}").format(e2)); return
|
|
687
690
|
except Exception as e:
|
|
688
|
-
QMessageBox.critical(self, "CSV Error",
|
|
691
|
+
QMessageBox.critical(self, self.tr("CSV Error"), self.tr("Could not read CSV:\n{0}").format(e)); return
|
|
689
692
|
|
|
690
693
|
ok, extname_base, channel_val = self._query_name_channel()
|
|
691
694
|
if not ok: return
|
|
692
695
|
wl_ang = (wl_nm * 10.0).astype(np.float32); tr_final = tp.astype(np.float32)
|
|
693
696
|
self._append_curve_hdu(wl_ang, tr_final, extname_base, "SENSOR" if channel_val=="Q" else "FILTER", f"CSV:{os.path.basename(csv_path)}")
|
|
694
697
|
self._reload_hdu_lists(); self.refresh_filter_sensor_lists()
|
|
695
|
-
QMessageBox.information(self, "Done",
|
|
698
|
+
QMessageBox.information(self, self.tr("Done"), self.tr("CSV curve '{0}' added.").format(extname_base))
|
|
696
699
|
|
|
697
700
|
def _digitize_curve_from_image(self):
|
|
698
|
-
img_path_str, _ = QFileDialog.getOpenFileName(self, "Select Curve Image to Digitize", "", "Images (*.png *.jpg *.jpeg *.bmp);;All Files (*)")
|
|
701
|
+
img_path_str, _ = QFileDialog.getOpenFileName(self, self.tr("Select Curve Image to Digitize"), "", "Images (*.png *.jpg *.jpeg *.bmp);;All Files (*)")
|
|
699
702
|
if not img_path_str: return
|
|
700
703
|
img_filename = os.path.basename(img_path_str)
|
|
701
704
|
try:
|
|
@@ -703,20 +706,20 @@ class SFCCDialog(QDialog):
|
|
|
703
706
|
if bgr is None: raise RuntimeError(f"cv2.imread returned None for '{img_path_str}'")
|
|
704
707
|
rgb_img = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB); gray_img = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)
|
|
705
708
|
except Exception as e:
|
|
706
|
-
QMessageBox.critical(self, "Error",
|
|
709
|
+
QMessageBox.critical(self, self.tr("Error"), self.tr("Could not load image:\n{0}").format(e)); return
|
|
707
710
|
|
|
708
711
|
try:
|
|
709
712
|
(px_bl, py_bl), (px_br, py_br), (px_tl, py_tl) = self.get_calibration_points(rgb_img)
|
|
710
713
|
except Exception as e:
|
|
711
|
-
QMessageBox.critical(self, "Digitization Error", str(e)); return
|
|
714
|
+
QMessageBox.critical(self, self.tr("Digitization Error"), str(e)); return
|
|
712
715
|
|
|
713
|
-
λ_min_str, ok1 = QInputDialog.getText(self, "λ_min", "Enter λ_min (in nm):")
|
|
714
|
-
λ_max_str, ok2 = QInputDialog.getText(self, "λ_max", "Enter λ_max (in nm):")
|
|
716
|
+
λ_min_str, ok1 = QInputDialog.getText(self, self.tr("λ_min"), self.tr("Enter λ_min (in nm):"))
|
|
717
|
+
λ_max_str, ok2 = QInputDialog.getText(self, self.tr("λ_max"), self.tr("Enter λ_max (in nm):"))
|
|
715
718
|
if not (ok1 and ok2 and λ_min_str.strip() and λ_max_str.strip()): return
|
|
716
719
|
try:
|
|
717
720
|
λ_min = float(λ_min_str); λ_max = float(λ_max_str)
|
|
718
721
|
except ValueError:
|
|
719
|
-
QMessageBox.critical(self, "Input Error", "λ_min and λ_max must be numbers."); return
|
|
722
|
+
QMessageBox.critical(self, self.tr("Input Error"), self.tr("λ_min and λ_max must be numbers.")); return
|
|
720
723
|
|
|
721
724
|
ok, extname_base, channel_val = self._query_name_channel()
|
|
722
725
|
if not ok: return
|
|
@@ -725,7 +728,7 @@ class SFCCDialog(QDialog):
|
|
|
725
728
|
try:
|
|
726
729
|
df_curve = self.extract_curve(gray_img, px_to_λ, py_to_resp, λ_min, λ_max, threshold=50)
|
|
727
730
|
except Exception as e:
|
|
728
|
-
QMessageBox.critical(self, "Extraction Error", str(e)); return
|
|
731
|
+
QMessageBox.critical(self, self.tr("Extraction Error"), str(e)); return
|
|
729
732
|
|
|
730
733
|
df_curve["wl_int"] = df_curve["wavelength_nm"].round().astype(int)
|
|
731
734
|
grp = (df_curve.groupby("wl_int")["response"].median().reset_index().sort_values("wl_int"))
|
|
@@ -734,21 +737,21 @@ class SFCCDialog(QDialog):
|
|
|
734
737
|
try:
|
|
735
738
|
tr_corr, _ = self.interpolate_bad_points(wl, tr)
|
|
736
739
|
except Exception as e:
|
|
737
|
-
QMessageBox.critical(self, "Interpolation Error", str(e)); return
|
|
740
|
+
QMessageBox.critical(self, self.tr("Interpolation Error"), str(e)); return
|
|
738
741
|
|
|
739
742
|
tr_smoothed = self.smooth_curve(tr_corr, window_size=5)
|
|
740
743
|
wl_ang = (wl.astype(float) * 10.0).astype(np.float32); tr_final = tr_smoothed.astype(np.float32)
|
|
741
744
|
self._append_curve_hdu(wl_ang, tr_final, extname_base, "SENSOR" if channel_val=="Q" else "FILTER", f"UserDefined:{img_filename}")
|
|
742
745
|
self._reload_hdu_lists(); self.refresh_filter_sensor_lists()
|
|
743
|
-
QMessageBox.information(self, "Done",
|
|
746
|
+
QMessageBox.information(self, self.tr("Done"), self.tr("Added curve '{0}'.").format(extname_base))
|
|
744
747
|
|
|
745
748
|
def remove_custom_curve(self):
|
|
746
749
|
all_curves = self.filter_list + self.sensor_list
|
|
747
750
|
if not all_curves:
|
|
748
|
-
QMessageBox.information(self, "Remove Curve", "No custom curves to remove."); return
|
|
749
|
-
curve, ok = QInputDialog.getItem(self, "Remove Curve", "Select a FILTER or SENSOR curve to delete:", all_curves, 0, False)
|
|
751
|
+
QMessageBox.information(self, self.tr("Remove Curve"), self.tr("No custom curves to remove.")); return
|
|
752
|
+
curve, ok = QInputDialog.getItem(self, self.tr("Remove Curve"), self.tr("Select a FILTER or SENSOR curve to delete:"), all_curves, 0, False)
|
|
750
753
|
if not ok or not curve: return
|
|
751
|
-
reply = QMessageBox.question(self, "Confirm Deletion",
|
|
754
|
+
reply = QMessageBox.question(self, self.tr("Confirm Deletion"), self.tr("Delete '{0}'?").format(curve), QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
|
752
755
|
if reply != QMessageBox.StandardButton.Yes: return
|
|
753
756
|
|
|
754
757
|
temp_path = self.user_custom_path + ".tmp"
|
|
@@ -768,7 +771,7 @@ class SFCCDialog(QDialog):
|
|
|
768
771
|
QMessageBox.critical(self, "Write Error", f"Could not remove curve:\n{e}"); return
|
|
769
772
|
|
|
770
773
|
self._reload_hdu_lists(); self.refresh_filter_sensor_lists()
|
|
771
|
-
QMessageBox.information(self, "Removed",
|
|
774
|
+
QMessageBox.information(self, self.tr("Removed"), self.tr("Deleted curve '{0}'.").format(curve))
|
|
772
775
|
|
|
773
776
|
def refresh_filter_sensor_lists(self):
|
|
774
777
|
self._reload_hdu_lists()
|
|
@@ -1155,18 +1158,56 @@ class SFCCDialog(QDialog):
|
|
|
1155
1158
|
diag_meas_BG, diag_exp_BG = [], []
|
|
1156
1159
|
enriched = []
|
|
1157
1160
|
|
|
1161
|
+
# --- Optimization: Pre-calculate integrals for unique templates ---
|
|
1162
|
+
unique_simbad_types = set(m["template"] for m in raw_matches)
|
|
1163
|
+
|
|
1164
|
+
# Map simbad_type -> pickles_template_name
|
|
1165
|
+
simbad_to_pickles = {}
|
|
1166
|
+
pickles_templates_needed = set()
|
|
1167
|
+
|
|
1168
|
+
for sp in unique_simbad_types:
|
|
1169
|
+
cands = pickles_match_for_simbad(sp, getattr(self, "pickles_templates", []))
|
|
1170
|
+
if cands:
|
|
1171
|
+
pickles_name = cands[0]
|
|
1172
|
+
simbad_to_pickles[sp] = pickles_name
|
|
1173
|
+
pickles_templates_needed.add(pickles_name)
|
|
1174
|
+
|
|
1175
|
+
# Pre-calc integrals for each unique Pickles template
|
|
1176
|
+
# Cache structure: template_name -> (S_sr, S_sg, S_sb)
|
|
1177
|
+
template_integrals = {}
|
|
1178
|
+
|
|
1179
|
+
# Cache for load_sed to avoid re-reading even across different calls if desired,
|
|
1180
|
+
# but here we just optimize the loop.
|
|
1181
|
+
|
|
1182
|
+
for pname in pickles_templates_needed:
|
|
1183
|
+
try:
|
|
1184
|
+
wl_s, fl_s = load_sed(pname)
|
|
1185
|
+
fs_i = np.interp(wl_grid, wl_s, fl_s, left=0., right=0.)
|
|
1186
|
+
|
|
1187
|
+
S_sr = np.trapezoid(fs_i * T_sys_R, x=wl_grid)
|
|
1188
|
+
S_sg = np.trapezoid(fs_i * T_sys_G, x=wl_grid)
|
|
1189
|
+
S_sb = np.trapezoid(fs_i * T_sys_B, x=wl_grid)
|
|
1190
|
+
|
|
1191
|
+
template_integrals[pname] = (S_sr, S_sg, S_sb)
|
|
1192
|
+
except Exception as e:
|
|
1193
|
+
print(f"[SFCC] Warning: failed to load/integrate template {pname}: {e}")
|
|
1194
|
+
|
|
1195
|
+
# --- Main Match Loop ---
|
|
1158
1196
|
for m in raw_matches:
|
|
1159
1197
|
xi, yi, sp = m["x_pix"], m["y_pix"], m["template"]
|
|
1160
1198
|
Rm = float(base[yi, xi, 0]); Gm = float(base[yi, xi, 1]); Bm = float(base[yi, xi, 2])
|
|
1161
1199
|
if Gm <= 0: continue
|
|
1162
1200
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1201
|
+
# 1. Resolve Simbad -> Pickles
|
|
1202
|
+
pname = simbad_to_pickles.get(sp)
|
|
1203
|
+
if not pname: continue
|
|
1204
|
+
|
|
1205
|
+
# 2. Retrieve pre-calced integrals
|
|
1206
|
+
integrals = template_integrals.get(pname)
|
|
1207
|
+
if not integrals: continue
|
|
1208
|
+
|
|
1209
|
+
S_sr, S_sg, S_sb = integrals
|
|
1210
|
+
|
|
1170
1211
|
if S_sg <= 0: continue
|
|
1171
1212
|
|
|
1172
1213
|
exp_RG = S_sr / S_sg; exp_BG = S_sb / S_sg
|
|
@@ -1180,7 +1221,8 @@ class SFCCDialog(QDialog):
|
|
|
1180
1221
|
"S_star_R": S_sr, "S_star_G": S_sg, "S_star_B": S_sb,
|
|
1181
1222
|
"exp_RG": exp_RG, "exp_BG": exp_BG
|
|
1182
1223
|
})
|
|
1183
|
-
|
|
1224
|
+
|
|
1225
|
+
self._last_matched = enriched
|
|
1184
1226
|
diag_meas_RG = np.array(diag_meas_RG); diag_exp_RG = np.array(diag_exp_RG)
|
|
1185
1227
|
diag_meas_BG = np.array(diag_meas_BG); diag_exp_BG = np.array(diag_exp_BG)
|
|
1186
1228
|
if diag_meas_RG.size == 0 or diag_meas_BG.size == 0:
|
|
@@ -1276,7 +1318,10 @@ class SFCCDialog(QDialog):
|
|
|
1276
1318
|
})
|
|
1277
1319
|
|
|
1278
1320
|
self.doc_manager.update_active_document(
|
|
1279
|
-
calibrated,
|
|
1321
|
+
calibrated,
|
|
1322
|
+
metadata=new_meta,
|
|
1323
|
+
step_name="SFCC Calibrated",
|
|
1324
|
+
doc=doc, # 👈 pin to the document we started from
|
|
1280
1325
|
)
|
|
1281
1326
|
|
|
1282
1327
|
self.count_label.setText(f"Applied SFCC color calibration using {n_stars} stars")
|
|
@@ -1384,8 +1429,10 @@ class SFCCDialog(QDialog):
|
|
|
1384
1429
|
new_meta["ColourGradRemoved"] = True
|
|
1385
1430
|
|
|
1386
1431
|
self.doc_manager.update_active_document(
|
|
1387
|
-
corrected,
|
|
1388
|
-
|
|
1432
|
+
corrected,
|
|
1433
|
+
metadata=new_meta,
|
|
1434
|
+
step_name="Colour-Gradient (star spectra, ¼-res fit)",
|
|
1435
|
+
doc=doc, # 👈 same idea
|
|
1389
1436
|
)
|
|
1390
1437
|
self.count_label.setText("Chromatic gradient removed ✓")
|
|
1391
1438
|
QApplication.processEvents()
|