def create_img(self, series: pd.Series, centroid_name: str = None): """ Create image based on given data. :param pd.Series series: Data to plot. :param str centroid_name: Name of selected Country. (Optional) """ fig, ax = plt.subplots() fig.suptitle(self.title, fontsize=14, fontweight='bold') plt.yticks(rotation=25) plt.xticks(rotation=15) if self.num != 1: pos = series.index.get_loc(centroid_name) ax.get_xticklabels()[pos].set_color("red") plot = sbn.barplot(x='Country Name', y=series.name, data=series.reset_index(), ax=ax, palette=self.palette.loc[series.index].values) plot.grid(axis='y'); plot.set_title(self.subtitle(centroid_name)); plot.yaxis.set_label_position("right") plot.set_ylim(0, self.no_max) plot.yaxis.set_major_formatter(tick.FuncFormatter(lambda x, _: f'{x / 1000000:,.0f}')) for rect, label in zip(plot.patches, np.round(series.values / 1000000, 1)): height = rect.get_height() ax.text(rect.get_x() + rect.get_width() / 2, height + 5, label, ha='center', va='bottom') plot.set_ylabel('Population Size [mln]', rotation=270, labelpad=25, fontsize=15) plot.set_xlabel('Country Name', labelpad=15, fontsize=15) plot.text(0.8, 0.9, series.name, size=20, color='black', transform=ax.transAxes) plot = plot.figure plot.savefig(f'../images/{self.num}/{series.name}.jpg', bbox_inches=Bbox([[0.0, -0.6], plot.get_size_inches()])) plt.close()
def paintEvent(self, event): """ Copy the image from the Agg canvas to the qt.drawable. In Qt, all drawing should be done inside of here when a widget is shown onscreen. """ self._draw_idle() # Only does something if a draw is pending. # If the canvas does not have a renderer, then give up and wait for # FigureCanvasAgg.draw(self) to be called. if not hasattr(self, 'renderer'): return painter = QtGui.QPainter(self) try: # See documentation of QRect: bottom() and right() are off # by 1, so use left() + width() and top() + height(). rect = event.rect() # scale rect dimensions using the screen dpi ratio to get # correct values for the Figure coordinates (rather than # QT5's coords) width = rect.width() * self.device_pixel_ratio height = rect.height() * self.device_pixel_ratio left, top = self.mouseEventCoords(rect.topLeft()) # shift the "top" by the height of the image to get the # correct corner for our coordinate system bottom = top - height # same with the right side of the image right = left + width # create a buffer using the image bounding box bbox = Bbox([[left, bottom], [right, top]]) reg = self.copy_from_bbox(bbox) buf = cbook._unmultiplied_rgba8888_to_premultiplied_argb32( memoryview(reg)) # clear the widget canvas painter.eraseRect(rect) if QT_API == "PyQt6": from PyQt6 import sip ptr = int(sip.voidptr(buf)) else: ptr = buf qimage = QtGui.QImage( ptr, buf.shape[1], buf.shape[0], _enum("QtGui.QImage.Format").Format_ARGB32_Premultiplied) _setDevicePixelRatio(qimage, self.device_pixel_ratio) # set origin using original QT coordinates origin = QtCore.QPoint(rect.left(), rect.top()) painter.drawImage(origin, qimage) # Adjust the buf reference count to work around a memory # leak bug in QImage under PySide. if QT_API in ('PySide', 'PySide2'): if QtCore.__version_info__ < (5, 12): ctypes.c_long.from_address(id(buf)).value = 1 self._draw_rect_callback(painter) finally: painter.end()
def get_virtual_bb(self, transform=None): """ Get the bounding box of the entire :class:`~Annotation`. This is called a virtual bounding box because it is not a real bounding box. Rather, it is the smallest rectangular bounding box that covers all of the bounding boxes of the :class:`~Annotation`'s tokens. :param transform: The bounding box transformation. If `None` is given, the data transformation is used. :type transform: None or :class:`matplotlib.transforms.TransformNode` :return: The bounding box of the annotation. :rtype: :class:`matplotlib.transforms.Bbox` """ figure = self.drawable.figure axes = self.drawable.axes transform = axes.transData if transform is None else transform renderer = figure.canvas.get_renderer() """ Go through all the lines and their tokens and get their bounding boxes. Compare them with the virtual bounding box and update it as need be. """ x0, y0, x1, y1 = None, None, None, None for line in self.lines: for token in line: bb = util.get_bb(figure, axes, token, transform) x0 = bb.x0 if x0 is None or bb.x0 < x0 else x0 y0 = bb.y0 if y0 is None or bb.y0 < y0 else y0 x1 = bb.x1 if x1 is None or bb.x1 > x1 else x1 y1 = bb.y1 if y1 is None or bb.y1 > y1 else y1 return Bbox(((x0, y0), (x1, y1)))
def DrawToAxes( self, ax=None, Inset=None, XY0=(0, 0), ViewAng=(30, 45, 0), ViewAxes='xy', TextSize=12, alpha=1., ): if not (Inset is None): # add as a new inset fig = ax.figure Coords = Bbox.from_bounds(Inset[0], Inset[1], Inset[2], Inset[3]) AxCoords = ax.transAxes.transform(Coords) FigCoords = fig.transFigure.inverted().transform(AxCoords) ax2 = fig.add_axes(Bbox(FigCoords)) ax = ax2 CP = ChemPallette(XY0=XY0, TextSize=TextSize) CP.SetProjection(ViewAng[0], ViewAng[1], ViewAng[2]) CP.ViewAxes(ViewAxes) self.DrawToPallette(CP) CP.Show(ax, alpha=alpha) ax.axis('equal') if not (Inset is None): ax.axis('off') return ax
def _generate_plot(self, output_path, plot_settings): """ Override base class method. @param output_path (str): the full path to the file @param plot_settings (StandardMap): an object containing plot settings """ # By default we want to show the legend self.show_legend = True # Set plot line width if self.input_data.get_value(InputType.IMAGE_SIZE) == 900: self.line_width = 1 if self.input_data.get_value(InputType.IMAGE_SIZE) == 1200: self.line_width = 2 elif self.input_data.get_value(InputType.IMAGE_SIZE) == 2400: self.line_width = 3 # First create the figure fig, _, _ = start_standard_figure(plot_settings) # Add the logo and metadata box self._add_logo(fig) # Set the area below the title and allow room for the labels # [[left, bottom], [right, top]] fig.add_axes(Bbox([[0.11, 0.12], [0.95, 0.81]])) self._generate_graph() # Set the title width and tick label padding width = 105 ax = plt.gca() if self.input_data.get_value(InputType.IMAGE_SIZE) == 900: width = 105 - (self.input_data.get_font_size() * 3) ax.tick_params(axis="both", which="major", pad=5) if self.input_data.get_value(InputType.IMAGE_SIZE) == 1200: width = 100 - (self.input_data.get_font_size() * 2) ax.tick_params(axis="both", which="major", pad=10) elif self.input_data.get_value(InputType.IMAGE_SIZE) == 2400: width = 100 - (self.input_data.get_font_size() * 1) ax.tick_params(axis="both", which="major", pad=20) # Add the title new_title = wrap_string(self.title, width) fig.suptitle(new_title, fontsize=self.input_data.get_font_size()) if self.show_legend is True: # Add the legend legend_font_size = self.input_data.get_font_size() * 0.7 plt.legend( loc=self.input_data.get_value(InputType.LEGEND_POSITION), prop={"size": legend_font_size}, ) # Put a grid on the plot. plt.grid(True) # Output the plot # plotgeneral.set_standard_margins(settings=None, fig=fig) end_figure(output_path)
def plot_symbol(self, bbox, alignment, column_i, seq_i): trace = alignment.trace if trace[column_i, seq_i] != -1: symbol = alignment.sequences[seq_i][trace[column_i, seq_i]] else: symbol = "" color = self._get_color(alignment, column_i, seq_i) draw_func = self._draw_funcs.get(symbol) # 'draw_func' is None for gaps if draw_func is not None: # Shrink Bbox slightly to get a small margin between shapes f = 0.04 shape_bbox = Bbox( ((bbox.x0 + f * bbox.width, bbox.y0 + f * bbox.height), (bbox.x1 - f * bbox.width, bbox.y1 - f * bbox.height)), ) draw_func(self, shape_bbox, color) text = self.axes.text(bbox.x0 + bbox.width / 2, bbox.y0 + bbox.height / 2, symbol, color="black", ha="center", va="center", size=self._font_size, **self._font_param) text.set_clip_on(True)
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 _bbox_with_margins(left, bottom, right, top): fig = plt.gcf() x0 = fig.bbox.x0 + left y0 = fig.bbox.y0 + bottom x1 = fig.bbox.x1 - right y1 = fig.bbox.y1 - top return Bbox([[x0, y0], [x1, y1]]).transformed(fig.transFigure.inverted())
def plotComparison(ens_mean, ens_ob_mean, ens_ob_std, obs, ob_locations, refl, grid, levels, cmap, title, file_name): max_std = 5.0 xs, ys = grid.getXY() obs_xs, obs_ys = grid(*ob_locations) clip_box = Bbox([[0, 0], [1, 1]]) pylab.figure() pylab.contourf(xs, ys, ens_mean, cmap=cmap, levels=levels) pylab.colorbar() pylab.contour(xs, ys, refl, colors='k', levels=np.arange(20, 80, 20)) for ob_x, ob_y, ob, ob_mean, ob_std in zip(obs_xs, obs_ys, obs, ens_ob_mean, ens_ob_std): color_bin = np.argmin(np.abs(ob - levels)) if ob > levels[color_bin]: color_bin += 1 color_level = float(color_bin) / len(levels) ob_z_score = (ob - ob_mean) / ob_std print "Ob z-score:", ob_z_score, "Ob:", ob, "Ob mean:", ob_mean, "Ob std:", ob_std pylab.plot(ob_x, ob_y, 'ko', markerfacecolor=cmap(color_level), markeredgecolor=std_cmap(ob_z_score / max_std), markersize=4, markeredgewidth=1) # pylab.text(ob_x - 1000, ob_y + 1000, "%5.1f" % temp_K, ha='right', va='bottom', size='xx-small', clip_box=clip_box, clip_on=True) grid.drawPolitical() pylab.suptitle(title) pylab.savefig(file_name) pylab.close() return
def mark_inset(ax, ax2, m, m2, MAP, loc1=(1, 2), loc2=(3, 4), **kwargs): """ https://stackoverflow.com/questions/41610834/basemap-projection-geos-controlling-mark-inset-location Patched mark_inset to work with Basemap. Reason: Basemap converts Geographic (lon/lat) to Map Projection (x/y) coordinates Additionally: set connector locations separately for both axes: loc1 & loc2: tuple defining start and end-locations of connector 1 & 2 """ axzoom_geoLims = (MAP['cyl'][2:], MAP['cyl'][:2]) rect = TransformedBbox(Bbox(np.array(m(*axzoom_geoLims)).T), ax.transData) pp = BboxPatch(rect, fill=False, **kwargs) ax.add_patch(pp) p1 = BboxConnector(ax2.bbox, rect, loc1=loc1[0], loc2=loc1[1], **kwargs) ax2.add_patch(p1) p1.set_clip_on(False) p2 = BboxConnector(ax2.bbox, rect, loc1=loc2[0], loc2=loc2[1], **kwargs) ax2.add_patch(p2) p2.set_clip_on(False) return pp, p1, p2
def draw(self, renderer): arrow_box = Bbox([(0, 0), (0, self._head_width)]) arrow_box_display = self.axes.transData.transform_bbox(arrow_box) head_length_display = np.abs(arrow_box_display.height * self._head_ratio) arrow_box_display.x1 = arrow_box_display.x0 + head_length_display # Transfrom back to data coordinates for plotting arrow_box = self.axes.transData.inverted().transform_bbox( arrow_box_display) head_length = arrow_box.width arrow_length = norm((self._dx, self._dy)) if head_length > arrow_length: # If the head would be longer than the entire arrow, # only draw the arrow head with reduced length head_length = arrow_length if not self._draw_head: head_length = 0 # Renew the arrow's properties super().__init__(self._x, self._y, self._dx, self._dy, width=self._tail_width, head_width=self._head_width, overhang=0, shape=self._shape, head_length=head_length, length_includes_head=True, axes=self.axes, transform=self.get_transform(), **self._kwargs) self.set_clip_path(self.axes.patch) super().draw(renderer)
def __init__(self, image: Union[AxesImage, QuadMesh], transform: NonOrthogonalTransform, do_transform: bool, widget: ImageInfoWidget, cursor_transform: tuple = None): """ Update the image that the widget refers too. :param: An AxesImage or Mesh instance to track :param: transpose_xy: If true the cursor position should be transposed before sending to the table update :param do_transform: Flag to perform transform for QuadMesh images :param widget: ImageInfoWidget instance :param cursor_transform: Full axes limits to use for mouse coord transform to use instead of image extents """ super().__init__(image_axes=image.axes, autoconnect=False) self._image = image self.transform = transform self.do_transform = do_transform self._widget = widget self._cursor_transform = None if cursor_transform is not None: self._cursor_transform = Bbox( [[cursor_transform[1][0], cursor_transform[0][0]], [cursor_transform[1][1], cursor_transform[0][1]]]) if hasattr(image, 'get_extent'): self.on_cursor_at = self._on_cursor_at_axesimage else: self.on_cursor_at = self._on_cursor_at_mesh
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_data_pixel(ax, fig, x, y, s): """ Method that return the bouding box of the points. Inputs: ax : (matplotlib obj) Matplotlib object of the axes of the plot fig : (matplotlib obj) Matplotlib object of the figure of the plot x, y : (list, list) Actuall x and y coordinates of the points. s : (list) sizes of the points. Outputs: boxes (list) : list of bounding boxes for each points. """ xy_pixels = ax.transData.transform(np.vstack([x, y]).T) xpix, ypix = xy_pixels.T boxes = [] for x_j, y_j, s_j in zip(xpix, ypix, s): if s_j < 25: s_j = 25 box_size = fig.dpi * np.sqrt(s_j) / 70.0 x0 = x_j - box_size / 2.0 y0 = y_j - box_size / 2.0 x1 = x_j + box_size / 2.0 y1 = y_j + box_size / 2.0 boxes.append(Bbox([[x0, y0], [x1, y1]])) return boxes
def print_table(self): row_colors = ["#f5f5f5", "#ffffff"] total_width = sum(self.col_widths) figheight = self.fig.get_figheight() row_locs = [height / figheight for height in self.row_heights] header_text_align = [vals[2] for vals in self.rows[0]] x0 = (1 - total_width) / 2 x = x0 yd = row_locs[0] y = 1 for i, (yd, row) in enumerate(zip(row_locs, self.rows)): x = x0 y -= yd for j, (xd, val) in enumerate(zip(self.col_widths, row)): text = val[0] weight = 'bold' if val[1] else None ha = val[2] or header_text_align[j] or 'right' if ha == 'right': x += xd elif ha == 'center': x += xd / 2 self.fig.text(x, y + yd / 2, text, family='Helvetica', size=self.fontsize, ha=ha, va='center', weight=weight) if ha == 'left': x += xd elif ha == 'center': x += xd / 2 diff = i - self.num_header_rows if diff >= 0 and diff % 2 == 0: p = mpatches.Rectangle((x0, y), width=total_width, height=yd, fill=True, color='#f5f5f5', transform=self.fig.transFigure) self.fig.add_artist(p) if i == self.num_header_rows - 1: line = mlines.Line2D([x0, x0 + total_width], [y, y], color='black') self.fig.add_artist(line) w, h = self.fig.get_size_inches() start = self.figwidth * min(x0, .1) end = self.figwidth - start bbox = Bbox([[start - .1, y * h], [end + .1, h]]) buffer = io.BytesIO() self.fig.savefig(buffer, bbox_inches=bbox) return base64.b64encode(buffer.getvalue()).decode()
def composite_images(images, renderer, magnification=1.0): """ Composite a number of RGBA images into one. The images are composited in the order in which they appear in the `images` list. Parameters ---------- images : list of Images Each must have a `make_image` method. For each image, `can_composite` should return `True`, though this is not enforced by this function. Each image must have a purely affine transformation with no shear. renderer : RendererBase instance magnification : float The additional magnification to apply for the renderer in use. Returns ------- tuple : image, offset_x, offset_y Returns the tuple: - image: A numpy array of the same type as the input images. - offset_x, offset_y: The offset of the image (left, bottom) in the output figure. """ if len(images) == 0: return np.empty((0, 0, 4), dtype=np.uint8), 0, 0 parts = [] bboxes = [] for image in images: data, x, y, trans = image.make_image(renderer, magnification) if data is not None: x *= magnification y *= magnification parts.append((data, x, y, image.get_alpha() or 1.0)) bboxes.append( Bbox([[x, y], [x + data.shape[1], y + data.shape[0]]])) if len(parts) == 0: return np.empty((0, 0, 4), dtype=np.uint8), 0, 0 bbox = Bbox.union(bboxes) output = np.zeros((int(bbox.height), int(bbox.width), 4), dtype=np.uint8) for data, x, y, alpha in parts: trans = Affine2D().translate(x - bbox.x0, y - bbox.y0) _image.resample(data, output, trans, _image.NEAREST, resample=False, alpha=alpha) return output, bbox.x0 / magnification, bbox.y0 / magnification
def GetOptimalAxesPosition(fig, ax, additionalArtists=[], padding=5): rendr = fig.canvas.get_renderer() #import cairo ##w_inch, h_inch = fig.get_size_inches() ##width, height = 72*w_inch, 72*h_inch #print fig.dpi #width, height = fig.canvas.get_width_height() #rendr = matplotlib.backends.backend_cairo.RendererCairo(fig.dpi) #rendr.set_width_height(width, height) #surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) #rendr.set_ctx_from_surface(surface) axBounds = ax.bbox getArea = lambda bbox: bbox.width * bbox.height def getExtent(artist): try: return artist.get_window_extent(rendr) except: return artist.get_window_extent() hasExtent = lambda artist: hasattr(artist, "get_window_extent" ) and getArea(getExtent(artist)) > 0 isVisible = lambda artist: not hasattr(artist, "get_visible" ) or artist.get_visible() HideUnusedTickLabels(fig) axBoxes = map(getExtent, filter(isVisible, filter(hasExtent, WalkChildren(ax)))) addBoxes = [ map(getExtent, filter(isVisible, filter(hasExtent, WalkChildren(artist)))) for artist in additionalArtists ] totalBounds = Bbox.union(axBoxes + map(Bbox.union, addBoxes)) width = rendr.width height = rendr.height xmin = ((axBounds.xmin - totalBounds.xmin) + padding) ymin = ((axBounds.ymin - totalBounds.ymin) + padding) xmax = (width + (axBounds.xmax - totalBounds.xmax) - padding) ymax = (height + (axBounds.ymax - totalBounds.ymax) - padding) t = matplotlib.transforms.BboxTransformFrom(fig.bbox) newPos = Bbox(t.transform(Bbox([[xmin, ymin], [xmax, ymax]]))) return newPos
def __init__(self): plt.close() self.fig = plt.figure(1, figsize=(15, 6), dpi=90) self.ax = self.fig.add_subplot(111) self.ax.set_axis_off() pos = self.ax.get_position() box = Bbox(pos) self.ax.set_position(box)
def imagesAtPositions(ax, images, positions): for s in range(len(positions)): #print(positions[s,:]) bbox = Bbox(corners(ax, positions[s, :], 20)) bbox_image = BboxImage(bbox) image = imread(images[s]) bbox_image.set_data(image) ax.add_artist(bbox_image)
def highlight_artist(self, val, artist=None): # print val, artist figure = self.get_figpage()._artists[0] ax = self.get_figaxes() if artist is None: alist = self._artists else: alist = artist if val == True: container = self.get_container() if container is None: return de = self.get_data_extent() from ifigure.matplotlib_mod.art3d_gl import AxesImageGL if isinstance(alist[0], AxesImageGL): hl = alist[0].add_hl_mask() for item in hl: alist[0].figobj_hl.append(item) # hl = alist[0].make_hl_artist(container) # rect_alpha = 0.0 else: x = [de[0], de[1], de[1], de[0], de[0]] y = [de[2], de[2], de[3], de[3], de[2]] hl = container.plot(x, y, marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth=0.5, scalex=False, scaley=False) rect_alpha = 0.3 hlp = Rectangle((de[0], de[2]), de[1] - de[0], de[3] - de[2], alpha=rect_alpha, facecolor='k', figure=figure, transform=container.transData) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0, 0)) x1, y1 = ax._artists[0].transAxes.transform((1, 1)) bbox = Bbox([[x0, y0], [x1, y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) for item in (hl[0], hlp): alist[0].figobj_hl.append(item) else: for a in alist: if len(a.figobj_hl) != 0: a.figobj_hl[0].remove() figure.patches.remove(a.figobj_hl[1]) a.figobj_hl = []
def paintEvent(self, event): """ Copy the image from the Agg canvas to the qt.drawable. In Qt, all drawing should be done inside of here when a widget is shown onscreen. """ if self._update_dpi(): # The dpi update triggered its own paintEvent. return self._draw_idle() # Only does something if a draw is pending. # If the canvas does not have a renderer, then give up and wait for # FigureCanvasAgg.draw(self) to be called. if not hasattr(self, 'renderer'): return painter = QtGui.QPainter(self) # See documentation of QRect: bottom() and right() are off by 1, so use # left() + width() and top() + height(). rect = event.rect() # scale rect dimensions using the screen dpi ratio to get # correct values for the Figure coordinates (rather than QT5's coords) width = rect.width() * self._dpi_ratio height = rect.height() * self._dpi_ratio left, top = self.mouseEventCoords(rect.topLeft()) # shift the "top" by the height of the image to get the # correct corner for our coordinate system bottom = top - height # same with the right side of the image right = left + width # create a buffer using the image bounding box bbox = Bbox([[left, bottom], [right, top]]) reg = self.copy_from_bbox(bbox) buf = cbook._unmultiplied_rgba8888_to_premultiplied_argb32( memoryview(reg)) # clear the widget canvas painter.eraseRect(rect) qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0], QtGui.QImage.Format_ARGB32_Premultiplied) if hasattr(qimage, 'setDevicePixelRatio'): # Not available on Qt4 or some older Qt5. qimage.setDevicePixelRatio(self._dpi_ratio) # set origin using original QT coordinates origin = QtCore.QPoint(rect.left(), rect.top()) painter.drawImage(origin, qimage) # Adjust the buf reference count to work around a memory # leak bug in QImage under PySide on Python 3. if QT_API in ('PySide', 'PySide2'): ctypes.c_long.from_address(id(buf)).value = 1 self._draw_rect_callback(painter) painter.end()
def get_virtual_bb(self, transform=None): """ Get the bounding box of the entire annotation. This is called a virtual bounding box because it is not a real bounding box. Rather, it is a bounding box that covers all of the bounding boxes of the legend. .. note:: The legend always spans the entire x-axis. :param transform: The bounding box transformation. If `None` is given, the data transformation is used. :type transform: None or :class:`matplotlib.transforms.TransformNode` :return: The bounding box of the annotation. :rtype: :class:`matplotlib.transforms.Bbox` """ figure = self.drawable.figure axis = self.drawable.axis transform = axis.transData if transform is None else transform """ If there are lines that are not empty, get the bounding boxes from the first and last lines. The virtual bounding box's top value is equivalent to the first line's highest point. The virtual bounding box's bottom value is equivalent to the last line's lowest point. """ if self.lines: top = self.lines[0] bottom = self.lines[-1] """ If the lines are empty, return a flat bounding box. Otherwise, get the maximum and minimum points of these bounding boxes. """ if not len(top) or not len(bottom): return Bbox(((0, 1), (1, 1))) y1 = max( annotation.get_virtual_bb(transform=transform).y1 for _, annotation in top) y0 = min( annotation.get_virtual_bb(transform=transform).y0 for _, annotation in bottom) return Bbox(((0, y0), (1, y1)))
def standalone_legends_lines(): from matplotlib.lines import Line2D lines = [ Line2D([0, 1], [0, 1], color='black', linestyle='-'), Line2D([0, 1], [0, 1], color='black', linestyle='--'), ] plt.legend(lines, ['One', 'Two'], loc=(-0.0, -0.25), ncol=2) bbox = Bbox(np.array([[0.7, -0.45], [2.6, -0.06]])) plt.savefig(f'graphics/legend-lines.png', dpi=300, bbox_inches=bbox) plt.clf()
def standalone_legends_patches(): import matplotlib.patches as mpatches patches = [ mpatches.Patch(label="One", color='red'), mpatches.Patch(label="Two", color='blue'), ] plt.legend(handles=patches, loc=(-0.0, -0.25), ncol=3) bbox = Bbox(np.array([[0.7, -0.45], [2.6, -0.06]])) plt.savefig(f'graphics/legend-patches.png', dpi=300, bbox_inches=bbox) plt.clf()
def reset_zoom(self): height, width = self.ih.get_size() lims = (-0.5, width - 0.5, -0.5, height - 0.5) self.ih.axes.axis(lims) self.ax.set_position(Bbox([[0, 0], [1, 1]])) try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() self.fig.canvas.draw()
def BoundingBoxTicks(ax, fig, tick_size, xAxisPos, yAxisPos): # Method that return the bouding box of the ticks. xTickPos = [ ax.transLimits.transform(textobj.get_position()) for textobj in ax.get_xticklabels() if len(textobj.get_text()) > 0 ] yTickPos = [ ax.transLimits.transform(textobj.get_position()) for textobj in ax.get_yticklabels() if len(textobj.get_text()) > 0 ] xTickPos = [ ax.transScale.transform(ax.transAxes.transform([array[0], xAxisPos])) for array in xTickPos ] yTickPos = [ ax.transScale.transform(ax.transAxes.transform([yAxisPos, array[1]])) for array in yTickPos ] box_x = [] for x_list, y_list in xTickPos: sizeof_box_x = fig.dpi * 5 / 50.0 sizeof_box_y = fig.dpi * 5 / 50.0 x0 = x_list - sizeof_box_x / 2.0 y0 = y_list - sizeof_box_y / 2.0 x1 = x_list + sizeof_box_x / 2.0 y1 = y_list + sizeof_box_y / 2.0 box_x.append(Bbox([[x0, y0], [x1, y1]])) box_y = [] for x_list, y_list in yTickPos: sizeof_box_x = fig.dpi * 5 / 50.0 sizeof_box_y = fig.dpi * 5 / 50.0 x0 = x_list - sizeof_box_x / 2.0 y0 = y_list - sizeof_box_y / 2.0 x1 = x_list + sizeof_box_x / 2.0 y1 = y_list + sizeof_box_y / 2.0 box_y.append(Bbox([[x0, y0], [x1, y1]])) return box_x, box_y
def _repositioning_axes(fig): n = _num_axes(fig) if n > 0: heights = np.linspace(0.05, 0.95, n + 1) for i, ax in enumerate(fig.axes): ax.set_position( Bbox([[0.10, heights[i] + 0.01], [0.99, heights[i + 1] - 0.01]]), which="both", )
def test_overlapping_inverted_y(self): """ Test that when the y-axis is inverted, the overlapping test adapts the bounding boxes. """ # first test the normal behavior of the bounding box viz = drawable.Drawable(plt.figure(figsize=(5, 5))) text = viz.text(0, 0, 'piece of text') bb = util.get_bb(viz.figure, viz.axes, text) self.assertLess(bb.y0, bb.y1) # test that when inverting the y-axis, the y-coordinates of the bounding box change viz.invert_yaxis() bb = util.get_bb(viz.figure, viz.axes, text) self.assertGreater(bb.y0, bb.y1) # create overlapping bounding boxes that emulate an inverted y-axis and test bb1, bb2 = Bbox(((0, 1), (1, 0))), Bbox(((0.5, 1.5), (1.5, 0.5))) self.assertTrue(util.overlapping_bb(bb1, bb2))
def make_image(self, renderer, magnification=1.0, unsampled=False): trans = self.get_transform() # image is created in the canvas coordinate. x1, x2, y1, y2 = self.get_extent() bbox = Bbox(np.array([[x1, y1], [x2, y2]])) transformed_bbox = TransformedBbox(bbox, trans) return self._make_image( self._A, bbox, transformed_bbox, self.axes.bbox, magnification, unsampled=unsampled)
def plot_polygon(ax, fig): ymin, ymax = ax.get_ylim() xy = [[-1 * log2(50), 0], [5, ymax * 0.35], [20, ymax * 0.35], [0, 0]] poly = Polygon(xy, facecolor='#E6E6E6', edgecolor='none', zorder=1) ax.add_patch(poly) bb_data = Bbox.from_bounds(5, ymax * 0.35, 15, ymax * 0.55) disp_coords = ax.transData.transform(bb_data) fig_coords = fig.transFigure.inverted().transform(disp_coords) ax2 = fig.add_axes(Bbox(fig_coords), zorder=5) return ax, ax2