Skip to content

Commit 90c74ba

Browse files
committed
REFACTOR: moved functions in launchers to be in the same file as the class they are launching. Removed launcher methods from classes in data_structures to better separate the model from the view/controller. Made more changes to the import structure.
1 parent 1f47f92 commit 90c74ba

File tree

11 files changed

+139
-194
lines changed

11 files changed

+139
-194
lines changed

src/pyxalign/__init__.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,7 @@
22
from . import io
33
from .api import options
44
from .api import enums
5-
6-
from .interactions.master import launch_master_gui
7-
from .interactions.viewers.launchers import launch_array_viewer, launch_volume_viewer, launch_linked_array_viewer
8-
9-
10-
# Create a gui namespace using a simple class
11-
class _GUI:
12-
"""Namespace for GUI-related functions."""
13-
14-
launch_master_gui = staticmethod(launch_master_gui)
15-
launch_array_viewer = staticmethod(launch_array_viewer)
16-
launch_volume_viewer = staticmethod(launch_volume_viewer)
17-
launch_linked_array_viewer = staticmethod(launch_linked_array_viewer)
18-
19-
20-
21-
gui = _GUI()
5+
from . import gui
226

237
__all__ = [
248
"data_structures",

src/pyxalign/data_structures/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
"""
77

88
from .projections import PhaseProjections, ComplexProjections
9-
from .task import LaminographyAlignmentTask
10-
from .xrf_task import XRFTask
9+
from .task import LaminographyAlignmentTask, load_task
10+
from .xrf_task import XRFTask, load_xrf_task
1111

1212
__all__ = [
1313
"ComplexProjections",
1414
"PhaseProjections",
1515
"LaminographyAlignmentTask",
1616
"XRFTask",
17+
"load_task",
18+
"load_xrf_task",
1719
]

src/pyxalign/data_structures/projections.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
get_center_of_rotation_from_different_resolution_alignment,
88
get_shift_from_different_resolution_alignment,
99
)
10-
from pyxalign.api.constants import divisor
1110
from pyxalign.api.options.plotting import PlotDataOptions
1211
from pyxalign.estimate_center import (
1312
estimate_center_of_rotation,
@@ -18,7 +17,6 @@
1817
from pyxalign.api import enums
1918
from pyxalign.api.options.alignment import AlignmentOptions
2019
from pyxalign.api.options.device import DeviceOptions
21-
from pyxalign.api.options import ProjectionViewerOptions
2220

2321
from pyxalign.api.options.projections import (
2422
EstimateCenterOptions,
@@ -43,7 +41,6 @@
4341

4442
from pyxalign.mask import estimate_reliability_region_mask, blur_masks
4543
from pyxalign.model_functions import symmetric_gaussian_2d
46-
from pyxalign.interactions.viewers.launchers import launch_projection_viewer
4744
import pyxalign.plotting.plotters as plotters
4845
from pyxalign.style.text import ordinal
4946
from pyxalign.timing.timer_utils import timer, clear_timer_globals
@@ -67,6 +64,7 @@
6764
from pyxalign.data_structures.positions import ProbePositions
6865
from pyxalign.api.types import ArrayType, r_type
6966

67+
7068
class TransformTracker:
7169
def __init__(
7270
self,
@@ -724,15 +722,6 @@ def save_projections_object(
724722
else:
725723
print(f"projections saved to {save_path}")
726724

727-
def launch_viewer(
728-
self,
729-
options: Optional[ProjectionViewerOptions] = None,
730-
wait_until_closed: Optional[bool] = False,
731-
):
732-
self.gui = launch_projection_viewer(
733-
self, options, display_only=False, wait_until_closed=wait_until_closed
734-
)
735-
736725
def load_and_stage_shift(
737726
self,
738727
task_file_path: str,
@@ -801,8 +790,7 @@ def unwrap_phase(self, pinned_results: Optional[np.ndarray] = None) -> ArrayType
801790
)
802791
# this method does not need a mask
803792
bool_2 = (
804-
self.options.phase_unwrap.method
805-
== enums.PhaseUnwrapMethods.GRADIENT_INTEGRATION
793+
self.options.phase_unwrap.method == enums.PhaseUnwrapMethods.GRADIENT_INTEGRATION
806794
) and (self.options.phase_unwrap.gradient_integration.use_masks)
807795
use_masks = bool_1 or bool_2
808796
if use_masks is True and self.masks is None:
@@ -1013,3 +1001,5 @@ def get_kwargs_for_copying_to_new_projections_object(
10131001
kwargs["projections"] = projections.data * 1
10141002

10151003
return kwargs
1004+
1005+

src/pyxalign/data_structures/volume.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import astra
66
import copy
77
import h5py
8-
from PyQt5.QtWidgets import QApplication
98

109
from pyxalign.api.constants import divisor
1110
from pyxalign.api.options.device import DeviceOptions
@@ -16,8 +15,6 @@
1615
import pyxalign.image_processing as ip
1716
from pyxalign import reconstruct
1817
from pyxalign.io.save import save_array_as_tiff
19-
from pyxalign.interactions.viewers.arrays import VolumeViewer
20-
from pyxalign.interactions.viewers.launchers import launch_volume_viewer
2118
from pyxalign.plotting.plotters import plot_slice_of_3D_array
2219
import pyxalign.data_structures.projections as projections
2320
from pyxalign.timing.timer_utils import timer
@@ -339,9 +336,6 @@ def save_as_h5(self, file_path: str):
339336
with h5py.File(file_path, "w") as F:
340337
F.create_dataset(name="volume", data=self.data)
341338

342-
def launch_viewer(self, wait_until_closed: bool = False):
343-
self.gui = launch_volume_viewer(self.data, wait_until_closed=wait_until_closed)
344-
345339

346340
def get_tomogram_rotation_angles(
347341
reconstruction: np.ndarray,

src/pyxalign/data_structures/xrf_task.py

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import numpy as np
33
import h5py
44
import copy
5+
56
# from pyxalign.data_structures.task import LaminographyAlignmentTask
67
from pyxalign.alignment.cross_correlation import CrossCorrelationAligner
78
from pyxalign.api import enums
@@ -30,7 +31,7 @@ def __init__(
3031
masks: Optional[np.ndarray] = None,
3132
_initialize_from_loaded_data: bool = False,
3233
_loaded_projections_dict: Optional[dict[str, XRFProjections]] = None,
33-
):
34+
):
3435
self.projection_options = projection_options
3536
self.alignment_options = alignment_options
3637
# force proper typing
@@ -53,9 +54,9 @@ def __init__(
5354
# reinforce references
5455
for channel, proj in self.projections_dict.items():
5556
proj.options = self.projection_options
56-
57+
5758
# if center_of_rotation is not None:
58-
# self.center_of_rotation = center_of_rotation.astype(r_type)
59+
# self.center_of_rotation = center_of_rotation.astype(r_type)
5960
# else:
6061
self._center_of_rotation = self.projections_dict[self._primary_channel].center_of_rotation
6162

@@ -141,7 +142,6 @@ def primary_channel(self, new_channel: str):
141142
for channel in self.channels:
142143
print(f"{channel}")
143144

144-
145145
def apply_staged_shift_to_all_channels(self, device_options: Optional[DeviceOptions] = None):
146146
for _, projections in self.projections_dict.items():
147147
projections.apply_staged_shift(device_options)
@@ -260,33 +260,12 @@ def save_task(self, file_path: str, save_channels: Optional[list[str]] = None):
260260
print(f"XRF task saved to {h5_obj.file.filename}{h5_obj.name}")
261261
h5_obj["task_file_type"] = "xrf"
262262

263-
# def launch_projections_viewer(self):
264-
265-
266-
# # def launch_xrf_projections_viewer(self):
267-
268-
# def load_task(file_path: str, exclude: list[str] = []) -> LaminographyAlignmentTask:
269-
# print("Loading task from", file_path, "...")
270-
271-
# with h5py.File(file_path, "r") as h5_obj:
272-
# # Load projections
273-
# loaded_projections = load_projections(h5_obj, exclude)
274-
275-
# # Insert projections into task along with saved task options
276-
# task = LaminographyAlignmentTask(
277-
# options=load_options(h5_obj["options"], AlignmentTaskOptions),
278-
# complex_projections=loaded_projections["complex_projections"],
279-
# phase_projections=loaded_projections["phase_projections"],
280-
# )
281-
282-
# print("Loading complete")
283-
284-
# return task
285-
286263

287264
def load_xrf_task(file_path: str, exclude_channels: Optional[list[str]] = None) -> XRFTask:
288265
with h5py.File(file_path, "r") as h5_obj:
289-
xrf_projections_dict = load_xrf_projections(task_h5_obj=h5_obj, exclude_channels=exclude_channels)
266+
xrf_projections_dict = load_xrf_projections(
267+
task_h5_obj=h5_obj, exclude_channels=exclude_channels
268+
)
290269
primary_channel = h5_obj["primary_channel"][()].decode()
291270
alignment_options = load_options(h5_obj["alignment_options"], AlignmentTaskOptions)
292271
projection_options = load_options(h5_obj["projection_options"], ProjectionOptions)
@@ -309,4 +288,3 @@ def load_xrf_task(file_path: str, exclude_channels: Optional[list[str]] = None)
309288
)
310289

311290
return xrf_task
312-

src/pyxalign/gui/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from ..interactions.viewers.xrf import (
2+
launch_xrf_projections_viewer,
3+
launch_xrf_volume_viewer,
4+
)
5+
from ..interactions.viewers.arrays import launch_projection_viewer, launch_volume_viewer
6+
from ..interactions.viewers.base import launch_array_viewer
7+
from ..interactions.master import launch_master_gui
8+
from ..interactions.viewers.base import (
9+
launch_linked_array_viewer,
10+
launch_array_viewer,
11+
)
12+
13+
__all__ = [
14+
"launch_master_gui",
15+
"launch_array_viewer",
16+
"launch_volume_viewer",
17+
"launch_linked_array_viewer",
18+
"launch_projection_viewer",
19+
"launch_xrf_projections_viewer",
20+
"launch_xrf_volume_viewer",
21+
]

src/pyxalign/interactions/viewers/arrays.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
from typing import Callable, Optional
22
import cupy as cp
33
from pyxalign.api.maps import get_process_func_by_enum
4-
from pyxalign.api.options.options import ExperimentOptions
4+
from pyxalign.api.options import ProjectionViewerOptions
55
from pyxalign.api.options.plotting import ArrayViewerOptions, ProjectionViewerOptions
66
from pyxalign.api.options_utils import get_all_attribute_names
77
import pyxalign.data_structures.projections as p
88
from pyxalign.gpu_utils import return_cpu_array
9-
from pyxalign.interactions.mask import ThresholdSelector
109
from pyxalign.interactions.options.options_editor import BasicOptionsEditor
1110
from pyxalign.interactions.utils.loading_decorator import loading_bar_wrapper
1211
from pyxalign.interactions.viewers.base import ArrayViewer, IndexSelectorWidget, MultiThreadedWidget
1312
from PyQt5.QtWidgets import (
13+
QApplication,
1414
QWidget,
1515
QVBoxLayout,
1616
QHBoxLayout,
@@ -117,6 +117,7 @@ def start(self):
117117

118118
class ProjectionViewer(MultiThreadedWidget):
119119
"""Widget for viewing projections"""
120+
120121
masks_created = pyqtSignal(np.ndarray)
121122

122123
def __init__(
@@ -653,7 +654,35 @@ def return_angle_string(angle):
653654

654655
def return_scan_string(scan_number):
655656
return f"<span style='color:#9FEDB9'>Scan {scan_number}</span>"
657+
656658
title_strings = [
657659
f"{whitespace}{return_scan_string(scan)}{whitespace}{return_angle_string(angle)}"
658-
for scan, angle in zip(scan_numbers, angles)]
660+
for scan, angle in zip(scan_numbers, angles)
661+
]
659662
return title_strings
663+
664+
665+
def launch_projection_viewer(
666+
projections: "p.Projections",
667+
options: Optional[ProjectionViewerOptions] = None,
668+
display_only: bool = False,
669+
wait_until_closed: bool = False,
670+
) -> ProjectionViewer:
671+
app = QApplication.instance() or QApplication([])
672+
gui = ProjectionViewer(projections, options, display_only=display_only)
673+
gui.show()
674+
if wait_until_closed:
675+
app.exec_()
676+
return gui
677+
678+
679+
def launch_volume_viewer(
680+
array_3d: np.ndarray,
681+
wait_until_closed: bool = False,
682+
) -> VolumeViewer:
683+
app = QApplication.instance() or QApplication([])
684+
gui = VolumeViewer(volume=array_3d)
685+
gui.show()
686+
if wait_until_closed:
687+
app.exec_()
688+
return gui

src/pyxalign/interactions/viewers/base.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,3 +686,49 @@ def stepBy(self, steps):
686686
else:
687687
cur = a[0]
688688
self.setValue(cur)
689+
690+
691+
def launch_array_viewer(
692+
array3d: np.ndarray,
693+
options: Optional[ArrayViewerOptions] = None,
694+
sort_idx: Optional[Sequence] = None,
695+
extra_title_strings_list: Optional[list[str]] = None,
696+
process_func: Optional[Callable] = None,
697+
wait_until_closed: bool = False,
698+
):
699+
app = QApplication.instance() or QApplication([])
700+
gui = ArrayViewer(
701+
array3d,
702+
options,
703+
sort_idx,
704+
extra_title_strings_list=extra_title_strings_list,
705+
process_func=process_func,
706+
)
707+
gui.setAttribute(Qt.WA_DeleteOnClose)
708+
gui.show()
709+
if wait_until_closed:
710+
app.exec_()
711+
return gui
712+
713+
714+
def launch_linked_array_viewer(
715+
array_list: list[np.ndarray],
716+
options: Optional[ArrayViewerOptions] = None,
717+
sort_idx: Optional[Sequence] = None,
718+
extra_title_strings_list: Optional[list[str]] = None,
719+
process_func: Optional[Callable] = None,
720+
wait_until_closed: bool = False,
721+
):
722+
app = QApplication.instance() or QApplication([])
723+
gui = LinkedArrayViewer(
724+
array_list,
725+
options,
726+
sort_idx,
727+
extra_title_strings_list=extra_title_strings_list,
728+
process_func=process_func,
729+
)
730+
gui.setAttribute(Qt.WA_DeleteOnClose)
731+
gui.show()
732+
if wait_until_closed:
733+
app.exec_()
734+
return gui

0 commit comments

Comments
 (0)