def init(self): # Make layout for setting the value range of the histogram hist_range_layout = GL.QHBoxLayout(self) hist_range_layout.setContentsMargins(0, 0, 0, 0) # Make a box for setting the value range of the histogram # TODO: Maybe use dual lineedits instead to eliminate range problem? hist_range_box = GW.DualSpinBox((float, float), r"<html>≤ X ≤</html>") x_min_box, x_max_box = hist_range_box[:] x_min_box.setRange(-9999999, 9999999) x_min_box.setToolTip("Minimum value to be included in the histogram") x_max_box.setRange(-9999999, 9999999) x_max_box.setToolTip("Maximum value to be included in the histogram") set_box_value(hist_range_box, (0, 0)) hist_range_box.setEnabled(False) self.range_box = hist_range_box # Make a checkbox for enabling/disabling the use of this range hist_range_flag = GW.QCheckBox() hist_range_flag.setToolTip("Toggle the use of a manual histogram value" " range") set_box_value(hist_range_flag, False) self.range_flag = hist_range_flag # Connect signals for hist_range_flag get_modified_signal(hist_range_flag).connect(hist_range_box.setEnabled) # Add everything together hist_range_layout.addWidget(hist_range_flag) hist_range_layout.addWidget(hist_range_box)
def add_data_box(self): """ Adds a new data tab to this plot property. """ # Create a default widget for the new DataND prop data_prop = GW.BaseBox() get_modified_signal(data_prop).connect(self.tab_widget.modified) # Create a dictionary with all requirements of this property prop_kwargs = { req: getattr(self, req) for req in self.data_prop.REQUIREMENTS } # Create the DataND prop prop_layout = self.data_prop(**prop_kwargs) # Set prop_layout as the layout for data_prop data_prop.setLayout(prop_layout) # Obtain the name of this data_prop name = "data_%i" % (self.tab_widget.count()) # Add data_prop to the tab widget index = self.tab_widget.addTab(data_prop, name) # Switch focus to the new tab set_box_value(self.tab_widget, index) # Check if there is now more than a single tab self.tab_widget.setTabsClosable(self.tab_widget.count() > 1)
def reset_config(self): # Initialize restart_flag restart_flag = False # Loop over all config pages and reset their values for name, page in self.config_pages.items(): # Obtain default config_dict config_dict = page.get_default_config() # Set value of page to this dict page.apply_config(config_dict) set_box_value(page, config_dict) # Store config_dict in saved config and parser self.config[name] = config_dict self.parser[name] = page.encode_config(config_dict) # Add restart_flag of page to current restart_flag restart_flag += page.restart_flag page.restart_flag = False # Save config to file self.write_config() # If restart_flag is True, show warning dialog if restart_flag: self.show_restart_warning()
def init(self, widget, text, tooltip): """ Sets up the togglebox after it has been initialized. """ # Create the box_layout box_layout = GL.QHBoxLayout(self) box_layout.setContentsMargins(0, 0, 0, 0) # Create a checkbox for toggling the widget if text is not None: checkbox = GW.QCheckBox(text) else: checkbox = GW.QCheckBox() box_layout.addWidget(checkbox) self.checkbox = checkbox self.left_box = checkbox # Set tooltip if tooltip is not None: checkbox.setToolTip(tooltip) # Add the widget to it box_layout.addWidget(widget) self.widget = widget self.right_box = widget # Connect some signals get_modified_signal(checkbox).connect(widget.setEnabled) # Make sure that the checkbox is unchecked set_box_value(checkbox, False) widget.setEnabled(False)
def set_plot_type(self, plot_type): # Obtain the index of the current plot entry index = self.layout.indexOf(self.plot_entry) # Remove this plot entry self.layout.removeWidget(self.plot_entry) self.plot_entry.close() # If the plot_type is empty, create dummy widget if not plot_type: plot_entry = GW.QWidget() entry_name = self.name # Else, initialize the requested type else: # Initialize the proper entry plot_type = PLOT_TYPES['2D'][plot_type] plot_entry = plot_type(self.figure_widget) entry_name = "%i_%s" % (self.index, plot_type.PREFIX) # Insert the new plot entry self.layout.insertRow(index, plot_entry) # Save new plot entry as the current entry self.plot_entry = plot_entry # Save new entry name set_box_value(self.name_box, entry_name)
def set_color(self, color): """ Sets the current color to the provided `color`, and updates the entry in the combobox and the label accordingly. Parameters ---------- color : str The color that needs to be used as the current color. The provided `color` can be any string that is accepted as a color by matplotlib. If `color` is invalid, the default color is used instead. """ # Check if the combobox currently holds an acceptable input status = self.color_combobox.lineEdit().hasAcceptableInput() # Check status if status: # If valid, add a hash if color is a 6-digit hex string color = re.sub(r"^[\da-fA-F]{6}$", lambda x: '#' + x[0], color) set_box_value(self.color_combobox, color) else: # Else, use the default color color = self.default_color # If combobox currently has no focus, set combobox value as well if not self.color_combobox.hasFocus(): set_box_value(self.color_combobox, color) # Set the color label of the colorbox self.set_color_label(color)
def set_box_value(self, value, *value_sig): # If the given value is a bool and bools are used, convert value if value in (True, False, None) and self.uses_bools: value = str(value) # Set value set_box_value(self, value, *value_sig, no_custom=True)
def revert_table_dimensions(self): # Obtain the current table dimensions n_rows = self.view.rowCount() n_cols = self.view.columnCount() # Set the spinboxes to the proper values set_box_value(self.dimensions_box, (n_rows, n_cols))
def init(self): # Check if this class has been initialized before, and do so if not if not self.init_flag: self.first_init() # Create a layout for this widget box_layout = GL.QHBoxLayout(self) box_layout.setContentsMargins(0, 0, 0, 0) # Create a combobox for cmaps cmaps_box = GW.EditableComboBox() validator = GW.ComboBoxValidator(cmaps_box) cmaps_box.setValidator(validator) # Add all colormaps to cmaps_box for cmap in self.cmaps_cl: cmap_icon = self.cmap_icons[cmap] cmaps_box.addItem(cmap_icon, cmap) # Add some separators for i in reversed(self.cum_len[:-2]): cmaps_box.insertSeparator(i) # Set remaining properties set_box_value(cmaps_box, rcParams['image.cmap']) cmaps_box.setIconSize(QC.QSize(*self.cmap_size)) cmaps_box.completer().popup().setIconSize(QC.QSize(*self.cmap_size)) get_modified_signal(cmaps_box, str).connect(self.cmap_selected) cmaps_box.focusLost.connect( lambda: set_box_value(cmaps_box, get_box_value(cmaps_box, int))) # Add cmaps_box to layout box_layout.addWidget(cmaps_box) self.cmaps_box = cmaps_box
def set_box_value(self, value, *value_sig): # Set value to empty if it uses a different spelling if value.lower() in ('none', ' '): value = '' # Call normal method set_box_value(self, value, *value_sig, no_custom=True)
def add_entry(self): """ Adds a new entry to the entries box. """ # Create a combobox with the name of the entry name_box = self.get_entry_name_box() name_box.setToolTip("Select or type name for this entry") name_box.addItems(self.entry_types.keys()) set_box_value(name_box, -1) get_modified_signal(name_box).connect( lambda: self.create_value_box(name_box)) # Create a 'Delete'-button del_but = GW.QToolButton() del_but.setFixedSize(self.entry_height, self.entry_height) del_but.setToolTip("Delete this entry") get_modified_signal(del_but).connect( lambda: self.remove_entry(name_box)) # If this theme has a 'remove' icon, use it if QG.QIcon.hasThemeIcon('remove'): del_but.setIcon(QG.QIcon.fromTheme('remove')) # Else, use a standard icon else: del_but.setIcon(del_but.style().standardIcon( QW.QStyle.SP_DialogCloseButton)) # Add a new row to the grid layout next_row = self.entries_grid.getItemPosition( self.entries_grid.count() - 1)[0] + 1 self.entries_grid.addWidget(del_but, next_row, 0) self.entries_grid.addWidget(name_box, next_row, 1) self.entries_grid.addWidget(GW.QLabel(), next_row, 2)
def discard_config(self): # Loop over all config pages and discard their values for name, page in self.config_pages.items(): # Obtain config_dict config_dict = self.config[name] # Set value of page to this dict set_box_value(page, config_dict)
def set_box_value(self, value, *value_sig): # If value is a string, it is a font scaling keyword if isinstance(value, str): # Obtain actual float fontsize value = rcParams['font.size'] * font_scalings[value] # Set value set_box_value(self, value, *value_sig, no_custom=True)
def init(self, *args, **kwargs): # Create layout for this scatter plot super().init(*args, **kwargs) # Set the starting color to be the number of scatters already present n_lines = len(self.axis.lines) color = "C%i" % (n_lines % len(rcParams['axes.prop_cycle'])) set_box_value(self.marker_color_box, color)
def set_box_value(self, value, *value_sig): """ Sets the radiobutton with index `value` to *True*. Parameters ---------- value : int The index of the radiobutton that must be set to *True*. """ set_box_value(self[value], True)
def hist_orient_box(self): """ Creates a widget box for setting the orientation property of this histogram and returns it. """ # Make a multi radiobutton hist_orient_box = GW.MultiRadioButton(['Horizontal', 'Vertical']) hist_orient_box.setToolTip("The orientation of the histogram") set_box_value(hist_orient_box, 'Vertical') # Return name and box return ('Orientation', hist_orient_box)
def set_box_value(self, value, *value_sig): """ Sets the current value of the togglebox to `value`. Parameters ---------- value : tuple A tuple containing the values of the checkbox and widget, formatted as `(checkbox, widget)`. """ set_box_value(self.checkbox, value[0]) set_box_value(self.widget, value[1], *value_sig)
def hist_tab_added(self, index): """ This slot is automatically called whenever a new histogram data tab with `index` has been added, and is used for initializing certain aspects of this tab. """ # Obtain the number of data tabs already present n_tabs = self.multi_data_box.count() # Use this number to cycle through MPL's color cycler color = "C%i" % (n_tabs - 1 % len(rcParams['axes.prop_cycle'])) set_box_value(self.multi_data_box, color, index, 'hist_color_box')
def add_tab(self, name=None, import_func=None): # Create a new DataTableWidget data_table = DataTableWidget(self, import_func) # If name is None, set it to default if name is None: name = "table_%i" % (self.tab_widget.count()) data_table.tab_name = name # Add data_table to the tab widget index = self.tab_widget.addTab(data_table, name) # Switch focus to the new tab set_box_value(self.tab_widget, index)
def set_box_value(self, value, *value_sig): """ Sets the value type to `type(value)` and the value to `value`. Parameters ---------- value : bool, float, int or str The value to use for this generic value box. The type of `value` determines which value box must be used. """ set_box_value(self.type_box, type(value).__name__) set_box_value(self.value_box, value, *value_sig)
def add_tab(self, name=None): # Create a new FigureWidget figure = FigureWidget(self.data_table, self.tab_widget.count(), self) # If name is None, set it to default if name is None: name = "figure_%i" % (self.tab_widget.count()) figure.tab_name = name # Add figure to the tab widget index = self.tab_widget.addTab(figure, name) # Switch focus to the new tab set_box_value(self.tab_widget, index)
def __call__(self, col): # Save which column index was requested self.col = col # Get the column that was requested column = self.model.dataColumn(col) # Get the dtype of this column dtype = self.model.dtypes[column.dtype.type] # Determine the names of all other columns used_column_names = set(self.model.columnNames()) used_column_names.difference_update(['', column.name]) self.used_column_names = used_column_names # Set the base name, name and dtype of this column base_name = "Column %s" % (to_base_26(col + 1)) set_box_value(self.base_name_label, base_name) set_box_value(self.n_val_box, column.count()) set_box_value(self.name_box, column.name) set_box_value(self.dtype_box, dtype) # Set keyboard focus to the name_box and select it self.name_box.setFocus(True) self.name_box.selectAll() # Show the popup self.show()
def create_entry_layout(self): # Create layout layout = GL.QFormLayout(self) layout.setContentsMargins(0, 0, 0, 0) self.layout = layout # Create a name editor layout name_layout = GL.QHBoxLayout() layout.addRow('Name', name_layout) # Create entry name editor name_box = GW.QLineEdit() name_box.setToolTip("Name of this plot entry") set_box_value(name_box, self.name) get_modified_signal(name_box).connect(self.entryNameChanged) name_layout.addWidget(name_box) get_modified_signal(name_box).disconnect(self.modified) self.name_box = name_box # Add a toolbutton for deleting this plot entry del_but = GW.QToolButton() del_but.setToolTip("Delete this plot entry") get_modified_signal(del_but).connect(self.entryRemoveRequested) name_layout.addWidget(del_but) # If this theme has a 'remove' icon, use it if QG.QIcon.hasThemeIcon('remove'): del_but.setIcon(QG.QIcon.fromTheme('remove')) # Else, use a standard icon else: del_but.setIcon(del_but.style().standardIcon( QW.QStyle.SP_DialogCloseButton)) # Create a combobox for choosing a plot type plot_types = GW.QComboBox() plot_types.addItems(PLOT_TYPES['2D']) plot_types.setToolTip("Select the plot type you wish to use for this " "plot entry") set_box_value(plot_types, -1) get_modified_signal(plot_types).connect(self.set_plot_type) layout.addRow('Type', plot_types) self.plot_types = plot_types # Add a separator layout.addSeparator() # Create a dummy entry to start off self.plot_entry = GW.QWidget() layout.addRow(self.plot_entry)
def draw_plot(self): # Obtain the x and y columns try: xcol = get_box_value(self.x_data_box)[1] ycol = get_box_value(self.y_data_box)[1] # If any of the columns cannot be called, return except IndexError: self.remove_plot() return # If either xcol or ycol is None, return if xcol is None or ycol is None: self.remove_plot() return # If xcol and ycol are not the same shape, return if (len(xcol) != len(ycol)): self.remove_plot() return # If the current saved scatter is not already in the figure, make one if self.plot not in self.axis.lines: # Make and update plot self.plot = self.axis.plot(xcol, ycol)[0] self.plot.set_linestyle('') # Obtain label currently set in label box label = get_box_value(self.data_label_box) # If label is not empty, reuse it in the plot if label: self.plot.set_label(label) # Else, obtain its label from MPL else: set_box_value(self.data_label_box, self.plot.get_label()) # If the figure currently has no title, set it title_box = self.options.title_box[0] if not get_box_value(title_box): set_box_value(title_box, "%s vs. %s" % (xcol.name, ycol.name)) # If the figure currently has no axes labels, set them x_label_box = self.options.x_label_box[0] y_label_box = self.options.y_label_box[0] if not (get_box_value(x_label_box) or get_box_value(y_label_box)): set_box_value(x_label_box, xcol.name) set_box_value(y_label_box, ycol.name) # If it does exist, check if it requires updating else: # Obtain the data currently used for this plot xcol_cur = self.plot.get_xdata() ycol_cur = self.plot.get_ydata() # If there are differences, update plot if not (xcol_cur == xcol).all(): self.plot.set_xdata(xcol) if not (ycol_cur == ycol).all(): self.plot.set_ydata(ycol)
def set_box_value(self, value, *value_sig): """ Sets the current value of the figure label box to `value`. Parameters ---------- value : tuple A tuple containing the values of the figure label box, formatted as `(label, {'fontsize': size})`. """ # Set box value of label and size set_box_value(self.left_box, value[0]) set_box_value(self.right_box, value[1]['fontsize'])
def add_config_page(self, config_page): """ Adds a provided :obj:`~guipy.config.BaseConfigPage` `config_page` to the config manager. """ # Add config page to dialog self.config_dialog.add_config_page(config_page) # Obtain the section name of this config page section_name = config_page.section_name # Add the config_page to the config_pages dict self.config_pages[section_name] = config_page # Check if the section already exists, add it if not if not self.parser.has_section(section_name): self.parser.add_section(section_name) # Obtain the associated config section from the parser config_section = self.parser[section_name] # Parse the config section belonging to this config page parsed_dict = config_page.decode_config(config_section) # Obtain the default config of this section config_dict = config_page.get_default_config() # Update default dict with parsed dict config_dict.update(parsed_dict) # Add this config_dict to the global config self.config[section_name] = config_dict # Set this config_dict as the current values config_page.apply_config(config_dict) set_box_value(config_page, config_dict) # Revert flags that were set due to the config page being modified self.config_dialog.disable_apply_button() config_page.restart_flag = False # Get updated config section from the config page config_section = config_page.encode_config(config_dict) # Update the parser with the config_section self.parser[section_name] = config_section
def set_box_value(self, value_list, *value_sig): """ Sets the values of the items in this items box to the provided `value_list`. Parameters ---------- value_list : list A list containing the values of all items that must be set in this items box. """ # Hide the items box to allow for its values to be set properly self.hide() # Remove all items from the items box, registering their values cur_items_dict = {} for _ in range(self.itemCount()): # Remove this item and obtain its value layout = self.items_layout.takeAt(0) value = get_box_value(layout.itemAt(1).widget()) # Check if it is required later if value in value_list: # If so, store for later cur_items_dict[value] = layout else: # If not, delete it self.remove_item(layout) # Add all items in value_list for row, value in enumerate(value_list): # Check if this value is in cur_items_dict if value in cur_items_dict: # If so, put it back into the items box self.items_layout.insertLayout(row, cur_items_dict.pop(value)) else: # If not, add a new item self.add_item() # Set the value of this item item_layout = self.items_layout.itemAt(row) item_box = item_layout.itemAt(1).widget() set_box_value(item_box, value) # Show the items box again now that its values have been set self.show()
def discard_options(self): """ Discards the current values of all figure options and sets them back to their saved values. """ # Emit the discarding signal self.discarding.emit() # Discard all current changes for widget, value in self.options_dict.items(): set_box_value(widget, value) # Disable the apply button self.disable_apply_button()
def line_style_box(self): """ Creates a widget box for setting the style of this line plot and returns it. """ # Make combobox for linestyles line_style_box = GW.LineStyleBox() line_style_box.setToolTip("Linestyle to be used for this line plot") # Set initial value to the default value in MPL set_box_value(line_style_box, rcParams['lines.linestyle']) # Return name and box return ('Style', line_style_box)
def marker_style_box(self): """ Creates a widget box for setting the style of the marker and returns it. """ # Make combobox for markerstyles marker_style_box = GW.MarkerStyleBox() marker_style_box.setToolTip("Marker to be used for this plot") # Set initial value to the default value in MPL set_box_value(marker_style_box, self.default_marker) # Return name and box return ('Style', marker_style_box)