setiastrosuitepro 1.6.1.post1__py3-none-any.whl → 1.6.4__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.

Potentially problematic release.


This version of setiastrosuitepro might be problematic. Click here for more details.

Files changed (139) hide show
  1. setiastro/images/Background_startup.jpg +0 -0
  2. setiastro/images/rotatearbitrary.png +0 -0
  3. setiastro/qml/ResourceMonitor.qml +126 -0
  4. setiastro/saspro/__main__.py +162 -25
  5. setiastro/saspro/_generated/build_info.py +2 -1
  6. setiastro/saspro/abe.py +62 -11
  7. setiastro/saspro/aberration_ai.py +3 -3
  8. setiastro/saspro/add_stars.py +5 -2
  9. setiastro/saspro/astrobin_exporter.py +3 -0
  10. setiastro/saspro/astrospike_python.py +3 -1
  11. setiastro/saspro/autostretch.py +4 -2
  12. setiastro/saspro/backgroundneutral.py +60 -9
  13. setiastro/saspro/batch_convert.py +3 -0
  14. setiastro/saspro/batch_renamer.py +3 -0
  15. setiastro/saspro/blemish_blaster.py +3 -0
  16. setiastro/saspro/blink_comparator_pro.py +474 -251
  17. setiastro/saspro/cheat_sheet.py +50 -15
  18. setiastro/saspro/clahe.py +27 -1
  19. setiastro/saspro/comet_stacking.py +103 -38
  20. setiastro/saspro/convo.py +3 -0
  21. setiastro/saspro/copyastro.py +3 -0
  22. setiastro/saspro/cosmicclarity.py +70 -45
  23. setiastro/saspro/crop_dialog_pro.py +28 -1
  24. setiastro/saspro/curve_editor_pro.py +18 -0
  25. setiastro/saspro/debayer.py +3 -0
  26. setiastro/saspro/doc_manager.py +40 -17
  27. setiastro/saspro/fitsmodifier.py +3 -0
  28. setiastro/saspro/frequency_separation.py +8 -2
  29. setiastro/saspro/function_bundle.py +18 -16
  30. setiastro/saspro/generate_translations.py +715 -1
  31. setiastro/saspro/ghs_dialog_pro.py +3 -0
  32. setiastro/saspro/graxpert.py +3 -0
  33. setiastro/saspro/gui/main_window.py +364 -92
  34. setiastro/saspro/gui/mixins/dock_mixin.py +119 -7
  35. setiastro/saspro/gui/mixins/file_mixin.py +7 -0
  36. setiastro/saspro/gui/mixins/geometry_mixin.py +105 -5
  37. setiastro/saspro/gui/mixins/menu_mixin.py +29 -0
  38. setiastro/saspro/gui/mixins/toolbar_mixin.py +33 -10
  39. setiastro/saspro/gui/statistics_dialog.py +47 -0
  40. setiastro/saspro/halobgon.py +29 -3
  41. setiastro/saspro/histogram.py +3 -0
  42. setiastro/saspro/history_explorer.py +2 -0
  43. setiastro/saspro/i18n.py +22 -10
  44. setiastro/saspro/image_combine.py +3 -0
  45. setiastro/saspro/image_peeker_pro.py +3 -0
  46. setiastro/saspro/imageops/stretch.py +5 -13
  47. setiastro/saspro/isophote.py +3 -0
  48. setiastro/saspro/legacy/numba_utils.py +64 -47
  49. setiastro/saspro/linear_fit.py +3 -0
  50. setiastro/saspro/live_stacking.py +13 -2
  51. setiastro/saspro/mask_creation.py +3 -0
  52. setiastro/saspro/mfdeconv.py +5 -0
  53. setiastro/saspro/morphology.py +30 -5
  54. setiastro/saspro/multiscale_decomp.py +713 -256
  55. setiastro/saspro/nbtorgb_stars.py +12 -2
  56. setiastro/saspro/numba_utils.py +148 -47
  57. setiastro/saspro/ops/scripts.py +77 -17
  58. setiastro/saspro/ops/settings.py +1 -43
  59. setiastro/saspro/perfect_palette_picker.py +1 -0
  60. setiastro/saspro/pixelmath.py +6 -2
  61. setiastro/saspro/plate_solver.py +1 -0
  62. setiastro/saspro/remove_green.py +18 -1
  63. setiastro/saspro/remove_stars.py +136 -162
  64. setiastro/saspro/remove_stars_preset.py +55 -13
  65. setiastro/saspro/resources.py +36 -10
  66. setiastro/saspro/rgb_combination.py +1 -0
  67. setiastro/saspro/rgbalign.py +4 -4
  68. setiastro/saspro/save_options.py +1 -0
  69. setiastro/saspro/selective_color.py +79 -20
  70. setiastro/saspro/sfcc.py +50 -8
  71. setiastro/saspro/shortcuts.py +94 -21
  72. setiastro/saspro/signature_insert.py +3 -0
  73. setiastro/saspro/stacking_suite.py +924 -446
  74. setiastro/saspro/star_alignment.py +291 -331
  75. setiastro/saspro/star_spikes.py +116 -32
  76. setiastro/saspro/star_stretch.py +38 -1
  77. setiastro/saspro/stat_stretch.py +35 -3
  78. setiastro/saspro/status_log_dock.py +1 -1
  79. setiastro/saspro/subwindow.py +63 -2
  80. setiastro/saspro/supernovaasteroidhunter.py +3 -0
  81. setiastro/saspro/swap_manager.py +77 -42
  82. setiastro/saspro/translations/all_source_strings.json +4726 -0
  83. setiastro/saspro/translations/ar_translations.py +4096 -0
  84. setiastro/saspro/translations/de_translations.py +441 -446
  85. setiastro/saspro/translations/es_translations.py +278 -32
  86. setiastro/saspro/translations/fr_translations.py +280 -32
  87. setiastro/saspro/translations/hi_translations.py +3803 -0
  88. setiastro/saspro/translations/integrate_translations.py +38 -1
  89. setiastro/saspro/translations/it_translations.py +1211 -145
  90. setiastro/saspro/translations/ja_translations.py +556 -307
  91. setiastro/saspro/translations/pt_translations.py +3316 -3322
  92. setiastro/saspro/translations/ru_translations.py +3082 -0
  93. setiastro/saspro/translations/saspro_ar.qm +0 -0
  94. setiastro/saspro/translations/saspro_ar.ts +16019 -0
  95. setiastro/saspro/translations/saspro_de.qm +0 -0
  96. setiastro/saspro/translations/saspro_de.ts +14428 -133
  97. setiastro/saspro/translations/saspro_es.qm +0 -0
  98. setiastro/saspro/translations/saspro_es.ts +11503 -7821
  99. setiastro/saspro/translations/saspro_fr.qm +0 -0
  100. setiastro/saspro/translations/saspro_fr.ts +11168 -7812
  101. setiastro/saspro/translations/saspro_hi.qm +0 -0
  102. setiastro/saspro/translations/saspro_hi.ts +14855 -0
  103. setiastro/saspro/translations/saspro_it.qm +0 -0
  104. setiastro/saspro/translations/saspro_it.ts +14347 -7821
  105. setiastro/saspro/translations/saspro_ja.qm +0 -0
  106. setiastro/saspro/translations/saspro_ja.ts +14860 -137
  107. setiastro/saspro/translations/saspro_pt.qm +0 -0
  108. setiastro/saspro/translations/saspro_pt.ts +14904 -137
  109. setiastro/saspro/translations/saspro_ru.qm +0 -0
  110. setiastro/saspro/translations/saspro_ru.ts +11835 -0
  111. setiastro/saspro/translations/saspro_sw.qm +0 -0
  112. setiastro/saspro/translations/saspro_sw.ts +15237 -0
  113. setiastro/saspro/translations/saspro_uk.qm +0 -0
  114. setiastro/saspro/translations/saspro_uk.ts +15248 -0
  115. setiastro/saspro/translations/saspro_zh.qm +0 -0
  116. setiastro/saspro/translations/saspro_zh.ts +10581 -7812
  117. setiastro/saspro/translations/sw_translations.py +3897 -0
  118. setiastro/saspro/translations/uk_translations.py +3929 -0
  119. setiastro/saspro/translations/zh_translations.py +283 -32
  120. setiastro/saspro/versioning.py +36 -5
  121. setiastro/saspro/view_bundle.py +20 -17
  122. setiastro/saspro/wavescale_hdr.py +22 -1
  123. setiastro/saspro/wavescalede.py +23 -1
  124. setiastro/saspro/whitebalance.py +39 -3
  125. setiastro/saspro/widgets/minigame/game.js +991 -0
  126. setiastro/saspro/widgets/minigame/index.html +53 -0
  127. setiastro/saspro/widgets/minigame/style.css +241 -0
  128. setiastro/saspro/widgets/resource_monitor.py +263 -0
  129. setiastro/saspro/widgets/spinboxes.py +18 -0
  130. setiastro/saspro/widgets/wavelet_utils.py +52 -20
  131. setiastro/saspro/wimi.py +100 -80
  132. setiastro/saspro/wims.py +33 -33
  133. setiastro/saspro/window_shelf.py +2 -2
  134. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/METADATA +15 -4
  135. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/RECORD +139 -115
  136. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/WHEEL +0 -0
  137. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/entry_points.txt +0 -0
  138. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/licenses/LICENSE +0 -0
  139. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/licenses/license.txt +0 -0
setiastro/saspro/wimi.py CHANGED
@@ -40,10 +40,9 @@ import io
40
40
  import re
41
41
  from collections import defaultdict
42
42
  from scipy.spatial import Delaunay, KDTree
43
- from scipy.ndimage import gaussian_filter, laplace
44
- import scipy.ndimage as ndi
45
- import plotly.graph_objects as go
46
- from scipy.ndimage import zoom
43
+ # from scipy.ndimage import gaussian_filter, laplace <-- Removed unused
44
+ # import scipy.ndimage as ndi <-- Removed unused
45
+ # from scipy.ndimage import zoom <-- Removed unused (replaced by cv2.resize)
47
46
  import multiprocessing
48
47
  import matplotlib
49
48
  matplotlib.use("QtAgg")
@@ -101,6 +100,7 @@ from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, as_compl
101
100
  from astropy.wcs.utils import skycoord_to_pixel
102
101
  from astropy.coordinates import SkyCoord
103
102
  from astropy import units as u
103
+ import plotly.graph_objects as go
104
104
 
105
105
  from astropy.io.fits import Header
106
106
  from pyvo.dal.exceptions import DALServiceError
@@ -139,9 +139,9 @@ from astropy.utils.data import conf
139
139
 
140
140
  from scipy.interpolate import PchipInterpolator
141
141
  from scipy.interpolate import Rbf
142
- from scipy.ndimage import median_filter
143
- from scipy.ndimage import convolve
144
- from scipy.signal import fftconvolve
142
+ # from scipy.ndimage import median_filter <-- Removed unused
143
+ # from scipy.ndimage import convolve <-- Removed unused
144
+ # from scipy.signal import fftconvolve <-- Removed unused
145
145
  from scipy.interpolate import interp1d
146
146
 
147
147
 
@@ -1949,7 +1949,8 @@ class CustomGraphicsView(QGraphicsView):
1949
1949
  self.parent.main_scene.addItem(rect_item)
1950
1950
  elif item[0] == 'line':
1951
1951
  line = item[1]
1952
- color = item[2]
1952
+ # Safely get color or default to green if missing
1953
+ color = item[2] if len(item) > 2 else QColor(0, 255, 0)
1953
1954
  line_item = QGraphicsLineItem(line)
1954
1955
  line_item.setPen(QPen(color, 2))
1955
1956
  self.parent.main_scene.addItem(line_item)
@@ -2595,12 +2596,12 @@ class WIMIDialog(QDialog):
2595
2596
  button_layout = QHBoxLayout()
2596
2597
 
2597
2598
  # Load button
2598
- self.load_button = QPushButton("Load Image File")
2599
+ self.load_button = QPushButton(self.tr("Load Image File"))
2599
2600
  self.load_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_FileDialogStart))
2600
2601
  self.load_button.clicked.connect(self.open_image)
2601
2602
 
2602
2603
  self.load_from_view_btn = QToolButton()
2603
- self.load_from_view_btn.setText("Load from View")
2604
+ self.load_from_view_btn.setText(self.tr("Load from View"))
2604
2605
  self.load_from_view_btn.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
2605
2606
  self.load_from_view_btn.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_DirOpenIcon))
2606
2607
  self.load_from_view_menu = QMenu(self)
@@ -2610,7 +2611,7 @@ class WIMIDialog(QDialog):
2610
2611
  button_layout.addWidget(self.load_from_view_btn)
2611
2612
 
2612
2613
  # AutoStretch button
2613
- self.auto_stretch_button = QPushButton("AutoStretch")
2614
+ self.auto_stretch_button = QPushButton(self.tr("AutoStretch"))
2614
2615
  self.auto_stretch_button.clicked.connect(self.toggle_autostretch)
2615
2616
 
2616
2617
  # Add both buttons to the horizontal layout
@@ -2621,7 +2622,7 @@ class WIMIDialog(QDialog):
2621
2622
  left_panel.addLayout(button_layout)
2622
2623
 
2623
2624
  # Create the instruction QLabel for search region
2624
- search_region_instruction_label = QLabel("Shift+Click to define a search region")
2625
+ search_region_instruction_label = QLabel(self.tr("Shift+Click to define a search region"))
2625
2626
  search_region_instruction_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
2626
2627
  search_region_instruction_label.setStyleSheet("font-size: 15px; color: gray;")
2627
2628
 
@@ -2631,12 +2632,12 @@ class WIMIDialog(QDialog):
2631
2632
 
2632
2633
 
2633
2634
  # Query Simbad button
2634
- self.query_button = QPushButton("Query Simbad")
2635
+ self.query_button = QPushButton(self.tr("Query Simbad"))
2635
2636
  self.query_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_DialogApplyButton))
2636
2637
  left_panel.addWidget(self.query_button)
2637
2638
  self.query_button.clicked.connect(lambda: self.query_simbad(self.get_defined_radius()))
2638
2639
 
2639
- self.legend_button = QPushButton("Legend")
2640
+ self.legend_button = QPushButton(self.tr("Legend"))
2640
2641
  self.legend_button.clicked.connect(self.show_legend)
2641
2642
  left_panel.addWidget(self.legend_button)
2642
2643
 
@@ -2644,12 +2645,12 @@ class WIMIDialog(QDialog):
2644
2645
  show_clear_layout = QHBoxLayout()
2645
2646
 
2646
2647
  # Create the Show Object Names checkbox
2647
- self.show_names_checkbox = QCheckBox("Show Object Names")
2648
+ self.show_names_checkbox = QCheckBox(self.tr("Show Object Names"))
2648
2649
  self.show_names_checkbox.stateChanged.connect(self.toggle_object_names) # Connect to a function to toggle names
2649
2650
  show_clear_layout.addWidget(self.show_names_checkbox)
2650
2651
 
2651
2652
  # Create the Clear Results button
2652
- self.clear_results_button = QPushButton("Clear Results")
2653
+ self.clear_results_button = QPushButton(self.tr("Clear Results"))
2653
2654
  self.clear_results_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_DialogCloseButton))
2654
2655
  self.clear_results_button.clicked.connect(self.clear_search_results) # Connect to a function to clear results
2655
2656
  show_clear_layout.addWidget(self.clear_results_button)
@@ -2661,7 +2662,7 @@ class WIMIDialog(QDialog):
2661
2662
  button_layout = QHBoxLayout()
2662
2663
 
2663
2664
  # Show Visible Objects Only button
2664
- self.toggle_visible_objects_button = QPushButton("Show Visible Objects Only")
2665
+ self.toggle_visible_objects_button = QPushButton(self.tr("Show Visible Objects Only"))
2665
2666
  self.toggle_visible_objects_button.setCheckable(True) # Toggle button state
2666
2667
  self.toggle_visible_objects_button.setIcon(QIcon(eye_icon_path))
2667
2668
  self.toggle_visible_objects_button.clicked.connect(self.filter_visible_objects)
@@ -2669,7 +2670,7 @@ class WIMIDialog(QDialog):
2669
2670
  button_layout.addWidget(self.toggle_visible_objects_button)
2670
2671
 
2671
2672
  # Save CSV button
2672
- self.save_csv_button = QPushButton("Save CSV")
2673
+ self.save_csv_button = QPushButton(self.tr("Save CSV"))
2673
2674
  self.save_csv_button.setIcon(QIcon(csv_icon_path))
2674
2675
  self.save_csv_button.clicked.connect(self.save_results_as_csv)
2675
2676
  button_layout.addWidget(self.save_csv_button)
@@ -2678,7 +2679,7 @@ class WIMIDialog(QDialog):
2678
2679
  left_panel.addLayout(button_layout)
2679
2680
 
2680
2681
  # Advanced Search Button
2681
- self.advanced_search_button = QPushButton("Advanced Search")
2682
+ self.advanced_search_button = QPushButton(self.tr("Advanced Search"))
2682
2683
  self.advanced_search_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_FileDialogDetailedView))
2683
2684
  self.advanced_search_button.setCheckable(True)
2684
2685
  self.advanced_search_button.clicked.connect(self.toggle_advanced_search)
@@ -2692,14 +2693,14 @@ class WIMIDialog(QDialog):
2692
2693
  self.advanced_search_panel_widget.setVisible(False) # Hide initially
2693
2694
 
2694
2695
  # Status label
2695
- self.status_label = QLabel("Status: Ready")
2696
+ self.status_label = QLabel(self.tr("Status: Ready"))
2696
2697
  left_panel.addWidget(self.status_label)
2697
2698
 
2698
2699
  # Create a horizontal layout
2699
2700
  button_layout = QHBoxLayout()
2700
2701
 
2701
2702
  # Copy RA/Dec to Clipboard button
2702
- self.copy_button = QPushButton("Copy RA/Dec to Clipboard", self)
2703
+ self.copy_button = QPushButton(self.tr("Copy RA/Dec to Clipboard"), self)
2703
2704
  self.copy_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_CommandLink))
2704
2705
  self.copy_button.clicked.connect(self.copy_ra_dec_to_clipboard)
2705
2706
  button_layout.addWidget(self.copy_button)
@@ -2714,23 +2715,23 @@ class WIMIDialog(QDialog):
2714
2715
  left_panel.addLayout(button_layout)
2715
2716
 
2716
2717
  # Save Plate Solved Fits Button
2717
- self.save_plate_solved_button = QPushButton("Save Plate Solved Fits")
2718
+ self.save_plate_solved_button = QPushButton(self.tr("Save Plate Solved Fits"))
2718
2719
  self.save_plate_solved_button.setIcon(QIcon(disk_icon_path))
2719
2720
  self.save_plate_solved_button.clicked.connect(self.save_plate_solved_fits)
2720
2721
  left_panel.addWidget(self.save_plate_solved_button)
2721
2722
 
2722
2723
  # RA/Dec Labels
2723
2724
  ra_dec_layout = QHBoxLayout()
2724
- self.ra_label = QLabel("RA: N/A")
2725
- self.dec_label = QLabel("Dec: N/A")
2726
- self.orientation_label = QLabel("Orientation: N/A°")
2725
+ self.ra_label = QLabel(self.tr("RA: N/A"))
2726
+ self.dec_label = QLabel(self.tr("Dec: N/A"))
2727
+ self.orientation_label = QLabel(self.tr("Orientation: N/A°"))
2727
2728
  ra_dec_layout.addWidget(self.ra_label)
2728
2729
  ra_dec_layout.addWidget(self.dec_label)
2729
2730
  ra_dec_layout.addWidget(self.orientation_label)
2730
2731
  left_panel.addLayout(ra_dec_layout)
2731
2732
 
2732
2733
  # Mini Preview
2733
- self.mini_preview = QLabel("Mini Preview")
2734
+ self.mini_preview = QLabel(self.tr("Mini Preview"))
2734
2735
  self.mini_preview.setMaximumSize(300, 300)
2735
2736
  self.mini_preview.mousePressEvent = self.on_mini_preview_press
2736
2737
  self.mini_preview.mouseMoveEvent = self.on_mini_preview_drag
@@ -2745,9 +2746,9 @@ class WIMIDialog(QDialog):
2745
2746
 
2746
2747
  # Zoom buttons above the main preview
2747
2748
  zoom_controls_layout = QHBoxLayout()
2748
- self.zoom_in_button = QPushButton("Zoom In")
2749
+ self.zoom_in_button = QPushButton(self.tr("Zoom In"))
2749
2750
  self.zoom_in_button.clicked.connect(self.zoom_in)
2750
- self.zoom_out_button = QPushButton("Zoom Out")
2751
+ self.zoom_out_button = QPushButton(self.tr("Zoom Out"))
2751
2752
  self.zoom_out_button.clicked.connect(self.zoom_out)
2752
2753
  zoom_controls_layout.addWidget(self.zoom_in_button)
2753
2754
  zoom_controls_layout.addWidget(self.zoom_out_button)
@@ -2782,28 +2783,28 @@ class WIMIDialog(QDialog):
2782
2783
  save_buttons_layout = QHBoxLayout()
2783
2784
 
2784
2785
  # Button to toggle annotation tools section
2785
- self.show_annotations_button = QPushButton("Show Annotation Tools")
2786
+ self.show_annotations_button = QPushButton(self.tr("Show Annotation Tools"))
2786
2787
  self.show_annotations_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_DialogResetButton))
2787
2788
  self.show_annotations_button.clicked.connect(self.toggle_annotation_tools)
2788
2789
  save_buttons_layout.addWidget(self.show_annotations_button)
2789
2790
 
2790
- self.save_annotated_button = QPushButton("Save Annotated Image")
2791
+ self.save_annotated_button = QPushButton(self.tr("Save Annotated Image"))
2791
2792
  self.save_annotated_button.setIcon(QIcon(annotated_path))
2792
2793
  self.save_annotated_button.clicked.connect(self.save_annotated_image)
2793
2794
  save_buttons_layout.addWidget(self.save_annotated_button)
2794
2795
 
2795
- self.save_collage_button = QPushButton("Save Collage of Objects")
2796
+ self.save_collage_button = QPushButton(self.tr("Save Collage of Objects"))
2796
2797
  self.save_collage_button.setIcon(QIcon(collage_path))
2797
2798
  self.save_collage_button.clicked.connect(self.save_collage_of_objects)
2798
2799
  save_buttons_layout.addWidget(self.save_collage_button)
2799
2800
 
2800
2801
  # New 3D View Button
2801
- self.show_3d_view_button = QPushButton("3D Distance Model")
2802
+ self.show_3d_view_button = QPushButton(self.tr("3D Distance Model"))
2802
2803
  self.show_3d_view_button.clicked.connect(self.show_3d_model_view)
2803
2804
  self.show_3d_view_button.setIcon( QApplication.style().standardIcon(QStyle.StandardPixmap.SP_TitleBarNormalButton))
2804
2805
  save_buttons_layout.addWidget(self.show_3d_view_button)
2805
2806
 
2806
- self.show_hr_button = QPushButton("H-R Diagram")
2807
+ self.show_hr_button = QPushButton(self.tr("H-R Diagram"))
2807
2808
  # Optionally give it an icon:
2808
2809
  self.show_hr_button.setIcon(QApplication.style().standardIcon(
2809
2810
  QStyle.StandardPixmap.SP_DesktopIcon))
@@ -2820,10 +2821,10 @@ class WIMIDialog(QDialog):
2820
2821
  label_layout = QHBoxLayout()
2821
2822
 
2822
2823
  # Create the label to display the count of objects
2823
- self.object_count_label = QLabel("Objects Found: 0")
2824
+ self.object_count_label = QLabel(self.tr("Objects Found: 0"))
2824
2825
 
2825
2826
  # Create the label with instructions
2826
- self.instructions_label = QLabel("Right Click a Row for More Options")
2827
+ self.instructions_label = QLabel(self.tr("Right Click a Row for More Options"))
2827
2828
 
2828
2829
  # Add both labels to the horizontal layout
2829
2830
  label_layout.addWidget(self.object_count_label)
@@ -2849,61 +2850,61 @@ class WIMIDialog(QDialog):
2849
2850
  self.annotation_tools_section = QWidget()
2850
2851
  annotation_tools_layout = QGridLayout(self.annotation_tools_section)
2851
2852
 
2852
- annotation_instruction_label = QLabel("Ctrl+Click to add items, Alt+Click to measure distance")
2853
+ annotation_instruction_label = QLabel(self.tr("Ctrl+Click to add items, Alt+Click to measure distance"))
2853
2854
  annotation_instruction_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
2854
2855
  annotation_instruction_label.setStyleSheet("font-size: 10px; color: gray;")
2855
2856
 
2856
- self.draw_ellipse_button = QPushButton("Draw Ellipse")
2857
+ self.draw_ellipse_button = QPushButton(self.tr("Draw Ellipse"))
2857
2858
  self.draw_ellipse_button.tool_name = "Ellipse"
2858
2859
  self.draw_ellipse_button.clicked.connect(lambda: self.set_tool("Ellipse"))
2859
2860
  self.annotation_buttons.append(self.draw_ellipse_button)
2860
2861
 
2861
- self.freehand_button = QPushButton("Freehand (Lasso)")
2862
+ self.freehand_button = QPushButton(self.tr("Freehand (Lasso)"))
2862
2863
  self.freehand_button.tool_name = "Freehand"
2863
2864
  self.freehand_button.clicked.connect(lambda: self.set_tool("Freehand"))
2864
2865
  self.annotation_buttons.append(self.freehand_button)
2865
2866
 
2866
- self.draw_rectangle_button = QPushButton("Draw Rectangle")
2867
+ self.draw_rectangle_button = QPushButton(self.tr("Draw Rectangle"))
2867
2868
  self.draw_rectangle_button.tool_name = "Rectangle"
2868
2869
  self.draw_rectangle_button.clicked.connect(lambda: self.set_tool("Rectangle"))
2869
2870
  self.annotation_buttons.append(self.draw_rectangle_button)
2870
2871
 
2871
- self.draw_arrow_button = QPushButton("Draw Arrow")
2872
+ self.draw_arrow_button = QPushButton(self.tr("Draw Arrow"))
2872
2873
  self.draw_arrow_button.tool_name = "Arrow"
2873
2874
  self.draw_arrow_button.clicked.connect(lambda: self.set_tool("Arrow"))
2874
2875
  self.annotation_buttons.append(self.draw_arrow_button)
2875
2876
 
2876
- self.place_compass_button = QPushButton("Place Celestial Compass")
2877
+ self.place_compass_button = QPushButton(self.tr("Place Celestial Compass"))
2877
2878
  self.place_compass_button.tool_name = "Compass"
2878
2879
  self.place_compass_button.clicked.connect(lambda: self.set_tool("Compass"))
2879
2880
  self.annotation_buttons.append(self.place_compass_button)
2880
2881
 
2881
- self.add_text_button = QPushButton("Add Text")
2882
+ self.add_text_button = QPushButton(self.tr("Add Text"))
2882
2883
  self.add_text_button.tool_name = "Text"
2883
2884
  self.add_text_button.clicked.connect(lambda: self.set_tool("Text"))
2884
2885
  self.annotation_buttons.append(self.add_text_button)
2885
2886
 
2886
2887
  # Add Color and Font buttons
2887
- self.color_button = QPushButton("Select Color")
2888
+ self.color_button = QPushButton(self.tr("Select Color"))
2888
2889
  self.color_button.setIcon(QIcon(colorwheel_path))
2889
2890
  self.color_button.clicked.connect(self.select_color)
2890
2891
 
2891
- self.font_button = QPushButton("Select Font")
2892
+ self.font_button = QPushButton(self.tr("Select Font"))
2892
2893
  self.font_button.setIcon(QIcon(font_path))
2893
2894
  self.font_button.clicked.connect(self.select_font)
2894
2895
 
2895
2896
  # Undo button
2896
- self.undo_button = QPushButton("Undo")
2897
+ self.undo_button = QPushButton(self.tr("Undo"))
2897
2898
  self.undo_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_ArrowLeft)) # Left arrow icon for undo
2898
2899
  self.undo_button.clicked.connect(self.main_preview.undo_annotation) # Connect to undo_annotation in CustomGraphicsView
2899
2900
 
2900
2901
  # Clear Annotations button
2901
- self.clear_annotations_button = QPushButton("Clear Annotations")
2902
+ self.clear_annotations_button = QPushButton(self.tr("Clear Annotations"))
2902
2903
  self.clear_annotations_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_TrashIcon)) # Trash icon
2903
2904
  self.clear_annotations_button.clicked.connect(self.main_preview.clear_annotations) # Connect to clear_annotations in CustomGraphicsView
2904
2905
 
2905
2906
  # Delete Selected Object button
2906
- self.delete_selected_object_button = QPushButton("Delete Selected Object(s)")
2907
+ self.delete_selected_object_button = QPushButton(self.tr("Delete Selected Items"))
2907
2908
  self.delete_selected_object_button.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_DialogCloseButton)) # Trash icon
2908
2909
  self.delete_selected_object_button.clicked.connect(self.main_preview.delete_selected_objects)
2909
2910
 
@@ -2927,12 +2928,12 @@ class WIMIDialog(QDialog):
2927
2928
  right_panel.addWidget(self.annotation_tools_section)
2928
2929
 
2929
2930
  # Advanced Search Panel
2930
- self.advanced_param_label = QLabel("Advanced Search Parameters")
2931
+ self.advanced_param_label = QLabel(self.tr("Advanced Search Parameters"))
2931
2932
  self.advanced_search_panel.addWidget(self.advanced_param_label)
2932
2933
 
2933
2934
  # TreeWidget for object types
2934
2935
  self.object_tree = QTreeWidget()
2935
- self.object_tree.setHeaderLabels(["Object Type", "Description"])
2936
+ self.object_tree.setHeaderLabels([self.tr("Object Type"), self.tr("Description")])
2936
2937
  self.object_tree.setColumnWidth(0, 150)
2937
2938
  self.object_tree.setSortingEnabled(True)
2938
2939
 
@@ -2948,17 +2949,17 @@ class WIMIDialog(QDialog):
2948
2949
  toggle_buttons_layout = QHBoxLayout()
2949
2950
 
2950
2951
  # Toggle All
2951
- self.toggle_all_button = QPushButton("Toggle All")
2952
+ self.toggle_all_button = QPushButton(self.tr("Toggle All"))
2952
2953
  self.toggle_all_button.clicked.connect(self.toggle_all_items)
2953
2954
  toggle_buttons_layout.addWidget(self.toggle_all_button)
2954
2955
 
2955
2956
  # Save Custom List
2956
- self.save_list_button = QPushButton("Save List…")
2957
+ self.save_list_button = QPushButton(self.tr("Save List…"))
2957
2958
  self.save_list_button.clicked.connect(self.save_custom_list)
2958
2959
  toggle_buttons_layout.addWidget(self.save_list_button)
2959
2960
 
2960
2961
  # Load Custom List
2961
- self.load_list_button = QPushButton("Load List…")
2962
+ self.load_list_button = QPushButton(self.tr("Load List…"))
2962
2963
  self.load_list_button.clicked.connect(self.load_custom_list)
2963
2964
  toggle_buttons_layout.addWidget(self.load_list_button)
2964
2965
 
@@ -2967,11 +2968,11 @@ class WIMIDialog(QDialog):
2967
2968
  # Add Simbad Search buttons below the toggle buttons
2968
2969
  search_button_layout = QHBoxLayout()
2969
2970
 
2970
- self.simbad_defined_region_button = QPushButton("Search Defined Region")
2971
+ self.simbad_defined_region_button = QPushButton(self.tr("Search Defined Region"))
2971
2972
  self.simbad_defined_region_button.clicked.connect(self.search_defined_region)
2972
2973
  search_button_layout.addWidget(self.simbad_defined_region_button)
2973
2974
 
2974
- self.simbad_entire_image_button = QPushButton("Search Entire Image")
2975
+ self.simbad_entire_image_button = QPushButton(self.tr("Search Entire Image"))
2975
2976
  self.simbad_entire_image_button.clicked.connect(self.search_entire_image)
2976
2977
  search_button_layout.addWidget(self.simbad_entire_image_button)
2977
2978
 
@@ -2980,17 +2981,17 @@ class WIMIDialog(QDialog):
2980
2981
  # ─────────────────────────────
2981
2982
  # Minor Planets / Comets block
2982
2983
  # ─────────────────────────────
2983
- self.minor_group = QGroupBox("Minor Planets / Comets")
2984
+ self.minor_group = QGroupBox(self.tr("Minor Planets / Comets"))
2984
2985
  minor_layout = QGridLayout(self.minor_group)
2985
2986
 
2986
2987
  # --- DB info + buttons ---
2987
- self.minor_db_label = QLabel("Database: not downloaded")
2988
+ self.minor_db_label = QLabel(self.tr("Database: not downloaded"))
2988
2989
  self.minor_db_label.setStyleSheet("font-size: 10px; color: gray;")
2989
2990
 
2990
- self.btn_minor_download = QPushButton("Download Catalog")
2991
+ self.btn_minor_download = QPushButton(self.tr("Download Catalog"))
2991
2992
  self.btn_minor_download.clicked.connect(self.download_minor_body_catalog)
2992
2993
 
2993
- self.btn_minor_search = QPushButton("Search Minor Bodies")
2994
+ self.btn_minor_search = QPushButton(self.tr("Search Minor Bodies"))
2994
2995
  self.btn_minor_search.clicked.connect(self.perform_minor_body_search)
2995
2996
 
2996
2997
  # Row 0: status label across full width
@@ -3001,18 +3002,18 @@ class WIMIDialog(QDialog):
3001
3002
  minor_layout.addWidget(self.btn_minor_search, 1, 2, 1, 2)
3002
3003
 
3003
3004
  # --- Search scope (Defined Circle vs Entire Image) ---
3004
- scope_label = QLabel("Search scope:")
3005
+ scope_label = QLabel(self.tr("Search scope:"))
3005
3006
  self.minor_scope_combo = QComboBox()
3006
3007
  self.minor_scope_combo.addItems([
3007
- "Defined Region",
3008
- "Entire Image",
3008
+ self.tr("Defined Region"),
3009
+ self.tr("Entire Image"),
3009
3010
  ])
3010
3011
 
3011
3012
  minor_layout.addWidget(scope_label, 2, 0)
3012
3013
  minor_layout.addWidget(self.minor_scope_combo, 2, 1, 1, 3)
3013
3014
 
3014
3015
  # --- Limits row 1: asteroid H_max + max count ---
3015
- ast_H_label = QLabel("Asteroid H \u2264")
3016
+ ast_H_label = QLabel(self.tr("Asteroid H \u2264"))
3016
3017
  self.minor_ast_H_spin = QDoubleSpinBox()
3017
3018
  self.minor_ast_H_spin.setRange(0.0, 40.0)
3018
3019
  self.minor_ast_H_spin.setDecimals(1)
@@ -3021,7 +3022,7 @@ class WIMIDialog(QDialog):
3021
3022
  float(self.settings.value("wimi/minor/asteroid_H_max", 20.0))
3022
3023
  )
3023
3024
 
3024
- ast_max_label = QLabel("Max asteroids:")
3025
+ ast_max_label = QLabel(self.tr("Max asteroids:"))
3025
3026
  self.minor_ast_max_spin = QSpinBox()
3026
3027
  self.minor_ast_max_spin.setRange(100, 2000000)
3027
3028
  self.minor_ast_max_spin.setSingleStep(1000)
@@ -3035,7 +3036,7 @@ class WIMIDialog(QDialog):
3035
3036
  minor_layout.addWidget(self.minor_ast_max_spin, 3, 3)
3036
3037
 
3037
3038
  # --- Limits row 2: comet H_max + max count ---
3038
- com_H_label = QLabel("Comet H \u2264")
3039
+ com_H_label = QLabel(self.tr("Comet H \u2264"))
3039
3040
  self.minor_com_H_spin = QDoubleSpinBox()
3040
3041
  self.minor_com_H_spin.setRange(0.0, 40.0)
3041
3042
  self.minor_com_H_spin.setDecimals(1)
@@ -3044,7 +3045,7 @@ class WIMIDialog(QDialog):
3044
3045
  float(self.settings.value("wimi/minor/comet_H_max", 15.0))
3045
3046
  )
3046
3047
 
3047
- com_max_label = QLabel("Max comets:")
3048
+ com_max_label = QLabel(self.tr("Max comets:"))
3048
3049
  self.minor_com_max_spin = QSpinBox()
3049
3050
  self.minor_com_max_spin.setRange(100, 100000)
3050
3051
  self.minor_com_max_spin.setSingleStep(500)
@@ -3058,14 +3059,14 @@ class WIMIDialog(QDialog):
3058
3059
  minor_layout.addWidget(self.minor_com_max_spin, 4, 3)
3059
3060
 
3060
3061
  # --- Optional specific target (designation / name) ---
3061
- target_label = QLabel("Target (optional):")
3062
+ target_label = QLabel(self.tr("Target (optional):"))
3062
3063
  self.minor_target_edit = QLineEdit()
3063
3064
  self.minor_target_edit.setPlaceholderText("e.g. 584, Semiramis, C/2023 A3...")
3064
3065
 
3065
3066
  minor_layout.addWidget(target_label, 5, 0)
3066
3067
  minor_layout.addWidget(self.minor_target_edit, 5, 1, 1, 3)
3067
3068
 
3068
- self.minor_count_button = QPushButton("Count Objects Brighter Than Limits")
3069
+ self.minor_count_button = QPushButton(self.tr("Count Objects Brighter Than Limits"))
3069
3070
  self.minor_count_button.setToolTip(
3070
3071
  "Show how many catalog objects are brighter than the selected H limits."
3071
3072
  )
@@ -3074,7 +3075,7 @@ class WIMIDialog(QDialog):
3074
3075
  minor_layout.addWidget(self.minor_count_button, 6, 0, 1, 4)
3075
3076
 
3076
3077
  # --- Time offset (hours) for ephemerides ---
3077
- time_offset_label = QLabel("Time offset (hours):")
3078
+ time_offset_label = QLabel(self.tr("Time offset (hours):"))
3078
3079
  self.minor_time_offset_spin = QDoubleSpinBox()
3079
3080
  self.minor_time_offset_spin.setRange(-24.0, 24.0)
3080
3081
  self.minor_time_offset_spin.setDecimals(2)
@@ -3098,7 +3099,7 @@ class WIMIDialog(QDialog):
3098
3099
  self._load_minor_db_path()
3099
3100
 
3100
3101
  # Adding the "Deep Vizier Search" button below the other search buttons
3101
- self.deep_vizier_button = QPushButton("Caution - Deep Vizier Search")
3102
+ self.deep_vizier_button = QPushButton(self.tr("Caution - Deep Vizier Search"))
3102
3103
  self.deep_vizier_button.setIcon(QIcon(nuke_path)) # Assuming `nuke_path` is the correct path for the icon
3103
3104
  self.deep_vizier_button.setToolTip("Perform a deep search with Vizier. Caution: May return large datasets.")
3104
3105
 
@@ -3108,7 +3109,7 @@ class WIMIDialog(QDialog):
3108
3109
  # Add the Deep Vizier button to the advanced search layout
3109
3110
  self.advanced_search_panel.addWidget(self.deep_vizier_button)
3110
3111
 
3111
- self.mast_search_button = QPushButton("Search M.A.S.T Database")
3112
+ self.mast_search_button = QPushButton(self.tr("Search M.A.S.T Database"))
3112
3113
  self.mast_search_button.setIcon(QIcon(hubble_path))
3113
3114
  self.mast_search_button.clicked.connect(self.perform_mast_search)
3114
3115
  self.mast_search_button.setToolTip("Search Hubble, JWST, Spitzer, TESS and More.")
@@ -3603,15 +3604,15 @@ class WIMIDialog(QDialog):
3603
3604
  menu = QMenu(self)
3604
3605
 
3605
3606
  # Define actions
3606
- open_website_action = QAction("Open Website", self)
3607
+ open_website_action = QAction(self.tr("Open Website"), self)
3607
3608
  open_website_action.triggered.connect(lambda: self.results_tree.itemDoubleClicked.emit(item, 0))
3608
3609
  menu.addAction(open_website_action)
3609
3610
 
3610
- zoom_to_object_action = QAction("Zoom to Object", self)
3611
+ zoom_to_object_action = QAction(self.tr("Zoom to Object"), self)
3611
3612
  zoom_to_object_action.triggered.connect(lambda: self.zoom_to_object(item))
3612
3613
  menu.addAction(zoom_to_object_action)
3613
3614
 
3614
- copy_info_action = QAction("Copy Object Information", self)
3615
+ copy_info_action = QAction(self.tr("Copy Object Information"), self)
3615
3616
  copy_info_action.triggered.connect(lambda: self.copy_object_information(item))
3616
3617
  menu.addAction(copy_info_action)
3617
3618
 
@@ -3654,9 +3655,10 @@ class WIMIDialog(QDialog):
3654
3655
 
3655
3656
  # Ensure the image has 3 channels (RGB)
3656
3657
  if stretched_image.ndim == 2:
3657
- stretched_image = np.stack((stretched_image,) * 3, axis=-1)
3658
+ # OPTIMIZATION: Use cv2.cvtColor instead of np.stack/repeat
3659
+ stretched_image = cv2.cvtColor(stretched_image, cv2.COLOR_GRAY2RGB)
3658
3660
  elif stretched_image.shape[2] == 1:
3659
- stretched_image = np.repeat(stretched_image, 3, axis=2)
3661
+ stretched_image = cv2.cvtColor(stretched_image, cv2.COLOR_GRAY2RGB)
3660
3662
 
3661
3663
 
3662
3664
 
@@ -3988,7 +3990,11 @@ class WIMIDialog(QDialog):
3988
3990
  elif field == "Long Type" and obj.get("long_type") != "N/A":
3989
3991
  text = f"{obj['long_type']}"
3990
3992
  elif field == "Redshift" and obj.get("redshift") != "N/A":
3991
- text = f"Redshift: {float(obj['redshift']):.5f}" # Limit redshift to 5 decimal places
3993
+ try:
3994
+ val_float = float(obj['redshift'])
3995
+ text = f"Redshift: {val_float:.5f}"
3996
+ except ValueError:
3997
+ text = f"Redshift: {obj['redshift']}"
3992
3998
  elif field == "Comoving Distance" and obj.get("comoving_distance") != "N/A":
3993
3999
  text = f"Distance: {obj['comoving_distance']} GLy"
3994
4000
  else:
@@ -4063,11 +4069,25 @@ class WIMIDialog(QDialog):
4063
4069
  # ─── 3) Normalize & downsample image ──────────────────────────
4064
4070
  img = self.image_data
4065
4071
  if img.ndim == 2:
4066
- img = np.stack([img]*3, axis=-1)
4072
+ # OPTIMIZATION: Use cv2.cvtColor
4073
+ img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
4067
4074
  img_norm = np.clip((img - img.min())/(np.ptp(img)+1e-8), 0, 1)
4068
4075
  full_h, full_w = img.shape[:2]
4069
4076
  scale = min(max_res/full_h, max_res/full_w, 1.0)
4070
- img_ds = np.stack([zoom(img_norm[..., i], scale, order=1) for i in range(3)], axis=-1)
4077
+
4078
+ # OPTIMIZATION: Use cv2.resize instead of scipy.ndimage.zoom
4079
+ # zoom(img, scale) equivalent to resize(img, None, fx=scale, fy=scale)
4080
+ # cv2.resize expects (width, height)
4081
+ if scale < 1.0:
4082
+ new_w = int(full_w * scale)
4083
+ new_h = int(full_h * scale)
4084
+ img_ds = cv2.resize(img_norm, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
4085
+ else:
4086
+ img_ds = img_norm
4087
+
4088
+ # Ensure 3D dimensionality if it somehow got flattened (cv2.resize keeps channels usually)
4089
+ if img_ds.ndim == 2:
4090
+ img_ds = cv2.cvtColor(img_ds, cv2.COLOR_GRAY2RGB)
4071
4091
  h_ds, w_ds, _ = img_ds.shape
4072
4092
 
4073
4093
  # ─── 4) Build plane coordinates ───────────────────────────────
@@ -5079,10 +5099,10 @@ class WIMIDialog(QDialog):
5079
5099
  if img.dtype != np.uint8:
5080
5100
  img = np.clip(img, 0.0, 1.0)
5081
5101
  if img.ndim == 2:
5082
- img = np.stack([img] * 3, axis=-1)
5102
+ img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
5083
5103
  img = (img * 255.0).astype(np.uint8)
5084
5104
  elif img.ndim == 2:
5085
- img = np.stack([img] * 3, axis=-1)
5105
+ img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
5086
5106
 
5087
5107
  h, w = img.shape[:2]
5088
5108
  bytes_per_line = 3 * w