Skip to content
Snippets Groups Projects
Commit d1b8b040 authored by WHITFIELDRE email's avatar WHITFIELDRE email
Browse files

Start of sliceviewer

parent 03814462
No related branches found
No related tags found
No related merge requests found
# 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 +
# This file is part of the mantid workbench.
#
#
# 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 +
# This file is part of the mantid workbench.
#
#
from __future__ import (absolute_import, division, print_function)
from qtpy.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QPushButton, QSlider, QDoubleSpinBox
from qtpy.QtCore import Qt, Signal
from mantid.py3compat.enum import Enum
class State(Enum):
X = 0
Y = 1
NONE = 2
class DimensionWidget(QWidget):
dimensionsChanged = Signal()
valueChanged = Signal()
"""
Hold all the individual dimensions
from mantidqt.widgets.sliceviewer.dimensionwidget import DimensionWidget
from qtpy.QtWidgets import QApplication
app = QApplication([])
dims = [{'minimum':-1.1, 'number_of_bins':11, 'width':0.2, 'name':'Dim0', 'units':'A'},
{'minimum':-2.1, 'number_of_bins':21, 'width':0.2, 'name':'Dim1', 'units':'B'},
{'minimum':-10.05, 'number_of_bins':201, 'width':0.1, 'name':'Dim2', 'units':'C'}]
window = DimensionWidget(dims)
window.show()
app.exec_()
"""
def __init__(self, dims_info, parent=None):
super(DimensionWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.dims = []
for n, dim in enumerate(dims_info):
if n == 0:
state = State.X
elif n == 1:
state = State.Y
else:
state = State.NONE
self.dims.append(Dimension(dim, number=n, state=state, parent=self))
for widget in self.dims:
widget.stateChanged.connect(self.change_dims)
widget.valueChanged.connect(self.valueChanged)
self.layout.addWidget(widget)
def change_dims(self, number):
states = [d.get_state() for n, d in enumerate(self.dims)]
if states.count(State.X) == 0:
for n, d in enumerate(self.dims):
if n != number and d.get_state() == State.Y:
d.set_state(State.X)
elif states.count(State.Y) == 0:
for n, d in enumerate(self.dims):
if n != number and d.get_state() == State.X:
d.set_state(State.Y)
elif states.count(State.X) == 2:
for n, d in enumerate(self.dims):
if n != number and d.get_state() == State.X:
d.set_state(State.NONE)
elif states.count(State.Y) == 2:
for n, d in enumerate(self.dims):
if n != number and d.get_state() == State.Y:
d.set_state(State.NONE)
self.dimensionsChanged.emit()
def get_slicepoint(self):
return [None if d.get_state() in (State.X, State.Y) else d.get_value() for d in self.dims]
class Dimension(QWidget):
stateChanged = Signal(int)
valueChanged = Signal()
"""
pass in dimension
state: one of (State.X, State.Y, State.NONE)
Can be run independently by:
from mantidqt.widgets.sliceviewer.dimensionwidget import Dimension
from qtpy.QtWidgets import QApplication
app = QApplication([])
window = Dimension({'minimum':-1.1, 'number_of_bins':11, 'width':0.2, 'name':'Dim0', 'units':'A'})
window.show()
app.exec_()
"""
def __init__(self, dim_info, number=0, state=State.NONE, parent=None):
super(Dimension, self).__init__(parent)
self.minimum = dim_info['minimum']
self.nbins = dim_info['number_of_bins']
self.width = dim_info['width']
self.number = number
self.layout = QHBoxLayout(self)
self.name = QLabel(dim_info['name'])
self.units = QLabel(dim_info['units'])
self.x = QPushButton('X')
self.x.setFixedSize(32,32)
self.x.setCheckable(True)
self.x.clicked.connect(self.x_clicked)
self.y = QPushButton('Y')
self.y.setFixedSize(32,32)
self.y.setCheckable(True)
self.y.clicked.connect(self.y_clicked)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, self.nbins-1)
self.slider.valueChanged.connect(self.slider_changed)
self.spinbox = QDoubleSpinBox()
self.spinbox.setDecimals(3)
self.spinbox.setRange(self.get_bin_center(0), self.get_bin_center(self.nbins-1))
self.spinbox.setSingleStep(self.width)
self.spinbox.valueChanged.connect(self.spinbox_changed)
self.layout.addWidget(self.name)
self.layout.addWidget(self.x)
self.layout.addWidget(self.y)
self.layout.addWidget(self.slider, stretch=1)
self.layout.addStretch(0)
self.layout.addWidget(self.spinbox)
self.layout.addWidget(self.units)
self.set_value(0)
self.set_state(state)
def set_state(self, state):
self.state = state
if self.state == State.X:
self.x.setChecked(True)
self.y.setChecked(False)
self.slider.hide()
self.spinbox.hide()
self.units.hide()
elif self.state == State.Y:
self.x.setChecked(False)
self.y.setChecked(True)
self.slider.hide()
self.spinbox.hide()
self.units.hide()
else:
self.x.setChecked(False)
self.y.setChecked(False)
self.slider.show()
self.spinbox.show()
self.units.show()
def get_state(self):
return self.state
def x_clicked(self):
old_state = self.state
self.set_state(State.X)
if self.state != old_state:
self.stateChanged.emit(self.number)
def y_clicked(self):
old_state = self.state
self.set_state(State.Y)
if self.state != old_state:
self.stateChanged.emit(self.number)
def spinbox_changed(self):
self.value = self.spinbox.value()
self.update_slider()
self.valueChanged.emit()
def slider_changed(self):
self.value = self.get_bin_center(self.slider.value())
self.update_spinbox()
self.valueChanged.emit()
def get_bin_center(self, n):
return (n+0.5)*self.width+self.minimum
def update_slider(self):
i = (self.value-self.minimum)/self.width
self.slider.setValue(int(min(max(i, 0), self.nbins-1)))
def update_spinbox(self):
self.spinbox.setValue(self.value)
def set_value(self, value):
self.value = value
self.update_slider()
self.update_spinbox()
def get_value(self):
return self.value
# 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 +
# This file is part of the mantid workbench.
#
#
from __future__ import (absolute_import, division, print_function)
from mantid.plots.helperfunctions import get_indices
import numpy as np
class SliceViewerModel(object):
"""Store the workspace to be plotted. Can be MatrixWorkspace, MDEventWorkspace or MDHistoWorkspace"""
def __init__(self, ws):
if ws.getNumDims() < 2:
raise ValueError("workspace must have at least 2 dimensions")
if not ws.isMDHistoWorkspace():
raise ValueError("currenly only works for MDHistoWorkspace")
self._ws = ws
def get_ws(self):
return self._ws
def get_data(self, slicepoint):
indices, _ = get_indices(self.get_ws(), slicepoint=slicepoint)
return np.ma.masked_invalid(self.get_ws().getSignalArray()[indices])
def get_dim_info(self, n):
"""
returns dict of (minimum, maximun, number_of_bins, width, name, units) for dimension n
"""
dim = self.get_ws().getDimension(n)
return {'minimum': dim.getMinimum(),
'maximum': dim.getMaximum(),
'number_of_bins': dim.getNBins(),
'width': dim.getBinWidth(),
'name': dim.name,
'units': dim.getUnits()}
def get_dimensions_info(self):
"""
returns a list of dict for each dimension conainting dim_info
"""
return [self.get_dim_info(n) for n in range(self.get_ws().getNumDims())]
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
# This file is part of the mantid workbench.
#
#
from __future__ import (absolute_import, division, print_function)
from .model import SliceViewerModel
from .view import SliceViewerView
class SliceViewer(object):
def __init__(self, ws, parent=None):
self.model = SliceViewerModel(ws)
self.view = SliceViewerView(self.model.get_dimensions_info(), parent)
self.view.dimensionsChanged.connect(self.new_plot)
self.view.valueChanged.connect(self.update_plot_data)
self.new_plot()
def new_plot(self):
self.view.plot(self.model.get_ws(), slicepoint=self.view.dimensions.get_slicepoint())
def update_plot_data(self):
self.view.update_plot_data(self.model.get_data(self.view.dimensions.get_slicepoint()))
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
# This file is part of the mantid workbench.
#
#
from __future__ import (absolute_import, division, print_function)
from qtpy.QtWidgets import QWidget, QVBoxLayout
from qtpy.QtCore import Signal, Qt
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from .dimensionwidget import DimensionWidget
class SliceViewerView(QWidget):
dimensionsChanged = Signal()
valueChanged = Signal()
def __init__(self, dims_info, parent=None):
super(SliceViewerView, self).__init__(parent)
self.setWindowTitle("SliceViewer")
self.setWindowFlags(Qt.Window)
self.setAttribute(Qt.WA_DeleteOnClose, True)
# Dimension widget
self.dimensions = DimensionWidget(dims_info, parent=self)
self.dimensions.dimensionsChanged.connect(self.dimensionsChanged)
self.dimensions.valueChanged.connect(self.valueChanged)
# MPL figure
self.fig = Figure()
self.fig.set_tight_layout(True)
self.canvas = FigureCanvas(self.fig)
self.ax = self.fig.add_subplot(111, projection='mantid')
# MPL toolbar
self.mpl_toolbar = NavigationToolbar(self.canvas, self)
# layout
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.dimensions)
self.layout.addWidget(self.mpl_toolbar)
self.layout.addWidget(self.canvas, stretch=1)
self.show()
def plot(self, ws, **kwargs):
"""
clears the plot and creates a new one using the workspace
"""
self.ax.clear()
try:
self.colorbar.remove()
except AttributeError:
pass
self.im = self.ax.imshow(ws, origin='lower', **kwargs)
self.ax.set_title('')
self.colorbar = self.fig.colorbar(self.im)
self.mpl_toolbar.update() # clear nav stack
self.fig.canvas.draw_idle()
def update_plot_data(self, data):
"""
This just updates the plot data without creating a new plot
"""
self.im.set_data(data.T)
self.im.set_clim(data.min(), data.max())
self.fig.canvas.draw_idle()
def closeEvent(self, event):
self.deleteLater()
super(SliceViewerView, self).closeEvent(event)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment