def inspect(self, data): """ The data item for an out-of-bound capability is expected to be in the form [cycles, base, length, offset] """ logger.debug("Inspect data point %s", data) cycles, base, bound, offset = data cap_range = ((base, cycles), (bound, cycles)) oob_offset = (offset, cycles) if offset < base: oob_link = ((offset, cycles), (base, cycles)) else: # offset > base + length because we are certain that # it is out of bounds oob_link = ((bound, cycles), (offset, cycles)) self._cap_ranges.append(cap_range) self._oob_links.append(oob_link) self._oob_offsets.append(oob_offset) # update bounding box range_bbox = Bbox(cap_range) link_bbox = Bbox(oob_link) offset_bbox = Bbox([oob_offset, oob_offset]) if self._bbox: self._bbox = Bbox.union( [self._bbox, range_bbox, link_bbox, offset_bbox]) else: self._bbox = Bbox.union([range_bbox, link_bbox, offset_bbox]) # update ranges logger.debug("View %s", self._bbox)
def get_tight_bbox(fig, bbox_extra_artists=[], pad=None): """ Compute a tight bounding box around all the artists in the figure. """ renderer = fig._cachedRenderer bbox_inches = fig.get_tightbbox(renderer) bbox_artists = bbox_extra_artists[:] bbox_artists += fig.get_default_bbox_extra_artists() bbox_filtered = [] for a in bbox_artists: bbox = a.get_window_extent(renderer) if isinstance(bbox, tuple): continue if a.get_clip_on(): clip_box = a.get_clip_box() if clip_box is not None: bbox = Bbox.intersection(bbox, clip_box) clip_path = a.get_clip_path() if clip_path is not None and bbox is not None: clip_path = clip_path.get_fully_transformed_path() bbox = Bbox.intersection(bbox, clip_path.get_extents()) if bbox is not None and (bbox.width != 0 or bbox.height != 0): bbox_filtered.append(bbox) if bbox_filtered: _bbox = Bbox.union(bbox_filtered) trans = Affine2D().scale(1.0 / fig.dpi) bbox_extra = TransformedBbox(_bbox, trans) bbox_inches = Bbox.union([bbox_inches, bbox_extra]) return bbox_inches.padded(pad) if pad else bbox_inches
def get_tight_bbox(fig, bbox_extra_artists=[], pad=None): """ Compute a tight bounding box around all the artists in the figure. """ renderer = fig.canvas.get_renderer() bbox_inches = fig.get_tightbbox(renderer) bbox_artists = bbox_extra_artists[:] bbox_artists += fig.get_default_bbox_extra_artists() bbox_filtered = [] for a in bbox_artists: bbox = a.get_window_extent(renderer) if isinstance(bbox, tuple): continue if a.get_clip_on(): clip_box = a.get_clip_box() if clip_box is not None: bbox = Bbox.intersection(bbox, clip_box) clip_path = a.get_clip_path() if clip_path is not None and bbox is not None: clip_path = clip_path.get_fully_transformed_path() bbox = Bbox.intersection(bbox, clip_path.get_extents()) if bbox is not None and (bbox.width != 0 or bbox.height != 0): bbox_filtered.append(bbox) if bbox_filtered: _bbox = Bbox.union(bbox_filtered) trans = Affine2D().scale(1.0 / fig.dpi) bbox_extra = TransformedBbox(_bbox, trans) bbox_inches = Bbox.union([bbox_inches, bbox_extra]) return bbox_inches.padded(pad) if pad else bbox_inches
def update_plot(self): """ update the plot. The DataSets themselves have already been updated in update, here we just push the changes to the plot. """ # matplotlib doesn't know how to autoscale to a pcolormesh after the # first draw (relim ignores it...) so we have to do this ourselves bboxes = dict(zip(self.subplots, [[] for p in self.subplots])) for trace in self.traces: config = trace['config'] plot_object = trace['plot_object'] if 'z' in config: # pcolormesh doesn't seem to allow editing x and y data, only z # so instead, we'll remove and re-add the data. if plot_object: plot_object.remove() ax = self[config.get('subplot', 1) - 1] kwargs = deepcopy(config) # figsize may be passed in as part of config. # pcolormesh will raise an error if this is passed to it # so strip it here. if 'figsize' in kwargs: kwargs.pop('figsize') plot_object = self._draw_pcolormesh(ax, **kwargs) trace['plot_object'] = plot_object if plot_object: bboxes[plot_object.axes].append( plot_object.get_datalim(plot_object.axes.transData)) else: for axletter in 'xy': setter = 'set_' + axletter + 'data' if axletter in config: getattr(plot_object, setter)(config[axletter]) for ax in self.subplots: if ax.get_autoscale_on(): ax.relim() if bboxes[ax]: bbox = Bbox.union(bboxes[ax]) if np.all(np.isfinite(ax.dataLim)): # should take care of the case of lines + heatmaps # where there's already a finite dataLim from relim ax.dataLim.set(Bbox.union(ax.dataLim, bbox)) else: # when there's only a heatmap, relim gives inf bounds # so just completely overwrite it ax.dataLim = bbox ax.autoscale() self.fig.canvas.draw()
def _compute_bbox(self, fig, kw): """ Compute the tight bounding box for each figure once, reducing number of required canvas draw calls from N*2 to N+1 as a function of the number of frames. Tight bounding box computing code here mirrors: matplotlib.backend_bases.FigureCanvasBase.print_figure as it hasn't been factored out as a function. """ fig_id = id(fig) if kw['bbox_inches'] == 'tight': if not fig_id in MPLRenderer.drawn: fig.set_dpi(self.dpi) fig.canvas.draw() renderer = fig._cachedRenderer bbox_inches = fig.get_tightbbox(renderer) bbox_artists = kw.pop("bbox_extra_artists", []) bbox_artists += fig.get_default_bbox_extra_artists() bbox_filtered = [] for a in bbox_artists: bbox = a.get_window_extent(renderer) if isinstance(bbox, tuple): continue if a.get_clip_on(): clip_box = a.get_clip_box() if clip_box is not None: bbox = Bbox.intersection(bbox, clip_box) clip_path = a.get_clip_path() if clip_path is not None and bbox is not None: clip_path = clip_path.get_fully_transformed_path() bbox = Bbox.intersection(bbox, clip_path.get_extents()) if bbox is not None and (bbox.width != 0 or bbox.height != 0): bbox_filtered.append(bbox) if bbox_filtered: _bbox = Bbox.union(bbox_filtered) trans = Affine2D().scale(1.0 / self.dpi) bbox_extra = TransformedBbox(_bbox, trans) bbox_inches = Bbox.union([bbox_inches, bbox_extra]) pad = plt.rcParams['savefig.pad_inches'] bbox_inches = bbox_inches.padded(pad) MPLRenderer.drawn[fig_id] = bbox_inches kw['bbox_inches'] = bbox_inches else: kw['bbox_inches'] = MPLRenderer.drawn[fig_id] return kw
def save_axes(ax, save_at="", name="fig", save_fmts=["png"], pad=0.0, **kwargs): """ Save either a single or multiple axes (from a single figure) based on their extent. Uses the save_figure procedure to save at a specific location using a number of formats. Todo ----- * Add legend to items """ # Check if axes is a single axis or list of axes if isinstance(ax, matplotlib.axes.Axes): extent = get_full_extent(ax, pad=pad) figure = ax.figure else: extent_items = [] for a in ax: extent_items.append(get_full_extent(a, pad=pad)) figure = ax[0].figure extent = Bbox.union([item for item in extent_items]) save_figure(figure, bbox_inches=extent, save_at=save_at, name=name, save_fmts=save_fmts, **kwargs)
def on_press(self, event): if event.inaxes == self.rax.axes: self.update() if event.inaxes == self.resax.axes: # 'reset view' button : default datarange, linear scale, first image self.clmin = self.mindef self.clmax = self.maxdef self.tbmin.set_val(self.clmin) self.tbmax.set_val(self.clmax) self.rb.set_active(0) self.ind = 0 print('updated data range is [%s , %s ]' % (self.clmin, self.clmax)) self.update() if event.inaxes == self.exitax: sys.exit(0) # exit program if event.inaxes == self.savebut.axes: # 'save image' button items = [ self.ax, self.cbax, self.cbax.get_yaxis().get_label(), self.ax.get_xaxis().get_label(), self.ax.get_yaxis().get_label() ] bbox = Bbox.union([item.get_window_extent() for item in items]) extent = bbox.transformed(self.fg.dpi_scale_trans.inverted()) strim = 'img_trID_{:d}_plID_{:d}_ceID_{:d}_type_{:d}.png'.format( self.trainid_data[self.ind], self.pulseid_data[self.ind], self.cellid_data[self.ind], self.imtype[self.ind]) self.fg.savefig(self.dirsave + strim, bbox_inches=extent)
def draw(self, renderer, *args, **kwargs): bbox = Bbox.union(self.yaxes.get_ticklabel_extents( renderer).broadcast('__getitem__')(0)) x = bbox.xmin - self.labelpad * self.get_figure().dpi / 72.0 y = (bbox.ymin + bbox.ymax) / 2.0 self.label.set_position((x, y)) self.label.draw(renderer, *args, **kwargs)
def get_tightbbox(self, renderer): if not self.get_visible(): return self._axis_artist_helper.update_lim(self.axes) dpi_cor = renderer.points_to_pixels(1.) self.dpi_transform.clear().scale(dpi_cor, dpi_cor) bb = [] self._update_ticks(renderer) #if self.major_ticklabels.get_visible(): bb.extend(self.major_ticklabels.get_window_extents(renderer)) #if self.minor_ticklabels.get_visible(): bb.extend(self.minor_ticklabels.get_window_extents(renderer)) self._update_label(renderer) #if self.label.get_visible(): bb.append(self.label.get_window_extent(renderer)) bb.append(self.offsetText.get_window_extent(renderer)) bb = [b for b in bb if b and (b.width != 0 or b.height != 0)] if bb: _bbox = Bbox.union(bb) return _bbox else: return None
def png_response(self): # try: # self.set_ylim_margin(top=0.1, bottom=0.0) # except: # pass # self.set_ylim_margin(top=0.1, bottom=0.0) major_locator = LessTicksAutoDateLocator(tz=self.tz) self.axes.xaxis.set_major_locator(major_locator) major_formatter = MultilineAutoDateFormatter(major_locator, self.axes, self.tz) self.axes.xaxis.set_major_formatter(major_formatter) # Do final tweaks after data has been added to the axes # ylim_old = self.axes.get_ylim() # ylim_new = (ylim_old[0], # ylim_old[1] + 0.15 * (ylim_old[1] - ylim_old[0])) # self.axes.set_ylim(ylim_new) # self.legend() self.axes.set_xlim(date2num((self.start_date_ams, self.end_date_ams))) # find out about the data extents and set ylim accordingly if len(self.axes.patches) > 0: data_bbox = Bbox.union([p.get_extents() for p in self.axes.patches]) ymin, ymax = data_bbox.inverse_transformed(self.axes.transData).get_points()[:, 1] * array([1, 1.1]) ymax = max(1, ymax) ymin = -0.01 * ymax self.axes.set_ylim((ymin, ymax)) return super(RainappGraph, self).png_response()
def test_text_with_arrow_annotation_get_window_extent(): headwidth = 21 fig, ax = plt.subplots(dpi=100) txt = ax.text(s='test', x=0, y=0) ann = ax.annotate('test', xy=(0.0, 50.0), xytext=(50.0, 50.0), xycoords='figure pixels', arrowprops={ 'facecolor': 'black', 'width': 2, 'headwidth': headwidth, 'shrink': 0.0}) plt.draw() renderer = fig.canvas.renderer # bounding box of text text_bbox = txt.get_window_extent(renderer=renderer) # bounding box of annotation (text + arrow) bbox = ann.get_window_extent(renderer=renderer) # bounding box of arrow arrow_bbox = ann.arrow.get_window_extent(renderer) # bounding box of annotation text ann_txt_bbox = Text.get_window_extent(ann) # make sure annotation with in 50 px wider than # just the text eq_(bbox.width, text_bbox.width + 50.0) # make sure the annotation text bounding box is same size # as the bounding box of the same string as a Text object eq_(ann_txt_bbox.height, text_bbox.height) eq_(ann_txt_bbox.width, text_bbox.width) # compute the expected bounding box of arrow + text expected_bbox = Bbox.union([ann_txt_bbox, arrow_bbox]) assert_almost_equal(bbox.height, expected_bbox.height)
def save_axes(axes, save_at='', name='fig', save_fmts=['png'], pad=0.0, **kwargs): """ Save either a single or multiple axes (from a single figure) based on their extent. Uses the save_figure procedure to save at a specific location using a number of formats. """ # Check if axes is a single axis or list of axes if isinstance(axes, matax.Axes): extent = get_full_extent(axes, pad=pad) figure = axes.figure else: extent_items = [] for ax in axes: extent_items.append(get_full_extent(ax, pad=pad)) figure = axes[0].figure extent = Bbox.union([item for item in extent_items]) save_figure(figure, bbox_inches=extent, save_at=save_at, name=name, save_fmts=save_fmts, **kwargs)
def get_tightbbox(self, renderer, call_axes_locator=True): bbs = [ ax.get_tightbbox(renderer, call_axes_locator) for ax in self.parasites ] bbs.append(super().get_tightbbox(renderer, call_axes_locator)) return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0])
def get_tightbbox(self, renderer, call_axes_locator=True): bb0 = super(Axes, self).get_tightbbox(renderer, call_axes_locator) if not self._axisline_on: return bb0 bb = [bb0] for axisline in self._axislines.values(): if not axisline.get_visible(): continue bb.append(axisline.get_tightbbox(renderer)) # if axisline.label.get_visible(): # bb.append(axisline.label.get_window_extent(renderer)) # if axisline.major_ticklabels.get_visible(): # bb.extend(axisline.major_ticklabels.get_window_extents(renderer)) # if axisline.minor_ticklabels.get_visible(): # bb.extend(axisline.minor_ticklabels.get_window_extents(renderer)) # if axisline.major_ticklabels.get_visible() or \ # axisline.minor_ticklabels.get_visible(): # bb.append(axisline.offsetText.get_window_extent(renderer)) #bb.extend([c.get_window_extent(renderer) for c in artists \ # if c.get_visible()]) _bbox = Bbox.union([b for b in bb if b and (b.width!=0 or b.height!=0)]) return _bbox
def get_tightbbox(self, renderer): if not self.get_visible(): return self._axis_artist_helper.update_lim(self.axes) dpi_cor = renderer.points_to_pixels(1.) self.dpi_transform.clear().scale(dpi_cor, dpi_cor) bb = [] self._update_ticks(renderer) bb.extend(self.major_ticklabels.get_window_extents(renderer)) bb.extend(self.minor_ticklabels.get_window_extents(renderer)) self._update_label(renderer) bb.append(self.label.get_window_extent(renderer)) bb.append(self.offsetText.get_window_extent(renderer)) bb = [b for b in bb if b and (b.width != 0 or b.height != 0)] if bb: _bbox = Bbox.union(bb) return _bbox else: return None
def zoom_nodes(self, nodes, border=1.2): y0, y1 = self.get_ylim(); x0, x1 = self.get_xlim() y0 = max(0, y0); y1 = min(1, y1) n2c = self.n2c v = [ n2c[n] for n in nodes ] ymin = min([ c.y for c in v ]) ymax = max([ c.y for c in v ]) xmin = min([ c.x for c in v ]) xmax = max([ c.x for c in v ]) bb = Bbox(((xmin,ymin), (xmax, ymax))) # convert data coordinates to display coordinates transform = self.transData.transform disp_bb = [Bbox(transform(bb))] disp_bb = Bbox.union(disp_bb).expanded(border, border) # convert back to data coordinates points = self.transData.inverted().transform(disp_bb) x0, x1 = points[:,0] y0, y1 = points[:,1] self.set_xlim(x0, x1) self.set_ylim(y0, y1) self.draw_labels()
def test_text_with_arrow_annotation_get_window_extent(): headwidth = 21 fig, ax = plt.subplots(dpi=100) txt = ax.text(s='test', x=0, y=0) ann = ax.annotate( 'test', xy=(0.0, 50.0), xytext=(50.0, 50.0), xycoords='figure pixels', arrowprops={ 'facecolor': 'black', 'width': 2, 'headwidth': headwidth, 'shrink': 0.0}) plt.draw() renderer = fig.canvas.renderer # bounding box of text text_bbox = txt.get_window_extent(renderer=renderer) # bounding box of annotation (text + arrow) bbox = ann.get_window_extent(renderer=renderer) # bounding box of arrow arrow_bbox = ann.arrow.get_window_extent(renderer) # bounding box of annotation text ann_txt_bbox = Text.get_window_extent(ann) # make sure annotation with in 50 px wider than # just the text eq_(bbox.width, text_bbox.width + 50.0) # make sure the annotation text bounding box is same size # as the bounding box of the same string as a Text object eq_(ann_txt_bbox.height, text_bbox.height) eq_(ann_txt_bbox.width, text_bbox.width) # compute the expected bounding box of arrow + text expected_bbox = Bbox.union([ann_txt_bbox, arrow_bbox]) assert_almost_equal(bbox.height, expected_bbox.height)
def get_tightbbox(self, renderer): bb0 = super(Axes, self).get_tightbbox(renderer) if not self._axisline_on: return bb0 bb = [bb0] for axisline in self._axislines.values(): if not axisline.get_visible(): continue if axisline.label.get_visible(): bb.append(axisline.label.get_window_extent(renderer)) if axisline.major_ticklabels.get_visible(): bb.extend( axisline.major_ticklabels.get_window_extents(renderer)) if axisline.minor_ticklabels.get_visible(): bb.extend( axisline.minor_ticklabels.get_window_extents(renderer)) if axisline.major_ticklabels.get_visible() or \ axisline.minor_ticklabels.get_visible(): bb.append(axisline.offsetText.get_window_extent(renderer)) #bb.extend([c.get_window_extent(renderer) for c in artists \ # if c.get_visible()]) _bbox = Bbox.union([b for b in bb if b.width != 0 or b.height != 0]) return _bbox
def get_tightbbox(self, renderer, call_axes_locator=True): bb0 = super(Axes, self).get_tightbbox(renderer, call_axes_locator) if not self._axisline_on: return bb0 bb = [bb0] for axisline in list(six.itervalues(self._axislines)): if not axisline.get_visible(): continue bb.append(axisline.get_tightbbox(renderer)) # if axisline.label.get_visible(): # bb.append(axisline.label.get_window_extent(renderer)) # if axisline.major_ticklabels.get_visible(): # bb.extend(axisline.major_ticklabels.get_window_extents(renderer)) # if axisline.minor_ticklabels.get_visible(): # bb.extend(axisline.minor_ticklabels.get_window_extents(renderer)) # if axisline.major_ticklabels.get_visible() or \ # axisline.minor_ticklabels.get_visible(): # bb.append(axisline.offsetText.get_window_extent(renderer)) #bb.extend([c.get_window_extent(renderer) for c in artists \ # if c.get_visible()]) _bbox = Bbox.union([b for b in bb if b and (b.width!=0 or b.height!=0)]) return _bbox
def zoom_nodes(self, nodes, border=1.2): y0, y1 = self.get_ylim(); x0, x1 = self.get_xlim() y0 = max(0, y0); y1 = min(1, y1) n2c = self.n2c v = [ n2c[n] for n in nodes ] ymin = min([ c.y for c in v ]) ymax = max([ c.y for c in v ]) xmin = min([ c.x for c in v ]) xmax = max([ c.x for c in v ]) bb = Bbox(((xmin,ymin), (xmax, ymax))) # convert data coordinates to display coordinates transform = self.transData.transform disp_bb = [Bbox(transform(bb))] for n in nodes: if n.isleaf: txt = self.node2label[n] if txt.get_visible(): disp_bb.append(txt.get_window_extent()) disp_bb = Bbox.union(disp_bb).expanded(border, border) # convert back to data coordinates points = self.transData.inverted().transform(disp_bb) x0, x1 = points[:,0] y0, y1 = points[:,1] self.set_xlim(x0, x1) self.set_ylim(y0, y1)
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 get_tightbbox(self, renderer): bbs = [ax.get_tightbbox(renderer) for ax in self.parasites] bbs.append(super(HostAxes, self).get_tightbbox(renderer)) _bbox = Bbox.union([b for b in bbs if b.width!=0 or b.height!=0]) return _bbox
def get_tightbbox(self, renderer, call_axes_locator=True, bbox_extra_artists=None): bbs = [ax.get_tightbbox(renderer, call_axes_locator=call_axes_locator) for ax in self.parasites] bbs.append(super().get_tightbbox(renderer, call_axes_locator=call_axes_locator, bbox_extra_artists=bbox_extra_artists)) return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0])
def adjust_tight_bbox(self, pad=0.1, extra_artists=None): bbox_inches = self.figure.get_tightbbox(self.renderer) bbox_artists = self.figure.get_default_bbox_extra_artists() if extra_artists is None: extra_artists = [] extra_artists.extend([ax.get_legend() for ax in self.figure.axes if ax.get_legend()]) bbox_artists.extend(extra_artists) bbox_filtered = [] for a in bbox_artists: bbox = a.get_window_extent(self.renderer) if a.get_clip_on(): clip_box = a.get_clip_box() if clip_box is not None: bbox = Bbox.intersection(bbox, clip_box) clip_path = a.get_clip_path() if clip_path is not None and bbox is not None: clip_path = clip_path.get_fully_transformed_path() bbox = Bbox.intersection(bbox, clip_path.get_extents()) if bbox is not None and (bbox.width != 0 or bbox.height != 0): bbox_filtered.append(bbox) if bbox_filtered: _bbox = Bbox.union(bbox_filtered) trans = Affine2D().scale(1.0 / self.figure.dpi) bbox_extra = TransformedBbox(_bbox, trans) bbox_inches = Bbox.union([bbox_inches, bbox_extra]) if pad: bbox_inches = bbox_inches.padded(pad) rect = (np.array(bbox_inches.bounds).reshape(-1,2) / self.figure.get_size_inches()).flatten() # Adjust the rect; values <0 to +; + to zero xpad = -np.min((rect[0], (1-rect[2]))) xpad = 0 if xpad < 0 else xpad ypad = -np.min((rect[1], (1-rect[3]))) ypad = 0 if ypad < 0 else ypad rect = np.array([ xpad, ypad, 1-xpad, 1-ypad ]) self.figure.tight_layout(rect=np.abs(rect))
def full_extent(axes, pad=0.0): from matplotlib.transforms import Bbox items = [] for ax in axes: items += [ax] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def _calculate_bbox(self): r = self.renderer bboxes = self.xaxis.get_window_extent(r), self.yaxis.get_window_extent(r), self.subplot.bbox all_bbox = Bbox.union(bboxes) (x0, y0), (x1, y1) = all_bbox.get_points() w = x1 - x0 h = y1 - y0 all_bbox = Bbox.from_bounds(x0, y0, w * 1.02, h * 1.02) return all_bbox
def get_tightbbox(self, renderer, call_axes_locator=True): bb0 = super().get_tightbbox(renderer, call_axes_locator) if not self._axisline_on: return bb0 bb = [bb0] + [axisline.get_tightbbox(renderer) for axisline in self._axislines.values() if axisline.get_visible()] bbox = Bbox.union([b for b in bb if b and (b.width!=0 or b.height!=0)]) return bbox
def get_tightbbox(self, renderer): bbs = [ax.get_tightbbox(renderer) for ax in self.parasites] get_tightbbox = self._get_base_axes_attr("get_tightbbox") bbs.append(get_tightbbox(self, renderer)) _bbox = Bbox.union([b for b in bbs if b.width!=0 or b.height!=0]) return _bbox
def get_tightbbox(self, renderer, call_axes_locator=True, bbox_extra_artists=None): bbs = [ *[ax.get_tightbbox(renderer, call_axes_locator=call_axes_locator) for ax in self.parasites], super().get_tightbbox(renderer, call_axes_locator=call_axes_locator, bbox_extra_artists=bbox_extra_artists)] return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0])
def get_tightbbox(self, renderer): bbs = [ax.get_tightbbox(renderer) for ax in self.parasites] get_tightbbox = self._get_base_axes_attr("get_tightbbox") bbs.append(get_tightbbox(self, renderer)) _bbox = Bbox.union([b for b in bbs if b.width != 0 or b.height != 0]) return _bbox
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 full_extent(ax, pad=0.0): # For text objects, we need to draw the figure first, otherwise the extents # are undefined. ax.figure.canvas.draw() items = ax.get_xticklabels() + ax.get_yticklabels() items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] items += [ax, ax.title] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def _full_extent(ax, items, pad=0.0): """Get the full extent of items in an axis. Adapted from https://stackoverflow.com/a/26432947/1435788 """ # For text objects, we need to draw the figure first, otherwise the extents # are undefined. ax.figure.canvas.draw() bbox = _Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def _get_labels_bbox(self): # Start with computing the union of all label boxes todata = self.ax.transData.inverted() renderer = self.canvas.get_renderer() boxes = [] for label in self.labels: # Update box for new label position label.draw(renderer) boxes.append(label.get_bbox_patch().get_window_extent(renderer).transformed(todata)) bbox = Bbox.union(boxes) return bbox
def full_extent(ax, pad=0.0): """Get the full extent of an axes, including axes labels, tick labels, and titles.""" # For text objects, we need to draw the figure first, otherwise the extents # are undefined. ax.figure.canvas.draw() items = ax.get_xticklabels() + ax.get_yticklabels() # items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] items += [ax, ax.title] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def object_width(self, objects): """Return width in figure coordinates of union of objects. The objects should support the get_window_extent()-method. Intended for use in the context of the on_draw method.""" bboxes = [] for o in objects: bbox = o.get_window_extent(renderer=self.renderer) # get_window_extent() gives pixels, we need figure coordinates: bboxi = bbox.inverse_transformed(self.figure.transFigure) bboxes.append(bboxi) bbox = Bbox.union(bboxes) return bbox.width
def get_tightbbox(self, renderer): if not self.get_visible(): return bb = [b for b in self._bboxes if b and (b.width != 0 or b.height != 0)] if bb: _bbox = Bbox.union(bb) return _bbox else: return self.get_window_extent(renderer)
def full_extent(self, ax, pad=0.0): """Get the full extent of an axes, including axes labels, tick labels, and titles.""" #http://stackoverflow.com/questions/14712665/matplotlib-subplot-background-axes-face-labels-colour-or-figure-axes-coor # For text objects, we need to draw the figure first, otherwise the extents # are undefined. self.pltCanv.draw() items = ax.get_xticklabels() + ax.get_yticklabels() items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] # items += [ax, ax.title] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def full_extent(ax, pad=0.0): """Get the full extent of an axes, including axes labels, tick labels, and titles.""" # for text objects we only include them if they are non empty. # empty ticks may be rendered outside the figure from matplotlib.transforms import Bbox items = [] items += [ax.xaxis.label, ax.yaxis.label, ax.title] items = [item for item in items if item.get_text()] items.append(ax) bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def full_extent(ax, pad=0.0): ''' Get the full extent of an axes, including axes labels, tick labels, and titles. ''' items = ax.get_xticklabels() + ax.get_yticklabels() items += [ax.get_xaxis().get_label(), ax.get_yaxis().get_label()] items += [ax, ax.title] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def full_extent(ax, pad=0.0): """Get the full extent of an axes, including axes labels, tick labels, and titles.""" # For text objects, we need to draw the figure first, otherwise the extents # are undefined. ax.figure.canvas.draw() items = ax.get_xticklabels() + ax.get_yticklabels() # items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] # items += [ax.get_xaxis().get_label(), ax.get_yaxis().get_label()] items += [ax, ax.title] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def full_extent(ax, pad=0.0): """Get the full extent of an axes, including axes labels, tick labels, and titles. Copied from https://stackoverflow.com/a/26432947 """ # For text objects, we need to draw the figure first, otherwise the extents # are undefined. ax.figure.canvas.draw() items = ax.get_xticklabels() + ax.get_yticklabels() items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] bbox = Bbox.union([item.get_window_extent() for item in items]) extent = bbox.expanded(1.0 + pad, 1.0 + pad) return extent.transformed(ax.get_figure().dpi_scale_trans.inverted())
def get_full_extent(self, ax, pad=0.0): """ Get the full extent of axes system `ax`, including axes labels, tick labels and titles. """ #http://stackoverflow.com/questions/14712665/matplotlib-subplot-background-axes-face-labels-colour-or-figure-axes-coor # For text objects, we need to draw the figure first, otherwise the extents # are undefined. self.pltCanv.draw() items = ax.get_xticklabels() + ax.get_yticklabels() items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def make_patches(self): """ Build the patches from all the registered patch builders The advantage is that a single iteration of each dataset is performed, all the patch-builders are invoked on the item during the iteration. Special handling can be done in subclasses at the expense of performance by passing a reduced set of patch_builders to this method. """ # XXX experimental replace start logger.debug("Make patches:\n%s", self._dbg_repr_patch_builders()) for idx, (dataset, builders) in enumerate(self._patch_builders): with ProgressTimer( "Inspect dataset [%d/%d]" % (idx + 1, len(self._patch_builders)), logger): for item in dataset: for b in builders: b.inspect(item) builders = list(chain(*map(itemgetter(1), self._patch_builders))) bboxes = [] for idx, b in enumerate(builders): with ProgressTimer( "Make patches [%d/%d]" % (idx + 1, len(builders)), logger): # grab all the patches from the builders b.get_patches(self.ax) with ProgressTimer( "Fetch plot elements [%d/%d]" % (idx + 1, len(builders)), logger): # grab the viewport from the builders bboxes.append(b.get_bbox()) # grab the legend from the builders self._legend_handles.extend(b.get_legend(self._legend_handles)) # grab the x and y ticks xticks = b.get_xticks() xlabels = b.get_xlabels() yticks = b.get_yticks() ylabels = b.get_ylabels() if xlabels is None: xlabels = repeat(None) if ylabels is None: ylabels = repeat(None) self._xticks.update(zip(xticks, xlabels)) self._yticks.update(zip(yticks, ylabels)) # free the builders as we have no use for them anymore self.clear_patch_builders() self._view_box = Bbox.union(bboxes) logger.debug("Plot viewport %s", self._view_box) logger.debug("Num ticks: x:%d y:%d", len(self._xticks), len(self._yticks)) logger.debug("Legend entries %s", list(map(lambda h: h.get_label(), self._legend_handles)))
def full_extent(ax, pad=0.0): """Get the full extent of an axes, including axes labels, tick labels, and titles. https://stackoverflow.com/questions/4325733/save-a-subplot-in-matplotlib """ # For text objects, we need to draw the figure first, otherwise the extents # are undefined. ax.figure.canvas.draw() items = ax.get_xticklabels() + ax.get_yticklabels() # items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] items += [ax, ax.title] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad)
def get_tightbbox(self, renderer, *args, **kwargs): # FIXME: we should determine what to do with the extra arguments here. # Note that the expected signature of this method is different in # Matplotlib 3.x compared to 2.x. if not self.get_visible(): return bb = [b for b in self._bboxes if b and (b.width != 0 or b.height != 0)] if bb: _bbox = Bbox.union(bb) return _bbox else: return self.get_window_extent(renderer)
def _get_label_offset_transform(self, pad_points, fontprops, renderer, bboxes=None): """ Returns (offset-transform, vertical-alignment, horiz-alignment) of (tick or axis) labels appropriate for the label direction. The offset-transform represents a required pixel offset from the reference point. For example, x-axis center will be the referece point for xlabel. pad_points : padding from axis line or tick labels (see bboxes) fontprops : font properties for label renderer : renderer bboxes=None : list of bboxes (window extents) of the tick labels. This only make sense for axis label. all the above parameters are used to estimate the offset. """ if renderer: pad_pixels = renderer.points_to_pixels(pad_points) font_size_points = fontprops.get_size_in_points() font_size_pixels = renderer.points_to_pixels(font_size_points) else: pad_pixels = pad_points font_size_points = fontprops.get_size_in_points() font_size_pixels = font_size_points if bboxes: bbox = Bbox.union(bboxes) w, h = bbox.width, bbox.height else: w, h = 0, 0 tr = Affine2D() if self.label_direction == "left": tr.translate(-(pad_pixels+w), 0.) return tr, "center", "right" elif self.label_direction == "right": tr.translate(+(pad_pixels+w), 0.) return tr, "center", "left" elif self.label_direction == "bottom": tr.translate(0, -(pad_pixels+font_size_pixels+h)) return tr, "baseline", "center" elif self.label_direction == "top": tr.translate(0, +(pad_pixels+h)) return tr, "baseline", "center" elif self.label_direction == "curved": return tr, "baseline", "center" else: raise ValueError("Unknown label direction : %s" \ % (self.label_direction,))
def _on_draw(event): """Makes room for vertical x-axis tick labels on the plot (if necessary) so that they don't get cut off when the plot is rendered. This function must be connected to matplotlib's draw_event in order to be called. """ # Note: the following code is largely taken from two separate code # postings. The first reference dealt with text labels being cut off when # the plot was rendered, and the second showed how to prevent infinite # recursion when handling a draw event that draws. # (1) http://matplotlib.sourceforge.net/faq/howto_faq.html#automatically- # make-room-for-tick-labels # (2) http://stackoverflow.com/questions/4018860/text-box-in-matplotlib/ # 4056853#4056853 fig = event.canvas.figure for ax in fig.axes: x_tick_labels = ax.get_xticklabels() bboxes = [] for label in x_tick_labels: bbox = label.get_window_extent() # The figure transform goes from relative coords->pixels and we # want the inverse of that. bboxi = bbox.inverse_transformed(fig.transFigure) bboxes.append(bboxi) # This is the bbox that bounds all the bboxes, again in relative # figure coords. bbox = Bbox.union(bboxes) if fig.subplotpars.bottom < bbox.height: # We need to move it up to add some padding for the labels. fig.subplots_adjust(bottom=min(1.2 * bbox.height, fig.subplotpars.top - 0.1)) # Temporarily disconnect any callbacks to the draw event to avoid # recursion. func_handles = fig.canvas.callbacks.callbacks[event.name] fig.canvas.callbacks.callbacks[event.name] = {} # Re-draw the figure and reset the draw event callbacks. fig.canvas.draw() fig.canvas.callbacks.callbacks[event.name] = func_handles return False
def get_tightbbox(self, renderer): """ Return a (tight) bounding box of the figure in inches. It only accounts axes title, axis labels, and axis ticklabels. Needs improvement. """ bb = [] for ax in self.axes: if ax.get_visible(): bb.append(ax.get_tightbbox(renderer)) _bbox = Bbox.union([b for b in bb if b.width!=0 or b.height!=0]) bbox_inches = TransformedBbox(_bbox, Affine2D().scale(1./self.dpi)) return bbox_inches
def get_tightbbox(self, renderer): bb0 = super(Axes, self).get_tightbbox(renderer) if not self._axisline_on: return bb0 bb = [bb0] for axisline in self._axislines.values(): if not axisline.get_visible(): continue if axisline.label.get_visible(): bb.append(axisline.label.get_window_extent(renderer)) if axisline.major_ticklabels.get_visible(): bb.extend(axisline.major_ticklabels.get_window_extents(renderer)) if axisline.minor_ticklabels.get_visible(): bb.extend(axisline.minor_ticklabels.get_window_extents(renderer)) if axisline.major_ticklabels.get_visible() or \ axisline.minor_ticklabels.get_visible(): bb.append(axisline.offsetText.get_window_extent(renderer)) _bbox = Bbox.union([b for b in bb if b.width!=0 or b.height!=0]) return _bbox
def test_plotwidget_three(): if True: raise pytest.skip() x = np.linspace(0, 5, 100) y = x ** 2 - 2 * x + 3 root = tk.Tk() p = RTPlotWidget(root) p.set_data(x, y) p.grid(1, 1) p2 = RTPlotWidget(root) p2.setup() p2.grid(2, 1) p2.set_yaxis(text="Hello World! Yaxis") p2.set_xaxis(text="XAxis") p2.set_title_text("MyTitle") from matplotlib.transforms import Bbox b1 = p2.subplot.title.get_window_extent(p2.renderer) b2 = p2.xlabel.get_window_extent(p2.renderer) bb = Bbox.union((b1, b2)) # p2.figure.subplots_adjust(top=0.65, left=0.25) wave = sin_wave() def add_sin(n=1): for _ in range(n): nonlocal wave p2.add_xy(*next(wave)) root.after(1, add_sin, n) i = 0 for r in range(4): for c in range(3): if r in (1, 2) and c == 1: continue i += 1 l = tk.Label(root, text="TestLabel %d" % i) l.grid(row=r, column=c) root.after(0, add_sin, 5) root.mainloop()
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 as_mpl_artists(shape_list, properties_func=None, text_offset=5.0, origin=1): """ Converts a region list to a list of patches and a list of artists. Optional Keywords: [ text_offset ] - If there is text associated with the regions, add some vertical offset (in pixels) to the text so that it doesn't overlap with the regions. Often, the regions files implicitly assume the lower-left corner of the image as a coordinate (1,1). However, the python convetion is that the array index starts from 0. By default (origin = 1), coordinates of the returned mpl artists have coordinate shifted by (1, 1). If you do not want this shift, set origin=0. """ patch_list = [] artist_list = [] if properties_func is None: properties_func = properties_func_default # properties for continued(? multiline?) regions saved_attrs = None for shape in shape_list: patches = [] if saved_attrs is None: _attrs = [], {} else: _attrs = copy.copy(saved_attrs[0]), copy.copy(saved_attrs[1]) kwargs = properties_func(shape, _attrs) if shape.name == "composite": saved_attrs = shape.attr continue if saved_attrs is None and shape.continued: saved_attrs = shape.attr # elif (shape.name in shape.attr[1]): # if (shape.attr[1][shape.name] != "ignore"): # saved_attrs = shape.attr if not shape.continued: saved_attrs = None # text associated with the shape txt = shape.attr[1].get("text") if shape.name == "polygon": xy = np.array(shape.coord_list) xy.shape = -1, 2 # -1 for change origin to 0,0 patches = [mpatches.Polygon(xy - origin, closed=True, **kwargs)] elif shape.name == "rotbox" or shape.name == "box": xc, yc, w, h, rot = shape.coord_list # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin _box = np.array([[-w / 2., -h / 2.], [-w / 2., h / 2.], [w / 2., h / 2.], [w / 2., -h / 2.]]) box = _box + [xc, yc] rotbox = rotated_polygon(box, xc, yc, rot) patches = [mpatches.Polygon(rotbox, closed=True, **kwargs)] elif shape.name == "ellipse": xc, yc = shape.coord_list[:2] # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin angle = shape.coord_list[-1] maj_list, min_list = shape.coord_list[2:-1:2], shape.coord_list[3:-1:2] patches = [mpatches.Ellipse((xc, yc), 2 * maj, 2 * min, angle=angle, **kwargs) for maj, min in zip(maj_list, min_list)] elif shape.name == "annulus": xc, yc = shape.coord_list[:2] # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin r_list = shape.coord_list[2:] patches = [mpatches.Ellipse((xc, yc), 2 * r, 2 * r, **kwargs) for r in r_list] elif shape.name == "circle": xc, yc, major = shape.coord_list # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin patches = [mpatches.Ellipse((xc, yc), 2 * major, 2 * major, angle=0, **kwargs)] elif shape.name == "panda": xc, yc, a1, a2, an, r1, r2, rn = shape.coord_list # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin patches = [mpatches.Arc((xc, yc), rr * 2, rr * 2, angle=0, theta1=a1, theta2=a2, **kwargs) for rr in np.linspace(r1, r2, rn + 1)] for aa in np.linspace(a1, a2, an + 1): xx = np.array([r1, r2]) * np.cos(aa / 180. * np.pi) + xc yy = np.array([r1, r2]) * np.sin(aa / 180. * np.pi) + yc p = Path(np.transpose([xx, yy])) patches.append(mpatches.PathPatch(p, **kwargs)) elif shape.name == "pie": xc, yc, r1, r2, a1, a2 = shape.coord_list # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin patches = [mpatches.Arc((xc, yc), rr * 2, rr * 2, angle=0, theta1=a1, theta2=a2, **kwargs) for rr in [r1, r2]] for aa in [a1, a2]: xx = np.array([r1, r2]) * np.cos(aa / 180. * np.pi) + xc yy = np.array([r1, r2]) * np.sin(aa / 180. * np.pi) + yc p = Path(np.transpose([xx, yy])) patches.append(mpatches.PathPatch(p, **kwargs)) elif shape.name == "epanda": xc, yc, a1, a2, an, r11, r12, r21, r22, rn, angle = shape.coord_list # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin # mpl takes angle a1, a2 as angle as in circle before # transformation to ellipse. x1, y1 = cos(a1 / 180. * pi), sin(a1 / 180. * pi) * r11 / r12 x2, y2 = cos(a2 / 180. * pi), sin(a2 / 180. * pi) * r11 / r12 a1, a2 = atan2(y1, x1) / pi * 180., atan2(y2, x2) / pi * 180. patches = [mpatches.Arc((xc, yc), rr1 * 2, rr2 * 2, angle=angle, theta1=a1, theta2=a2, **kwargs) for rr1, rr2 in zip(np.linspace(r11, r21, rn + 1), np.linspace(r12, r22, rn + 1))] for aa in np.linspace(a1, a2, an + 1): xx = np.array([r11, r21]) * np.cos(aa / 180. * np.pi) yy = np.array([r11, r21]) * np.sin(aa / 180. * np.pi) p = Path(np.transpose([xx, yy])) tr = Affine2D().scale(1, r12 / r11).rotate_deg(angle).translate(xc, yc) p2 = tr.transform_path(p) patches.append(mpatches.PathPatch(p2, **kwargs)) elif shape.name == "text": xc, yc = shape.coord_list[:2] # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin if txt: _t = _get_text(txt, xc, yc, 0, 0, **kwargs) artist_list.append(_t) elif shape.name == "point": xc, yc = shape.coord_list[:2] # -1 for change origin to 0,0 xc, yc = xc - origin, yc - origin artist_list.append(Line2D([xc], [yc], **kwargs)) if txt: textshape = copy.copy(shape) textshape.name = "text" textkwargs = properties_func(textshape, _attrs) _t = _get_text(txt, xc, yc, 0, text_offset, va="bottom", **textkwargs) artist_list.append(_t) elif shape.name in ["line", "vector"]: if shape.name == "line": x1, y1, x2, y2 = shape.coord_list[:4] # -1 for change origin to 0,0 x1, y1, x2, y2 = x1 - origin, y1 - origin, x2 - origin, y2 - origin a1, a2 = shape.attr[1].get("line", "0 0").strip().split()[:2] arrowstyle = "-" if int(a1): arrowstyle = "<" + arrowstyle if int(a2): arrowstyle = arrowstyle + ">" else: # shape.name == "vector" x1, y1, l, a = shape.coord_list[:4] # -1 for change origin to 0,0 x1, y1 = x1 - origin, y1 - origin x2, y2 = x1 + l * np.cos(a / 180. * np.pi), y1 + l * np.sin(a / 180. * np.pi) v1 = int(shape.attr[1].get("vector", "0").strip()) if v1: arrowstyle = "->" else: arrowstyle = "-" patches = [mpatches.FancyArrowPatch(posA=(x1, y1), posB=(x2, y2), arrowstyle=arrowstyle, arrow_transmuter=None, connectionstyle="arc3", patchA=None, patchB=None, shrinkA=0, shrinkB=0, connector=None, **kwargs)] else: warnings.warn("'as_mpl_artists' does not know how to convert {0} " "to mpl artist".format(shape.name)) patch_list.extend(patches) if txt and patches: # the text associated with a shape uses different # matplotlib keywords than the shape itself for, e.g., # color textshape = copy.copy(shape) textshape.name = "text" textkwargs = properties_func(textshape, _attrs) # calculate the text position _bb = [p.get_window_extent() for p in patches] # this is to work around backward-incompatible change made # in matplotlib 1.2. This change is later reverted so only # some versions are affected. With affected version of # matplotlib, get_window_extent method calls get_transform # method which sets the _transformSet to True, which is # not desired. for p in patches: p._transformSet = False _bbox = Bbox.union(_bb) x0, y0, x1, y1 = _bbox.extents xc = .5 * (x0 + x1) _t = _get_text(txt, xc, y1, 0, text_offset, va="bottom", **textkwargs) artist_list.append(_t) return patch_list, artist_list