def _read_backup(self, emul_i, *, suffix=None): """ Reads in a backup HDF5-file created by the :meth:`~_make_backup` method, using the provided `emul_i` and the value of :attr:`~name`. Parameters ---------- emul_i : int The emulator iteration that was provided to the :meth:`~call_model` method when the backup was made. Optional -------- suffix : str or None. Default: None The suffix of the backup file (everything between parentheses) that needs to be read. If *None*, the last created backup will be read. Returns ------- filename : str The absolute path to the backup file that has been read. data : dict with keys `('emul_i', 'prism_version', 'par_set',` \ `'data_idx', 'args', 'kwargs')` A dict containing the data that was provided to the :meth:`~_make_backup` method. """ # Raise warning about this feature being experimental warn_msg = ("The 'call_model' backup system is still experimental and " "it may see significant changes or be (re)moved in the " "future!") warnings.warn(warn_msg, FeatureWarning, stacklevel=2) # Check if provided emul_i is an integer emul_i = check_vals(emul_i, 'emul_i', 'int', 'nneg') # Check if provided suffix is None or a string if suffix is None: suffix = '' else: suffix = check_vals(suffix, 'suffix', 'str') # Obtain name of backup file filepath = self._get_backup_path(emul_i, suffix) # Initialize empty data dict data = sdict() # Read emul_i, par_set, data_idx, args and kwargs from hdf5 with h5py.File(filepath, 'r') as file: data['emul_i'] = file.attrs['emul_i'] data['prism_version'] = file.attrs['prism_version'] data['par_set'] = sdict(hickle.load(file, path='/par_set')) data['data_idx'] = hickle.load(file, path='/data_idx') data['args'] = hickle.load(file, path='/args') data['kwargs'] = hickle.load(file, path='/kwargs') # Return data return (filepath, data)
def test_init_walkers_dict(self, pipe): sam_set = lhd(10, pipe._modellink._n_par, pipe._modellink._par_rng, 'center', pipe._criterion, 100) sam_dict = sdict(zip(pipe._modellink._par_name, sam_set.T)) p0_walkers = get_walkers(pipe, init_walkers=sam_dict)[1] if pipe._is_controller: assert isinstance(p0_walkers, dict)
def _default_model_parameters(self): """ dict: The default model parameters to use for every instance of this :class:`~ModelLink` subclass. """ return (sdict())
def add_config_pages(self): # Initialize empty dict of config pages self.config_pages = sdict() # Initialize all config pages of this plugin for config_page in self.CONFIG_PAGES: # Initialize config_page self.config_pages[config_page.NAME] = config_page(self)
def par_est(self): """ dict of {float, None}: The user-defined estimated values of the model parameters. Contains *None* in places where estimates were not provided. """ return (sdict(zip(self._par_name, self._par_est)))
def test_non_default(self, pipe): hybrid_lnpost = get_hybrid_lnpost_fn(lnpost, pipe, par_dict=True, unit_space=True, impl_prior=False) assert hybrid_lnpost({'A': 0.5, 'B': 0.5}, pipe) == -np.infty hybrid_lnpost( sdict(zip(pipe._modellink._par_name, pipe._modellink._par_est)), pipe)
def encode_config(self, config_dict): # Initialize empty dict of section config values section_dict = sdict() # Loop over all arguments in config and encode them in for key, value in config_dict.items(): section_dict[key] = '{!r}'.format(value) # Return section_dict return (section_dict)
def create_tab_general(self): """ Creates the 'General' tab and returns it. """ self.proj_defaults = sdict(self.get_proj_attr('proj_kwargs')) self.proj_keys = list(self.proj_defaults.keys()) self.proj_keys.remove('align') self.proj_keys.extend(['align_col', 'align_row']) return(self.create_tab("General", ['proj_grid', 'proj_kwargs']))
def decode_config(self, section_dict): # Initialize empty dict of parsed config values config_dict = sdict() # Decode all values in section_dict for key, value in section_dict.items(): # Add all values to config dict using literal_eval config_dict[key] = literal_eval(value) # Return config_dict return (config_dict)
def decode_config(self, section_dict): # Initialize empty dict of parsed config values config_dict = sdict() # Decode all values in section_dict for key, value in section_dict.items(): # Convert to Python object value = literal_eval(value) # Add to dict config_dict[key] = value # Return config_dict return(config_dict)
def add_argument(self, action): # Check if the help of this action is required if action.help is not argparse.SUPPRESS: # Check if this action is a subparser's action if isinstance(action, argparse._SubParsersAction): # Convert action.choices to a sorted dictionary choices = sdict(action.choices) # If so, loop over all subcommands defined in the action for name, subparser in choices.items(): # Format the description of this subcommand and add it self._add_item(self.format_subcommands, [name, subparser.description]) # Call super method in all other cases else: super().add_argument(action)
def __init__(self, section_name=None, parent=None): # Save the config section name self.section_name = self.NAME if section_name is None else section_name # Initialize empty config_entries dict self.config_entries = sdict() # Initialize restart_flag self.restart_flag = False # Call super constructor super().__init__(parent) # Set up config page self.init() # Add this config page to the config manager CONFIG.add_config_page(self)
def lnpost(par_set, pipe): # Obtain mod_out emul_i = pipe._emulator._emul_i if not isinstance(par_set, dict): par_dict = sdict(zip(pipe._modellink._par_name, par_set)) else: par_dict = par_set mod_out = pipe._modellink.call_model(emul_i, par_dict, pipe._modellink._data_idx) # As GaussianLink2D returns dicts, convert to NumPy array mod_out = np.array([mod_out[idx] for idx in pipe._modellink._data_idx]) # Get model and data variances. Since val_spc is lin, data_err is centered md_var = pipe._modellink.get_md_var(emul_i, par_dict, pipe._modellink._data_idx) md_var = np.array([md_var[idx] for idx in pipe._modellink._data_idx]) data_var = [err[0]**2 for err in pipe._modellink._data_err] sigma2 = md_var + data_var return (-0.5 * (np.sum((pipe._modellink._data_val - mod_out)**2 / sigma2)))
def get_box_value(self): """ Returns the current value of the kwargs dict page. Returns ------- page_dict : dict A dict containing all valid entries that are currently on this kwargs dict page. Any invalid entries (banned or empty ones) are ignored. """ # Create an empty dict to hold the values in page_dict = sdict() # Loop over all items in grid and save them to page_dict for row in range(1, self.kwargs_grid.rowCount()): # Obtain item that should contain the entry_type in this row entry_type_item = self.kwargs_grid.itemAtPosition(row, 1) # If entry_type_item is None, this row contains no items if entry_type_item is None: continue # Obtain the entry_type entry_type = get_box_value(entry_type_item.widget()) # If the entry_type is empty or banned, skip this row if not entry_type or entry_type in self.banned_entries: continue # Obtain the value of the corresponding field box field_value = get_box_value( self.kwargs_grid.itemAtPosition(row, 2).widget()) # Add this to the dict page_dict[entry_type] = field_value # Return page_dict return(page_dict)
def get_box_value(self, *value_sig): """ Returns the current values for the config section belonging to this config page. Returns ------- config_dict : dict Dict containing the current config section values. """ # Create empty dict of config values config_dict = sdict() # Retrieve values of all config entries for key, entry_box in self.config_entries.items(): config_dict[key] = get_box_value(entry_box) # Return the config_dict return(config_dict)
def test_PolyLink(): # Save paths to data file model_data = path.join(DIR_PATH, 'data/data_poly.txt') # Initialize PolyLink class modellink_obj = _test_subclass(PolyLink, 3, model_data=model_data) repr(modellink_obj) # Check if this instance is has the correct number of polynomial terms assert modellink_obj.order == 3 # Call model par_set = [2.5, 2, 1, 2.5] par_dict = sdict(zip(modellink_obj._par_name, np.array(par_set))) exp_mod_out = [8.0, 85.0, 186.5] assert np.allclose( modellink_obj.call_model(1, par_dict, sorted(modellink_obj._data_idx)), exp_mod_out) # Retrieve model discrepancy variance assert np.allclose( modellink_obj.get_md_var(1, par_dict, modellink_obj._data_idx), [0.01, 0.01, 0.01])
def test_SineWaveLink(): # Save paths to data file model_data = path.join(DIR_PATH, 'data/data_sine_wave.txt') # Initialize SineWaveLink class modellink_obj = _test_subclass(SineWaveLink, model_data=model_data) repr(modellink_obj) # Call model par_set = [4, 3, 5, 4.6] par_dict = sdict(zip(modellink_obj._par_name, np.array(par_set))) exp_mod_out = [ 3.9477019656331063, 4.268437351642151, 4.204589086020441, 3.8476310228828132, 3.7089682798878445 ] assert np.allclose( modellink_obj.call_model(1, par_dict, sorted(modellink_obj._data_idx)), exp_mod_out) # Retrieve model discrepancy variance assert np.allclose( modellink_obj.get_md_var(1, par_dict, modellink_obj._data_idx), [0.01, 0.01, 0.01, 0.01, 0.01])
def first_init(self): # Obtain all colormaps that are registered in MPL cmaps = plt.colormaps() # Split cmaps up into their cmap types cm_types = ['sequential', 'diverging', 'cyclic', 'qualitative', 'misc'] cmaps_cd = {cm_type: sset() for cm_type in cm_types} for cmap in cmaps: cmaps_cd[get_cmap_type(cmap)].add(cmap) # Create empty list of cmaps sorted on type cmaps_cl = [] cum_len = [] # Loop over every type for cmaps_cs in cmaps_cd.values(): # Take all base versions of the colormaps cmaps_cl.extend( [cmap for cmap in cmaps_cs if not cmap.endswith('_r')]) cum_len.extend([len(cmaps_cl)]) # Also add all the reversed versions cmaps_cl.extend([cmap for cmap in cmaps_cs if cmap.endswith('_r')]) cum_len.extend([len(cmaps_cl)] * 2) # Store list of colormaps and the category lengths ColorMapBox.cmaps_cl = cmaps_cl ColorMapBox.cum_len = cum_len # Create the colormap icons cmap_icons = sdict() for cmap in cmaps: cmap_icons[cmap] = self.create_cmap_icon(cmap, self.cmap_size) ColorMapBox.cmap_icons = cmap_icons # Save that class has been initialized for the first time ColorMapBox.init_flag = True
def init(self): """ Sets up the options dialog after it has been initialized. This function is mainly responsible for initializing all option entries that the GUI has, and creating a database for them. It also creates the layout of the options dialog. """ # Create a window layout window_layout = QW.QVBoxLayout(self) # Create a tab widget window_tabs = QW.QTabWidget() window_layout.addWidget(window_tabs) # Create a options dict self.option_entries = sdict() # Define list with all tabs that should be available in what order option_tabs = ['general', 'appearance'] # Include all tabs named in options_tabs for tab in option_tabs: window_tabs.addTab(*getattr(self, 'create_tab_%s' % (tab))()) # Also add the buttons self.create_group_buttons(window_layout) # Set a few properties of options window self.setWindowModality(QC.Qt.WindowModal) # Modality self.setWindowTitle("Preferences") # Title # Add a new method to self.main self.main.get_option = self.get_option
def _check_sam_set(self, sam_set, name): """ Checks validity of provided set of model parameter samples `sam_set` in this :obj:`~ModelLink` instance. Parameters ---------- sam_set : 1D or 2D array_like or dict Parameter/sample set to validate in this :obj:`~ModelLink` instance. name : str The name of the parameter/sample set, which is used in the error message if the validation fails. Returns ------- sam_set : 1D or 2D :obj:`~numpy.ndarray` object The provided `sam_set` if the validation was successful. If `sam_set` was a dict, it will be converted to a :obj:`~numpy.ndarray` object. """ # Make logger logger = getCLogger('CHECK') logger.info("Validating provided set of model parameter samples %r." % (name)) # If sam_set is a dict, convert it to a NumPy array if isinstance(sam_set, dict): sam_set = np_array(sdict(sam_set).values()).T # Make sure that sam_set is a NumPy array sam_set = np_array(sam_set) # Raise error if sam_set is not 1D or 2D if not (sam_set.ndim == 1 or sam_set.ndim == 2): err_msg = ("Input argument %r is not one-dimensional or " "two-dimensional!" % (name)) raise_error(err_msg, ShapeError, logger) # Raise error if sam_set does not have n_par parameter values if not (sam_set.shape[-1] == self._n_par): err_msg = ("Input argument %r has incorrect number of parameters " "(%i != %i)!" % (name, sam_set.shape[-1], self._n_par)) raise_error(err_msg, ShapeError, logger) # Check if sam_set solely consists out of floats sam_set = check_vals(sam_set, name, 'float') # Check if all samples are within parameter space sam_set_2D = np_array(sam_set, ndmin=2) rng = self._par_rng check = np.apply_along_axis( lambda x: ((rng[:, 0] <= x) * (x <= rng[:, 1])).all(), 1, sam_set_2D) # If check is not empty (can be indexed), raise error try: index = np.argwhere(~check)[0] except IndexError: pass else: err_msg = ("Input argument '%s%s' is outside parameter space!" % (name, index if sam_set.ndim != 1 else '')) raise_error(err_msg, ValueError, logger) # Log again and return sam_set logger.info("Finished validating provided set of model parameter " "samples %r." % (name)) return (sam_set)
def convert_parameters(model_parameters): """ Converts the provided `model_parameters` into a full parameters dict, taking into account all formatting options, and returns it. This function can be used externally to check how the provided `model_parameters` would be interpreted when provided to the :class:`~prism.modellink.ModelLink` subclass. Its output can be used for the 'model_parameters' input argument. Parameters ---------- model_parameters : array_like, dict or str Anything that can be converted to a dict that provides model parameters information. Returns ------- par_dict : dict Dict with the provided `model_parameters` converted to its full format. """ # If a parameter file is given if isinstance(model_parameters, str): # Obtain absolute path to given file par_file = path.abspath(model_parameters) # Read the parameter file in as a string pars = np.genfromtxt(par_file, dtype=(str), delimiter=':', autostrip=True) # Make sure that pars is 2D pars = np_array(pars, ndmin=2) # Convert read-in parameters to dict model_parameters = sdict(pars) # If a parameter dict is given elif isinstance(model_parameters, dict): model_parameters = sdict(model_parameters) # If anything else is given else: # Check if it can be converted to a dict try: model_parameters = sdict(model_parameters) except Exception: raise TypeError("Input model parameters cannot be converted to" " type 'dict'!") # Initialize empty par_dict par_dict = sdict() # Loop over all items in model_parameters for name, values_str in model_parameters.items(): # Convert values_str to values values = e13.split_seq(values_str) # Check if provided name is a string name = check_vals(name, 'par_name[%r]' % (name), 'str') # Check if provided range consists of two floats par_rng = check_vals(values[:2], 'par_rng[%r]' % (name), 'float') # Check if provided lower bound is lower than the upper bound if(par_rng[0] >= par_rng[1]): raise ValueError("Input argument 'par_rng[%r]' does not define a " "valid parameter range (%f !< %f)!" % (name, par_rng[0], par_rng[1])) # Check if a float parameter estimate was provided try: est = check_vals(values[2], 'par_est[%r]' % (name), 'float') # If no estimate was provided, save it as None except IndexError: est = None # If no float was provided, check if it was None except TypeError as error: # If it is None, save it as such if(str(values[2]).lower() == 'none'): est = None # If it is not None, reraise the previous error else: raise error # If a float was provided, check if it is within parameter range else: if not(values[0] <= est <= values[1]): raise ValueError("Input argument 'par_est[%r]' is outside " "of defined parameter range!" % (name)) # Add parameter to par_dict par_dict[name] = [*par_rng, est] # Return par_dict return(par_dict)
def init(self): # Create layout layout = GL.QVBoxLayout(self) # COLORMAPS # Create 'Colormaps' group box colormaps_group = GW.QGroupBox('Import colormaps') layout.addWidget(colormaps_group) colormaps_layout = GL.QFormLayout(colormaps_group) # Add label with explaining text cmaps_label = GW.QLabel( "You can import several Python packages that register colormaps in" " <u>matplotlib</u> before a figure is created. Packages that are " "not installed are ignored. Please provide each package separated " "by a comma, like: <i>cmasher, cmocean</i>") colormaps_layout.addRow(cmaps_label) # Create box for setting the colormap packages that must be imported cmap_pkg_box = GW.QLineEdit() colormaps_layout.addRow("Packages:", cmap_pkg_box) self.add_config_entry('cmap_packages', cmap_pkg_box, True) # RCPARAMS # Create 'rcParams' group box rcParams_group = GW.QGroupBox('rcParams') layout.addWidget(rcParams_group) rcParams_layout = GL.QVBoxLayout(rcParams_group) # Add label with explaining text rcParams_label = GW.QLabel( "You can modify most of the <u>rcParams</u> used in " "<u>matplotlib</u> below. Adding an entry will override the value " "for that specific parameter for every figure created.<br>" "See <a href=\"%s\">here</a> for an overview with descriptions of " "each parameter." % ("https://matplotlib.org/tutorials/introductory/customizing.html")) rcParams_layout.addWidget(rcParams_label) # Add separator rcParams_layout.addSeparator() # Create entries_box entries_box = GW.EntriesBox() rcParams_layout.addWidget(entries_box) self.add_config_entry('rcParams', entries_box) # Create list of all prefixes that should be skipped prefix_skip = ('_internal', 'agg', 'animation', 'backend', 'boxplot.bootstrap', 'datapath', 'docstring', 'figure.figsize', 'figure.max_open_warning', 'image.aspect', 'image.composite_image', 'image.origin', 'interactive', 'keymap', 'lines.color', 'mpl_toolkits', 'path', 'pdf', 'pgf', 'ps', 'savefig', 'svg', 'text.kerning_factor', 'tk', 'toolbar', 'verbose', 'webagg') # Create a combobox factory for text weights text_weight_box = create_combobox( ['normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900']) # Create dict of all rcParams that use specific widgets key_widgets = { 'axes.autolimit_mode': create_combobox(['data', 'round_numbers']), 'axes.axisbelow': lambda: BoolComboBox([True, 'line', False]), 'axes.edgecolor': GW.ColorBox, 'axes.facecolor': GW.ColorBox, 'axes.formatter.limits': lambda: GW.ItemsBox([int]*2), 'axes.formatter.min_exponent': GW.QSpinBox, 'axes.formatter.offset_threshold': GW.QSpinBox, 'axes.formatter.use_locale': GW.QCheckBox, 'axes.formatter.use_mathtext': GW.QCheckBox, 'axes.formatter.useoffset': GW.QCheckBox, 'axes.grid': GW.QCheckBox, 'axes.grid.axes': create_combobox(['major', 'minor', 'both']), 'axes.grid.which': create_combobox(['major', 'minor', 'both']), 'axes.labelcolor': GW.ColorBox, 'axes.labelpad': GW.FontSizeBox, 'axes.labelsize': GW.FontSizeBox, 'axes.labelweight': text_weight_box, 'axes.linewidth': GW.FontSizeBox, 'axes.prop_cycle': lambda: GW.GenericItemsBox( lambda: GW.ColorBox(False)), 'axes.spines.bottom': GW.QCheckBox, 'axes.spines.left': GW.QCheckBox, 'axes.spines.right': GW.QCheckBox, 'axes.spines.top': GW.QCheckBox, 'axes.titlecolor': lambda: AutoToggleBox(GW.ColorBox(), 'auto'), 'axes.titlelocation': create_combobox(['left', 'center', 'right']), 'axes.titlepad': GW.FontSizeBox, 'axes.titlesize': GW.FontSizeBox, 'axes.titleweight': text_weight_box, 'axes.unicode_minus': GW.QCheckBox, 'axes.xmargin': UnitySpinBox, 'axes.ymargin': UnitySpinBox, 'axes3d.grid': GW.QCheckBox, 'boxplot.boxprops.color': GW.ColorBox, 'boxplot.boxprops.linestyle': GW.LineStyleBox, 'boxplot.boxprops.linewidth': GW.FontSizeBox, 'boxplot.capprops.color': GW.ColorBox, 'boxplot.capprops.linestyle': GW.LineStyleBox, 'boxplot.capprops.linewidth': GW.FontSizeBox, 'boxplot.flierprops.color': GW.ColorBox, 'boxplot.flierprops.linestyle': GW.LineStyleBox, 'boxplot.flierprops.linewidth': GW.FontSizeBox, 'boxplot.flierprops.marker': GW.MarkerStyleBox, 'boxplot.flierprops.markeredgecolor': lambda: AutoToggleBox( GW.ColorBox(), 'none'), 'boxplot.flierprops.markeredgewidth': GW.FontSizeBox, 'boxplot.flierprops.markerfacecolor': lambda: AutoToggleBox( GW.ColorBox(), 'none'), 'boxplot.flierprops.markersize': GW.FontSizeBox, 'boxplot.meanline': GW.QCheckBox, 'boxplot.meanprops.color': GW.ColorBox, 'boxplot.meanprops.linestyle': GW.LineStyleBox, 'boxplot.meanprops.linewidth': GW.FontSizeBox, 'boxplot.meanprops.marker': GW.MarkerStyleBox, 'boxplot.meanprops.markeredgecolor': lambda: AutoToggleBox( GW.ColorBox(), 'none'), 'boxplot.meanprops.markerfacecolor': lambda: AutoToggleBox( GW.ColorBox(), 'none'), 'boxplot.meanprops.markersize': GW.FontSizeBox, 'boxplot.medianprops.color': GW.ColorBox, 'boxplot.medianprops.linestyle': GW.LineStyleBox, 'boxplot.medianprops.linewidth': GW.FontSizeBox, 'boxplot.notch': GW.QCheckBox, 'boxplot.showbox': GW.QCheckBox, 'boxplot.showcaps': GW.QCheckBox, 'boxplot.showfliers': GW.QCheckBox, 'boxplot.showmeans': GW.QCheckBox, 'boxplot.vertical': GW.QCheckBox, 'boxplot.whiskerprops.color': GW.ColorBox, 'boxplot.whiskerprops.linestyle': GW.LineStyleBox, 'boxplot.whiskerprops.linewidth': GW.FontSizeBox, 'boxplot.whiskers': GW.FloatLineEdit, 'contour.corner_mask': lambda: BoolComboBox( [True, False, 'legacy']), 'contour.negative_linestyle': GW.LineStyleBox, 'date.autoformatter.day': GW.QLineEdit, 'date.autoformatter.hour': GW.QLineEdit, 'date.autoformatter.microsecond': GW.QLineEdit, 'date.autoformatter.minute': GW.QLineEdit, 'date.autoformatter.month': GW.QLineEdit, 'date.autoformatter.second': GW.QLineEdit, 'date.autoformatter.year': GW.QLineEdit, 'errorbar.capsize': GW.FloatLineEdit, 'figure.autolayout': GW.QCheckBox, 'figure.constrained_layout.h_pad': UnitySpinBox, 'figure.constrained_layout.hspace': UnitySpinBox, 'figure.constrained_layout.use': GW.QCheckBox, 'figure.constrained_layout.w_pad': UnitySpinBox, 'figure.constrained_layout.wspace': UnitySpinBox, 'figure.dpi': GW.FloatLineEdit, 'figure.edgecolor': GW.ColorBox, 'figure.facecolor': GW.ColorBox, 'figure.frameon': GW.QCheckBox, 'figure.subplot.bottom': UnitySpinBox, 'figure.subplot.hspace': UnitySpinBox, 'figure.subplot.left': UnitySpinBox, 'figure.subplot.right': UnitySpinBox, 'figure.subplot.top': UnitySpinBox, 'figure.subplot.wspace': UnitySpinBox, 'figure.titlesize': GW.FontSizeBox, 'figure.titleweight': text_weight_box, 'font.cursive': lambda: GW.GenericItemsBox(GW.QFontComboBox), 'font.family': lambda: GW.GenericItemsBox(GW.QFontComboBox), 'font.fantasy': lambda: GW.GenericItemsBox(GW.QFontComboBox), 'font.monospace': lambda: GW.GenericItemsBox(GW.QFontComboBox), 'font.sans-serif': lambda: GW.GenericItemsBox(GW.QFontComboBox), 'font.serif': lambda: GW.GenericItemsBox(GW.QFontComboBox), 'font.size': GW.FontSizeBox, 'font.stretch': create_combobox( ['ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded', 'wider', 'narrower']), 'font.style': create_combobox(['normal', 'italic', 'oblique']), 'font.variant': create_combobox(['normal', 'small-caps']), 'font.weight': text_weight_box, 'grid.alpha': UnitySpinBox, 'grid.color': GW.ColorBox, 'grid.linestyle': GW.LineStyleBox, 'grid.linewidth': GW.FontSizeBox, 'hatch.color': GW.ColorBox, 'hatch.linewidth': GW.FontSizeBox, 'hist.bins': get_n_bins_box, 'image.cmap': GW.ColorMapBox, 'image.interpolation': create_combobox( ['none', 'antialiased', 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos']), 'image.lut': GW.IntLineEdit, 'image.resample': GW.QCheckBox, 'legend.borderaxespad': GW.FontSizeBox, 'legend.borderpad': GW.FontSizeBox, 'legend.columnspacing': GW.FontSizeBox, 'legend.edgecolor': GW.ColorBox, 'legend.facecolor': lambda: AutoToggleBox( GW.ColorBox(), 'inherit'), 'legend.fancybox': GW.QCheckBox, 'legend.fontsize': GW.FontSizeBox, 'legend.framealpha': UnitySpinBox, 'legend.frameon': GW.QCheckBox, 'legend.handleheight': GW.FontSizeBox, 'legend.handlelength': GW.FontSizeBox, 'legend.handletextpad': GW.FontSizeBox, 'legend.labelspacing': GW.FontSizeBox, 'legend.loc': create_combobox(mpl.legend.Legend.codes.keys()), 'legend.markerscale': GW.FloatLineEdit, 'legend.numpoints': GW.IntLineEdit, 'legend.scatterpoints': GW.IntLineEdit, 'legend.shadow': GW.QCheckBox, 'legend.title_fontsize': lambda: AutoToggleBox( GW.FontSizeBox(), None), 'lines.antialiased': GW.QCheckBox, 'lines.dash_capstyle': create_combobox( ['butt', 'projecting', 'round']), 'lines.dash_joinstyle': create_combobox( ['bevel', 'miter', 'round']), 'lines.dashdot_pattern': lambda: GW.ItemsBox([float]*4), 'lines.dashed_pattern': lambda: GW.ItemsBox([float]*2), 'lines.dotted_pattern': lambda: GW.ItemsBox([float]*2), 'lines.linestyle': GW.LineStyleBox, 'lines.linewidth': GW.FontSizeBox, 'lines.marker': GW.MarkerStyleBox, 'lines.markeredgecolor': lambda: AutoToggleBox( GW.ColorBox(), 'auto'), 'lines.markeredgewidth': GW.FontSizeBox, 'lines.markerfacecolor': lambda: AutoToggleBox( GW.ColorBox(), 'auto'), 'lines.markersize': GW.FontSizeBox, 'lines.scale_dashes': GW.QCheckBox, 'lines.solid_capstyle': create_combobox( ['butt', 'projecting', 'round']), 'lines.solid_joinstyle': create_combobox( ['bevel', 'miter', 'round']), 'markers.fillstyle': create_combobox( ['full', 'left', 'right', 'bottom', 'top', 'none']), 'mathtext.bf': GW.QLineEdit, 'mathtext.cal': GW.QLineEdit, 'mathtext.default': GW.QLineEdit, 'mathtext.fallback_to_cm': GW.QCheckBox, 'mathtext.fontset': create_combobox( ['dejavusans', 'cm', 'stix', 'stixsans', 'custom']), 'mathtext.it': GW.QLineEdit, 'mathtext.rm': GW.QLineEdit, 'mathtext.sf': GW.QLineEdit, 'mathtext.tt': GW.QLineEdit, 'patch.antialiased': GW.QCheckBox, 'patch.edgecolor': GW.ColorBox, 'patch.facecolor': GW.ColorBox, 'patch.force_edgecolor': GW.QCheckBox, 'patch.linewidth': GW.FontSizeBox, 'polaraxes.grid': GW.QCheckBox, 'scatter.edgecolors': lambda: AutoToggleBox( GW.ColorBox(), 'face'), 'scatter.marker': GW.MarkerStyleBox, 'text.antialiased': GW.QCheckBox, 'text.color': GW.ColorBox, 'text.hinting': create_combobox( ['either', 'native', 'auto', 'none']), 'text.hinting_factor': GW.IntLineEdit, 'text.latex.preamble': GW.QLineEdit, 'text.latex.preview': GW.QCheckBox, 'text.usetex': GW.QCheckBox, 'timezone': GW.QLineEdit, 'xtick.alignment': create_combobox(['left', 'center', 'right']), 'xtick.bottom': GW.QCheckBox, 'xtick.color': GW.ColorBox, 'xtick.direction': create_combobox(['in', 'out', 'inout']), 'xtick.labelbottom': GW.QCheckBox, 'xtick.labelsize': GW.FontSizeBox, 'xtick.labeltop': GW.QCheckBox, 'xtick.major.bottom': GW.QCheckBox, 'xtick.major.pad': GW.FontSizeBox, 'xtick.major.size': GW.FontSizeBox, 'xtick.major.top': GW.QCheckBox, 'xtick.major.width': GW.FontSizeBox, 'xtick.minor.bottom': GW.QCheckBox, 'xtick.minor.pad': GW.FontSizeBox, 'xtick.minor.size': GW.FontSizeBox, 'xtick.minor.top': GW.QCheckBox, 'xtick.minor.visible': GW.QCheckBox, 'xtick.minor.width': GW.FontSizeBox, 'xtick.top': GW.QCheckBox, 'ytick.alignment': create_combobox( ['left_baseline', 'center_baseline', 'right_baseline']), 'ytick.color': GW.ColorBox, 'ytick.direction': create_combobox(['in', 'out', 'inout']), 'ytick.labelleft': GW.QCheckBox, 'ytick.labelright': GW.QCheckBox, 'ytick.labelsize': GW.FontSizeBox, 'ytick.left': GW.QCheckBox, 'ytick.major.left': GW.QCheckBox, 'ytick.major.pad': GW.FontSizeBox, 'ytick.major.right': GW.QCheckBox, 'ytick.major.size': GW.FontSizeBox, 'ytick.major.width': GW.FontSizeBox, 'ytick.minor.left': GW.QCheckBox, 'ytick.minor.pad': GW.FontSizeBox, 'ytick.minor.right': GW.QCheckBox, 'ytick.minor.size': GW.FontSizeBox, 'ytick.minor.visible': GW.QCheckBox, 'ytick.minor.width': GW.FontSizeBox, 'ytick.right': GW.QCheckBox} # Initialize empty dict of entry_types entry_types = sdict() # Loop over all rcParams and determine what widget to use for key, value in rcParamsDefault.items(): # Check if key starts with anything in prefix_skip if key.startswith(prefix_skip): # If so, continue continue # Obtain proper box box = key_widgets.get(key, GW.LongGenericBox) # If key is 'axes.prop_cycle', obtain the proper value if(key == 'axes.prop_cycle'): value = value.by_key()['color'] # Add box to entry_types dict with default value entry_types[key] = (box, value) # Add all rcParams entries to the box entries_box.addEntryTypes(entry_types)
def hybrid_lnpost(par_set, *args, **kwargs): """ Calculates the natural logarithm of the posterior probability of `par_set` using the provided function `lnpost_fn`, in addition to constraining it first with the emulator defined in the `pipeline_obj`. This function needs to be called by all MPI ranks unless called within the :attr:`~prism.Pipeline.worker_mode` context manager. Parameters ---------- par_set : 1D array_like or dict Sample to calculate the posterior probability for. This sample is first analyzed in `pipeline_obj` and only given to `lnpost_fn` if it is plausible. If `par_dict` is *True*, this is a dict. args : positional arguments Positional arguments that need to be passed to `lnpost_fn`. kwargs : keyword arguments Keyword arguments that need to be passed to `lnpost_fn`. Returns ------- lnp : float The natural logarithm of the posterior probability of `par_set`, as determined by `lnpost_fn` if `par_set` is plausible. If `impl_prior` is *True*, `lnp` is calculated as `lnprior` + `lnpost_fn()`, with `lnprior` the natural logarithm of the first implausibility cut-off value of `par_set` scaled with its maximum. """ # If par_dict is True, convert par_set to a NumPy array if par_dict: sam = np_array(sdict(par_set).values(), ndmin=2) else: sam = np_array(par_set, ndmin=2) # If unit_space is True, convert par_set to par_space if unit_space: sam = pipe._modellink._to_par_space(sam) # Check if par_set is within parameter space and return -inf if not par_rng = pipe._modellink._par_rng if not ((par_rng[:, 0] <= sam[0]) * (sam[0] <= par_rng[:, 1])).all(): return (-np.infty) # Check what sampling is requested and analyze par_set if impl_prior: impl_sam, lnprior = pipe._make_call('_evaluate_sam_set', emul_i, sam, 'hybrid') else: impl_sam = pipe._make_call('_evaluate_sam_set', emul_i, sam, 'analyze') lnprior = 0 # If par_set is plausible, call lnpost_fn if len(impl_sam): return (lnprior + lnpost_fn(par_set, *args, **kwargs)) # If par_set is not plausible, return -inf else: return (-np.infty)
def set_box_value(self, page_dict): """ Sets the current value of the kwargs dict page to `page_dict`. Parameters ---------- page_dict : dict A dict containing all entries that this kwargs dict page must have. Current entries that are also in `page_dict` will be reused, otherwise they are deleted. """ # Make empty dict containing all current valid entries cur_entry_dict = sdict() # Remove all entries from kwargs_grid for row in range(1, self.kwargs_grid.rowCount()): # Obtain item that should contain the entry_type in this row entry_type_item = self.kwargs_grid.itemAtPosition(row, 1) # If entry_type_item is None, this row contains no items if entry_type_item is None: continue # Obtain the entry_type entry_type = get_box_value(entry_type_item.widget()) # Delete this entry if not in page_dict or if it is not allowed if(entry_type not in page_dict or not entry_type or entry_type in self.banned_entries): self.remove_editable_entry(entry_type_item.widget()) continue # If this entry appears multiple times, delete its previous entry if entry_type in cur_entry_dict: for item in cur_entry_dict[entry_type]: item.widget().close() del item cur_entry_dict.pop(entry_type) # Add this entry to cur_entry_dict cur_entry_dict[entry_type] =\ [self.kwargs_grid.takeAt(3) for _ in range(3)] # Loop over all items in page_dict and act accordingly for row, (entry_type, field_value) in enumerate(page_dict.items(), 1): # Check if this entry_type already existed if entry_type in cur_entry_dict: # If so, put it back into kwargs_grid for col, item in enumerate(cur_entry_dict[entry_type]): self.kwargs_grid.addItem(item, row, col) else: # If not, add it to kwargs_grid self.add_editable_entry() # Set this new entry to the proper type set_box_value(self.kwargs_grid.itemAtPosition(row, 1).widget(), entry_type) # Set the value of the corresponding field set_box_value(self.kwargs_grid.itemAtPosition(row, 2).widget(), field_value)
""" # %% IMPORTS # Package imports from sortedcontainers import SortedDict as sdict # All declaration __all__ = [ 'FILE_EXTS', 'FILE_FILTERS', 'FILE_FORMATS', 'FILE_TYPES', 'register_file_format' ] # %% GLOBALS # Define dicts of file extensions, filters, formats and types FILE_EXTS = sdict() FILE_FILTERS = sdict() FILE_FORMATS = sdict() FILE_TYPES = sdict() # %% FUNCTION DEFINITIONS # This function registers a file format # TODO: Should the MIME type of the file also be given? def register_file_format(file_type, file_exts): """ Registers a provided file format with type `file_type` and associated extensions `file_exts` for use in *GuiPy*. All file formats must be registered with this function in order to be used.
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)
def add_config_page(self, config_page): """ Adds a provided `config_page` to this dialog, allowing it to be modified. The name of the config page determines where it will appear in the dialog. Parameters ---------- config_page : :obj:`~guipy.config.BaseConfigPage` object The config page object that must be added to this dialog. """ # Add a stretch to the layout of the page config_page.layout().addStretch() # Create scrollarea for the config page scroll_area = GW.QScrollArea(self) scroll_area.setWidgetResizable(True) scroll_area.setWidget(config_page) # Obtain the page sections of this config page main, sub, tab = self.get_page_sections(config_page.section_name) # Obtain the full page section for this config page page_section = self.config_pages.setdefault( main, sdict()).setdefault(sub, sdict()) # Check if this section existed before if(len(page_section) == 0): # Add the config page as a widget to the page_section and sections self.sections.addWidget(scroll_area) self.contents.addItem(main) # If this is the first section in contents, select it if(self.contents.count() == 1): self.contents.setCurrentRow(0) elif(len(page_section) == 1): # If so, a tab widget will be required tab_widget = GW.QTabWidget() page_section[''] = tab_widget # Obtain the index of the current widget at this section prev_page = page_section.values()[1] index = self.sections.indexOf(prev_page) # Remove this widget self.sections.removeWidget(prev_page) # Add the tab_widget self.sections.insertWidget(index, tab_widget) # Add the previous widget and the new config page to the tab_widget tab_widget.addTab(prev_page, page_section.keys()[1]) tab_widget.addTab(scroll_area, tab) else: # Obtain the current tab widget tab_widget = page_section[''] tab_widget.addTab(scroll_area, tab) # Connect signals get_modified_signal(config_page).connect(self.enable_apply_button) # Add this config page to the proper page section page_section[tab] = scroll_area
def get_walkers(pipeline_obj, *, emul_i=None, init_walkers=None, req_n_walkers=None, unit_space=False, lnpost_fn=None, **kwargs): """ Analyzes proposed `init_walkers` and returns plausible `p0_walkers`. Analyzes sample set `init_walkers` in the provided `pipeline_obj` at iteration `emul_i` and returns all samples that are plausible to be used as starting positions for MCMC walkers. The provided samples and returned walkers should be/are given in unit space if `unit_space` is *True*. If `init_walkers` is *None*, returns :attr:`~prism.Pipeline.impl_sam` instead if it is available. This function needs to be called by all MPI ranks. Parameters ---------- pipeline_obj : :obj:`~prism.Pipeline` object The instance of the :class:`~prism.Pipeline` class that needs to be used for determining the plausibility of the proposed starting positions. Optional -------- %(emul_i)s init_walkers : 2D array_like, dict, int or None. Default: None Sample set of proposed initial MCMC walker positions. All plausible samples in `init_walkers` will be returned. If int, generate an LHD of provided size and return all plausible samples. If *None*, return :attr:`~prism.Pipeline.impl_sam` corresponding to iteration `emul_i` instead. req_n_walkers : int or None. Default: None The minimum required number of plausible starting positions that should be returned. If *None*, all plausible starting positions in `init_walkers` are returned instead. .. versionadded:: 1.2.0 unit_space : bool. Default: False Bool determining whether or not the provided samples and returned walkers are given in unit space. lnpost_fn : function or None. Default: None If function, call :func:`~get_hybrid_lnpost_fn` using `lnpost_fn` and the same values for `pipeline_obj`, `emul_i` and `unit_space`, and return the resulting function definition `hybrid_lnpost()`. Any additionally provided `kwargs` are also passed to it. Returns ------- n_walkers : int Number of returned MCMC walkers. Note that this number can be higher than `req_n_walkers` if not *None*. p0_walkers : 2D :obj:`~numpy.ndarray` object or dict Array containing plausible starting positions of valid MCMC walkers. If `init_walkers` was provided as a dict, `p0_walkers` will be a dict. hybrid_lnpost : function (if `lnpost_fn` is a function) The function returned by :func:`~get_hybrid_lnpost_fn` using `lnpost_fn`, `pipeline_obj`, `emul_i`, `unit_space` and `kwargs` as the input values. See also -------- :func:`~get_hybrid_lnpost_fn` Returns a function definition ``hybrid_lnpost(par_set, *args, **kwargs)``. :attr:`~prism.Pipeline.worker_mode` Special context manager within which all code is executed in worker mode. Notes ----- If `init_walkers` is *None* and emulator iteration `emul_i` has not been analyzed yet, a :class:`~prism._internal.RequestError` will be raised. If `req_n_walkers` is not *None*, a custom Metropolis-Hastings sampling algorithm is used to generate the required number of starting positions. All plausible samples in `init_walkers` are used as the start of every MCMC chain. Note that if the number of plausible samples in `init_walkers` is small, it is possible that the returned `p0_walkers` are not spread out properly over parameter space. """ # Make abbreviation for pipeline_obj pipe = pipeline_obj # Check if provided pipeline_obj is an instance of the Pipeline class if not isinstance(pipe, Pipeline): raise TypeError("Input argument 'pipeline_obj' must be an instance of " "the Pipeline class!") # Check if the provided pipeline_obj uses a default emulator if (pipe._emulator._emul_type != 'default'): raise e13.InputError("Input argument 'pipeline_obj' does not use a " "default emulator!") # Get emulator iteration emul_i = pipe._emulator._get_emul_i(emul_i) # If req_n_walkers is not None, check if it is an integer if req_n_walkers is not None: req_n_walkers = check_vals(req_n_walkers, 'req_n_walkers', 'int', 'pos') # Check if unit_space is a bool unit_space = check_vals(unit_space, 'unit_space', 'bool') # Assume that walkers are not to be returned as a dict walker_dict = False # Check if lnpost_fn is None and try to get hybrid_lnpost function if not if lnpost_fn is not None: try: hybrid_lnpost =\ get_hybrid_lnpost_fn(lnpost_fn, pipe, emul_i=emul_i, unit_space=unit_space, **kwargs) except e13.InputError: raise e13.InputError("Input argument 'lnpost_fn' is invalid!") # If init_walkers is None, use impl_sam of emul_i if init_walkers is None: # Controller checking if emul_i has already been analyzed if pipe._is_controller: # If iteration has not been analyzed, raise error if not pipe._n_eval_sam[emul_i]: raise RequestError("Emulator iteration %i has not been " "analyzed yet!" % (emul_i)) # If iteration is last iteration, init_walkers is current impl_sam elif (emul_i == pipe._emulator._emul_i): init_walkers = pipe._impl_sam # If iteration is not last, init_walkers is previous impl_sam else: init_walkers = pipe._emulator._sam_set[emul_i + 1] # Make sure to make a copy of init_walkers to avoid modifications init_walkers = init_walkers.copy() # Broadcast init_walkers to workers as p0_walkers p0_walkers = pipe._comm.bcast(init_walkers, 0) # If init_walkers is not None, use provided samples or LHD size else: # Controller checking if init_walkers is valid if pipe._is_controller: # If init_walkers is an int, create LHD of provided size if isinstance(init_walkers, int): # Check if provided integer is positive n_sam = check_vals(init_walkers, 'init_walkers', 'pos') # Obtain the par_space to sample in par_space = pipe._get_impl_space(emul_i) # If par_space is None, use the corresponding emul_space if par_space is None: par_space = pipe._emulator._emul_space[emul_i] # Create LHD of provided size init_walkers = e13.lhd(n_sam, pipe._modellink._n_par, par_space, 'center', pipe._criterion, 100) # If init_walkers is not an int, it must be array_like or dict else: # If init_walkers is provided as a dict, convert it if isinstance(init_walkers, dict): # Make sure that init_walkers is a SortedDict init_walkers = sdict(init_walkers) # Convert it to normal init_walkers = np_array(init_walkers.values()).T # Return p0_walkers as a dict walker_dict = True # Make sure that init_walkers is a NumPy array init_walkers = np_array(init_walkers, ndmin=2) # If unit_space is True, convert init_walkers to par_space if unit_space: init_walkers = pipe._modellink._to_par_space(init_walkers) # Check if init_walkers is valid init_walkers = pipe._modellink._check_sam_set( init_walkers, 'init_walkers') # Broadcast init_walkers to workers init_walkers = pipe._comm.bcast(init_walkers, 0) # Analyze init_walkers and save them as p0_walkers p0_walkers = pipe._evaluate_sam_set(emul_i, init_walkers, 'analyze') # Check if init_walkers is not empty and raise error if it is if not p0_walkers.shape[0]: raise e13.InputError("Input argument 'init_walkers' contains no " "plausible samples!") # If req_n_walkers is not None, use MH MCMC to find all required walkers if req_n_walkers is not None: n_walkers, p0_walkers = _do_mh_walkers(pipe, p0_walkers, req_n_walkers) else: p0_walkers = np.unique(p0_walkers, axis=0) n_walkers = p0_walkers.shape[0] # Check if p0_walkers needs to be converted if unit_space: p0_walkers = pipe._modellink._to_unit_space(p0_walkers) # Check if p0_walkers needs to be returned as a dict if walker_dict: p0_walkers = pipe._modellink._get_sam_dict(p0_walkers) # Check if hybrid_lnpost was requested and return it as well if so if lnpost_fn is not None: return (n_walkers, p0_walkers, hybrid_lnpost) else: return (n_walkers, p0_walkers)
"Encapsulated PostScript (*.eps)", "Flexible Image Transport System (*.fits)", "GuiPy Environment File (*.gpy)", "Hierarchical Data Format (*.hdf5 *.hdf4 *.hdf *.h5 *.h4 *.he5 *.he2)", "Joint Photographic Experts Group (*.jpg *.jpeg)", "NumPy Binary File (*.npy)", "NumPy Binary Archive (*.npz)", "Portable Document Format (*.pdf)", "PGF code for LaTeX (*.pgf)", "Portable Network Graphics (*.png)", "Postscript (*.ps)", "Python Script (*.py)", "Raw RGBA Bitmap (*.raw *.rgba)", "Scalable Vector Graphics (*.svg *.svgz)", "Portable Pixmap (*.ppm)", "Text Document (*.txt)", "X11 Bitmap (*.xbm)", "Excel File Format (*.xlsx *.xls)", "X11 Pixmap (*.xpm)" ] # Define dict of data table formatters FORMATTERS = sdict() # %% FUNCTION DEFINITIONS # This function registers a data table formatter def register_formatter(formatter_class): """ Registers a provided data table formatter `formatter_class` for use in *GuiPy*. All data table formatters must be registered with this function in order to be used. Parameters ---------- formatter_class : \
def init(self): """ Sets up the dialog used for setting the configuration in *GuiPy*. """ # Set properties of configuration dialog self.setWindowTitle(self.NAME.replace('&', '')) self.setWindowFlags( QC.Qt.MSWindowsOwnDC | QC.Qt.Dialog | QC.Qt.WindowTitleHint | QC.Qt.WindowSystemMenuHint | QC.Qt.WindowCloseButtonHint) # Create a window layout layout = GL.QVBoxLayout(self) # Create a splitter widget for this window splitter = GW.QSplitter() splitter.setChildrenCollapsible(False) layout.addWidget(splitter) # Create a contents widget contents = GW.QListWidget() contents.setMovement(GW.QListView.Static) contents.setSpacing(1) splitter.addWidget(contents) splitter.setStretchFactor(0, 1) self.contents = contents # Create a sections widget sections = GW.QStackedWidget() splitter.addWidget(sections) splitter.setStretchFactor(1, 4) self.sections = sections # Connect signals contents.currentRowChanged.connect(sections.setCurrentIndex) # Create empty dict of config pages self.config_pages = sdict() # Add a buttonbox button_box = QW.QDialogButtonBox() button_box.clicked.connect(self.buttonWasPressed) layout.addWidget(button_box) self.button_box = button_box # Add an 'Ok' button ok_but = button_box.addButton(button_box.Ok) ok_but.setToolTip("Apply current changes and close the configuration " "window") # Add a 'Cancel' button cancel_but = button_box.addButton(button_box.Cancel) cancel_but.setToolTip("Discard current changes and close the " "configuration window") self.cancel_but = cancel_but # Add an 'Apply' button apply_but = button_box.addButton(button_box.Apply) apply_but.setToolTip("Apply current configuration changes") self.apply_but = apply_but self.disable_apply_button() # Add a 'Reset' button reset_but = button_box.addButton(button_box.Reset) reset_but.setToolTip("Reset configuration values to defaults") # Create a slot dict for all buttons self.slot_dict = { button_box.AcceptRole: [ self.apply_options, self.close], button_box.RejectRole: [ self.discard_options, self.close], button_box.ApplyRole: [ self.apply_options], button_box.ResetRole: [ self.reset_options]} # Set the size of the dialog self.resize(800, 600)