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 test_enabling_fill_with_line_colour_creates_fills_that_match_line_colour( self): self.presenter.view.enable_fill_group_box.isChecked.return_value = True self.presenter.view.use_line_colour_radio_button.isChecked.return_value = True self.presenter.set_fill_enabled() self.assertTrue(datafunctions.waterfall_fill_is_line_colour(self.ax))
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 _replot_selected_curve(self, plot_kwargs): """Replot the selected curve with the given plot kwargs""" ax = self.get_selected_ax() curve = self.get_selected_curve() waterfall = False if isinstance(ax, MantidAxes): waterfall = ax.is_waterfall() check_line_colour = False # If the plot is a waterfall plot and the user has set it so the area under each line is filled, and the fill # colour for each line is set as the line colour, after the curve is updated we need to check if its colour has # changed so the fill can be updated accordingly. if waterfall and ax.waterfall_has_fill( ) and datafunctions.waterfall_fill_is_line_colour(ax): check_line_colour = True if isinstance(curve, Line2D): curve_index = ax.get_lines().index(curve) errorbar = False else: curve_index = ax.get_lines().index(curve[0]) errorbar = True new_curve = FigureErrorsManager.replot_curve(ax, curve, plot_kwargs) self.curve_names_dict[self.view.get_selected_curve_name()] = new_curve if isinstance(ax, MantidAxes): errorbar_cap_lines = datafunctions.remove_and_return_errorbar_cap_lines( ax) else: errorbar_cap_lines = [] # When a curve is redrawn it is moved to the back of the list of curves so here it is moved back to its previous # position. This is so that the correct offset is applied to the curve if the plot is a waterfall plot, but it # also just makes sense for the curve order to remain unchanged. ax.lines.insert(curve_index, ax.lines.pop()) if waterfall: if check_line_colour: # curve can be either a Line2D or an ErrorContainer and the colour is accessed differently for each. if not errorbar: # if the line colour hasn't changed then the fill colour doesn't need to be updated. update_fill = curve.get_color() != new_curve[0].get_color() else: update_fill = curve[0].get_color( ) != new_curve[0].get_color() datafunctions.convert_single_line_to_waterfall( ax, curve_index, need_to_update_fill=update_fill) else: # the curve has been reset to its original position so for a waterfall plot it needs to be re-offset. datafunctions.convert_single_line_to_waterfall(ax, curve_index) datafunctions.set_waterfall_fill_visible(ax, curve_index) ax.lines += errorbar_cap_lines
def init_view(self): # This function sets the correct values in the menu when it is first opened. if self.ax.waterfall_has_fill(): self.view.enable_fill_group_box.setChecked(True) if datafunctions.waterfall_fill_is_line_colour(self.ax): self.view.use_line_colour_radio_button.setChecked(True) else: self.view.use_solid_colour_radio_button.setChecked(True) poly = next(poly_collection for poly_collection in self.ax.collections if isinstance(poly_collection, PolyCollection)) self.view.colour_selector_widget.set_color(convert_color_to_hex(poly.get_facecolor().tolist()[0]))
def _replot_current_curve(self, plot_kwargs): """Replot the selected curve with the given plot kwargs""" ax = self.get_selected_ax() curve = self.get_current_curve() waterfall = False if isinstance(ax, MantidAxes): waterfall = ax.is_waterfall() check_line_colour = False # If the plot is a waterfall plot and the user has set it so the area under each line is filled, and the fill # colour for each line is set as the line colour, after the curve is updated we need to check if its colour has # changed so the fill can be updated accordingly. if waterfall and ax.waterfall_has_fill() and datafunctions.waterfall_fill_is_line_colour(ax): check_line_colour = True if isinstance(curve, Line2D): curve_index = ax.get_lines().index(curve) errorbar = False else: curve_index = ax.get_lines().index(curve[0]) errorbar = True # When you remove the curve on a waterfall plot, the remaining curves are repositioned so that they are # equally spaced apart. However since the curve is being replotted we don't want that to happen, so here # the waterfall offsets are set to 0 so the plot appears to be non-waterfall. The offsets are then re-set # after the curve is replotted. if waterfall: x_offset, y_offset = ax.waterfall_x_offset, ax.waterfall_y_offset ax.waterfall_x_offset = ax.waterfall_y_offset = 0 new_curve = FigureErrorsManager.replot_curve(ax, curve, plot_kwargs) self.curve_names_dict[self.view.get_current_curve_name()] = new_curve if isinstance(ax, MantidAxes): errorbar_cap_lines = datafunctions.remove_and_return_errorbar_cap_lines(ax) else: errorbar_cap_lines = [] # TODO: Accessing the ax.lines property is deprecated in mpl 3.5. It must be removed by mpl 3.7. with warnings.catch_warnings(): warnings.simplefilter("ignore") # When a curve is redrawn it is moved to the back of the list of curves so here it is moved back to its previous # position. This is so that the correct offset is applied to the curve if the plot is a waterfall plot, but it # also just makes sense for the curve order to remain unchanged. ax.lines.insert(curve_index, ax.lines.pop()) if waterfall: # Set the waterfall offsets to what they were previously. ax.waterfall_x_offset, ax.waterfall_y_offset = x_offset, y_offset if check_line_colour: # curve can be either a Line2D or an ErrorContainer and the colour is accessed differently for each. if not errorbar: # if the line colour hasn't changed then the fill colour doesn't need to be updated. update_fill = curve.get_color() != new_curve[0].get_color() else: update_fill = curve[0].get_color() != new_curve[0].get_color() datafunctions.convert_single_line_to_waterfall(ax, curve_index, need_to_update_fill=update_fill) else: # the curve has been reset to its original position so for a waterfall plot it needs to be re-offset. datafunctions.convert_single_line_to_waterfall(ax, curve_index) datafunctions.set_waterfall_fill_visible(ax, curve_index) for cap in errorbar_cap_lines: ax.add_line(cap)