Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple plotting GUI #24338

Merged
merged 20 commits into from Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
703e9d1
refs #24036 basic multi plotting has been refactored
AnthonyLim23 Nov 19, 2018
ee2da0a
refs #24036 removed unneeded files for multi plotting
AnthonyLim23 Nov 19, 2018
bdfb788
refs #24036 subplot GUI now has x,y controls
AnthonyLim23 Nov 20, 2018
ca4d639
refs #24036 subplot GUI now has working error tick and autoscale
AnthonyLim23 Nov 20, 2018
8d152fb
refs #24036 plot selector in multi plotting populated
AnthonyLim23 Nov 26, 2018
9060d5f
refs #24036 autoscale and zoom (except with errors) in multi plotting
AnthonyLim23 Nov 26, 2018
d433ee7
refs #24036 multi plotting bug fix for errors
AnthonyLim23 Nov 30, 2018
30bd6f4
refs #24036 auto scale works with multi plot
AnthonyLim23 Dec 3, 2018
0199375
refs #24036 auto scale works for multi plotting
AnthonyLim23 Dec 11, 2018
614149f
refs #24036 added autocomplete box to multi plot
AnthonyLim23 Dec 13, 2018
40b8080
refs #24036 merge master
AnthonyLim23 Dec 14, 2018
e48d3da
refs #24036 restored elemental analysis
AnthonyLim23 Dec 14, 2018
3813c14
refs #24036 flake8 fixes for multiplotting
AnthonyLim23 Dec 14, 2018
a9f1755
refs #24036 rm unused code from multiplot
AnthonyLim23 Dec 14, 2018
9142174
refs #24036 rm unused code from multiplot
AnthonyLim23 Dec 14, 2018
57b63e3
refs #24036 rm unused code from multiplot - flake8
AnthonyLim23 Dec 14, 2018
240bff7
refs #24036 fixed flake8 on multiplot
AnthonyLim23 Dec 14, 2018
8c387de
refs #24036 added qucikedit tests v1
AnthonyLim23 Dec 17, 2018
f9d93f2
refs #24036 unit tests for multi plotting
AnthonyLim23 Dec 19, 2018
1c32fcb
refs #24036 made multiplotwidget test python3 compatible
AnthonyLim23 Dec 19, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/CMakeLists.txt
Expand Up @@ -131,6 +131,7 @@ set ( TEST_PYQT4_FILES
# Additional tests
add_subdirectory(test/directtools)
add_subdirectory(test/isis_powder)
add_subdirectory(test/MultiPlotting)
add_subdirectory(test/Muon)
add_subdirectory(test/SANS)
add_subdirectory(test/TOFTOF)
Expand Down
6 changes: 6 additions & 0 deletions scripts/MultiPlotting/AxisChanger/__init__.py
@@ -0,0 +1,6 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
39 changes: 39 additions & 0 deletions scripts/MultiPlotting/AxisChanger/axis_changer_presenter.py
@@ -0,0 +1,39 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +


class AxisChangerPresenter(object):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this class strictly needed it seems to just simply forward everything to the view?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be useful if we ever decide to restrain acceptable inputs. We could then do the logic in here. However, yes it is unneeded for this case.


def __init__(self, view):
self.view = view

def set_enabled(self, state):
self.view.set_enabled(state)

def hide(self):
self.view.hide()

def show(self):
self.view.show()

def get_bounds(self):
return self.view.get_bounds()

def set_bounds(self, bounds):
self.view.set_bounds(bounds)

def clear_bounds(self):
self.view.clear_bounds()

def on_bound_changed(self, slot):
self.view.on_bound_changed(slot)

def unreg_on_bound_changed(self, slot):
try:
self.view.unreg_bound_changed(slot)
except TypeError:
return
70 changes: 70 additions & 0 deletions scripts/MultiPlotting/AxisChanger/axis_changer_view.py
@@ -0,0 +1,70 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
from qtpy import QtGui, QtCore, QtWidgets


class AxisChangerView(QtWidgets.QWidget):
sig_bound_changed = QtCore.Signal(object)

def __init__(self, label):
super(AxisChangerView, self).__init__()
layout = QtWidgets.QHBoxLayout()
self._label = QtWidgets.QLabel(label)
layout.addWidget(self._label)

self.lower_bound = QtWidgets.QLineEdit()
self.lower_bound.setValidator(QtGui.QDoubleValidator())
self.lower_bound.returnPressed.connect(self._bound_changed)

self.upper_bound = QtWidgets.QLineEdit()
self.upper_bound.setValidator(QtGui.QDoubleValidator())
self.upper_bound.returnPressed.connect(self._bound_changed)

layout.addWidget(self.lower_bound)
self._to = QtWidgets.QLabel("to")
layout.addWidget(self._to)
layout.addWidget(self.upper_bound)
self.setLayout(layout)

def set_enabled(self, state):
self.lower_bound.setDisabled(state)
self.upper_bound.setDisabled(state)

def show(self):
self.lower_bound.show()
self.upper_bound.show()
self._label.show()
self._to.show()

def hide(self):
self.lower_bound.hide()
self.upper_bound.hide()
self._label.hide()
self._to.hide()

def get_bounds(self):
bounds = [self.lower_bound, self.upper_bound]
return [float(str(bound.text())) if bound.text()
else 0 for bound in bounds]

def set_bounds(self, bounds):
lower, upper = [str(bound) for bound in bounds]
self.lower_bound.setText(lower)
self.upper_bound.setText(upper)

def clear_bounds(self):
self.lower_bound.clear()
self.upper_bound.clear()

def _bound_changed(self):
self.sig_bound_changed.emit(self.get_bounds())

def on_bound_changed(self, slot):
self.sig_bound_changed.connect(slot)

def unreg_bound_changed(self, slot):
self.sig_bound_changed.disconnect(slot)
6 changes: 6 additions & 0 deletions scripts/MultiPlotting/QuickEdit/__init__.py
@@ -0,0 +1,6 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
53 changes: 53 additions & 0 deletions scripts/MultiPlotting/QuickEdit/quickEdit_presenter.py
@@ -0,0 +1,53 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
from __future__ import absolute_import, print_function


class QuickEditPresenter(object):

def __init__(self, view ):
self._view = view

@property
def widget(self):
return self._view

def connect_autoscale_changed(self, slot):
self._view.connect_autoscale_changed(slot)

def connect_errors_changed(self, slot):
self._view.connect_errors_changed(slot)

def connect_x_range_changed(self, slot):
self._view.connect_x_range_changed(slot)

def connect_y_range_changed(self, slot):
self._view.connect_y_range_changed(slot)

def connect_plot_selection(self, slot):
self._view.connect_plot_selection(slot)

def add_subplot(self, name):
current = self._view.current_selection()
self._view.add_subplot(name)
index = self._view.find_index(current)
self._view.set_index(index)

def all(self):
return [self._view.plot_at_index(index) for index in range(1, self._view.number_of_plots())]

def set_plot_x_range(self, range):
self._view.set_plot_x_range(range)

def set_plot_y_range(self, range):
self._view.set_plot_y_range(range)

def set_errors(self, state):
previous = self._view.get_errors()
if previous == state:
return
self._view.set_errors(state)
121 changes: 121 additions & 0 deletions scripts/MultiPlotting/QuickEdit/quickEdit_view.py
@@ -0,0 +1,121 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
from __future__ import absolute_import, print_function
from qtpy import QtWidgets, QtCore
import qtpy
from MultiPlotting.AxisChanger.axis_changer_presenter import AxisChangerPresenter
from MultiPlotting.AxisChanger.axis_changer_view import AxisChangerView


class QuickEditView(QtWidgets.QWidget):
error_signal = QtCore.Signal(object)

def __init__(self, subcontext, parent=None):
super(QuickEditView, self).__init__(parent)

button_layout = QtWidgets.QHBoxLayout()
self.plot_selector = QtWidgets.QComboBox()
self.plot_selector.setEditable(True)
self.plot_selector.completer().setCompletionMode(
QtWidgets.QCompleter.PopupCompletion)
if qtpy.PYQT5:
self.plot_selector.completer().setFilterMode(
QtCore.Qt.MatchContains)

self.plot_selector.addItem("All")
self.x_axis_changer = AxisChangerPresenter(AxisChangerView("X"))

self.autoscale = QtWidgets.QPushButton("Autoscale y")
self.autoscale.setStyleSheet("background-color:lightgrey")

self.y_axis_changer = AxisChangerPresenter(AxisChangerView("Y"))

self.errors = QtWidgets.QCheckBox("Errors")
self.errors.stateChanged.connect(self._emit_errors)

button_layout.addWidget(self.plot_selector)
button_layout.addWidget(self.x_axis_changer.view)
button_layout.addWidget(self.autoscale)
button_layout.addWidget(self.y_axis_changer.view)
button_layout.addWidget(self.errors)
self.setLayout(button_layout)

""" plot selection """

def current_selection(self):
return self.plot_selector.currentText()

def find_index(self, name):
return self.plot_selector.findText(name)

def set_index(self, index):
self.plot_selector.setCurrentIndex(index)

def plot_at_index(self, index):
return self.plot_selector.itemText(index)

def number_of_plots(self):
return self.plot_selector.count()

def add_subplot(self, name):
self.plot_selector.addItem(name)

def connect_plot_selection(self, slot):
self.plot_selector.currentIndexChanged.connect(slot)

""" x axis selection """

def connect_x_range_changed(self, slot):
self.x_axis_changer.on_bound_changed(slot)

def set_plot_x_range(self, range):
self.x_axis_changer.set_bounds(range)

""" y axis selection """

def connect_y_range_changed(self, slot):
self.y_axis_changer.on_bound_changed(slot)

def set_plot_y_range(self, range):
self.y_axis_changer.set_bounds(range)

def get_y_bounds(self):
return self.y_axis_changer.get_bounds()

""" auto scale selection """

def connect_autoscale_changed(self, slot):
self.autoscale.clicked.connect(slot)

""" errors selection """

# need our own signal that sends a bool

def _emit_errors(self):
state = self.get_errors()
self.error_signal.emit(state)

def connect_errors_changed(self, slot):
self.error_signal.connect(slot)

def set_errors(self, state):
self.errors.setChecked(state)

def get_errors(self):
return self.errors.isChecked()

""" load/save from/to context """

def loadFromContext(self, context):
self.x_axis_changer.set_bounds(context["x bounds"])
self.y_axis_changer.set_bounds(context["y bounds"])

def getSubContext(self):
subcontext = {}
subcontext["x bounds"] = self.x_axis_changer.get_bounds()
subcontext["y bounds"] = self.y_axis_changer.get_bounds()
return subcontext
60 changes: 60 additions & 0 deletions scripts/MultiPlotting/QuickEdit/quickEdit_widget.py
@@ -0,0 +1,60 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
from __future__ import absolute_import, print_function


from MultiPlotting.QuickEdit.quickEdit_view import QuickEditView
from MultiPlotting.QuickEdit.quickEdit_presenter import QuickEditPresenter


class QuickEditWidget(object):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this class needed ? as it seems to mainly forward all of it's methods straight to methods on the presenter with the same names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something I have to clean up the code at import. It is a wrapper so we only have to import this if we want to use the widget. As opposed to importing the view, presenter and model.


def __init__(self, parent=None):
view = QuickEditView(None, parent)
self._presenter = QuickEditPresenter(view)

@property
def widget(self):
return self._presenter.widget
""" connect statements"""

def connect_autoscale_changed(self, slot):
self._presenter.connect_autoscale_changed(slot)

def connect_errors_changed(self, slot):
self._presenter.connect_errors_changed(slot)

def connect_x_range_changed(self, slot):
self._presenter.connect_x_range_changed(slot)

def connect_y_range_changed(self, slot):
self._presenter.connect_y_range_changed(slot)

def connect_plot_selection(self, slot):
self._presenter.connect_plot_selection(slot)
# add subplot

def add_subplot(self, name):
self._presenter.add_subplot(name)

def get_selection(self):
name = self._presenter.widget.current_selection()
if name == "All":
return self._presenter.all()
return [name]

def set_plot_x_range(self, range):
self._presenter.set_plot_x_range(range)

def set_plot_y_range(self, range):
self._presenter.set_plot_y_range(range)

def set_errors(self, state):
self._presenter.set_errors(state)

def set_mock(self,mock_presenter):
self._presenter = mock_presenter
6 changes: 6 additions & 0 deletions scripts/MultiPlotting/__init__.py
@@ -0,0 +1,6 @@
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +