"""Dialog to show final reduced data."""
# pylint: disable=bare-except
import logging
from typing import List, Optional, Tuple
from qtpy import QtCore, QtWidgets
import quicknxs.ui.mplwidget as mpl
from quicknxs.interfaces import load_ui
from quicknxs.interfaces.data_manager import DataManager
[docs]
class ResultViewer(QtWidgets.QDialog):
"""Reduction dialog."""
default_template = "{instrument}_{numbers}_{peak}_{item}_{state}.{type}"
def __init__(self, parent, data_manager: DataManager):
super(ResultViewer, self).__init__(parent)
self.ui = load_ui("ui_result_viewer.ui", base_instance=self)
self.ui.resize(1024, 1024)
self.settings = QtCore.QSettings(".quicknxs")
self.data_manager = data_manager
self.ui.main_window = parent
self.ui.specular_compare_widget.data_manager = self.data_manager
self._gisans_reference = None
[docs]
def update_active_tab(self):
if self.ui.tabWidget.currentIndex() == 0:
self.update_specular()
elif self.ui.tabWidget.currentIndex() == 1:
self.update_off_specular()
elif self.ui.tabWidget.currentIndex() == 2:
self.update_gisans()
[docs]
def update_specular(self):
self.ui.specular_compare_widget.refl_preview()
[docs]
def update_off_specular(self, crop: bool = False):
"""Update the result viewer with the latest off-specular calculations.
Parameters
----------
crop:
If True, all the plots will be cropped to the ++ cross-section
"""
off_spec_data = self.data_manager.cached_offspec
if off_spec_data is None:
return
xlim = None
ylim = None
if crop and self.ui.offspec_pp_plot.cplot is not None:
xlim = self.ui.offspec_pp_plot.canvas.ax.get_xlim()
ylim = self.ui.offspec_pp_plot.canvas.ax.get_ylim()
data_set_keys = list(self.data_manager.data_sets.keys())
if len(data_set_keys) > 4:
logging.error("Too many cross-sections for plotting: %s", str(len(data_set_keys)))
plots: List[mpl.MPLWidget] = [
self.ui.offspec_pp_plot,
self.ui.offspec_mm_plot,
self.ui.offspec_pm_plot,
self.ui.offspec_mp_plot,
]
for plot in plots:
plot.clear()
for i in range(len(data_set_keys), 4):
if plots[i].cplot is not None:
plots[i].draw()
plots[i].hide()
i_min = 10 ** self.ui.offspec_intensity_min.value()
i_max = 10 ** self.ui.offspec_intensity_max.value()
for i, xs in enumerate(data_set_keys):
plot = plots[i]
plot.show()
plots[i].clear_fig()
_data = off_spec_data[xs][0].T
plots[i].pcolormesh(_data[0], _data[1], _data[2], log=True, imin=i_min, imax=i_max)
plots[i].set_xlabel("%s [%s]" % (off_spec_data["columns"][0], off_spec_data["units"][0]))
plots[i].set_ylabel("%s [%s]" % (off_spec_data["columns"][1], off_spec_data["units"][1]))
plots[i].set_title(xs)
if plots[i].cplot is not None:
plots[i].cplot.set_clim([i_min, i_max])
if xlim is not None and ylim is not None:
plots[i].canvas.ax.set_xlim(*xlim)
plots[i].canvas.ax.set_ylim(*ylim)
plots[i].draw()
[docs]
def apply_offspec_crop(self):
self.update_off_specular(crop=True)
[docs]
def reset_offspec_crop(self):
self.update_off_specular(crop=False)
[docs]
def apply_gisans_crop(self):
self.update_gisans(crop=True)
[docs]
def reset_gisans_crop(self):
self.update_gisans(crop=False)
def _plot_gisans(
self,
gisans_data: dict,
xs_name: str,
layout: QtWidgets.QGridLayout,
i_min: float,
i_max: float,
xlim: Optional[Tuple[float, float]] = None,
ylim: Optional[Tuple[float, float]] = None,
):
_data = gisans_data[xs_name][0].T
gisans_plot = mpl.MPLWidget(self)
gisans_plot.setMinimumSize(QtCore.QSize(0, 250))
if self._gisans_reference is None:
self._gisans_reference = gisans_plot
layout.addWidget(gisans_plot) # , i_row, i_col)
gisans_plot.pcolormesh(_data[0], _data[1], _data[2], log=True, imin=i_min, imax=i_max)
gisans_plot.set_xlabel("%s [%s]" % (gisans_data["columns"][0], gisans_data["units"][0]))
gisans_plot.set_ylabel("%s [%s]" % (gisans_data["columns"][1], gisans_data["units"][1]))
gisans_plot.set_title(xs_name)
if xlim is not None and ylim is not None:
gisans_plot.canvas.ax.set_xlim(*xlim)
gisans_plot.canvas.ax.set_ylim(*ylim)
gisans_plot.draw()
return gisans_plot
[docs]
def update_gisans(self, crop: bool = False):
"""Update the results viewer with the latest GISANS calculations.
Parameters
----------
crop:
If True, all the plots will be cropped to the ++ cross-section
"""
logging.info("Updating GISANS")
gisans_data = self.data_manager.cached_gisans
if gisans_data is None:
logging.info("Nothing to plot for GISANS")
return
# Clear everything
xlim = None
ylim = None
if crop and self._gisans_reference is not None and self._gisans_reference.cplot is not None:
xlim = self._gisans_reference.canvas.ax.get_xlim()
ylim = self._gisans_reference.canvas.ax.get_ylim()
self._gisans_reference = None
data_set_keys = list(self.data_manager.data_sets.keys())
if len(data_set_keys) > 4:
logging.error("Too many cross-sections for plotting: %s", str(len(data_set_keys)))
layouts = [
self.ui.gisans_pp_layout,
self.ui.gisans_mm_layout,
self.ui.gisans_pm_layout,
self.ui.gisans_mp_layout,
]
i_min = 10 ** self.ui.gisans_intensity_min.value()
i_max = 10 ** self.ui.gisans_intensity_max.value()
for i, pol_state in enumerate(data_set_keys):
clear_layout(layouts[i])
logging.info("State: %s" % pol_state)
for j, xs in enumerate(gisans_data["cross_section_bins"][pol_state]):
logging.info(" cross section: %s", xs)
_plot = self._plot_gisans(gisans_data, xs, layouts[i], i_min, i_max, xlim=xlim, ylim=ylim)
if i == 0 and j == 0:
self._gisans_reference = _plot
[docs]
def clear_layout(layout):
while layout.count() > 0:
item = layout.takeAt(0)
if not item:
continue
w = item.widget()
if w:
w.deleteLater()