def update(self): if self.state.density_map: pass else: self.scatter.x = (ensure_numerical( self.layer.data[self._viewer_state.x_att]).astype( np.float32).ravel()) self.scatter.y = (ensure_numerical( self.layer.data[self._viewer_state.y_att]).astype( np.float32).ravel()) self.quiver.x = self.scatter.x self.quiver.y = self.scatter.y if isinstance(self.layer, Subset): try: mask = self.layer.to_mask() except IncompatibleAttribute: self.disable("Could not compute subset") self._clear_selection() return selected_indices = np.nonzero(mask)[0].tolist() self.scatter.selected = selected_indices self.scatter.selected_style = {} self.scatter.unselected_style = {'fill': 'none', 'stroke': 'none'} self.quiver.selected = selected_indices self.quiver.selected_style = {} self.quiver.unselected_style = {'fill': 'none', 'stroke': 'none'} else: self._clear_selection()
def update(self): # we don't use layer, but layer.data to get everything self.scatter.x = ensure_numerical( self.layer.data[self._viewer_state.x_att]).ravel() self.scatter.z = ensure_numerical( self.layer.data[self._viewer_state.y_att]).ravel() self.scatter.y = ensure_numerical( self.layer.data[self._viewer_state.z_att]).ravel() self.quiver.x = self.scatter.x self.quiver.z = self.scatter.y self.quiver.y = self.scatter.z if isinstance(self.layer, Subset): try: mask = self.layer.to_mask() except IncompatibleAttribute: self.disable("Could not compute subset") self._clear_selection() return selected_indices = np.nonzero(mask)[0] self.scatter.selected = selected_indices self.quiver.selected = selected_indices self._update_size()
def _update_visual_attributes(self, changed, force=False): if not self.enabled: return if self.state.markers_visible: if self.state.density_map: if self.state.cmap_mode == 'Fixed': if force or 'color' in changed or 'cmap_mode' in changed: self.density_artist.set_color(self.state.color) self.density_artist.set_clim( self.density_auto_limits.min, self.density_auto_limits.max) elif force or any(prop in changed for prop in CMAP_PROPERTIES): c = ensure_numerical( self.layer[self.state.cmap_att].ravel()) set_mpl_artist_cmap(self.density_artist, c, self.state) if force or 'stretch' in changed: self.density_artist.set_norm( ImageNormalize( stretch=STRETCHES[self.state.stretch]())) if force or 'dpi' in changed: self.density_artist.set_dpi(self._viewer_state.dpi) if force or 'density_contrast' in changed: self.density_auto_limits.contrast = self.state.density_contrast self.density_artist.stale = True else: if self.state.cmap_mode == 'Fixed' and self.state.size_mode == 'Fixed': if force or 'color' in changed or 'fill' in changed: if self.state.fill: self.plot_artist.set_markeredgecolor('none') self.plot_artist.set_markerfacecolor( self.state.color) else: self.plot_artist.set_markeredgecolor( self.state.color) self.plot_artist.set_markerfacecolor('none') if force or 'size' in changed or 'size_scaling' in changed: self.plot_artist.set_markersize( self.state.size * self.state.size_scaling) else: # TEMPORARY: Matplotlib has a bug that causes set_alpha to # change the colors back: https://github.com/matplotlib/matplotlib/issues/8953 if 'alpha' in changed: force = True if self.state.cmap_mode == 'Fixed': if force or 'color' in changed or 'cmap_mode' in changed or 'fill' in changed: self.scatter_artist.set_array(None) if self.state.fill: self.scatter_artist.set_facecolors( self.state.color) self.scatter_artist.set_edgecolors('none') else: self.scatter_artist.set_facecolors('none') self.scatter_artist.set_edgecolors( self.state.color) elif force or any( prop in changed for prop in CMAP_PROPERTIES) or 'fill' in changed: self.scatter_artist.set_edgecolors(None) self.scatter_artist.set_facecolors(None) c = ensure_numerical( self.layer[self.state.cmap_att].ravel()) set_mpl_artist_cmap(self.scatter_artist, c, self.state) if self.state.fill: self.scatter_artist.set_edgecolors('none') else: colors = self.scatter_artist.get_facecolors() self.scatter_artist.set_facecolors('none') self.scatter_artist.set_edgecolors(colors) if force or any(prop in changed for prop in MARKER_PROPERTIES): if self.state.size_mode == 'Fixed': s = self.state.size * self.state.size_scaling s = broadcast_to( s, self.scatter_artist.get_sizes().shape) else: s = ensure_numerical( self.layer[self.state.size_att].ravel()) s = ((s - self.state.size_vmin) / (self.state.size_vmax - self.state.size_vmin)) # The following ensures that the sizes are in the # range 3 to 30 before the final size_scaling. np.clip(s, 0, 1, out=s) s *= 0.95 s += 0.05 s *= (30 * self.state.size_scaling) # Note, we need to square here because for scatter, s is actually # proportional to the marker area, not radius. self.scatter_artist.set_sizes(s**2) if self.state.line_visible: if self.state.cmap_mode == 'Fixed': if force or 'color' in changed or 'cmap_mode' in changed: self.line_collection.set_linearcolor( color=self.state.color) elif force or any(prop in changed for prop in CMAP_PROPERTIES): # Higher up we oversampled the points in the line so that # half a segment on either side of each point has the right # color, so we need to also oversample the color here. c = ensure_numerical(self.layer[self.state.cmap_att].ravel()) self.line_collection.set_linearcolor(data=c, state=self.state) if force or 'linewidth' in changed: self.line_collection.set_linewidth(self.state.linewidth) if force or 'linestyle' in changed: self.line_collection.set_linestyle(self.state.linestyle) if self.state.vector_visible and self.vector_artist is not None: if self.state.cmap_mode == 'Fixed': if force or 'color' in changed or 'cmap_mode' in changed: self.vector_artist.set_array(None) self.vector_artist.set_color(self.state.color) elif force or any(prop in changed for prop in CMAP_PROPERTIES): c = ensure_numerical(self.layer[self.state.cmap_att].ravel()) set_mpl_artist_cmap(self.vector_artist, c, self.state) if self.state.xerr_visible or self.state.yerr_visible: for eartist in ravel_artists(self.errorbar_artist): if self.state.cmap_mode == 'Fixed': if force or 'color' in changed or 'cmap_mode' in changed: eartist.set_color(self.state.color) elif force or any(prop in changed for prop in CMAP_PROPERTIES): c = ensure_numerical( self.layer[self.state.cmap_att].ravel()).copy() c = c[self._errorbar_keep] set_mpl_artist_cmap(eartist, c, self.state) if force or 'alpha' in changed: eartist.set_alpha(self.state.alpha) if force or 'visible' in changed: eartist.set_visible(self.state.visible) if force or 'zorder' in changed: eartist.set_zorder(self.state.zorder) for artist in [ self.scatter_artist, self.plot_artist, self.vector_artist, self.line_collection, self.density_artist ]: if artist is None: continue if force or 'alpha' in changed: artist.set_alpha(self.state.alpha) if force or 'zorder' in changed: artist.set_zorder(self.state.zorder) if force or 'visible' in changed: # We need to hide the density artist if it is not needed because # otherwise it might still show even if there is no data as the # neutral/zero color might not be white. if artist is self.density_artist: artist.set_visible(self.state.visible and self.state.density_map and self.state.markers_visible) else: artist.set_visible(self.state.visible) self.redraw()
def _update_data(self): # Layer artist has been cleared already if len(self.mpl_artists) == 0: return try: if not self.state.density_map: x = ensure_numerical( self.layer[self._viewer_state.x_att].ravel()) if x.dtype.kind == 'M': x = datetime64_to_mpl(x) except (IncompatibleAttribute, IndexError): # The following includes a call to self.clear() self.disable_invalid_attributes(self._viewer_state.x_att) return else: self.enable() try: if not self.state.density_map: y = ensure_numerical( self.layer[self._viewer_state.y_att].ravel()) if y.dtype.kind == 'M': y = datetime64_to_mpl(y) except (IncompatibleAttribute, IndexError): # The following includes a call to self.clear() self.disable_invalid_attributes(self._viewer_state.y_att) return else: self.enable() if self.state.markers_visible: if self.state.density_map: # We don't use x, y here because we actually make use of the # ability of the density artist to call a custom histogram # method which is defined on this class and does the data # access. self.plot_artist.set_data([], []) self.scatter_artist.set_offsets(np.zeros((0, 2))) else: if self.state.cmap_mode == 'Fixed' and self.state.size_mode == 'Fixed': # In this case we use Matplotlib's plot function because it has much # better performance than scatter. self.plot_artist.set_data(x, y) self.scatter_artist.set_offsets(np.zeros((0, 2))) else: self.plot_artist.set_data([], []) offsets = np.vstack((x, y)).transpose() self.scatter_artist.set_offsets(offsets) else: self.plot_artist.set_data([], []) self.scatter_artist.set_offsets(np.zeros((0, 2))) if self.state.line_visible: if self.state.cmap_mode == 'Fixed': self.line_collection.set_points(x, y, oversample=False) else: # In the case where we want to color the line, we need to over # sample the line by a factor of two so that we can assign the # correct colors to segments - if we didn't do this, then # segments on one side of a point would be a different color # from the other side. With oversampling, we can have half a # segment on either side of a point be the same color as a # point self.line_collection.set_points(x, y) else: self.line_collection.set_points([], []) for eartist in ravel_artists(self.errorbar_artist): try: eartist.remove() except ValueError: pass if self.vector_artist is not None: self.vector_artist.remove() self.vector_artist = None if self.state.vector_visible: if self.state.vx_att is not None and self.state.vy_att is not None: vx = ensure_numerical(self.layer[self.state.vx_att].ravel()) vy = ensure_numerical(self.layer[self.state.vy_att].ravel()) if self.state.vector_mode == 'Polar': ang = vx length = vy # assume ang is anti clockwise from the x axis vx = length * np.cos(np.radians(ang)) vy = length * np.sin(np.radians(ang)) else: vx = None vy = None if self.state.vector_arrowhead: hw = 3 hl = 5 else: hw = 1 hl = 0 vmax = nanmax(np.hypot(vx, vy)) self.vector_artist = self.axes.quiver( x, y, vx, vy, units='width', pivot=self.state.vector_origin, headwidth=hw, headlength=hl, scale_units='width', angles='xy', scale=10 / self.state.vector_scaling * vmax) self.mpl_artists[self.vector_index] = self.vector_artist if self.state.xerr_visible or self.state.yerr_visible: keep = ~np.isnan(x) & ~np.isnan(y) if self.state.xerr_visible and self.state.xerr_att is not None: xerr = ensure_numerical( self.layer[self.state.xerr_att].ravel()).copy() keep &= ~np.isnan(xerr) else: xerr = None if self.state.yerr_visible and self.state.yerr_att is not None: yerr = ensure_numerical( self.layer[self.state.yerr_att].ravel()).copy() keep &= ~np.isnan(yerr) else: yerr = None if xerr is not None: xerr = xerr[keep] if yerr is not None: yerr = yerr[keep] self._errorbar_keep = keep self.errorbar_artist = self.axes.errorbar(x[keep], y[keep], fmt='none', xerr=xerr, yerr=yerr) self.mpl_artists[self.errorbar_index] = self.errorbar_artist