def draw_quadmesh(data, obj): '''Returns the PGFPlots code for an graphics environment holding a rendering of the object. ''' content = [] # Generate file name for current object if 'img number' not in data.keys(): data['img number'] = 0 filename = os.path.join( data['output dir'], '%s_img%03d.png' % (data['base name'], data['img number'])) data['img number'] = data['img number'] + 1 # Get the dpi for rendering and store the original dpi of the figure dpi = data['dpi'] fig_dpi = obj.figure.get_dpi() obj.figure.set_dpi(dpi) # Render the object and save as png file from matplotlib.backends.backend_agg import RendererAgg cbox = obj.get_clip_box() width = int(round(cbox.extents[2])) height = int(round(cbox.extents[3])) ren = RendererAgg(width, height, dpi) obj.draw(ren) # Generate a image from the render buffer image = Image.frombuffer('RGBA', ren.get_canvas_width_height(), ren.buffer_rgba(), 'raw', 'RGBA', 0, 1) # Crop the image to the actual content (removing the the regions otherwise # used for axes, etc.) # 'image.crop' expects the crop box to specify the left, upper, right, and # lower pixel. 'cbox.extents' gives the left, lower, right, and upper # pixel. box = (int(round(cbox.extents[0])), 0, int(round(cbox.extents[2])), int(round(cbox.extents[3] - cbox.extents[1]))) cropped = image.crop(box) cropped.save(filename) # Restore the original dpi of the figure obj.figure.set_dpi(fig_dpi) # write the corresponding information to the TikZ file extent = obj.axes.get_xlim() + obj.axes.get_ylim() rel_filepath = os.path.basename(filename) if data['rel data path']: rel_filepath = os.path.join(data['rel data path'], rel_filepath) # Explicitly use \pgfimage as includegrapics command, as the default # \includegraphics fails unexpectedly in some cases content.append('\\addplot graphics [includegraphics cmd=\\pgfimage,' 'xmin=%.15g, xmax=%.15g, ' 'ymin=%.15g, ymax=%.15g] {%s};\n' % (extent + (rel_filepath, ))) return data, content
def draw_quadmesh(data, obj): """Returns the PGFPlots code for an graphics environment holding a rendering of the object. """ content = [] # Generate file name for current object filename, rel_filepath = files.new_filename(data, "img", ".png") # Get the dpi for rendering and store the original dpi of the figure dpi = data["dpi"] fig_dpi = obj.figure.get_dpi() obj.figure.set_dpi(dpi) # Render the object and save as png file from matplotlib.backends.backend_agg import RendererAgg cbox = obj.get_clip_box() width = int(round(cbox.extents[2])) height = int(round(cbox.extents[3])) ren = RendererAgg(width, height, dpi) obj.draw(ren) # Generate a image from the render buffer image = Image.frombuffer( "RGBA", ren.get_canvas_width_height(), ren.buffer_rgba(), "raw", "RGBA", 0, 1 ) # Crop the image to the actual content (removing the the regions otherwise # used for axes, etc.) # 'image.crop' expects the crop box to specify the left, upper, right, and # lower pixel. 'cbox.extents' gives the left, lower, right, and upper # pixel. box = ( int(round(cbox.extents[0])), 0, int(round(cbox.extents[2])), int(round(cbox.extents[3] - cbox.extents[1])), ) cropped = image.crop(box) cropped.save(filename) # Restore the original dpi of the figure obj.figure.set_dpi(fig_dpi) # write the corresponding information to the TikZ file extent = obj.axes.get_xlim() + obj.axes.get_ylim() # Explicitly use \pgfimage as includegrapics command, as the default # \includegraphics fails unexpectedly in some cases ff = data["float format"] content.append( ( "\\addplot graphics [includegraphics cmd=\\pgfimage," "xmin=" + ff + ", xmax=" + ff + ", " "ymin=" + ff + ", ymax=" + ff + "] {{{}}};\n" ).format(*(extent + (rel_filepath,))) ) return data, content
def draw_quadmesh(data, obj): """Returns the PGFPlots code for an graphics environment holding a rendering of the object. """ content = [] # Generate file name for current object filename, rel_filepath = _files.new_filename(data, "img", ".png") # Get the dpi for rendering and store the original dpi of the figure dpi = data["dpi"] fig_dpi = obj.figure.get_dpi() obj.figure.set_dpi(dpi) # Render the object and save as png file from matplotlib.backends.backend_agg import RendererAgg cbox = obj.get_clip_box() width = int(round(cbox.extents[2])) height = int(round(cbox.extents[3])) ren = RendererAgg(width, height, dpi) obj.draw(ren) # Generate a image from the render buffer image = Image.frombuffer( "RGBA", ren.get_canvas_width_height(), ren.buffer_rgba(), "raw", "RGBA", 0, 1 ) # Crop the image to the actual content (removing the the regions otherwise # used for axes, etc.) # 'image.crop' expects the crop box to specify the left, upper, right, and # lower pixel. 'cbox.extents' gives the left, lower, right, and upper # pixel. box = ( int(round(cbox.extents[0])), 0, int(round(cbox.extents[2])), int(round(cbox.extents[3] - cbox.extents[1])), ) cropped = image.crop(box) cropped.save(filename) # Restore the original dpi of the figure obj.figure.set_dpi(fig_dpi) # write the corresponding information to the TikZ file extent = obj.axes.get_xlim() + obj.axes.get_ylim() # Explicitly use \pgfimage as includegrapics command, as the default # \includegraphics fails unexpectedly in some cases ff = data["float format"] content.append( "\\addplot graphics [includegraphics cmd=\\pgfimage," f"xmin={extent[0]:{ff}}, xmax={extent[1]:{ff}}, " f"ymin={extent[2]:{ff}}, ymax={extent[3]:{ff}}] {{{rel_filepath}}};\n" ) return data, content
def render(self): w, h = self.shape r = RendererAgg(w, h, 72) arr = np.frombuffer(r.buffer_rgba(), np.uint8) arr.shape = r.height, r.width, -1 for stroke in self.strokes: stroke.render(r) image_raw = np.float32(arr, dtype=np.float32) / 255 return rgba_to_rgb(image_raw)
def render(self): """ Renders the image from the set of strokes and returns an RGB image with dimensions self.shape. """ w, h = self.shape r = RendererAgg(w, h, 72) arr = np.frombuffer(r.buffer_rgba(), np.uint8) arr.shape = r.height, r.width, -1 for stroke in self.strokes: stroke.render(r) image_raw = np.float32(arr, dtype=np.float32) / 255 return rgba_to_rgb(image_raw)
class PNG(EPS): def write_header(self): from matplotlib.backends.backend_agg import RendererAgg dpi = 72 self.renderer = RendererAgg(self.w, self.h, dpi) def write_trailer(self): # The array conversion magic is necessary to make things work with # matplotlib 2.0.0, 3.2.x, and 3.3.0 at the same time. import matplotlib.image buf = self.renderer.buffer_rgba() # Buf is of type bytes (matplotlib < 3.3.0) or memoryview. # That might be an implementation detail. array = np.frombuffer(buf, dtype=np.uint8).reshape( int(self.h), int(self.w), 4) matplotlib.image.imsave( self.filename, array, format="png")
class ImageMaskDrawer(HasTraits): mask_updated = Event drawed = Event is_dirty = Bool(False) def __init__(self, ax, img=None, mask_shape=None, canmove=True, size=None): self.canmove = canmove self.ax = ax if size is None: size = 10 self.bbox = mtrans.Bbox(np.array([[0, 0], [10, 10]])) bbox = mtrans.TransformedBbox(self.bbox, ax.transData) self.mask_img = mimage.BboxImage(bbox, animated=True, alpha=0.6, zorder=1000) self.ax.add_artist(self.mask_img) self.create_mask(img, mask_shape) self.canvas = ax.figure.canvas self.event_ids = [ self.canvas.mpl_connect('motion_notify_event', self.on_move), self.canvas.mpl_connect('draw_event', self.on_draw), self.canvas.mpl_connect('button_press_event', self.on_press), self.canvas.mpl_connect('button_release_event', self.on_release), self.canvas.mpl_connect('scroll_event', self.on_scroll), ] self.circle = mpatches.Circle((0, 0), size, facecolor="red", alpha=0.5, animated=True) self.ax.add_patch(self.circle) self.mask_circle = mpatches.Circle((0, 0), 10, facecolor="white", lw=0) self.mask_line = plt.Line2D((0, 0), (0, 0), lw=18, solid_capstyle="round", color="white") self.background = None self.last_pos = None self.timer = Timer(40, self.check_dirty) def remove(self): self.mask_img.remove() self.circle.remove() for event_id in self.event_ids: self.canvas.mpl_disconnect(event_id) def check_dirty(self): if self.is_dirty: self._update() self.is_dirty = False def create_mask(self, img=None, mask_shape=None): if mask_shape is None: self.height, self.width = img.shape[:2] else: self.height, self.width = mask_shape self.renderer = RendererAgg(self.width, self.height, 90) buf = self.renderer.buffer_rgba() arr = np.frombuffer(buf, np.uint8) self.array = arr.reshape(self.height, self.width, 4) self.mask_img.set_data(self.array) self.bbox.set_points(np.array([[0, 0], [self.width, self.height]])) def clear_mask(self): self.array[:, :, :-1] = 255 self.array[:, :, -1] = 0 def get_mask_array(self): return self.array[:, :, -1].copy() def get_mask_offset(self): box = self.mask_img.bbox._bbox return box.x0, box.y0 def on_scroll(self, event): radius = self.circle.get_radius() radius += event.step radius = max(3, min(30, radius)) self.circle.set_radius(radius) self.mask_circle.set_radius(radius) self.mask_line.set_linewidth(radius * 2 - 2) self._update() def transform_pos(self, x, y): box = self.mask_img.bbox._bbox return x - box.x0, y - box.y0 def on_press(self, event): buttons = (1, 3) if self.canmove else (1, ) if event.button in buttons and event.inaxes is self.ax: self.mask_img.set_visible(True) self.img_pos = self.mask_img.bbox._bbox.get_points() self.last_pos = self.transform_pos(event.xdata, event.ydata) self.last_pos2 = event.xdata, event.ydata self.mask_circle.center = self.last_pos if event.button == 1: self.mask_circle.draw(self.renderer) self.mask_updated = True self.mask_img.set_array(self.array) self.is_dirty = True def on_release(self, event): self.last_pos = None if event.button == 1 and event.inaxes is self.ax: self.drawed = True def on_draw(self, event): self.background = self.canvas.copy_from_bbox(self.ax.bbox) self.mask_img.set_array(self.array) self.ax.draw_artist(self.mask_img) if self.circle.get_visible(): self.ax.draw_artist(self.circle) self.canvas.blit(self.ax.bbox) def on_move(self, event): self.is_dirty = True if event.inaxes != self.ax: self.circle.set_visible(False) return self.circle.set_visible(True) self.circle.center = event.xdata, event.ydata if event.button == 1 and self.last_pos is not None: pos = self.transform_pos(event.xdata, event.ydata) self.mask_line.set_data((self.last_pos[0], pos[0]), (self.last_pos[1], pos[1])) self.mask_line.draw(self.renderer) self.last_pos = pos self.mask_updated = True if self.canmove and event.button == 3 and self.last_pos is not None: xdata, ydata = event.xdata, event.ydata dx = self.last_pos2[0] - xdata dy = self.last_pos2[1] - ydata new_pos = self.img_pos - [dx, dy] self.mask_img.bbox._bbox.set_points(new_pos) self.mask_img.bbox.invalidate() def _update(self): if self.background is not None: self.canvas.restore_region(self.background) self.mask_img.set_array(self.array) self.ax.draw_artist(self.mask_img) if self.circle.get_visible(): self.ax.draw_artist(self.circle) self.canvas.blit(self.ax.bbox) def update(self): # self.mask_img.set_array(self.array) self._update() def hide_mask(self): self.mask_img.set_visible(False) def show_mask(self): self.mask_img.set_visible(True)
class ImageMaskDrawer(HasTraits): mask_updated = Event drawed = Event def __init__(self, ax, img=None, mask_shape=None, canmove=True, size=None): self.canmove = canmove self.ax = ax if size is None: size = 10 self.bbox = mtrans.Bbox(np.array([[0, 0], [10, 10]])) bbox = mtrans.TransformedBbox(self.bbox, ax.transData) self.mask_img = mimage.BboxImage(bbox, animated=True, alpha=0.6, zorder=1000) self.ax.add_artist(self.mask_img) self.create_mask(img, mask_shape) self.canvas = ax.figure.canvas self.canvas.mpl_connect('motion_notify_event', self.on_move) self.canvas.mpl_connect('draw_event', self.on_draw) self.canvas.mpl_connect('button_press_event', self.on_press) self.canvas.mpl_connect('button_release_event', self.on_release) self.canvas.mpl_connect('scroll_event', self.on_scroll) self.circle = mpatches.Circle((0, 0), size, facecolor="red", alpha=0.5, animated=True) self.ax.add_patch(self.circle) self.mask_circle = mpatches.Circle((0, 0), 10, facecolor="white", lw=0) self.mask_line = plt.Line2D((0, 0), (0, 0), lw=18, solid_capstyle="round", color="white") self.background = None self.last_pos = None def create_mask(self, img=None, mask_shape=None): if mask_shape is None: self.height, self.width = img.shape[:2] else: self.height, self.width = mask_shape self.renderer = RendererAgg(self.width, self.height, 90) buf = self.renderer.buffer_rgba() arr = np.frombuffer(buf, np.uint8) self.array = arr.reshape(self.height, self.width, 4) self.mask_img.set_data(self.array) self.bbox.set_points(np.array([[0, 0], [self.width, self.height]])) def clear_mask(self): self.array[:, :, :-1] = 255 self.array[:, :, -1] = 0 def get_mask_array(self): return self.array[:, :, -1].copy() def get_mask_offset(self): box = self.mask_img.bbox._bbox return box.x0, box.y0 def on_scroll(self, event): radius = self.circle.get_radius() radius += event.step radius = max(3, min(30, radius)) self.circle.set_radius(radius) self.mask_circle.set_radius(radius) self.mask_line.set_linewidth(radius*2 - 2) self._update() def transform_pos(self, x, y): box = self.mask_img.bbox._bbox return x - box.x0, y - box.y0 def on_press(self, event): buttons = (1, 3) if self.canmove else (1, ) if event.button in buttons and event.inaxes is self.ax: self.mask_img.set_visible(True) self.mask_img.set_animated(True) self.canvas.draw() self.img_pos = self.mask_img.bbox._bbox.get_points() self.last_pos = self.transform_pos(event.xdata, event.ydata) self.last_pos2 = event.xdata, event.ydata self.mask_circle.center = self.last_pos if event.button == 1: self.mask_circle.draw(self.renderer) self.mask_updated = True self.mask_img.set_array(self.array) self._update() def on_release(self, event): self.mask_img.set_animated(False) self.last_pos = None self.canvas.draw() if event.button == 1 and event.inaxes is self.ax: self.drawed = True def on_draw(self, event): self.background = self.canvas.copy_from_bbox(self.ax.bbox) def on_move(self, event): if event.inaxes != self.ax: self.circle.set_visible(False) return self.circle.set_visible(True) self.circle.center = event.xdata, event.ydata if event.button == 1 and self.last_pos is not None: pos = self.transform_pos(event.xdata, event.ydata) self.mask_line.set_data((self.last_pos[0], pos[0]), (self.last_pos[1], pos[1])) self.mask_line.draw(self.renderer) self.last_pos = pos self.mask_img.set_array(self.array) self.mask_updated = True if self.canmove and event.button == 3 and self.last_pos is not None: xdata, ydata = event.xdata, event.ydata dx = self.last_pos2[0] - xdata dy = self.last_pos2[1] - ydata new_pos = self.img_pos - [dx, dy] self.mask_img.bbox._bbox.set_points(new_pos) self.mask_img.bbox.invalidate() self._update() def _update(self): if self.background is not None: self.canvas.restore_region(self.background) if self.mask_img.get_animated(): self.ax.draw_artist(self.mask_img) self.ax.draw_artist(self.circle) self.canvas.blit(self.ax.bbox) def update(self): self.mask_img.set_array(self.array) self._update() def hide_mask(self): self.mask_img.set_visible(False) def show_mask(self): self.mask_img.set_visible(True)
def draw_quadmesh(data, obj): '''Returns the PGFPlots code for an graphics environment holding a rendering of the object. ''' content = [] # Generate file name for current object if 'img number' not in data.keys(): data['img number'] = 0 filename = os.path.join(data['output dir'], '%s_img%03d.png' % (data['base name'], data['img number']) ) data['img number'] = data['img number'] + 1 # Get the dpi for rendering and store the original dpi of the figure dpi = data['dpi'] fig_dpi = obj.figure.get_dpi() obj.figure.set_dpi(dpi) # Render the object and save as png file from matplotlib.backends.backend_agg import RendererAgg cbox = obj.get_clip_box() width = int(round(cbox.extents[2])) height = int(round(cbox.extents[3])) ren = RendererAgg(width, height, dpi) obj.draw(ren) # Generate a image from the render buffer image = Image.frombuffer('RGBA', ren.get_canvas_width_height(), ren.buffer_rgba(), 'raw', 'RGBA', 0, 1) # Crop the image to the actual content (removing the the regions otherwise # used for axes, etc.) # 'image.crop' expects the crop box to specify the left, upper, right, and # lower pixel. 'cbox.extents' gives the left, lower, right, and upper # pixel. box = (int(round(cbox.extents[0])), 0, int(round(cbox.extents[2])), int(round(cbox.extents[3] - cbox.extents[1]))) cropped = image.crop(box) cropped.save(filename) # Restore the original dpi of the figure obj.figure.set_dpi(fig_dpi) # write the corresponding information to the TikZ file extent = obj.axes.get_xlim() + obj.axes.get_ylim() if data['rel data path']: rel_filepath = os.path.join(data['rel data path'], os.path.basename(filename) ) else: rel_filepath = os.path.basename(filename) # Explicitly use \pgfimage as includegrapics command, as the default # \includegraphics fails unexpectedly in some cases content.append('\\addplot graphics [includegraphics cmd=\pgfimage,' 'xmin=%.15g, xmax=%.15g, ' 'ymin=%.15g, ymax=%.15g] {%s};\n' % (extent + (rel_filepath,)) ) return data, content