def cursor_info(image: AxesImage, xdata: float, ydata: float, full_bbox: Bbox = None) -> Optional[CursorInfo]: """Return information on the image for the given position in data coordinates. :param image: An instance of an image type :param xdata: X data coordinate of cursor :param xdata: Y data coordinate of cursor :param full_bbox: Bbox of full workspace dimension to use for transforming mouse position :return: None if point is not valid on the image else return CursorInfo type """ extent = image.get_extent() xmin, xmax, ymin, ymax = extent arr = image.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) if full_bbox is None: trans = BboxTransform(boxin=data_extent, boxout=array_extent) else: # If the view is zoomed in and the slice is changed, then the image extents # and data extents change. This causes the cursor to be transformed to the # wrong point for certain MDH workspaces (since it cannot be dynamically rebinned). # This will use the full WS data dimensions to do the transformation trans = BboxTransform(boxin=full_bbox, boxout=array_extent) point = trans.transform_point([ydata, xdata]) if any(np.isnan(point)): return None point = point.astype(int) if 0 <= point[0] < arr.shape[0] and 0 <= point[1] < arr.shape[1]: return CursorInfo(array=arr, extent=extent, point=point) else: return None
def test_transform_array(): trans = BboxTransform(SMALL, LARGE) result = trans.transform(np.array([(SMALL.x0, SMALL.y0), (SMALL.x1, SMALL.y1)])) expected = [(LARGE.x0, LARGE.y0), (LARGE.x1, LARGE.y1)] assert_allclose(result, expected)
def test_transform_list_of_points(): trans = BboxTransform(SMALL, LARGE) result = trans.transform([(SMALL.x0, SMALL.y0), (SMALL.x1, SMALL.y1)]) expected = [(LARGE.x0, LARGE.y0), (LARGE.x1, LARGE.y1)] assert_allclose(result, expected)
def update_line_plots(self, x, y): xmin, xmax, ymin, ymax = self.im.get_extent() arr = self.im.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) point = trans.transform_point([y, x]) if any(np.isnan(point)): return i, j = point.astype(int) if 0 <= i < arr.shape[0]: self.plot_x_line(np.linspace(xmin, xmax, arr.shape[1]), arr[i, :]) if 0 <= j < arr.shape[1]: self.plot_y_line(np.linspace(ymin, ymax, arr.shape[0]), arr[:, j])
def convert_point(self,point_px, stop=False): ''' given a touch point in the view space, compute the corresponding point in data coords. assumes linear scaling! TODO: support log scaling there are basically two bbox transforms: 1) from figure coords to view coords, accounting for sign change in y. this then lets us compute axes box in view coords, and generate 2) transform from view to data coords. ''' transFig=BboxTransformTo(Bbox([(0,self.height),(self.width,0)])) bbox_axes=Bbox(transFig.transform(plt.gca().get_position())) bbox_data=Bbox([(self.xlim[0],self.ylim[0]),(self.xlim[1],self.ylim[1])]) transMPL=BboxTransform(bbox_axes,bbox_data) self.trans=transMPL ax_pt=transMPL.transform_point(point_px) return ax_pt
def get_courser_index(img, event): xmin, xmax, ymin, ymax = img.get_extent() if img.origin == 'upper': ymin, ymax = ymax, ymin arr = img.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) y, x = event.ydata, event.xdata point = trans.transform_point([y, x]) if any(np.isnan(point)): return None row, col = point.astype(int) # Clip the coordinates at array bounds return row, col
def convert_point(self, point_px, stop=False): ''' given a touch point in the view space, compute the corresponding point in data coords. assumes linear scaling! TODO: support log scaling there are basically two bbox transforms: 1) from figure coords to view coords, accounting for sign change in y. this then lets us compute axes box in view coords, and generate 2) transform from view to data coords. ''' transFig = BboxTransformTo(Bbox([(0, self.height), (self.width, 0)])) bbox_axes = Bbox(transFig.transform(plt.gca().get_position())) bbox_data = Bbox([(self.xlim[0], self.ylim[0]), (self.xlim[1], self.ylim[1])]) transMPL = BboxTransform(bbox_axes, bbox_data) self.trans = transMPL ax_pt = transMPL.transform_point(point_px) return ax_pt
def get_cursor_data(self, event): """Get the cursor data for a given event""" xmin, xmax, ymin, ymax = self.get_extent() if self.origin == 'upper': ymin, ymax = ymax, ymin arr = self.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) y, x = event.ydata, event.xdata i, j = trans.transform_point([y, x]).astype(int) # Clip the coordinates at array bounds if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]): return None else: return arr[i, j]
def get_cursor_data(self, event): """Get the cursor data for a given event""" xmin, xmax, ymin, ymax = self.get_extent() if self.origin == "upper": ymin, ymax = ymax, ymin arr = self.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) y, x = event.ydata, event.xdata i, j = trans.transform_point([y, x]).astype(int) # Clip the coordinates at array bounds if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]): return None else: return arr[i, j]
def make_image(self, renderer, magnification=1.0, unsampled=False): width, height = renderer.get_canvas_width_height() bbox_in = self.get_window_extent(renderer).frozen() bbox_in._points /= [width, height] bbox_out = self.get_window_extent(renderer) clip = Bbox([[0, 0], [width, height]]) self._transform = BboxTransform(Bbox([[0, 0], [1, 1]]), clip) return self._make_image( self._A, bbox_in, bbox_out, clip, magnification, unsampled=unsampled)
def get_cursor_data(self, event): """ Return the aggregated data at the event position or *None* if the event is outside the bounds of the current view. """ xmin, xmax, ymin, ymax = self.get_extent() if self.origin == "upper": ymin, ymax = ymax, ymin arr = self.get_ds_data().data data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) y, x = event.ydata, event.xdata i, j = trans.transform_point([y, x]).astype(int) # Clip the coordinates at array bounds if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]): return None else: return arr[i, j]
def cursor_info(image: AxesImage, xdata: float, ydata: float) -> Optional[CursorInfo]: """Return information on the image for the given position in data coordinates. :param image: An instance of an image type :param xdata: X data coordinate of cursor :param xdata: Y data coordinate of cursor :return: None if point is not valid on the image else return CursorInfo type """ extent = image.get_extent() xmin, xmax, ymin, ymax = extent arr = image.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) point = trans.transform_point([ydata, xdata]) if any(np.isnan(point)): return None point = point.astype(int) if 0 <= point[0] < arr.shape[0] and 0 <= point[1] < arr.shape[1]: return CursorInfo(array=arr, extent=extent, point=point) else: return None
def get_cursor_data(self, event): """Get the cursor data for a given event""" from matplotlib.transforms import Bbox, BboxTransform aximg = self.image xmin, xmax, ymin, ymax = aximg.get_extent() if aximg.origin == 'upper': ymin, ymax = ymax, ymin arr = aximg.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) y, x = event.ydata, event.xdata point = trans.transform_point([y, x]) if any(isnan(point)): return None i, j = point.astype(int) # Clip the coordinates at array bounds if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]): return None else: return i, j, arr[i, j]
def _transform_from_image(self): from matplotlib.transforms import Bbox, BboxTransform ref_im = np.array([(15.152, 57.079), (15.152, 65.091), (12.949, 65.091), (12.949, 62.575), (5.613, 62.575), (5.613, 60.587), (12.949, 60.587), (12.949, 57.079)]) ref = Vessel().digitizer.xy[2] bbox_im, bbox = Bbox.unit(), Bbox.unit() bbox_im.update_from_data_xy(ref_im) bbox.update_from_data_xy(ref) trans = BboxTransform(bbox_im, bbox) return trans
def update_image_data(self, x, y, update_line_plot=False): xmin, xmax, ymin, ymax = self.image.get_extent() arr = self.image.get_array() data_extent = Bbox([[ymin, xmin], [ymax, xmax]]) array_extent = Bbox([[0, 0], arr.shape[:2]]) trans = BboxTransform(boxin=data_extent, boxout=array_extent) point = trans.transform_point([y, x]) if any(np.isnan(point)): return i, j = point.astype(int) if update_line_plot: if 0 <= i < arr.shape[0]: self.plot_x_line(np.linspace(xmin, xmax, arr.shape[1]), arr[i, :]) if 0 <= j < arr.shape[1]: self.plot_y_line(np.linspace(ymin, ymax, arr.shape[0]), arr[:, j]) # Clip the coordinates at array bounds if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]): return None else: return arr[i, j]
def main(): blue = '#4b92db' # We're drawing a flag with a 3:5 aspect ratio. fig = plt.figure(figsize=[7.5, 4.5], facecolor=blue) # Put a blue background on the figure. blue_background = PathPatch(matplotlib.path.Path.unit_rectangle(), transform=fig.transFigure, color=blue, zorder=-1) fig.patches.append(blue_background) # Set up the Azimuthal Equidistant and Plate Carree projections # for later use. az_eq = ccrs.AzimuthalEquidistant(central_latitude=90) pc = ccrs.PlateCarree() # Pick a suitable location for the map (which is in an Azimuthal # Equidistant projection). ax = fig.add_axes([0.25, 0.24, 0.5, 0.54], projection=az_eq) # The background patch is not needed in this example. ax.background_patch.set_facecolor('none') # The Axes frame produces the outer meridian line. for spine in ax.spines.values(): spine.update({'edgecolor': 'white', 'linewidth': 2}) # We want the map to go down to -60 degrees latitude. ax.set_extent([-180, 180, -60, 90], ccrs.PlateCarree()) # Importantly, we want the axes to be circular at the -60 latitude # rather than cartopy's default behaviour of zooming in and becoming # square. _, patch_radius = az_eq.transform_point(0, -60, pc) circular_path = matplotlib.path.Path.circle(0, patch_radius) ax.set_boundary(circular_path) if filled_land: ax.add_feature(cfeature.LAND, facecolor='white', edgecolor='none') else: ax.stock_img() gl = ax.gridlines(crs=pc, linewidth=2, color='white', linestyle='-') # Meridians every 45 degrees, and 4 parallels. gl.xlocator = matplotlib.ticker.FixedLocator(np.arange(-180, 181, 45)) parallels = np.arange(-30, 70, 30) gl.ylocator = matplotlib.ticker.FixedLocator(parallels) # Now add the olive branches around the axes. We do this in normalised # figure coordinates olive_leaf = olive_path() olives_bbox = Bbox.null() olives_bbox.update_from_path(olive_leaf) # The first olive branch goes from left to right. olive1_axes_bbox = Bbox([[0.45, 0.15], [0.725, 0.75]]) olive1_trans = BboxTransform(olives_bbox, olive1_axes_bbox) # THe second olive branch goes from right to left (mirroring the first). olive2_axes_bbox = Bbox([[0.55, 0.15], [0.275, 0.75]]) olive2_trans = BboxTransform(olives_bbox, olive2_axes_bbox) olive1 = PathPatch(olive_leaf, facecolor='white', edgecolor='none', transform=olive1_trans + fig.transFigure) olive2 = PathPatch(olive_leaf, facecolor='white', edgecolor='none', transform=olive2_trans + fig.transFigure) fig.patches.append(olive1) fig.patches.append(olive2) plt.show()
ax = subplot(212) xlim(0, 10) xticks(arange(10)) boxin = Bbox.from_extents(ax.viewLim.x0, -20, ax.viewLim.x1, 20) height = ax.bbox.height boxout = Bbox.from_extents(ax.bbox.x0, -1.0 * height, ax.bbox.x1, 1.0 * height) transOffset = BboxTransformTo( Bbox.from_extents(0.0, ax.bbox.y0, 1.0, ax.bbox.y1)) for i in range(numRows): # effectively a copy of transData trans = BboxTransform(boxin, boxout) offset = (i + 1) / (numRows + 1) trans += Affine2D().translate(*transOffset.transform_point((0, offset))) thisLine = Line2D( t, data[:, i] - data[0, i], ) thisLine.set_transform(trans) ax.add_line(thisLine) ticklocs.append(offset)