diff --git a/pyampp/gxbox/UI/gxbox.ui b/pyampp/gxbox/UI/gxbox.ui new file mode 100644 index 0000000..3b5109a --- /dev/null +++ b/pyampp/gxbox/UI/gxbox.ui @@ -0,0 +1,208 @@ + + + MainWindow + + + + 0 + 0 + 643 + 273 + + + + GxBox Map Viewer + + + + + 10 + + + 15 + + + 15 + + + 15 + + + 15 + + + + + + + + + + Map Controls + + + + + + + + Bottom Map: + + + + + + + + + + + + + + Context Map: + + + + + + + + + + + + + + 3D Mag. Model: + + + + + + + + + + + + + + + Field Line Controls + + + + + + + + 3D viewer + + + + + + + Hide + + + + + + + Clear + + + + + + + Save + + + + + + + + + + + Bmin/Bmax [G]: + + + + + + + 0 + + + + + + + Clip + + + + + + + 1000 + + + + + + + Clip + + + + + + + + + + + cmap: + + + + + + + + + + + + + + + + + + + + Enter bounds (comma-separated) + + + + + + + + + + + + + + + + + diff --git a/pyampp/gxbox/gxbox_factory.py b/pyampp/gxbox/gxbox_factory.py index 3aac70c..80e1934 100644 --- a/pyampp/gxbox/gxbox_factory.py +++ b/pyampp/gxbox/gxbox_factory.py @@ -12,6 +12,8 @@ from PyQt5.QtWidgets import QApplication, QComboBox,QCheckBox, QFileDialog, QGroupBox, QHBoxLayout, QLabel, QLineEdit, \ QMainWindow, \ QPushButton, QVBoxLayout, QWidget +from PyQt5 import uic + from astropy.coordinates import SkyCoord from astropy.time import Time from matplotlib import colormaps as mplcmaps @@ -612,143 +614,45 @@ def init_ui(self): """ Initializes the user interface for the GxBox application. """ - self.setWindowTitle('GxBox Map Viewer') - # self.setGeometry(100, 100, 800, 600) - # Create a central widget - central_widget = QWidget(self) - self.setCentralWidget(central_widget) - - # Layout - main_layout = QVBoxLayout(central_widget) - control_layout = QHBoxLayout() + uic.loadUi(Path(__file__).parent / "UI" / "gxbox.ui", self) # Matplotlib Figure self.fig = plt.Figure() self.canvas = FigureCanvas(self.fig) - main_layout.addWidget(self.canvas) + self.canvasLayout.addWidget(self.canvas) # Add Matplotlib Navigation Toolbar self.toolbar = NavigationToolbar(self.canvas, self) - main_layout.addWidget(self.toolbar) - - map_control_group = QGroupBox("Map Controls") - # Horizontal layout for dropdowns and labels - map_control_layout = QVBoxLayout() - map_control_layout1 = QHBoxLayout() - map_control_layout2 = QHBoxLayout() - map_control_layout3 = QHBoxLayout() - - - # Dropdown for bottom map selection - self.map_bottom_selector = QComboBox() - self.map_bottom_selector.addItems(list(self.avaliable_maps)) - self.map_bottom_selector.setCurrentIndex(self.avaliable_maps.index(self.init_map_bottom_name)) - self.map_bottom_selector.setMaximumWidth(100) - self.map_bottom_selector_label = QLabel("Bottom Map:") - map_control_layout1.addWidget(self.map_bottom_selector_label) - map_control_layout1.addWidget(self.map_bottom_selector) - - # Dropdown for context map selection - self.map_context_selector = QComboBox() - self.map_context_selector.addItems(list(self.avaliable_maps)) - self.map_context_selector.setCurrentIndex(self.avaliable_maps.index(self.init_map_context_name)) - self.map_context_selector.setMaximumWidth(100) - self.map_context_selector_label = QLabel("Context Map:") - map_control_layout2.addWidget(self.map_context_selector_label) - map_control_layout2.addWidget(self.map_context_selector) - - # Dropdown for 3D magnetic model selection - self.b3d_model_selector = QComboBox() - self.b3d_model_selector.addItems(self.box.b3dtype) - self.b3d_model_selector.setCurrentIndex(0) - self.b3d_model_selector_label = QLabel("3D Mag. Model:") - map_control_layout3.addWidget(self.b3d_model_selector_label) - map_control_layout3.addWidget(self.b3d_model_selector) - - map_control_layout.addLayout(map_control_layout1) - map_control_layout.addLayout(map_control_layout2) - map_control_layout.addLayout(map_control_layout3) - map_control_group.setLayout(map_control_layout) - control_layout.addWidget(map_control_group) - map_control_group.setFixedHeight(160) - # map_control_group.adjustSize() - - # Connect dropdowns to their respective handlers - self.map_bottom_selector.currentTextChanged.connect(self.update_bottom_map) - self.map_context_selector.currentTextChanged.connect(self.update_context_map) - - fieldline_control_group = QGroupBox("Field Line Controls") - fieldline_control_layout = QVBoxLayout() - fieldline_control_layout1 = QHBoxLayout() - fieldline_control_layout2 = QHBoxLayout() - fieldline_control_layout3 = QHBoxLayout() - - # Add the visualize button - self.visualize_button = QPushButton("3D viewer") - self.visualize_button.setToolTip("Visualize the 3D magnetic field.") - self.visualize_button.clicked.connect(self.visualize_3d_magnetic_field) - fieldline_control_layout1.addWidget(self.visualize_button) - - self.toggle_fieldlines_button = QPushButton("Hide") - self.toggle_fieldlines_button.setToolTip("Toggle the visibility of the field lines.") - self.toggle_fieldlines_button.clicked.connect(self.toggle_fieldlines_visibility) - fieldline_control_layout1.addWidget(self.toggle_fieldlines_button) - - self.clear_fieldlines_button = QPushButton("Clear") - self.clear_fieldlines_button.setToolTip("Clear the field lines.") - self.clear_fieldlines_button.clicked.connect(self.clear_fieldlines) - fieldline_control_layout1.addWidget(self.clear_fieldlines_button) - - self.save_fieldlines_button = QPushButton("Save") - self.save_fieldlines_button.setToolTip("Save the field lines to a file.") - self.save_fieldlines_button.clicked.connect( + self.canvasLayout.addWidget(self.toolbar) + + self.mapBottomSelector.addItems(list(self.avaliable_maps)) + self.mapBottomSelector.setCurrentIndex(self.avaliable_maps.index(self.init_map_bottom_name)) + self.mapBottomSelector.currentTextChanged.connect(self.update_bottom_map) + + self.mapContextSelector.addItems(list(self.avaliable_maps)) + self.mapContextSelector.setCurrentIndex(self.avaliable_maps.index(self.init_map_context_name)) + self.mapContextSelector.currentTextChanged.connect(self.update_context_map) + + self.visualizeButton.setToolTip("Visualize the 3D magnetic field.") + self.visualizeButton.clicked.connect(self.visualize_3d_magnetic_field) + + self.toggleFieldlinesButton.setToolTip("Toggle the visibility of the field lines.") + self.toggleFieldlinesButton.clicked.connect(self.toggle_fieldlines_visibility) + self.clearFieldlinesButton.setToolTip("Clear the field lines.") + self.clearFieldlinesButton.clicked.connect(self.clear_fieldlines) + self.saveFieldlinesButton.setToolTip("Save the field lines to a file.") + self.saveFieldlinesButton.clicked.connect( lambda: self.save_fieldlines(f'fieldlines_{self.time.to_datetime().strftime("%Y%m%dT%H%M%S")}.pkl')) - fieldline_control_layout1.addWidget(self.save_fieldlines_button) - - self.bminmax_label = QLabel("Bmin/Bmax [G]:") - self.bmin_input = QLineEdit(self) - self.bmin_input.setText("0") # Set default value - self.bmin_clip_checkbox = QCheckBox("Clip") - self.bmin_clip_checkbox.setChecked(False) - self.bmax_input = QLineEdit(self) - self.bmax_input.setText("1000") # Set default value - self.bmax_clip_checkbox = QCheckBox("Clip") - self.bmax_clip_checkbox.setChecked(False) - - fieldline_control_layout2.addWidget(self.bminmax_label) - fieldline_control_layout2.addWidget(self.bmin_input) - fieldline_control_layout2.addWidget(self.bmin_clip_checkbox) - fieldline_control_layout2.addWidget(self.bmax_input) - fieldline_control_layout2.addWidget(self.bmax_clip_checkbox) - - self.cmap_selector = QComboBox(self) - self.cmap_selector.addItems(sorted(list(mplcmaps))) # List all available colormaps - self.cmap_selector.setCurrentText("viridis") # Set a default colormap - self.cmap_selector.setMaximumWidth(200) - self.discrete_cmap_bounds_input = QLineEdit(self) - self.discrete_cmap_bounds_input.setPlaceholderText("Enter bounds (comma-separated)") - - - # self.cmap_clip_checkbox = QCheckBox("Clip") - # self.cmap_clip_checkbox.setChecked(False) - # self.cmap_clip_checkbox.clicked.connect(self.toggle_cmap_clip) - - fieldline_control_layout3.addWidget(QLabel("cmap:")) - fieldline_control_layout3.addWidget(self.cmap_selector) - # fieldline_control_layout3.addWidget(self.cmap_clip_checkbox) - fieldline_control_layout3.addWidget(self.discrete_cmap_bounds_input) - fieldline_control_layout3.setStretch(0, 1) - - fieldline_control_layout.addLayout(fieldline_control_layout1) - fieldline_control_layout.addLayout(fieldline_control_layout2) - fieldline_control_layout.addLayout(fieldline_control_layout3) - - fieldline_control_group.setLayout(fieldline_control_layout) - control_layout.addWidget(fieldline_control_group) - fieldline_control_group.setFixedHeight(160) - # fieldline_control_group.adjustSize() - - main_layout.addLayout(control_layout) + + self.b3dModelSelector.addItems(self.box.b3dtype) + self.b3dModelSelector.setCurrentIndex(0) + + self.bminClipCheckbox.setChecked(False) + self.bmaxClipCheckbox.setChecked(False) + + self.cmapSelector.addItems(sorted(list(mplcmaps))) # List all available colormaps + self.cmapSelector.setCurrentText("viridis") # Set a default colormap + # self.cmapClipCheckbox.setChecked(False) if self.external_box is not None: if os.path.isfile(self.external_box): @@ -772,7 +676,7 @@ def visualize_3d_magnetic_field(self): """ box_norm_direction = self.box_norm_direction() box_view_up = self.box_view_up() - b3dtype = self.b3d_model_selector.currentText() + b3dtype = self.b3dModelSelector.currentText() # print(f'type of self.box.b3d is {type(self.box.b3d)}') # print(f'value of self.box.b3d is {self.box.b3d}') # if b3dtype == 'pot': @@ -780,8 +684,8 @@ def visualize_3d_magnetic_field(self): pass else: if self.box.b3d['pot'] is None: - if self.map_bottom_selector.currentText() != 'br': - self.map_bottom_selector.setCurrentIndex(self.avaliable_maps.index('br')) + if self.mapBottomSelector.currentText() != 'br': + self.mapBottomSelector.setCurrentIndex(self.avaliable_maps.index('br')) maglib_lff = MagFieldLinFFF() bnddata = self.map_bottom.data bnddata[np.isnan(bnddata)] = 0.0 @@ -902,11 +806,11 @@ def get_axes_pixel_coords(self, coords_world=None): # Toggles the clipping of the colormap. # """ # if self.cmap_clip_checkbox.isChecked(): - # self.bmax_clip_checkbox.setChecked(True) - # self.bmin_clip_checkbox.setChecked(True) + # self.bmaxClipCheckbox.setChecked(True) + # self.bminClipCheckbox.setChecked(True) # else: - # self.bmax_clip_checkbox.setChecked(False) - # self.bmin_clip_checkbox.setChecked(False) + # self.bmaxClipCheckbox.setChecked(False) + # self.bminClipCheckbox.setChecked(False) def toggle_fieldlines_visibility(self): """ @@ -922,9 +826,9 @@ def toggle_fieldlines_visibility(self): lc.set_visible(self.fieldlines_show_status) if self.fieldlines_show_status: - self.toggle_fieldlines_button.setText("Hide") + self.toggleFieldlinesButton.setText("Hide") else: - self.toggle_fieldlines_button.setText("Show") + self.toggleFieldlinesButton.setText("Show") self.canvas.draw() @@ -1031,8 +935,8 @@ def plot_fieldlines(self, streamlines, z_base=0.0): # Fetch Bmin and Bmax values from input fields try: - bmin = float(self.bmin_input.text()) - bmax = float(self.bmax_input.text()) + bmin = float(self.bminInput.text()) + bmax = float(self.bmaxInput.text()) except ValueError: bmin = 0 bmax = 1000 @@ -1040,9 +944,10 @@ def plot_fieldlines(self, streamlines, z_base=0.0): # Normalize the magnitude values for colormap - cmap = plt.get_cmap(self.cmap_selector.currentText()) + + cmap = plt.get_cmap(self.cmapSelector.currentText()) # Check if bounds input box is empty - bounds_text = self.discrete_cmap_bounds_input.text() + bounds_text = self.cmapDiscreteBoundsInput.text() if bounds_text: bounds = list(map(float, bounds_text.split(','))) norm = mcolors.BoundaryNorm(bounds, cmap.N) @@ -1066,19 +971,20 @@ def plot_fieldlines(self, streamlines, z_base=0.0): magnitude = field['magnitude'] segments = [((x[i], y[i]), (x[i + 1], y[i + 1])) for i in range(len(x) - 1)] colors = [cmap(norm(value)) for value in magnitude] # Colormap for each segment - if self.bmin_clip_checkbox.isChecked() or self.bmax_clip_checkbox.isChecked(): + + if self.bminClipCheckbox.isChecked() or self.bmaxClipCheckbox.isChecked(): bmin=0.0 bmax=5e6 ## an unrealistic large B field value for solar corona - if self.bmin_clip_checkbox.isChecked(): - bmin = float(self.bmin_input.text()) - if self.bmax_clip_checkbox.isChecked(): - bmax = float(self.bmax_input.text()) + if self.bminClipCheckbox.isChecked(): + bmin = float(self.bminInput.text()) + if self.bmaxClipCheckbox.isChecked(): + bmax = float(self.bmaxInput.text()) mask = np.logical_and(magnitude >= bmin, magnitude <= bmax) colors = np.array(colors)[mask] segments = np.array(segments)[mask[:-1]] # if self.cmap_clip_checkbox.isChecked(): - # bmin = float(self.bmin_input.text()) - # bmax = float(self.bmax_input.text()) + # bmin = float(self.bminInput.text()) + # bmax = float(self.bmaxInput.text()) # mask = np.logical_and(magnitude >= bmin, magnitude <= bmax) # colors = np.array(colors)[mask] # segments = np.array(segments)[mask[:-1]] diff --git a/pyampp/gxbox/magfield_viewer.py b/pyampp/gxbox/magfield_viewer.py index 85ca801..0edd4b9 100644 --- a/pyampp/gxbox/magfield_viewer.py +++ b/pyampp/gxbox/magfield_viewer.py @@ -885,7 +885,7 @@ def init_grid(self): self.grid_bottom.dimensions = (len(x), len(y), 1) self.grid_bottom.spacing = (x[1] - x[0], y[1] - y[0], 0) self.grid_bottom.origin = (x.min(), y.min(), z.min()) - self.bottom_name = self.parent.map_bottom_selector.currentText() + self.bottom_name = self.parent.mapBottomSelector.currentText() self.grid_bottom[self.bottom_name] = self.parent.map_bottom.data.T.ravel(order='F') self.scalar_selector_items.append(self.bottom_name)