def make_png(self, tex, fontsize, dpi, force=0): if debug: force = True basefile = self.get_basefile(tex, fontsize, dpi) pngfile = '%s.png'% basefile # see get_rgba for a discussion of the background if force or not os.path.exists(pngfile): dvifile = self.make_dvi(tex, fontsize) outfile = basefile+'.output' command = self.get_shell_cmd('cd "%s"' % self.texcache, 'dvipng -bg Transparent -D %s -T tight -o \ "%s" "%s" > "%s"'%(dpi, os.path.split(pngfile)[-1], os.path.split(dvifile)[-1], outfile)) verbose.report(command, 'debug') exit_status = os.system(command) fh = file(outfile) if exit_status: raise RuntimeError('dvipng was not able to \ process the flowing file:\n%s\nHere is the full report generated by dvipng: \ \n\n'% dvifile + fh.read()) else: verbose.report(fh.read(), 'debug') fh.close() os.remove(outfile) return pngfile
def make_dvi(self, tex, fontsize, force=0): if debug: force = True basefile = self.get_basefile(tex, fontsize) dvifile = '%s.dvi'% basefile if force or not os.path.exists(dvifile): texfile = self.make_tex(tex, fontsize) outfile = basefile+'.output' command = self.get_shell_cmd('cd "%s"'% self.texcache, 'latex -interaction=nonstopmode %s > "%s"'\ %(os.path.split(texfile)[-1], outfile)) verbose.report(command, 'debug') exit_status = os.system(command) fh = file(outfile) if exit_status: raise RuntimeError('LaTeX was not able to process the flowing \ string:\n%s\nHere is the full report generated by LaTeX: \n\n'% tex + fh.read()) else: verbose.report(fh.read(), 'debug') fh.close() for fname in glob.glob(basefile+'*'): if fname.endswith('dvi'): pass elif fname.endswith('tex'): pass else: os.remove(fname) return dvifile
def make_ps(self, tex, fontsize, force=0): if debug: force = True basefile = self.get_basefile(tex, fontsize) psfile = '%s.epsf'% basefile if force or not os.path.exists(psfile): dvifile = self.make_dvi(tex, fontsize) outfile = basefile+'.output' command = self.get_shell_cmd('cd "%s"'% self.texcache, 'dvips -q -E -o "%s" "%s" > "%s"'\ %(os.path.split(psfile)[-1], os.path.split(dvifile)[-1], outfile)) verbose.report(command, 'debug') exit_status = os.system(command) fh = file(outfile) if exit_status: raise RuntimeError('dvipng was not able to \ process the flowing file:\n%s\nHere is the full report generated by dvipng: \ \n\n'% dvifile + fh.read()) else: verbose.report(fh.read(), 'debug') fh.close() os.remove(outfile) return psfile
def __init__(self, width, height, dpi): if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying') self.dpi = dpi self.width = width self.height = height self._renderer = _RendererAgg(int(width), int(height), dpi.get(), debug=False) self.draw_polygon = self._renderer.draw_polygon self.draw_rectangle = self._renderer.draw_rectangle self.draw_path = self._renderer.draw_path self.draw_lines = self._renderer.draw_lines self.draw_markers = self._renderer.draw_markers self.draw_image = self._renderer.draw_image self.draw_line_collection = self._renderer.draw_line_collection self.draw_quad_mesh = self._renderer.draw_quad_mesh self.draw_poly_collection = self._renderer.draw_poly_collection self.draw_regpoly_collection = self._renderer.draw_regpoly_collection self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region self.texmanager = TexManager() self.bbox = lbwh_to_bbox(0,0, self.width, self.height)
def fetch_historical_yahoo(ticker, date1, date2, cachename=None): """ Fetch historical data for ticker between date1 and date2. date1 and date2 are datetime instances Ex: fh = fetch_historical_yahoo('^GSPC', d1, d2) cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) a file handle is returned """ ticker = ticker.upper() d1 = (date1.month-1, date1.day, date1.year) d2 = (date2.month-1, date2.day, date2.year) urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=d&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker) if cachename is None: cachename = os.path.join(cachedir, md5(url).hexdigest()) if os.path.exists(cachename): fh = file(cachename) verbose.report('Using cachefile %s for %s'%(cachename, ticker)) else: if not os.path.isdir(cachedir): os.mkdir(cachedir) urlfh = urlopen(url) fh = file(cachename, 'w') fh.write(urlfh.read()) fh.close() verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) fh = file(cachename, 'r') return fh
def _get_agg_font(self, prop): """ Get the font for text instance t, cacheing for efficiency """ if __debug__: verbose.report('RendererAgg._get_agg_font', 'debug-annoying') key = hash(prop) font = RendererAgg._fontd.get(key) if font is None: fname = findfont(prop) font = RendererAgg._fontd.get(fname) if font is None: font = FT2Font( fname, hinting_factor=rcParams['text.hinting_factor']) RendererAgg._fontd[fname] = font RendererAgg._fontd[key] = font font.clear() size = prop.get_size_in_points() font.set_size(size, self.dpi) return font
def draw(self): """ Draw the figure using the renderer """ if __debug__: verbose.report('FigureCanvasAgg.draw', 'debug-annoying') self.renderer = self.get_renderer() self.figure.draw(self.renderer)
def quotes_historical_yahoo(ticker, date1, date2, asobject=False, adjusted=True): """ Get historical data for ticker between date1 and date2. date1 and date2 are datetime instances results are a list of tuples (d, open, close, high, low, volume) where d is a floating poing representation of date, as returned by date2num if asobject is True, the return val is an object with attrs date, open, close, high, low, volume, which are equal length arrays if adjust=True, use adjusted prices Ex: sp = f.quotes_historical_yahoo('^GSPC', d1, d2, asobject=True, adjusted=True) returns = (sp.open[1:] - sp.open[:-1])/sp.open[1:] [n,bins,patches] = hist(returns, 100) mu = mean(returns) sigma = std(returns) x = normpdf(bins, mu, sigma) plot(bins, x, color='red', lw=2) """ d1 = (date1.month-1, date1.day, date1.year) d2 = (date2.month-1, date2.day, date2.year) urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=d&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker) cachename = os.path.join(cachedir, md5.md5(url).hexdigest()) if os.path.exists(cachename): fh = file(cachename) verbose.report('Using cachefile %s for %s'%(cachename, ticker)) else: if not os.path.isdir(cachedir): os.mkdir(cachedir) fh = file(cachename, 'w') fh.write(urlopen(url).read()) fh.close() verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) fh = file(cachename, 'r') ticker = ticker.upper() try: ret = parse_yahoo_historical(fh, asobject, adjusted) except IOError, exc: warnings.warn('urlopen() failure\n' + url + '\n' + exc.strerror[1]) return None
def draw_text(self, gc, x, y, s, prop, angle, ismath): """ Render the text """ if __debug__: verbose.report("RendererAgg.draw_text", "debug-annoying") if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle) flags = self._get_hinting_flag() font = self._get_agg_font(prop) if font is None: return None if len(s) == 1 and ord(s) > 127: font.load_char(ord(s), flags=flags) else: # We pass '0' for angle here, since it will be rotated (in raster # space) in the following call to draw_text_image). font.set_text(s, 0, flags=flags) font.draw_glyphs_to_bitmap() # print x, y, int(x), int(y), s self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc)
def cleanup(self): 'Clean-up and collect the process used to write the movie file.' out, err = self._proc.communicate() verbose.report('MovieWriter -- Command stdout:\n%s' % out, level='debug') verbose.report('MovieWriter -- Command stderr:\n%s' % err, level='debug')
def points_to_pixels(self, points): """ convert point measures to pixes using dpi and the pixels per inch of the display """ if __debug__: verbose.report('RendererAgg.points_to_pixels', 'debug-annoying') return points*self.dpi.get()/72.0
def draw_image(self, x, y, im, bbox): filename = os.path.join (tempfile.gettempdir(), tempfile.gettempprefix() + '.png' ) verbose.report ('Writing image file for include: %s' % filename) # im.write_png() accepts a filename, not file object, would be # good to avoid using files and write to mem with StringIO # JDH: it *would* be good, but I don't know how to do this # since libpng seems to want a FILE* and StringIO doesn't seem # to provide one. I suspect there is a way, but I don't know # it im.flipud_out() h,w = im.get_size_out() y = self.height-y-h im.write_png(filename) imfile = file (filename, 'r') image64 = base64.b64encode (imfile.read()) imfile.close() os.remove(filename) lines = [image64[i:i+76] for i in range(0, len(image64), 76)] self._svgwriter.write ( '<image x="%f" y="%f" width="%f" height="%f" ' 'xlink:href="data:image/png;base64,\n%s" />\n' % (x, y, w+1, h+1, '\n'.join(lines)) ) # unflip im.flipud_out()
def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None): """ Use ghostscript's pswrite or epswrite device to distill a file. This yields smaller files without illegal encapsulated postscript operators. The output is low-level, converting text to outlines. """ paper = '-sPAPERSIZE=%s'% ptype psfile = tmpfile + '.ps' outfile = tmpfile + '.output' dpi = rcParams['ps.distiller.res'] if sys.platform == 'win32': gs_exe = 'gswin32c' else: gs_exe = 'gs' command = '%s -dBATCH -dNOPAUSE -r%d -sDEVICE=pswrite %s -sOutputFile="%s" \ "%s" > "%s"'% (gs_exe, dpi, paper, psfile, tmpfile, outfile) verbose.report(command, 'debug') exit_status = os.system(command) fh = file(outfile) if exit_status: raise RuntimeError('ghostscript was not able to process \ your image.\nHere is the full report generated by ghostscript:\n\n' + fh.read()) else: verbose.report(fh.read(), 'debug') fh.close() os.remove(outfile) os.remove(tmpfile) shutil.move(psfile, tmpfile) if eps: pstoeps(tmpfile, bbox)
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): """ Render the text """ if __debug__: verbose.report('RendererAgg.draw_text', 'debug-annoying') if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle) flags = get_hinting_flag() font = self._get_agg_font(prop) if font is None: return None if len(s) == 1 and ord(s) > 127: font.load_char(ord(s), flags=flags) else: # We pass '0' for angle here, since it will be rotated (in raster # space) in the following call to draw_text_image). font.set_text(s, 0, flags=flags) font.draw_glyphs_to_bitmap(antialiased=rcParams['text.antialiased']) d = font.get_descent() / 64.0 # The descent needs to be adjusted for the angle xo, yo = font.get_bitmap_offset() xo /= 64.0 yo /= 64.0 xd = -d * np.sin(np.deg2rad(angle)) yd = d * np.cos(np.deg2rad(angle)) #print x, y, int(x), int(y), s self._renderer.draw_text_image( font, np.round(x - xd + xo), np.round(y + yd + yo) + 1, angle, gc)
def set_linestyle(self, linestyle): """ Set the linestyle of the line 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. ACCEPTS: [ '-' | '--' | '-.' | ':' | 'None' | ' ' | '' ] and any drawstyle in combination with a linestyle, e.g. 'steps--'. """ # handle long drawstyle names before short ones ! for ds in flatten([k.keys() for k in (self._drawStyles_l, self._drawStyles_s)], is_string_like): if linestyle.startswith(ds): self.set_drawstyle(ds) if len(linestyle) > len(ds): linestyle = linestyle[len(ds):] else: linestyle = '-' if linestyle not in self._lineStyles: if linestyle in ls_mapper: linestyle = ls_mapper[linestyle] else: verbose.report('Unrecognized line style %s, %s' % (linestyle, type(linestyle))) if linestyle in [' ','']: linestyle = 'None' self._linestyle = linestyle
def _fetch_historical_yahoo(self, ticker, date1, date2, freq=None, cachename=None): """matplotlib's implementation, modified to provide proxy support and frequency Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. Ex: fh = fetch_historical_yahoo('^GSPC', (2000, 1, 1), (2001, 12, 31)) cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) a file handle is returned """ if freq is None or type(freq) != str: raise ValueError('Must enter a frequency as a string, m, w, or d') proxy = self._proxy ticker = ticker.upper() configdir = get_configdir() cachedir = os.path.join(configdir, 'finance.cache') if iterable(date1): d1 = (date1[1]-1, date1[2], date1[0]) else: d1 = (date1.month-1, date1.day, date1.year) if iterable(date2): d2 = (date2[1]-1, date2[2], date2[0]) else: d2 = (date2.month-1, date2.day, date2.year) urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker, freq) if proxy: proxy_support = urllib2.ProxyHandler(proxy) opener = urllib2.build_opener(proxy_support) urllib2.install_opener(opener) if cachename is None: cachename = os.path.join(cachedir, md5(url).hexdigest()) if os.path.exists(cachename): fh = file(cachename) verbose.report('Using cachefile %s for %s'%(cachename, ticker)) else: if not os.path.isdir(cachedir): os.mkdir(cachedir) urlfh = urllib2.urlopen(url) fh = file(cachename, 'w') fh.write(urlfh.read()) fh.close() verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) fh = file(cachename, 'r') return fh
def cleanup(self): MovieWriter.cleanup(self) # Delete temporary files if self.clear_temp: verbose.report("MovieWriter: clearing temporary fnames=%s" % str(self._temp_names), level="debug") for fname in self._temp_names: os.remove(fname)
def _draw_image(self, x, y, im): """ Draw the Image instance into the current axes; x, y is the upper left hand corner of the image """ if __debug__: verbose.report('RendererAgg.draw_image', 'debug-annoying') #self._renderer.draw_image(int(x), int(self.height-y), im) self._renderer.draw_image(int(x), int(y), im)
def draw_point(self, gc, x, y): """ Draw a single point at x,y """ if __debug__: verbose.report('RendererAgg.draw_point', 'debug-annoying') rgbFace = gc.get_rgb() self._renderer.draw_ellipse( gc, rgbFace, x, y, 0.5, 0.5)
def __init__(self, canvas, num): if _debug: print("FigureManagerGTK.%s" % fn_name()) FigureManagerBase.__init__(self, canvas, num) self.window = gtk.Window() self.window.set_title("Figure %d" % num) if window_icon: try: self.window.set_icon_from_file(window_icon) except: # some versions of gtk throw a glib.GError but not # all, so I am not sure how to catch it. I am unhappy # diong a blanket catch here, but an not sure what a # better way is - JDH verbose.report("Could not load matplotlib icon: %s" % sys.exc_info()[1]) self.vbox = gtk.VBox() self.window.add(self.vbox) self.vbox.show() self.canvas.show() # attach a show method to the figure for pylab ease of use self.canvas.figure.show = lambda *args: self.window.show() self.vbox.pack_start(self.canvas, True, True) self.toolbar = self._get_toolbar(canvas) # calculate size for window w = int(self.canvas.figure.bbox.width) h = int(self.canvas.figure.bbox.height) if self.toolbar is not None: self.toolbar.show() self.vbox.pack_end(self.toolbar, False, False) tb_w, tb_h = self.toolbar.size_request() h += tb_h self.window.set_default_size(w, h) def destroy(*args): Gcf.destroy(num) self.window.connect("destroy", destroy) self.window.connect("delete_event", destroy) if matplotlib.is_interactive(): self.window.show() def notify_axes_change(fig): "this will be called whenever the current axes is changed" if self.toolbar is not None: self.toolbar.update() self.canvas.figure.add_axobserver(notify_axes_change) self.canvas.grab_focus()
def set_marker(self, marker): """ Set the line marker ========== ========================== marker description ========== ========================== '.' point ',' pixel 'o' circle 'v' triangle_down '^' triangle_up '<' triangle_left '>' triangle_right '1' tri_down '2' tri_up '3' tri_left '4' tri_right 's' square 'p' pentagon '*' star 'h' hexagon1 'H' hexagon2 '+' plus 'x' x 'D' diamond 'd' thin_diamond '|' vline '_' hline TICKLEFT tickleft TICKRIGHT tickright TICKUP tickup TICKDOWN tickdown CARETLEFT caretleft CARETRIGHT caretright CARETUP caretup CARETDOWN caretdown 'None' nothing ' ' nothing '' nothing ========== ========================== ACCEPTS: [ '+' | '*' | ',' | '.' | '1' | '2' | '3' | '4' | '<' | '>' | 'D' | 'H' | '^' | '_' | 'd' | 'h' | 'o' | 'p' | 's' | 'v' | 'x' | '|' | TICKUP | TICKDOWN | TICKLEFT | TICKRIGHT | 'None' | ' ' | '' ] """ if marker not in self._markers: verbose.report('Unrecognized marker style %s, %s' % (marker, type(marker))) if marker in [' ','']: marker = 'None' self._marker = marker self._markerFunc = self._markers[marker]
def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble, paperWidth, paperHeight, orientation): """ When we want to use the LaTeX backend with postscript, we write PSFrag tags to a temporary postscript file, each one marking a position for LaTeX to render some text. convert_psfrags generates a LaTeX document containing the commands to convert those tags to text. LaTeX/dvips produces the postscript file that includes the actual text. """ tmpdir = os.path.split(tmpfile)[0] epsfile = tmpfile+'.eps' shutil.move(tmpfile, epsfile) latexfile = tmpfile+'.tex' outfile = tmpfile+'.output' latexh = file(latexfile, 'w') dvifile = tmpfile+'.dvi' psfile = tmpfile+'.ps' if orientation=='landscape': angle = 90 else: angle = 0 if rcParams['text.latex.unicode']: unicode_preamble = """\usepackage{ucs} \usepackage[utf8x]{inputenc}""" else: unicode_preamble = '' s = r"""\documentclass{article} %s %s %s \usepackage[dvips, papersize={%sin,%sin}, body={%sin,%sin}, margin={0in,0in}]{geometry} \usepackage{psfrag} \usepackage[dvips]{graphicx} \usepackage{color} \pagestyle{empty} \begin{document} \begin{figure} \centering \leavevmode %s \includegraphics*[angle=%s]{%s} \end{figure} \end{document} """% (font_preamble, unicode_preamble, custom_preamble, paperWidth, paperHeight, paperWidth, paperHeight, '\n'.join(psfrags), angle, os.path.split(epsfile)[-1]) if rcParams['text.latex.unicode']: latexh.write(s.encode('utf8')) else: try: latexh.write(s) except UnicodeEncodeError, err: verbose.report("You are using unicode and latex, but have " "not enabled the matplotlib 'text.latex.unicode' " "rcParam.", 'helpful') raise
def get_dvipng_version(): stdin, stdout = os.popen4('dvipng --version') for line in stdout: if line.startswith('dvipng '): version = line.split()[-1] verbose.report('Found dvipng version %s'% version, 'helpful') return version raise RuntimeError('Could not obtain dvipng version')
def draw_line(self, gc, x1, y1, x2, y2): """ x and y are equal length arrays, draw lines connecting each point in x, y """ if __debug__: verbose.report('RendererAgg.draw_line', 'debug-annoying') x = array([x1,x2], typecode=Float) y = array([y1,y2], typecode=Float) self._renderer.draw_lines(gc, x, y)
def __init__(self, canvas, num): if _debug: print 'FigureManagerGTK3.%s' % fn_name() FigureManagerBase.__init__(self, canvas, num) self.window = Gtk.Window() self.set_window_title("Figure %d" % num) try: self.window.set_icon_from_file(window_icon) except (SystemExit, KeyboardInterrupt): # re-raise exit type Exceptions raise except: # some versions of gtk throw a glib.GError but not # all, so I am not sure how to catch it. I am unhappy # doing a blanket catch here, but am not sure what a # better way is - JDH verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1]) self.vbox = Gtk.Box() self.vbox.set_property("orientation", Gtk.Orientation.VERTICAL) self.window.add(self.vbox) self.vbox.show() self.canvas.show() # attach a show method to the figure for pylab ease of use self.canvas.figure.show = lambda *args: self.window.show() self.vbox.pack_start(self.canvas, True, True, 0) self.toolbar = self._get_toolbar(canvas) # calculate size for window w = int (self.canvas.figure.bbox.width) h = int (self.canvas.figure.bbox.height) if self.toolbar is not None: self.toolbar.show() self.vbox.pack_end(self.toolbar, False, False, 0) size_request = self.toolbar.size_request() h += size_request.height self.window.set_default_size (w, h) def destroy(*args): Gcf.destroy(num) self.window.connect("destroy", destroy) self.window.connect("delete_event", destroy) if matplotlib.is_interactive(): self.window.show() def notify_axes_change(fig): 'this will be called whenever the current axes is changed' if self.toolbar is not None: self.toolbar.update() self.canvas.figure.add_axobserver(notify_axes_change) self.canvas.grab_focus()
def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): # MGDTODO: Support clippath here trans = [1,0,0,1,0,0] transstr = '' if rcParams['svg.image_noscale']: trans = list(im.get_matrix()) if im.get_interpolation() != 0: trans[4] += trans[0] trans[5] += trans[3] trans[5] = -trans[5] transstr = 'transform="matrix(%s %s %s %s %s %s)" '%tuple(trans) assert trans[1] == 0 assert trans[2] == 0 numrows,numcols = im.get_size() im.reset_matrix() im.set_interpolation(0) im.resize(numcols, numrows) h,w = im.get_size_out() self._svgwriter.write ( '<image x="%s" y="%s" width="%s" height="%s" ' '%s xlink:href="'%(x/trans[0], (self.height-y)/trans[3]-h, w, h, transstr) ) if rcParams['svg.image_inline']: class Base64Writer(object): def __init__(self, write_method): self._write_method = write_method self._buffer = '' def write(self, data): self._buffer += data while len(self._buffer) >= 64: self._write_method(base64.encodestring(buffer[:64])) self._write_method('\n') self._buffer = self._buffer[64:] def flush(self): self._write_method(base64.encodestring(self._buffer)) self._write_method('\n') self._svgwriter.write("data:image/png;base64,\n") base64writer = Base64Writer(self._svgwriter.write) im.flipud_out() im.write_png(base64writer) im.flipud_out() base64writer.flush() else: self._imaged[self.basename] = self._imaged.get(self.basename,0) + 1 filename = '%s.image%d.png'%(self.basename, self._imaged[self.basename]) verbose.report( 'Writing image file for inclusion: %s' % filename) im.flipud_out() im.write_png(filename) im.flipud_out() self._svgwriter.write(filename) self._svgwriter.write('"/>\n')
def _run(self): # Uses subprocess to call the program for assembling frames into a # movie file. *args* returns the sequence of command line arguments # from a few configuration options. command = self._args() verbose.report('MovieWriter.run: running command: %s'%' '.join(command)) self._proc = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
def draw_image(self, x, y, im, bbox): trans = [1,0,0,1,0,0] transstr = '' if rcParams['svg.image_noscale']: trans = list(im.get_matrix()) if im.get_interpolation() != 0: trans[4] += trans[0] trans[5] += trans[3] trans[5] = -trans[5] transstr = 'transform="matrix(%s %s %s %s %s %s)" '%tuple(trans) assert trans[1] == 0 assert trans[2] == 0 numrows,numcols = im.get_size() im.reset_matrix() im.set_interpolation(0) im.resize(numcols, numrows) h,w = im.get_size_out() if rcParams['svg.image_inline']: filename = os.path.join (tempfile.gettempdir(), tempfile.gettempprefix() + '.png' ) verbose.report ('Writing temporary image file for inlining: %s' % filename) # im.write_png() accepts a filename, not file object, would be # good to avoid using files and write to mem with StringIO # JDH: it *would* be good, but I don't know how to do this # since libpng seems to want a FILE* and StringIO doesn't seem # to provide one. I suspect there is a way, but I don't know # it im.flipud_out() im.write_png(filename) im.flipud_out() imfile = file (filename, 'rb') image64 = base64.encodestring (imfile.read()) imfile.close() os.remove(filename) hrefstr = 'data:image/png;base64,\n' + image64 else: self._imaged[self.basename] = self._imaged.get(self.basename,0) + 1 filename = '%s.image%d.png'%(self.basename, self._imaged[self.basename]) verbose.report( 'Writing image file for inclusion: %s' % filename) im.flipud_out() im.write_png(filename) im.flipud_out() hrefstr = filename self._svgwriter.write ( '<image x="%s" y="%s" width="%s" height="%s" ' 'xlink:href="%s" %s/>\n'%(x/trans[0], (self.height-y)/trans[3]-h, w, h, hrefstr, transstr) )
def new_figure_manager(num, *args, **kwargs): """ Create a new figure manager instance """ if __debug__: verbose.report('backend_agg.new_figure_manager', 'debug-annoying') FigureClass = kwargs.pop('FigureClass', Figure) thisFig = FigureClass(*args, **kwargs) canvas = FigureCanvasAgg(thisFig) manager = FigureManagerBase(canvas, num) return manager
def on_event(self, event): """ Event handler that will be passed to the current figure to retrieve events. """ self.add_event(event) verbose.report("Event %i" % len(self.events)) self.post_event() if len(self.events) >= self.n and self.n > 0: self.fig.canvas.stop_event_loop()
def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): attrib = {} clipid = self._get_clip(gc) if clipid is not None: # Can't apply clip-path directly to the image because the # image has a transformation, which would also be applied # to the clip-path self.writer.start('g', attrib={'clip-path': 'url(#%s)' % clipid}) trans = [1, 0, 0, 1, 0, 0] if rcParams['svg.image_noscale']: trans = list(im.get_matrix()) trans[5] = -trans[5] attrib['transform'] = generate_transform([('matrix', tuple(trans)) ]) assert trans[1] == 0 assert trans[2] == 0 numrows, numcols = im.get_size() im.reset_matrix() im.set_interpolation(0) im.resize(numcols, numrows) h, w = im.get_size_out() url = getattr(im, '_url', None) if url is not None: self.writer.start('a', attrib={'xlink:href': url}) if rcParams['svg.image_inline']: stringio = cStringIO.StringIO() im.flipud_out() rows, cols, buffer = im.as_rgba_str() _png.write_png(buffer, cols, rows, stringio) im.flipud_out() attrib['xlink:href'] = ("data:image/png;base64,\n" + base64.encodestring(stringio.getvalue())) else: self._imaged[self.basename] = self._imaged.get(self.basename, 0) + 1 filename = '%s.image%d.png' % (self.basename, self._imaged[self.basename]) verbose.report('Writing image file for inclusion: %s' % filename) im.flipud_out() rows, cols, buffer = im.as_rgba_str() _png.write_png(buffer, cols, rows, filename) im.flipud_out() attrib['xlink:href'] = filename alpha = gc.get_alpha() if alpha != 1.0: attrib['opacity'] = str(alpha) if transform is None: self.writer.element('image', x=str(x / trans[0]), y=str((self.height - y) / trans[3] - h), width=str(w), height=str(h), attrib=attrib) else: flipped = self._make_flip_transform(transform) attrib['transform'] = generate_transform([('matrix', flipped.to_values())]) self.writer.element('image', x=str(x), y=str(y + dy), width=str(dx), height=str(-dy), attrib=attrib) if url is not None: self.writer.end('a') if clipid is not None: self.writer.end('g')
def save(self, filename, fps=5, codec='mpeg4', clear_temp=True, frame_prefix='_tmp'): ''' Saves a movie file by drawing every frame. *filename* is the output filename, eg :file:`mymovie.mp4` *fps* is the frames per second in the movie *codec* is the codec to be used,if it is supported by the output method. *clear_temp* specifies whether the temporary image files should be deleted. *frame_prefix* gives the prefix that should be used for individual image files. This prefix will have a frame number (i.e. 0001) appended when saving individual frames. ''' # Need to disconnect the first draw callback, since we'll be doing # draws. Otherwise, we'll end up starting the animation. if self._first_draw_id is not None: self._fig.canvas.mpl_disconnect(self._first_draw_id) reconnect_first_draw = True else: reconnect_first_draw = False fnames = [] # Create a new sequence of frames for saved data. This is different # from new_frame_seq() to give the ability to save 'live' generated # frame information to be saved later. # TODO: Right now, after closing the figure, saving a movie won't # work since GUI widgets are gone. Either need to remove extra code # to allow for this non-existant use case or find a way to make it work. for idx, data in enumerate(self.new_saved_frame_seq()): #TODO: Need to see if turning off blit is really necessary self._draw_next_frame(data, blit=False) fname = '%s%04d.png' % (frame_prefix, idx) fnames.append(fname) verbose.report('Animation.save: saved frame %d to fname=%s' % (idx, fname), level='debug') self._fig.savefig(fname) self._make_movie(filename, fps, codec, frame_prefix) #Delete temporary files if clear_temp: import os verbose.report('Animation.save: clearing temporary fnames=%s' % str(fnames), level='debug') for fname in fnames: os.remove(fname) # Reconnect signal for first draw if necessary if reconnect_first_draw: self._first_draw_id = self._fig.canvas.mpl_connect( 'draw_event', self._start)
def _print_figure_tex(self, outfile, format, dpi, facecolor, edgecolor, orientation, isLandscape, papertype): """ If text.usetex is True in rc, a temporary pair of tex/eps files are created to allow tex to manage the text layout via the PSFrags package. These files are processed to yield the final ps or eps file. """ isEPSF = format == 'eps' title = outfile # write to a temp file, we'll move it to outfile when done fd, tmpfile = mkstemp() os.close(fd) fh = file(tmpfile, 'w') self.figure.dpi = 72 # ignore the dpi kwarg width, height = self.figure.get_size_inches() xo = 0 yo = 0 l, b, w, h = self.figure.bbox.bounds llx = xo lly = yo urx = llx + w ury = lly + h bbox = (llx, lly, urx, ury) # generate PostScript code for the figure and store it in a string origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) self._pswriter = StringIO() renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi) self.figure.draw(renderer) self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) # write the Encapsulated PostScript headers print >>fh, "%!PS-Adobe-3.0 EPSF-3.0" if title: print >>fh, "%%Title: "+title print >>fh, ("%%Creator: matplotlib version " +__version__+", http://matplotlib.sourceforge.net/") print >>fh, "%%CreationDate: "+time.ctime(time.time()) print >>fh, "%%%%BoundingBox: %d %d %d %d" % bbox print >>fh, "%%EndComments" Ndict = len(psDefs) print >>fh, "%%BeginProlog" print >>fh, "/mpldict %d dict def"%Ndict print >>fh, "mpldict begin" for d in psDefs: d=d.strip() for l in d.split('\n'): print >>fh, l.strip() print >>fh, "end" print >>fh, "%%EndProlog" print >>fh, "mpldict begin" #print >>fh, "gsave" print >>fh, "%s translate"%_nums_to_str(xo, yo) print >>fh, "%s clipbox"%_nums_to_str(width*72, height*72, 0, 0) # write the figure print >>fh, self._pswriter.getvalue() # write the trailer #print >>fh, "grestore" print >>fh, "end" print >>fh, "showpage" fh.close() if isLandscape: # now we are ready to rotate isLandscape = True width, height = height, width bbox = (lly, llx, ury, urx) temp_papertype = _get_papertype(width, height) if papertype=='auto': papertype = temp_papertype paperWidth, paperHeight = papersize[temp_papertype] else: paperWidth, paperHeight = papersize[papertype] if (width>paperWidth or height>paperHeight) and isEPSF: paperWidth, paperHeight = papersize[temp_papertype] verbose.report('Your figure is too big to fit on %s paper. %s \ paper will be used to prevent clipping.'%(papertype, temp_papertype), 'helpful') texmanager = renderer.get_texmanager() font_preamble = texmanager.get_font_preamble() custom_preamble = texmanager.get_custom_preamble() convert_psfrags(tmpfile, renderer.psfrag, font_preamble, custom_preamble, paperWidth, paperHeight, orientation) if rcParams['ps.usedistiller'] == 'ghostscript': gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) elif rcParams['ps.usedistiller'] == 'xpdf': xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) elif rcParams['text.usetex']: if False: pass # for debugging else: gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) if isinstance(outfile, file): fh = file(tmpfile) print >>outfile, fh.read() else: shutil.move(tmpfile, outfile)
def print_figure(self, outfile, dpi=72, facecolor='w', edgecolor='w', orientation='portrait'): """ Render the figure to hardcopy. Set the figure patch face and edge colors. This is useful because some of the GUIs have a gray figure face color background and you'll probably want to override this on hardcopy If outfile is a string, it is interpreted as a file name. If the extension matches .ep* write encapsulated postscript, otherwise write a stand-alone PostScript file. If outfile is a file object, a stand-alone PostScript file is written into this file object. If text.usetex is True in rc, a temporary pair of tex/eps files are created to allow tex to handle the text. The final output is a simple ps or eps file. """ if isinstance(outfile, file): # assume plain PostScript and write to fileobject isEPSF = False fh = outfile needsClose = False title = None else: basename, ext = os.path.splitext(outfile) if not ext: if rcParams['text.usetex']: ext = '.eps' outfile += ext else: ext = '.ps' outfile += ext if rcParams['text.usetex']: # need to make some temporary files so latex can run without # writing over something important. m = md5.md5(outfile) tmpname = m.hexdigest() epsfile = tmpname + '.eps' psfile = tmpname + '.ps' texfile = tmpname + '.tex' dvifile = tmpname + '.dvi' latexh = file(texfile, 'w') fh = file(epsfile, 'w') else: fh = file(outfile, 'w') isEPSF = ext.lower().startswith('.ep') or rcParams['text.usetex'] needsClose = True title = outfile # center the figure on the paper self.figure.dpi.set(72) # ignore the passsed dpi setting for PS width, height = self.figure.get_size_inches() if orientation == 'landscape': isLandscape = True paperHeight, paperWidth = defaultPaperSize else: isLandscape = False paperWidth, paperHeight = defaultPaperSize xo = 72 * 0.5 * (paperWidth - width) yo = 72 * 0.5 * (paperHeight - height) l, b, w, h = self.figure.bbox.get_bounds() llx = xo lly = yo urx = llx + w ury = lly + h if isLandscape: xo, yo = 72 * paperHeight - yo, xo llx, lly, urx, ury = lly, llx, ury, urx rotation = 90 else: rotation = 0 # generate PostScript code for the figure and store it in a string origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) self._pswriter = StringIO() renderer = RendererPS(width, height, self._pswriter) self.figure.draw(renderer) self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) # write the PostScript headers if isEPSF: print >> fh, "%!PS-Adobe-3.0 EPSF-3.0" else: print >> fh, "%!PS-Adobe-3.0" if title: print >> fh, "%%Title: " + title print >> fh, ("%%Creator: matplotlib version " + __version__ + ", http://matplotlib.sourceforge.net/") print >> fh, "%%CreationDate: " + time.ctime(time.time()) if not isEPSF: if paperWidth > paperHeight: ostr = "Landscape" else: ostr = "Portrait" print >> fh, "%%Orientation: " + ostr print >> fh, "%%DocumentPaperSizes: " + defaultPaperType print >> fh, "%%%%BoundingBox: %d %d %d %d" % (llx, lly, urx, ury) if not isEPSF: print >> fh, "%%Pages: 1" print >> fh, "%%EndComments" Ndict = len(psDefs) print >> fh, "%%BeginProlog" if not rcParams['text.usetex']: type42 = _type42 + [os.path.join(self.basepath, name) + '.ttf' \ for name in bakoma_fonts] if not rcParams['ps.useafm']: Ndict += len(type42) print >> fh, "/mpldict %d dict def" % Ndict print >> fh, "mpldict begin" for d in psDefs: d = d.strip() for l in d.split('\n'): print >> fh, l.strip() if not rcParams['text.usetex']: if not rcParams['ps.useafm']: for font in type42: print >> fh, "%%BeginFont: " + FT2Font( str(font)).postscript_name print >> fh, encodeTTFasPS(font) print >> fh, "%%EndFont" print >> fh, "%%EndProlog" if not isEPSF: print >> fh, "%%Page: 1 1" print >> fh, "mpldict begin" #print >>fh, "gsave" print >> fh, "%s translate" % _nums_to_str(xo, yo) if rotation: print >> fh, "%d rotate" % rotation print >> fh, "%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0) # write the figure print >> fh, self._pswriter.getvalue() # write the trailer #print >>fh, "grestore" print >> fh, "end" print >> fh, "showpage" if not isEPSF: print >> fh, "%%EOF" if needsClose: fh.close() if rcParams['text.usetex']: if rcParams['text.tex.engine'] == 'latex': fontpackage = rcParams['font.latex.package'] else: fontpackage = 'type1cm' pw, ph = defaultPaperSize if width > pw - 2 or height > ph - 2: pw, ph = _get_papersize(width, height) print >> latexh, r"""\documentclass{scrartcl} \usepackage{%s} \usepackage{psfrag} \usepackage[dvips]{graphicx} \usepackage{color} \pagestyle{empty} \setlength{\paperheight}{%fin} \setlength{\paperwidth}{%fin} \setlength{\textwidth}{%fin} \setlength{\textheight}{%fin} \special{papersize=%fin,%fin} \begin{document} \begin{figure}[th!] \begin{center} %s \includegraphics{%s} \end{center} \end{figure} \end{document} """ % (fontpackage, pw, ph, pw - 2, ph - 2, pw, ph, '\n'.join( renderer.psfrag), epsfile) latexh.close() command = 'latex -interaction=nonstopmode "%s"' % texfile verbose.report(command, 'debug-annoying') stdin, stdout, stderr = os.popen3(command) verbose.report(stdout.read(), 'debug-annoying') verbose.report(stderr.read(), 'helpful') command = 'dvips -R -T %fin,%fin -o "%s" "%s"' % (pw, ph, psfile, dvifile) verbose.report(command, 'debug-annoying') stdin, stdout, stderr = os.popen3(command) verbose.report(stdout.read(), 'debug-annoying') verbose.report(stderr.read(), 'helpful') os.remove(epsfile) if ext.startswith('.ep'): dpi = rcParams['ps.distiller.res'] if sys.platform == 'win32': command = 'gswin32c -dBATCH -dNOPAUSE -dSAFER -r%d \ -sDEVICE=epswrite -dLanguageLevel=2 -dEPSFitPage \ -sOutputFile="%s" "%s"' % (dpi, epsfile, psfile) else: command = 'gs -dBATCH -dNOPAUSE -dSAFER -r%d \ -sDEVICE=epswrite -dLanguageLevel=2 -dEPSFitPage \ -sOutputFile="%s" "%s"' % (dpi, epsfile, psfile) verbose.report(command, 'debug-annoying') stdin, stdout, stderr = os.popen3(command) verbose.report(stdout.read(), 'debug-annoying') verbose.report(stderr.read(), 'helpful') shutil.move(epsfile, outfile) else: shutil.move(psfile, outfile) for fname in glob.glob(tmpname + '.*'): os.remove(fname) if rcParams['ps.usedistiller']: dpi = rcParams['ps.distiller.res'] m = md5.md5(outfile) tmpfile = m.hexdigest() if ext.startswith('ep'): command = 'eps2eps -dSAFER -r%d "%s" "%s"' % (dpi, outfile, tmpfile) else: command = 'ps2ps -dSAFER -r%d "%s" "%s"' % (dpi, outfile, tmpfile) verbose.report(command, 'debug-annoying') stdin, stdout, stderr = os.popen3(command) verbose.report(stdout.read(), 'debug-annoying') verbose.report(stderr.read(), 'helpful') shutil.move(tmpfile, outfile)
except ImportError: # Try using PySide QT_API = QT_API_PYSIDE if _sip_imported: if QT_API == QT_API_PYQTv2: if QT_API_ENV == 'pyqt': cond = ("Found 'QT_API=pyqt' environment variable. " "Setting PyQt4 API accordingly.\n") else: cond = "PyQt API v2 specified." try: sip.setapi('QString', 2) except: res = 'QString API v2 specification failed. Defaulting to v1.' verbose.report(cond + res, 'helpful') # condition has now been reported, no need to repeat it: cond = "" try: sip.setapi('QVariant', 2) except: res = 'QVariant API v2 specification failed. Defaulting to v1.' verbose.report(cond + res, 'helpful') if QT_API in [QT_API_PYQT, QT_API_PYQTv2]: # PyQt4 API from PyQt4 import QtCore, QtGui try: if sip.getapi("QString") > 1: # Use new getSaveFileNameAndFilter()
def draw_image(self, gc, x, y, im, transform=None): h, w = im.shape[:2] if w == 0 or h == 0: return attrib = {} clipid = self._get_clip(gc) if clipid is not None: # Can't apply clip-path directly to the image because the # image has a transformation, which would also be applied # to the clip-path self.writer.start('g', attrib={'clip-path': 'url(#%s)' % clipid}) oid = gc.get_gid() url = gc.get_url() if url is not None: self.writer.start('a', attrib={'xlink:href': url}) if rcParams['svg.image_inline']: bytesio = io.BytesIO() _png.write_png(im, bytesio) oid = oid or self._make_id('image', bytesio.getvalue()) attrib['xlink:href'] = ( "data:image/png;base64,\n" + base64.b64encode(bytesio.getvalue()).decode('ascii')) else: self._imaged[self.basename] = self._imaged.get(self.basename, 0) + 1 filename = '%s.image%d.png' % (self.basename, self._imaged[self.basename]) verbose.report('Writing image file for inclusion: %s' % filename) _png.write_png(im, filename) oid = oid or 'Im_' + self._make_id('image', filename) attrib['xlink:href'] = filename attrib['id'] = oid if transform is None: w = 72.0 * w / self.image_dpi h = 72.0 * h / self.image_dpi self.writer.element('image', transform=generate_transform([ ('scale', (1, -1)), ('translate', (0, -h)) ]), x=short_float_fmt(x), y=short_float_fmt(-(self.height - y - h)), width=short_float_fmt(w), height=short_float_fmt(h), attrib=attrib) else: alpha = gc.get_alpha() if alpha != 1.0: attrib['opacity'] = short_float_fmt(alpha) flipped = (Affine2D().scale(1.0 / w, 1.0 / h) + transform + Affine2D().translate(x, y).scale(1.0, -1.0).translate( 0.0, self.height)) attrib['transform'] = generate_transform([('matrix', flipped.frozen())]) self.writer.element('image', width=short_float_fmt(w), height=short_float_fmt(h), attrib=attrib) if url is not None: self.writer.end('a') if clipid is not None: self.writer.end('g')
def save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None, savefig_kwargs=None): ''' Saves a movie file by drawing every frame. *filename* is the output filename, e.g., :file:`mymovie.mp4` *writer* is either an instance of :class:`MovieWriter` or a string key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. If nothing is passed, the value of the rcparam `animation.writer` is used. *fps* is the frames per second in the movie. Defaults to None, which will use the animation's specified interval to set the frames per second. *dpi* controls the dots per inch for the movie frames. This combined with the figure's size in inches controls the size of the movie. *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the value specified by the rcparam `animation.codec`. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam `animation.bitrate`. *extra_args* is a list of extra string arguments to be passed to the underlying movie utiltiy. The default is None, which passes the additional argurments in the 'animation.extra_args' rcParam. *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: title, artist, genre, subject, copyright, srcform, comment. *extra_anim* is a list of additional `Animation` objects that should be included in the saved movie file. These need to be from the same `matplotlib.Figure` instance. Also, animation frames will just be simply combined, so there should be a 1:1 correspondence between the frames from the different animations. *savefig_kwargs* is a dictionary containing keyword arguments to be passed on to the 'savefig' command which is called repeatedly to save the individual frames. This can be used to set tight bounding boxes, for example. ''' if savefig_kwargs is None: savefig_kwargs = {} # FIXME: Using 'bbox_inches' doesn't currently work with # writers that pipe the data to the command because this # requires a fixed frame size (see Ryan May's reply in this # thread: [1]). Thus we drop the 'bbox_inches' argument if it # exists in savefig_kwargs. # # [1] (http://matplotlib.1069221.n5.nabble.com/ # Animation-class-let-save-accept-kwargs-which- # are-passed-on-to-savefig-td39627.html) # if 'bbox_inches' in savefig_kwargs: if not (writer in ['ffmpeg_file', 'mencoder_file'] or isinstance(writer, (FFMpegFileWriter, MencoderFileWriter))): print("Warning: discarding the 'bbox_inches' argument in " "'savefig_kwargs' as it is only currently supported " "with the writers 'ffmpeg_file' and 'mencoder_file' " "(writer used: " "'{}').".format(writer if isinstance(writer, str) else writer.__class__.__name__)) savefig_kwargs.pop('bbox_inches') # Need to disconnect the first draw callback, since we'll be doing # draws. Otherwise, we'll end up starting the animation. if self._first_draw_id is not None: self._fig.canvas.mpl_disconnect(self._first_draw_id) reconnect_first_draw = True else: reconnect_first_draw = False if fps is None and hasattr(self, '_interval'): # Convert interval in ms to frames per second fps = 1000. / self._interval # If the writer is None, use the rc param to find the name of the one # to use if writer is None: writer = rcParams['animation.writer'] # Re-use the savefig DPI for ours if none is given if dpi is None: dpi = rcParams['savefig.dpi'] if codec is None: codec = rcParams['animation.codec'] if bitrate is None: bitrate = rcParams['animation.bitrate'] all_anim = [self] if not extra_anim is None: all_anim.extend(anim for anim in extra_anim if anim._fig is self._fig) # If we have the name of a writer, instantiate an instance of the # registered class. if is_string_like(writer): if writer in writers.avail: writer = writers[writer](fps, codec, bitrate, extra_args=extra_args, metadata=metadata) else: import warnings warnings.warn("MovieWriter %s unavailable" % writer) try: writer = writers.list()[0] except IndexError: raise ValueError("Cannot save animation: no writers are " "available. Please install mencoder or " "ffmpeg to save animations.") verbose.report('Animation.save using %s' % type(writer), level='helpful') # Create a new sequence of frames for saved data. This is different # from new_frame_seq() to give the ability to save 'live' generated # frame information to be saved later. # TODO: Right now, after closing the figure, saving a movie won't work # since GUI widgets are gone. Either need to remove extra code to # allow for this non-existant use case or find a way to make it work. with writer.saving(self._fig, filename, dpi): for data in itertools.izip( *[a.new_saved_frame_seq() for a in all_anim]): for anim, d in zip(all_anim, data): #TODO: Need to see if turning off blit is really necessary anim._draw_next_frame(d, blit=False) writer.grab_frame(**savefig_kwargs) # Reconnect signal for first draw if necessary if reconnect_first_draw: self._first_draw_id = self._fig.canvas.mpl_connect( 'draw_event', self._start)
def fetch_historical_yahoo(ticker, date1, date2, cachename=None, dividends=False): """ Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. Parameters ---------- ticker : str ticker date1 : sequence of form (year, month, day), `datetime`, or `date` start date date2 : sequence of form (year, month, day), `datetime`, or `date` end date cachename : str cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) dividends : bool set dividends=True to return dividends instead of price data. With this option set, parse functions will not work Returns ------- file_handle : file handle a file handle is returned Examples -------- >>> fh = fetch_historical_yahoo('^GSPC', (2000, 1, 1), (2001, 12, 31)) """ ticker = ticker.upper() if iterable(date1): d1 = (date1[1] - 1, date1[2], date1[0]) else: d1 = (date1.month - 1, date1.day, date1.year) if iterable(date2): d2 = (date2[1] - 1, date2[2], date2[0]) else: d2 = (date2.month - 1, date2.day, date2.year) if dividends: g = 'v' verbose.report('Retrieving dividends instead of prices') else: g = 'd' urlFmt = ('http://ichart.yahoo.com/table.csv?a=%d&b=%d&' + 'c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv') url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker, g) # Cache the finance data if cachename is supplied, or there is a writable # cache directory. if cachename is None and cachedir is not None: cachename = os.path.join(cachedir, md5(url).hexdigest()) if cachename is not None: if os.path.exists(cachename): fh = open(cachename) verbose.report('Using cachefile %s for ' '%s' % (cachename, ticker)) else: mkdirs(os.path.abspath(os.path.dirname(cachename))) with contextlib.closing(urlopen(url)) as urlfh: with open(cachename, 'wb') as fh: fh.write(urlfh.read()) verbose.report('Saved %s data to cache file ' '%s' % (ticker, cachename)) fh = open(cachename, 'r') return fh else: return urlopen(url)
def tostring_rgb(self): if __debug__: verbose.report('RendererAgg.tostring_rgb', 'debug-annoying') return self._renderer.tostring_rgb()
def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): attrib = {} clipid = self._get_clip(gc) if clipid is not None: # Can't apply clip-path directly to the image because the # image as a transformation, which would also be applied # to the clip-path self.writer.start(u'g', attrib={u'clip-path': u'url(#%s)' % clipid}) trans = [1,0,0,1,0,0] if rcParams['svg.image_noscale']: trans = list(im.get_matrix()) trans[5] = -trans[5] attrib[u'transform'] = generate_transform([(u'matrix', tuple(trans))]) assert trans[1] == 0 assert trans[2] == 0 numrows, numcols = im.get_size() im.reset_matrix() im.set_interpolation(0) im.resize(numcols, numrows) h,w = im.get_size_out() url = getattr(im, '_url', None) if url is not None: self.writer.start(u'a', attrib={u'xlink:href': url}) if rcParams['svg.image_inline']: bytesio = io.BytesIO() im.flipud_out() rows, cols, buffer = im.as_rgba_str() _png.write_png(buffer, cols, rows, bytesio) im.flipud_out() attrib[u'xlink:href'] = ( u"data:image/png;base64,\n" + base64.b64encode(bytesio.getvalue()).decode('ascii')) else: self._imaged[self.basename] = self._imaged.get(self.basename,0) + 1 filename = u'%s.image%d.png'%(self.basename, self._imaged[self.basename]) verbose.report( 'Writing image file for inclusion: %s' % filename) im.flipud_out() rows, cols, buffer = im.as_rgba_str() _png.write_png(buffer, cols, rows, filename) im.flipud_out() attrib[u'xlink:href'] = filename if transform is None: self.writer.element( u'image', x=unicode(x/trans[0]), y=unicode((self.height-y)/trans[3]-h), width=unicode(w), height=unicode(h), attrib=attrib) else: attrib[u'transform'] = generate_transform( [(u'matrix', transform.to_values())]) self.writer.element( u'image', x=unicode(x), y=unicode(y), width=unicode(dx), height=unicode(dy), attrib=attrib) if url is not None: self.writer.end(u'a') if clipid is not None: self.writer.end(u'g')
def add(self, patchlabel='', flows=None, orientations=None, labels='', trunklength=1.0, pathlengths=0.25, prior=None, connect=(0, 0), rotation=0, **kwargs): """ Add a simple Sankey diagram with flows at the same hierarchical level. Return value is the instance of :class:`Sankey`. Optional keyword arguments: =============== =================================================== Keyword Description =============== =================================================== *patchlabel* label to be placed at the center of the diagram Note: *label* (not *patchlabel*) will be passed to the patch through ``**kwargs`` and can be used to create an entry in the legend. *flows* array of flow values By convention, inputs are positive and outputs are negative. *orientations* list of orientations of the paths Valid values are 1 (from/to the top), 0 (from/to the left or right), or -1 (from/to the bottom). If *orientations* == 0, inputs will break in from the left and outputs will break away to the right. *labels* list of specifications of the labels for the flows Each value may be *None* (no labels), '' (just label the quantities), or a labeling string. If a single value is provided, it will be applied to all flows. If an entry is a non-empty string, then the quantity for the corresponding flow will be shown below the string. However, if the *unit* of the main diagram is None, then quantities are never shown, regardless of the value of this argument. *trunklength* length between the bases of the input and output groups *pathlengths* list of lengths of the arrows before break-in or after break-away If a single value is given, then it will be applied to the first (inside) paths on the top and bottom, and the length of all other arrows will be justified accordingly. The *pathlengths* are not applied to the horizontal inputs and outputs. *prior* index of the prior diagram to which this diagram should be connected *connect* a (prior, this) tuple indexing the flow of the prior diagram and the flow of this diagram which should be connected If this is the first diagram or *prior* is *None*, *connect* will be ignored. *rotation* angle of rotation of the diagram [deg] *rotation* is ignored if this diagram is connected to an existing one (using *prior* and *connect*). The interpretation of the *orientations* argument will be rotated accordingly (e.g., if *rotation* == 90, an *orientations* entry of 1 means to/from the left). =============== =================================================== Valid kwargs are :meth:`matplotlib.patches.PathPatch` arguments: %(Patch)s As examples, ``fill=False`` and ``label='A legend entry'``. By default, ``facecolor='#bfd1d4'`` (light blue) and ``linewidth=0.5``. The indexing parameters (*prior* and *connect*) are zero-based. The flows are placed along the top of the diagram from the inside out in order of their index within the *flows* list or array. They are placed along the sides of the diagram from the top down and along the bottom from the outside in. If the sum of the inputs and outputs is nonzero, the discrepancy will appear as a cubic Bezier curve along the top and bottom edges of the trunk. .. seealso:: :meth:`finish` """ # Check and preprocess the arguments. if flows is None: flows = np.array([1.0, -1.0]) else: flows = np.array(flows) n = flows.shape[0] # Number of flows if rotation is None: rotation = 0 else: # In the code below, angles are expressed in deg/90. rotation /= 90.0 if orientations is None: orientations = [0, 0] if len(orientations) != n: raise ValueError( "orientations and flows must have the same length.\n" "orientations has length %d, but flows has length %d." % (len(orientations), n)) if labels != '' and getattr(labels, '__iter__', False): # iterable() isn't used because it would give True if labels is a # string if len(labels) != n: raise ValueError( "If labels is a list, then labels and flows must have the " "same length.\nlabels has length %d, but flows has length %d." % (len(labels), n)) else: labels = [labels] * n if trunklength < 0: raise ValueError( "trunklength is negative.\nThis isn't allowed, because it would " "cause poor layout.") if np.absolute(np.sum(flows)) > self.tolerance: verbose.report( "The sum of the flows is nonzero (%f).\nIs the " "system not at steady state?" % np.sum(flows), 'helpful') scaled_flows = self.scale * flows gain = sum(max(flow, 0) for flow in scaled_flows) loss = sum(min(flow, 0) for flow in scaled_flows) if not (0.5 <= gain <= 2.0): verbose.report( "The scaled sum of the inputs is %f.\nThis may " "cause poor layout.\nConsider changing the scale so" " that the scaled sum is approximately 1.0." % gain, 'helpful') if not (-2.0 <= loss <= -0.5): verbose.report( "The scaled sum of the outputs is %f.\nThis may " "cause poor layout.\nConsider changing the scale so" " that the scaled sum is approximately 1.0." % gain, 'helpful') if prior is not None: if prior < 0: raise ValueError("The index of the prior diagram is negative.") if min(connect) < 0: raise ValueError( "At least one of the connection indices is negative.") if prior >= len(self.diagrams): raise ValueError( "The index of the prior diagram is %d, but there are " "only %d other diagrams.\nThe index is zero-based." % (prior, len(self.diagrams))) if connect[0] >= len(self.diagrams[prior].flows): raise ValueError( "The connection index to the source diagram is %d, but " "that diagram has only %d flows.\nThe index is zero-based." % (connect[0], len(self.diagrams[prior].flows))) if connect[1] >= n: raise ValueError( "The connection index to this diagram is %d, but this diagram" "has only %d flows.\n The index is zero-based." % (connect[1], n)) if self.diagrams[prior].angles[connect[0]] is None: raise ValueError( "The connection cannot be made. Check that the magnitude " "of flow %d of diagram %d is greater than or equal to the " "specified tolerance." % (connect[0], prior)) flow_error = (self.diagrams[prior].flows[connect[0]] + flows[connect[1]]) if abs(flow_error) >= self.tolerance: raise ValueError( "The scaled sum of the connected flows is %f, which is not " "within the tolerance (%f)." % (flow_error, self.tolerance)) # Determine if the flows are inputs. are_inputs = [None] * n for i, flow in enumerate(flows): if flow >= self.tolerance: are_inputs[i] = True elif flow <= -self.tolerance: are_inputs[i] = False else: verbose.report( "The magnitude of flow %d (%f) is below the " "tolerance (%f).\nIt will not be shown, and it " "cannot be used in a connection." % (i, flow, self.tolerance), 'helpful') # Determine the angles of the arrows (before rotation). angles = [None] * n for i, (orient, is_input) in enumerate(zip(orientations, are_inputs)): if orient == 1: if is_input: angles[i] = DOWN elif not is_input: # Be specific since is_input can be None. angles[i] = UP elif orient == 0: if is_input is not None: angles[i] = RIGHT else: if orient != -1: raise ValueError( "The value of orientations[%d] is %d, " "but it must be [ -1 | 0 | 1 ]." % (i, orient)) if is_input: angles[i] = UP elif not is_input: angles[i] = DOWN # Justify the lengths of the paths. if iterable(pathlengths): if len(pathlengths) != n: raise ValueError( "If pathlengths is a list, then pathlengths and flows must " "have the same length.\npathlengths has length %d, but flows " "has length %d." % (len(pathlengths), n)) else: # Make pathlengths into a list. urlength = pathlengths ullength = pathlengths lrlength = pathlengths lllength = pathlengths d = dict(RIGHT=pathlengths) pathlengths = [d.get(angle, 0) for angle in angles] # Determine the lengths of the top-side arrows # from the middle outwards. for i, (angle, is_input, flow) in enumerate(zip(angles, are_inputs, scaled_flows)): if angle == DOWN and is_input: pathlengths[i] = ullength ullength += flow elif angle == UP and not is_input: pathlengths[i] = urlength urlength -= flow # Flow is negative for outputs. # Determine the lengths of the bottom-side arrows # from the middle outwards. for i, (angle, is_input, flow) in enumerate(reversed(list(zip( angles, are_inputs, scaled_flows)))): if angle == UP and is_input: pathlengths[n - i - 1] = lllength lllength += flow elif angle == DOWN and not is_input: pathlengths[n - i - 1] = lrlength lrlength -= flow # Determine the lengths of the left-side arrows # from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) in enumerate(reversed(list(zip( angles, are_inputs, zip(scaled_flows, pathlengths))))): if angle == RIGHT: if is_input: if has_left_input: pathlengths[n - i - 1] = 0 else: has_left_input = True # Determine the lengths of the right-side arrows # from the top downwards. has_right_output = False for i, (angle, is_input, spec) in enumerate(zip( angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == RIGHT: if not is_input: if has_right_output: pathlengths[i] = 0 else: has_right_output = True # Begin the subpaths, and smooth the transition if the sum of the flows # is nonzero. urpath = [(Path.MOVETO, [(self.gap - trunklength / 2.0), # Upper right gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, gain / 2.0]), (Path.CURVE4, [(self.gap - trunklength / 2.0) / 8.0, gain / 2.0]), (Path.CURVE4, [(trunklength / 2.0 - self.gap) / 8.0, -loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, -loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap), -loss / 2.0])] llpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower left loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, loss / 2.0]), (Path.CURVE4, [(trunklength / 2.0 - self.gap) / 8.0, loss / 2.0]), (Path.CURVE4, [(self.gap - trunklength / 2.0) / 8.0, -gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, -gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0), -gain / 2.0])] lrpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower right loss / 2.0])] ulpath = [(Path.LINETO, [self.gap - trunklength / 2.0, # Upper left gain / 2.0])] # Add the subpaths and assign the locations of the tips and labels. tips = np.zeros((n, 2)) label_locations = np.zeros((n, 2)) # Add the top-side inputs and outputs from the middle outwards. for i, (angle, is_input, spec) in enumerate(zip( angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == DOWN and is_input: tips[i, :], label_locations[i, :] = self._add_input( ulpath, angle, *spec) elif angle == UP and not is_input: tips[i, :], label_locations[i, :] = self._add_output( urpath, angle, *spec) # Add the bottom-side inputs and outputs from the middle outwards. for i, (angle, is_input, spec) in enumerate(reversed(list(zip( angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): if angle == UP and is_input: tip, label_location = self._add_input(llpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location elif angle == DOWN and not is_input: tip, label_location = self._add_output(lrpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location # Add the left-side inputs from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) in enumerate(reversed(list(zip( angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): if angle == RIGHT and is_input: if not has_left_input: # Make sure the lower path extends # at least as far as the upper one. if llpath[-1][1][0] > ulpath[-1][1][0]: llpath.append((Path.LINETO, [ulpath[-1][1][0], llpath[-1][1][1]])) has_left_input = True tip, label_location = self._add_input(llpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location # Add the right-side outputs from the top downwards. has_right_output = False for i, (angle, is_input, spec) in enumerate(zip( angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == RIGHT and not is_input: if not has_right_output: # Make sure the upper path extends # at least as far as the lower one. if urpath[-1][1][0] < lrpath[-1][1][0]: urpath.append((Path.LINETO, [lrpath[-1][1][0], urpath[-1][1][1]])) has_right_output = True tips[i, :], label_locations[i, :] = self._add_output( urpath, angle, *spec) # Trim any hanging vertices. if not has_left_input: ulpath.pop() llpath.pop() if not has_right_output: lrpath.pop() urpath.pop() # Concatenate the subpaths in the correct order (clockwise from top). path = (urpath + self._revert(lrpath) + llpath + self._revert(ulpath) + [(Path.CLOSEPOLY, urpath[0][1])]) # Create a patch with the Sankey outline. codes, vertices = list(zip(*path)) vertices = np.array(vertices) def _get_angle(a, r): if a is None: return None else: return a + r if prior is None: if rotation != 0: # By default, none of this is needed. angles = [_get_angle(angle, rotation) for angle in angles] rotate = Affine2D().rotate_deg(rotation * 90).transform_affine tips = rotate(tips) label_locations = rotate(label_locations) vertices = rotate(vertices) text = self.ax.text(0, 0, s=patchlabel, ha='center', va='center') else: rotation = (self.diagrams[prior].angles[connect[0]] - angles[connect[1]]) angles = [_get_angle(angle, rotation) for angle in angles] rotate = Affine2D().rotate_deg(rotation * 90).transform_affine tips = rotate(tips) offset = self.diagrams[prior].tips[connect[0]] - tips[connect[1]] translate = Affine2D().translate(*offset).transform_affine tips = translate(tips) label_locations = translate(rotate(label_locations)) vertices = translate(rotate(vertices)) kwds = dict(s=patchlabel, ha='center', va='center') text = self.ax.text(*offset, **kwds) if False: # Debug print("llpath\n", llpath) print("ulpath\n", self._revert(ulpath)) print("urpath\n", urpath) print("lrpath\n", self._revert(lrpath)) xs, ys = list(zip(*vertices)) self.ax.plot(xs, ys, 'go-') patch = PathPatch(Path(vertices, codes), fc=kwargs.pop('fc', kwargs.pop('facecolor', '#bfd1d4')), # Custom defaults lw=kwargs.pop('lw', kwargs.pop('linewidth', 0.5)), **kwargs) self.ax.add_patch(patch) # Add the path labels. texts = [] for number, angle, label, location in zip(flows, angles, labels, label_locations): if label is None or angle is None: label = '' elif self.unit is not None: quantity = self.format % abs(number) + self.unit if label != '': label += "\n" label += quantity texts.append(self.ax.text(x=location[0], y=location[1], s=label, ha='center', va='center')) # Text objects are placed even they are empty (as long as the magnitude # of the corresponding flow is larger than the tolerance) in case the # user wants to provide labels later. # Expand the size of the diagram if necessary. self.extent = (min(np.min(vertices[:, 0]), np.min(label_locations[:, 0]), self.extent[0]), max(np.max(vertices[:, 0]), np.max(label_locations[:, 0]), self.extent[1]), min(np.min(vertices[:, 1]), np.min(label_locations[:, 1]), self.extent[2]), max(np.max(vertices[:, 1]), np.max(label_locations[:, 1]), self.extent[3])) # Include both vertices _and_ label locations in the extents; there are # where either could determine the margins (e.g., arrow shoulders). # Add this diagram as a subdiagram. self.diagrams.append(Bunch(patch=patch, flows=flows, angles=angles, tips=tips, text=text, texts=texts)) # Allow a daisy-chained call structure (see docstring for the class). return self
def print_figure(self, filename, dpi=150, facecolor='w', edgecolor='w', orientation='portrait'): """ Render the figure to hardcopy. Set the figure patch face and edge colors. This is useful because some of the GUIs have a gray figure face color background and you'll probably want to override this on hardcopy If the extension matches PNG, write a PNG file If the extension matches BMP or RAW, write an RGBA bitmap file If filename is a fileobject, write png to file object (thus you can, for example, write the png to stdout """ if __debug__: verbose.report('FigureCanvasAgg.print_figure', 'debug-annoying') # store the orig figure dpi, color and size information so we # can restore them later. For image creation alone, this is # not important since after the print the figure is done. But # backend_agg may be used as a renderer for a GUI figure, and # restoring figure props will be important in that case. # TODO: move most of this functionality into backend_bases origDPI = self.figure.dpi.get() origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() self.figure.dpi.set(dpi) self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) # render the printed figure self.draw() if isinstance(filename, file): # assume png and write to fileobject self.renderer._renderer.write_png(filename) #pass else: # take a look at the extension and choose the print handler basename, ext = os.path.splitext(filename) if not len(ext): ext = '.png' filename += ext ext = ext.lower() if (ext.find('rgb')>=0 or ext.find('raw')>=0 or ext.find('bmp')>=0 ): # agg doesn't handle unicode yet self.renderer._renderer.write_rgba(str(filename)) elif ext.find('png')>=0: # agg doesn't handle unicode yet self.renderer._renderer.write_png(str(filename)) #pass elif ext.find('svg')>=0: from backend_svg import FigureCanvasSVG svg = self.switch_backends(FigureCanvasSVG) svg.print_figure(filename, dpi, facecolor, edgecolor, orientation) elif ext.find('ps')>=0 or ext.find('ep')>=0: from backend_ps import FigureCanvasPS # lazy import ps = self.switch_backends(FigureCanvasPS) ps.print_figure(filename, dpi, facecolor, edgecolor, orientation) else: error_msg('Do not know know to handle extension *%s' % ext) # restore the original figure properties self.figure.dpi.set(origDPI) self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor)
h = abs(y1 - y0) rect = [ int(val)for val in min(x0,x1), min(y0, y1), w, h ] self.canvas.drawRectangle( rect ) def save_figure( self ): fname = qt.QFileDialog.getSaveFileName() if fname: self.canvas.print_figure( fname.latin1() ) # set icon used when windows are minimized try: qt.window_set_default_icon_from_file ( os.path.join( matplotlib.rcParams['datapath'], 'matplotlib.svg' ) ) except: verbose.report( 'Could not load matplotlib icon: %s' % sys.exc_info()[1] ) def error_msg_qt( msg, parent=None ): if not is_string_like( msg ): msg = ','.join( map( str,msg ) ) qt.QMessageBox.warning( None, "Matplotlib", msg, qt.QMessageBox.Ok ) def exception_handler( type, value, tb ): """Handle uncaught exceptions It does not catch SystemExit """ msg = '' # get the filename attribute if available (for IOError) if hasattr(value, 'filename') and value.filename != None:
def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): # MGDTODO: Support clippath here trans = [1, 0, 0, 1, 0, 0] transstr = '' if rcParams['svg.image_noscale']: trans = list(im.get_matrix()) if im.get_interpolation() != 0: trans[4] += trans[0] trans[5] += trans[3] trans[5] = -trans[5] transstr = 'transform="matrix(%s %s %s %s %s %s)" ' % tuple(trans) assert trans[1] == 0 assert trans[2] == 0 numrows, numcols = im.get_size() im.reset_matrix() im.set_interpolation(0) im.resize(numcols, numrows) h, w = im.get_size_out() self._svgwriter.write( '<image x="%s" y="%s" width="%s" height="%s" ' '%s xlink:href="' % (x / trans[0], (self.height - y) / trans[3] - h, w, h, transstr)) if rcParams['svg.image_inline']: class Base64Writer(object): def __init__(self, write_method): self._write_method = write_method self._buffer = '' def write(self, data): self._buffer += data while len(self._buffer) >= 64: self._write_method(base64.encodestring(buffer[:64])) self._write_method('\n') self._buffer = self._buffer[64:] def flush(self): self._write_method(base64.encodestring(self._buffer)) self._write_method('\n') self._svgwriter.write("data:image/png;base64,\n") base64writer = Base64Writer(self._svgwriter.write) im.flipud_out() im.write_png(base64writer) im.flipud_out() base64writer.flush() else: self._imaged[self.basename] = self._imaged.get(self.basename, 0) + 1 filename = '%s.image%d.png' % (self.basename, self._imaged[self.basename]) verbose.report('Writing image file for inclusion: %s' % filename) im.flipud_out() im.write_png(filename) im.flipud_out() self._svgwriter.write(filename) self._svgwriter.write('"/>\n')
def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): attrib = {} clipid = self._get_clip(gc) if clipid is not None: # Can't apply clip-path directly to the image because the # image has a transformation, which would also be applied # to the clip-path self.writer.start('g', attrib={'clip-path': 'url(#%s)' % clipid}) trans = [1, 0, 0, 1, 0, 0] if rcParams['svg.image_noscale']: trans = list(im.get_matrix()) trans[5] = -trans[5] attrib['transform'] = generate_transform([('matrix', tuple(trans)) ]) assert trans[1] == 0 assert trans[2] == 0 numrows, numcols = im.get_size() im.reset_matrix() im.set_interpolation(0) im.resize(numcols, numrows) h, w = im.get_size_out() if dx is None: w = 72.0 * w / self.image_dpi else: w = dx if dy is None: h = 72.0 * h / self.image_dpi else: h = dy oid = getattr(im, '_gid', None) url = getattr(im, '_url', None) if url is not None: self.writer.start('a', attrib={'xlink:href': url}) if rcParams['svg.image_inline']: bytesio = io.BytesIO() _png.write_png(np.array(im)[::-1], bytesio) oid = oid or self._make_id('image', bytesio) attrib['xlink:href'] = ( "data:image/png;base64,\n" + base64.b64encode(bytesio.getvalue()).decode('ascii')) else: self._imaged[self.basename] = self._imaged.get(self.basename, 0) + 1 filename = '%s.image%d.png' % (self.basename, self._imaged[self.basename]) verbose.report('Writing image file for inclusion: %s' % filename) _png.write_png(np.array(im)[::-1], filename) oid = oid or 'Im_' + self._make_id('image', filename) attrib['xlink:href'] = filename alpha = gc.get_alpha() if alpha != 1.0: attrib['opacity'] = str(alpha) attrib['id'] = oid if transform is None: self.writer.element('image', x=six.text_type(x / trans[0]), y=six.text_type((self.height - y) / trans[3] - h), width=six.text_type(w), height=six.text_type(h), attrib=attrib) else: flipped = self._make_flip_transform(transform) flipped = np.array(flipped.to_values()) y = y + dy if dy > 0.0: flipped[3] *= -1.0 y *= -1.0 attrib['transform'] = generate_transform([('matrix', flipped)]) self.writer.element('image', x=six.text_type(x), y=six.text_type(y), width=six.text_type(dx), height=six.text_type(abs(dy)), attrib=attrib) if url is not None: self.writer.end('a') if clipid is not None: self.writer.end('g')
def convert_psfrags(tmpfile, psfrags, font_preamble, pw, ph): """ When we want to use the LaTeX backend with postscript, we write PSFrag tags to a temporary postscript file, each one marking a position for LaTeX to render some text. convert_psfrags generates a LaTeX document containing the commands to convert those tags to text. LaTeX/dvips produces the postscript file that includes the actual text. """ epsfile = tmpfile+'.eps' shutil.move(tmpfile, epsfile) latexfile = tmpfile+'.tex' latexh = file(latexfile, 'w') dvifile = tmpfile+'.dvi' psfile = tmpfile+'.ps' print >>latexh, r"""\documentclass{scrartcl} %s \usepackage{psfrag} \usepackage[dvips]{graphicx} \usepackage{color} \pagestyle{empty} \setlength{\oddsidemargin}{0in} \setlength{\evensidemargin}{0in} \setlength{\topmargin}{0in} \setlength{\headheight}{0in} \setlength{\headsep}{0in} \setlength{\parindent}{0in} \setlength{\paperwidth}{%fin} \setlength{\paperheight}{%fin} \setlength{\textwidth}{%fin} \setlength{\textheight}{%fin} \special{papersize=%fin,%fin} \begin{document} \begin{figure} \centering %s \includegraphics{%s} \end{figure} \end{document} """% (font_preamble, pw, ph, pw-2, ph-2, pw, ph, '\n'.join(psfrags), os.path.split(epsfile)[-1]) latexh.close() curdir = os.getcwd() os.chdir(gettempdir()) command = 'latex -interaction=nonstopmode "%s"' % latexfile verbose.report(command, 'debug-annoying') stdin, stdout, stderr = os.popen3(command) verbose.report(stdout.read(), 'debug-annoying') verbose.report(stderr.read(), 'helpful') command = 'dvips -R -T %fin,%fin -o "%s" "%s"' % \ (pw, ph, psfile, dvifile) verbose.report(command, 'debug-annoying') stdin, stdout, stderr = os.popen3(command) verbose.report(stdout.read(), 'debug-annoying') verbose.report(stderr.read(), 'helpful') shutil.move(psfile, tmpfile) for fname in glob.glob(tmpfile+'.*'): os.remove(fname) os.chdir(curdir)
def __init__(self, canvas, num): if _debug: print('FigureManagerGTK3.%s' % fn_name()) FigureManagerBase.__init__(self, canvas, num) self.window = Gtk.Window() self.window.set_wmclass("matplotlib", "Matplotlib") self.set_window_title("Figure %d" % num) try: self.window.set_icon_from_file(window_icon) except (SystemExit, KeyboardInterrupt): # re-raise exit type Exceptions raise except: # some versions of gtk throw a glib.GError but not # all, so I am not sure how to catch it. I am unhappy # doing a blanket catch here, but am not sure what a # better way is - JDH verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1]) self.vbox = Gtk.Box() self.vbox.set_property("orientation", Gtk.Orientation.VERTICAL) self.window.add(self.vbox) self.vbox.show() self.canvas.show() self.vbox.pack_start(self.canvas, True, True, 0) # calculate size for window w = int(self.canvas.figure.bbox.width) h = int(self.canvas.figure.bbox.height) self.toolmanager = self._get_toolmanager() self.toolbar = self._get_toolbar() self.statusbar = None def add_widget(child, expand, fill, padding): child.show() self.vbox.pack_end(child, False, False, 0) size_request = child.size_request() return size_request.height if self.toolmanager: backend_tools.add_tools_to_manager(self.toolmanager) if self.toolbar: backend_tools.add_tools_to_container(self.toolbar) self.statusbar = StatusbarGTK3(self.toolmanager) h += add_widget(self.statusbar, False, False, 0) h += add_widget(Gtk.HSeparator(), False, False, 0) if self.toolbar is not None: self.toolbar.show() h += add_widget(self.toolbar, False, False, 0) self.window.set_default_size(w, h) def destroy(*args): Gcf.destroy(num) self.window.connect("destroy", destroy) self.window.connect("delete_event", destroy) if matplotlib.is_interactive(): self.window.show() self.canvas.draw_idle() def notify_axes_change(fig): 'this will be called whenever the current axes is changed' if self.toolmanager is not None: pass elif self.toolbar is not None: self.toolbar.update() self.canvas.figure.add_axobserver(notify_axes_change) self.canvas.grab_focus()
def save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None): ''' Saves a movie file by drawing every frame. *filename* is the output filename, eg :file:`mymovie.mp4` *writer* is either an instance of :class:`MovieWriter` or a string key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. If nothing is passed, the value of the rcparam `animation.writer` is used. *fps* is the frames per second in the movie. Defaults to None, which will use the animation's specified interval to set the frames per second. *dpi* controls the dots per inch for the movie frames. This combined with the figure's size in inches controls the size of the movie. *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the value specified by the rcparam `animation.codec`. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam `animation.bitrate`. *extra_args* is a list of extra string arguments to be passed to the underlying movie utiltiy. The default is None, which passes the additional argurments in the 'animation.extra_args' rcParam. *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: title, artist, genre, subject, copyright, srcform, comment. *extra_anim* is a list of additional `Animation` objects that should be included in the saved movie file. These need to be from the same `matplotlib.Figure` instance. Also, animation frames will just be simply combined, so there should be a 1:1 correspondence between the frames from the different animations. ''' # Need to disconnect the first draw callback, since we'll be doing # draws. Otherwise, we'll end up starting the animation. if self._first_draw_id is not None: self._fig.canvas.mpl_disconnect(self._first_draw_id) reconnect_first_draw = True else: reconnect_first_draw = False if fps is None and hasattr(self, '_interval'): # Convert interval in ms to frames per second fps = 1000. / self._interval # If the writer is None, use the rc param to find the name of the one # to use if writer is None: writer = rcParams['animation.writer'] # Re-use the savefig DPI for ours if none is given if dpi is None: dpi = rcParams['savefig.dpi'] if codec is None: codec = rcParams['animation.codec'] if bitrate is None: bitrate = rcParams['animation.bitrate'] all_anim = [self] if not extra_anim is None: all_anim.extend(anim for anim in extra_anim if anim._fig is self._fig) # If we have the name of a writer, instantiate an instance of the # registered class. if is_string_like(writer): if writer in writers.avail: writer = writers[writer](fps, codec, bitrate, extra_args=extra_args, metadata=metadata) else: import warnings warnings.warn("MovieWriter %s unavailable" % writer) writer = writers.list()[0] verbose.report('Animation.save using %s' % type(writer), level='helpful') # Create a new sequence of frames for saved data. This is different # from new_frame_seq() to give the ability to save 'live' generated # frame information to be saved later. # TODO: Right now, after closing the figure, saving a movie won't # work since GUI widgets are gone. Either need to remove extra code # to allow for this non-existant use case or find a way to make it work. with writer.saving(self._fig, filename, dpi): for data in itertools.izip( *[a.new_saved_frame_seq() for a in all_anim]): for anim, d in zip(all_anim, data): #TODO: Need to see if turning off blit is really necessary anim._draw_next_frame(d, blit=False) writer.grab_frame() # Reconnect signal for first draw if necessary if reconnect_first_draw: self._first_draw_id = self._fig.canvas.mpl_connect( 'draw_event', self._start)
def buffer_rgba(self): if __debug__: verbose.report('RendererAgg.buffer_rgba', 'debug-annoying') return self._renderer.buffer_rgba()
latexh.write(s) except UnicodeEncodeError, err: verbose.report("You are using unicode and latex, but have " "not enabled the matplotlib 'text.latex.unicode' " "rcParam.", 'helpful') raise latexh.close() # the split drive part of the command is necessary for windows users with # multiple if sys.platform == 'win32': precmd = '%s &&'% os.path.splitdrive(tmpdir)[0] else: precmd = '' command = '%s cd "%s" && latex -interaction=nonstopmode "%s" > "%s"'\ %(precmd, tmpdir, latexfile, outfile) verbose.report(command, 'debug') exit_status = os.system(command) fh = file(outfile) if exit_status: raise RuntimeError('LaTeX was not able to process your file:\ \nHere is the full report generated by LaTeX: \n\n%s'% fh.read()) else: verbose.report(fh.read(), 'debug') fh.close() os.remove(outfile) command = '%s cd "%s" && dvips -q -R0 -o "%s" "%s" > "%s"'%(precmd, tmpdir, os.path.split(psfile)[-1], os.path.split(dvifile)[-1], outfile) verbose.report(command, 'debug') exit_status = os.system(command) fh = file(outfile) if exit_status: raise RuntimeError('dvips was not able to \
def tostring_argb(self): if __debug__: verbose.report('FigureCanvasAgg.tostring_argb', 'debug-annoying') return self.renderer.tostring_argb()
from numpy import angle def typecode(a): return a.dtype.char def iscontiguous(a): return a.flags.contiguous def byteswapped(a): return a.byteswap() def itemsize(a): return a.itemsize verbose.report('numerix %s' % version) # a bug fix for blas numeric suggested by Fernando Perez matrixmultiply = dot asum = sum def _import_fail_message(module, version): """Prints a message when the array package specific version of an extension fails to import correctly. """ _dict = {"which": which[0], "module": module, "specific": version + module} print """ The import of the %(which)s version of the %(module)s module, %(specific)s, failed. This is is either because %(which)s was unavailable when matplotlib was compiled, because a dependency of %(specific)s could not be satisfied, or because the build flag for
def buffer_rgba(self): if __debug__: verbose.report('FigureCanvasAgg.buffer_rgba', 'debug-annoying') return self.renderer.buffer_rgba()