Source code for prism._gui.widgets.overview
# -*- coding: utf-8 -*-
"""
GUI Projection Overview
=======================
Provides the overview dock widget for the Projection GUI.
"""
# %% IMPORTS
# Built-in imports
import os
from os import path
from sys import platform
import time
# Package imports
import e13tools as e13
import matplotlib.pyplot as plt
from qtpy import QtCore as QC, QtGui as QG, QtWidgets as QW
from sortedcontainers import SortedDict as sdict
# PRISM imports
from prism._docstrings import (
kwargs_doc, list_items_optional_doc, list_item_optional_doc, qt_slot_doc)
from prism._gui import APP_NAME
from prism._gui.widgets import (
FigureCanvas, QW_QAction, QW_QMenu, OverviewListWidget,
ThreadedProgressDialog)
# All declaration
__all__ = ['OverviewDockWidget']
# %% CLASS DEFINITIONS
# Create class for the projection overview dock widget
[docs]class OverviewDockWidget(QW.QDockWidget):
"""
Defines the :class:`~OverviewDockWidget` class for the Projection GUI.
This class provides the user with the ability to quickly create; draw;
view; and save projection figures.
"""
# TODO: Allow for the lists to be sorted differently?
[docs] @e13.docstring_substitute(optional=kwargs_doc.format(
'PyQt5.QtWidgets.QDockWidget'))
def __init__(self, main_window_obj, *args, **kwargs):
"""
Initialize an instance of the :class:`~OverviewDockWidget` class.
Parameters
----------
main_window_obj : :obj:`~prism._gui.widgets.MainViewerWindow` object
Instance of the :class:`~prism._gui.widgets.MainViewerWindow` class
that acts as the parent of this dock widget.
%(optional)s
"""
# Save provided MainWindow object
self.main = main_window_obj
self.pipe = self.main.pipe
self.set_proj_attr = self.main.set_proj_attr
self.all_set_proj_attr = self.main.all_set_proj_attr
self.get_proj_attr = self.main.get_proj_attr
self.call_proj_attr = self.main.call_proj_attr
self.all_call_proj_attr = self.main.all_call_proj_attr
# Call the super constructor
super().__init__("Overview", self.main, *args, **kwargs)
# Create the overview widget
self.init()
# This function is called when the main window is closed
[docs] def closeEvent(self, *args, **kwargs):
"""
Special :meth:`~PyQt5.QtWidgets.QWidget.closeEvent` event that
automatically performs some clean-up operations before the overview
dock widget closes.
"""
# Close all currently opened figures and subwindows
for fig, subwindow in self.proj_fig_registry.values():
plt.close(fig)
subwindow.close()
# Close the projection overview
super().closeEvent(*args, **kwargs)
# This function creates the projection overview
[docs] def init(self):
"""
Sets up the projection overview dock widget after it has been
initialized.
This function is mainly responsible for creating the different overview
lists and menus that allow the user to manipulate projection figures.
"""
# Create an overview
overview_widget = QW.QWidget()
self.proj_overview = QW.QVBoxLayout()
overview_widget.setLayout(self.proj_overview)
self.setWidget(overview_widget)
# Set the contents margins at the bottom to zero
contents_margins = self.proj_overview.getContentsMargins()
self.proj_overview.setContentsMargins(*contents_margins[:3], 0)
# Create empty dict containing all projection figure instances
self.proj_fig_registry = {}
# Make lists of all hcubes and their names
self.hcubes = list(self.get_proj_attr('hcubes'))
self.names = [self.call_proj_attr('get_hcube_name', hcube)
for hcube in self.hcubes]
# Divide all hcubes up into three different lists
# Drawn; available; unavailable
unavail_hcubes = [self.call_proj_attr('get_hcube_name', hcube)
for hcube in self.get_proj_attr('create_hcubes')]
avail_hcubes = [name for name in self.names
if name not in unavail_hcubes]
drawn_hcubes = []
# DRAWN PROJECTIONS
# Add list for drawn projections
self.proj_list_d = OverviewListWidget(
hcubes_list=drawn_hcubes,
status_tip="Lists all projections that have been drawn",
context_menu=self.show_drawn_context_menu,
activated=self.show_projection_figures)
self.proj_overview.addWidget(QW.QLabel("Drawn:"))
self.proj_overview.addWidget(self.proj_list_d)
self.create_drawn_context_menu()
# AVAILABLE PROJECTIONS
# Add list for available projections
self.proj_list_a = OverviewListWidget(
hcubes_list=avail_hcubes,
status_tip=("Lists all projections that have been calculated but "
"not drawn"),
context_menu=self.show_available_context_menu,
activated=self.draw_projection_figures)
self.proj_overview.addWidget(QW.QLabel("Available:"))
self.proj_overview.addWidget(self.proj_list_a)
self.create_available_context_menu()
# UNAVAILABLE PROJECTIONS
# Add list for projections that can be created
self.proj_list_u = OverviewListWidget(
hcubes_list=unavail_hcubes,
status_tip="Lists all projections that have not been calculated",
context_menu=self.show_unavailable_context_menu,
activated=self.create_projection_figures)
self.proj_overview.addWidget(QW.QLabel("Unavailable:"))
self.proj_overview.addWidget(self.proj_list_u)
self.create_unavailable_context_menu()
# This function creates the context menu for drawn projections
# This function shows the context menu for drawn projections
# This function creates the context menu for available projections
# This function shows the context menu for available projections
# This function creates the context menu for unavailable projections
# This function shows the context menu for unavailable projections
# This function shows a list of projection figures in the viewing area
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def show_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and shows them in the projection viewing area.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_d.selectedItems()
# Loop over all items in list_items
for list_item in list_items:
# Retrieve text of list_item
hcube_name = list_item.text()
# Obtain the corresponding figure and subwindow
fig, subwindow = self.proj_fig_registry[hcube_name]
# If subwindow is None, create a new one
if subwindow is None:
# Create a new subwindow
subwindow = QW.QMdiSubWindow(self.main.area_dock.proj_area)
subwindow.setWindowTitle(hcube_name)
# Set a few properties of the subwindow
# TODO: Make subwindow frameless when not being hovered
subwindow.setOption(QW.QMdiSubWindow.RubberBandResize)
# Add subwindow to registry
self.proj_fig_registry[hcube_name][1] = subwindow
# If subwindow is currently not visible, create a canvas for it
if not subwindow.isVisible():
# Create a FigureCanvas instance
canvas = FigureCanvas(fig)
# Add canvas to subwindow
subwindow.setWidget(canvas)
# Add new subwindow to viewing area if not shown before
if subwindow not in self.main.area_dock.proj_area.subWindowList():
self.main.area_dock.proj_area.addSubWindow(subwindow)
# Show subwindow
subwindow.showNormal()
subwindow.setFocus()
# If auto_tile is set to True, tile all the windows
if self.main.get_option('auto_tile'):
self.main.area_dock.proj_area.tileSubWindows()
# This function closes a list of projection figures permanently
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def close_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and closes their :obj:`~matplotlib.figure.Figure` objects.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_d.selectedItems()
# Loop over all items in list_items
for list_item in list_items:
# Retrieve text of list_item
hcube_name = list_item.text()
# Pop the figure from the registry
fig, subwindow = self.proj_fig_registry.pop(hcube_name)
# Close the figure, canvas and subwindow
plt.close(fig)
subwindow.close()
# Move figure from drawn to available
item = self.proj_list_d.takeItem(
self.proj_list_d.row(list_item))
self.proj_list_a.addItem(item)
# This function draws a list of projection figures
# OPTIMIZE: Reshaping a 3D projection figure takes up to 15 seconds
# TODO: Figure out if there is a way to make a figure static, and only
# resize when explicitly told to do so
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def draw_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and draws them, creating their :class:`~matplotlib.figure.Figure`
instances.
If the `auto_show` option is *True*, drawn figures will be shown
automatically as well.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_a.selectedItems()
# Draw projections
result = self.use_progress_dialog("Drawing projection figures...",
self._draw_projection_figure,
list_items)
# Show all drawn projection figures if the dialog was not cancelled
if result and self.main.get_option('auto_show'):
self.show_projection_figures(list_items)
# Return result
return(result)
# This function draws a projection figure
[docs] def _draw_projection_figure(self, list_item):
"""
Draws the projection figure requested in the provided `list_item`,
creating its :class:`~matplotlib.figure.Figure` instance.
This function is used iteratively by :meth:`~draw_projection_figures`.
Parameters
----------
list_item : :obj:`~PyQt5.QtWidgets.QListWidgetItem` object
The item that contains the requested projection figure.
"""
# Retrieve text of list_item
hcube_name = list_item.text()
hcube = self.hcubes[self.names.index(hcube_name)]
# Call the proper function for drawing the projection figure
fig = self.call_proj_attr('draw_%iD_proj_fig' % (len(hcube)), hcube)
# Register figure in the registry
self.proj_fig_registry[hcube_name] = [fig, None]
# Move figure from available to drawn
item = self.proj_list_a.takeItem(
self.proj_list_a.row(list_item))
self.proj_list_d.addItem(item)
# This function deletes a list of projection figures
# TODO: Avoid reimplementing the __get_req_hcubes() logic here
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def delete_projection_figures(self, list_items=None, *,
skip_warning=False):
"""
Retrieves the projection figures requested in the provided `list_items`
and delete them, permanently removing their corresponding projection
data.
%(qt_slot)s
%(optional)s
skip_warning : bool. Default: False
Whether or not to skip showing the warning asking the user if they
are sure they want to permanently delete all items in `list_items`.
If *True*, the answer is taken to be *True*.
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_a.selectedItems()
# If skip_warning is False, ask the user if they really want this
if not skip_warning:
button_clicked = QW.QMessageBox.warning(
self, "WARNING: Delete projection(s)",
("Are you sure you want to delete the selected projection "
"figure(s)? (<i>Note: This action is irreversible!</i>)"),
QW.QMessageBox.Yes | QW.QMessageBox.No, QW.QMessageBox.No)
# Else, this answer is always yes
else:
button_clicked = QW.QMessageBox.Yes
# If the answer is yes, loop over all items in list_items
if(button_clicked == QW.QMessageBox.Yes):
for list_item in list_items:
# Retrieve text of list_item
hcube_name = list_item.text()
hcube = self.hcubes[self.names.index(hcube_name)]
# Retrieve the emul_i of this hcube
emul_i = hcube[0]
# Open hdf5-file
with self.pipe._File('r+', None) as file:
# Remove the data belonging to this hcube
del file['%i/proj_hcube/%s' % (emul_i, hcube_name)]
# Try to remove figures as well
fig_path, fig_path_s =\
self.call_proj_attr('get_fig_path', hcube)
if path.exists(fig_path):
os.remove(fig_path)
if path.exists(fig_path_s):
os.remove(fig_path_s)
# Move figure from available to unavailable
item = self.proj_list_a.takeItem(
self.proj_list_a.row(list_item))
self.proj_list_u.addItem(item)
# This function creates a list of projection figures
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def create_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and creates them, calculating their corresponding projection data.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_u.selectedItems()
# Create projections
result = self.use_progress_dialog("Creating projection figures...",
self._create_projection_figure,
list_items)
# Return result
return(result)
# This function creates a projection figure
[docs] def _create_projection_figure(self, list_item):
"""
Creates the projection figure requested in the provided `list_item`,
calculating its projection data.
This function is used iteratively by
:meth:`~create_projection_figures`.
Parameters
----------
list_item : :obj:`~PyQt5.QtWidgets.QListWidgetItem` object
The item that contains the requested projection figure.
"""
# Retrieve text of list_item
hcube_name = list_item.text()
hcube = self.hcubes[self.names.index(hcube_name)]
# Calculate projection data
_, _ = self.all_call_proj_attr('analyze_proj_hcube', hcube)
# Move figure from unavailable to available
item = self.proj_list_u.takeItem(self.proj_list_u.row(list_item))
self.proj_list_a.addItem(item)
# This function saves a list of projection figures to file
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def save_projection_figures(self, list_items=None, *, choose=False):
"""
Retrieves the projection figures requested in the provided `list_items`
and saves their :obj:`~matplotlib.figure.Figure` objects.
%(qt_slot)s
%(optional)s
choose : bool. Default: False
Whether or not the user is allowed to choose where the projection
figure is saved to.
If *False*, it uses the default filename as defined by
:meth:`~prism.Pipeline._Projection__get_fig_path`.
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_d.selectedItems()
# Loop over all items in list_items
for list_item in list_items:
# Retrieve text of list_item
hcube_name = list_item.text()
hcube = self.hcubes[self.names.index(hcube_name)]
# Obtain the corresponding figure
fig, _ = self.proj_fig_registry[hcube_name]
# Obtain the default figure path
fig_paths = self.call_proj_attr('get_fig_path', hcube)
fig_path = fig_paths[self.get_proj_attr('smooth')]
# If choose, save using non-default figure path
if choose:
# Get the supported filetypes
filetypes = FigureCanvas.get_supported_filetypes_grouped()
# Get dict of all supported file extensions in MPL
ext_dict = sdict()
for name, exts in filetypes.items():
ext_dict[name] = ' '.join(['*.%s' % (ext) for ext in exts])
# Set default extension
default_ext = '*.png'
# Initialize empty list of filters and default filter
file_filters = []
default_filter = None
# Obtain list with the different file filters
for name, ext in ext_dict.items():
# Create proper string layout for this filter
file_filter = "%s (%s)" % (name, ext)
file_filters.append(file_filter)
# If this extension is the default one, save it as such
if default_ext in file_filter:
default_filter = file_filter
# Add 'All (Image) Files' filter to the list of filters
file_filters.append("All Image Files (%s)"
% (' '.join(ext_dict.values())))
file_filters.append("All Files (*)")
# Combine list into a single string
file_filters = ';;'.join(file_filters)
# Create an OS-dependent options dict
options = {}
# Do not use Linux' native dialog as it is bad on some dists
if platform.startswith('linux'):
options = {'options': QW.QFileDialog.DontUseNativeDialog}
# Open the file saving system
# Don't use native dialog as it is terrible on some Linux dists
filename, _ = QW.QFileDialog.getSaveFileName(
parent=self.main,
caption="Save %s as..." % (hcube_name),
directory=fig_path,
filter=file_filters,
initialFilter=default_filter,
**options)
# If filename was provided, save image
if filename:
fig.savefig(filename)
# Else, break the loop
else:
break
# Else, use default figure path
else:
fig.savefig(fig_path)
# This function saves a list of projection figures to file
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def save_as_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and saves their :obj:`~matplotlib.figure.Figure` objects, asking the
user where to save each one.
This function basically calls :meth:`~save_projection_figures` with
`choose` set to *True*.
%(qt_slot)s
%(optional)s
"""
self.save_projection_figures(list_items, choose=True)
# This function redraws a list of projection figures
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def redraw_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and redraws them, closing and recreating their
:obj:`~matplotlib.figure.Figure` objects.
This function is basically a combination of
:meth:`~close_projection_figures` and :meth:`~draw_projection_figures`.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_d.selectedItems()
# Close and redraw all projection figures in list_items
self.close_projection_figures(list_items)
self.draw_projection_figures(list_items)
# This function draws and saves a list of projection figures
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def draw_save_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided
`list_items`, draws their :obj:`~matplotlib.figure.Figure` objects and
saves them afterward.
This function is basically a combination of
:meth:`~draw_projection_figures` and :meth:`~save_projection_figures`.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_a.selectedItems()
# Draw and save all projection figures in list_items
if self.draw_projection_figures(list_items):
self.save_projection_figures(list_items)
# This function recreates a list of projection figures
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def recreate_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided `list_items`
and recreates them, permanently removing their corresponding projection
data and recalculating it.
This function is basically a combination of
:meth:`~delete_projection_figures` and
:meth:`~create_projection_figures`.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_a.selectedItems()
# Ask the user if they really want to recreate the figures
button_clicked = QW.QMessageBox.warning(
self, "WARNING: Recreate projection(s)",
("Are you sure you want to recreate the selected projection "
"figure(s)? (<i>Note: This action is irreversible!</i>)"),
QW.QMessageBox.Yes | QW.QMessageBox.No, QW.QMessageBox.No)
# Delete and recreate all projection figures in list_items if yes
if(button_clicked == QW.QMessageBox.Yes):
self.delete_projection_figures(list_items, skip_warning=True)
self.create_projection_figures(list_items)
# This function creates and draws a list of projection figures
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def create_draw_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided
`list_items`, calculates their projection data and draws their
:obj:`~matplotlib.figure.Figure` objects afterward.
This function is basically a combination of
:meth:`~create_projection_figures` and
:meth:`~draw_projection_figures`.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_u.selectedItems()
# Create and draw all projection figures in list_items
if self.create_projection_figures(list_items):
self.draw_projection_figures(list_items)
# This function creates, draws and saves a list of projection figures
[docs] @QC.Slot()
@QC.Slot(list)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_items_optional_doc)
def create_draw_save_projection_figures(self, list_items=None):
"""
Retrieves the projection figures requested in the provided
`list_items`, calculates their projection data, draws their
:obj:`~matplotlib.figure.Figure` objects and saves them afterward.
This function is basically a combination of
:meth:`~create_projection_figures`; :meth:`~draw_projection_figures`
and :meth:`~save_projection_figures`.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_items
if list_items is None:
list_items = self.proj_list_u.selectedItems()
# Create, draw and save all projection figures in list_items
if self.create_projection_figures(list_items):
if self.draw_projection_figures(list_items):
self.save_projection_figures(list_items)
# This function shows a details overview of a drawn projection figure
[docs] @QC.Slot()
@QC.Slot(QW.QListWidgetItem)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_item_optional_doc)
def details_drawn_projection_figure(self, list_item=None):
"""
Retrieves the projection figure requested in the provided `list_item`,
gathers its properties and shows a details dialog listing them.
This function is used for projections in the 'Drawn' list.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_item
if list_item is None:
list_item = self.proj_list_d.selectedItems()[0]
# Show details
self._details_projection_figure(list_item)
# This function shows a details overview of an available projection figure
[docs] @QC.Slot()
@QC.Slot(QW.QListWidgetItem)
@e13.docstring_substitute(qt_slot=qt_slot_doc,
optional=list_item_optional_doc)
def details_available_projection_figure(self, list_item=None):
"""
Retrieves the projection figure requested in the provided `list_item`,
gathers its properties and shows a details dialog listing them.
This function is used for projections in the 'Available' list.
%(qt_slot)s
%(optional)s
"""
# Obtain the list_item
if list_item is None:
list_item = self.proj_list_a.selectedItems()[0]
# Show details
self._details_projection_figure(list_item)
# This function shows a details overview of a projection figure
# TODO: Add section on how the figure was drawn for drawn projections?
[docs] def _details_projection_figure(self, list_item):
"""
Creates and shows a details dialog for the projection figure requested
in the provided `list_item`.
Parameters
----------
list_item : :obj:`~PyQt5.QtWidgets.QListWidgetItem` object
The item that contains the requested projection figure.
"""
# Retrieve text of list_item
hcube_name = list_item.text()
hcube = self.hcubes[self.names.index(hcube_name)]
# Is this a 3D projection?
is_3D = (len(hcube) == 3)
# Gather some details about this projection figure
emul_i = hcube[0] # Emulator iteration
pars = hcube[1:] # Plotted parameters
proj_type = '%iD' % (len(hcube)) # Projection type
# Open hdf5-file
with self.pipe._File('r', None) as file:
# Get the group that contains the data for this projection figure
group = file["%i/proj_hcube/%s" % (emul_i, hcube_name)]
# Gather more details about this projection figure
impl_cut = group.attrs['impl_cut'] # Implausibility cut-offs
cut_idx = group.attrs['cut_idx'] # Number of wildcards
res = group.attrs['proj_res'] # Projection resolution
depth = group.attrs['proj_depth'] # Projection depth
# Get the percentage of plausible space remaining
pl_space_rem = "{0:#.3g}%".format(self.pipe._get_f_impl(emul_i)*100)
pl_space_rem = QW.QLabel(pl_space_rem)
# Obtain QLabel instances of all details
emul_i = QW.QLabel(str(emul_i))
pars = ', '.join([self.pipe._modellink._par_name[par] for par in pars])
pars = QW.QLabel(pars)
proj_type = QW.QLabel(proj_type)
impl_cut = QW.QLabel(str(impl_cut.tolist()))
cut_idx = QW.QLabel(str(cut_idx))
# Get the labels for the grid shape and size
if is_3D:
grid_shape = QW.QLabel("{0:,}x{0:,}x{1:,}".format(res, depth))
grid_size = QW.QLabel("{0:,}".format(res*res*depth))
else:
grid_shape = QW.QLabel("{0:,}x{1:,}".format(res, depth))
grid_size = QW.QLabel("{0:,}".format(res*depth))
# Convert res and depth as well
res = QW.QLabel("{0:,}".format(res))
depth = QW.QLabel("{0:,}".format(depth))
# Create a layout for the details
details_layout = QW.QVBoxLayout()
# GENERAL
# Create a group for the general details
general_group = QW.QGroupBox("General")
details_layout.addWidget(general_group)
general_layout = QW.QFormLayout()
general_group.setLayout(general_layout)
# Add general details
general_layout.addRow("Emulator iteration", emul_i)
general_layout.addRow("Parameters", pars)
general_layout.addRow("Projection type", proj_type)
general_layout.addRow("% of parameter space remaining",
pl_space_rem)
# PROJECTION DATA
# Create a group for the projection data details
data_group = QW.QGroupBox("Projection data")
details_layout.addWidget(data_group)
data_layout = QW.QFormLayout()
data_group.setLayout(data_layout)
# Add projection data details
data_layout.addRow("Grid shape", grid_shape)
data_layout.addRow("Grid size", grid_size)
data_layout.addRow("# of implausibility wildcards", cut_idx)
data_layout.addRow("Implausibility cut-offs", impl_cut)
# Create a details message box for this projection figure
details_box = QW.QDialog(self.main)
details_box.setWindowModality(QC.Qt.NonModal)
details_box.setAttribute(QC.Qt.WA_DeleteOnClose)
details_box.setWindowFlags(
QC.Qt.WindowSystemMenuHint |
QC.Qt.Window |
QC.Qt.WindowCloseButtonHint |
QC.Qt.MSWindowsOwnDC |
QC.Qt.MSWindowsFixedSizeDialogHint)
details_layout.setSizeConstraint(QW.QLayout.SetFixedSize)
details_box.setWindowTitle("%s: %s details" % (APP_NAME, hcube_name))
details_box.setLayout(details_layout)
# Show the details message box
details_box.show()
# This function creates the proper progress dialog for given operation
[docs] def use_progress_dialog(self, label, func, *iterables):
"""
Creates a progress dialog with the given `label`, and executes the
requested `func` using the provided `iterables`.
Depending on the current settings, this function will either create a
:obj:`~prism._gui.widgets.helpers.ThreadedProgressDialog` object that
allows the user to abort the operation (but is slower), or a static
dialog that cannot be interrupted.
Parameters
----------
label : str
The label that is used as the description of what operation is
currently being executed.
func : function
The function that must be called iteratively using the arguments
provided in `iterables`.
iterables : positional arguments
All iterables that must be used to call `func` with.
Returns
-------
result : bool
Whether or not the operations ended successfully, which can be used
by other functions to determine if it should continue.
"""
# Set result to False
result = False
# Use a progress dialog if one was requested
if self.main.get_option('use_progress_dialog'):
# Create a threaded progress dialog for creating projections
progress_dialog = ThreadedProgressDialog(
self.main, label, func, *iterables)
# Wrap in try-statement to make sure the dialog is always closed
try:
# Execute the function provided to the progress dialog
result = progress_dialog()
# Close dialog
finally:
progress_dialog.close()
# Else, do not use one and execute on main thread
else:
# Create a dialog showing that an operation is being executed
dialog = QW.QDialog(self.main)
dialog.setWindowModality(QC.Qt.ApplicationModal)
dialog.setWindowTitle(APP_NAME)
dialog.setAttribute(QC.Qt.WA_DeleteOnClose)
dialog.setWindowFlags(
QC.Qt.WindowTitleHint |
QC.Qt.Dialog |
QC.Qt.CustomizeWindowHint)
layout = QW.QVBoxLayout(dialog)
layout.addWidget(QW.QLabel(label))
# Show the dialog
dialog.show()
# Make cursor show that it is busy
QW.QApplication.setOverrideCursor(QG.QCursor(QC.Qt.WaitCursor))
# Wait for 0.1 seconds and then process events to update dialog
time.sleep(0.1)
QW.QApplication.instance().processEvents()
# Wrap in try-statement to make sure the dialog is always closed
try:
# Loop over all iterables
for items in zip(*iterables):
func(*items)
# If this finishes successfully, set result to True
else:
result = True
# Restore mouse cursor and close dialog
finally:
QW.QApplication.restoreOverrideCursor()
dialog.close()
# Return result
return(result)