Skip to content

Commit 3d71ce5

Browse files
authored
Add Plot Options menu to Plotting tab (#39335)
### Description of work This PR contains changes that add Plot Options menu to Plotting tab. This menu allows a user to modify omega offset and d-spacing values dx and dy and update the "Plotting" tab view correspondingly. This PR includes a first part of adding advanced plotting capabilities for the Single Cristal Elastic mode of DNS Reduction GUI. Complete integration of the Single Cristal Elastic mode into the DNS Reduction GUI will be implemented in several steps (in order to ensure reasonable PR sizes and reduce the workload for the reviewers). #### Summary of work Fixes Part 6a of #36407. <!-- If the original issue was raised by a user they should be named here. Do not leak email addresses **Report to:** [user name] --> #### Further detail of work <!-- Please provide a more detailed description of the work that has been undertaken. --> ### To test: - Download test data: [Single_Crystal_Elastic.zip](https://github.com/mantidproject/mantid/files/13751286/Single_Crystal_Elastic.zip) - Open the reduction GUI [Interfaces->Direct->DNS Reduction] - The "Single Crystal Elastic" mode should open by default. If not, switch to this mode, by selecting Tools -> Change Mode -> Single Crystal Elastic - Make sure that the corresponding documentation is up-to-date (run `cmake --build . --target docs-html` in build folder to create docs). Relevant documentation will then be located in `[mantid_build_path]/docs/html/interfaces/direct/dns_reduction/` - Browse to the directory where the test data are located using the "Paths" tab of the GUI - Load and select the sample data for reduction using the "Data" tab - Click on the "Options" tab and select options for data reduction. - Proceed to the "Script Generator" tab and click on the "Generate and Run Script" button, which should run the corresponding workflow depending on the parameters selected under the "Options" tab. - Open the "Plotting" tab and make sure that the images are generated. - At the top of the "Plotting" widget click on the "Plot Options" menu and click on one of the suggested menus ("Change omega offset" or "Change d-spasings"). - Make sure that the view is updated once the new values for omega offset and d-spasings are applied. *This does not require release notes* because **this PR contains limited functionality.** Release notes for the Single Cristal Elastic mode will be included in a subsequent PR, once all components for implementing the data reduction workflow are uploaded. --- ### Reviewer Please comment on the points listed below ([full description](http://developer.mantidproject.org/ReviewingAPullRequest.html)). **Your comments will be used as part of the gatekeeper process, so please comment clearly on what you have checked during your review.** If changes are made to the PR during the review process then your final comment will be the most important for gatekeepers. In this comment you should make it clear why any earlier review is still valid, or confirm that all requested changes have been addressed. #### Code Review - Is the code of an acceptable quality? - Does the code conform to the [coding standards](http://developer.mantidproject.org/Standards/)? - Are the unit tests small and test the class in isolation? - If there is GUI work does it follow the [GUI standards](http://developer.mantidproject.org/Standards/GUIStandards.html)? - If there are changes in the release notes then do they describe the changes appropriately? - Do the release notes conform to the [release notes guide](https://developer.mantidproject.org/Standards/ReleaseNotesGuide.html)? #### Functional Tests - Do changes function as described? Add comments below that describe the tests performed? - Do the changes handle unexpected situations, e.g. bad input? - Has the relevant (user and developer) documentation been added/updated? Does everything look good? Mark the review as **Approve**. A member of `@mantidproject/gatekeepers` will take care of it. ### Gatekeeper If you need to request changes to a PR then please add a comment and set the review status to "Request changes". This will stop the PR from showing up in the list for other gatekeepers.
1 parent fe5d7f3 commit 3d71ce5

File tree

11 files changed

+312
-101
lines changed

11 files changed

+312
-101
lines changed

qt/python/mantidqtinterfaces/mantidqtinterfaces/dns_powder_tof/main_presenter.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def _switch_mode(self, modus):
5353
self.view.clear_subviews()
5454
self.view.clear_submenus()
5555
self.modus.change(modus)
56+
self.view.action[modus].setChecked(True)
5657
self._parameter_abo.clear()
5758
for widget in self.modus.widgets.values():
5859
self._parameter_abo.register(widget.presenter)
@@ -71,6 +72,13 @@ def _tab_changed(self, old_tab_index, tab_index):
7172
for observer in self._parameter_abo.observers:
7273
if observer.view == actual_view:
7374
self._parameter_abo.notify_focused_tab(observer)
75+
if self.modus.name == "single_crystal_elastic":
76+
if tab_index == 4:
77+
self.modus.widgets["plot_elastic_single_crystal"].view.set_plot_view_menu_visibility(True)
78+
self.modus.widgets["plot_elastic_single_crystal"].view.set_plot_options_menu_visibility(True)
79+
else:
80+
self.modus.widgets["plot_elastic_single_crystal"].view.set_plot_view_menu_visibility(False)
81+
self.modus.widgets["plot_elastic_single_crystal"].view.set_plot_options_menu_visibility(False)
7482

7583
def _attach_signal_slots(self):
7684
self.view.sig_tab_changed.connect(self._tab_changed)

qt/python/mantidqtinterfaces/mantidqtinterfaces/dns_powder_tof/main_view.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from mantidqt.gui_helper import show_interface_help
1616

1717
from qtpy.QtCore import Signal
18-
from qtpy.QtWidgets import QMainWindow
18+
from qtpy.QtWidgets import QMainWindow, QAction, QActionGroup
1919
from qtpy.QtCore import QProcess
2020

2121

@@ -43,13 +43,13 @@ def __init__(self, parent=None, app=None, within_mantid=None):
4343
self.ui.actionDNS_website.triggered.connect(self._open_dns_webpage)
4444
# connect mode switching signals
4545
self.modus_mapping = {
46-
self.ui.actionPowder_Elastic: "powder_elastic",
4746
self.ui.actionPowder_TOF: "powder_tof",
47+
self.ui.actionPowder_Elastic: "powder_elastic",
4848
self.ui.actionSingle_Crystal_Elastic: "single_crystal_elastic",
4949
}
5050
self.modus_titles = {
51-
"powder_elastic": "DNS Reduction GUI - Powder Elastic",
5251
"powder_tof": "DNS Reduction GUI - Powder TOF",
52+
"powder_elastic": "DNS Reduction GUI - Powder Elastic",
5353
"single_crystal_elastic": "DNS Reduction GUI - Single Crystal Elastic",
5454
}
5555
for key in self.modus_mapping:
@@ -60,6 +60,21 @@ def __init__(self, parent=None, app=None, within_mantid=None):
6060
# connect signals
6161
self.ui.tabWidget.currentChanged.connect(self._tab_changed)
6262

63+
# Create an exclusive action group with radio button like behavior
64+
self.action_group = QActionGroup(self)
65+
self.action_group.setExclusive(True)
66+
67+
self.action = {}
68+
self.modus_actions = {
69+
"powder_tof": "actionPowder_TOF",
70+
"powder_elastic": "actionPowder_Elastic",
71+
"single_crystal_elastic": "actionSingle_Crystal_Elastic",
72+
}
73+
for modus_name, modus_action in self.modus_actions.items():
74+
self.action[modus_name] = self.findChild(QAction, modus_action)
75+
self.action[modus_name].setCheckable(True)
76+
self.action_group.addAction(self.action[modus_name])
77+
6378
# signals
6479
sig_tab_changed = Signal(int, int)
6580
sig_save_as_triggered = Signal()
@@ -104,7 +119,7 @@ def _help_button_clicked(self):
104119

105120
def add_submenu(self, subview):
106121
for menu in subview.menus:
107-
submenu = self.menu.insertMenu(self.ui.menuHelp.menuAction(), menu)
122+
submenu = self.menu.insertMenu(None, menu)
108123
self.subview_menus.append(submenu)
109124

110125
def clear_submenus(self):
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Mantid Repository : https://github.com/mantidproject/mantid
2+
#
3+
# Copyright &copy; 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
# NScD Oak Ridge National Laboratory, European Spallation Source
5+
# & Institut Laue - Langevin
6+
# SPDX - License - Identifier: GPL - 3.0 +
7+
8+
"""
9+
Class for small input dialogs.
10+
"""
11+
12+
from pathlib import Path
13+
14+
from qtpy.QtWidgets import QDialog
15+
from qtpy.uic import loadUi
16+
17+
18+
class DNSDialog(QDialog):
19+
"""
20+
Class for dialogs which can be opened by the GUI.
21+
"""
22+
23+
def __init__(self, files=None, ui=None):
24+
super().__init__()
25+
path = str(Path(files).parent.absolute())
26+
self._content = loadUi(path + ui, self)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Mantid Repository : https://github.com/mantidproject/mantid
2+
#
3+
# Copyright &copy; 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
# NScD Oak Ridge National Laboratory, European Spallation Source
5+
# & Institut Laue - Langevin
6+
# SPDX - License - Identifier: GPL - 3.0 +
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Mantid Repository : https://github.com/mantidproject/mantid
2+
#
3+
# Copyright &copy; 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
# NScD Oak Ridge National Laboratory, European Spallation Source
5+
# & Institut Laue - Langevin
6+
# SPDX - License - Identifier: GPL - 3.0 +
7+
8+
from qtpy.QtWidgets import QProxyStyle, QStyle
9+
10+
from mantidqtinterfaces.dns_single_crystal_elastic.data_structures.dns_dialog import DNSDialog
11+
12+
13+
class SpinboxNorepeatStyle(QProxyStyle): # turn off auto repeat on spinbox
14+
def styleHint(self, hint, option=None, widget=None, returnData=None):
15+
if hint == QStyle.SH_SpinBox_KeyPressAutoRepeatRate:
16+
return 10**5
17+
if hint == QStyle.SH_SpinBox_ClickAutoRepeatRate:
18+
return 10**5
19+
if hint == QStyle.SH_SpinBox_ClickAutoRepeatThreshold:
20+
return 10**5
21+
return super().styleHint(hint, option, widget, returnData)
22+
23+
24+
class DNSOmegaOffsetDialog(DNSDialog):
25+
def __init__(self, parent, omega_offset):
26+
super().__init__(files=__file__, ui="/omega_offset.ui")
27+
self._content.dSB_omega_offset.setStyle(SpinboxNorepeatStyle())
28+
self._initial_omega_offset = omega_offset
29+
self._content.dSB_omega_offset.setValue(self._initial_omega_offset)
30+
self._content.dSB_omega_offset.setFocus()
31+
self._content.dSB_omega_offset.valueChanged.connect(self._omega_offset_changed)
32+
self._content.pB_restore_default.clicked.connect(self._discard_changes)
33+
self._parent = parent
34+
35+
def _omega_offset_changed(self, omega_offset):
36+
self._parent.sig_update_omega_offset.emit(omega_offset)
37+
38+
def _discard_changes(self):
39+
self._parent.sig_restore_default_omega_offset.emit()
40+
self._content.dSB_omega_offset.setValue(self._parent.initial_values["omega_offset"])
41+
42+
43+
class DNSdxdyDialog(DNSDialog):
44+
def __init__(self, parent, dx, dy):
45+
super().__init__(files=__file__, ui="/dxdy.ui")
46+
self._initial_dx = dx
47+
self._initial_dy = dy
48+
self._content.dSB_dx.setStyle(SpinboxNorepeatStyle())
49+
self._content.dSB_dy.setStyle(SpinboxNorepeatStyle())
50+
self._content.dSB_dx.setValue(dx)
51+
self._content.dSB_dx.setFocus()
52+
self._content.dSB_dx.valueChanged.connect(self._dxdy_changed)
53+
self._content.dSB_dy.setValue(dy)
54+
self._content.dSB_dy.valueChanged.connect(self._dxdy_changed)
55+
self._content.pB_restore_default.clicked.connect(self._discard_changes)
56+
self._parent = parent
57+
58+
def _dxdy_changed(self, dx=None, dy=None):
59+
if dx is None or dy is None:
60+
dx = self._content.dSB_dx.value()
61+
dy = self._content.dSB_dy.value()
62+
self._parent.sig_update_dxdy.emit(dx, dy)
63+
64+
def _discard_changes(self):
65+
self._parent.sig_restore_default_dxdy.emit()
66+
self._content.dSB_dx.setValue(self._parent.initial_values["dx"])
67+
self._parent.sig_restore_default_dxdy.emit()
68+
self._content.dSB_dy.setValue(self._parent.initial_values["dy"])

qt/python/mantidqtinterfaces/mantidqtinterfaces/dns_single_crystal_elastic/plot/dialogs/dxdy.ui

Lines changed: 81 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>400</width>
10-
<height>300</height>
9+
<width>457</width>
10+
<height>57</height>
1111
</rect>
1212
</property>
1313
<property name="sizePolicy">
@@ -19,75 +19,85 @@
1919
<property name="windowTitle">
2020
<string>Change d-spacings</string>
2121
</property>
22-
<layout class="QGridLayout" name="gridLayout">
23-
<item row="0" column="0">
24-
<widget class="QLabel" name="l_dx">
25-
<property name="text">
26-
<string>d&lt;sub&gt;x&lt;/sub&gt;</string>
27-
</property>
28-
<property name="alignment">
29-
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
30-
</property>
31-
</widget>
32-
</item>
33-
<item row="0" column="1">
34-
<widget class="QDoubleSpinBox" name="dSB_dx">
35-
<property name="keyboardTracking">
36-
<bool>false</bool>
37-
</property>
38-
<property name="maximum">
39-
<double>399.990000000000009</double>
40-
</property>
41-
<property name="singleStep">
42-
<double>0.100000000000000</double>
43-
</property>
44-
</widget>
45-
</item>
46-
<item row="1" column="0">
47-
<widget class="QLabel" name="l_dy">
48-
<property name="text">
49-
<string>d&lt;sub&gt;y&lt;/sub&gt;</string>
50-
</property>
51-
<property name="alignment">
52-
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
53-
</property>
54-
<property name="openExternalLinks">
55-
<bool>false</bool>
56-
</property>
57-
</widget>
58-
</item>
59-
<item row="1" column="1">
60-
<widget class="QDoubleSpinBox" name="dSB_dy">
61-
<property name="keyboardTracking">
62-
<bool>false</bool>
63-
</property>
64-
<property name="maximum">
65-
<double>399.990000000000009</double>
66-
</property>
67-
<property name="singleStep">
68-
<double>0.100000000000000</double>
69-
</property>
70-
</widget>
71-
</item>
72-
<item row="2" column="0">
73-
<widget class="QPushButton" name="pB_apply">
74-
<property name="text">
75-
<string>Apply</string>
76-
</property>
77-
<property name="autoDefault">
78-
<bool>false</bool>
79-
</property>
80-
</widget>
81-
</item>
82-
<item row="2" column="1">
83-
<widget class="QPushButton" name="pB_discard">
84-
<property name="text">
85-
<string>Discard</string>
86-
</property>
87-
<property name="autoDefault">
88-
<bool>false</bool>
89-
</property>
90-
</widget>
22+
<layout class="QHBoxLayout" name="horizontalLayout_2">
23+
<item>
24+
<layout class="QHBoxLayout" name="horizontalLayout">
25+
<item>
26+
<widget class="QLabel" name="l_dx">
27+
<property name="text">
28+
<string>d&lt;sub&gt;x&lt;/sub&gt;</string>
29+
</property>
30+
<property name="alignment">
31+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
32+
</property>
33+
</widget>
34+
</item>
35+
<item>
36+
<widget class="QDoubleSpinBox" name="dSB_dx">
37+
<property name="keyboardTracking">
38+
<bool>false</bool>
39+
</property>
40+
<property name="maximum">
41+
<double>399.990000000000009</double>
42+
</property>
43+
<property name="singleStep">
44+
<double>0.100000000000000</double>
45+
</property>
46+
</widget>
47+
</item>
48+
<item>
49+
<widget class="QLabel" name="l_dy">
50+
<property name="text">
51+
<string>d&lt;sub&gt;y&lt;/sub&gt;</string>
52+
</property>
53+
<property name="alignment">
54+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
55+
</property>
56+
<property name="openExternalLinks">
57+
<bool>false</bool>
58+
</property>
59+
</widget>
60+
</item>
61+
<item>
62+
<widget class="QDoubleSpinBox" name="dSB_dy">
63+
<property name="keyboardTracking">
64+
<bool>false</bool>
65+
</property>
66+
<property name="maximum">
67+
<double>399.990000000000009</double>
68+
</property>
69+
<property name="singleStep">
70+
<double>0.100000000000000</double>
71+
</property>
72+
</widget>
73+
</item>
74+
<item>
75+
<spacer name="horizontalSpacer">
76+
<property name="orientation">
77+
<enum>Qt::Horizontal</enum>
78+
</property>
79+
<property name="sizeType">
80+
<enum>QSizePolicy::Preferred</enum>
81+
</property>
82+
<property name="sizeHint" stdset="0">
83+
<size>
84+
<width>80</width>
85+
<height>20</height>
86+
</size>
87+
</property>
88+
</spacer>
89+
</item>
90+
<item>
91+
<widget class="QPushButton" name="pB_restore_default">
92+
<property name="text">
93+
<string>Restore Default</string>
94+
</property>
95+
<property name="autoDefault">
96+
<bool>false</bool>
97+
</property>
98+
</widget>
99+
</item>
100+
</layout>
91101
</item>
92102
</layout>
93103
</widget>

0 commit comments

Comments
 (0)