Skip to content

Commit

Permalink
Crosshair updates and more (#26)
Browse files Browse the repository at this point in the history
* add test for invalid modq

* test comment update

* missing tests added

* experiment widget renamed to conform snake case standards

* snake case renaming of the widget variables

* update_crosshair plot function, connections,updates and logic added

* sample plot for crosshair added

* eline and qline data added for tests, tests added for crosshair plot,

* snakecase for tests
  • Loading branch information
mpatrou authored Jan 15, 2025
1 parent f3ccd22 commit f7b5f76
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 70 deletions.
37 changes: 23 additions & 14 deletions src/hyspecppt/hppt/hppt_presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ def __init__(self, view: any, model: any):
self.view.connect_sc_mode_switch(self.handle_switch_to_sc)

# populate fields
self.view.SCW.set_values(DEFAULT_LATTICE)
self.view.EW.initializeCombo(PLOT_TYPES)
self.view.EW.set_values(DEFAULT_EXPERIMENT)
self.view.CW.set_values(DEFAULT_CROSSHAIR)
self.view.sc_widget.set_values(DEFAULT_LATTICE)
self.view.experiment_widget.initializeCombo(PLOT_TYPES)
self.view.experiment_widget.set_values(DEFAULT_EXPERIMENT)
self.view.crosshair_widget.set_values(DEFAULT_CROSSHAIR)

# model init
# to be removed needs to happen in the model
Expand All @@ -32,10 +32,10 @@ def __init__(self, view: any, model: any):
self.model.set_single_crystal_data(params=DEFAULT_LATTICE)

# set default selection mode
experiment_type = self.view.SelW.powder_label
experiment_type = self.view.selection_widget.powder_label
if DEFAULT_MODE["current_experiment_type"].startswith("single"):
experiment_type = self.view.SelW.sc_label
self.view.SelW.selector_init(experiment_type) # pass the default mode from experiment type
experiment_type = self.view.selection_widget.sc_label
self.view.selection_widget.selector_init(experiment_type) # pass the default mode from experiment type

@property
def view(self):
Expand All @@ -53,7 +53,7 @@ def handle_field_values_update(self, field_values):
data = field_values["data"]
if section == "crosshair":
# get the current experiment type
experiment_type_label = self.view.SelW.get_selected_mode_label()
experiment_type_label = self.view.selection_widget.get_selected_mode_label()
experiment_type = "powder"
if experiment_type_label.startswith("Single"):
experiment_type = "single_crystal"
Expand All @@ -70,7 +70,10 @@ def handle_field_values_update(self, field_values):
# get the valid values for crosshair saved fields
# if the view contains an invalid value it is overwritten
saved_values = self.model.get_crosshair_data()
self.view.CW.set_values(saved_values)
self.view.crosshair_widget.set_values(saved_values)
# update the plot crosshair, if valid values are passed
if self.view.crosshair_widget.validation_status_all_inputs():
self.view.plot_widget.update_crosshair(eline=saved_values["DeltaE"], qline=saved_values["modQ"])

def handle_switch_to_powder(self):
"""Switch to Powder mode"""
Expand All @@ -83,10 +86,13 @@ def handle_switch_to_powder(self):
# get the valid values for crosshair saved fields
# if the view contains an invalid value it is overwritten
saved_values = self.model.get_crosshair_data()
self.view.CW.set_values(saved_values)
self.view.crosshair_widget.set_values(saved_values)
# update the plot crosshair, if valid values are passed
if self.view.crosshair_widget.validation_status_all_inputs():
self.view.plot_widget.update_crosshair(eline=saved_values["DeltaE"], qline=saved_values["modQ"])

saved_values = self.model.get_experiment_data()
self.view.EW.set_values(saved_values)
self.view.experiment_widget.set_values(saved_values)

def handle_switch_to_sc(self):
"""Switch to Single Crystal mode"""
Expand All @@ -99,14 +105,17 @@ def handle_switch_to_sc(self):
# get the valid values for crosshair saved fields
# if the view contains an invalid value it is overwritten
saved_values = self.model.get_crosshair_data()
self.view.CW.set_values(saved_values)
self.view.crosshair_widget.set_values(saved_values)
# update the plot crosshair, if valid values are passed
if self.view.crosshair_widget.validation_status_all_inputs():
self.view.plot_widget.update_crosshair(eline=saved_values["DeltaE"], qline=saved_values["modQ"])

# get the valid values for experiment saved fields
# if the view contains an invalid value it is overwritten
saved_values = self.model.get_experiment_data()
self.view.EW.set_values(saved_values)
self.view.experiment_widget.set_values(saved_values)

# get the valid values for single crystal saved fields
# if the view contains an invalid value it is overwritten
saved_values = self.model.get_single_crystal_data()
self.view.SCW.set_values(saved_values)
self.view.sc_widget.set_values(saved_values)
86 changes: 66 additions & 20 deletions src/hyspecppt/hppt/hppt_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from typing import Optional, Union

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qtagg import FigureCanvas
from matplotlib.backends.backend_qtagg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
Expand Down Expand Up @@ -50,25 +51,27 @@ def __init__(self, parent: Optional["QObject"] = None) -> None:

layout = QHBoxLayout()
self.setLayout(layout)
layoutLeft = QVBoxLayout()
layout.addLayout(layoutLeft)
self.EW = ExperimentWidget(self)
layoutLeft.addWidget(self.EW)
self.SCW = SingleCrystalWidget(self)
self.CW = CrosshairWidget(self)
self.SelW = SelectorWidget(self)
layoutLeft.addWidget(self.SelW)
layoutLeft.addWidget(self.SCW)
layoutLeft.addWidget(self.CW)
left_side_layout = QVBoxLayout()
layout.addLayout(left_side_layout)
self.experiment_widget = ExperimentWidget(self)
left_side_layout.addWidget(self.experiment_widget)
self.sc_widget = SingleCrystalWidget(self)
self.crosshair_widget = CrosshairWidget(self)
self.selection_widget = SelectorWidget(self)
left_side_layout.addWidget(self.selection_widget)
left_side_layout.addWidget(self.sc_widget)
left_side_layout.addWidget(self.crosshair_widget)
spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
layoutLeft.addItem(spacer)
self.PW = PlotWidget(self)
layout.addWidget(self.PW)
left_side_layout.addItem(spacer)
self.plot_widget = PlotWidget(self)
layout.addWidget(self.plot_widget)

# signal handling for every valid field update
self.EW.valid_signal.connect(self.values_update)
self.SCW.valid_signal.connect(self.values_update)
self.CW.valid_signal.connect(self.values_update)
self.experiment_widget.valid_signal.connect(self.values_update)
self.sc_widget.valid_signal.connect(self.values_update)
self.crosshair_widget.valid_signal.connect(self.values_update)
# plot update
self.crosshair_widget.valid_signal.connect(self.plot_widget.update_plot_crosshair)

def connect_fields_update(self, callback):
"""Callback for the fields update - set by the presenter"""
Expand Down Expand Up @@ -102,13 +105,13 @@ def switch_to_powder(self) -> None:

def field_visibility_in_SC(self) -> None:
"""Set visibility for Single Crystal mode"""
self.SCW.setVisible(True)
self.CW.set_Qmod_enabled(False)
self.sc_widget.setVisible(True)
self.crosshair_widget.set_Qmod_enabled(False)

def field_visibility_in_Powder(self) -> None:
"""Set visibility for Powder mode"""
self.SCW.setVisible(False)
self.CW.set_Qmod_enabled(True)
self.sc_widget.setVisible(False)
self.crosshair_widget.set_Qmod_enabled(True)


class PlotWidget(QWidget):
Expand All @@ -128,6 +131,41 @@ def __init__(self, parent: Optional["QObject"] = None) -> None:
layoutRight.addWidget(NavigationToolbar(self.static_canvas, self))
self.setLayout(layoutRight)

# crosshair initialization
self.fig, self.ax = plt.subplots()
self.eline_data = 0
self.qline_data = 0
self.qline = self.ax.axvline(x=self.eline_data)
self.eline = self.ax.axhline(y=self.qline_data)
self.fig.canvas.draw()
self.fig.show()

def update_plot_crosshair(self, crosshair_data: dict) -> None:
"""Update the plot with valid crosshair_data
Args:
eline (float): x
qline (float): y
"""
self.update_crosshair(crosshair_data["data"]["DeltaE"], crosshair_data["data"]["modQ"])

def update_crosshair(self, eline: float, qline: float) -> None:
"""Update the plot with crosshair lines
Args:
eline (float): x
qline (float): y
"""
self.eline_data = eline
self.qline_data = qline
# when plot is created this part needs to be updated accordingly to be part of the heatmap
self.eline.set_data([0, 1], [self.eline_data, self.eline_data])
self.qline.set_data([self.qline_data, self.qline_data], [0, 1])
self.ax.relim()
self.ax.autoscale()
self.fig.canvas.draw()
self.fig.show()


class SelectorWidget(QWidget):
"""Widget that selects Powder/Single Crystal mode"""
Expand Down Expand Up @@ -567,6 +605,14 @@ def validate_inputs(self, *_, **__) -> None:
else:
self.sender().setStyleSheet("")

def validation_status_all_inputs(self) -> bool:
"""Return validation status of all inpus, if all are valid returns True, else False"""
inputs = [self.DeltaE_edit, self.modQ_edit]
for edit in inputs:
if not edit.hasAcceptableInput():
return False
return True

def validate_all_inputs(self):
"""If all inputs are valid emit a valid_signal"""
inputs = [self.DeltaE_edit, self.modQ_edit]
Expand Down
Loading

0 comments on commit f7b5f76

Please sign in to comment.