def test_contour_plot_returns_contour(self): ax = plt.subplot(111) ax.imshow([[1], [1]]) ax.contour([[1, 1], [1, 1]]) if LooseVersion("3.5") <= LooseVersion(matplotlib.__version__): self.assertEqual(FigureType.Image, figure_type(ax.figure)) else: self.assertEqual(FigureType.Contour, figure_type(ax.figure))
def set_buttons_visibility(self, fig): if figure_type(fig) not in [FigureType.Line, FigureType.Errorbar ] or len(fig.get_axes()) > 1: self.set_fit_enabled(False) self.set_superplot_enabled(False) # if any of the lines are a sample log plot disable fitting for ax in fig.get_axes(): for artist in ax.get_lines(): try: if ax.get_artists_sample_log_plot_details( artist) is not None: self.set_fit_enabled(False) break except Exception: # The artist is not tracked - ignore this one and check the rest continue # For plot-to-script button to show, every axis must be a MantidAxes with lines in it # Plot-to-script currently doesn't work with waterfall plots so the button is hidden for that plot type. if not all((isinstance(ax, MantidAxes) and curve_in_ax(ax)) for ax in fig.get_axes()) or \ fig.get_axes()[0].is_waterfall(): self.set_generate_plot_script_enabled(False) # reenable script generation for colormaps if self.is_colormap(fig): self.set_generate_plot_script_enabled(True) # Only show options specific to waterfall plots if the axes is a MantidAxes and is a waterfall plot. if not isinstance(fig.get_axes()[0], MantidAxes) or not fig.get_axes()[0].is_waterfall(): self.set_waterfall_options_enabled(False) # For contour and wireframe plots, add a toolbar option to change the colour of the lines. if figure_type(fig) in [FigureType.Wireframe, FigureType.Contour]: self.set_up_color_selector_toolbar_button(fig) if figure_type(fig) in [ FigureType.Surface, FigureType.Wireframe, FigureType.Mesh ]: self.adjust_for_3d_plots() # Determine the toggle state of the grid button. If all subplots have grids, then set it to on. is_major_grid_on = False for ax in fig.get_axes(): # Don't look for grids on colour bars. if self._is_colorbar(ax): continue if hasattr(ax, 'grid_on'): is_major_grid_on = ax.grid_on() else: is_major_grid_on = ax.xaxis._major_tick_kw.get( 'gridOn', False) and ax.yaxis._major_tick_kw.get( 'gridOn', False) # If ANY of the axes have no grid, set the button to unchecked. if not is_major_grid_on: break self._actions['toggle_grid'].setChecked(is_major_grid_on)
def _plot_on_here(self, names, ax): """ Assume the list of strings refer to workspace names and they are to be plotted on this figure. If the current figure contains an image plot then a new image plot will replace the current image. If the current figure contains a line plot then the user will be asked what should be plotted and this will overplot onto the figure. If the first line of the plot :param names: A list of workspace names :param ax: The matplotlib axes object to overplot onto """ if len(names) == 0: return # local import to avoid circular import with FigureManager from mantidqt.plotting.functions import pcolormesh, plot_from_names, plot_surface, plot_wireframe, plot_contour fig = self._canvas.figure fig_type = figure_type(fig, ax) if fig_type == FigureType.Image: pcolormesh(names, fig=fig) elif fig_type == FigureType.Surface: plot_surface(names, fig=fig) elif fig_type == FigureType.Wireframe: plot_wireframe(names, fig=fig) elif fig_type == FigureType.Contour: plot_contour(names, fig=fig) else: plot_from_names(names, errors=(fig_type == FigureType.Errorbar), overplot=ax, fig=fig)
def set_up_color_selector_toolbar_button(self, fig): # check if the action is already in the toolbar if self._actions.get('line_colour'): return a = self.addAction(get_icon('mdi.palette'), "Line Colour", lambda: None) self._actions['line_colour'] = a if figure_type(fig) == FigureType.Wireframe: a.setToolTip("Set the colour of the wireframe.") else: a.setToolTip("Set the colour of the contour lines.") line_collection = next(col for col in fig.get_axes()[0].collections if isinstance(col, LineCollection)) initial_colour = convert_color_to_hex(line_collection.get_color()[0]) colour_dialog = QtWidgets.QColorDialog(QtGui.QColor(initial_colour)) colour_dialog.setOption(QtWidgets.QColorDialog.NoButtons) colour_dialog.setOption(QtWidgets.QColorDialog.DontUseNativeDialog) colour_dialog.currentColorChanged.connect(self.change_line_collection_colour) button = [child for child in self.children() if isinstance(child, QtWidgets.QToolButton)][-1] menu = QtWidgets.QMenu("Menu", parent=button) colour_selector_action = QtWidgets.QWidgetAction(menu) colour_selector_action.setDefaultWidget(colour_dialog) menu.addAction(colour_selector_action) button.setMenu(menu) button.setPopupMode(QtWidgets.QToolButton.InstantPopup)
def __init__(self, canvas, axes, axis_id): """ :param canvas: A reference to the target canvas :param axes: The axes object holding the properties to be edited :param axis_id: A string ID for the axis """ super(AxisEditor, self).__init__('axiseditor.ui', canvas) # suppress errors self.ui.errors.hide() # Ensure that only floats can be entered self.ui.editor_min.setValidator(QDoubleValidator()) self.ui.editor_max.setValidator(QDoubleValidator()) if figure_type(canvas.figure) == FigureType.Image: self.ui.logBox.hide() self.ui.gridBox.hide() self.axes = axes self.axis_id = axis_id self.lim_setter = getattr(axes, 'set_{}lim'.format(axis_id)) self.scale_setter = getattr(axes, 'set_{}scale'.format(axis_id)) self.linthresholdkw = 'linthres' + axis_id # Grid has no direct accessor from the axes axis = axes.xaxis if axis_id == 'x' else axes.yaxis memento = AxisEditorModel() self._memento = memento memento.min, memento.max = getattr(axes, 'get_{}lim'.format(axis_id))() memento.log = getattr(axes, 'get_{}scale'.format(axis_id))() != 'linear' memento.grid = axis.majorTicks[0].gridOn self._fill(memento)
def __init__(self, canvas, axes, axis_id): """ :param canvas: A reference to the target canvas :param axes: The axes object holding the properties to be edited :param axis_id: A string ID for the axis """ super(AxisEditor, self).__init__('axiseditor.ui', canvas) # suppress errors self.ui.errors.hide() # Ensure that only floats can be entered self.ui.editor_min.setValidator(QDoubleValidator()) self.ui.editor_max.setValidator(QDoubleValidator()) if figure_type( canvas.figure) in [FigureType.Surface, FigureType.Wireframe]: self.ui.logBox.hide() self.ui.gridBox.hide() self.ui.editor_format.addItem('Decimal Format') self.ui.editor_format.addItem('Scientific Format') self.axes = axes self.axis_id = axis_id self.lim_getter = getattr(axes, 'get_{}lim'.format(axis_id)) if isinstance(axes, Axes3D): self.lim_setter = getattr(axes, 'set_{}lim3d'.format(axis_id)) else: self.lim_setter = getattr(axes, 'set_{}lim'.format(axis_id)) self.scale_setter = getattr(axes, 'set_{}scale'.format(axis_id)) self.nonposkw = 'nonpos' + axis_id # Grid has no direct accessor from the axes self.axis = axes.xaxis if axis_id == 'x' else axes.yaxis
def __init__(self, canvas, axes, axis_id): """ :param canvas: A reference to the target canvas :param axes: The axes object holding the properties to be edited :param axis_id: A string ID for the axis """ super(AxisEditor, self).__init__('axiseditor.ui', canvas) # suppress errors self.ui.errors.hide() # Ensure that only floats can be entered self.ui.editor_min.setValidator(QDoubleValidator()) self.ui.editor_max.setValidator(QDoubleValidator()) if figure_type(canvas.figure) in [ FigureType.Surface, FigureType.Wireframe, FigureType.Mesh ]: self.ui.logBox.hide() self.ui.gridBox.hide() self.ui.editor_format.addItem(DECIMAL_FORMAT) self.ui.editor_format.addItem(SCIENTIFIC_FORMAT) self.axes = axes self.axis_id = axis_id self.lim_getter = getattr(axes, 'get_{}lim'.format(axis_id)) if isinstance(axes, Axes3D): self.lim_setter = getattr(axes, 'set_{}lim3d'.format(axis_id)) else: self.lim_setter = getattr(axes, 'set_{}lim'.format(axis_id)) self.scale_setter = getattr(axes, 'set_{}scale'.format(axis_id)) self.nonposkw = 'nonpos' + axis_id # Store the axis for attributes that can't be directly accessed # from axes object (e.g. grid and tick parameters). self.axis = getattr(axes, '{}axis'.format(axis_id))
def __init__(self, canvas, axes, axis_id): """ :param canvas: A reference to the target canvas :param axes: The axes object holding the properties to be edited :param axis_id: A string ID for the axis """ super(AxisEditor, self).__init__('axiseditor.ui', canvas) # suppress errors self.ui.errors.hide() # Ensure that only floats can be entered self.ui.editor_min.setValidator(QDoubleValidator()) self.ui.editor_max.setValidator(QDoubleValidator()) if figure_type(canvas.figure) == FigureType.Image: self.ui.logBox.hide() self.ui.gridBox.hide() self.axes = axes self.axis_id = axis_id self.lim_setter = getattr(axes, 'set_{}lim'.format(axis_id)) self.scale_setter = getattr(axes, 'set_{}scale'.format(axis_id)) self.linthresholdkw = 'linthres' + axis_id # Grid has no direct accessor from the axes axis = axes.xaxis if axis_id == 'x' else axes.yaxis memento = AxisEditorModel() self._momento = memento memento.min, memento.max = getattr(axes, 'get_{}lim'.format(axis_id))() memento.log = getattr(axes, 'get_{}scale'.format(axis_id))() != 'linear' memento.grid = axis.majorTicks[0].gridOn self._fill(memento)
def show(self): self.window.show() self.window.activateWindow() self.window.raise_() if self.window.windowState() & Qt.WindowMinimized: # windowState() stores a combination of window state enums # and multiple window states can be valid. On Windows # a window can be both minimized and maximized at the # same time, so we make a check here. For more info see: # http://doc.qt.io/qt-5/qt.html#WindowState-enum if self.window.windowState() & Qt.WindowMaximized: self.window.setWindowState(Qt.WindowMaximized) else: self.window.setWindowState(Qt.WindowNoState) # Hack to ensure the canvas is up to date self.canvas.draw_idle() if figure_type(self.canvas.figure) not in [FigureType.Line, FigureType.Errorbar] \ or self.toolbar is not None and len(self.canvas.figure.get_axes()) > 1: self._set_fit_enabled(False) # For plot-to-script button to show, we must have a MantidAxes with lines in it # Plot-to-script currently doesn't work with waterfall plots so the button is hidden for that plot type. if not any((isinstance(ax, MantidAxes) and curve_in_ax(ax)) for ax in self.canvas.figure.get_axes() ) or self.canvas.figure.get_axes()[0].is_waterfall(): self.toolbar.set_generate_plot_script_enabled(False) # Only show options specific to waterfall plots if the axes is a MantidAxes and is a waterfall plot. if not isinstance(self.canvas.figure.get_axes()[0], MantidAxes) or not self.canvas.figure.get_axes( )[0].is_waterfall(): self.toolbar.set_waterfall_options_enabled(False)
def _toggle_normalization(self, selected_ax): if figure_type(self.canvas.figure) == FigureType.Image and len(self.canvas.figure.get_axes()) > 1: axes = datafunctions.get_axes_from_figure(self.canvas.figure) else: axes = [selected_ax] for ax in axes: waterfall = isinstance(ax, MantidAxes) and ax.is_waterfall() if waterfall: x, y = ax.waterfall_x_offset, ax.waterfall_y_offset has_fill = ax.waterfall_has_fill() if has_fill: line_colour_fill = datafunctions.waterfall_fill_is_line_colour(ax) if line_colour_fill: fill_colour = None else: fill_colour = datafunctions.get_waterfall_fills(ax)[0].get_facecolor() ax.update_waterfall(0, 0) # The colorbar can get screwed up with ragged workspaces and log scales as they go # through the normalisation toggle. # Set it to Linear and change it back after if necessary, since there's no reason # to duplicate the handling. colorbar_log = False if ax.images: colorbar_log = isinstance(ax.images[-1].norm, LogNorm) if colorbar_log: self._change_colorbar_axes(Normalize) self._change_plot_normalization(ax) if ax.lines: # Relim causes issues with colour plots, which have no lines. ax.relim() ax.autoscale() if ax.images: # Colour bar limits are wrong if workspace is ragged. Set them manually. colorbar_min = np.nanmin(ax.images[-1].get_array()) colorbar_max = np.nanmax(ax.images[-1].get_array()) for image in ax.images: image.set_clim(colorbar_min, colorbar_max) # Update the colorbar label cb = image.colorbar if cb: datafunctions.add_colorbar_label(cb, ax.get_figure().axes) if colorbar_log: # If it had a log scaled colorbar before, put it back. self._change_colorbar_axes(LogNorm) axesfunctions.update_colorplot_datalimits(ax, ax.images) datafunctions.set_initial_dimensions(ax) if waterfall: ax.update_waterfall(x, y) if has_fill: ax.set_waterfall_fill(True, fill_colour) self.canvas.draw()
def _show_context_menu(self, event): """Display a relevant context menu on the canvas :param event: The MouseEvent that generated this call """ if not event.inaxes: # the current context menus are ony relevant for axes return fig_type = figure_type(self.canvas.figure) if fig_type == FigureType.Empty: # Fitting or changing scale types does not make sense in this case return menu = QMenu() if fig_type == FigureType.Image or fig_type == FigureType.Contour: if isinstance(event.inaxes, MantidAxes): self._add_axes_scale_menu(menu, event.inaxes) self._add_normalization_option_menu(menu, event.inaxes) self._add_colorbar_axes_scale_menu(menu, event.inaxes) elif fig_type == FigureType.Surface: self._add_colorbar_axes_scale_menu(menu, event.inaxes) elif fig_type != FigureType.Wireframe: if self.fit_browser.tool is not None: self.fit_browser.add_to_menu(menu) menu.addSeparator() self._add_axes_scale_menu(menu, event.inaxes) if isinstance(event.inaxes, MantidAxes): self._add_normalization_option_menu(menu, event.inaxes) self.add_error_bars_menu(menu, event.inaxes) self._add_marker_option_menu(menu, event) self._add_plot_type_option_menu(menu, event.inaxes) menu.exec_(QCursor.pos())
def _toggle_normalization(self, ax): waterfall = isinstance(ax, MantidAxes) and ax.is_waterfall() if waterfall: x, y = ax.waterfall_x_offset, ax.waterfall_y_offset has_fill = ax.waterfall_has_fill() if has_fill: line_colour_fill = datafunctions.waterfall_fill_is_line_colour(ax) if line_colour_fill: fill_colour = None else: fill_colour = datafunctions.get_waterfall_fills(ax)[0].get_facecolor() ax.update_waterfall(0, 0) is_normalized = self._is_normalized(ax) for arg_set in ax.creation_args: if arg_set['workspaces'] in ax.tracked_workspaces: workspace = ads.retrieve(arg_set['workspaces']) arg_set['distribution'] = is_normalized arg_set_copy = copy(arg_set) [ arg_set_copy.pop(key) for key in ['function', 'workspaces', 'autoscale_on_update', 'norm'] if key in arg_set_copy.keys() ] if 'specNum' not in arg_set: if 'wkspIndex' in arg_set: arg_set['specNum'] = workspace.getSpectrum( arg_set.pop('wkspIndex')).getSpectrumNo() else: raise RuntimeError("No spectrum number associated with plot of " "workspace '{}'".format(workspace.name())) # 2D plots have no spec number so remove it if figure_type(self.canvas.figure) == FigureType.Image: arg_set_copy.pop('specNum') for ws_artist in ax.tracked_workspaces[workspace.name()]: if ws_artist.spec_num == arg_set.get('specNum'): ws_artist.is_normalized = not is_normalized ws_artist.replace_data(workspace, arg_set_copy) if ax.lines: # Relim causes issues with colour plots, which have no lines. ax.relim() if ax.images: # Colour bar limits are wrong if workspace is ragged. Set them manually. colorbar_min = np.nanmin(ax.images[-1].get_array()) colorbar_max = np.nanmax(ax.images[-1].get_array()) for image in ax.images: image.set_clim(colorbar_min, colorbar_max) ax.autoscale() datafunctions.set_initial_dimensions(ax) if waterfall: ax.update_waterfall(x, y) if has_fill: ax.set_waterfall_fill(True, fill_colour) self.canvas.draw()
def is_colormap(self, fig): """Identify as a single colour map if it has a axes, one with the plot and the other the colorbar""" if figure_type(fig) in [FigureType.Image] and len(fig.get_axes()) == 2: if len(fig.get_axes()[0].get_images()) == 1 and len(fig.get_axes()[1].get_images()) == 0 \ and self._is_colorbar(fig.get_axes()[1]): return True else: return False
def set_buttons_visiblity(self, fig): if figure_type(fig) not in [FigureType.Line, FigureType.Errorbar ] or len(fig.get_axes()) > 1: self.set_fit_enabled(False) # if any of the lines are a sample log plot disable fitting for ax in fig.get_axes(): for artist in ax.get_lines(): try: if ax.get_artists_sample_log_plot_details( artist) is not None: self.set_fit_enabled(False) break except Exception: # The artist is not tracked - ignore this one and check the rest continue # For plot-to-script button to show, every axis must be a MantidAxes with lines in it # Plot-to-script currently doesn't work with waterfall plots so the button is hidden for that plot type. if not all((isinstance(ax, MantidAxes) and curve_in_ax(ax)) for ax in fig.get_axes()) or \ fig.get_axes()[0].is_waterfall(): self.set_generate_plot_script_enabled(False) # reenable script generation for colormaps if self.is_colormap(fig): self.set_generate_plot_script_enabled(True) # Only show options specific to waterfall plots if the axes is a MantidAxes and is a waterfall plot. if not isinstance(fig.get_axes()[0], MantidAxes) or not fig.get_axes()[0].is_waterfall(): self.set_waterfall_options_enabled(False) # For contour and wireframe plots, add a toolbar option to change the colour of the lines. if figure_type(fig) in [FigureType.Wireframe, FigureType.Contour]: self.set_up_color_selector_toolbar_button(fig) if figure_type(fig) in [FigureType.Surface, FigureType.Wireframe]: self.adjust_for_3d_plots()
def _change_plot_normalization(self, ax): is_normalized = self._is_normalized(ax) for arg_set in ax.creation_args: if arg_set['function'] == 'contour': continue if arg_set['workspaces'] in ax.tracked_workspaces: workspace = ads.retrieve(arg_set['workspaces']) arg_set['distribution'] = is_normalized arg_set_copy = copy(arg_set) [ arg_set_copy.pop(key) for key in ['function', 'workspaces', 'autoscale_on_update', 'norm'] if key in arg_set_copy.keys() ] if 'specNum' not in arg_set: if 'wkspIndex' in arg_set: arg_set['specNum'] = workspace.getSpectrum( arg_set.pop('wkspIndex')).getSpectrumNo() else: raise RuntimeError( "No spectrum number associated with plot of " "workspace '{}'".format(workspace.name())) # 2D plots have no spec number so remove it if figure_type(self.canvas.figure) in [ FigureType.Image, FigureType.Contour ]: arg_set_copy.pop('specNum') for ws_artist in ax.tracked_workspaces[workspace.name()]: if ws_artist.spec_num == arg_set_copy.get('specNum'): ws_artist.is_normalized = not is_normalized # This check is to prevent the contour lines being re-plotted using the colorfill plot args. if isinstance(ws_artist._artists[0], QuadContourSet): contour_line_colour = ws_artist._artists[ 0].collections[0].get_color() ws_artist.replace_data(workspace, None) # Re-apply the contour line colour for col in ws_artist._artists[0].collections: col.set_color(contour_line_colour) else: ws_artist.replace_data(workspace, arg_set_copy)
def can_overplot(): """ Checks if overplotting on the current figure can proceed with the given options :return: A 2-tuple of boolean indicating compatability and a string containing an error message if the current figure is not compatible. """ compatible = False msg = "Unable to overplot on currently active plot type.\n" \ "Please select another plot." fig = current_figure_or_none() if fig is not None: figtype = figure_type(fig) if figtype is FigureType.Line or figtype is FigureType.Errorbar: compatible, msg = True, None return compatible, msg
def show(self): # noqa self.window.show() self.window.activateWindow() self.window.raise_() if self.window.windowState() & Qt.WindowMinimized: # windowState() stores a combination of window state enums # and multiple window states can be valid. On Windows # a window can be both minimized and maximized at the # same time, so we make a check here. For more info see: # http://doc.qt.io/qt-5/qt.html#WindowState-enum if self.window.windowState() & Qt.WindowMaximized: self.window.setWindowState(Qt.WindowMaximized) else: self.window.setWindowState(Qt.WindowNoState) # Hack to ensure the canvas is up to date self.canvas.draw_idle() if figure_type(self.canvas.figure) not in [FigureType.Line, FigureType.Errorbar]: self._set_fit_enabled(False)
def can_overplot(): """ Checks if overplotting on the current figure can proceed with the given options :return: A 2-tuple of boolean indicating compatability and a string containing an error message if the current figure is not compatible. """ compatible = False fig = current_figure_or_none() if fig is not None: figtype = figure_type(fig) if figtype in [ FigureType.Line, FigureType.Errorbar, FigureType.Waterfall ]: compatible = True return compatible
def can_overplot(): """ Checks if overplotting on the current figure can proceed with the given options :return: A 2-tuple of boolean indicating compatability and a string containing an error message if the current figure is not compatible. """ compatible = False msg = "Unable to overplot on currently active plot type.\n" \ "Please select another plot." fig = current_figure_or_none() if fig is not None: figtype = figure_type(fig) if figtype is FigureType.Line or figtype is FigureType.Errorbar: compatible, msg = True, None return compatible, msg
def show(self): # noqa self.window.show() self.window.activateWindow() self.window.raise_() if self.window.windowState() & Qt.WindowMinimized: # windowState() stores a combination of window state enums # and multiple window states can be valid. On Windows # a window can be both minimized and maximized at the # same time, so we make a check here. For more info see: # http://doc.qt.io/qt-5/qt.html#WindowState-enum if self.window.windowState() & Qt.WindowMaximized: self.window.setWindowState(Qt.WindowMaximized) else: self.window.setWindowState(Qt.WindowNoState) # Hack to ensure the canvas is up to date self.canvas.draw_idle() if figure_type(self.canvas.figure) != FigureType.Line: self._set_fit_enabled(False)
def _toggle_normalization(self, ax): waterfall = isinstance(ax, MantidAxes) and ax.is_waterfall() if waterfall: x, y = ax.waterfall_x_offset, ax.waterfall_y_offset ax.update_waterfall(0, 0) is_normalized = self._is_normalized(ax) for arg_set in ax.creation_args: if arg_set['workspaces'] in ax.tracked_workspaces: workspace = ads.retrieve(arg_set['workspaces']) arg_set['distribution'] = is_normalized arg_set_copy = copy(arg_set) [ arg_set_copy.pop(key) for key in ['function', 'workspaces', 'autoscale_on_update', 'norm'] if key in arg_set_copy.keys() ] if 'specNum' not in arg_set: if 'wkspIndex' in arg_set: arg_set['specNum'] = workspace.getSpectrum( arg_set.pop('wkspIndex')).getSpectrumNo() else: raise RuntimeError( "No spectrum number associated with plot of " "workspace '{}'".format(workspace.name())) # 2D plots have no spec number so remove it if figure_type(self.canvas.figure) == FigureType.Image: arg_set_copy.pop('specNum') for ws_artist in ax.tracked_workspaces[workspace.name()]: if ws_artist.spec_num == arg_set.get('specNum'): ws_artist.is_normalized = not is_normalized ws_artist.replace_data(workspace, arg_set_copy) if ax.lines: # Relim causes issues with colour plots, which have no lines. ax.relim() ax.autoscale() if waterfall: datafunctions.set_initial_dimensions(ax) ax.update_waterfall(x, y) self.canvas.draw()
def _show_context_menu(self, event): """Display a relevant context menu on the canvas :param event: The MouseEvent that generated this call """ if not event.inaxes: # the current context menus are ony relevant for axes return fig_type = figure_type(self.canvas.figure) if fig_type == FigureType.Empty or fig_type == FigureType.Image: # Fitting or changing scale types does not make sense in # these cases return menu = QMenu() if self.fit_browser.tool is not None: self.fit_browser.add_to_menu(menu) menu.addSeparator() self._add_axes_scale_menu(menu) menu.exec_(QCursor.pos())
def _plot_on_here(self, names): """ Assume the list of strings refer to workspace names and they are to be plotted on this figure. If the current figure contains an image plot then a new image plot will replace the current image. If the current figure contains a line plot then the user will be asked what should be plotted and this will overplot onto the figure. If the first line of the plot :param names: A list of workspace names """ if len(names) == 0: return # local import to avoid circular import with FigureManager from mantidqt.plotting.functions import pcolormesh_from_names, plot_from_names fig = self._canvas.figure fig_type = figure_type(fig) if fig_type == FigureType.Image: pcolormesh_from_names(names, fig=fig) else: plot_from_names(names, errors=(fig_type == FigureType.Errorbar), overplot=True, fig=fig)
def _show_markers_menu(self, markers, event): """ This is opened when right-clicking on top of a marker. The menu will have an entry for each marker near the cursor at the time of clicking. The menu will allow deletion and single marker editing :param markers: list of markers close to the cursor at the time of clicking :param event: The MouseEvent that generated this call """ if not event.inaxes: return QApplication.restoreOverrideCursor() fig_type = figure_type(self.canvas.figure) if fig_type == FigureType.Empty or fig_type == FigureType.Image: return menu = QMenu() for marker in markers: self._single_marker_menu(menu, marker) menu.exec_(QCursor.pos())
def _show_context_menu(self, event): """Display a relevant context menu on the canvas :param event: The MouseEvent that generated this call """ if not event.inaxes: # the current context menus are ony relevant for axes return fig_type = figure_type(self.canvas.figure) if fig_type == FigureType.Empty: # Fitting or changing scale types does not make sense in this case return menu = QMenu() if fig_type == FigureType.Image: if isinstance(event.inaxes, MantidAxes): self._add_axes_scale_menu(menu, event.inaxes) self._add_normalization_option_menu(menu, event.inaxes) self._add_colorbar_axes_scale_menu(menu, event.inaxes) else: if self.fit_browser.tool is not None: self.fit_browser.add_to_menu(menu) menu.addSeparator() self._add_axes_scale_menu(menu, event.inaxes) if isinstance(event.inaxes, MantidAxes): self._add_normalization_option_menu(menu, event.inaxes) self.add_error_bars_menu(menu, event.inaxes) self._add_marker_option_menu(menu, event) # Able to change the plot type to waterfall if there is only one axes, it is a MantidAxes, and there is more # than one line on the axes. if len(event.inaxes.get_figure().get_axes()) == 1 and isinstance(event.inaxes, MantidAxes)\ and len(event.inaxes.get_lines()) > 1: self._add_plot_type_option_menu(menu, event.inaxes) menu.exec_(QCursor.pos())
def show(self): self.window.show() self.window.activateWindow() self.window.raise_() if self.window.windowState() & Qt.WindowMinimized: # windowState() stores a combination of window state enums # and multiple window states can be valid. On Windows # a window can be both minimized and maximized at the # same time, so we make a check here. For more info see: # http://doc.qt.io/qt-5/qt.html#WindowState-enum if self.window.windowState() & Qt.WindowMaximized: self.window.setWindowState(Qt.WindowMaximized) else: self.window.setWindowState(Qt.WindowNoState) # Hack to ensure the canvas is up to date self.canvas.draw_idle() if figure_type(self.canvas.figure) not in [FigureType.Line, FigureType.Errorbar]: self._set_fit_enabled(False) # For plot-to-script button to show, we must have a MantidAxes with lines in it if not any((isinstance(ax, MantidAxes) and curve_in_ax(ax)) for ax in self.canvas.figure.get_axes()): self._set_generate_plot_script_enabled(False)
def test_error_plot_returns_error(self): ax = plt.subplot(111) ax.errorbar([1], [1], yerr=[0.01]) self.assertEqual(FigureType.Errorbar, figure_type(ax.figure))
def test_line_plot_returns_line(self): ax = plt.subplot(111) ax.plot([1]) self.assertEqual(FigureType.Line, figure_type(ax.figure))
def test_subplot_with_multiple_plots_returns_other(self): ax = plt.subplot(221) self.assertEqual(FigureType.Other, figure_type(ax.figure))
def test_figure_type_empty_figure_returns_empty(self): self.assertEqual(FigureType.Empty, figure_type(plt.figure()))
def test_figure_type_empty_figure_returns_empty(self): self.assertEqual(FigureType.Empty, figure_type(plt.figure()))
def test_subplot_with_multiple_plots_returns_other(self): ax = plt.subplot(221) self.assertEqual(FigureType.Other, figure_type(ax.figure))
def test_mesh_plot_returns_mesh(self): a = np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]]]) mesh_polygon = Poly3DCollection(a) fig, ax = plt.subplots(subplot_kw={'projection': 'mantid3d'}) ax.add_collection3d(mesh_polygon) self.assertEqual(FigureType.Mesh, figure_type(ax.figure))
def test_error_plot_returns_error(self): ax = plt.subplot(111) ax.errorbar([1], [1], yerr=[0.01]) self.assertEqual(FigureType.Errorbar, figure_type(ax.figure))
def test_image_plot_returns_image(self): ax = plt.subplot(111) ax.imshow([[1], [1]]) self.assertEqual(FigureType.Image, figure_type(ax.figure))
def test_wireframe_plot_returns_wireframe(self): a = np.array([[1]]) ax = plt.subplot(111, projection='3d') ax.plot_wireframe(a, a, a) self.assertEqual(FigureType.Wireframe, figure_type(ax.figure))
def test_image_plot_returns_image(self): ax = plt.subplot(111) ax.imshow([[1], [1]]) self.assertEqual(FigureType.Image, figure_type(ax.figure))
def show_help_page_for_figure(cls, figure): fig_type = figure_type(figure) doc_url = HELP_PAGES[fig_type] InterfaceManager().showHelpPage(doc_url)
def test_line_plot_returns_line(self): ax = plt.subplot(111) ax.plot([1]) self.assertEqual(FigureType.Line, figure_type(ax.figure))