class DetectorsPresenterTest(unittest.TestCase): def setUp(self): self.mock_view = mock.Mock() self.mock_view.widgets = { 'name1': 'GE1', 'name2': 'GE2', 'name3': 'GE3' } self.detector_presenter = DetectorsPresenter(self.mock_view) def test_that_all_view_widgets_are_appended_to_detector_list(self): self.assertEqual(self.detector_presenter.detectors, list(self.mock_view.widgets.values())) def test_that_setStateQuietly_calls_view_setStateQuietly(self): name = 'name' state = 3 self.detector_presenter.setStateQuietly(name, state) self.mock_view.setStateQuietly.assert_called_with(name, state) self.assertEqual(self.mock_view.setStateQuietly.call_count, 1) def test_that_get_names_gives_correct_list_of_names(self): self.assertEqual(self.detector_presenter.getNames(), self.mock_view.widgets.keys())
class ElementalAnalysisGui(QtWidgets.QMainWindow): def __init__(self, parent=None): super(ElementalAnalysisGui, self).__init__(parent) # set menu self.menu = self.menuBar() self.menu.addAction("File") edit_menu = self.menu.addMenu("Edit") edit_menu.addAction("Change Peak Data file", self.select_data_file) self.menu.addAction("Binning") self.menu.addAction("Normalise") # periodic table stuff self.ptable = PeriodicTablePresenter( PeriodicTableView(), PeriodicTableModel()) self.ptable.register_table_lclicked(self.table_left_clicked) self.ptable.register_table_rclicked(self.table_right_clicked) # load stuff self.load_widget = LoadPresenter( LoadView(), LoadModel(), CoLoadModel()) self.load_widget.on_loading_finished(self.loading_finished) # detectors self.detectors = DetectorsPresenter(DetectorsView()) for detector in self.detectors.detectors: detector.on_checkbox_checked(self.add_plot) detector.on_checkbox_unchecked(self.del_plot) # peaks boxes self.peaks = PeaksPresenter(PeaksView()) self.peaks.major.setChecked(True) self.peaks.major.on_checkbox_checked(self.major_peaks_checked) self.peaks.major.on_checkbox_unchecked(self.major_peaks_unchecked) self.peaks.minor.on_checkbox_checked(self.minor_peaks_checked) self.peaks.minor.on_checkbox_unchecked(self.minor_peaks_unchecked) self.peaks.gamma.on_checkbox_checked(self.gammas_checked) self.peaks.gamma.on_checkbox_unchecked(self.gammas_unchecked) self.peaks.electron.on_checkbox_checked(self.electrons_checked) self.peaks.electron.on_checkbox_unchecked(self.electrons_unchecked) # set up self.widget_list = QtWidgets.QVBoxLayout() self.widget_list.addWidget(self.peaks.view) self.widget_list.addWidget(self.detectors.view) self.widget_list.addWidget(self.load_widget.view) # plotting self.plot_window = None # layout self.box = QtWidgets.QHBoxLayout() self.box.addWidget(self.ptable.view) self.box.addLayout(self.widget_list) self.setCentralWidget(QtWidgets.QWidget(self)) self.centralWidget().setLayout(self.box) self.setWindowTitle("Elemental Analysis") self.element_widgets = {} self.element_lines = {} self.electron_peaks = self._get_electron_peaks() self._generate_element_widgets() def closeEvent(self, event): if self.plot_window is not None: self.plot_window.closeEvent(event) super(ElementalAnalysisGui, self).closeEvent(event) # general functions def _gen_label(self, name, x_value_in, element=None): if element is None: return # check x value is a float x_value = 0.0 try: x_value = float(x_value_in) except: return if name not in self.element_lines[element]: self.element_lines[element].append(name) # make sure the names are strings and x values are numbers return Label(str(name), float(x_value), False, offset, True, rotation=-90, protected=True) def _plot_line(self, name, x_value_in, element=None): label = self._gen_label(name, x_value_in, element) if self.plot_window is None: return for subplot in self.plotting.get_subplots(): self.plotting.add_vline_and_annotate( subplot, float(x_value_in), label) def _plot_line_once(self, subplot, x_value, label): self.plotting.add_vline_and_annotate(subplot, float(x_value), label) def _rm_line(self, name): if self.plot_window is None: return for subplot in self.plotting.get_subplots(): self.plotting.rm_vline_and_annotate(subplot, name) # setup element pop up def _generate_element_widgets(self): self.element_widgets = {} for element in self.ptable.peak_data: if element in ["Gammas", "Electrons"]: continue data = self.ptable.element_data(element) try: data["Gammas"] = self.ptable.peak_data["Gammas"][element] except KeyError: pass widget = PeakSelectorPresenter(PeakSelectorView(data, element)) widget.on_finished(self._update_peak_data) self.element_widgets[element] = widget # interact with periodic table def table_right_clicked(self, item): self.element_widgets[item.symbol].view.show() def table_left_clicked(self, item): if self.ptable.is_selected(item.symbol): self._add_element_lines( item.symbol) else: self._remove_element_lines(item.symbol) def _add_element_lines(self, element, data=None): if data is None: data = self.element_widgets[element].get_checked() if element not in self.element_lines: self.element_lines[element] = [] for name, x_value in iteritems(data): full_name = gen_name(element, name) self._plot_line(full_name, x_value, element) def _remove_element_lines(self, element): if element not in self.element_lines: return names = deepcopy(self.element_lines[element]) for name in names: try: self.element_lines[element].remove(name) self._rm_line(name) except: continue # loading def load_run(self, detector, run): name = "{}; Detector {}".format(run, detector[-1]) if self.plot_window is None: self.plot_window = MultiPlotWindow(str(run)) self.plotting = self.plot_window.multi_plot self.add_detector_to_plot(detector, name) self.plotting.set_all_values() self.plotting.removeSubplotConnection(self.subplotRemoved) self.plot_window.show() # untick detectors if plot window is closed self.plot_window.windowClosedSignal.connect(self._unset_detectors) else: self.add_detector_to_plot(detector, name) self.plot_window.show() self.plot_window.raise_() def loading_finished(self): last_run = self.load_widget.last_loaded_run() if last_run is None: return to_plot = deepcopy([det.isChecked() for det in self.detectors.detectors]) if self.plot_window is None and any(to_plot) is False: return # generate plots - if new run clear old plot(s) and replace it if self.plot_window is None: for name in self.detectors.getNames(): self.detectors.setStateQuietly(name, False) else: for plot in self.plotting.get_subplots(): self.plotting.remove_subplot(plot) for j in range(len(to_plot)): if to_plot[j]: self.detectors.detectors[j].setChecked(True) # detectors def add_detector_to_plot(self, detector, name): self.plotting.add_subplot(detector) for ws in mantid.mtd[name]: self.plotting.plot(detector, ws.getName()) # add current selection of lines for element in self.ptable.selection: self.add_peak_data(element.symbol, detector) def _unset_detectors(self): self.plot_window.windowClosedSignal.disconnect() self.plot_window = None for name in self.detectors.getNames(): self.detectors.setStateQuietly(name, False) # plotting def add_peak_data(self, element, subplot, data=None): # if already selected add to just new plot if data is None: data = self.element_widgets[element].get_checked() for name, x_value in iteritems(data): full_name = gen_name(element, name) label = self._gen_label(full_name, x_value, element) self._plot_line_once(subplot, float(x_value), label) def _update_peak_data(self, element, data=None): if self.ptable.is_selected(element): # remove all of the lines for the element self._remove_element_lines(element) # add the ticked lines to the plot self._add_element_lines(element) else: self._remove_element_lines(element) def add_plot(self, checkbox): detector = checkbox.name last_run = self.load_widget.last_loaded_run() # not using load_last_run prevents two calls to last_loaded_run() if last_run is not None: self.load_run(detector, last_run) if self.peaks.electron.isChecked(): self.add_peak_data("e-", detector, data=self.electron_peaks) def del_plot(self, checkbox): if self.load_widget.last_loaded_run() is not None: self.plotting.remove_subplot(checkbox.name) if not self.plotting.get_subplots() and self.plot_window is not None: self.plot_window.close() self.plot_window = None def subplotRemoved(self, name): # need to change the state without sending signal # as the plot has already been removed self.detectors.setStateQuietly(name, False) if not self.plotting.get_subplots(): self.plot_window.close() self.plot_window = None # sets data file for periodic table def select_data_file(self): filename = QtWidgets.QFileDialog.getOpenFileName() if isinstance(filename, tuple): filename = filename[0] filename = str(filename) if filename: self.ptable.set_peak_datafile(filename) # these are commneted out as they are a bug # see issue 25326 #self._clear_lines_after_data_file_selected() self._generate_element_widgets() #self._generate_element_data() # general checked data def checked_data(self, element, selection, state): for checkbox in selection: checkbox.setChecked(state) self._update_peak_data( element, self.element_widgets[element].get_checked()) # electron Peaks def _get_electron_peaks(self): # make a dict so we can label the peaks electron_dict = {} electron_peaks = self.ptable.peak_data["Electrons"].copy() for peak, intensity in iteritems(electron_peaks): electron_dict[str(peak)] = peak return electron_dict def electrons_checked(self): self._add_element_lines("e-", self.electron_peaks) def electrons_unchecked(self): self._remove_element_lines("e-") # gamma Peaks def gammas_checked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.gamma_checkboxes, True) def gammas_unchecked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.gamma_checkboxes, False) # major peaks def major_peaks_checked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.primary_checkboxes, True) def major_peaks_unchecked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.primary_checkboxes, False) # minor peaks def minor_peaks_checked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.secondary_checkboxes, True) def minor_peaks_unchecked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.secondary_checkboxes, False)
class ElementalAnalysisGui(QtWidgets.QMainWindow): BLUE = 'C0' ORANGE = 'C1' GREEN = 'C2' def __init__(self, parent=None): super(ElementalAnalysisGui, self).__init__(parent) # set menu self.menu = self.menuBar() self.menu.addAction("File") edit_menu = self.menu.addMenu("Edit") edit_menu.addAction("Change Peak Data file", self.select_data_file) self.menu.addAction("Binning") self.menu.addAction("Normalise") # periodic table stuff self.ptable = PeriodicTablePresenter(PeriodicTableView(), PeriodicTableModel()) self.ptable.register_table_lclicked(self.table_left_clicked) self.ptable.register_table_rclicked(self.table_right_clicked) # load stuff self.load_widget = LoadPresenter(LoadView(), LoadModel(), CoLoadModel()) self.load_widget.on_loading_finished(self.loading_finished) # detectors self.detectors = DetectorsPresenter(DetectorsView()) for detector in self.detectors.detectors: detector.on_checkbox_checked(self.add_plot) detector.on_checkbox_unchecked(self.del_plot) # peaks boxes self.peaks = PeaksPresenter(PeaksView()) self.peaks.major.setChecked(True) self.peaks.major.on_checkbox_checked(self.major_peaks_changed) self.peaks.major.on_checkbox_unchecked(self.major_peaks_changed) self.peaks.minor.on_checkbox_checked(self.minor_peaks_changed) self.peaks.minor.on_checkbox_unchecked(self.minor_peaks_changed) self.peaks.gamma.on_checkbox_checked(self.gammas_changed) self.peaks.gamma.on_checkbox_unchecked(self.gammas_changed) self.peaks.electron.on_checkbox_checked(self.electrons_changed) self.peaks.electron.on_checkbox_unchecked(self.electrons_changed) self.peaks.set_deselect_elements_slot(self.deselect_elements) # Line type boxes self.lines = LineSelectorPresenter(LineSelectorView()) self.lines.total.setChecked(True) self.lines.total.on_checkbox_checked(self.line_total_changed) self.lines.total.on_checkbox_unchecked(self.line_total_changed) self.lines.prompt.on_checkbox_checked(self.line_prompt_changed) self.lines.prompt.on_checkbox_unchecked(self.line_prompt_changed) self.lines.delayed.on_checkbox_checked(self.line_delayed_changed) self.lines.delayed.on_checkbox_unchecked(self.line_delayed_changed) # set up self.widget_list = QtWidgets.QVBoxLayout() self.widget_list.addWidget(self.peaks.view) self.widget_list.addWidget(self.lines.view) self.widget_list.addWidget(self.detectors.view) self.widget_list.addWidget(self.load_widget.view) # plotting self.plot_window = None self.num_colors = len(mpl.rcParams['axes.prop_cycle']) self.used_colors = {} # layout self.box = QtWidgets.QHBoxLayout() self.box.addWidget(self.ptable.view) self.box.addLayout(self.widget_list) self.setCentralWidget(QtWidgets.QWidget(self)) self.centralWidget().setLayout(self.box) self.setWindowTitle("Elemental Analysis") self.element_widgets = {} self.element_lines = {} self.electron_peaks = {} self._generate_element_widgets() def get_color(self, element): """ When requesting the colour for a new element, return the first unused colour of the matplotlib default colour cycle (i.e. mpl.rcParams['axes.prop_cycle']). If all colours are used, return the first among the least used ones. That is if C0-4 are all used twice and C5-9 are used once, C5 will be returned. When requesting the colour for an element that is already plotted return the colour of that element. This prevents the same element from being displayed in different colours in separate plots :param element: Chemical symbol of the element that one wants the colour of :return: Matplotlib colour string: C0, C1, ..., C9 to be used as plt.plot(..., color='C3') """ if element in self.used_colors: return self.used_colors[element] occurrences = [ list(self.used_colors.values()).count('C{}'.format(i)) for i in range(self.num_colors) ] color_index = occurrences.index(min(occurrences)) color = "C{}".format(color_index) self.used_colors[element] = color return color def closeEvent(self, event): if self.plot_window is not None: self.plot_window.closeEvent(event) super(ElementalAnalysisGui, self).closeEvent(event) # general functions def _gen_label(self, name, x_value_in, element=None): if element is None: return # check x value is a float try: x_value = float(x_value_in) except: return if name not in self.element_lines[element]: self.element_lines[element].append(name) # make sure the names are strings and x values are numbers return Label(str(name), x_value, False, offset, True, rotation=-90, protected=True) def _plot_line(self, name, x_value_in, color, element=None): label = self._gen_label(name, x_value_in, element) if self.plot_window is None: return for subplot in self.plotting.get_subplots(): self._plot_line_once(subplot, x_value_in, label, color) def _plot_line_once(self, subplot, x_value, label, color): self.plotting.add_vline_and_annotate(subplot, x_value, label, color) def _rm_line(self, name): if self.plot_window is None: return for subplot in self.plotting.get_subplots(): self.plotting.rm_vline_and_annotate(subplot, name) # setup element pop up def _generate_element_widgets(self): self.element_widgets = {} for element in self.ptable.peak_data: data = self.ptable.element_data(element) widget = PeakSelectorPresenter(PeakSelectorView(data, element)) widget.on_finished(self._update_peak_data) self.element_widgets[element] = widget # interact with periodic table def table_right_clicked(self, item): self.element_widgets[item.symbol].view.show() def table_left_clicked(self, item): if self.ptable.is_selected(item.symbol): self._add_element_lines(item.symbol) else: self._remove_element_lines(item.symbol) def _add_element_lines(self, element, data=None): if data is None: data = self.element_widgets[element].get_checked() if element not in self.element_lines: self.element_lines[element] = [] # Select a different color, if all used then use the first color = self.get_color(element) for name, x_value in data.items(): try: x_value = float(x_value) except ValueError: continue full_name = gen_name(element, name) if full_name not in self.element_lines[element]: self.element_lines[element].append(full_name) self._plot_line(full_name, x_value, color, element) def _remove_element_lines(self, element): if element not in self.element_lines: return names = deepcopy(self.element_lines[element]) for name in names: try: self.element_lines[element].remove(name) self._rm_line(name) if not self.element_lines[element]: del self.element_lines[element] if element in self.used_colors: del self.used_colors[element] except: continue if element in self.element_lines and not self.element_lines[element]: del self.element_lines[element] # loading def load_run(self, detector, run): name = "{}; Detector {}".format(run, detector[-1]) if self.plot_window is None: self.plot_window = MultiPlotWindow(str(run)) self.plotting = self.plot_window.multi_plot self.add_detector_to_plot(detector, name) self.plotting.set_all_values() self.plotting.remove_subplot_connection(self.subplot_removed) self.plotting.remove_line_connection(self.uncheck_on_removed) self.plot_window.show() # untick detectors if plot window is closed self.plot_window.windowClosedSignal.connect(self._unset_detectors) else: self.add_detector_to_plot(detector, name) self.plot_window.show() self.plot_window.raise_() def loading_finished(self): last_run = self.load_widget.last_loaded_run() if last_run is None: return # check all detectors are loaded num_detectors = self.load_widget.get_run_num_loaded_detectors(last_run) for j, detector in enumerate(self.detectors.getNames()): if j < num_detectors: self.detectors.enableDetector(detector) else: # disable checkbox and uncheck box self.detectors.disableDetector(detector) self.detectors.setStateQuietly(detector, False) to_plot = deepcopy( [det.isChecked() for det in self.detectors.detectors]) if self.plot_window is None and any(to_plot) is False: return # generate plots - if new run clear old plot(s) and replace it if self.plot_window is None: for name in self.detectors.getNames(): self.detectors.setStateQuietly(name, False) else: for plot in self.plotting.get_subplots(): self.plotting.remove_subplot(plot) for j in range(len(to_plot)): if to_plot[j]: self.detectors.detectors[j].setChecked(True) # detectors def add_detector_to_plot(self, detector, name): self.plotting.add_subplot(detector) ws = mantid.mtd[name] ws.setYUnit('Counts') # find correct detector number from the workspace group run if self.lines.total.isChecked(): self.plotting.plot(detector, ws.name(), spec_num=spectrum_index["Total"], color=self.BLUE) if self.lines.prompt.isChecked(): self.plotting.plot(detector, ws.name(), spec_num=spectrum_index["Prompt"], color=self.ORANGE) if self.lines.delayed.isChecked(): self.plotting.plot(detector, ws.name(), spec_num=spectrum_index["Delayed"], color=self.GREEN) # add current selection of lines for element in self.ptable.selection: self.add_peak_data(element.symbol, detector) def _unset_detectors(self): self.plot_window.windowClosedSignal.disconnect() self.plot_window = None for name in self.detectors.getNames(): self.detectors.setStateQuietly(name, False) self.uncheck_detectors_if_no_line_plotted() # plotting def add_peak_data(self, element, subplot, data=None): # if already selected add to just new plot if data is None: data = self.element_widgets[element].get_checked() color = self.get_color(element) for name, x_value in data.items(): if isinstance(x_value, float): full_name = gen_name(element, name) label = self._gen_label(full_name, x_value, element) self._plot_line_once(subplot, x_value, label, color) def _update_peak_data(self, element): if self.ptable.is_selected(element): # remove all of the lines for the element self._remove_element_lines(element) # add the ticked lines to the plot self._add_element_lines(element) else: self._remove_element_lines(element) def add_plot(self, checkbox): detector = checkbox.name last_run = self.load_widget.last_loaded_run() # not using load_last_run prevents two calls to last_loaded_run() if last_run is not None: self.load_run(detector, last_run) def del_plot(self, checkbox): if self.load_widget.last_loaded_run() is not None: self.plotting.remove_subplot(checkbox.name) if not self.plotting.get_subplots( ) and self.plot_window is not None: self.plot_window.close() self.plot_window = None def subplot_removed(self, name): # need to change the state without sending signal # as the plot has already been removed self.detectors.setStateQuietly(name, False) if not self.plotting.get_subplots(): self.plot_window.close() self.plot_window = None # sets data file for periodic table def select_data_file(self): old_lines = deepcopy(list(self.element_lines.keys())) filename = QtWidgets.QFileDialog.getOpenFileName() if isinstance(filename, tuple): filename = filename[0] filename = str(filename) if filename: self.ptable.set_peak_datafile(filename) try: self._generate_element_widgets() except ValueError: message_box.warning( 'The file does not contain correctly formatted data, resetting to default data file.' 'See "https://docs.mantidproject.org/nightly/interfaces/' 'Muon%20Elemental%20Analysis.html" for more information.') self.ptable.set_peak_datafile(None) self._generate_element_widgets() for element in old_lines: if element in self.element_widgets.keys(): self.ptable.select_element(element) else: self._remove_element_lines(element) self._update_checked_data() def _update_checked_data(self): self.major_peaks_changed(self.peaks.major) self.minor_peaks_changed(self.peaks.minor) self.gammas_changed(self.peaks.gamma) self.electrons_changed(self.peaks.electron) # general checked data def checked_data(self, element, selection, state): for checkbox in selection: checkbox.setChecked(state) self._update_peak_data(element) def electrons_changed(self, electron_peaks): for element, selector in self.element_widgets.items(): self.checked_data(element, selector.electron_checkboxes, electron_peaks.isChecked()) def gammas_changed(self, gamma_peaks): for element, selector in self.element_widgets.items(): self.checked_data(element, selector.gamma_checkboxes, gamma_peaks.isChecked()) def major_peaks_changed(self, major_peaks): for element, selector in self.element_widgets.items(): self.checked_data(element, selector.primary_checkboxes, major_peaks.isChecked()) def minor_peaks_changed(self, minor_peaks): for element, selector in self.element_widgets.items(): self.checked_data(element, selector.secondary_checkboxes, minor_peaks.isChecked()) def deselect_elements(self): self.peaks.disable_deselect_elements_btn() for element in self.element_widgets.keys(): self.ptable.deselect_element(element) self._remove_element_lines(element) self.peaks.enable_deselect_elements_btn() def add_line_by_type(self, run, _type): # Ensure all detectors are enabled last_run = self.load_widget.last_loaded_run() for i, detector in enumerate(self.detectors.detectors): if i < self.load_widget.get_run_num_loaded_detectors(last_run): if not detector.isEnabled(): detector.setEnabled(True) if self.plot_window is None: return # Plot the correct line type on all open subplots if _type == 'Total': color = self.BLUE elif _type == 'Prompt': color = self.ORANGE else: color = self.GREEN for subplot in self.plotting.get_subplots(): name = '{}; Detector {}'.format(run, subplot[-1]) ws = mantid.mtd[name] self.plotting.plot(subplot, ws.name(), spec_num=spectrum_index[_type], color=color) def remove_line_type(self, run, _type): if self.plot_window is None: self.uncheck_detectors_if_no_line_plotted() return # Remove the correct line type on all open subplots for subplot in self.plotting.get_subplots(): name = '{}; Detector {}'.format(run, subplot[-1]) ws = mantid.mtd[name] self.plotting.remove_line(subplot, ws.name(), spec=spectrum_index[_type]) # If no line type is selected do not allow plotting self.uncheck_detectors_if_no_line_plotted() def uncheck_detectors_if_no_line_plotted(self): last_run = self.load_widget.last_loaded_run() if not any([ self.lines.total.isChecked(), self.lines.prompt.isChecked(), self.lines.delayed.isChecked() ]): for i, detector in enumerate(self.detectors.detectors): if i < self.load_widget.get_run_num_loaded_detectors(last_run): detector.setEnabled(False) # When removing a line with the remove window uncheck the line here def uncheck_on_removed(self, removed_lines): if sum([ 1 if detector.isChecked() else 0 for detector in self.detectors.detectors ]) > 1: return for line in removed_lines: if 'Total' in line: self.lines.total.blockSignals(True) self.lines.total.setChecked(False) self.lines.total.blockSignals(False) if 'Prompt' in line: self.lines.prompt.blockSignals(True) self.lines.prompt.setChecked(False) self.lines.prompt.blockSignals(False) if 'Delayed' in line: self.lines.delayed.blockSignals(True) self.lines.delayed.setChecked(False) self.lines.delayed.blockSignals(False) self.uncheck_detectors_if_no_line_plotted() # Line total def line_total_changed(self, line_total): self.lines.total.setChecked(line_total.isChecked()) if line_total.isChecked(): self.add_line_by_type(self.load_widget.last_loaded_run(), 'Total') else: self.remove_line_type(self.load_widget.last_loaded_run(), 'Total') # Line prompt def line_prompt_changed(self, line_prompt): self.lines.prompt.setChecked(line_prompt.isChecked()) if line_prompt.isChecked(): self.add_line_by_type(self.load_widget.last_loaded_run(), 'Prompt') else: self.remove_line_type(self.load_widget.last_loaded_run(), 'Prompt') # Line delayed def line_delayed_changed(self, line_delayed): self.lines.delayed.setChecked(line_delayed.isChecked()) if line_delayed.isChecked(): self.add_line_by_type(self.load_widget.last_loaded_run(), 'Delayed') else: self.remove_line_type(self.load_widget.last_loaded_run(), 'Delayed')
class ElementalAnalysisGui(QtWidgets.QMainWindow): def __init__(self, parent=None): super(ElementalAnalysisGui, self).__init__(parent) # set menu self.menu = self.menuBar() self.menu.addAction("File") edit_menu = self.menu.addMenu("Edit") edit_menu.addAction("Change Peak Data file", self.select_data_file) self.menu.addAction("Binning") self.menu.addAction("Normalise") # periodic table stuff self.ptable = PeriodicTablePresenter(PeriodicTableView(), PeriodicTableModel()) self.ptable.register_table_lclicked(self.table_left_clicked) self.ptable.register_table_rclicked(self.table_right_clicked) # load stuff self.load_widget = LoadPresenter(LoadView(), LoadModel(), CoLoadModel()) self.load_widget.on_loading_finished(self.loading_finished) # detectors self.detectors = DetectorsPresenter(DetectorsView()) for detector in self.detectors.detectors: detector.on_checkbox_checked(self.add_plot) detector.on_checkbox_unchecked(self.del_plot) # peaks boxes self.peaks = PeaksPresenter(PeaksView()) self.peaks.major.setChecked(True) self.peaks.major.on_checkbox_checked(self.major_peaks_checked) self.peaks.major.on_checkbox_unchecked(self.major_peaks_unchecked) self.peaks.minor.on_checkbox_checked(self.minor_peaks_checked) self.peaks.minor.on_checkbox_unchecked(self.minor_peaks_unchecked) self.peaks.gamma.on_checkbox_checked(self.gammas_checked) self.peaks.gamma.on_checkbox_unchecked(self.gammas_unchecked) self.peaks.electron.on_checkbox_checked(self.electrons_checked) self.peaks.electron.on_checkbox_unchecked(self.electrons_unchecked) # set up self.widget_list = QtWidgets.QVBoxLayout() self.widget_list.addWidget(self.peaks.view) self.widget_list.addWidget(self.detectors.view) self.widget_list.addWidget(self.load_widget.view) # plotting self.plot_window = None self.colors = ['b', 'g', 'r', 'y', 'c', 'm', 'b'] self.color_index = 0 # layout self.box = QtWidgets.QHBoxLayout() self.box.addWidget(self.ptable.view) self.box.addLayout(self.widget_list) self.setCentralWidget(QtWidgets.QWidget(self)) self.centralWidget().setLayout(self.box) self.setWindowTitle("Elemental Analysis") self.element_widgets = {} self.element_lines = {} self.electron_peaks = self._get_electron_peaks() self._generate_element_widgets() # Return an unused colour, if all used then start with the first one def get_color(self): color = self.colors[self.color_index] self.color_index = (self.color_index + 1) % len(self.colors) return color def closeEvent(self, event): if self.plot_window is not None: self.plot_window.closeEvent(event) super(ElementalAnalysisGui, self).closeEvent(event) # general functions def _gen_label(self, name, x_value_in, element=None): if element is None: return # check x value is a float x_value = 0.0 try: x_value = float(x_value_in) except: return if name not in self.element_lines[element]: self.element_lines[element].append(name) # make sure the names are strings and x values are numbers return Label(str(name), float(x_value), False, offset, True, rotation=-90, protected=True) def _plot_line(self, name, x_value_in, color, element=None): label = self._gen_label(name, x_value_in, element) if self.plot_window is None: return for subplot in self.plotting.get_subplots(): self._plot_line_once(subplot, float(x_value_in), label, color) def _plot_line_once(self, subplot, x_value, label, color): self.plotting.add_vline_and_annotate(subplot, float(x_value), label, color) def _rm_line(self, name): if self.plot_window is None: return for subplot in self.plotting.get_subplots(): self.plotting.rm_vline_and_annotate(subplot, name) # setup element pop up def _generate_element_widgets(self): self.element_widgets = {} for element in self.ptable.peak_data: if element in ["Gammas", "Electrons"]: continue data = self.ptable.element_data(element) try: data["Gammas"] = self.ptable.peak_data["Gammas"][element] except KeyError: pass widget = PeakSelectorPresenter(PeakSelectorView(data, element)) widget.on_finished(self._update_peak_data) self.element_widgets[element] = widget # interact with periodic table def table_right_clicked(self, item): self.element_widgets[item.symbol].view.show() def table_left_clicked(self, item): if self.ptable.is_selected(item.symbol): self._add_element_lines(item.symbol) else: self._remove_element_lines(item.symbol) def _add_element_lines(self, element, data=None): if data is None: data = self.element_widgets[element].get_checked() if element not in self.element_lines: self.element_lines[element] = [] # Select a different color, if all used then use the first color = self.get_color() for name, x_value in iteritems(data): full_name = gen_name(element, name) self._plot_line(full_name, x_value, color, element) def _remove_element_lines(self, element): if element not in self.element_lines: return names = deepcopy(self.element_lines[element]) for name in names: try: self.element_lines[element].remove(name) self._rm_line(name) except: continue # loading def load_run(self, detector, run): name = "{}; Detector {}".format(run, detector[-1]) if self.plot_window is None: self.plot_window = MultiPlotWindow(str(run)) self.plotting = self.plot_window.multi_plot self.add_detector_to_plot(detector, name) self.plotting.set_all_values() self.plotting.removeSubplotConnection(self.subplotRemoved) self.plot_window.show() # untick detectors if plot window is closed self.plot_window.windowClosedSignal.connect(self._unset_detectors) else: self.add_detector_to_plot(detector, name) self.plot_window.show() self.plot_window.raise_() def loading_finished(self): last_run = self.load_widget.last_loaded_run() if last_run is None: return to_plot = deepcopy( [det.isChecked() for det in self.detectors.detectors]) if self.plot_window is None and any(to_plot) is False: return # generate plots - if new run clear old plot(s) and replace it if self.plot_window is None: for name in self.detectors.getNames(): self.detectors.setStateQuietly(name, False) else: for plot in self.plotting.get_subplots(): self.plotting.remove_subplot(plot) for j in range(len(to_plot)): if to_plot[j]: self.detectors.detectors[j].setChecked(True) # detectors def add_detector_to_plot(self, detector, name): self.plotting.add_subplot(detector) for ws in mantid.mtd[name]: self.plotting.plot(detector, ws.getName()) # add current selection of lines for element in self.ptable.selection: self.add_peak_data(element.symbol, detector) def _unset_detectors(self): self.plot_window.windowClosedSignal.disconnect() self.plot_window = None for name in self.detectors.getNames(): self.detectors.setStateQuietly(name, False) # plotting def add_peak_data(self, element, subplot, data=None): # if already selected add to just new plot if data is None: data = self.element_widgets[element].get_checked() color = self.get_color() for name, x_value in iteritems(data): full_name = gen_name(element, name) label = self._gen_label(full_name, x_value, element) self._plot_line_once(subplot, float(x_value), label, color) def _update_peak_data(self, element, data=None): if self.ptable.is_selected(element): # remove all of the lines for the element self._remove_element_lines(element) # add the ticked lines to the plot self._add_element_lines(element) else: self._remove_element_lines(element) def add_plot(self, checkbox): detector = checkbox.name last_run = self.load_widget.last_loaded_run() # not using load_last_run prevents two calls to last_loaded_run() if last_run is not None: self.load_run(detector, last_run) if self.peaks.electron.isChecked(): self.add_peak_data("e-", detector, data=self.electron_peaks) def del_plot(self, checkbox): if self.load_widget.last_loaded_run() is not None: self.plotting.remove_subplot(checkbox.name) if not self.plotting.get_subplots( ) and self.plot_window is not None: self.plot_window.close() self.plot_window = None def subplotRemoved(self, name): # need to change the state without sending signal # as the plot has already been removed self.detectors.setStateQuietly(name, False) if not self.plotting.get_subplots(): self.plot_window.close() self.plot_window = None # sets data file for periodic table def select_data_file(self): filename = QtWidgets.QFileDialog.getOpenFileName() if isinstance(filename, tuple): filename = filename[0] filename = str(filename) if filename: self.ptable.set_peak_datafile(filename) # these are commneted out as they are a bug # see issue 25326 #self._clear_lines_after_data_file_selected() self._generate_element_widgets() #self._generate_element_data() # general checked data def checked_data(self, element, selection, state): for checkbox in selection: checkbox.setChecked(state) self._update_peak_data(element, self.element_widgets[element].get_checked()) # electron Peaks def _get_electron_peaks(self): # make a dict so we can label the peaks electron_dict = {} electron_peaks = self.ptable.peak_data["Electrons"].copy() for peak, intensity in iteritems(electron_peaks): electron_dict[str(peak)] = peak return electron_dict def electrons_checked(self): self._add_element_lines("e-", self.electron_peaks) def electrons_unchecked(self): self._remove_element_lines("e-") # gamma Peaks def gammas_checked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.gamma_checkboxes, True) def gammas_unchecked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.gamma_checkboxes, False) # major peaks def major_peaks_checked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.primary_checkboxes, True) def major_peaks_unchecked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.primary_checkboxes, False) # minor peaks def minor_peaks_checked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.secondary_checkboxes, True) def minor_peaks_unchecked(self): for element, selector in iteritems(self.element_widgets): self.checked_data(element, selector.secondary_checkboxes, False)