def show_xy(self, axes): downsample = self.w_downsample.value() fixed_slice = self.fixed_img[::downsample, ::downsample, self.fixed_img_z.value()].transpose() moving_slice = self.moving_img[::downsample, ::downsample, self.moving_img_z.value()].transpose() if self.w_flip_lr.isChecked(): moving_slice = np.fliplr(moving_slice) if self.w_flip_ud.isChecked(): moving_slice = np.flipud(moving_slice) angle = self.w_angle.value() * np.pi / 180 rot_matrix = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]) y, x = np.mgrid[0:fixed_slice.shape[0], 0:fixed_slice.shape[1]] center = np.array([self.w_center_y.value(), self.w_center_x.value()]).reshape(1, 2) // downsample offset = np.array([self.w_off_y.value(), self.w_off_x.value()]).reshape(1, 2) // downsample yx = np.column_stack([y.flatten(), x.flatten()]) yxt = ((yx - center - offset) @ rot_matrix) + center yt, xt = yxt.transpose() yt, xt = [_.reshape(fixed_slice.shape) for _ in (yt, xt)] cimg = np.zeros((fixed_slice.shape[0], fixed_slice.shape[1], 3), np.float32) cimg[:, : , 0] = fixed_slice map_coordinates(moving_slice, [yt, xt], cimg[:, :, 1]) axes.cla() clip = np.quantile(cimg.flatten(), .90) axes.imshow(np.clip(cimg, 0, clip) / clip) self.redo_axes_ticks(axes, self.fixed_img.shape[0], self.fixed_img.shape[1])
def imshow_fn(pixel_data): # Note: requires typecast to avoid failure during # figure_to_image (IMG-764) img = pixel_data * 255 img[img < 0] = 0 img[img > 255] = 255 img = img.astype(numpy.uint8) axes.imshow(img, cmap=matplotlib.cm.get_cmap("Greys"))
def plot(X=[0], Y=[0], IMAGE=np.zeros((10, 10)), COLOR='b.', MS=2.0, LW=2.0, FIGX=10, FIGY=10, NAXIS=1, BG='white', INTER='none', VMIN=True, VMAX=True, NO=1): if NAXIS == 1: plt.figure(NO, figsize=(FIGX, FIGY)) plt.plot(X, Y, COLOR, ms=MS, linewidth=LW) plt.gca().set_axis_bgcolor(BG) if NAXIS == 2: if VMIN == True and VMAX == True: mid, std = np.median(IMAGE), np.std(IMAGE) VMIN, VMAX = mid - 1 * std, mid + 1 * std else: VMIN, VMAX = VMIN, VMAX plt.figure(NO, figsize=(FIGX, FIGY)) ax = plt.gca() im = ax.imshow(IMAGE, cmap='gray', vmin=VMAX, vmax=VMAX, interpolation=INTER) div = make_axes_locatable(ax) cax = div.append_axes("right", size="5%", pad=0.05) plt.colorbar(im, cax=cax) pass
def show_xz(self, axes): downsample = self.w_downsample.value() y = self.fixed_img.shape[1] // 2 min_x = min(self.fixed_img.shape[0], self.moving_img.shape[0]) min_z = min(self.fixed_img.shape[2], self.moving_img.shape[2]) fixed_slice = self.fixed_img[:min_x:downsample, y, :min_z:downsample].transpose() moving_slice = self.moving_img[:min_x:downsample, y, :min_z:downsample].transpose() combined = np.stack([fixed_slice, moving_slice, np.zeros_like(fixed_slice)], 2).astype(np.float32) clip = np.quantile(combined.flatten(), .90) combined = np.clip(combined, 0, clip) axes.imshow(combined) z_fixed = self.fixed_img_z.value() // downsample z_moving = self.moving_img_z.value() // downsample axes.plot([0, min_x // downsample], [z_fixed, z_fixed]) axes.plot([0, min_x // downsample], [z_moving, z_moving]) self.redo_axes_ticks(axes, min_x, min_z)
def show_yz(self, axes): downsample = self.w_downsample.value() x = self.fixed_img.shape[0] // 2 min_y = min(self.fixed_img.shape[1], self.moving_img.shape[1]) min_z = min(self.fixed_img.shape[2], self.moving_img.shape[2]) fixed_slice = self.fixed_img[x, :min_y:downsample, :min_z:downsample] moving_slice = self.moving_img[x, :min_y:downsample, :min_z:downsample] combined = np.stack([fixed_slice, moving_slice, np.zeros_like(fixed_slice)], 2).astype(np.float32) clip = np.quantile(combined.flatten(), .90) combined = np.clip(combined, 0, clip) axes.imshow(combined) z_fixed = self.fixed_img_z.value() // downsample z_moving = self.moving_img_z.value() // downsample axes.plot([z_fixed, z_fixed], [0, min_y // downsample]) axes.plot([z_moving, z_moving], [0, min_y // downsample]) self.redo_axes_ticks(axes, min_z, min_y)
def handle_interaction(self, current_shape, orig_image): from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg import wx """Show the cropping user interface""" pixel_data = stretch(orig_image) # # Create the UI - a dialog with a figure inside # style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER dialog_box = wx.Dialog( wx.GetApp().TopWindow, -1, "Select the cropping region", size=(640, 480), style=style, ) sizer = wx.BoxSizer(wx.VERTICAL) figure = matplotlib.figure.Figure() panel = FigureCanvasWxAgg(dialog_box, -1, figure) sizer.Add(panel, 1, wx.EXPAND) btn_sizer = wx.StdDialogButtonSizer() btn_sizer.AddButton(wx.Button(dialog_box, wx.ID_OK)) btn_sizer.AddButton(wx.Button(dialog_box, wx.ID_CANCEL)) btn_sizer.Realize() sizer.Add(btn_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5) dialog_box.SetSizer(sizer) dialog_box.Size = dialog_box.BestSize dialog_box.Layout() axes = figure.add_subplot(1, 1, 1) assert isinstance(axes, matplotlib.axes.Axes) if pixel_data.ndim == 2: axes.imshow(pixel_data, matplotlib.cm.Greys_r, origin="upper") else: axes.imshow(pixel_data, origin="upper") # t = axes.transData.inverted() current_handle = [None] def data_xy(mouse_event): """Return the mouse event's x & y converted into data-relative coords""" x = mouse_event.xdata y = mouse_event.ydata return x, y class Handle(matplotlib.patches.Rectangle): dm = max((10, min(pixel_data.shape) / 50)) height, width = (dm, dm) def __init__(self, x, y, on_move): x = max(0, min(x, pixel_data.shape[1])) y = max(0, min(y, pixel_data.shape[0])) self.__selected = False self.__color = cellprofiler_core.preferences.get_primary_outline_color( ) self.__color = numpy.hstack( (self.__color, [255])).astype(float) / 255.0 self.__on_move = on_move super(Handle, self).__init__( (x - self.width / 2, y - self.height / 2), self.width, self.height, edgecolor=self.__color, facecolor="none", ) self.set_picker(True) def move(self, x, y): self.set_xy((x - self.width / 2, y - self.height / 2)) self.__on_move(x, y) def select(self, on): self.__selected = on if on: current_handle[0] = self self.set_facecolor(self.__color) else: self.set_facecolor("none") if current_handle[0] == self: current_handle[0] = None figure.canvas.draw() dialog_box.Update() @property def is_selected(self): return self.__selected @property def center_x(self): """The handle's notion of its x coordinate""" return self.get_x() + self.get_width() / 2 @property def center_y(self): """The handle's notion of its y coordinate""" return self.get_y() + self.get_height() / 2 def handle_pick(self, event): mouse_event = event.mouseevent x, y = data_xy(mouse_event) if mouse_event.button == 1: self.select(True) self.orig_x = self.center_x self.orig_y = self.center_y self.first_x = x self.first_y = y def handle_mouse_move_event(self, event): x, y = data_xy(event) if x is None or y is None: return x = x - self.first_x + self.orig_x y = y - self.first_y + self.orig_y if x < 0: x = 0 if x >= pixel_data.shape[1]: x = pixel_data.shape[1] - 1 if y < 0: y = 0 if y >= pixel_data.shape[0]: y = pixel_data.shape[0] - 1 self.move(x, y) class CropRectangle(object): def __init__(self, top_left, bottom_right): self.__left, self.__top = top_left self.__right, self.__bottom = bottom_right color = cellprofiler_core.preferences.get_primary_outline_color( ) color = numpy.hstack((color, [255])).astype(float) / 255.0 self.rectangle = matplotlib.patches.Rectangle( (min(self.__left, self.__right), min(self.__bottom, self.__top)), abs(self.__right - self.__left), abs(self.__top - self.__bottom), edgecolor=color, facecolor="none", ) self.top_left_handle = Handle(top_left[0], top_left[1], self.handle_top_left) self.bottom_right_handle = Handle(bottom_right[0], bottom_right[1], self.handle_bottom_right) def handle_top_left(self, x, y): self.__left = x self.__top = y self.__reshape() def handle_bottom_right(self, x, y): self.__right = x self.__bottom = y self.__reshape() def __reshape(self): self.rectangle.set_xy( (min(self.__left, self.__right), min(self.__bottom, self.__top))) self.rectangle.set_width(abs(self.__right - self.__left)) self.rectangle.set_height(abs(self.__bottom - self.__top)) self.rectangle.figure.canvas.draw() dialog_box.Update() @property def patches(self): return [ self.rectangle, self.top_left_handle, self.bottom_right_handle ] @property def handles(self): return [self.top_left_handle, self.bottom_right_handle] @property def left(self): return min(self.__left, self.__right) @property def right(self): return max(self.__left, self.__right) @property def top(self): return min(self.__top, self.__bottom) @property def bottom(self): return max(self.__top, self.__bottom) class CropEllipse(object): def __init__(self, center, radius): """Draw an ellipse with control points at the ellipse center and a given x and y radius""" self.center_x, self.center_y = center self.radius_x = self.center_x + radius[0] / 2 self.radius_y = self.center_y + radius[1] / 2 color = cellprofiler_core.preferences.get_primary_outline_color( ) color = numpy.hstack((color, [255])).astype(float) / 255.0 self.ellipse = matplotlib.patches.Ellipse(center, self.width, self.height, edgecolor=color, facecolor="none") self.center_handle = Handle(self.center_x, self.center_y, self.move_center) self.radius_handle = Handle(self.radius_x, self.radius_y, self.move_radius) def move_center(self, x, y): self.center_x = x self.center_y = y self.redraw() def move_radius(self, x, y): self.radius_x = x self.radius_y = y self.redraw() @property def width(self): return abs(self.center_x - self.radius_x) * 4 @property def height(self): return abs(self.center_y - self.radius_y) * 4 def redraw(self): self.ellipse.center = (self.center_x, self.center_y) self.ellipse.width = self.width self.ellipse.height = self.height self.ellipse.figure.canvas.draw() dialog_box.Update() @property def patches(self): return [self.ellipse, self.center_handle, self.radius_handle] @property def handles(self): return [self.center_handle, self.radius_handle] if self.shape == SH_ELLIPSE: if current_shape is None: current_shape = { EL_XCENTER: pixel_data.shape[1] / 2, EL_YCENTER: pixel_data.shape[0] / 2, EL_XRADIUS: pixel_data.shape[1] / 2, EL_YRADIUS: pixel_data.shape[0] / 2, } ellipse = current_shape shape = CropEllipse( (ellipse[EL_XCENTER], ellipse[EL_YCENTER]), (ellipse[EL_XRADIUS], ellipse[EL_YRADIUS]), ) else: if current_shape is None: current_shape = { RE_LEFT: pixel_data.shape[1] / 4, RE_TOP: pixel_data.shape[0] / 4, RE_RIGHT: pixel_data.shape[1] * 3 / 4, RE_BOTTOM: pixel_data.shape[0] * 3 / 4, } rectangle = current_shape shape = CropRectangle( (rectangle[RE_LEFT], rectangle[RE_TOP]), (rectangle[RE_RIGHT], rectangle[RE_BOTTOM]), ) for patch in shape.patches: axes.add_artist(patch) def on_mouse_down_event(event): axes.pick(event) def on_mouse_move_event(event): if current_handle[0] is not None: current_handle[0].handle_mouse_move_event(event) def on_mouse_up_event(event): if current_handle[0] is not None: current_handle[0].select(False) def on_pick_event(event): for h in shape.handles: if id(h) == id(event.artist): h.handle_pick(event) figure.canvas.mpl_connect("button_press_event", on_mouse_down_event) figure.canvas.mpl_connect("button_release_event", on_mouse_up_event) figure.canvas.mpl_connect("motion_notify_event", on_mouse_move_event) figure.canvas.mpl_connect("pick_event", on_pick_event) try: if dialog_box.ShowModal() != wx.ID_OK: raise ValueError("Cancelled by user") finally: dialog_box.Destroy() if self.shape == SH_RECTANGLE: return { RE_LEFT: shape.left, RE_TOP: shape.top, RE_RIGHT: shape.right, RE_BOTTOM: shape.bottom, } else: return { EL_XCENTER: shape.center_x, EL_YCENTER: shape.center_y, EL_XRADIUS: shape.width / 2, EL_YRADIUS: shape.height / 2, }
def plot_soln_frame_on_ax(axes: matplotlib.axes.Axes, soln: pyclaw.Solution, level: int, clims: Tuple[float, float], dry_tol: float, **kwargs: str): """Plot solution patch-by-patch to an existing Axes object. Arguments --------- axes : matplotlib.axes.Axes The target Axes target. soln : pyclaw.Solution Solution object from simulation. level : int Target AMR level. clims : [float, float] Min and max colormap limits. dry_tol : float Depth below this value will be cutoff and masked. **kwargs : keyword arguments Valid keyword arguments include: cmap : matplotlib.cm.Colormap Colormap to use. (Default: viridis) border : bool To draw border line for each patch. Returns ------- axes : matplotlib.axes.Axes The updated Axes object. imgs : matplotlib.image.AxesImage Thes artist objects created by this function. cmap : matplotlib.colors.Colormap The colormap object used by the solutions. cmscale : matplotlib.colors.Normalize The normalization object that maps solution data to the the colormap values. """ # process optional keyword arguments cmap = "viridis" if "cmap" not in kwargs else kwargs["cmap"] # normalization object cmscale = matplotlib.colors.Normalize(*clims, False) imgs = [] for state in soln.states: if state.patch.level != level: continue # skip patches not on target level p = state.patch # pylint: disable=invalid-name affine = rasterio.transform.from_origin(p.lower_global[0], p.upper_global[1], p.delta[0], p.delta[1]) dst = state.q[0].T[::-1, :] dst = numpy.ma.array(dst, mask=(dst < dry_tol)) imgs.append( axes.imshow( dst, cmap=cmap, extent=rasterio.plot.plotting_extent(dst, affine), norm=cmscale, )) # boarder line stl = {"color": "k", "lw": 1, "alpha": 0.7} if "border" in kwargs and kwargs["border"]: imgs.append( axes.hlines(p.lower_global[1], p.lower_global[0], p.upper_global[0], **stl)) imgs.append( axes.hlines(p.upper_global[1], p.lower_global[0], p.upper_global[0], **stl)) imgs.append( axes.vlines(p.lower_global[0], p.lower_global[1], p.upper_global[1], **stl)) imgs.append( axes.vlines(p.upper_global[0], p.lower_global[1], p.upper_global[1], **stl)) return axes, imgs, cmap, cmscale
def plot_topo_on_ax(axes: matplotlib.axes.Axes, topo_files: Sequence[os.PathLike], colorize: bool = False, **kwargs: str): """Add a topography elevation plot to an existing Axes object. Arguments --------- axes : matplotlib.axes.Axes The target Axes object. topo_files : tuple/lsit of pathlike A list of list following the topography files specification in GeoClaw's settings. colorize : bool Whether to use colorized colormap for the elevation. (default: False). **kwargs : Other possible keyword arguments: extent : [xmin, ymin, xmax, ymax] The extent of the topography. If not porvided, use the union of all provided topography files. degs : [azdeg, altdeg] The `azdeg` and `altdeg` for shading. See matplotlib's documentation regarding light sources. If not provided, use the default value of [45, 25]. clims : [colormap min, colormap max] Customize the limits of the colormap. If not provided, use the full range. nodata : int Indicates the `nodata` values in the topography files. Default value is -9999. alpha : float Opacity. Returns ------- axes : matplotlib.axes.Axes The updated Axes object. img : matplotlib.image.AxesImage The image object of the topography plot returned by matplotlib's `imshow`. cmap : matplotlib.colors.Colormap The colormap object used by the topography plot. cmscale : matplotlib.colors.Normalize The normalization object that maps elevation data to the the colormap valess. """ # process optional keyword arguments extent = None if "extent" not in kwargs else kwargs["extent"] degs = [45, 25] if "degs" not in kwargs else kwargs["degs"] clims = None if "clims" not in kwargs else kwargs["clims"] nodata = -9999 if "nodata" not in kwargs else kwargs["nodata"] alpha = 0.7 if "alpha" not in kwargs else kwargs["alpha"] # use mosaic raster to obtain interpolated terrain rasters = [rasterio.open(topo, "r") for topo in topo_files] # merge and interplate dst, affine = rasterio.merge.merge(rasters, extent) # close raster datasets for topo in rasters: topo.close() # convert to masked array dst = numpy.ma.array(dst[0], mask=(dst[0] == nodata)) # update the limits based on elevation clims = [dst.min(), dst.max()] if clims is None else clims if colorize: # use colorized colormap if numpy.all(dst >= 0.): # colorbar: land-only cmap = matplotlib.colors.ListedColormap( matplotlib.cm.get_cmap("terrain")(numpy.linspace(0.25, 1, 256))) cmscale = matplotlib.colors.Normalize(*clims, False) else: # mixture of land and ocean cmap = matplotlib.colors.LinearSegmentedColormap.from_list( 'cmap', numpy.concatenate( (matplotlib.cm.get_cmap("terrain")(numpy.linspace( 0, 0.17, 256)), matplotlib.cm.get_cmap("terrain")( numpy.linspace(0.25, 1, 256))), 0)) cmscale = matplotlib.colors.TwoSlopeNorm(0., *clims) else: # use gray scale cmap = matplotlib.cm.get_cmap("gray") cmscale = matplotlib.colors.Normalize(*clims, False) # shade has required rgb values, no need to provide cmap again img = axes.imshow( matplotlib.colors.LightSource(*degs).shade( dst, cmap, cmscale, vert_exag=5, fraction=1, dx=affine._scaling[0], dy=affine._scaling[1] # pylint: disable=protected-access ), extent=rasterio.plot.plotting_extent(dst, affine), alpha=alpha) return axes, img, cmap, cmscale
def plot_soln_frames_on_sat(args: argparse.Namespace, satellite_img: numpy.ndarray, satellite_extent: Tuple[float, float, float, float]): """Plot solution frames on a satellite image. Currently, this function is supposed to be called by `plot_depth` with multiprocessing. Argumenst --------- args : argparse.Namespace CMD argument parsed by `argparse`. satellite_img : numpy.ndarray, The RBG data for the satellite image. satellite_extent : Tuple[float, float, float, float]): The extent of the satellite image. Returns ------- Execution code. 0 for success. """ # plot fig, axes = matplotlib.pyplot.subplots() axes.imshow(satellite_img, extent=[ satellite_extent[0], satellite_extent[2], satellite_extent[1], satellite_extent[3] ]) for fno in range(args.frame_bg, args.frame_ed): print("Processing frame {} by PID {}".format(fno, os.getpid())) # read in solution data soln = pyclaw.Solution() soln.read(fno, str(args.soln_dir), file_format="binary", read_aux=args.soln_dir.joinpath( "fort.a" + "{}".format(fno).zfill(4)).is_file()) axes, imgs, _, _ = plot_soln_frame_on_ax(axes, soln, args.level, [args.cmin, args.cmax], args.dry_tol, cmap=args.cmap, border=args.border) axes.set_xlim(satellite_extent[0], satellite_extent[2]) axes.set_ylim(satellite_extent[1], satellite_extent[3]) fig.suptitle("T = {} sec".format(soln.state.t)) # title fig.savefig(args.dest_dir.joinpath( "frame{:05d}.png".format(fno))) # save # clear artists while True: try: img = imgs.pop() img.remove() del img except IndexError: break print("PID {} done processing frames {} - {}".format( os.getpid(), args.frame_bg, args.frame_ed)) return 0
g_tri_center[1] = int(g_tri_center[1]) start_location = tri_center goal_location = g_tri_center int_waypoints = get_int_waypoints(start_location, goal_location) [AlphaWaypoints, BetaWaypoints, GammaWaypoints] = get_split_waypoints(int_waypoints) plot_robot(mr1_coords) plot_robot(mr2_coords) plot_robot(mr3_coords) plot_robot(g_mr1_coords) plot_robot(g_mr2_coords) plot_robot(g_mr3_coords) plot_point(start_position) plot_point(goal_position) print("Alpha Coordinates = ", mr1_coords) print("Beta Coordinates = ", mr2_coords) print("Gamma Coordinates = ", mr3_coords) print("Box Center = ", box_center) print("Triangle Center = ", tri_center) ax.imshow(arena) plt.gca().invert_yaxis() plt.show()
ax.text(0.1, 0.9, "{}".format(labels[i][j]), fontsize=18, ha="center", va="center", transform=ax.transAxes, bbox=dict(facecolor='white', alpha=0.75, edgecolor='.75')) #setting the phase plots if ax == axes[1, 0] or ax == axes[2, 0] or ax == axes[2, 1]: im = ax.imshow(frb[fields[i][j]].d, origin='lower', extent=[ ds.domain_left_edge[1].value, ds.domain_right_edge[1].value, ds.domain_left_edge[2].value, ds.domain_right_edge[2].value ], vmin=-180, vmax=180, cmap='twilight') #setting colorbar limits im.set_clim(-180, 180) #setting the N magnitudes plots else: #origin=lower keeps image from getting flipped, extent gives the grid coordinates in physical units im = ax.imshow(frb[fields[i][j]].d, origin='lower', extent=[ ds.domain_left_edge[1].value, ds.domain_right_edge[1].value,
def plot_aux_frame_on_ax(axes: matplotlib.axes.Axes, soln: pyclaw.Solution, clims: Tuple[float, float], max_lv: int, **kwargs: str): """Plot solution patch-by-patch to an existing Axes object. Arguments --------- axes : matplotlib.axes.Axes The target Axes target. soln : pyclaw.Solution Solution object from simulation. clims : [float, float] Min and max colormap limits. max_lv: int Maximum level of AMR grid. **kwargs : keyword arguments Valid keyword arguments include: cmap : matplotlib.cm.Colormap Colormap to use. (Default: viridis) border : bool To draw border line for each patch. Returns ------- axes : matplotlib.axes.Axes The updated Axes object. imgs : matplotlib.image.AxesImage Thes artist objects created by this function. cmap : matplotlib.colors.Colormap The colormap object used by the solutions. cmscale : matplotlib.colors.Normalize The normalization object that maps solution data to the the colormap values. """ # process optional keyword arguments cmap = "viridis" if "cmap" not in kwargs else kwargs["cmap"] # normalization object cmscale = matplotlib.colors.Normalize(*clims, False) imgs = [] for state in soln.states: p = state.patch # pylint: disable=invalid-name if p.level > max_lv: # skip AMR level greater than sprcified level continue affine = rasterio.transform.from_origin(p.lower_global[0], p.upper_global[1], p.delta[0], p.delta[1]) dst = state.aux[0].T[::-1, :] imgs.append( axes.imshow( dst, cmap=cmap, extent=rasterio.plot.plotting_extent(dst, affine), norm=cmscale, )) # boarder line stl = { "color": matplotlib.cm.get_cmap("Greys")(p.level / max_lv), "lw": 1, "alpha": 0.7 } if "border" in kwargs and kwargs["border"]: imgs.append( axes.hlines(p.lower_global[1], p.lower_global[0], p.upper_global[0], **stl)) imgs.append( axes.hlines(p.upper_global[1], p.lower_global[0], p.upper_global[0], **stl)) imgs.append( axes.vlines(p.lower_global[0], p.lower_global[1], p.upper_global[1], **stl)) imgs.append( axes.vlines(p.upper_global[0], p.lower_global[1], p.upper_global[1], **stl)) return axes, imgs, cmap, cmscale
def imshow(self, *args, show_crosshair=True, show_mask=True, show_qscale=True, axes=None, invalid_color='black', mask_opacity=0.8, show_colorbar=True, **kwargs): """Plot the matrix (imshow) Keyword arguments [and their default values]: show_crosshair [True]: if a cross-hair marking the beam position is to be plotted. show_mask [True]: if the mask is to be plotted. show_qscale [True]: if the horizontal and vertical axes are to be scaled into q axes [None]: the axes into which the image should be plotted. If None, defaults to the currently active axes (returned by plt.gca()) invalid_color ['black']: the color for invalid (NaN or infinite) pixels mask_opacity [0.8]: the opacity of the overlaid mask (1 is fully opaque, 0 is fully transparent) show_colorbar [True]: if a colorbar is to be added. Can be a boolean value (True or False) or an instance of matplotlib.axes.Axes, into which the color bar should be drawn. All other keywords are forwarded to plt.imshow() or matplotlib.Axes.imshow() Returns: the image instance returned by imshow() """ if 'aspect' not in kwargs: kwargs['aspect'] = 'equal' if 'interpolation' not in kwargs: kwargs['interpolation'] = 'nearest' if 'origin' not in kwargs: kwargs['origin'] = 'upper' if show_qscale: ymin, xmin = self.pixel_to_q(0, 0) ymax, xmax = self.pixel_to_q(*self.shape) if kwargs['origin'].upper() == 'UPPER': kwargs['extent'] = [xmin, xmax, -ymax, -ymin] else: kwargs['extent'] = [xmin, xmax, ymin, ymax] bcx = 0 bcy = 0 else: bcx = self.header.beamcenterx bcy = self.header.beamcentery xmin = 0 xmax = self.shape[1] ymin = 0 ymax = self.shape[0] if kwargs['origin'].upper() == 'UPPER': kwargs['extent'] = [0, self.shape[1], self.shape[0], 0] else: kwargs['extent'] = [0, self.shape[1], 0, self.shape[0]] if axes is None: axes = plt.gca() ret = axes.imshow(self.intensity, **kwargs) if show_mask: # workaround: because of the colour-scaling we do here, full one and # full zero masks look the SAME, i.e. all the image is shaded. # Thus if we have a fully unmasked matrix, skip this section. # This also conserves memory. if (self.mask == 0).sum(): # there are some masked pixels # we construct another representation of the mask, where the masked pixels are 1.0, and the # unmasked ones will be np.nan. They will thus be not rendered. mf = np.ones(self.mask.shape, np.float) mf[self.mask != 0] = np.nan kwargs['cmap'] = matplotlib.cm.gray_r kwargs['alpha'] = mask_opacity kwargs['norm'] = matplotlib.colors.Normalize() axes.imshow(mf, **kwargs) if show_crosshair: ax = axes.axis() # save zoom state axes.plot([xmin, xmax], [bcy] * 2, 'w-') axes.plot([bcx] * 2, [ymin, ymax], 'w-') axes.axis(ax) # restore zoom state axes.set_axis_bgcolor(invalid_color) if show_colorbar: if isinstance(show_colorbar, matplotlib.axes.Axes): axes.figure.colorbar( ret, cax=show_colorbar) else: # try to find a suitable colorbar axes: check if the plot target axes already # contains some images, then check if their colorbars exist as # axes. cax = [i.colorbar[1] for i in axes.images if i.colorbar is not None] cax = [c for c in cax if c in c.figure.axes] if cax: cax = cax[0] else: cax = None axes.figure.colorbar(ret, cax=cax, ax=axes) axes.figure.canvas.draw() return ret
def handle_interaction(self, current_shape, orig_image): from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg import wx """Show the cropping user interface""" pixel_data = stretch(orig_image) # # Create the UI - a dialog with a figure inside # style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER dialog_box = wx.Dialog(wx.GetApp().TopWindow, -1, "Select the cropping region", size=(640, 480), style=style) sizer = wx.BoxSizer(wx.VERTICAL) figure = matplotlib.figure.Figure() panel = FigureCanvasWxAgg(dialog_box, -1, figure) sizer.Add(panel, 1, wx.EXPAND) btn_sizer = wx.StdDialogButtonSizer() btn_sizer.AddButton(wx.Button(dialog_box, wx.ID_OK)) btn_sizer.AddButton(wx.Button(dialog_box, wx.ID_CANCEL)) btn_sizer.Realize() sizer.Add(btn_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5) dialog_box.SetSizer(sizer) dialog_box.Size = dialog_box.BestSize dialog_box.Layout() axes = figure.add_subplot(1, 1, 1) assert isinstance(axes, matplotlib.axes.Axes) if pixel_data.ndim == 2: axes.imshow(pixel_data, matplotlib.cm.Greys_r, origin="upper") else: axes.imshow(pixel_data, origin="upper") # t = axes.transData.inverted() current_handle = [None] def data_xy(mouse_event): """Return the mouse event's x & y converted into data-relative coords""" x = mouse_event.xdata y = mouse_event.ydata return x, y class Handle(matplotlib.patches.Rectangle): dm = max((10, min(pixel_data.shape) / 50)) height, width = (dm, dm) def __init__(self, x, y, on_move): x = max(0, min(x, pixel_data.shape[1])) y = max(0, min(y, pixel_data.shape[0])) self.__selected = False self.__color = cellprofiler.preferences.get_primary_outline_color() self.__color = numpy.hstack((self.__color, [255])).astype(float) / 255.0 self.__on_move = on_move super(Handle, self).__init__((x - self.width / 2, y - self.height / 2), self.width, self.height, edgecolor=self.__color, facecolor="none") self.set_picker(True) def move(self, x, y): self.set_xy((x - self.width / 2, y - self.height / 2)) self.__on_move(x, y) def select(self, on): self.__selected = on if on: current_handle[0] = self self.set_facecolor(self.__color) else: self.set_facecolor("none") if current_handle[0] == self: current_handle[0] = None figure.canvas.draw() dialog_box.Update() @property def is_selected(self): return self.__selected @property def center_x(self): """The handle's notion of its x coordinate""" return self.get_x() + self.get_width() / 2 @property def center_y(self): """The handle's notion of its y coordinate""" return self.get_y() + self.get_height() / 2 def handle_pick(self, event): mouse_event = event.mouseevent x, y = data_xy(mouse_event) if mouse_event.button == 1: self.select(True) self.orig_x = self.center_x self.orig_y = self.center_y self.first_x = x self.first_y = y def handle_mouse_move_event(self, event): x, y = data_xy(event) if x is None or y is None: return x = x - self.first_x + self.orig_x y = y - self.first_y + self.orig_y if x < 0: x = 0 if x >= pixel_data.shape[1]: x = pixel_data.shape[1] - 1 if y < 0: y = 0 if y >= pixel_data.shape[0]: y = pixel_data.shape[0] - 1 self.move(x, y) class CropRectangle(object): def __init__(self, top_left, bottom_right): self.__left, self.__top = top_left self.__right, self.__bottom = bottom_right color = cellprofiler.preferences.get_primary_outline_color() color = numpy.hstack((color, [255])).astype(float) / 255.0 self.rectangle = matplotlib.patches.Rectangle( (min(self.__left, self.__right), min(self.__bottom, self.__top)), abs(self.__right - self.__left), abs(self.__top - self.__bottom), edgecolor=color, facecolor="none" ) self.top_left_handle = Handle(top_left[0], top_left[1], self.handle_top_left) self.bottom_right_handle = Handle(bottom_right[0], bottom_right[1], self.handle_bottom_right) def handle_top_left(self, x, y): self.__left = x self.__top = y self.__reshape() def handle_bottom_right(self, x, y): self.__right = x self.__bottom = y self.__reshape() def __reshape(self): self.rectangle.set_xy((min(self.__left, self.__right), min(self.__bottom, self.__top))) self.rectangle.set_width(abs(self.__right - self.__left)) self.rectangle.set_height(abs(self.__bottom - self.__top)) self.rectangle.figure.canvas.draw() dialog_box.Update() @property def patches(self): return [self.rectangle, self.top_left_handle, self.bottom_right_handle] @property def handles(self): return [self.top_left_handle, self.bottom_right_handle] @property def left(self): return min(self.__left, self.__right) @property def right(self): return max(self.__left, self.__right) @property def top(self): return min(self.__top, self.__bottom) @property def bottom(self): return max(self.__top, self.__bottom) class CropEllipse(object): def __init__(self, center, radius): """Draw an ellipse with control points at the ellipse center and a given x and y radius""" self.center_x, self.center_y = center self.radius_x = self.center_x + radius[0] / 2 self.radius_y = self.center_y + radius[1] / 2 color = cellprofiler.preferences.get_primary_outline_color() color = numpy.hstack((color, [255])).astype(float) / 255.0 self.ellipse = matplotlib.patches.Ellipse(center, self.width, self.height, edgecolor=color, facecolor="none") self.center_handle = Handle(self.center_x, self.center_y, self.move_center) self.radius_handle = Handle(self.radius_x, self.radius_y, self.move_radius) def move_center(self, x, y): self.center_x = x self.center_y = y self.redraw() def move_radius(self, x, y): self.radius_x = x self.radius_y = y self.redraw() @property def width(self): return abs(self.center_x - self.radius_x) * 4 @property def height(self): return abs(self.center_y - self.radius_y) * 4 def redraw(self): self.ellipse.center = (self.center_x, self.center_y) self.ellipse.width = self.width self.ellipse.height = self.height self.ellipse.figure.canvas.draw() dialog_box.Update() @property def patches(self): return [self.ellipse, self.center_handle, self.radius_handle] @property def handles(self): return [self.center_handle, self.radius_handle] if self.shape == SH_ELLIPSE: if current_shape is None: current_shape = { EL_XCENTER: pixel_data.shape[1] / 2, EL_YCENTER: pixel_data.shape[0] / 2, EL_XRADIUS: pixel_data.shape[1] / 2, EL_YRADIUS: pixel_data.shape[0] / 2 } ellipse = current_shape shape = CropEllipse((ellipse[EL_XCENTER], ellipse[EL_YCENTER]), (ellipse[EL_XRADIUS], ellipse[EL_YRADIUS])) else: if current_shape is None: current_shape = { RE_LEFT: pixel_data.shape[1] / 4, RE_TOP: pixel_data.shape[0] / 4, RE_RIGHT: pixel_data.shape[1] * 3 / 4, RE_BOTTOM: pixel_data.shape[0] * 3 / 4 } rectangle = current_shape shape = CropRectangle((rectangle[RE_LEFT], rectangle[RE_TOP]), (rectangle[RE_RIGHT], rectangle[RE_BOTTOM])) for patch in shape.patches: axes.add_artist(patch) def on_mouse_down_event(event): axes.pick(event) def on_mouse_move_event(event): if current_handle[0] is not None: current_handle[0].handle_mouse_move_event(event) def on_mouse_up_event(event): if current_handle[0] is not None: current_handle[0].select(False) def on_pick_event(event): for h in shape.handles: if id(h) == id(event.artist): h.handle_pick(event) figure.canvas.mpl_connect('button_press_event', on_mouse_down_event) figure.canvas.mpl_connect('button_release_event', on_mouse_up_event) figure.canvas.mpl_connect('motion_notify_event', on_mouse_move_event) figure.canvas.mpl_connect('pick_event', on_pick_event) try: if dialog_box.ShowModal() != wx.ID_OK: raise ValueError("Cancelled by user") finally: dialog_box.Destroy() if self.shape == SH_RECTANGLE: return { RE_LEFT: shape.left, RE_TOP: shape.top, RE_RIGHT: shape.right, RE_BOTTOM: shape.bottom } else: return { EL_XCENTER: shape.center_x, EL_YCENTER: shape.center_y, EL_XRADIUS: shape.width / 2, EL_YRADIUS: shape.height / 2 }