diff --git a/CHANGELOG b/CHANGELOG index 6f70ce6cc7a2..8b9e5139178a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,53 @@ +2011-02-18 scatter([], []) is now valid. Also fixed issues + with empty collections - BVR + +2011-02-07 Quick workaround for dviread bug #3175113 - JKS + +2011-02-05 Add cbook memory monitoring for Windows, using + tasklist. - EF + +2011-02-05 Speed up Normalize and LogNorm by using in-place + operations and by using float32 for float32 inputs + and for ints of 2 bytes or shorter; based on + patch by Christoph Gohlke. - EF + +2011-02-04 Changed imshow to use rgba as uint8 from start to + finish, instead of going through an intermediate + step as double precision; thanks to Christoph Gohlke. - EF + +2011-01-13 Added zdir and offset arguments to contourf3d to + bring contourf3d in feature parity with contour3d. - BVR + +2011-01-04 Tag 1.0.1 for release at r8896 + +2011-01-03 Added display of ticker offset to 3d plots. - BVR + +2011-01-03 Turn off tick labeling on interior subplots for + pyplots.subplots when sharex/sharey is True. - JDH + +2010-12-29 Implement axes_divider.HBox and VBox. -JJL + + 2010-11-22 Fixed error with Hammer projection. - BVR 2010-11-12 Fixed the placement and angle of axis labels in 3D plots. - BVR 2010-11-07 New rc parameters examples.download and examples.directory - allow bypassing the download mechanism in get_sample_data. + allow bypassing the download mechanism in get_sample_data. - JKS +2010-10-04 Fix JPEG saving bug: only accept the kwargs documented + by PIL for JPEG files. - JKS + +2010-09-15 Remove unused _wxagg extension and numerix.h. - EF + +2010-08-25 Add new framework for doing animations with examples.- RM + +2010-08-21 Remove unused and inappropriate methods from Tick classes: + set_view_interval, get_minpos, and get_data_interval are + properly found in the Axis class and don't need to be + duplicated in XTick and YTick. - EF + 2010-08-21 Change Axis.set_view_interval() so that when updating an existing interval, it respects the orientation of that interval, and can enlarge but not reduce the interval. @@ -20,6 +62,23 @@ 2010-08-14 Fix bug in patch alpha handling, and in bar color kwarg - EF +2010-08-12 Removed all traces of numerix module after 17 months of + deprecation warnings. - EF + +2010-08-05 Added keyword arguments 'thetaunits' and 'runits' for polar + plots. Fixed PolarAxes so that when it set default + Formatters, it marked them as such. Fixed semilogx and + semilogy to no longer blindly reset the ticker information + on the non-log axis. Axes.arrow can now accept unitized + data. - JRE + +2010-08-03 Add support for MPLSETUPCFG variable for custom setup.cfg + filename. Used by sage buildbot to build an mpl w/ no gui + support - JDH + +2010-08-01 Create directory specified by MPLCONFIGDIR if it does + not exist. - ADS + 2010-07-20 Return Qt4's default cursor when leaving the canvas - DSD 2010-07-06 Tagging for mpl 1.0 at r8502 diff --git a/FILETYPES b/FILETYPES index 5378f6c4a2dc..84af57a892ed 100644 --- a/FILETYPES +++ b/FILETYPES @@ -5,30 +5,33 @@ correctly. It may be edited with emacs' table mode. Each cell specifies the backend that actually handles the file format. A cell with a '+' in it denotes the rasterizer and the file writing -infrastructure as separate pieces. +infrastructure as separate pieces. +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ | |bmp |emf |eps |jpeg |pcx |pdf |png |ps |raw |svg |svgz |tiff |xpm | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|Agg | |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|Agg | |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |Cairo | |emf |ps | | |cairo |cairo |cairo|agg |cairo|cairo| | | |[1] | | |[2] | | | |* | | | | | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|CocoaAgg| |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|CocoaAgg| |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |Emf | |emf *| | | | | | | | | | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|FltkAgg | |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|FltkAgg | |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |Gd | | | | | | |gd * | | | | | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|Gtk | |emf |ps |gdk + | |pdf |gdk + |ps |agg |svg |svg | | | -|(gdk) | | | |pixbuf | | |pixbuf| | | | | | | +|Gtk | |emf |ps |gdk + | |pdf |gdk + |ps |agg |svg |svg |agg +| | +|(gdk) | | | |pixbuf | | |pixbuf| | | | |pil | | | | | | | | | |* | | | | | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|GtkAgg | |emf |ps |agg + | |pdf |agg + |ps |agg |svg |svg | | | -| | | | |pixbuf | | |pixbuf| | | | | | | +|GtkAgg | |emf |ps |agg + | |pdf |agg + |ps |agg |svg |svg |agg +| | +| | | | |pixbuf | | |pixbuf| | | | |pil | | | | | | | | | |* | | | | | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |GtkCairo| |emf |ps |cairo +| |cairo |cairo |cairo|agg |cairo|cairo| | | @@ -41,18 +44,22 @@ infrastructure as separate pieces. +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |Ps | | |ps | | | | |ps * | | | | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|QtAgg | |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|QtAgg | |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|Qt4Agg | |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|Qt4Agg | |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |Svg | | | | | | | | | |svg *|svg | | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|TkAgg | |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|TkAgg | |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ |Wx |wx + |emf |ps |wx + wx|wx + |pdf |wx + |ps |agg |svg |svg |wx + |wx + | | |wx | | | |wx | |wx * | | | | |wx |wx | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ -|WxAgg | |emf |ps | | |pdf |agg * |ps |agg |svg |svg | | | +|WxAgg | |emf |ps |agg + | |pdf |agg * |ps |agg |svg |svg |agg +| | +| | | | |pil | | | | | | | |pil | | +--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+-----+ * Default filetype for the backend diff --git a/README.txt b/README.txt index 318ee55f43c0..760b580af87a 100644 --- a/README.txt +++ b/README.txt @@ -43,3 +43,4 @@ interactive : False # see http://matplotlib.sourceforge.net/interactive.html See also + diff --git a/doc/api/gridspec_api.rst b/doc/api/gridspec_api.rst index c0107dfa6bf9..6e4135ae401b 100644 --- a/doc/api/gridspec_api.rst +++ b/doc/api/gridspec_api.rst @@ -1,6 +1,6 @@ -************* +******************* matplotlib gridspec -************* +******************* :mod:`matplotlib.gridspec` diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst index 3e95cb0e61e4..883fdf3329b3 100644 --- a/doc/faq/installing_faq.rst +++ b/doc/faq/installing_faq.rst @@ -106,6 +106,17 @@ and build and install as usual with:: > cd matplotlib > python setup.py install +.. note:: + + If you are on debian/ubuntu, you can get all the dependencies + required to build matplotlib with:: + + sudo apt-get build_dep python-matplotlib + + This does not build matplotlib, but it does get the install the + build dependencies, which will make building from svn easy. + + If you want to be able to follow the development branch as it changes just replace the last step with (Make sure you have **setuptools** installed):: @@ -116,8 +127,10 @@ Then, if you want to update your **matplotlib** at any time, just do:: > svn update -When you run `svn update`, if the output shows that only Python files have been updated, you are all set. -If C files have changed, you need to run the `python setupegg develop` command again to compile them. + +When you run `svn update`, if the output shows that only Python files +have been updated, you are all set. If C files have changed, you need +to run the `python setupegg develop` command again to compile them. There is more information on :ref:`using Subversion ` in the developer docs. diff --git a/doc/matplotlibrc b/doc/matplotlibrc index f7088e15440e..aca4828a0799 100644 --- a/doc/matplotlibrc +++ b/doc/matplotlibrc @@ -1,318 +1,15 @@ -### MATPLOTLIBRC FORMAT - -# This is a sample matplotlib configuration file. It should be placed -# in HOME/.matplotlib/matplotlibrc (unix/linux like systems) and -# C:\Documents and Settings\yourname\.matplotlib (win32 systems) -# -# By default, the installer will overwrite the existing file in the -# install path, so if you want to preserve your's, please move it to -# your HOME dir and set the environment variable if necessary. -# -# This file is best viewed in a editor which supports python mode -# syntax highlighting -# -# Blank lines, or lines starting with a comment symbol, are ignored, -# as are trailing comments. Other lines must have the format -# -# key : val # optional comment -# -# Colors: for the color values below, you can either use -# - a matplotlib color string, such as r, k, or b -# - an rgb tuple, such as (1.0, 0.5, 0.0) -# - a hex string, such as ff00ff (no '#' symbol) -# - a scalar grayscale intensity such as 0.75 -# - a legal html color name, eg red, blue, darkslategray - -#### CONFIGURATION BEGINS HERE -# the default backend; one of GTK GTKAgg GTKCairo FltkAgg QtAgg TkAgg -# WX WXAgg Agg Cairo GD GDK Paint PS PDF SVG Template backend : Agg -#maskedarray : False # True to use external maskedarray module - # instead of numpy.ma; this is a temporary - # setting for testing maskedarray. -#interactive : False # see http://matplotlib.sourceforge.net/interactive.html -#toolbar : toolbar2 # None | classic | toolbar2 -#timezone : UTC # a pytz timezone string, eg US/Central or Europe/Paris - -# Where your matplotlib data lives if you installed to a non-default -# location. This is where the matplotlib fonts, bitmaps, etc reside -#datapath : /home/jdhunter/mpldata - - -### LINES -# See http://matplotlib.sourceforge.net/matplotlib.lines.html for more -# information on line properties. -lines.linewidth : 1.5 # line width in points -#lines.linestyle : - # solid line -#lines.color : blue -#lines.marker : None # the default marker -#lines.markeredgewidth : 0.5 # the line width around the marker symbol -#lines.markersize : 6 # markersize, in points -#lines.dash_joinstyle : miter # miter|round|bevel -#lines.dash_capstyle : butt # butt|round|projecting -#lines.solid_joinstyle : miter # miter|round|bevel -#lines.solid_capstyle : projecting # butt|round|projecting -#lines.antialiased : True # render lines in antialised (no jaggies) - -### PATCHES -# Patches are graphical objects that fill 2D space, like polygons or -# circles. See -# http://matplotlib.sourceforge.net/matplotlib.patches.html for more -# information on patch properties -#patch.linewidth : 1.0 # edge width in points -#patch.facecolor : blue -#patch.edgecolor : black -#patch.antialiased : True # render patches in antialised (no jaggies) - -### FONT -# -# font properties used by text.Text. See -# http://matplotlib.sourceforge.net/matplotlib.font_manager.html for more -# information on font properties. The 6 font properties used for font -# matching are given below with their default values. -# -# The font.family property has five values: 'serif' (e.g. Times), -# 'sans-serif' (e.g. Helvetica), 'cursive' (e.g. Zapf-Chancery), -# 'fantasy' (e.g. Western), and 'monospace' (e.g. Courier). Each of -# these font families has a default list of font names in decreasing -# order of priority associated with them. -# -# The font.style property has three values: normal (or roman), italic -# or oblique. The oblique style will be used for italic, if it is not -# present. -# -# The font.variant property has two values: normal or small-caps. For -# TrueType fonts, which are scalable fonts, small-caps is equivalent -# to using a font size of 'smaller', or about 83% of the current font -# size. -# -# The font.weight property has effectively 13 values: normal, bold, -# bolder, lighter, 100, 200, 300, ..., 900. Normal is the same as -# 400, and bold is 700. bolder and lighter are relative values with -# respect to the current weight. -# -# The font.stretch property has 11 values: ultra-condensed, -# extra-condensed, condensed, semi-condensed, normal, semi-expanded, -# expanded, extra-expanded, ultra-expanded, wider, and narrower. This -# property is not currently implemented. -# -# The font.size property is the default font size for text, given in pts. -# 12pt is the standard value. -# -#font.family : sans-serif -#font.style : normal -#font.variant : normal -#font.weight : medium -#font.stretch : normal -# note that font.size controls default text sizes. To configure -# special text sizes tick labels, axes, labels, title, etc, see the rc -# settings for axes and ticks. Special text sizes can be defined -# relative to font.size, using the following values: xx-small, x-small, -# small, medium, large, x-large, xx-large, larger, or smaller -#font.size : 12.0 -#font.serif : Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif -#font.sans-serif : Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif -#font.cursive : Apple Chancery, Textile, Zapf Chancery, Sand, cursive -#font.fantasy : Comic Sans MS, Chicago, Charcoal, Impact, Western, fantasy -#font.monospace : Bitstream Vera Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace - -### TEXT -# text properties used by text.Text. See -# http://matplotlib.sourceforge.net/matplotlib.text.html for more -# information on text properties - -#text.color : black - -### LaTeX customizations. See http://www.scipy.org/Wiki/Cookbook/Matplotlib/UsingTex -#text.usetex : False # use latex for all text handling. The following fonts - # are supported through the usual rc parameter settings: - # new century schoolbook, bookman, times, palatino, - # zapf chancery, charter, serif, sans-serif, helvetica, - # avant garde, courier, monospace, computer modern roman, - # computer modern sans serif, computer modern typewriter - # If another font is desired which can loaded using the - # LaTeX \usepackage command, please inquire at the - # matplotlib mailing list -#text.latex.unicode : False # use "ucs" and "inputenc" LaTeX packages for handling - # unicode strings. -#text.latex.preamble : # IMPROPER USE OF THIS FEATURE WILL LEAD TO LATEX FAILURES - # AND IS THEREFORE UNSUPPORTED. PLEASE DO NOT ASK FOR HELP - # IF THIS FEATURE DOES NOT DO WHAT YOU EXPECT IT TO. - # preamble is a comma separated list of LaTeX statements - # that are included in the LaTeX document preamble. - # An example: - # text.latex.preamble : \usepackage{bm},\usepackage{euler} - # The following packages are always loaded with usetex, so - # beware of package collisions: color, geometry, graphicx, - # type1cm, textcomp. Adobe Postscript (PSSNFS) font packages - # may also be loaded, depending on your font settings -#text.dvipnghack : False # some versions of dvipng don't handle - # alpha channel properly. Use True to correct and flush - # ~/.matplotlib/tex.cache before testing -#text.markup : 'plain' # Affects how text, such as titles and labels, are - # interpreted by default. - # 'plain': As plain, unformatted text - # 'tex': As TeX-like text. Text between $'s will be - # formatted as a TeX math expression. - # This setting has no effect when text.usetex is True. - # In that case, all text will be sent to TeX for - # processing. - -# The following settings allow you to select the fonts in math mode. -# They map from a TeX font name to a fontconfig font pattern. -# These settings are only used if mathtext.fontset is 'custom'. -#mathtext.cal : cursive -#mathtext.rm : serif -#mathtext.tt : monospace -#mathtext.it : serif:italic -#mathtext.bf : serif:bold -#mathtext.sf : sans -#mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix', - # 'stixsans' or 'custom' -#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern - # fonts when a symbol can not be found in one of - # the custom math fonts. - -### AXES -# default face and edge color, default tick sizes, -# default fontsizes for ticklabels, and so on. See -# http://matplotlib.sourceforge.net/matplotlib.axes.html#Axes -#axes.hold : True # whether to clear the axes by default on -#axes.facecolor : white # axes background color -#axes.edgecolor : black # axes edge color -#axes.linewidth : 1.0 # edge linewidth -#axes.grid : False # display grid or not -#axes.titlesize : 14 # fontsize of the axes title -#axes.labelsize : 12 # fontsize of the x any y labels -#axes.labelcolor : black -#axes.axisbelow : False # whether axis gridlines and ticks are below - # the axes elements (lines, text, etc) -#axes.formatter.limits : -7, 7 # use scientific notation if log10 - # of the axis range is smaller than the - # first or larger than the second - -#polaraxes.grid : True # display grid on polar axes - -### TICKS -# see http://matplotlib.sourceforge.net/matplotlib.axis.html#Ticks -#xtick.major.size : 4 # major tick size in points -#xtick.minor.size : 2 # minor tick size in points -#xtick.major.pad : 4 # distance to major tick label in points -#xtick.minor.pad : 4 # distance to the minor tick label in points -#xtick.color : k # color of the tick labels -#xtick.labelsize : 12 # fontsize of the tick labels -#xtick.direction : in # direction: in or out - -#ytick.major.size : 4 # major tick size in points -#ytick.minor.size : 2 # minor tick size in points -#ytick.major.pad : 4 # distance to major tick label in points -#ytick.minor.pad : 4 # distance to the minor tick label in points -#ytick.color : k # color of the tick labels -#ytick.labelsize : 12 # fontsize of the tick labels -#ytick.direction : in # direction: in or out - -### GRIDS -#grid.color : black # grid color -#grid.linestyle : : # dotted -#grid.linewidth : 0.5 # in points - -### Legend -#legend.isaxes : True -#legend.numpoints : 2 # the number of points in the legend line -#legend.fontsize : 14 -#legend.pad : 0.2 # the fractional whitespace inside the legend border -#legend.markerscale : 1.0 # the relative size of legend markers vs. original -# the following dimensions are in axes coords -#legend.labelsep : 0.010 # the vertical space between the legend entries -#legend.handlelen : 0.05 # the length of the legend lines -#legend.handletextsep : 0.02 # the space between the legend line and legend text -#legend.axespad : 0.02 # the border between the axes and legend edge -#legend.shadow : False - -### FIGURE -# See http://matplotlib.sourceforge.net/matplotlib.figure.html#Figure -figure.figsize : 6, 4 # figure size in inches -#figure.dpi : 80 # figure dots per inch -#figure.facecolor : 0.75 # figure facecolor; 0.75 is scalar gray -#figure.edgecolor : white # figure edgecolor - -# The figure subplot parameters. All dimensions are fraction of the -# figure width or height -figure.subplot.left : 0.2 # the left side of the subplots of the figure -#figure.subplot.right : 0.9 # the right side of the subplots of the figure -figure.subplot.bottom : 0.1 # the bottom of the subplots of the figure -#figure.subplot.top : 0.9 # the top of the subplots of the figure -#figure.subplot.wspace : 0.2 # the amount of width reserved for blank space between subplots -#figure.subplot.hspace : 0.2 # the amount of height reserved for white space between subplots - -#figure.autolayout : False # when True, adjust the axes so that text doesn't overlap - -### IMAGES -#image.aspect : equal # equal | auto | a number -#image.interpolation : bilinear # see help(imshow) for options -#image.cmap : jet # gray | jet etc... -#image.lut : 256 # the size of the colormap lookup table -#image.origin : upper # lower | upper - - -### CONTOUR PLOTS -#contour.negative_linestyle : dashed # dashed | solid - -### SAVING FIGURES -# the default savefig params can be different for the GUI backends. -# Eg, you may want a higher resolution, or to make the figure -# background white +figure.figsize : 5.5, 4.5 # figure size in inches savefig.dpi : 80 # figure dots per inch -#savefig.facecolor : white # figure facecolor when saving -#savefig.edgecolor : white # figure edgecolor when saving - -#cairo.format : png # png, ps, pdf, svg - -# tk backend params -#tk.window_focus : False # Maintain shell focus for TkAgg -#tk.pythoninspect : False # tk sets PYTHONINSEPCT - -# ps backend params -#ps.papersize : letter # auto, letter, legal, ledger, A0-A10, B0-B10 -#ps.useafm : False # use of afm fonts, results in small files -#ps.usedistiller : False # can be: None, ghostscript or xpdf - # Experimental: may produce smaller files. - # xpdf intended for production of publication quality files, - # but requires ghostscript, xpdf and ps2eps -#ps.distiller.res : 6000 # dpi -#ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType) - -# pdf backend params -#pdf.compression : 6 # integer from 0 to 9 - # 0 disables compression (good for debugging) -#pdf.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType) - -# svg backend params -#svg.image_inline : True # write raster image data directly into the svg file -#svg.image_noscale : False # suppress scaling of raster data embedded in SVG -#svg.embed_chars : True # embed character outlines in the SVG file - -# docstring params docstring.hardcopy : True # set this when you want to generate hardcopy docstring -# Set the verbose flags. This controls how much information -# matplotlib gives you at runtime and where it goes. The verbosity -# levels are: silent, helpful, debug, debug-annoying. Any level is -# inclusive of all the levels below it. If you setting is debug, -# you'll get all the debug and helpful messages. When submitting -# problems to the mailing-list, please set verbose to helpful or debug -# and paste the output into your report. -# -# The fileo gives the destination for any calls to verbose.report. -# These objects can a filename, or a filehandle like sys.stdout. -# -# You can override the rc default verbosity from the command line by -# giving the flags --verbose-LEVEL where LEVEL is one of the legal -# levels, eg --verbose-helpful. -# -# You can access the verbose instance in your code -# from matplotlib import verbose. +# these parameters are useful for packagers who want to build the docs +# w/o invoking file downloads for the sampledata (see +# matplotlib.cbook.get_sample_data. Unpack +# mpl_sampledata-VERSION.tar.gz and point examples.directory to it. +# You can use a relative path for examples.directory and it must be +# relative to this matplotlibrc file -#verbose.level : silent # one of silent, helpful, debug, debug-annoying -#verbose.fileo : sys.stdout # a log filename, sys.stdout or sys.stderr +#examples.download : False # False to bypass downloading mechanism +#examples.directory : /your/path/to/sample_data/ # directory to look in if download is false diff --git a/doc/mpl_toolkits/axes_grid/index.rst b/doc/mpl_toolkits/axes_grid/index.rst index e7c41630a710..29cad77489d0 100644 --- a/doc/mpl_toolkits/axes_grid/index.rst +++ b/doc/mpl_toolkits/axes_grid/index.rst @@ -18,13 +18,13 @@ multiple axes according to their aspects. 0.99. Originally, the toolkit had a single namespace of *axes_grid*. In more recent version (since svn r8226), the toolkit has divided into two separate namespace (*axes_grid1* and *axisartist*). - While *axes_grid* namespace is maintained for he backward compatibility, + While *axes_grid* namespace is maintained for the backward compatibility, use of *axes_grid1* and *axisartist* is recommended. .. warning:: *axes_grid* and *axisartist* (but not *axes_grid1*) uses - a custome Axes class (derived from the mpl's original Axes class). - As a sideeffect, some commands (mostly tick-related) do not work. + a custom Axes class (derived from the mpl's original Axes class). + As a side effect, some commands (mostly tick-related) do not work. Use *axes_grid1* to avoid this, or see how things are different in *axes_grid* and *axisartist* (LINK needed) diff --git a/doc/mpl_toolkits/axes_grid/users/axes_divider.rst b/doc/mpl_toolkits/axes_grid/users/axes_divider.rst index 50d01827ad71..fe0b782306c5 100644 --- a/doc/mpl_toolkits/axes_grid/users/axes_divider.rst +++ b/doc/mpl_toolkits/axes_grid/users/axes_divider.rst @@ -4,20 +4,21 @@ AxesDivider The axes_divider module provide helper classes to adjust the axes positions of set of images in the drawing time. -* :mod:`~mpl_toolkits.axes_grid.axes_size` provides a classese of +* :mod:`~mpl_toolkits.axes_grid.axes_size` provides a classes of units that the size of each axes will be determined. For example, you can specify a fixed size * :class:`~mpl_toolkits.axes_grid.axes_size.Divider` this is the class that is used calculates the axes position. It divides the given - renctangular area into several areas. You intialize the divider by + rectangular area into several areas. You initialize the divider by setting the horizontal and vertical list of sizes that the division will be based on. You then use the new_locator method, whose return value is a callable object that can be used to set the axes_locator of the axes. -You first initialize the divider by specifying its grids, i.e., horiz and vert. +You first initialize the divider by specifying its grids, i.e., +horizontal and vertical. for example,:: @@ -56,8 +57,8 @@ be adjusted accordingly. The :mod:`mpl_toolkits.axes_grid.axes_size` contains several classes -that can be used to set the horiz and vert. For example, for the -vertical configuration above will be:: +that can be used to set the horizontal and vertical configurations. For +example, for the vertical configuration above will be:: from mpl_toolkits.axes_grid.axes_size import Fixed, Scaled vert = [Fixed(2), Scaled(2), Scaled(3)] @@ -84,7 +85,7 @@ See the example, .. plot:: mpl_toolkits/axes_grid/figures/simple_axes_divider2.py :include-source: -You can adjust the size of the each axes accroding to their x or y +You can adjust the size of the each axes according to their x or y data limits (AxesX and AxesY), similar to the axes aspect parameter. .. plot:: mpl_toolkits/axes_grid/figures/simple_axes_divider3.py diff --git a/doc/mpl_toolkits/axes_grid/users/axisartist.rst b/doc/mpl_toolkits/axes_grid/users/axisartist.rst index b25aed8eb97e..67cdf64ecfa1 100644 --- a/doc/mpl_toolkits/axes_grid/users/axisartist.rst +++ b/doc/mpl_toolkits/axes_grid/users/axisartist.rst @@ -4,11 +4,11 @@ AXISARTIST namespace ==================== -The AxisArtist namesapce includes a derived Axes implementation. The +The AxisArtist namespace includes a derived Axes implementation. The biggest difference is that the artists responsible to draw axis line, ticks, ticklabel and axis labels are separated out from the mpl's Axis class, which are much more than artists in the original mpl. This -change was strongly motivated to support curvlinear grid. Here are a +change was strongly motivated to support curvilinear grid. Here are a few things that mpl_tootlkits.axisartist.Axes is different from original Axes from mpl. @@ -18,7 +18,7 @@ Axes from mpl. have different tick location and different tick labels. * gridlines are drawn by a Gridlines instance. The change was - motivated that in curvelinear coordinate, a gridline may not cross + motivated that in curvilinear coordinate, a gridline may not cross axis-lines (i.e., no associated ticks). In the original Axes class, gridlines are tied to ticks. @@ -26,7 +26,7 @@ Axes from mpl. In summary, all these changes was to support -* a curvelinear grid. +* a curvilinear grid. * a floating axis .. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axis.py @@ -111,7 +111,8 @@ Similarly, to make ticklabels invisible :: ax.axis["bottom"].major_ticklabels.set_visible(False) -AxisAritst provides a helper method to control the visibility of ticks, ticklabels, and label. To make ticklabel invisible, :: +AxisAritst provides a helper method to control the visibility of ticks, +ticklabels, and label. To make ticklabel invisible, :: ax.axis["bottom"].toggle(ticklabels=False) @@ -138,7 +139,7 @@ Note that 'ax.axis["top","right"]' returns a simple proxy object that translate for n in ["top","right"]: ax.axis[n].toggle(ticklabels=True)) -So, any return values in the for loop are ignored. And you shoud not +So, any return values in the for loop are ignored. And you should not use it anything more than a simple method. Like the list indexing ":" means all items, i.e., :: @@ -184,8 +185,8 @@ HowTo axis.label.set_pad method. -Rotaion and Alignment of TickLabels -=================================== +Rotation and Alignment of TickLabels +==================================== This is also quite different from the original mpl and can be confusing. When you want to rotate the ticklabels, first consider @@ -252,7 +253,7 @@ direction can be more clear with curved axis. .. plot:: mpl_toolkits/axes_grid/figures/demo_axis_direction.py -The axis_drection can be adjusted in the AxisArtist level, or in the +The axis_direction can be adjusted in the AxisArtist level, or in the level of its child arists, i.e., ticks, ticklabels, and axis-label. :: ax1.axis["left"].set_axis_direction("top") @@ -264,7 +265,7 @@ axis, while :: changes the axis_direction of only the major_ticklabels. Note that set_axis_direction in the AxisArtist level changes the -ticklabel_direction and label_direction, while chainging the +ticklabel_direction and label_direction, while changing the axis_direction of ticks, ticklabels, and axis-label does not affect them. @@ -295,11 +296,11 @@ So, in summary, * set_ticksize : size in points * TickLabels' methods (major_ticklabels and minor_ticklabels) * set_axis_direction : "left", "right", "bottom", or "top" - * set_rotation : angle with respect to the renference direction + * set_rotation : angle with respect to the reference direction * set_ha and set_va : see below * AxisLabels' methods (label) * set_axis_direction : "left", "right", "bottom", or "top" - * set_rotation : angle with respect to the renference direction + * set_rotation : angle with respect to the reference direction * set_ha and set_va @@ -329,13 +330,13 @@ Or ticklabels and axis-label :: GridHelper ========== -To actually define a curvelinear coordinate, you have to use your own +To actually define a curvilinear coordinate, you have to use your own grid helper. A generalised version of grid helper class is supplied and this class should suffice in most of cases. A user may provide two functions which defines a transformation (and its inverse pair) -from the curved coordinate to (rectlinear) image coordinate. Note that +from the curved coordinate to (rectilinear) image coordinate. Note that while ticks and grids are drawn for curved coordinate, the data -transform of the axes itself (ax.transData) is still rectlinear +transform of the axes itself (ax.transData) is still rectilinear (image) coordinate. :: @@ -404,7 +405,7 @@ required. :: ) -Again, the *transData* of the axes is still a rectlinear coordinate +Again, the *transData* of the axes is still a rectilinear coordinate (image coordinate). You may manually do conversion between two coordinates, or you may use Parasite Axes for convenience.:: @@ -447,7 +448,7 @@ Current Limitations and TODO's The code need more refinement. Here is a incomplete list of issues and TODO's * No easy way to support a user customized tick location (for - curvelinear grid). A new Locator class needs to be created. + curvilinear grid). A new Locator class needs to be created. * FloatingAxis may have coordinate limits, e.g., a floating axis of x = 0, but y only spans from 0 to 1. diff --git a/doc/mpl_toolkits/axes_grid/users/overview.rst b/doc/mpl_toolkits/axes_grid/users/overview.rst index b4d76d58a661..c2cef96d2084 100644 --- a/doc/mpl_toolkits/axes_grid/users/overview.rst +++ b/doc/mpl_toolkits/axes_grid/users/overview.rst @@ -17,19 +17,19 @@ mainly to ease displaying (multiple) images in matplotlib. 0.99. Originally, the toolkit had a single namespace of *axes_grid*. In more recent version (since svn r8226), the toolkit has divided into two separate namespace (*axes_grid1* and *axisartist*). - While *axes_grid* namespace is maintained for he backward compatibility, + While *axes_grid* namespace is maintained for the backward compatibility, use of *axes_grid1* and *axisartist* is recommended. .. warning:: *axes_grid* and *axisartist* (but not *axes_grid1*) uses - a custome Axes class (derived from the mpl's original Axes class). - As a sideeffect, some commands (mostly tick-related) do not work. + a custom Axes class (derived from the mpl's original Axes class). + As a side effect, some commands (mostly tick-related) do not work. Use *axes_grid1* to avoid this, or see how things are different in *axes_grid* and *axisartist* (LINK needed) AxesGrid toolkit has two namespaces (*axes_grid1* and *axisartist*). -*axisartist* contains custome Axes class that is meant to support for +*axisartist* contains custom Axes class that is meant to support for curvilinear grids (e.g., the world coordinate system in astronomy). Unlike mpl's original Axes class which uses Axes.xaxis and Axes.yaxis to draw ticks, ticklines and etc., Axes in axisartist uses special @@ -46,8 +46,8 @@ Axes.xaxis and Axes.yaxis may not work. See LINK for more detail. (multiple) images with matplotlib. In matplotlib, the axes location (and size) is specified in the normalized figure coordinates, which may not be ideal for displaying images that needs to have a given -aspect ratio. For example, it helps you to have a colobar whose -height always matches that of the image. `AxesGrid`_, `RGB Axes`_ and +aspect ratio. For example, it helps you to have a colorbar whose +height always matches that of the image. `ImageGrid`_, `RGB Axes`_ and `AxesDivider`_ are helper classes that deals with adjusting the location of (multiple) Axes. They provides a framework to adjust the position of multiple axes at the drawing time. `ParasiteAxes`_ @@ -76,9 +76,9 @@ used in such case. .. plot:: mpl_toolkits/axes_grid/examples/simple_axesgrid.py :include-source: -* The postion of each axes is determined at the drawing time (see +* The position of each axes is determined at the drawing time (see `AxesDivider`_), so that the size of the entire grid fits in the - given rectangle (like the aspec of axes). Note that in this example, + given rectangle (like the aspect of axes). Note that in this example, the paddings between axes are fixed even if you changes the figure size. @@ -141,7 +141,7 @@ AxesGrid takes following arguments, means the increasing direction of the axes number. *aspect* - By default (False), widths and heigths of axes in the grid are + By default (False), widths and heights of axes in the grid are scaled independently. If True, they are scaled according to their data limits (similar to aspect parameter in mpl). @@ -165,7 +165,7 @@ AxesGrid takes following arguments, | grid[1] | grid[3] | +---------+---------+ -You can also create a colorbar (or colobars). You can have colorbar +You can also create a colorbar (or colorbars). You can have colorbar for each axes (cbar_mode="each"), or you can have a single colorbar for the grid (cbar_mode="single"). The colorbar can be placed on your right, or top. The axes for each colorbar is stored as a *cbar_axes* @@ -187,7 +187,7 @@ at drawing time. While a more about the AxesDivider is (will be) explained in (yet to be written) AxesDividerGuide, direct use of the AxesDivider class will not be necessary for most users. The axes_divider module provides a helper function make_axes_locatable, -which can be useful. It takes a exisitng axes instance and create a +which can be useful. It takes a existing axes instance and create a divider for it. :: ax = subplot(1,1,1) @@ -196,7 +196,7 @@ divider for it. :: -*make_axes_locatable* returns an isntance of the AxesLocator class, +*make_axes_locatable* returns an instance of the AxesLocator class, derived from the Locator. It provides *append_axes* method that creates a new axes on the given side of ("top", "right", "bottom" and "left") of the original axes. @@ -255,7 +255,7 @@ if the host change its location (e.g., images). In most cases, you first create a host axes, which provides a few method that can be used to create parasite axes. They are *twinx*, *twiny* (which are similar to twinx and twiny in the matplotlib) and -*twin*. *twin* takes an arbitraty tranfromation that maps between the +*twin*. *twin* takes an arbitrary transformation that maps between the data coordinates of the host axes and the parasite axes. *draw* method of the parasite axes are never called. Instead, host axes collects artists in parasite axes and draw them as if they belong to @@ -292,7 +292,7 @@ tick-formatter for bottom(or left)-axis. :: -A more sophiscated example using twin. Note that if you change the +A more sophisticated example using twin. Note that if you change the x-limit in the host axes, the x-limit of the parasite axes will change accordingly. @@ -319,7 +319,7 @@ InsetLocator :mod:`mpl_toolkits.axes_grid.inset_locator` provides helper classes and functions to place your (inset) axes at the anchored position of -the parent axes, similarly to AnchoredArtis. +the parent axes, similarly to AnchoredArtist. Using :func:`mpl_toolkits.axes_grid.inset_locator.inset_axes`, you can have inset axes whose size is either fixed, or a fixed proportion @@ -359,7 +359,7 @@ represented by the inset axes. RGB Axes ~~~~~~~~ -RGBAxes is a helper clase to conveniently show RGB composite +RGBAxes is a helper class to conveniently show RGB composite images. Like ImageGrid, the location of axes are adjusted so that the area occupied by them fits in a given rectangle. Also, the xaxis and yaxis of each axes are shared. :: @@ -386,7 +386,7 @@ AxisArtist AxisArtist module provides a custom (and very experimental) Axes class, where each axis (left, right, top and bottom) have a separate -artist associated which is resposible to draw axis-line, ticks, +artist associated which is responsible to draw axis-line, ticks, ticklabels, label. Also, you can create your own axis, which can pass through a fixed position in the axes coordinate, or a fixed position in the data coordinate (i.e., the axis floats around when viewlimit @@ -407,7 +407,7 @@ To create an axes, :: ax = AA.Axes(fig, [0.1, 0.1, 0.8, 0.8]) fig.add_axes(ax) -or to creat a subplot :: +or to create a subplot :: ax = AA.Subplot(fig, 111) fig.add_subplot(ax) @@ -441,7 +441,7 @@ Or a fixed axis with some offset :: AxisArtist with ParasiteAxes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Most commands in the axes_grid toolkit1 can take a axes_class keyword +Most commands in the axes_grid1 toolkit can take a axes_class keyword argument, and the commands creates an axes of the given class. For example, to create a host subplot with axisartist.Axes, :: @@ -458,10 +458,10 @@ Here is an example that uses parasiteAxes. -Curvelinear Grid +Curvilinear Grid ---------------- -The motivation behind the AxisArtist module is to support cuvelinear grid +The motivation behind the AxisArtist module is to support curvilinear grid and ticks. .. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axis.py @@ -472,7 +472,7 @@ See :ref:`axisartist-manual` for more details. Floating Axes ------------- -This also suppport a Floating Axes whose outer axis are defined as +This also support a Floating Axes whose outer axis are defined as floating axis. .. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axes.py diff --git a/doc/mpl_toolkits/mplot3d/tutorial.rst b/doc/mpl_toolkits/mplot3d/tutorial.rst index 97a4e034a0ac..3027b4938e74 100644 --- a/doc/mpl_toolkits/mplot3d/tutorial.rst +++ b/doc/mpl_toolkits/mplot3d/tutorial.rst @@ -14,7 +14,7 @@ add a new axes to it of type :class:`~mpl_toolkits.mplot3d.Axes3D`:: import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D - fig = pyplt.figure() + fig = plt.figure() ax = fig.add_subplot(111, projection='3d') Line plots diff --git a/doc/pyplots/plotmap.py b/doc/pyplots/plotmap.py index 4da5efb5fbf3..a15dfa997fc0 100644 --- a/doc/pyplots/plotmap.py +++ b/doc/pyplots/plotmap.py @@ -1,66 +1,41 @@ -# make plot of etopo bathymetry/topography data on -# lambert conformal conic map projection, drawing coastlines, state and -# country boundaries, and parallels/meridians. - -# the data is interpolated to the native projection grid. -import os -from mpl_toolkits.basemap import Basemap, shiftgrid +from mpl_toolkits.basemap import Basemap +import matplotlib.pyplot as plt import numpy as np - -from pylab import title, colorbar, show, axes, cm, arange, figure, \ - text - -# read in topo data (on a regular lat/lon grid) -# longitudes go from 20 to 380. -# you can get this data from matplolib svn matplotlib/htdocs/screenshots/data/ -datadir = '/home/jdhunter/python/svn/matplotlib/trunk/htdocs/screenshots/data/' -if not os.path.exists(datadir): - raise SystemExit('You need to download the data with svn co https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/trunk/htdocs/screenshots/data/" and set the datadir variable in %s'%__file__) - -topoin = np.loadtxt(os.path.join(datadir, 'etopo20data.gz')) -lons = np.loadtxt(os.path.join(datadir, 'etopo20lons.gz')) -lats = np.loadtxt(os.path.join(datadir, 'etopo20lats.gz')) -# shift data so lons go from -180 to 180 instead of 20 to 380. -topoin,lons = shiftgrid(180.,topoin,lons,start=False) - -# setup of basemap ('lcc' = lambert conformal conic). -# use major and minor sphere radii from WGS84 ellipsoid. -m = Basemap(llcrnrlon=-145.5,llcrnrlat=1.,urcrnrlon=-2.566,urcrnrlat=46.352,\ - rsphere=(6378137.00,6356752.3142),\ - resolution='l',area_thresh=1000.,projection='lcc',\ - lat_1=50.,lon_0=-107.) -# transform to nx x ny regularly spaced native projection grid -nx = int((m.xmax-m.xmin)/40000.)+1; ny = int((m.ymax-m.ymin)/40000.)+1 -topodat,x,y = m.transform_scalar(topoin,lons,lats,nx,ny,returnxy=True) -# create the figure. -fig=figure(figsize=(6,6)) -# add an axes, leaving room for colorbar on the right. -ax = fig.add_axes([0.1,0.1,0.7,0.7]) -# plot image over map with imshow. -im = m.imshow(topodat,cm.jet) -# setup colorbar axes instance. -# for matplotlib 0.91 and earlier, could do l,b,w,h = ax.get_position() -# for post 0.91, pos = ax.get_position(); l,b,w,h = pos.bounds -# this works for both. -pos = ax.get_position() -l, b, w, h = getattr(pos, 'bounds', pos) -cax = axes([l+w+0.075, b, 0.05, h]) -colorbar(cax=cax) # draw colorbar -axes(ax) # make the original axes current again -# plot blue dot on boulder, colorado and label it as such. -xpt,ypt = m(-104.237,40.125) -m.plot([xpt],[ypt],'bo') -text(xpt+100000,ypt+100000,'Boulder') -# draw coastlines and political boundaries. -m.drawcoastlines() -m.drawcountries() -m.drawstates() -# draw parallels and meridians. -# label on left, right and bottom of map. -parallels = arange(0.,80,20.) -m.drawparallels(parallels,labels=[1,1,0,1]) -meridians = arange(10.,360.,30.) -m.drawmeridians(meridians,labels=[1,1,0,1]) -# set title. -title('ETOPO Topography - Lambert Conformal Conic') -show() +# create figure +fig = plt.figure(figsize=(8,8)) +# set up orthographic map projection with +# perspective of satellite looking down at 50N, 100W. +# use low resolution coastlines. +map = Basemap(projection='ortho',lat_0=50,lon_0=-100,resolution='l') +# lat/lon coordinates of five cities. +lats=[40.02,32.73,38.55,48.25,17.29] +lons=[-105.16,-117.16,-77.00,-114.21,-88.10] +cities=['Boulder, CO','San Diego, CA', + 'Washington, DC','Whitefish, MT','Belize City, Belize'] +# compute the native map projection coordinates for cities. +xc,yc = map(lons,lats) +# make up some data on a regular lat/lon grid. +nlats = 73; nlons = 145; delta = 2.*np.pi/(nlons-1) +lats = (0.5*np.pi-delta*np.indices((nlats,nlons))[0,:,:]) +lons = (delta*np.indices((nlats,nlons))[1,:,:]) +wave = 0.75*(np.sin(2.*lats)**8*np.cos(4.*lons)) +mean = 0.5*np.cos(2.*lats)*((np.sin(2.*lats))**2 + 2.) +# compute native map projection coordinates of lat/lon grid. +# (convert lons and lats to degrees first) +x, y = map(lons*180./np.pi, lats*180./np.pi) +# draw map boundary +map.drawmapboundary(color="0.9") +# draw graticule (latitude and longitude grid lines) +map.drawmeridians(np.arange(0,360,30),color="0.9") +map.drawparallels(np.arange(-90,90,30),color="0.9") +# plot filled circles at the locations of the cities. +map.plot(xc,yc,'wo') +# plot the names of five cities. +for name,xpt,ypt in zip(cities,xc,yc): + plt.text(xpt+100000,ypt+100000,name,fontsize=9,color='w') +# contour data over the map. +cs = map.contour(x,y,wave+mean,15,linewidths=1.5) +# draw blue marble image in background. +# (downsample the image by 50% for speed) +map.bluemarble(scale=0.5) +plt.show() diff --git a/doc/pyplots/tex_demo.png b/doc/pyplots/tex_demo.png index 883f22546130..8dcb9e6832b1 100644 Binary files a/doc/pyplots/tex_demo.png and b/doc/pyplots/tex_demo.png differ diff --git a/doc/users/gridspec.rst b/doc/users/gridspec.rst index 5f2b2776d993..a91e943bae14 100644 --- a/doc/users/gridspec.rst +++ b/doc/users/gridspec.rst @@ -1,4 +1,4 @@ -\.. _gridspec-guide: +.. _gridspec-guide: ************************************************ @@ -129,6 +129,16 @@ parameters are set to that of the location of the given SubplotSpec. :: .. plot:: users/plotting/examples/demo_gridspec04.py +A Complex Nested GridSpec using SubplotSpec +=========================================== + +Here's a more sophisticated example of nested gridspec where we put +a box around each cell of the outer 4x4 grid, by hiding appropriate +spines in each of the inner 3x3 grids. :: + +.. plot:: users/plotting/examples/demo_gridspec06.py + + GridSpec with Varying Cell Sizes ================================ diff --git a/doc/users/installing.rst b/doc/users/installing.rst index a0ef036b6b74..4faea15844fa 100644 --- a/doc/users/installing.rst +++ b/doc/users/installing.rst @@ -131,6 +131,17 @@ dependencies with a package manager, you may need to install the development packages (look for a "-dev" postfix) in addition to the libraries themselves. +.. note:: + + If you are on debian/ubuntu, you can get all the dependencies + required to build matplotlib with:: + + sudo apt-get build_dep python-matplotlib + + This does not build matplotlib, but it does get the install the + build dependencies, which will make building from svn easy. + + :term:`python` 2.4 (or later but not python3) matplotlib requires python 2.4 or later (`download `__) diff --git a/doc/users/mathtext.rst b/doc/users/mathtext.rst index 790114d66945..8fd934c6d598 100644 --- a/doc/users/mathtext.rst +++ b/doc/users/mathtext.rst @@ -299,6 +299,7 @@ There are long and short forms for some of them. ``\hat a`` or ``\^a`` :math:`\hat a` ``\tilde a`` or ``\~a`` :math:`\tilde a` ``\vec a`` :math:`\vec a` + ``\overline{abc}`` :math:`\overline{abc}` ============================== ================================= In addition, there are two special accents that automatically adjust diff --git a/doc/users/plotting/examples/demo_gridspec06.py b/doc/users/plotting/examples/demo_gridspec06.py new file mode 100644 index 000000000000..261668b30168 --- /dev/null +++ b/doc/users/plotting/examples/demo_gridspec06.py @@ -0,0 +1,53 @@ +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import numpy as np + +try: + from itertools import product +except ImportError: + # product is new in v 2.6 + def product(*args, **kwds): + pools = map(tuple, args) * kwds.get('repeat', 1) + result = [[]] + for pool in pools: + result = [x+[y] for x in result for y in pool] + for prod in result: + yield tuple(prod) + + +def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)): + return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) + +f = plt.figure(figsize=(8, 8)) + +# gridspec inside gridspec +outer_grid = gridspec.GridSpec(4, 4, wspace=0.0, hspace=0.0) + +for i in xrange(16): + inner_grid = gridspec.GridSpecFromSubplotSpec(3, 3, + subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0) + a, b = int(i/4)+1,i%4+1 + for j, (c, d) in enumerate(product(range(1, 4), repeat=2)): + ax = plt.Subplot(f, inner_grid[j]) + ax.plot(*squiggle_xy(a, b, c, d)) + ax.set_xticks([]) + ax.set_yticks([]) + f.add_subplot(ax) + +all_axes = f.get_axes() + +#show only the outside spines +for ax in all_axes: + for sp in ax.spines.values(): + sp.set_visible(False) + if ax.is_first_row(): + ax.spines['top'].set_visible(True) + if ax.is_last_row(): + ax.spines['bottom'].set_visible(True) + if ax.is_first_col(): + ax.spines['left'].set_visible(True) + if ax.is_last_col(): + ax.spines['right'].set_visible(True) + +plt.show() + diff --git a/doc/users/screenshots.rst b/doc/users/screenshots.rst index e3ecdcaac00a..f3853d88e930 100644 --- a/doc/users/screenshots.rst +++ b/doc/users/screenshots.rst @@ -188,13 +188,9 @@ techniques, not market analysis! Basemap demo ============ -Jeff Whitaker provided this example showing how to efficiently plot a -collection of lines over a colormap image using the -:ref:`toolkit_basemap` . Many map projections are handled via the -proj4 library: cylindrical equidistant, mercator, lambert conformal -conic, lambert azimuthal equal area, albers equal area conic and -stereographic. See the `tutorial -`_ entry on the wiki. +Jeff Whitaker's :ref:`toolkit_basemap` add-on toolkit makes it possible to plot data on many +different map projections. This example shows how to plot contours, markers and text +on an orthographic projection, with NASA's "blue marble" satellite image as a background. .. plot:: pyplots/plotmap.py diff --git a/examples/animation/animate_decay.py b/examples/animation/animate_decay.py new file mode 100644 index 000000000000..90267c605032 --- /dev/null +++ b/examples/animation/animate_decay.py @@ -0,0 +1,37 @@ +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +def data_gen(): + t = data_gen.t + cnt = 0 + while cnt < 1000: + cnt+=1 + t += 0.05 + yield t, np.sin(2*np.pi*t) * np.exp(-t/10.) +data_gen.t = 0 + +fig = plt.figure() +ax = fig.add_subplot(111) +line, = ax.plot([], [], lw=2) +ax.set_ylim(-1.1, 1.1) +ax.set_xlim(0, 5) +ax.grid() +xdata, ydata = [], [] +def run(data): + # update the data + t,y = data + xdata.append(t) + ydata.append(y) + xmin, xmax = ax.get_xlim() + + if t >= xmax: + ax.set_xlim(xmin, 2*xmax) + ax.figure.canvas.draw() + line.set_data(xdata, ydata) + + return line, + +ani = animation.FuncAnimation(fig, run, data_gen, blit=True, interval=10, + repeat=False) +plt.show() diff --git a/examples/animation/basic_example.py b/examples/animation/basic_example.py new file mode 100644 index 000000000000..72c95eb95682 --- /dev/null +++ b/examples/animation/basic_example.py @@ -0,0 +1,34 @@ +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +def update_line(num, data, line): + line.set_data(data[...,:num]) + return line, + +fig1 = plt.figure() + +data = np.random.rand(2, 25) +l, = plt.plot([], [], 'r-') +plt.xlim(0, 1) +plt.ylim(0, 1) +plt.xlabel('x') +plt.title('test') +line_ani = animation.FuncAnimation(fig1, update_line, 25, fargs=(data, l), + interval=50, blit=True) +#line_ani.save('lines.mp4') + +fig2 = plt.figure() + +x = np.arange(-9, 10) +y = np.arange(-9, 10).reshape(-1, 1) +base = np.hypot(x, y) +ims = [] +for add in np.arange(15): + ims.append((plt.pcolor(x, y, base + add, norm=plt.Normalize(0, 30)),)) + +im_ani = animation.ArtistAnimation(fig2, ims, interval=50, repeat_delay=3000, + blit=True) +#im_ani.save('im.mp4') + +plt.show() diff --git a/examples/animation/dynamic_image.py b/examples/animation/dynamic_image.py new file mode 100644 index 000000000000..e25e66b0eb33 --- /dev/null +++ b/examples/animation/dynamic_image.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +""" +An animated image +""" +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +fig = plt.figure() + +def f(x, y): + return np.sin(x) + np.cos(y) + +x = np.linspace(0, 2 * np.pi, 120) +y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1) + +im = plt.imshow(f(x, y), cmap=plt.get_cmap('jet')) + +def updatefig(*args): + global x,y + x += np.pi / 15. + y += np.pi / 20. + im.set_array(f(x,y)) + return im, + +ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True) +plt.show() diff --git a/examples/animation/dynamic_image2.py b/examples/animation/dynamic_image2.py new file mode 100644 index 000000000000..29fb4295dc82 --- /dev/null +++ b/examples/animation/dynamic_image2.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +""" +An animated image +""" +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +fig = plt.figure() + +def f(x, y): + return np.sin(x) + np.cos(y) + +x = np.linspace(0, 2 * np.pi, 120) +y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1) +# ims is a list of lists, each row is a list of artists to draw in the +# current frame; here we are just animating one artist, the image, in +# each frame +ims = [] +for i in range(60): + x += np.pi / 15. + y += np.pi / 20. + im = plt.imshow(f(x, y)) + ims.append([im]) + +ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, + repeat_delay=1000) + +ani.save('dynamic_images.mp4') + + +plt.show() diff --git a/examples/animation/histogram.py b/examples/animation/histogram.py new file mode 100644 index 000000000000..b1aa9249dff7 --- /dev/null +++ b/examples/animation/histogram.py @@ -0,0 +1,62 @@ +""" +This example shows how to use a path patch to draw a bunch of +rectangles for an animated histogram +""" +import numpy as np + +import matplotlib.pyplot as plt +import matplotlib.patches as patches +import matplotlib.path as path +import matplotlib.animation as animation + +fig = plt.figure() +ax = fig.add_subplot(111) + +# histogram our data with numpy +data = np.random.randn(1000) +n, bins = np.histogram(data, 100) + +# get the corners of the rectangles for the histogram +left = np.array(bins[:-1]) +right = np.array(bins[1:]) +bottom = np.zeros(len(left)) +top = bottom + n +nrects = len(left) + +# here comes the tricky part -- we have to set up the vertex and path +# codes arrays using moveto, lineto and closepoly + +# for each rect: 1 for the MOVETO, 3 for the LINETO, 1 for the +# CLOSEPOLY; the vert for the closepoly is ignored but we still need +# it to keep the codes aligned with the vertices +nverts = nrects*(1+3+1) +verts = np.zeros((nverts, 2)) +codes = np.ones(nverts, int) * path.Path.LINETO +codes[0::5] = path.Path.MOVETO +codes[4::5] = path.Path.CLOSEPOLY +verts[0::5,0] = left +verts[0::5,1] = bottom +verts[1::5,0] = left +verts[1::5,1] = top +verts[2::5,0] = right +verts[2::5,1] = top +verts[3::5,0] = right +verts[3::5,1] = bottom + +barpath = path.Path(verts, codes) +patch = patches.PathPatch(barpath, facecolor='green', edgecolor='yellow', alpha=0.5) +ax.add_patch(patch) + +ax.set_xlim(left[0], right[-1]) +ax.set_ylim(bottom.min(), top.max()) + +def animate(i): + # simulate new data coming in + data = np.random.randn(1000) + n, bins = np.histogram(data, 100) + top = bottom + n + verts[1::5,1] = top + verts[2::5,1] = top + +ani = animation.FuncAnimation(fig, animate, 100, repeat=False) +plt.show() diff --git a/examples/animation/README.txt b/examples/animation/old_animation/README.txt similarity index 100% rename from examples/animation/README.txt rename to examples/animation/old_animation/README.txt diff --git a/examples/animation/animate_decay_tk_blit.py b/examples/animation/old_animation/animate_decay_tk_blit.py similarity index 100% rename from examples/animation/animate_decay_tk_blit.py rename to examples/animation/old_animation/animate_decay_tk_blit.py diff --git a/examples/animation/animation_blit_fltk.py b/examples/animation/old_animation/animation_blit_fltk.py similarity index 100% rename from examples/animation/animation_blit_fltk.py rename to examples/animation/old_animation/animation_blit_fltk.py diff --git a/examples/animation/animation_blit_gtk.py b/examples/animation/old_animation/animation_blit_gtk.py similarity index 100% rename from examples/animation/animation_blit_gtk.py rename to examples/animation/old_animation/animation_blit_gtk.py diff --git a/examples/animation/animation_blit_gtk2.py b/examples/animation/old_animation/animation_blit_gtk2.py similarity index 100% rename from examples/animation/animation_blit_gtk2.py rename to examples/animation/old_animation/animation_blit_gtk2.py diff --git a/examples/animation/animation_blit_qt.py b/examples/animation/old_animation/animation_blit_qt.py similarity index 100% rename from examples/animation/animation_blit_qt.py rename to examples/animation/old_animation/animation_blit_qt.py diff --git a/examples/animation/animation_blit_qt4.py b/examples/animation/old_animation/animation_blit_qt4.py similarity index 97% rename from examples/animation/animation_blit_qt4.py rename to examples/animation/old_animation/animation_blit_qt4.py index bd52e02d718d..ee1a3826d461 100644 --- a/examples/animation/animation_blit_qt4.py +++ b/examples/animation/old_animation/animation_blit_qt4.py @@ -46,7 +46,7 @@ def timerEvent(self, evt): self.draw() self.ax_background = self.copy_from_bbox(self.ax.bbox) - self.restore_region(self.ax_background, bbox=self.ax.bbox) + self.restore_region(self.ax_background) # update the data self.sin_line.set_ydata(np.sin(self.x+self.cnt/10.0)) diff --git a/examples/animation/animation_blit_tk.py b/examples/animation/old_animation/animation_blit_tk.py similarity index 100% rename from examples/animation/animation_blit_tk.py rename to examples/animation/old_animation/animation_blit_tk.py diff --git a/examples/animation/animation_blit_wx.py b/examples/animation/old_animation/animation_blit_wx.py similarity index 100% rename from examples/animation/animation_blit_wx.py rename to examples/animation/old_animation/animation_blit_wx.py diff --git a/examples/animation/draggable_legend.py b/examples/animation/old_animation/draggable_legend.py similarity index 100% rename from examples/animation/draggable_legend.py rename to examples/animation/old_animation/draggable_legend.py diff --git a/examples/animation/dynamic_collection.py b/examples/animation/old_animation/dynamic_collection.py similarity index 100% rename from examples/animation/dynamic_collection.py rename to examples/animation/old_animation/dynamic_collection.py diff --git a/examples/animation/dynamic_image_gtkagg.py b/examples/animation/old_animation/dynamic_image_gtkagg.py similarity index 100% rename from examples/animation/dynamic_image_gtkagg.py rename to examples/animation/old_animation/dynamic_image_gtkagg.py diff --git a/examples/animation/dynamic_image_wxagg2.py b/examples/animation/old_animation/dynamic_image_wxagg2.py similarity index 100% rename from examples/animation/dynamic_image_wxagg2.py rename to examples/animation/old_animation/dynamic_image_wxagg2.py diff --git a/examples/animation/gtk_timeout.py b/examples/animation/old_animation/gtk_timeout.py similarity index 100% rename from examples/animation/gtk_timeout.py rename to examples/animation/old_animation/gtk_timeout.py diff --git a/examples/animation/histogram_tkagg.py b/examples/animation/old_animation/histogram_tkagg.py similarity index 100% rename from examples/animation/histogram_tkagg.py rename to examples/animation/old_animation/histogram_tkagg.py diff --git a/examples/animation/movie_demo.py b/examples/animation/old_animation/movie_demo.py similarity index 100% rename from examples/animation/movie_demo.py rename to examples/animation/old_animation/movie_demo.py diff --git a/examples/animation/simple_anim_gtk.py b/examples/animation/old_animation/simple_anim_gtk.py similarity index 100% rename from examples/animation/simple_anim_gtk.py rename to examples/animation/old_animation/simple_anim_gtk.py diff --git a/examples/animation/simple_anim_tkagg.py b/examples/animation/old_animation/simple_anim_tkagg.py similarity index 100% rename from examples/animation/simple_anim_tkagg.py rename to examples/animation/old_animation/simple_anim_tkagg.py diff --git a/examples/animation/simple_idle_wx.py b/examples/animation/old_animation/simple_idle_wx.py similarity index 100% rename from examples/animation/simple_idle_wx.py rename to examples/animation/old_animation/simple_idle_wx.py diff --git a/examples/animation/simple_timer_wx.py b/examples/animation/old_animation/simple_timer_wx.py similarity index 100% rename from examples/animation/simple_timer_wx.py rename to examples/animation/old_animation/simple_timer_wx.py diff --git a/examples/animation/old_animation/strip_chart_demo.py b/examples/animation/old_animation/strip_chart_demo.py new file mode 100644 index 000000000000..ac7587a261d3 --- /dev/null +++ b/examples/animation/old_animation/strip_chart_demo.py @@ -0,0 +1,72 @@ +""" +Emulate an oscilloscope. Requires the animation API introduced in +matplotlib 0.84. See +http://www.scipy.org/wikis/topical_software/Animations for an +explanation. + +This example uses gtk but does not depend on it intimately. It just +uses the idle handler to trigger events. You can plug this into a +different GUI that supports animation (GTKAgg, TkAgg, WXAgg) and use +your toolkits idle/timer functions. +""" +import gobject +import matplotlib +matplotlib.use('GTKAgg') +import numpy as np +from matplotlib.lines import Line2D + + +class Scope: + def __init__(self, ax, maxt=10, dt=0.01): + self.ax = ax + self.canvas = ax.figure.canvas + self.dt = dt + self.maxt = maxt + self.tdata = [0] + self.ydata = [0] + self.line = Line2D(self.tdata, self.ydata, animated=True) + self.ax.add_line(self.line) + self.background = None + self.canvas.mpl_connect('draw_event', self.update_background) + self.ax.set_ylim(-.1, 1.1) + self.ax.set_xlim(0, self.maxt) + + def update_background(self, event): + self.background = self.canvas.copy_from_bbox(self.ax.bbox) + + def emitter(self, p=0.01): + 'return a random value with probability p, else 0' + v = np.random.rand(1) + if v>p: return 0. + else: return np.random.rand(1) + + def update(self, *args): + if self.background is None: return True + y = self.emitter() + lastt = self.tdata[-1] + if lastt>self.tdata[0]+self.maxt: # reset the arrays + self.tdata = [self.tdata[-1]] + self.ydata = [self.ydata[-1]] + self.ax.set_xlim(self.tdata[0], self.tdata[0]+self.maxt) + self.ax.figure.canvas.draw() + + self.canvas.restore_region(self.background) + + t = self.tdata[-1] + self.dt + self.tdata.append(t) + self.ydata.append(y) + self.line.set_data(self.tdata, self.ydata) + self.ax.draw_artist(self.line) + + self.canvas.blit(self.ax.bbox) + return True + + +from pylab import figure, show + +fig = figure() +ax = fig.add_subplot(111) +scope = Scope(ax) +gobject.idle_add(scope.update) + +show() diff --git a/examples/animation/random_data.py b/examples/animation/random_data.py new file mode 100644 index 000000000000..1a31e963a246 --- /dev/null +++ b/examples/animation/random_data.py @@ -0,0 +1,18 @@ +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +fig = plt.figure() +ax = fig.add_subplot(111) +line, = ax.plot(np.random.rand(10)) +ax.set_ylim(0, 1) + +def update(data): + line.set_ydata(data) + return line, + +def data_gen(): + while True: yield np.random.rand(10) + +ani = animation.FuncAnimation(fig, update, data_gen, interval=100) +plt.show() diff --git a/examples/animation/simple_3danim.py b/examples/animation/simple_3danim.py new file mode 100644 index 000000000000..7cb69b7c5d89 --- /dev/null +++ b/examples/animation/simple_3danim.py @@ -0,0 +1,62 @@ +""" +A simple example of an animated plot... In 3D! +""" +import numpy as np +import matplotlib.pyplot as plt +import mpl_toolkits.mplot3d.axes3d as p3 +import matplotlib.animation as animation + +def Gen_RandLine(length, dims=2) : + """ + Create a line using a random walk algorithm + + length is the number of points for the line. + dims is the number of dimensions the line has. + """ + lineData = np.empty((dims, length)) + lineData[:, 0] = np.random.rand(1, dims) + for index in xrange(1, length) : + # scaling the random numbers by 0.1 so + # movement is small compared to position. + # subtraction by 0.5 is to change the range to [-0.5, 0.5] + # to allow a line to move backwards. + step = ((np.random.rand(1, dims) - 0.5) * 0.1) + lineData[:, index] = lineData[:, index-1] + step + + return lineData + +def update_lines(num, dataLines, lines) : + for line, data in zip(lines, dataLines) : + # NOTE: there is no .set_data() for 3 dim data... + line.set_data(data[0:2, :num]) + line.set_3d_properties(data[2,:num]) + return lines + +# Attaching 3D axis to the figure +fig = plt.figure() +ax = p3.Axes3D(fig) + +# Fifty lines of random 3-D lines +data = [Gen_RandLine(25, 3) for index in xrange(50)] + +# Creating fifty line objects. +# NOTE: Can't pass empty arrays into 3d version of plot() +lines = [ax.plot(dat[0, 0:1], dat[1, 0:1], dat[2, 0:1])[0] for dat in data] + +# Setting the axes properties +ax.set_xlim3d([0.0, 1.0]) +ax.set_xlabel('X') + +ax.set_ylim3d([0.0, 1.0]) +ax.set_ylabel('Y') + +ax.set_zlim3d([0.0, 1.0]) +ax.set_zlabel('Z') + +ax.set_title('3D Test') + +# Creating the Animation object +line_ani = animation.FuncAnimation(fig, update_lines, 25, fargs=(data, lines), + interval=50, blit=False) + +plt.show() diff --git a/examples/animation/simple_anim.py b/examples/animation/simple_anim.py new file mode 100644 index 000000000000..78c9cdfc3ae2 --- /dev/null +++ b/examples/animation/simple_anim.py @@ -0,0 +1,25 @@ +""" +A simple example of an animated plot +""" +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +fig = plt.figure() +ax = fig.add_subplot(111) + +x = np.arange(0, 2*np.pi, 0.01) # x-array +line, = ax.plot(x, np.sin(x)) + +def animate(i): + line.set_ydata(np.sin(x+i/10.0)) # update the data + return line, + +#Init only required for blitting to give a clean slate. +def init(): + line.set_ydata(np.ma.array(x, mask=True)) + return line, + +ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init, + interval=25, blit=True) +plt.show() diff --git a/examples/animation/strip_chart_demo.py b/examples/animation/strip_chart_demo.py index ac7587a261d3..119fac9f6719 100644 --- a/examples/animation/strip_chart_demo.py +++ b/examples/animation/strip_chart_demo.py @@ -1,72 +1,56 @@ """ Emulate an oscilloscope. Requires the animation API introduced in -matplotlib 0.84. See -http://www.scipy.org/wikis/topical_software/Animations for an -explanation. - -This example uses gtk but does not depend on it intimately. It just -uses the idle handler to trigger events. You can plug this into a -different GUI that supports animation (GTKAgg, TkAgg, WXAgg) and use -your toolkits idle/timer functions. +matplotlib 1.0 SVN. """ -import gobject import matplotlib -matplotlib.use('GTKAgg') import numpy as np from matplotlib.lines import Line2D - +import matplotlib.pyplot as plt +import matplotlib.animation as animation class Scope: - def __init__(self, ax, maxt=10, dt=0.01): + def __init__(self, ax, maxt=2, dt=0.02): self.ax = ax - self.canvas = ax.figure.canvas self.dt = dt self.maxt = maxt self.tdata = [0] self.ydata = [0] - self.line = Line2D(self.tdata, self.ydata, animated=True) + self.line = Line2D(self.tdata, self.ydata) self.ax.add_line(self.line) - self.background = None - self.canvas.mpl_connect('draw_event', self.update_background) self.ax.set_ylim(-.1, 1.1) self.ax.set_xlim(0, self.maxt) - def update_background(self, event): - self.background = self.canvas.copy_from_bbox(self.ax.bbox) - - def emitter(self, p=0.01): - 'return a random value with probability p, else 0' - v = np.random.rand(1) - if v>p: return 0. - else: return np.random.rand(1) - - def update(self, *args): - if self.background is None: return True - y = self.emitter() + def update(self, y): lastt = self.tdata[-1] - if lastt>self.tdata[0]+self.maxt: # reset the arrays + if lastt > self.tdata[0] + self.maxt: # reset the arrays self.tdata = [self.tdata[-1]] self.ydata = [self.ydata[-1]] - self.ax.set_xlim(self.tdata[0], self.tdata[0]+self.maxt) + self.ax.set_xlim(self.tdata[0], self.tdata[0] + self.maxt) self.ax.figure.canvas.draw() - self.canvas.restore_region(self.background) - t = self.tdata[-1] + self.dt self.tdata.append(t) self.ydata.append(y) self.line.set_data(self.tdata, self.ydata) - self.ax.draw_artist(self.line) - - self.canvas.blit(self.ax.bbox) - return True + return self.line, -from pylab import figure, show +def emitter(p=0.03): + 'return a random value with probability p, else 0' + while True: + v = np.random.rand(1) + if v > p: + yield 0. + else: + yield np.random.rand(1) -fig = figure() +fig = plt.figure() ax = fig.add_subplot(111) scope = Scope(ax) -gobject.idle_add(scope.update) -show() +# pass a generator in "emitter" to produce data for the update func +ani = animation.FuncAnimation(fig, scope.update, emitter, interval=10, + blit=True) + + +plt.show() diff --git a/examples/animation/subplots.py b/examples/animation/subplots.py new file mode 100644 index 000000000000..462549e658f8 --- /dev/null +++ b/examples/animation/subplots.py @@ -0,0 +1,93 @@ +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.lines import Line2D +import matplotlib.animation as animation + +# This example uses subclassing, but there is no reason that the proper function +# couldn't be set up and then use FuncAnimation. The code is long, but not +# really complex. The length is due solely to the fact that there are a total +# of 9 lines that need to be changed for the animation as well as 3 subplots +# that need initial set up. +class SubplotAnimation(animation.TimedAnimation): + def __init__(self): + fig = plt.figure() + ax1 = fig.add_subplot(1, 2, 1) + ax2 = fig.add_subplot(2, 2, 2) + ax3 = fig.add_subplot(2, 2, 4) + + self.t = np.linspace(0, 80, 400) + self.x = np.cos(2 * np.pi * self.t / 10.) + self.y = np.sin(2 * np.pi * self.t / 10.) + self.z = 10 * self.t + + ax1.set_xlabel('x') + ax1.set_ylabel('y') + self.line1 = Line2D([], [], color='black') + self.line1a = Line2D([], [], color='red', linewidth=2) + self.line1e = Line2D([], [], color='red', marker='o', markeredgecolor='r') + ax1.add_line(self.line1) + ax1.add_line(self.line1a) + ax1.add_line(self.line1e) + ax1.set_xlim(-1, 1) + ax1.set_ylim(-2, 2) + ax1.set_aspect('equal', 'datalim') + + ax2.set_xlabel('y') + ax2.set_ylabel('z') + self.line2 = Line2D([], [], color='black') + self.line2a = Line2D([], [], color='red', linewidth=2) + self.line2e = Line2D([], [], color='red', marker='o', markeredgecolor='r') + ax2.add_line(self.line2) + ax2.add_line(self.line2a) + ax2.add_line(self.line2e) + ax2.set_xlim(-1, 1) + ax2.set_ylim(0, 800) + + ax3.set_xlabel('x') + ax3.set_ylabel('z') + self.line3 = Line2D([], [], color='black') + self.line3a = Line2D([], [], color='red', linewidth=2) + self.line3e = Line2D([], [], color='red', marker='o', markeredgecolor='r') + ax3.add_line(self.line3) + ax3.add_line(self.line3a) + ax3.add_line(self.line3e) + ax3.set_xlim(-1, 1) + ax3.set_ylim(0, 800) + + animation.TimedAnimation.__init__(self, fig, interval=50, blit=True) + + def _draw_frame(self, framedata): + i = framedata + head = i - 1 + head_len = 10 + head_slice = (self.t > self.t[i] - 1.0) & (self.t < self.t[i]) + + self.line1.set_data(self.x[:i], self.y[:i]) + self.line1a.set_data(self.x[head_slice], self.y[head_slice]) + self.line1e.set_data(self.x[head], self.y[head]) + + self.line2.set_data(self.y[:i], self.z[:i]) + self.line2a.set_data(self.y[head_slice], self.z[head_slice]) + self.line2e.set_data(self.y[head], self.z[head]) + + self.line3.set_data(self.x[:i], self.z[:i]) + self.line3a.set_data(self.x[head_slice], self.z[head_slice]) + self.line3e.set_data(self.x[head], self.z[head]) + + self._drawn_artists = [self.line1, self.line1a, self.line1e, + self.line2, self.line2a, self.line2e, + self.line3, self.line3a, self.line3e] + + def new_frame_seq(self): + return iter(range(self.t.size)) + + def _init_draw(self): + lines = [self.line1, self.line1a, self.line1e, + self.line2, self.line2a, self.line2e, + self.line3, self.line3a, self.line3e] + for l in lines: + l.set_data([], []) + +ani = SubplotAnimation() +#ani.save('test_sub.mp4') +plt.show() diff --git a/examples/api/quad_bezier.py b/examples/api/quad_bezier.py index cad7379df55c..5314dfb936b2 100644 --- a/examples/api/quad_bezier.py +++ b/examples/api/quad_bezier.py @@ -16,5 +16,5 @@ ax.plot([0.75], [0.25], "ro") ax.set_title('The red point should be on the path') -plt.draw() +plt.show() diff --git a/examples/axes_grid/demo_axes_divider.py b/examples/axes_grid/demo_axes_divider.py index c40d8dac3e00..5a0652cf1052 100644 --- a/examples/axes_grid/demo_axes_divider.py +++ b/examples/axes_grid/demo_axes_divider.py @@ -27,7 +27,7 @@ def demo_locatable_axes_hard(fig1): # axes for image ax = LocatableAxes(fig1, divider.get_position()) - # axes for coloarbar + # axes for colorbar ax_cb = LocatableAxes(fig1, divider.get_position()) h = [Size.AxesX(ax), # main axes @@ -117,7 +117,7 @@ def demo(): ## PLOT 4 - # two images side by sied with fixed padding. + # two images side by side with fixed padding. ax = fig1.add_subplot(2, 2, 4) demo_images_side_by_sied(ax) diff --git a/examples/axes_grid/demo_axes_grid.py b/examples/axes_grid/demo_axes_grid.py index f6232d5ef3c8..d28f50efbd40 100644 --- a/examples/axes_grid/demo_axes_grid.py +++ b/examples/axes_grid/demo_axes_grid.py @@ -12,7 +12,7 @@ def get_demo_image(): def demo_simple_grid(fig): """ A grid of 2x2 images with 0.05 inch pad between images and only - the lower-left axes is labeld. + the lower-left axes is labeled. """ grid = AxesGrid(fig, 131, # similar to subplot(131) nrows_ncols = (2, 2), @@ -31,7 +31,7 @@ def demo_simple_grid(fig): def demo_grid_with_single_cbar(fig): """ - A grid of 2x2 images with a single colobar + A grid of 2x2 images with a single colorbar """ grid = AxesGrid(fig, 132, # similar to subplot(132) nrows_ncols = (2, 2), @@ -58,7 +58,7 @@ def demo_grid_with_single_cbar(fig): def demo_grid_with_each_cbar(fig): """ - A grid of 2x2 images. Each image has its own colobar. + A grid of 2x2 images. Each image has its own colorbar. """ grid = AxesGrid(F, 133, # similar to subplot(122) diff --git a/examples/axes_grid/demo_axes_hbox_divider.py b/examples/axes_grid/demo_axes_hbox_divider.py new file mode 100644 index 000000000000..fe72bdc14195 --- /dev/null +++ b/examples/axes_grid/demo_axes_hbox_divider.py @@ -0,0 +1,52 @@ +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.axes_grid1.axes_divider import HBoxDivider +import mpl_toolkits.axes_grid1.axes_size as Size + +def make_heights_equal(fig, rect, ax1, ax2, pad): + # pad in inches + + h1, v1 = Size.AxesX(ax1), Size.AxesY(ax1) + h2, v2 = Size.AxesX(ax2), Size.AxesY(ax2) + + pad_v = Size.Scaled(1) + pad_h = Size.Fixed(pad) + + my_divider = HBoxDivider(fig, rect, + horizontal=[h1, pad_h, h2], + vertical=[v1, pad_v, v2]) + + + ax1.set_axes_locator(my_divider.new_locator(0)) + ax2.set_axes_locator(my_divider.new_locator(2)) + + +if __name__ == "__main__": + + fig1 = plt.figure() + + arr1 = np.arange(20).reshape((4,5)) + arr2 = np.arange(20).reshape((5,4)) + + ax1 = plt.subplot(121) + ax2 = plt.subplot(122) + + ax1.imshow(arr1, interpolation="nearest") + ax2.imshow(arr2, interpolation="nearest") + + rect = 111 # subplot param for combined axes + make_heights_equal(fig1, rect, ax1, ax2, pad=0.5) # pad in inches + + for ax in [ax1, ax2]: + ax.locator_params(nbins=4) + + # annotate + ax3 = plt.axes([0.5, 0.5, 0.001, 0.001], frameon=False) + ax3.xaxis.set_visible(False) + ax3.yaxis.set_visible(False) + ax3.annotate("Location of two axes are adjusted\n so that they have equal heights\n while maintaining their aspect ratios", (0.5, 0.5), + xycoords="axes fraction", va="center", ha="center", + bbox=dict(boxstyle="round, pad=1", fc="w")) + + plt.show() + diff --git a/examples/axes_grid/demo_floating_axes.py b/examples/axes_grid/demo_floating_axes.py index 9eda9e4a2ab2..e6712ac01363 100644 --- a/examples/axes_grid/demo_floating_axes.py +++ b/examples/axes_grid/demo_floating_axes.py @@ -146,7 +146,7 @@ def setup_axes3(fig, rect): ax3, aux_ax3 = setup_axes3(fig, 133) - theta = (8 + np.random.rand(10)*(14-8))*15. # indegree + theta = (8 + np.random.rand(10)*(14-8))*15. # in degrees radius = np.random.rand(10)*14000. aux_ax3.scatter(theta, radius) diff --git a/examples/axes_grid/demo_floating_axis.py b/examples/axes_grid/demo_floating_axis.py index dc9ed3be94b3..bc8dea6b2729 100644 --- a/examples/axes_grid/demo_floating_axis.py +++ b/examples/axes_grid/demo_floating_axis.py @@ -1,5 +1,5 @@ """ -An experimental support for curvelinear grid. +An experimental support for curvilinear grid. """ diff --git a/examples/axes_grid/make_room_for_ylabel_using_axesgrid.py b/examples/axes_grid/make_room_for_ylabel_using_axesgrid.py new file mode 100644 index 000000000000..6a269a5c8f32 --- /dev/null +++ b/examples/axes_grid/make_room_for_ylabel_using_axesgrid.py @@ -0,0 +1,62 @@ +from mpl_toolkits.axes_grid1 import make_axes_locatable +from mpl_toolkits.axes_grid1.axes_divider import make_axes_area_auto_adjustable + + + +if __name__ == "__main__": + + import matplotlib.pyplot as plt + def ex1(): + plt.figure(1) + ax = plt.axes([0,0,1,1]) + # ax = plt.subplot(111) + + ax.set_yticks([0.5]) + ax.set_yticklabels(["very long label"]) + + make_axes_area_auto_adjustable(ax) + + + def ex2(): + + plt.figure(2) + ax1 = plt.axes([0,0,1,0.5]) + ax2 = plt.axes([0,0.5,1,0.5]) + + ax1.set_yticks([0.5]) + ax1.set_yticklabels(["very long label"]) + ax1.set_ylabel("Y label") + + ax2.set_title("Title") + + make_axes_area_auto_adjustable(ax1, pad=0.1, use_axes=[ax1, ax2]) + make_axes_area_auto_adjustable(ax2, pad=0.1, use_axes=[ax1, ax2]) + + def ex3(): + + fig = plt.figure(3) + ax1 = plt.axes([0,0,1,1]) + divider = make_axes_locatable(ax1) + + ax2 = divider.new_horizontal("100%", pad=0.3, sharey=ax1) + ax2.tick_params(labelleft="off") + fig.add_axes(ax2) + + divider.add_auto_adjustable_area(use_axes=[ax1], pad=0.1, + adjust_dirs=["left"]) + divider.add_auto_adjustable_area(use_axes=[ax2], pad=0.1, + adjust_dirs=["right"]) + divider.add_auto_adjustable_area(use_axes=[ax1, ax2], pad=0.1, + adjust_dirs=["top", "bottom"]) + + ax1.set_yticks([0.5]) + ax1.set_yticklabels(["very long label"]) + + ax2.set_title("Title") + ax2.set_xlabel("X - Label") + + ex1() + ex2() + ex3() + + plt.show() diff --git a/examples/misc/developer_commit_history.py b/examples/misc/developer_commit_history.py new file mode 100644 index 000000000000..759fea87a804 --- /dev/null +++ b/examples/misc/developer_commit_history.py @@ -0,0 +1,44 @@ +""" +report how many days it has been since each developer committed. You +must do an + +svn log > log.txt + +and place the output next to this file before running + +""" +import os, datetime + +import matplotlib.cbook as cbook + +todate = cbook.todate('%Y-%m-%d') +today = datetime.date.today() +if not os.path.exists('log.txt'): + print('You must place the "svn log" output into a file "log.txt"') + raise SystemExit + +parse = False + +lastd = dict() +for line in file('log.txt'): + if line.startswith('--------'): + parse = True + continue + + if parse: + parts = [part.strip() for part in line.split('|')] + developer = parts[1] + dateparts = parts[2].split(' ') + ymd = todate(dateparts[0]) + + + if developer not in lastd: + lastd[developer] = ymd + + parse = False + +dsu = [((today - lastdate).days, developer) for developer, lastdate in lastd.items()] + +dsu.sort() +for timedelta, developer in dsu: + print('%s : %d'%(developer, timedelta)) diff --git a/examples/mplot3d/contour3d_demo2.py b/examples/mplot3d/contour3d_demo2.py index 94bc66531c80..be9ab883dbe4 100644 --- a/examples/mplot3d/contour3d_demo2.py +++ b/examples/mplot3d/contour3d_demo2.py @@ -4,7 +4,7 @@ fig = plt.figure() ax = fig.gca(projection='3d') X, Y, Z = axes3d.get_test_data(0.05) -cset = ax.contour(X, Y, Z, 16, extend3d=True) +cset = ax.contour(X, Y, Z, extend3d=True) ax.clabel(cset, fontsize=9, inline=1) plt.show() diff --git a/examples/mplot3d/contourf3d_demo2.py b/examples/mplot3d/contourf3d_demo2.py new file mode 100644 index 000000000000..eb8d23776da3 --- /dev/null +++ b/examples/mplot3d/contourf3d_demo2.py @@ -0,0 +1,20 @@ +from mpl_toolkits.mplot3d import axes3d +import matplotlib.pyplot as plt + +fig = plt.figure() +ax = fig.gca(projection='3d') +X, Y, Z = axes3d.get_test_data(0.05) +ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3) +cset = ax.contourf(X, Y, Z, zdir='z', offset=-100) +cset = ax.contourf(X, Y, Z, zdir='x', offset=-40) +cset = ax.contourf(X, Y, Z, zdir='y', offset=40) + +ax.set_xlabel('X') +ax.set_xlim3d(-40, 40) +ax.set_ylabel('Y') +ax.set_ylim3d(-40, 40) +ax.set_zlabel('Z') +ax.set_zlim3d(-100, 100) + +plt.show() + diff --git a/examples/mplot3d/surface3d_radial_demo.py b/examples/mplot3d/surface3d_radial_demo.py index 8e8a3c84bd3d..938866cd07a1 100644 --- a/examples/mplot3d/surface3d_radial_demo.py +++ b/examples/mplot3d/surface3d_radial_demo.py @@ -23,5 +23,4 @@ ax.set_xlabel(r'$\phi_\mathrm{real}$') ax.set_ylabel(r'$\phi_\mathrm{im}$') ax.set_zlabel(r'$V(\phi)$') -ax.set_xticks([]) plt.show() diff --git a/examples/pylab_examples/axes_zoom_effect.py b/examples/pylab_examples/axes_zoom_effect.py index b01e2d91472a..7a4d10d0c271 100644 --- a/examples/pylab_examples/axes_zoom_effect.py +++ b/examples/pylab_examples/axes_zoom_effect.py @@ -100,21 +100,19 @@ def zoom_effect02(ax1, ax2, **kwargs): return c1, c2, bbox_patch1, bbox_patch2, p -if __name__ == "__main__": - import matplotlib.pyplot as plt +import matplotlib.pyplot as plt - plt.figure(1, figsize=(5,5)) - ax1 = plt.subplot(221) - ax2 = plt.subplot(212) - ax2.set_xlim(0, 1) - ax2.set_xlim(0, 5) - zoom_effect01(ax1, ax2, 0.2, 0.8) +plt.figure(1, figsize=(5,5)) +ax1 = plt.subplot(221) +ax2 = plt.subplot(212) +ax2.set_xlim(0, 1) +ax2.set_xlim(0, 5) +zoom_effect01(ax1, ax2, 0.2, 0.8) - ax1 = plt.subplot(222) - ax1.set_xlim(2, 3) - ax2.set_xlim(0, 5) - zoom_effect02(ax1, ax2) - - plt.show() +ax1 = plt.subplot(222) +ax1.set_xlim(2, 3) +ax2.set_xlim(0, 5) +zoom_effect02(ax1, ax2) +plt.show() diff --git a/examples/pylab_examples/broken_axis.py b/examples/pylab_examples/broken_axis.py new file mode 100644 index 000000000000..a5927d9132cd --- /dev/null +++ b/examples/pylab_examples/broken_axis.py @@ -0,0 +1,61 @@ +""" +Broken axis example, where the y-axis will have a portion cut out. +""" +import matplotlib.pylab as plt +import numpy as np + + +# 30 points between 0 0.2] originally made using np.random.rand(30)*.2 +pts = np.array([ 0.015, 0.166, 0.133, 0.159, 0.041, 0.024, 0.195, + 0.039, 0.161, 0.018, 0.143, 0.056, 0.125, 0.096, 0.094, 0.051, + 0.043, 0.021, 0.138, 0.075, 0.109, 0.195, 0.05 , 0.074, 0.079, + 0.155, 0.02 , 0.01 , 0.061, 0.008]) + +# Now let's make two outlier points which are far away from everything. +pts[[3,14]] += .8 + +# If we were to simply plot pts, we'd lose most of the interesting +# details due to the outliers. So let's 'break' or 'cut-out' the y-axis +# into two portions - use the top (ax) for the outliers, and the bottom +# (ax2) for the details of the majority of our data +f,(ax,ax2) = plt.subplots(2,1,sharex=True) + +# plot the same data on both axes +ax.plot(pts) +ax2.plot(pts) + +# zoom-in / limit the view to different portions of the data +ax.set_ylim(.78,1.) # outliers only +ax2.set_ylim(0,.22) # most of the data + +# hide the spines between ax and ax2 +ax.spines['bottom'].set_visible(False) +ax2.spines['top'].set_visible(False) +ax.xaxis.tick_top() +ax.tick_params(labeltop='off') # don't put tick labels at the top +ax2.xaxis.tick_bottom() + +# This looks pretty good, and was fairly painless, but you can get that +# cut-out diagonal lines look with just a bit more work. The important +# thing to know here is that in axes coordinates, which are always +# between 0-1, spine endpoints are at these locations (0,0), (0,1), +# (1,0), and (1,1). Thus, we just need to put the diagonals in the +# appropriate corners of each of our axes, and so long as we use the +# right transform and disable clipping. + +d = .015 # how big to make the diagonal lines in axes coordinates +# arguments to pass plot, just so we don't keep repeating them +kwargs = dict(transform=ax.transAxes, color='k', clip_on=False) +ax.plot((-d,+d),(-d,+d), **kwargs) # top-left diagonal +ax.plot((1-d,1+d),(-d,+d), **kwargs) # top-right diagonal + +kwargs.update(transform=ax2.transAxes) # switch to the bottom axes +ax2.plot((-d,+d),(1-d,1+d), **kwargs) # bottom-left diagonal +ax2.plot((1-d,1+d),(1-d,1+d), **kwargs) # bottom-right diagonal + +# What's cool about this is that now if we vary the distance between +# ax and ax2 via f.subplots_adjust(hspace=...) or plt.subplot_tool(), +# the diagonal lines will move accordingly, and stay right at the tips +# of the spines they are 'breaking' + +plt.show() diff --git a/examples/pylab_examples/image_demo3.py b/examples/pylab_examples/image_demo3.py index 46f87147f4e4..ba1c7011ae8f 100644 --- a/examples/pylab_examples/image_demo3.py +++ b/examples/pylab_examples/image_demo3.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from pylab import * try: - import Image + from PIL import Image except ImportError, exc: raise SystemExit("PIL must be installed to run this example") diff --git a/examples/pylab_examples/image_slices_viewer.py b/examples/pylab_examples/image_slices_viewer.py index c476c3dd6287..a9c1b78f472b 100644 --- a/examples/pylab_examples/image_slices_viewer.py +++ b/examples/pylab_examples/image_slices_viewer.py @@ -1,5 +1,5 @@ import numpy -from pylab import figure, show +from matplotlib.pyplot import figure, show @@ -7,7 +7,7 @@ class IndexTracker: def __init__(self, ax, X): self.ax = ax - ax.set_title('use scroll wheen to navigate images') + ax.set_title('use scroll wheel to navigate images') self.X = X rows,cols,self.slices = X.shape @@ -28,7 +28,7 @@ def onscroll(self, event): def update(self): self.im.set_data(self.X[:,:,self.ind]) - ax.set_ylabel('slice %s'%self.ind) + ax.set_ylabel('slice %s'%self.ind) self.im.axes.figure.canvas.draw() diff --git a/examples/pylab_examples/multiple_yaxis_with_spines.py b/examples/pylab_examples/multiple_yaxis_with_spines.py index 66da6241ccfa..a0051246b202 100644 --- a/examples/pylab_examples/multiple_yaxis_with_spines.py +++ b/examples/pylab_examples/multiple_yaxis_with_spines.py @@ -1,66 +1,54 @@ import matplotlib.pyplot as plt def make_patch_spines_invisible(ax): - par2.set_frame_on(True) - par2.patch.set_visible(False) - for sp in par2.spines.itervalues(): + ax.set_frame_on(True) + ax.patch.set_visible(False) + for sp in ax.spines.itervalues(): sp.set_visible(False) -def make_spine_invisible(ax, direction): - if direction in ["right", "left"]: - ax.yaxis.set_ticks_position(direction) - ax.yaxis.set_label_position(direction) - elif direction in ["top", "bottom"]: - ax.xaxis.set_ticks_position(direction) - ax.xaxis.set_label_position(direction) - else: - raise ValueError("Unknown Direction : %s" % (direction,)) +fig = plt.figure() +fig.subplots_adjust(right=0.75) - ax.spines[direction].set_visible(True) +host = fig.add_subplot(111) +par1 = host.twinx() +par2 = host.twinx() +# Offset the right spine of par2. The ticks and label have already been +# placed on the right by twinx above. +par2.spines["right"].set_position(("axes", 1.2)) +# Having been created by twinx, par2 has its frame off, so the line of its +# detached spine is invisible. First, activate the frame but make the patch +# and spines invisible. +make_patch_spines_invisible(par2) +# Second, show the right spine. +par2.spines["right"].set_visible(True) -if 1: - fig = plt.figure(1) +p1, = host.plot([0, 1, 2], [0, 1, 2], "b-", label="Density") +p2, = par1.plot([0, 1, 2], [0, 3, 2], "r-", label="Temperature") +p3, = par2.plot([0, 1, 2], [50, 30, 15], "g-", label="Velocity") - host = fig.add_subplot(111) +host.set_xlim(0, 2) +host.set_ylim(0, 2) +par1.set_ylim(0, 4) +par2.set_ylim(1, 65) - host.set_xlabel("Distance") +host.set_xlabel("Distance") +host.set_ylabel("Density") +par1.set_ylabel("Temperature") +par2.set_ylabel("Velocity") - par1 = host.twinx() - par2 = host.twinx() +host.yaxis.label.set_color(p1.get_color()) +par1.yaxis.label.set_color(p2.get_color()) +par2.yaxis.label.set_color(p3.get_color()) - par2.spines["right"].set_position(("axes", 1.2)) - make_patch_spines_invisible(par2) - make_spine_invisible(par2, "right") +tkw = dict(size=4, width=1.5) +host.tick_params(axis='y', colors=p1.get_color(), **tkw) +par1.tick_params(axis='y', colors=p2.get_color(), **tkw) +par2.tick_params(axis='y', colors=p3.get_color(), **tkw) +host.tick_params(axis='x', **tkw) - plt.subplots_adjust(right=0.75) +lines = [p1, p2, p3] +host.legend(lines, [l.get_label() for l in lines]) - p1, = host.plot([0, 1, 2], [0, 1, 2], "b-", label="Density") - p2, = par1.plot([0, 1, 2], [0, 3, 2], "r-", label="Temperature") - p3, = par2.plot([0, 1, 2], [50, 30, 15], "g-", label="Velocity") - - host.set_xlim(0, 2) - host.set_ylim(0, 2) - par1.set_ylim(0, 4) - par2.set_ylim(1, 65) - - host.set_xlabel("Distance") - host.set_ylabel("Density") - par1.set_ylabel("Temperature") - par2.set_ylabel("Velocity") - - host.yaxis.label.set_color(p1.get_color()) - par1.yaxis.label.set_color(p2.get_color()) - par2.yaxis.label.set_color(p3.get_color()) - - tkw = dict(size=4, width=1.5) - host.tick_params(axis='y', colors=p1.get_color(), **tkw) - par1.tick_params(axis='y', colors=p2.get_color(), **tkw) - par2.tick_params(axis='y', colors=p3.get_color(), **tkw) - host.tick_params(axis='x', **tkw) - - lines = [p1, p2, p3] - host.legend(lines, [l.get_label() for l in lines]) - plt.show() - +plt.show() diff --git a/examples/pylab_examples/to_numeric.py b/examples/pylab_examples/to_numeric.py index 67aff0a2731e..c58a2d4d6116 100644 --- a/examples/pylab_examples/to_numeric.py +++ b/examples/pylab_examples/to_numeric.py @@ -8,7 +8,7 @@ from pylab import * from matplotlib.backends.backend_agg import FigureCanvasAgg try: - import Image + from PIL import Image except ImportError, exc: raise SystemExit("PIL must be installed to run this example") diff --git a/examples/pylab_examples/toggle_images.py b/examples/pylab_examples/toggle_images.py index 327a91391d66..14173edb953a 100644 --- a/examples/pylab_examples/toggle_images.py +++ b/examples/pylab_examples/toggle_images.py @@ -5,7 +5,7 @@ them to the same axes with hold "on". Then, toggle the visible property of them using keypress event handling -If you want two images with sifferent shapes to be plotted with the same +If you want two images with different shapes to be plotted with the same extent, they must have the same "extent" property As usual, we'll define some random images for demo. Real data is much more diff --git a/examples/user_interfaces/histogram_demo_canvasagg.py b/examples/user_interfaces/histogram_demo_canvasagg.py index a2b368f689a6..3f99c3d1f42e 100644 --- a/examples/user_interfaces/histogram_demo_canvasagg.py +++ b/examples/user_interfaces/histogram_demo_canvasagg.py @@ -54,7 +54,7 @@ if 0: # pass off to PIL - import Image + from PIL import Image im = Image.fromstring( "RGB", (w,h), s) im.show() diff --git a/examples/widgets/radio_buttons.py b/examples/widgets/radio_buttons.py index d18cc5ec3ac5..cf14c155d68a 100644 --- a/examples/widgets/radio_buttons.py +++ b/examples/widgets/radio_buttons.py @@ -20,17 +20,17 @@ def hzfunc(label): radio.on_clicked(hzfunc) rax = axes([0.05, 0.4, 0.15, 0.15], axisbg=axcolor) -radio = RadioButtons(rax, ('red', 'blue', 'green')) +radio2 = RadioButtons(rax, ('red', 'blue', 'green')) def colorfunc(label): l.set_color(label) draw() -radio.on_clicked(colorfunc) +radio2.on_clicked(colorfunc) rax = axes([0.05, 0.1, 0.15, 0.15], axisbg=axcolor) -radio = RadioButtons(rax, ('-', '--', '-.', 'steps', ':')) +radio3 = RadioButtons(rax, ('-', '--', '-.', 'steps', ':')) def stylefunc(label): l.set_linestyle(label) draw() -radio.on_clicked(stylefunc) +radio3.on_clicked(stylefunc) show() diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 58c3321e9775..127966c1b9fe 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -99,7 +99,7 @@ """ from __future__ import generators -__version__ = '1.0.0' +__version__ = '1.1.0svn' __revision__ = '$Revision$' __date__ = '$Date$' @@ -456,6 +456,8 @@ def _get_configdir(): configdir = os.environ.get('MPLCONFIGDIR') if configdir is not None: + if not os.path.exists(configdir): + os.makedirs(configdir) if not _is_writable_dir(configdir): raise RuntimeError('Could not write to MPLCONFIGDIR="%s"'%configdir) return configdir @@ -637,7 +639,7 @@ class RcParams(dict): def __setitem__(self, key, val): try: - if key in _deprecated_map.keys(): + if key in _deprecated_map: alt = _deprecated_map[key] warnings.warn(self.msg_depr % (key, alt)) key = alt @@ -652,7 +654,7 @@ def __setitem__(self, key, val): See rcParams.keys() for a list of valid parameters.' % (key,)) def __getitem__(self, key): - if key in _deprecated_map.keys(): + if key in _deprecated_map: alt = _deprecated_map[key] warnings.warn(self.msg_depr % (key, alt)) key = alt @@ -763,12 +765,30 @@ def rc_params(fail_on_error=False): # this is the instance used by the matplotlib classes rcParams = rc_params() +if rcParams['examples.directory']: + # paths that are intended to be relative to matplotlib_fname() + # are allowed for the examples.directory parameter. + # However, we will need to fully qualify the path because + # Sphinx requires absolute paths. + if not os.path.isabs(rcParams['examples.directory']): + _basedir, _fname = os.path.split(matplotlib_fname()) + # Sometimes matplotlib_fname() can return relative paths, + # Also, using realpath() guarentees that Sphinx will use + # the same path that matplotlib sees (in case of weird symlinks). + _basedir = os.path.realpath(_basedir) + _fullpath = os.path.join(_basedir, rcParams['examples.directory']) + rcParams['examples.directory'] = _fullpath + +rcParamsOrig = rcParams.copy() + rcParamsDefault = RcParams([ (key, default) for key, (default, converter) in \ defaultParams.iteritems() ]) rcParams['ps.usedistiller'] = checkdep_ps_distiller(rcParams['ps.usedistiller']) rcParams['text.usetex'] = checkdep_usetex(rcParams['text.usetex']) + + def rc(group, **kwargs): """ Set the current rc params. Group is the grouping for the rc, eg. @@ -843,11 +863,19 @@ def rc(group, **kwargs): def rcdefaults(): """ - Restore the default rc params - the ones that were created at - matplotlib load time. + Restore the default rc params - these are not the params loaded by + the rc file, but mpl's internal params. See rc_file_defaults for + reloading the default params from the rc file """ rcParams.update(rcParamsDefault) +def rc_file_defaults(): + """ + Restore the default rc params from the original matplotlib rc that + was loaded + """ + rcParams.update(rcParamsOrig) + _use_error_msg = """ This call to matplotlib.use() has no effect because the the backend has already been chosen; matplotlib.use() must be called *before* pylab, matplotlib.pyplot, @@ -878,10 +906,11 @@ def use(arg, warn=True): if 'matplotlib.backends' in sys.modules: if warn: warnings.warn(_use_error_msg) return - arg = arg.lower() if arg.startswith('module://'): name = arg else: + # Lowercase only non-module backend names (modules are case-sensitive) + arg = arg.lower() be_parts = arg.split('.') name = validate_backend(be_parts[0]) if len(be_parts) > 1: diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py new file mode 100644 index 000000000000..9ff014d26423 --- /dev/null +++ b/lib/matplotlib/animation.py @@ -0,0 +1,473 @@ +# TODO: +# * Loop Delay is broken on GTKAgg. This is because source_remove() is not +# working as we want. PyGTK bug? +# * Documentation -- this will need a new section of the User's Guide. +# Both for Animations and just timers. +# - Also need to update http://www.scipy.org/Cookbook/Matplotlib/Animations +# * Blit +# * Currently broken with Qt4 for widgets that don't start on screen +# * Still a few edge cases that aren't working correctly +# * Can this integrate better with existing matplotlib animation artist flag? +# - If animated removes from default draw(), perhaps we could use this to +# simplify initial draw. +# * Example +# * Frameless animation - pure procedural with no loop +# * Need example that uses something like inotify or subprocess +# * Complex syncing examples +# * Movies +# * Library to make movies? +# * RC parameter for config? +# * Can blit be enabled for movies? +# * Need to consider event sources to allow clicking through multiple figures +import itertools +from matplotlib.cbook import iterable + +class Animation(object): + ''' + This class wraps the creation of an animation using matplotlib. It is + only a base class which should be subclassed to provide needed behavior. + + *fig* is the figure object that is used to get draw, resize, and any + other needed events. + + *event_source* is a class that can run a callback when desired events + are generated, as well as be stopped and started. Examples include timers + (see :class:`TimedAnimation`) and file system notifications. + + *blit* is a boolean that controls whether blitting is used to optimize + drawing. + ''' + def __init__(self, fig, event_source=None, blit=False): + self._fig = fig + self._blit = blit + + # These are the basics of the animation. The frame sequence represents + # information for each frame of the animation and depends on how the + # drawing is handled by the subclasses. The event source fires events + # that cause the frame sequence to be iterated. + self.frame_seq = self.new_frame_seq() + self.event_source = event_source + + # Clear the initial frame + self._init_draw() + + # Instead of starting the event source now, we connect to the figure's + # draw_event, so that we only start once the figure has been drawn. + self._first_draw_id = fig.canvas.mpl_connect('draw_event', self._start) + + # Connect to the figure's close_event so that we don't continue to + # fire events and try to draw to a deleted figure. + self._close_id = self._fig.canvas.mpl_connect('close_event', self._stop) + if blit: + self._setup_blit() + + def _start(self, *args): + ''' + Starts interactive animation. Adds the draw frame command to the GUI + handler, calls show to start the event loop. + ''' + # On start, we add our callback for stepping the animation and + # actually start the event_source. We also disconnect _start + # from the draw_events + self.event_source.add_callback(self._step) + self.event_source.start() + self._fig.canvas.mpl_disconnect(self._first_draw_id) + self._first_draw_id = None # So we can check on save + + def _stop(self, *args): + # On stop we disconnect all of our events. + if self._blit: + self._fig.canvas.mpl_disconnect(self._resize_id) + self._fig.canvas.mpl_disconnect(self._close_id) + self.event_source.remove_callback(self._step) + self.event_source = None + + def save(self, filename, fps=5, codec='mpeg4', clear_temp=True, + frame_prefix='_tmp'): + ''' + Saves a movie file by drawing every frame. + + *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) + self._fig.savefig(fname) + + self._make_movie(filename, fps, codec, frame_prefix) + + #Delete temporary files + if clear_temp: + import os + 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 ffmpeg_cmd(self, fname, fps, codec, frame_prefix): + # Returns the command line parameters for subprocess to use + # ffmpeg to create a movie + return ['ffmpeg', '-y', '-r', str(fps), '-b', '1800k', '-i', + '%s%%04d.png' % frame_prefix, fname] + + def mencoder_cmd(self, fname, fps, codec, frame_prefix): + # Returns the command line parameters for subprocess to use + # mencoder to create a movie + return ['mencoder', 'mf://%s*.png' % frame_prefix, '-mf', + 'type=png:fps=%d' % fps, '-ovc', 'lavc', '-lavcopts', + 'vcodec=%s' % codec, '-oac', 'copy', '-o', fname] + + def _make_movie(self, fname, fps, codec, frame_prefix, cmd_gen=None): + # Uses subprocess to call the program for assembling frames into a + # movie file. *cmd_gen* is a callable that generates the sequence + # of command line arguments from a few configuration options. + from subprocess import Popen, PIPE + if cmd_gen is None: + cmd_gen = self.ffmpeg_cmd + proc = Popen(cmd_gen(fname, fps, codec, frame_prefix), shell=False, + stdout=PIPE, stderr=PIPE) + proc.wait() + + def _step(self, *args): + ''' + Handler for getting events. By default, gets the next frame in the + sequence and hands the data off to be drawn. + ''' + # Returns True to indicate that the event source should continue to + # call _step, until the frame sequence reaches the end of iteration, + # at which point False will be returned. + try: + framedata = self.frame_seq.next() + self._draw_next_frame(framedata, self._blit) + return True + except StopIteration: + return False + + def new_frame_seq(self): + 'Creates a new sequence of frame information.' + # Default implementation is just an iterator over self._framedata + return iter(self._framedata) + + def new_saved_frame_seq(self): + 'Creates a new sequence of saved/cached frame information.' + # Default is the same as the regular frame sequence + return self.new_frame_seq() + + def _draw_next_frame(self, framedata, blit): + # Breaks down the drawing of the next frame into steps of pre- and + # post- draw, as well as the drawing of the frame itself. + self._pre_draw(framedata, blit) + self._draw_frame(framedata) + self._post_draw(framedata, blit) + + def _init_draw(self): + # Initial draw to clear the frame. Also used by the blitting code + # when a clean base is required. + pass + + def _pre_draw(self, framedata, blit): + # Perform any cleaning or whatnot before the drawing of the frame. + # This default implementation allows blit to clear the frame. + if blit: + self._blit_clear(self._drawn_artists, self._blit_cache) + + def _draw_frame(self, framedata): + # Performs actual drawing of the frame. + raise NotImplementedError('Needs to be implemented by subclasses to' + ' actually make an animation.') + + def _post_draw(self, framedata, blit): + # After the frame is rendered, this handles the actual flushing of + # the draw, which can be a direct draw_idle() or make use of the + # blitting. + if blit and self._drawn_artists: + self._blit_draw(self._drawn_artists, self._blit_cache) + else: + self._fig.canvas.draw_idle() + + # The rest of the code in this class is to facilitate easy blitting + def _blit_draw(self, artists, bg_cache): + # Handles blitted drawing, which renders only the artists given instead + # of the entire figure. + updated_ax = [] + for a in artists: + # If we haven't cached the background for this axes object, do + # so now. This might not always be reliable, but it's an attempt + # to automate the process. + if a.axes not in bg_cache: + bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox) + a.axes.draw_artist(a) + updated_ax.append(a.axes) + + # After rendering all the needed artists, blit each axes individually. + for ax in set(updated_ax): + ax.figure.canvas.blit(ax.bbox) + + def _blit_clear(self, artists, bg_cache): + # Get a list of the axes that need clearing from the artists that + # have been drawn. Grab the appropriate saved background from the + # cache and restore. + axes = set(a.axes for a in artists) + for a in axes: + a.figure.canvas.restore_region(bg_cache[a]) + + def _setup_blit(self): + # Setting up the blit requires: a cache of the background for the + # axes + self._blit_cache = dict() + self._drawn_artists = [] + self._resize_id = self._fig.canvas.mpl_connect('resize_event', + self._handle_resize) + self._post_draw(None, self._blit) + + def _handle_resize(self, *args): + # On resize, we need to disable the resize event handling so we don't + # get too many events. Also stop the animation events, so that + # we're paused. Reset the cache and re-init. Set up an event handler + # to catch once the draw has actually taken place. + self._fig.canvas.mpl_disconnect(self._resize_id) + self.event_source.stop() + self._blit_cache.clear() + self._init_draw() + self._resize_id = self._fig.canvas.mpl_connect('draw_event', self._end_redraw) + + def _end_redraw(self, evt): + # Now that the redraw has happened, do the post draw flushing and + # blit handling. Then re-enable all of the original events. + self._post_draw(None, self._blit) + self.event_source.start() + self._fig.canvas.mpl_disconnect(self._resize_id) + self._resize_id = self._fig.canvas.mpl_connect('resize_event', + self._handle_resize) + + +class TimedAnimation(Animation): + ''' + :class:`Animation` subclass that supports time-based animation, drawing + a new frame every *interval* milliseconds. + + *repeat* controls whether the animation should repeat when the sequence + of frames is completed. + + *repeat_delay* optionally adds a delay in milliseconds before repeating + the animation. + ''' + def __init__(self, fig, interval=200, repeat_delay=None, repeat=True, + event_source=None, *args, **kwargs): + # Store the timing information + self._interval = interval + self._repeat_delay = repeat_delay + self.repeat = repeat + + # If we're not given an event source, create a new timer. This permits + # sharing timers between animation objects for syncing animations. + if event_source is None: + event_source = fig.canvas.new_timer() + event_source.interval = self._interval + + Animation.__init__(self, fig, event_source=event_source, *args, **kwargs) + + def _step(self, *args): + ''' + Handler for getting events. + ''' + # Extends the _step() method for the Animation class. If + # Animation._step signals that it reached the end and we want to repeat, + # we refresh the frame sequence and return True. If _repeat_delay is + # set, change the event_source's interval to our loop delay and set the + # callback to one which will then set the interval back. + still_going = Animation._step(self, *args) + if not still_going and self.repeat: + if self._repeat_delay: + self.event_source.remove_callback(self._step) + self.event_source.add_callback(self._loop_delay) + self.event_source.interval = self._repeat_delay + self.frame_seq = self.new_frame_seq() + return True + else: + return still_going + + def _stop(self, *args): + # If we stop in the middle of a loop delay (which is relatively likely + # given the potential pause here, remove the loop_delay callback as + # well. + self.event_source.remove_callback(self._loop_delay) + Animation._stop(self) + + def _loop_delay(self, *args): + # Reset the interval and change callbacks after the delay. + self.event_source.remove_callback(self._loop_delay) + self.event_source.interval = self._interval + self.event_source.add_callback(self._step) + + +class ArtistAnimation(TimedAnimation): + ''' + Before calling this function, all plotting should have taken place + and the relevant artists saved. + + frame_info is a list, with each list entry a collection of artists that + represent what needs to be enabled on each frame. These will be disabled + for other frames. + ''' + def __init__(self, fig, artists, *args, **kwargs): + # Internal list of artists drawn in the most recent frame. + self._drawn_artists = [] + + # Use the list of artists as the framedata, which will be iterated + # over by the machinery. + self._framedata = artists + TimedAnimation.__init__(self, fig, *args, **kwargs) + + def _init_draw(self): + # Make all the artists involved in *any* frame invisible + axes = [] + for f in self.new_frame_seq(): + for artist in f: + artist.set_visible(False) + # Assemble a list of unique axes that need flushing + if artist.axes not in axes: + axes.append(artist.axes) + + # Flush the needed axes + for ax in axes: + ax.figure.canvas.draw() + + def _pre_draw(self, framedata, blit): + ''' + Clears artists from the last frame. + ''' + if blit: + # Let blit handle clearing + self._blit_clear(self._drawn_artists, self._blit_cache) + else: + # Otherwise, make all the artists from the previous frame invisible + for artist in self._drawn_artists: + artist.set_visible(False) + + def _draw_frame(self, artists): + # Save the artists that were passed in as framedata for the other + # steps (esp. blitting) to use. + self._drawn_artists = artists + + # Make all the artists from the current frame visible + for artist in artists: + artist.set_visible(True) + +class FuncAnimation(TimedAnimation): + ''' + Makes an animation by repeatedly calling a function *func*, passing in + (optional) arguments in *fargs*. + + *frames* can be a generator, an iterable, or a number of frames. + + *init_func* is a function used to draw a clear frame. If not given, the + results of drawing from the first item in the frames sequence will be + used. + ''' + def __init__(self, fig, func, frames=None ,init_func=None, fargs=None, + save_count=None, **kwargs): + if fargs: + self._args = fargs + else: + self._args = () + self._func = func + + # Amount of framedata to keep around for saving movies. This is only + # used if we don't know how many frames there will be: in the case + # of no generator or in the case of a callable. + self.save_count = save_count + + # Set up a function that creates a new iterable when needed. If nothing + # is passed in for frames, just use itertools.count, which will just + # keep counting from 0. A callable passed in for frames is assumed to + # be a generator. An iterable will be used as is, and anything else + # will be treated as a number of frames. + if frames is None: + self._iter_gen = itertools.count + elif callable(frames): + self._iter_gen = frames + elif iterable(frames): + self._iter_gen = lambda: iter(frames) + self.save_count = len(frames) + else: + self._iter_gen = lambda: iter(range(frames)) + self.save_count = frames + + # If we're passed in and using the default, set it to 100. + if self.save_count is None: + self.save_count = 100 + + self._init_func = init_func + + # Needs to be initialized so the draw functions work without checking + self._save_seq = [] + + TimedAnimation.__init__(self, fig, **kwargs) + + # Need to reset the saved seq, since right now it will contain data + # for a single frame from init, which is not what we want. + self._save_seq = [] + + def new_frame_seq(self): + # Use the generating function to generate a new frame sequence + return self._iter_gen() + + def new_saved_frame_seq(self): + # Generate an iterator for the sequence of saved data. If there are + # no saved frames, generate a new frame sequence and take the first + # save_count entries in it. + if self._save_seq: + return iter(self._save_seq) + else: + return itertools.islice(self.new_frame_seq(), self.save_count) + + def _init_draw(self): + # Initialize the drawing either using the given init_func or by + # calling the draw function with the first item of the frame sequence. + # For blitting, the init_func should return a sequence of modified + # artists. + if self._init_func is None: + self._draw_frame(self.new_frame_seq().next()) + else: + self._drawn_artists = self._init_func() + + def _draw_frame(self, framedata): + # Save the data for potential saving of movies. + self._save_seq.append(framedata) + + # Make sure to respect save_count (keep only the last save_count around) + self._save_seq = self._save_seq[-self.save_count:] + + # Call the func with framedata and args. If blitting is desired, + # func needs to return a sequence of any artists that were modified. + self._drawn_artists = self._func(framedata, *self._args) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index ef05e9200273..17cc94d83835 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -92,7 +92,11 @@ def __init__(self): self.eventson = False # fire events only if eventson self._oid = 0 # an observer id self._propobservers = {} # a dict from oids to funcs - self.axes = None + try: + self.axes = None + except AttributeError: + # Handle self.axes as a read-only property, as in Figure. + pass self._remove_method = None self._url = None self._gid = None @@ -235,13 +239,13 @@ def hitlist(self, event): """ List the children of the artist which contain the mouse event *event*. """ - import traceback L = [] try: hascursor,info = self.contains(event) if hascursor: L.append(self) except: + import traceback traceback.print_exc() print "while checking",self.__class__ diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index 60a1aea59973..4972d27170df 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -178,7 +178,11 @@ def __call__(self, *args, **kwargs): if self.axes.xaxis is not None and self.axes.yaxis is not None: xunits = kwargs.pop( 'xunits', self.axes.xaxis.units) + if self.axes.name == 'polar': + xunits = kwargs.pop( 'thetaunits', xunits ) yunits = kwargs.pop( 'yunits', self.axes.yaxis.units) + if self.axes.name == 'polar': + yunits = kwargs.pop( 'runits', yunits ) if xunits!=self.axes.xaxis.units: self.axes.xaxis.set_units(xunits) if yunits!=self.axes.yaxis.units: @@ -1559,6 +1563,8 @@ def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): # process kwargs 2nd since these will override default units if kwargs is not None: xunits = kwargs.pop( 'xunits', self.xaxis.units) + if self.name == 'polar': + xunits = kwargs.pop( 'thetaunits', xunits ) if xunits!=self.xaxis.units: #print '\tkw setting xunits', xunits self.xaxis.set_units(xunits) @@ -1568,6 +1574,8 @@ def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): self.xaxis.update_units(xdata) yunits = kwargs.pop('yunits', self.yaxis.units) + if self.name == 'polar': + yunits = kwargs.pop( 'runits', yunits ) if yunits!=self.yaxis.units: #print '\tkw setting yunits', yunits self.yaxis.set_units(yunits) @@ -2263,7 +2271,7 @@ def set_axis_bgcolor(self, color): def invert_xaxis(self): "Invert the x-axis." left, right = self.get_xlim() - self.viewLim.intervalx = (right, left) + self.set_xlim(right, left) def xaxis_inverted(self): 'Returns True if the x-axis is inverted.' @@ -2471,7 +2479,7 @@ def set_xticklabels(self, labels, fontdict=None, minor=False, **kwargs): def invert_yaxis(self): "Invert the y-axis." bottom, top = self.get_ylim() - self.viewLim.intervaly = (top, bottom) + self.set_ylim(top, bottom) def yaxis_inverted(self): 'Returns True if the y-axis is inverted.' @@ -3965,7 +3973,6 @@ def semilogx(self, *args, **kwargs): } self.set_xscale('log', **d) - self.set_yscale('linear') b = self._hold self._hold = True # we've already processed the hold l = self.plot(*args, **kwargs) @@ -4016,7 +4023,6 @@ def semilogy(self, *args, **kwargs): 'nonposy': kwargs.pop('nonposy', 'mask'), } self.set_yscale('log', **d) - self.set_xscale('linear') b = self._hold self._hold = True # we've already processed the hold l = self.plot(*args, **kwargs) @@ -5826,24 +5832,17 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, else: collection.autoscale_None() - temp_x = x - temp_y = y - - minx = np.amin(temp_x) - maxx = np.amax(temp_x) - miny = np.amin(temp_y) - maxy = np.amax(temp_y) - - w = maxx-minx - h = maxy-miny - # the pad is a little hack to deal with the fact that we don't # want to transform all the symbols whose scales are in points # to data coords to get the exact bounding box for efficiency # reasons. It can be done right if this is deemed important - padx, pady = 0.05*w, 0.05*h - corners = (minx-padx, miny-pady), (maxx+padx, maxy+pady) - self.update_datalim( corners) + # Also, only bother with this padding if there is anything to draw. + if self._xmargin < 0.05 and x.size > 0 : + self.set_xmargin(0.05) + + if self._ymargin < 0.05 and x.size > 0 : + self.set_ymargin(0.05) + self.autoscale_view() # add the collection last @@ -6305,6 +6304,13 @@ def arrow(self, x, y, dx, dy, **kwargs): .. plot:: mpl_examples/pylab_examples/arrow_demo.py """ + # Strip away units for the underlying patch since units + # do not make sense to most patch-like code + x = self.convert_xunits(x) + y = self.convert_yunits(y) + dx = self.convert_xunits(dx) + dy = self.convert_yunits(dy) + a = mpatches.FancyArrow(x, y, dx, dy, **kwargs) self.add_artist(a) return a @@ -6921,14 +6927,14 @@ def pcolor(self, *args, **kwargs): %(PolyCollection)s - Note: the default *antialiaseds* is taken from + Note: the default *antialiaseds* is False if the default + *edgecolors*="none" is used. This eliminates artificial lines + at patch boundaries, and works regardless of the value of + alpha. If *edgecolors* is not "none", then the default + *antialiaseds* is taken from rcParams['patch.antialiased'], which defaults to *True*. - In some cases, particularly if *alpha* is 1, - you may be able to reduce rendering artifacts (light or - dark patch boundaries) by setting it to *False*. An - alternative it to set *edgecolors* to 'face'. Unfortunately, - there seems to be no single combination of parameters that - eliminates artifacts under all conditions. + Stroking the edges may be preferred if *alpha* is 1, but + will cause artifacts otherwise. """ @@ -6977,21 +6983,28 @@ def pcolor(self, *args, **kwargs): C = compress(ravelmask, ma.filled(C[0:Ny-1,0:Nx-1]).ravel()) + linewidths = (0.25,) + if 'linewidth' in kwargs: + kwargs['linewidths'] = kwargs.pop('linewidth') + kwargs.setdefault('linewidths', linewidths) + if shading == 'faceted': edgecolors = 'k', else: edgecolors = 'none' - linewidths = (0.25,) - # Not sure if we want to have the following, or just trap - # invalid kwargs and raise an exception. if 'edgecolor' in kwargs: kwargs['edgecolors'] = kwargs.pop('edgecolor') - if 'linewidth' in kwargs: - kwargs['linewidths'] = kwargs.pop('linewidth') + ec = kwargs.setdefault('edgecolors', edgecolors) + + # aa setting will default via collections to patch.antialiased + # unless the boundary is not stroked, in which case the + # default will be False; with unstroked boundaries, aa + # makes artifacts that are often disturbing. if 'antialiased' in kwargs: kwargs['antialiaseds'] = kwargs.pop('antialiased') - kwargs.setdefault('edgecolors', edgecolors) - kwargs.setdefault('linewidths', linewidths) + if 'antialiaseds' not in kwargs and ec.lower() == "none": + kwargs['antialiaseds'] = False + collection = mcoll.PolyCollection(verts, **kwargs) @@ -7378,6 +7391,7 @@ def twinx(self): frameon=False) ax2.yaxis.tick_right() ax2.yaxis.set_label_position('right') + ax2.yaxis.set_offset_position('right') self.yaxis.tick_left() ax2.xaxis.set_visible(False) return ax2 @@ -7421,9 +7435,11 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, """ call signature:: - hist(x, bins=10, range=None, normed=False, cumulative=False, - bottom=None, histtype='bar', align='mid', - orientation='vertical', rwidth=None, log=False, **kwargs) + def hist(x, bins=10, range=None, normed=False, weights=None, + cumulative=False, bottom=None, histtype='bar', align='mid', + orientation='vertical', rwidth=None, log=False, + color=None, label=None, + **kwargs): Compute and draw the histogram of *x*. The return value is a tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*, @@ -7592,7 +7608,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, 'this looks transposed (shape is %d x %d)' % x.shape[::-1]) else: # multiple hist with data of different length - x = [np.array(xi) for xi in x] + x = [np.asarray(xi) for xi in x] nx = len(x) # number of datasets @@ -7615,7 +7631,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, else: raise ValueError("weights must be 1D or 2D") else: - w = [np.array(wi) for wi in weights] + w = [np.asarray(wi) for wi in weights] if len(w) != nx: raise ValueError('weights should have the same shape as x') @@ -8278,10 +8294,12 @@ def get_tightbbox(self, renderer): if self.xaxis.get_visible(): artists.append(self.xaxis.label) bbx1, bbx2 = self.xaxis.get_ticklabel_extents(renderer) + self.xaxis._update_label_position([bbx1], [bbx2]) bb.extend([bbx1, bbx2]) if self.yaxis.get_visible(): artists.append(self.yaxis.label) bby1, bby2 = self.yaxis.get_ticklabel_extents(renderer) + self.yaxis._update_label_position([bby1], [bby2]) bb.extend([bby1, bby2]) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 85e078c93332..585c1a29405b 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -262,9 +262,6 @@ def get_view_interval(self): 'return the view Interval instance for the axis this tick is ticking' raise NotImplementedError('Derived must override') - def set_view_interval(self, vmin, vmax, ignore=False): - raise NotImplementedError('Derived must override') - def _apply_params(self, **kw): switchkw = ['gridOn', 'tick1On', 'tick2On', 'label1On', 'label2On'] switches = [k for k in kw if k in switchkw] @@ -445,20 +442,6 @@ def get_view_interval(self): 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervalx - def set_view_interval(self, vmin, vmax, ignore = False): - if ignore: - self.axes.viewLim.intervalx = vmin, vmax - else: - Vmin, Vmax = self.get_view_interval() - self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) - - def get_minpos(self): - return self.axes.dataLim.minposx - - def get_data_interval(self): - 'return the Interval instance for this axis data limits' - return self.axes.dataLim.intervalx - class YTick(Tick): """ @@ -595,20 +578,6 @@ def get_view_interval(self): 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly - def set_view_interval(self, vmin, vmax, ignore = False): - if ignore: - self.axes.viewLim.intervaly = vmin, vmax - else: - Vmin, Vmax = self.get_view_interval() - self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) - - def get_minpos(self): - return self.axes.dataLim.minposy - - def get_data_interval(self): - 'return the Interval instance for this axis data limits' - return self.axes.dataLim.intervaly - class Ticker: locator = None diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 3b64bd1d080d..80741763134b 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -48,7 +48,11 @@ import matplotlib.textpath as textpath from matplotlib.path import Path - +try: + from PIL import Image + _has_pil = True +except ImportError: + _has_pil = False _backend_d = {} @@ -1758,6 +1762,42 @@ def print_svgz(self, *args, **kwargs): svg = self.switch_backends(FigureCanvasSVG) return svg.print_svgz(*args, **kwargs) + if _has_pil: + filetypes['jpg'] = filetypes['jpeg'] = 'Joint Photographic Experts Group' + def print_jpg(self, filename_or_obj, *args, **kwargs): + """ + Supported kwargs: + + *quality*: The image quality, on a scale from 1 (worst) to + 95 (best). The default is 75. Values above 95 should + be avoided; 100 completely disables the JPEG + quantization stage. + + *optimize*: If present, indicates that the encoder should + make an extra pass over the image in order to select + optimal encoder settings. + + *progressive*: If present, indicates that this image + should be stored as a progressive JPEG file. + """ + from backends.backend_agg import FigureCanvasAgg # lazy import + agg = self.switch_backends(FigureCanvasAgg) + buf, size = agg.print_to_buffer() + image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) + options = cbook.restrict_dict(kwargs, ['quality', 'optimize', + 'progressive']) + return image.save(filename_or_obj, **options) + print_jpeg = print_jpg + + filetypes['tif'] = filetypes['tiff'] = 'Tagged Image File Format' + def print_tif(self, filename_or_obj, *args, **kwargs): + from backends.backend_agg import FigureCanvasAgg # lazy import + agg = self.switch_backends(FigureCanvasAgg) + buf, size = agg.print_to_buffer() + image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) + return image.save(filename_or_obj) + print_tiff = print_tif + def get_supported_filetypes(self): return self.filetypes diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 77887243bb6c..b41f4aaee105 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -75,15 +75,18 @@ def _get_hinting_flag(self): else: return LOAD_NO_HINTING + # for filtering to work with rasterization, methods needs to be wrapped. + # maybe there is better way to do it. def draw_markers(self, *kl, **kw): - # for filtering to work with rastrization, methods needs to be wrapped. - # maybe there is better way to do it. return self._renderer.draw_markers(*kl, **kw) + def draw_path_collection(self, *kl, **kw): + return self._renderer.draw_path_collection(*kl, **kw) + def _update_methods(self): #self.draw_path = self._renderer.draw_path # see below #self.draw_markers = self._renderer.draw_markers - self.draw_path_collection = self._renderer.draw_path_collection + #self.draw_path_collection = self._renderer.draw_path_collection self.draw_quad_mesh = self._renderer.draw_quad_mesh self.draw_gouraud_triangle = self._renderer.draw_gouraud_triangle self.draw_gouraud_triangles = self._renderer.draw_gouraud_triangles @@ -326,6 +329,10 @@ def post_processing(image, dpi): post_processing is plotted (using draw_image) on it. """ + # WARNING. + # For agg_filter to work, the rendere's method need + # to overridden in the class. See draw_markers, and draw_path_collections + from matplotlib._image import fromarray width, height = int(self.width), int(self.height) @@ -445,3 +452,13 @@ def print_png(self, filename_or_obj, *args, **kwargs): renderer.width, renderer.height, filename_or_obj, self.figure.dpi) renderer.dpi = original_dpi + + def print_to_buffer(self): + FigureCanvasAgg.draw(self) + renderer = self.get_renderer() + original_dpi = renderer.dpi + renderer.dpi = self.figure.dpi + result = (renderer._renderer.buffer_rgba(0, 0), + (int(renderer.width), int(renderer.height))) + renderer.dpi = original_dpi + return result diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index a7a70b4a09dc..8d818f89c24e 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -993,8 +993,9 @@ def __init__ (self, filetypes = [], default_filetype = None ): - super (FileChooserDialog, self).__init__ (title, parent, action, - buttons) + super(FileChooserDialog, self).__init__ (title, parent, action, + buttons) + super(FileChooserDialog, self).set_do_overwrite_confirmation(True) self.set_default_response (gtk.RESPONSE_OK) if not path: path = os.getcwd() + os.sep diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index c353d3378297..99476b1e75d8 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -2,11 +2,10 @@ import os import numpy -import MacOS from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ - FigureManagerBase, FigureCanvasBase, NavigationToolbar2 + FigureManagerBase, FigureCanvasBase, NavigationToolbar2, TimerBase from matplotlib.backend_bases import ShowBase from matplotlib.cbook import maxdict @@ -16,7 +15,6 @@ from matplotlib.colors import colorConverter - from matplotlib.widgets import SubplotTool import matplotlib @@ -105,6 +103,10 @@ def new_gc(self): self.gc.set_hatch(None) return self.gc + def draw_gouraud_triangle(self, gc, points, colors, transform): + points = transform.transform(points) + gc.draw_gouraud_triangle(points, colors) + def draw_image(self, gc, x, y, im): im.flipud_out() nrows, ncols, data = im.as_rgba_str() @@ -229,7 +231,7 @@ def new_figure_manager(num, *args, **kwargs): """ Create a new figure manager instance """ - if not MacOS.WMAvailable(): + if not _macosx.verify_main_display(): import warnings warnings.warn("Python is not installed as a framework. The MacOSX backend may not work correctly if Python is not installed as a framework. Please see the Python documentation for more information on installing Python as a framework on Mac OS X") FigureClass = kwargs.pop('FigureClass', Figure) @@ -238,6 +240,24 @@ def new_figure_manager(num, *args, **kwargs): manager = FigureManagerMac(canvas, num) return manager +class TimerMac(_macosx.Timer, TimerBase): + ''' + Subclass of :class:`backend_bases.TimerBase` that uses CoreFoundation + run loops for timer events. + + Attributes: + * interval: The time between timer events in milliseconds. Default + is 1000 ms. + * single_shot: Boolean flag indicating whether this timer should + operate as single shot (run once and then stop). Defaults to False. + * callbacks: Stores list of (func, args) tuples that will be called + upon timer events. This list can be manipulated directly, or the + functions add_callback and remove_callback can be used. + ''' + # completely implemented at the C-level (in _macosx.Timer) + + + class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasBase): """ The canvas the figure renders into. Calls the draw and print fig @@ -308,6 +328,21 @@ def print_gif(self, filename, *args, **kwargs): def get_default_filetype(self): return 'png' + def new_timer(self, *args, **kwargs): + """ + Creates a new backend-specific subclass of :class:`backend_bases.Timer`. + This is useful for getting periodic events through the backend's native + event loop. Implemented only for backends with GUIs. + + optional arguments: + + *interval* + Timer interval in milliseconds + *callbacks* + Sequence of (func, args, kwargs) where func(*args, **kwargs) will + be executed by the timer every *interval*. + """ + return TimerMac(*args, **kwargs) class FigureManagerMac(_macosx.FigureManager, FigureManagerBase): """ diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 9ac73c81cf06..0527bfb85e1c 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -1386,14 +1386,41 @@ def merge_used_characters(self, other): def get_image_magnification(self): return self.image_dpi/72.0 - def draw_image(self, gc, x, y, im): + def option_scale_image(self): + """ + pdf backend support arbitrary scaling of image. + """ + return True + + def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): self.check_gc(gc) h, w = im.get_size_out() - h, w = 72.0*h/self.image_dpi, 72.0*w/self.image_dpi + + 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 + imob = self.file.imageObject(im) - self.file.output(Op.gsave, w, 0, 0, h, x, y, Op.concat_matrix, - imob, Op.use_xobject, Op.grestore) + + if transform is None: + self.file.output(Op.gsave, + w, 0, 0, h, x, y, Op.concat_matrix, + imob, Op.use_xobject, Op.grestore) + else: + tr1, tr2, tr3, tr4, tr5, tr6 = transform.to_values() + + self.file.output(Op.gsave, + tr1, tr2, tr3, tr4, tr5, tr6, Op.concat_matrix, + w, 0, 0, h, x, y, Op.concat_matrix, + imob, Op.use_xobject, Op.grestore) + def draw_path(self, gc, path, transform, rgbFace=None): self.check_gc(gc, rgbFace) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 94901e8177fb..8bbddb914203 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -1363,7 +1363,8 @@ def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): operators. The output is low-level, converting text to outlines. """ - paper_option = "-sPAPERSIZE=%s" % ptype + if eps: paper_option = "-dEPSCrop" + else: paper_option = "-sPAPERSIZE=%s" % ptype psfile = tmpfile + '.ps' outfile = tmpfile + '.output' @@ -1385,14 +1386,6 @@ def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): shutil.move(psfile, tmpfile) - # While it is best if above steps preserve the original bounding - # box, it does not seems to be the case. pstoeps not only convert - # the input to eps format, but also restores the original bbox. - - if eps: - pstoeps(tmpfile, bbox, rotated=rotated) - - def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): """ Use ghostscript's ps2pdf and xpdf's/poppler's pdftops to distill a file. @@ -1432,17 +1425,9 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): os.remove(tmpfile) shutil.move(psfile, tmpfile) - - # Similar to the gs_distillier case, ps2pdf does not seem to - # preserve the bbox of the original file (at least w/ gs - # 8.61). Thus, the original bbox need to be resotred. - - if eps: - pstoeps(tmpfile, bbox, rotated) for fname in glob.glob(tmpfile+'.*'): os.remove(fname) - def get_bbox_header(lbrt, rotated=False): """ return a postscript header stringfor the given bbox lbrt=(l, b, r, t). @@ -1559,6 +1544,8 @@ def pstoeps(tmpfile, bbox, rotated=False): if rcParams['ps.usedistiller'] == 'xpdf': # remove extraneous "end" operator: line = tmph.readline() + elif line.startswith('%%PageBoundingBox'): + pass else: epsh.write(line) line = tmph.readline() diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 7c2d22c956f1..c31bb7b054df 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -18,7 +18,7 @@ import matplotlib.backends.qt4_editor.figureoptions as figureoptions try: - from PyQt4 import QtCore, QtGui, Qt + from PyQt4 import QtCore, QtGui except ImportError: raise ImportError("Qt4 backend requires that PyQt4 is installed.") @@ -50,11 +50,16 @@ def _create_qApp(): if QtGui.QApplication.startingUp(): if DEBUG: print "Starting up QApplication" global qApp - qApp = QtGui.QApplication( [" "] ) - QtCore.QObject.connect( qApp, QtCore.SIGNAL( "lastWindowClosed()" ), - qApp, QtCore.SLOT( "quit()" ) ) - #remember that matplotlib created the qApp - will be used by show() - _create_qApp.qAppCreatedHere = True + app = QtGui.QApplication.instance() + if app is None: + qApp = QtGui.QApplication( [" "] ) + QtCore.QObject.connect( qApp, QtCore.SIGNAL( "lastWindowClosed()" ), + qApp, QtCore.SLOT( "quit()" ) ) + #remember that matplotlib created the qApp - will be used by show() + _create_qApp.qAppCreatedHere = True + else: + qApp = app + _create_qApp.qAppCreatedHere = False _create_qApp.qAppCreatedHere = False @@ -182,7 +187,7 @@ def wheelEvent( self, event ): y = self.figure.bbox.height - event.y() # from QWheelEvent::delta doc steps = event.delta()/120 - if (event.orientation() == Qt.Qt.Vertical): + if (event.orientation() == QtCore.Qt.Vertical): FigureCanvasBase.scroll_event( self, x, y, steps) if DEBUG: print 'scroll event : delta = %i, steps = %i ' % (event.delta(),steps) @@ -243,7 +248,7 @@ def new_timer(self, *args, **kwargs): return TimerQT(*args, **kwargs) def flush_events(self): - Qt.qApp.processEvents() + QtGui.qApp.processEvents() def start_event_loop(self,timeout): FigureCanvasBase.start_event_loop_default(self,timeout) @@ -267,13 +272,13 @@ def idle_draw(*args): # http://old.nabble.com/Qt4-backend:-critical-bug-with-PyQt4-v4.6%2B-td26205716.html # Once a release of Qt/PyQt is available without the bug, the version check # below can be tightened further to only be applied in the necessary versions. -if Qt.PYQT_VERSION_STR.startswith('4.6'): +if QtCore.PYQT_VERSION_STR.startswith('4.6'): class FigureWindow(QtGui.QMainWindow): def __init__(self): super(FigureWindow, self).__init__() def closeEvent(self, event): super(FigureWindow, self).closeEvent(event) - self.emit(Qt.SIGNAL('destroyed()')) + self.emit(QtCore.SIGNAL('destroyed()')) else: FigureWindow = QtGui.QMainWindow # /end pyqt hackish bugfix @@ -450,7 +455,7 @@ def edit_parameters(self): text += ": "+ylabel text += " (%s)" elif ylabel: - text = "%s (%s)" % ylabel + text = "%%s (%s)" % ylabel else: text = "%s" titles.append(text % repr(axes)) diff --git a/lib/matplotlib/backends/backend_qt4agg.py b/lib/matplotlib/backends/backend_qt4agg.py index 89d9f4e63a4d..d9f5090e5d44 100644 --- a/lib/matplotlib/backends/backend_qt4agg.py +++ b/lib/matplotlib/backends/backend_qt4agg.py @@ -110,7 +110,7 @@ def paintEvent( self, e ): w = int(r) - int(l) h = int(t) - int(b) t = int(b) + h - reg = self.copy_from_bbox(bbox) + reg = FigureCanvasAgg.copy_from_bbox(self, bbox) stringBuffer = reg.to_string_argb() qImage = QtGui.QImage(stringBuffer, w, h, QtGui.QImage.Format_ARGB32) pixmap = QtGui.QPixmap.fromImage(qImage) @@ -127,7 +127,6 @@ def draw( self ): if DEBUG: print "FigureCanvasQtAgg.draw", self self.replot = True - FigureCanvasAgg.draw(self) self.update() def blit(self, bbox=None): @@ -140,6 +139,16 @@ def blit(self, bbox=None): t = b + h self.repaint(l, self.renderer.height-t, w, h) + def copy_from_bbox(self, *args): + """ + If a draw() has been called but the update() has not + occurred, draw into the agg canvas before copying. + """ + if self.replot: + FigureCanvasAgg.draw(self) + self.replot = False + return FigureCanvasAgg.copy_from_bbox(self, *args) + def print_figure(self, *args, **kwargs): FigureCanvasAgg.print_figure(self, *args, **kwargs) self.draw() diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 0942f83f1c5f..61d27f6506d2 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -603,7 +603,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath): if rcParams['svg.embed_char_paths']: new_chars = [] for c in s: - path = self._add_char_def(prop, c) + path = self._add_char_def(prop, ord(c)) if path is not None: new_chars.append(path) if len(new_chars): @@ -628,7 +628,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath): lastgind = None currx = 0 for c in s: - charnum = self._get_char_def_id(prop, c) + charnum = self._get_char_def_id(prop, ord(c)) ccode = ord(c) gind = cmap.get(ccode) if gind is None: @@ -680,13 +680,13 @@ def _add_char_def(self, prop, char): font = prop font.set_size(self.FONT_SCALE, 72) ps_name = font.get_sfnt()[(1,0,0,6)] - char_id = urllib.quote('%s-%d' % (ps_name, ord(char))) + char_id = urllib.quote('%s-%d' % (ps_name, char)) char_num = self._char_defs.get(char_id, None) if char_num is not None: return None path_data = [] - glyph = font.load_char(ord(char), flags=LOAD_NO_HINTING) + glyph = font.load_char(char, flags=LOAD_NO_HINTING) currx, curry = 0.0, 0.0 for step in glyph.path: if step[0] == 0: # MOVE_TO @@ -724,7 +724,7 @@ def _get_char_def_id(self, prop, char): font = prop font.set_size(self.FONT_SCALE, 72) ps_name = font.get_sfnt()[(1,0,0,6)] - char_id = urllib.quote('%s-%d' % (ps_name, ord(char))) + char_id = urllib.quote('%s-%d' % (ps_name, char)) return self._char_defs[char_id] def _draw_mathtext(self, gc, x, y, s, prop, angle): @@ -742,8 +742,8 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle): if rcParams['svg.embed_char_paths']: new_chars = [] - for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: - path = self._add_char_def(font, thetext) + for font, fontsize, char, new_x, new_y_mtc, metrics in svg_glyphs: + path = self._add_char_def(font, char) if path is not None: new_chars.append(path) if len(new_chars): @@ -760,8 +760,8 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle): svg.append('translate(%f,%f)' % (x, y)) svg.append('">\n') - for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: - charid = self._get_char_def_id(font, thetext) + for font, fontsize, char, new_x, new_y_mtc, metrics in svg_glyphs: + charid = self._get_char_def_id(font, char) svg.append('\n' % (charid, new_x, -new_y_mtc, fontsize / self.FONT_SCALE)) @@ -860,7 +860,7 @@ def print_svg(self, filename, *args, **kwargs): if is_string_like(filename): fh_to_close = svgwriter = codecs.open(filename, 'w', 'utf-8') elif is_writable_file_like(filename): - svgwriter = codecs.EncodedFile(filename, 'utf-8') + svgwriter = codecs.getwriter('utf-8')(filename) fh_to_close = None else: raise ValueError("filename must be a path or a file-like object") @@ -869,10 +869,10 @@ def print_svg(self, filename, *args, **kwargs): def print_svgz(self, filename, *args, **kwargs): if is_string_like(filename): gzipwriter = gzip.GzipFile(filename, 'w') - fh_to_close = svgwriter = codecs.EncodedFile(gzipwriter, 'utf-8') + fh_to_close = svgwriter = codecs.getwriter('utf-8')(gzipwriter) elif is_writable_file_like(filename): fh_to_close = gzipwriter = gzip.GzipFile(fileobj=filename, mode='w') - svgwriter = codecs.EncodedFile(gzipwriter, 'utf-8') + svgwriter = codecs.getwriter('utf-8')(gzipwriter) else: raise ValueError("filename must be a path or a file-like object") return self._print_svg(filename, svgwriter, fh_to_close) diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index 9c07cbc954af..1f6d5d8dc7cc 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -101,8 +101,10 @@ class TimerTk(TimerBase): def __init__(self, parent, *args, **kwargs): TimerBase.__init__(self, *args, **kwargs) self.parent = parent + self._timer = None def _timer_start(self): + self._timer_stop() self._timer = self.parent.after(self._interval, self._on_timer) def _timer_stop(self): @@ -213,18 +215,6 @@ def filter_destroy(evt): self._master = master self._tkcanvas.focus_set() - # a dict from func-> cbook.Scheduler threads - self.sourced = dict() - - # call the idle handler - def on_idle(*ignore): - self.idle_event() - return True - - # disable until you figure out how to handle threads and interrupts - #t = cbook.Idle(on_idle) - #self._tkcanvas.after_idle(lambda *ignore: t.start()) - def resize(self, event): width, height = event.width, event.height if self._resize_callback is not None: diff --git a/lib/matplotlib/backends/backend_wxagg.py b/lib/matplotlib/backends/backend_wxagg.py index a1f406f0fb74..de2b016bb319 100644 --- a/lib/matplotlib/backends/backend_wxagg.py +++ b/lib/matplotlib/backends/backend_wxagg.py @@ -128,78 +128,12 @@ def new_figure_manager(num, *args, **kwargs): return figmgr -# -# agg/wxPython image conversion functions (wxPython <= 2.6) -# - -def _py_convert_agg_to_wx_image(agg, bbox): - """ - Convert the region of the agg buffer bounded by bbox to a wx.Image. If - bbox is None, the entire buffer is converted. - - Note: agg must be a backend_agg.RendererAgg instance. - """ - image = wx.EmptyImage(int(agg.width), int(agg.height)) - image.SetData(agg.tostring_rgb()) - - if bbox is None: - # agg => rgb -> image - return image - else: - # agg => rgb -> image => bitmap => clipped bitmap => image - return wx.ImageFromBitmap(_clipped_image_as_bitmap(image, bbox)) - - -def _py_convert_agg_to_wx_bitmap(agg, bbox): - """ - Convert the region of the agg buffer bounded by bbox to a wx.Bitmap. If - bbox is None, the entire buffer is converted. - - Note: agg must be a backend_agg.RendererAgg instance. - """ - if bbox is None: - # agg => rgb -> image => bitmap - return wx.BitmapFromImage(_py_convert_agg_to_wx_image(agg, None)) - else: - # agg => rgb -> image => bitmap => clipped bitmap - return _clipped_image_as_bitmap( - _py_convert_agg_to_wx_image(agg, None), - bbox) - - -def _clipped_image_as_bitmap(image, bbox): - """ - Convert the region of a wx.Image bounded by bbox to a wx.Bitmap. - """ - l, b, width, height = bbox.bounds - r = l + width - t = b + height - - srcBmp = wx.BitmapFromImage(image) - srcDC = wx.MemoryDC() - srcDC.SelectObject(srcBmp) - - destBmp = wx.EmptyBitmap(int(width), int(height)) - destDC = wx.MemoryDC() - destDC.SelectObject(destBmp) - - destDC.BeginDrawing() - x = int(l) - y = int(image.GetHeight() - t) - destDC.Blit(0, 0, int(width), int(height), srcDC, x, y) - destDC.EndDrawing() - - srcDC.SelectObject(wx.NullBitmap) - destDC.SelectObject(wx.NullBitmap) - - return destBmp - # # agg/wxPython image conversion functions (wxPython >= 2.8) # -def _py_WX28_convert_agg_to_wx_image(agg, bbox): +def _convert_agg_to_wx_image(agg, bbox): """ Convert the region of the agg buffer bounded by bbox to a wx.Image. If bbox is None, the entire buffer is converted. @@ -216,7 +150,7 @@ def _py_WX28_convert_agg_to_wx_image(agg, bbox): return wx.ImageFromBitmap(_WX28_clipped_agg_as_bitmap(agg, bbox)) -def _py_WX28_convert_agg_to_wx_bitmap(agg, bbox): +def _convert_agg_to_wx_bitmap(agg, bbox): """ Convert the region of the agg buffer bounded by bbox to a wx.Bitmap. If bbox is None, the entire buffer is converted. @@ -262,34 +196,3 @@ def _WX28_clipped_agg_as_bitmap(agg, bbox): return destBmp - -def _use_accelerator(state): - """ - Enable or disable the WXAgg accelerator, if it is present and is also - compatible with whatever version of wxPython is in use. - """ - global _convert_agg_to_wx_image - global _convert_agg_to_wx_bitmap - - if getattr(wx, '__version__', '0.0')[0:3] < '2.8': - # wxPython < 2.8, so use the C++ accelerator or the Python routines - if state and _wxagg is not None: - _convert_agg_to_wx_image = _wxagg.convert_agg_to_wx_image - _convert_agg_to_wx_bitmap = _wxagg.convert_agg_to_wx_bitmap - else: - _convert_agg_to_wx_image = _py_convert_agg_to_wx_image - _convert_agg_to_wx_bitmap = _py_convert_agg_to_wx_bitmap - else: - # wxPython >= 2.8, so use the accelerated Python routines - _convert_agg_to_wx_image = _py_WX28_convert_agg_to_wx_image - _convert_agg_to_wx_bitmap = _py_WX28_convert_agg_to_wx_bitmap - - -# try to load the WXAgg accelerator -try: - import _wxagg -except ImportError: - _wxagg = None - -# if it's present, use it -_use_accelerator(True) diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index 0accdbbdade9..5805249b91f6 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -272,7 +272,11 @@ def setup(self): field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QCheckBox(self) - field.setCheckState(Qt.Checked if value else Qt.Unchecked) + if value: + field.setCheckState(Qt.Checked) + else: + field.setCheckedState(Qt.Unchecked) + elif isinstance(value, float): field = QLineEdit(repr(value), self) elif isinstance(value, int): diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index e3dc292c2205..5ffa48f5ed4e 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -1224,6 +1224,12 @@ def reverse_dict(d): 'reverse the dictionary -- may lose data if values are not unique!' return dict([(v,k) for k,v in d.items()]) +def restrict_dict(d, keys): + """ + Return a dictionary that contains those keys that appear in both + d and keys, with values from d. + """ + return dict([(k,v) for (k,v) in d.iteritems() if k in keys]) def report_memory(i=0): # argument may go away 'return the memory consumed by process' @@ -1241,7 +1247,18 @@ def report_memory(i=0): # argument may go away a2 = Popen('ps -p %d -o rss,vsz' % pid, shell=True, stdout=PIPE).stdout.readlines() mem = int(a2[1].split()[0]) - + elif sys.platform.startswith('win'): + try: + a2 = Popen(["tasklist", "/nh", "/fi", "pid eq %d" % pid], + stdout=PIPE).stdout.read() + except OSError: + raise NotImplementedError( + "report_memory works on Windows only if " + "the 'tasklist' program is found") + mem = int(a2.strip().split()[-2].replace(',','')) + else: + raise NotImplementedError( + "We don't have a memory monitor for %s" % sys.platform) return mem _safezip_msg = 'In safezip, len(args[0])=%d but len(args[%d])=%d' diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index a35ceb8c8075..d89bbeb587fb 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -25,6 +25,7 @@ def freversed(x): return freversed def revcmap(data): + """Can only handle specification *data* in dictionary format.""" data_r = {} for key, val in data.iteritems(): if callable(val): @@ -39,32 +40,51 @@ def revcmap(data): data_r[key] = valnew return data_r +def _reverse_cmap_spec(spec): + """Reverses cmap specification *spec*, can handle both dict and tuple + type specs.""" + + if 'red' in spec: + return revcmap(spec) + else: + revspec = list(reversed(spec)) + if len(revspec[0]) == 2: # e.g., (1, (1.0, 0.0, 1.0)) + revspec = [(1.0 - a, b) for a, b in revspec] + return revspec + +def _generate_cmap(name, lutsize): + """Generates the requested cmap from it's name *name*. The lut size is + *lutsize*.""" + + spec = datad[name] + + # Generate the colormap object. + if 'red' in spec: + return colors.LinearSegmentedColormap(name, spec, lutsize) + else: + return colors.LinearSegmentedColormap.from_list(spec, spec, lutsize) + LUTSIZE = mpl.rcParams['image.lut'] _cmapnames = datad.keys() # need this list because datad is changed in loop +# Generate the reversed specifications ... + for cmapname in _cmapnames: - cmapname_r = cmapname+'_r' - cmapspec = datad[cmapname] - if 'red' in cmapspec: - datad[cmapname_r] = revcmap(cmapspec) - cmap_d[cmapname] = colors.LinearSegmentedColormap( - cmapname, cmapspec, LUTSIZE) - cmap_d[cmapname_r] = colors.LinearSegmentedColormap( - cmapname_r, datad[cmapname_r], LUTSIZE) - else: - revspec = list(reversed(cmapspec)) - if len(revspec[0]) == 2: # e.g., (1, (1.0, 0.0, 1.0)) - revspec = [(1.0 - a, b) for a, b in revspec] - datad[cmapname_r] = revspec + spec = datad[cmapname] + spec_reversed = _reverse_cmap_spec(spec) + datad[cmapname + '_r'] = spec_reversed + +# Precache the cmaps with ``lutsize = LUTSIZE`` ... - cmap_d[cmapname] = colors.LinearSegmentedColormap.from_list( - cmapname, cmapspec, LUTSIZE) - cmap_d[cmapname_r] = colors.LinearSegmentedColormap.from_list( - cmapname_r, revspec, LUTSIZE) +# Use datad.keys() to also add the reversed ones added in the section above: +for cmapname in datad.keys(): + cmap_d[cmapname] = _generate_cmap(cmapname, LUTSIZE) locals().update(cmap_d) +# Continue with definitions ... + def register_cmap(name=None, cmap=None, data=None, lut=None): """ Add a colormap to the set recognized by :func:`get_cmap`. @@ -128,7 +148,7 @@ def get_cmap(name=None, lut=None): if lut is None: return cmap_d[name] elif name in datad: - return colors.LinearSegmentedColormap(name, datad[name], lut) + return _generate_cmap(name, lut) else: raise ValueError("Colormap %s is not recognized" % name) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 6a93ccbc27d9..d764d99893c2 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -59,6 +59,8 @@ class Collection(artist.Artist, cm.ScalarMappable): scalar mappable will be made to set the face colors. """ _offsets = np.array([], np.float_) + # _offsets must be a Nx2 array! + _offsets.shape = (0, 2) _transOffset = transforms.IdentityTransform() _transforms = [] @@ -95,10 +97,11 @@ def __init__(self, self._uniform_offsets = None self._offsets = np.array([], np.float_) + # Force _offsets to be Nx2 + self._offsets.shape = (0, 2) if offsets is not None: offsets = np.asarray(offsets) - if len(offsets.shape) == 1: - offsets = offsets[np.newaxis,:] # Make it Nx2. + offsets.shape = (-1, 2) # Make it Nx2 if transOffset is not None: self._offsets = offsets self._transOffset = transOffset @@ -148,13 +151,17 @@ def get_datalim(self, transData): transOffset = self._transOffset offsets = self._offsets paths = self.get_paths() + + if not transform.is_affine: paths = [transform.transform_path_non_affine(p) for p in paths] transform = transform.get_affine() if not transOffset.is_affine: offsets = transOffset.transform_non_affine(offsets) transOffset = transOffset.get_affine() + offsets = np.asarray(offsets, np.float_) + offsets.shape = (-1, 2) # Make it Nx2 result = mpath.get_path_collection_extents( transform.frozen(), paths, self.get_transforms(), @@ -176,6 +183,7 @@ def _prepare_points(self): offsets = self._offsets paths = self.get_paths() + if self.have_units(): paths = [] for path in self.get_paths(): @@ -184,17 +192,19 @@ def _prepare_points(self): xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) paths.append(mpath.Path(zip(xs, ys), path.codes)) - if len(self._offsets): - xs = self.convert_xunits(self._offsets[:,0]) - ys = self.convert_yunits(self._offsets[:,1]) + + if offsets.size > 0: + xs = self.convert_xunits(offsets[:,0]) + ys = self.convert_yunits(offsets[:,1]) offsets = zip(xs, ys) offsets = np.asarray(offsets, np.float_) + offsets.shape = (-1, 2) # Make it Nx2 if not transform.is_affine: paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() - if not transOffset.is_affine: + if not transOffset.is_affine : offsets = transOffset.transform_non_affine(offsets) transOffset = transOffset.get_affine() @@ -258,8 +268,7 @@ def set_offsets(self, offsets): ACCEPTS: float or sequence of floats """ offsets = np.asarray(offsets, np.float_) - if len(offsets.shape) == 1: - offsets = offsets[np.newaxis,:] # Make it Nx2. + offsets.shape = (-1, 2) # Make it Nx2 #This decision is based on how they are initialized above if self._uniform_offsets is None: self._offsets = offsets @@ -428,13 +437,17 @@ def set_edgecolor(self, c): self._is_stroked = False except AttributeError: pass - if c == 'face': - self._edgecolors = 'face' - self._edgecolors_original = 'face' - else: - if c is None: c = mpl.rcParams['patch.edgecolor'] - self._edgecolors_original = c - self._edgecolors = mcolors.colorConverter.to_rgba_array(c, self._alpha) + try: + if c.lower() == 'face': + self._edgecolors = 'face' + self._edgecolors_original = 'face' + return + except AttributeError: + pass + if c is None: + c = mpl.rcParams['patch.edgecolor'] + self._edgecolors_original = c + self._edgecolors = mcolors.colorConverter.to_rgba_array(c, self._alpha) def set_edgecolors(self, c): @@ -479,9 +492,12 @@ def update_scalarmappable(self): If the scalar mappable array is not none, update colors from scalar data """ - if self._A is None: return + if self._A is None: + return if self._A.ndim > 1: raise ValueError('Collections can only map rank 1 arrays') + if not self.check_update("array"): + return if self._is_filled: self._facecolors = self.to_rgba(self._A, self._alpha) elif self._is_stroked: @@ -807,7 +823,7 @@ def __init__(self, segments, # Can be None. The default is 5 pt. The use of :class:`~matplotlib.cm.ScalarMappable` is optional. - If the :class:`~matplotlib.cm.ScalarMappable` matrix + If the :class:`~matplotlib.cm.ScalarMappable` array :attr:`~matplotlib.cm.ScalarMappable._A` is not None (ie a call to :meth:`~matplotlib.cm.ScalarMappable.set_array` has been made), at draw time a call to scalar mappable will be made to set the colors. @@ -1214,9 +1230,9 @@ def draw(self, renderer): offsets = zip(xs, ys) offsets = np.asarray(offsets, np.float_) + offsets.shape = (-1, 2) # Make it Nx2 - if self.check_update('array'): - self.update_scalarmappable() + self.update_scalarmappable() if not transform.is_affine: coordinates = self._coordinates.reshape( diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index eb2f44557eb3..42d43d8b7a34 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -509,27 +509,36 @@ def __call__(self, X, alpha=None, bytes=False): xa = np.array([X]) else: vtype = 'array' - # force a copy here -- the ma.array and filled functions - # do force a cop of the data by default - JDH - xma = ma.array(X, copy=True) - xa = xma.filled(0) - mask_bad = ma.getmask(xma) + xma = ma.array(X, copy=False) + mask_bad = xma.mask + xa = xma.data.copy() # Copy here to avoid side effects. + del xma + # masked values are substituted below; no need to fill them here + if xa.dtype.char in np.typecodes['Float']: np.putmask(xa, xa==1.0, 0.9999999) #Treat 1.0 as slightly less than 1. # The following clip is fast, and prevents possible # conversion of large positive values to negative integers. + xa *= self.N if NP_CLIP_OUT: - np.clip(xa * self.N, -1, self.N, out=xa) + np.clip(xa, -1, self.N, out=xa) else: - xa = np.clip(xa * self.N, -1, self.N) + xa = np.clip(xa, -1, self.N) + + # ensure that all 'under' values will still have negative + # value after casting to int + np.putmask(xa, xa<0.0, -1) xa = xa.astype(int) # Set the over-range indices before the under-range; # otherwise the under-range values get converted to over-range. np.putmask(xa, xa>self.N-1, self._i_over) np.putmask(xa, xa<0, self._i_under) - if mask_bad is not None and mask_bad.shape == xa.shape: - np.putmask(xa, mask_bad, self._i_bad) + if mask_bad is not None: + if mask_bad.shape == xa.shape: + np.putmask(xa, mask_bad, self._i_bad) + elif mask_bad: + xa.fill(self._i_bad) if bytes: lut = (self._lut * 255).astype(np.uint8) else: @@ -538,6 +547,8 @@ def __call__(self, X, alpha=None, bytes=False): if alpha is not None: alpha = min(alpha, 1.0) # alpha must be between 0 and 1 alpha = max(alpha, 0.0) + if bytes: + alpha = int(alpha * 255) if (lut[-1] == 0).all(): lut[:-1, -1] = alpha # All zeros is taken as a flag for the default bad @@ -793,32 +804,63 @@ def __init__(self, vmin=None, vmax=None, clip=False): self.vmax = vmax self.clip = clip + @staticmethod + def process_value(value): + """ + Homogenize the input *value* for easy and efficient normalization. + + *value* can be a scalar or sequence. + + Returns *result*, *is_scalar*, where *result* is a + masked array matching *value*. Float dtypes are preserved; + integer types with two bytes or smaller are converted to + np.float32, and larger types are converted to np.float. + Preserving float32 when possible, and using in-place operations, + can greatly improve speed for large arrays. + + Experimental; we may want to add an option to force the + use of float32. + """ + if cbook.iterable(value): + is_scalar = False + result = ma.asarray(value) + if result.dtype.kind == 'f': + if isinstance(value, np.ndarray): + result = result.copy() + elif result.dtype.itemsize > 2: + result = result.astype(np.float) + else: + result = result.astype(np.float32) + else: + is_scalar = True + result = ma.array([value]).astype(np.float) + return result, is_scalar + def __call__(self, value, clip=None): if clip is None: clip = self.clip - if cbook.iterable(value): - vtype = 'array' - val = ma.asarray(value).astype(np.float) - else: - vtype = 'scalar' - val = ma.array([value]).astype(np.float) + result, is_scalar = self.process_value(value) - self.autoscale_None(val) + self.autoscale_None(result) vmin, vmax = self.vmin, self.vmax if vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") - elif vmin==vmax: - result = 0.0 * val + elif vmin == vmax: + result.fill(0) # Or should it be all masked? Or 0.5? else: vmin = float(vmin) vmax = float(vmax) if clip: - mask = ma.getmask(val) - val = ma.array(np.clip(val.filled(vmax), vmin, vmax), - mask=mask) - result = (val-vmin) / (vmax-vmin) - if vtype == 'scalar': + mask = ma.getmask(result) + result = ma.array(np.clip(result.filled(vmax), vmin, vmax), + mask=mask) + # ma division is very slow; we can take a shortcut + resdat = result.data + resdat -= vmin + resdat /= (vmax - vmin) + result = np.ma.array(resdat, mask=result.mask, copy=False) + if is_scalar: result = result[0] return result @@ -843,8 +885,10 @@ def autoscale(self, A): def autoscale_None(self, A): ' autoscale only None-valued vmin or vmax' - if self.vmin is None: self.vmin = ma.min(A) - if self.vmax is None: self.vmax = ma.max(A) + if self.vmin is None: + self.vmin = ma.min(A) + if self.vmax is None: + self.vmax = ma.max(A) def scaled(self): 'return true if vmin and vmax set' @@ -858,30 +902,37 @@ def __call__(self, value, clip=None): if clip is None: clip = self.clip - if cbook.iterable(value): - vtype = 'array' - val = ma.asarray(value).astype(np.float) - else: - vtype = 'scalar' - val = ma.array([value]).astype(np.float) + result, is_scalar = self.process_value(value) - val = ma.masked_less_equal(val, 0, copy=False) + result = ma.masked_less_equal(result, 0, copy=False) - self.autoscale_None(val) + self.autoscale_None(result) vmin, vmax = self.vmin, self.vmax if vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") elif vmin<=0: raise ValueError("values must all be positive") elif vmin==vmax: - result = 0.0 * val + result.fill(0) else: if clip: - mask = ma.getmask(val) - val = ma.array(np.clip(val.filled(vmax), vmin, vmax), + mask = ma.getmask(result) + val = ma.array(np.clip(result.filled(vmax), vmin, vmax), mask=mask) - result = (ma.log(val)-np.log(vmin))/(np.log(vmax)-np.log(vmin)) - if vtype == 'scalar': + #result = (ma.log(result)-np.log(vmin))/(np.log(vmax)-np.log(vmin)) + # in-place equivalent of above can be much faster + resdat = result.data + mask = result.mask + if mask is np.ma.nomask: + mask = (resdat <= 0) + else: + mask |= resdat <= 0 + np.putmask(resdat, mask, 1) + np.log(resdat, resdat) + resdat -= np.log(vmin) + resdat /= (np.log(vmax) - np.log(vmin)) + result = np.ma.array(resdat, mask=mask, copy=False) + if is_scalar: result = result[0] return result diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 9b4cc75e830f..9c8ef0e34b30 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -662,7 +662,14 @@ def __init__(self, ax, *args, **kwargs): self.colors = kwargs.get('colors', None) norm = kwargs.get('norm', None) self.extend = kwargs.get('extend', 'neither') - self.antialiased = kwargs.get('antialiased', True) + self.antialiased = kwargs.get('antialiased', None) + if self.antialiased is None and self.filled: + self.antialiased = False # eliminate artifacts; we are not + # stroking the boundaries. + # The default for line contours will be taken from + # the LineCollection default, which uses the + # rcParams['lines.antialiased'] + self.nchunk = kwargs.get('nchunk', 0) self.locator = kwargs.get('locator', None) if (isinstance(norm, colors.LogNorm) @@ -734,11 +741,15 @@ def __init__(self, ax, *args, **kwargs): tlinewidths = self._process_linewidths() self.tlinewidths = tlinewidths tlinestyles = self._process_linestyles() + aa = self.antialiased + if aa is not None: + aa = (self.antialiased,) for level, width, lstyle, segs in \ zip(self.levels, tlinewidths, tlinestyles, self.allsegs): # Default zorder taken from LineCollection zorder = kwargs.get('zorder', 2) col = collections.LineCollection(segs, + antialiaseds = aa, linewidths = width, linestyle = lstyle, alpha=self.alpha, @@ -1358,6 +1369,10 @@ def _initialize_x_y(self, z): Override axis units by specifying an instance of a :class:`matplotlib.units.ConversionInterface`. + *antialiased*: [ True | False ] + enable antialiasing, overriding the defaults. For + filled contours, the default is True. For line contours, + it is taken from rcParams['lines.antialiased']. contour-only keyword arguments: @@ -1385,9 +1400,6 @@ def _initialize_x_y(self, z): contourf-only keyword arguments: - *antialiased*: [ True | False ] - enable antialiasing - *nchunk*: [ 0 | integer ] If 0, no subdivision of the domain. Specify a positive integer to divide the domain into subdomains of roughly *nchunk* by *nchunk* diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index 5843a3c5894d..7aca0ed26b59 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -714,22 +714,30 @@ def _register(self, words): subsetting, but I have no example of << in my TeX installation. """ texname, psname = words[:2] - effects, encoding, filename = '', None, None + effects, encodings, filename = '', [], None for word in words[2:]: if not word.startswith('<'): effects = word else: word = word.lstrip('<') if word.startswith('['): - assert encoding is None - encoding = word[1:] + encodings.append(word[1:]) elif word.endswith('.enc'): - assert encoding is None - encoding = word + encodings.append(word) else: assert filename is None filename = word + if len(encodings) > 1: + # TODO this is a stopgap workaround, need to handle this correctly + matplotlib.verbose.report('Multiple encodings for %s = %s, skipping' + % (texname, psname), 'debug') + return + elif len(encodings) == 1: + encoding, = encodings + else: + encoding = None + eff = effects.split() effects = {} try: diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 090d58173264..99fd09fed4d4 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -37,6 +37,83 @@ docstring.interpd.update(projection_names = get_projection_names()) +class AxesStack(Stack): + """ + Specialization of the Stack to handle all + tracking of Axes in a Figure. This requires storing + key, (ind, axes) pairs. The key is based on the args and kwargs + used in generating the Axes. ind is a serial number for tracking + the order in which axes were added. + """ + def __init__(self): + Stack.__init__(self) + self._ind = 0 + + def as_list(self): + """ + Return a list of the Axes instances that have been added to the figure + """ + ia_list = [a for k, a in self._elements] + ia_list.sort() + return [a for i, a in ia_list] + + def get(self, key): + """ + Return the Axes instance that was added with *key*. + If it is not present, return None. + """ + item = dict(self._elements).get(key) + if item is None: + return None + return item[1] + + def _entry_from_axes(self, e): + ind, k = dict([(a, (ind, k)) for (k, (ind, a)) in self._elements])[e] + return (k, (ind, e)) + + def remove(self, a): + Stack.remove(self, self._entry_from_axes(a)) + + def bubble(self, a): + return Stack.bubble(self, self._entry_from_axes(a)) + + def add(self, key, a): + """ + Add Axes *a*, with key *key*, to the stack, and return the stack. + + If *a* is already on the stack, don't add it again, but + return *None*. + """ + # All the error checking may be unnecessary; but this method + # is called so seldom that the overhead is negligible. + if not isinstance(a, Axes): + raise ValueError("second argument, %s, is not an Axes" % a) + try: + hash(key) + except TypeError: + raise ValueError("first argument, %s, is not a valid key" % key) + + a_existing = self.get(key) + if a_existing is not None: + Stack.remove(self, (key, a_existing)) + warnings.Warn( + "key %s already existed; Axes is being replaced" % key) + # I don't think the above should ever happen. + + if a in self: + return None + self._ind += 1 + return Stack.push(self, (key, (self._ind, a))) + + def __call__(self): + if not len(self._elements): + return self._default + else: + return self._elements[self._pos][1][1] + + def __contains__(self, a): + return a in self.as_list() + class SubplotParams: """ A class to hold the parameters for a subplot @@ -202,11 +279,15 @@ def __init__(self, self.subplotpars = subplotpars - self._axstack = Stack() # maintain the current axes - self.axes = [] + self._axstack = AxesStack() # track all figure axes and current axes self.clf() self._cachedRenderer = None + def _get_axes(self): + return self._axstack.as_list() + + axes = property(fget=_get_axes, doc="Read-only: list of axes in Figure") + def _get_dpi(self): return self._dpi def _set_dpi(self, dpi): @@ -231,24 +312,24 @@ def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): *ha* the horizontal alignment of the xticklabels """ - allsubplots = np.alltrue([hasattr(ax, 'is_last_row') for ax in self.axes]) if len(self.axes)==1: + # Always operate on the ticklabels if there is a single + # Axes object in the figure. + ax = self.get_axes()[0] for label in ax.get_xticklabels(): label.set_ha(ha) label.set_rotation(rotation) else: - if allsubplots: - for ax in self.get_axes(): - if ax.is_last_row(): - for label in ax.get_xticklabels(): - label.set_ha(ha) - label.set_rotation(rotation) - else: - for label in ax.get_xticklabels(): - label.set_visible(False) - ax.set_xlabel('') - - if allsubplots: + for ax in self.get_axes(): + if hasattr(ax, 'is_last_row') and ax.is_last_row(): + for label in ax.get_xticklabels(): + label.set_ha(ha) + label.set_rotation(rotation) + else: + for label in ax.get_xticklabels(): + label.set_visible(False) + ax.set_xlabel('') + self.subplots_adjust(bottom=bottom) def get_children(self): @@ -523,15 +604,9 @@ def set_frameon(self, b): def delaxes(self, a): 'remove a from the figure and update the current axes' - self.axes.remove(a) self._axstack.remove(a) - keys = [] - for key, thisax in self._seen.items(): - if a==thisax: del self._seen[key] for func in self._axobservers: func(self) - - def _make_key(self, *args, **kwargs): 'make a hashable key out of args and kwargs' @@ -592,15 +667,14 @@ def add_axes(self, *args, **kwargs): %(Axes)s """ + if not len(args): return key = self._make_key(*args, **kwargs) - - if key in self._seen: - ax = self._seen[key] + ax = self._axstack.get(key) + if ax is not None: self.sca(ax) return ax - if not len(args): return if isinstance(args[0], Axes): a = args[0] assert(a.get_figure() is self) @@ -618,10 +692,8 @@ def add_axes(self, *args, **kwargs): a = projection_factory(projection, self, rect, **kwargs) - self.axes.append(a) - self._axstack.push(a) + self._axstack.add(key, a) self.sca(a) - self._seen[key] = a return a @docstring.dedent_interpd @@ -653,15 +725,17 @@ def add_subplot(self, *args, **kwargs): %(Axes)s """ - - kwargs = kwargs.copy() - if not len(args): return + if len(args) == 1 and isinstance(args[0], int): + args = tuple([int(c) for c in str(args[0])]) + if isinstance(args[0], SubplotBase): a = args[0] assert(a.get_figure() is self) + key = self._make_key(*args, **kwargs) else: + kwargs = kwargs.copy() ispolar = kwargs.pop('polar', False) projection = kwargs.pop('projection', None) if ispolar: @@ -674,20 +748,23 @@ def add_subplot(self, *args, **kwargs): projection_class = get_projection_class(projection) + # Remake the key without projection kwargs: key = self._make_key(*args, **kwargs) - if key in self._seen: - ax = self._seen[key] + ax = self._axstack.get(key) + if ax is not None: if isinstance(ax, projection_class): self.sca(ax) return ax else: - self.axes.remove(ax) self._axstack.remove(ax) + # Undocumented convenience behavior: + # subplot(111); subplot(111, projection='polar') + # will replace the first with the second. + # Without this, add_subplot would be simpler and + # more similar to add_axes. a = subplot_class_factory(projection_class)(self, *args, **kwargs) - self._seen[key] = a - self.axes.append(a) - self._axstack.push(a) + self._axstack.add(key, a) self.sca(a) return a @@ -703,13 +780,12 @@ def clf(self, keep_observers=False): for ax in tuple(self.axes): # Iterate over the copy. ax.cla() - self.delaxes(ax) # removes ax from self.axes + self.delaxes(ax) # removes ax from self._axstack toolbar = getattr(self.canvas, 'toolbar', None) if toolbar is not None: toolbar.update() self._axstack.clear() - self._seen = {} self.artists = [] self.lines = [] self.patches = [] @@ -731,7 +807,6 @@ def draw(self, renderer): Render the figure using :class:`matplotlib.backend_bases.RendererBase` instance renderer """ # draw the figure bounding box, perhaps none for white figure - #print 'figure draw' if not self.get_visible(): return renderer.open_group('figure') @@ -975,7 +1050,7 @@ def _gci(self): helper for :func:`~matplotlib.pyplot.gci`; do not use elsewhere. """ - for ax in reversed(self._axstack): + for ax in reversed(self.axes): im = ax._gci() if im is not None: return im diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index 08b9c21adadb..aa1a951a200e 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -38,7 +38,7 @@ ('close', np.float), ('high', np.float), ('low', np.float), - ('volume', np.int), + ('volume', np.float), ('aclose', np.float)]) @@ -57,7 +57,7 @@ def parse_yahoo_historical(fh, adjusted=True, asobject=False): by the adjusted close, regardless of whether you choose adjusted = True|False. - + *asobject* If False (default for compatibility with earlier versions) return a list of tuples containing @@ -101,7 +101,7 @@ def parse_yahoo_historical(fh, adjusted=True, asobject=False): dt = datetime.date(*[int(val) for val in datestr.split('-')]) dnum = date2num(dt) open, high, low, close = [float(val) for val in vals[1:5]] - volume = int(vals[5]) + volume = float(vals[5]) aclose = float(vals[6]) results.append((dt, dt.year, dt.month, dt.day, diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index d6e1b58e8bc0..73932d016e49 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -127,7 +127,6 @@ def get_grid_positions(self, fig): return figBottoms, figTops, figLefts, figRights - def __getitem__(self, key): """ create and return a SuplotSpec instance. @@ -146,6 +145,8 @@ def __getitem__(self, key): else: if k1 < 0: k1 += nrows + if k1 >= nrows or k1 < 0 : + raise IndexError("index out of range") row1, row2 = k1, k1+1 @@ -154,6 +155,8 @@ def __getitem__(self, key): else: if k2 < 0: k2 += ncols + if k2 >= ncols or k2 < 0 : + raise IndexError("index out of range") col1, col2 = k2, k2+1 @@ -168,6 +171,8 @@ def __getitem__(self, key): else: if key < 0: key += total + if key >= total or key < 0 : + raise IndexError("index out of range") num1, num2 = key, None diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 395de7452f86..624e9dd04c38 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -97,7 +97,7 @@ def __init__(self, ax, self._imcache = None - # this is an expetimental attribute, if True, unsampled image + # this is an experimental attribute, if True, unsampled image # will be drawn using the affine transform that are # appropriately skewed so that the given postition # corresponds to the actual position in the coordinate. -JJL @@ -138,7 +138,7 @@ def make_image(self, magnification=1.0): def _get_unsampled_image(self, A, image_extents, viewlim): """ convert numpy array A with given extents ([x1, x2, y1, y2] in - data coordinate) into the Image, given the vielim (should be a + data coordinate) into the Image, given the viewlim (should be a bbox instance). Image will be clipped if the extents is significantly larger than the viewlim. """ @@ -193,17 +193,17 @@ def _get_unsampled_image(self, A, image_extents, viewlim): self._oldyslice = yslice if self._imcache is None: - if self._A.dtype == np.uint8 and len(self._A.shape) == 3: + if self._A.dtype == np.uint8 and self._A.ndim == 3: im = _image.frombyte(self._A[yslice,xslice,:], 0) im.is_grayscale = False else: if self._rgbacache is None: - x = self.to_rgba(self._A, self._alpha) + x = self.to_rgba(self._A, self._alpha, bytes=True) self._rgbacache = x else: x = self._rgbacache - im = _image.fromarray(x[yslice,xslice], 0) - if len(self._A.shape) == 2: + im = _image.frombyte(x[yslice,xslice,:], 0) + if self._A.ndim == 2: im.is_grayscale = self.cmap.is_gray() else: im.is_grayscale = False @@ -654,12 +654,13 @@ class NonUniformImage(AxesImage): def __init__(self, ax, **kwargs): """ kwargs are identical to those for AxesImage, except - that 'interpolation' defaults to 'nearest' + that 'interpolation' defaults to 'nearest', and 'bilinear' + is the only alternative. """ interp = kwargs.pop('interpolation', 'nearest') AxesImage.__init__(self, ax, **kwargs) - AxesImage.set_interpolation(self, interp) + self.set_interpolation(interp) def _check_unsampled_image(self, renderer): """ @@ -712,7 +713,7 @@ def set_data(self, x, y, A): A.shape = A.shape[0:2] if len(A.shape) == 2: if A.dtype != np.uint8: - A = (self.cmap(self.norm(A))*255).astype(np.uint8) + A = self.to_rgba(A, alpha=self._alpha, bytes=True) self.is_grayscale = self.cmap.is_gray() else: A = np.repeat(A[:,:,np.newaxis], 4, 2) @@ -796,6 +797,9 @@ def __init__(self, ax, cm.ScalarMappable.__init__(self, norm, cmap) self.axes = ax self._rgbacache = None + # There is little point in caching the image itself because + # it needs to be remade if the bbox or viewlim change, + # so caching does help with zoom/pan/resize. self.update(kwargs) self.set_data(x, y, A) @@ -810,7 +814,7 @@ def make_image(self, magnification=1.0): height = (round(t) + 0.5) - (round(b) - 0.5) width = width * magnification height = height * magnification - if self.check_update('array'): + if self._rgbacache is None: A = self.to_rgba(self._A, alpha=self._alpha, bytes=True) self._rgbacache = A if self._A.ndim == 2: @@ -826,9 +830,14 @@ def make_image(self, magnification=1.0): im.is_grayscale = self.is_grayscale return im + def changed(self): + self._rgbacache = None + cm.ScalarMappable.changed(self) + @allow_rasterization def draw(self, renderer, *args, **kwargs): - if not self.get_visible(): return + if not self.get_visible(): + return im = self.make_image(renderer.get_image_magnification()) gc = renderer.new_gc() gc.set_clip_rectangle(self.axes.bbox.frozen()) @@ -870,7 +879,7 @@ def set_data(self, x, y, A): self._A = A self._Ax = x self._Ay = y - self.update_dict['array'] = True + self._rgbacache = None def set_array(self, *args): raise NotImplementedError('Method not supported') @@ -956,7 +965,7 @@ def make_image(self, magnification=1.0): if self._A is None: raise RuntimeError('You must first set the image array') - x = self.to_rgba(self._A, self._alpha) + x = self.to_rgba(self._A, self._alpha, bytes=True) self.magnification = magnification # if magnification is not one, we need to resize ismag = magnification!=1 @@ -965,7 +974,7 @@ def make_image(self, magnification=1.0): isoutput = 0 else: isoutput = 1 - im = _image.fromarray(x, isoutput) + im = _image.frombyte(x, isoutput) fc = self.figure.get_facecolor() im.set_bg( *mcolors.colorConverter.to_rgba(fc, 0) ) im.is_grayscale = (self.cmap.name == "gray" and @@ -1078,11 +1087,11 @@ def make_image(self, renderer, magnification=1.0): im.is_grayscale = False else: if self._rgbacache is None: - x = self.to_rgba(self._A, self._alpha) + x = self.to_rgba(self._A, self._alpha, bytes=True) self._rgbacache = x else: x = self._rgbacache - im = _image.fromarray(x, 0) + im = _image.frombyte(x, 0) if len(self._A.shape) == 2: im.is_grayscale = self.cmap.is_gray() else: @@ -1157,7 +1166,7 @@ def imread(fname, format=None): def pilread(): 'try to load the image with PIL or return None' - try: import Image + try: from PIL import Image except ImportError: return None image = Image.open( fname ) return pil_to_array(image) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index b567036c7b68..9a838fd8242a 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -39,8 +39,19 @@ class DraggableLegend(DraggableOffsetBox): - def __init__(self, legend, use_blit=False): + def __init__(self, legend, use_blit=False, update="loc"): + """ + update : If "loc", update *loc* parameter of + legend upon finalizing. If "bbox", update + *bbox_to_anchor* parameter. + """ self.legend=legend + + if update in ["loc", "bbox"]: + self._update = update + else: + raise ValueError("update parameter '%s' is not supported." % update) + DraggableOffsetBox.__init__(self, legend, legend._legend_box, use_blit=use_blit) @@ -50,6 +61,14 @@ def artist_picker(self, legend, evt): def finalize_offset(self): loc_in_canvas = self.get_loc_in_canvas() + if self._update == "loc": + self._update_loc(loc_in_canvas) + elif self._update == "bbox": + self._update_bbox_to_anchor(loc_in_canvas) + else: + raise RuntimeError("update parameter '%s' is not supported." % self.update) + + def _update_loc(self, loc_in_canvas): bbox = self.legend.get_bbox_to_anchor() # if bbox has zero width or height, the transformation is @@ -62,6 +81,14 @@ def finalize_offset(self): self.legend._loc = tuple(_bbox_transform.transform_point(loc_in_canvas)) + def _update_bbox_to_anchor(self, loc_in_canvas): + + tr = self.legend.axes.transAxes + loc_in_bbox = tr.transform_point(loc_in_canvas) + + self.legend.set_bbox_to_anchor(loc_in_bbox) + + class Legend(Artist): """ Place a legend on the axes at location loc. Labels are a @@ -931,7 +958,7 @@ def _find_best_position(self, width, height, renderer, consider=None): return ox, oy - def draggable(self, state=None, use_blit=False): + def draggable(self, state=None, use_blit=False, update="loc"): """ Set the draggable state -- if state is @@ -944,6 +971,10 @@ def draggable(self, state=None, use_blit=False): If draggable is on, you can drag the legend on the canvas with the mouse. The DraggableLegend helper instance is returned if draggable is on. + + The update parameter control which parameter of the legend changes + when dragged. If update is "loc", the *loc* paramter of the legend + is changed. If "bbox", the *bbox_to_anchor* parameter is changed. """ is_draggable = self._draggable is not None @@ -953,7 +984,7 @@ def draggable(self, state=None, use_blit=False): if state: if self._draggable is None: - self._draggable = DraggableLegend(self, use_blit) + self._draggable = DraggableLegend(self, use_blit, update=update) else: if self._draggable is not None: self._draggable.disconnect() diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 203e29ffcaa4..daf600f322b6 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -248,6 +248,7 @@ def __init__(self, xdata, ydata, # chance to init axes (and hence unit support) self.update(kwargs) self.pickradius = pickradius + self.ind_offset = 0 if is_numlike(self._picker): self.pickradius = self._picker @@ -283,6 +284,8 @@ def contains(self, mouseevent): if len(self._xy)==0: return False,{} # Convert points to pixels + if self._transformed_path is None: + self._transform_path() path, affine = self._transformed_path.get_transformed_path_and_affine() path = affine.transform_path(path) xy = path.vertices diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 9f8fd82c6a9b..e80def3fe69e 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -329,10 +329,9 @@ def __init__(self): def render_glyph(self, ox, oy, info): oy = self.height - oy + info.offset - thetext = unichr_safe(info.num) self.svg_glyphs.append( - (info.font, info.fontsize, thetext, ox, oy, info.metrics)) + (info.font, info.fontsize, info.num, ox, oy, info.metrics)) def render_rect_filled(self, x1, y1, x2, y2): self.svg_rects.append( @@ -2251,7 +2250,6 @@ def __init__(self): | Error(r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) ).setParseAction(self.genfrac).setName("genfrac") - sqrt = Group( Suppress(Literal(r"\sqrt")) + Optional( @@ -2263,6 +2261,11 @@ def __init__(self): + (group | Error("Expected \sqrt{value}")) ).setParseAction(self.sqrt).setName("sqrt") + overline = Group( + Suppress(Literal(r"\overline")) + + (group | Error("Expected \overline{value}")) + ).setParseAction(self.overline).setName("overline") + placeable <<(function ^ (c_over_c | symbol) ^ accent @@ -2272,6 +2275,7 @@ def __init__(self): ^ binom ^ genfrac ^ sqrt + ^ overline ) simple <<(space @@ -2845,6 +2849,31 @@ def sqrt(self, s, loc, toks): rightside]) # Body return [hlist] + def overline(self, s, loc, toks): + assert(len(toks)==1) + assert(len(toks[0])==1) + + body = toks[0][0] + + state = self.get_state() + thickness = state.font_output.get_underline_thickness( + state.font, state.fontsize, state.dpi) + + height = body.height - body.shift_amount + thickness * 3.0 + depth = body.depth + body.shift_amount + + # Place overline above body + rightside = Vlist([Hrule(state), + Fill(), + Hlist([body])]) + + # Stretch the glue between the hrule and the body + rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0), + depth, 'exactly') + + hlist = Hlist([rightside]) + return [hlist] + def _auto_sized_delimiter(self, front, middle, back): state = self.get_state() height = max([x.height for x in middle]) diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index 9051745e2f4f..516ceee59640 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -212,10 +212,11 @@ def _spectral_helper(x, y, NFFT=256, Fs=2, detrend=detrend_none, #Make sure we're dealing with a numpy array. If y and x were the same #object to start with, keep them that way - x = np.asarray(x) if not same_data: y = np.asarray(y) + else: + y = x # zero pad x and y up to NFFT if they are shorter than NFFT if len(x)1: + # turn off all but the bottom row + for ax in axarr[:-1,:].flat: + for label in ax.get_xticklabels(): + label.set_visible(False) + + + if sharey and ncols>1: + # turn off all but the first column + for ax in axarr[:,1:].flat: + for label in ax.get_yticklabels(): + label.set_visible(False) + if squeeze: # Reshape the array to have the final desired dimension (nrow,ncol), # though discarding unneeded dimensions that equal 1. If we only have # one subplot, just return it instead of a 1-element array. if nplots==1: - return fig, axarr[0] + ret = fig, axarr[0,0] else: - return fig, axarr.reshape(nrows, ncols).squeeze() - else: - # returned axis array will be always 2-d, even if nrows=ncols=1 - return fig, axarr.reshape(nrows, ncols) + ret = fig, axarr.squeeze() + + + return ret from gridspec import GridSpec @@ -1054,10 +1078,14 @@ def xlim(*args, **kwargs): xlim(xmax=3) # adjust the max leaving min unchanged xlim(xmin=1) # adjust the min leaving max unchanged + Setting limits turns autoscaling off for the x-axis. + The new axis limits are returned as a length 2 tuple. """ ax = gca() + if not args and not kwargs: + return ax.get_xlim() ret = ax.set_xlim(*args, **kwargs) draw_if_interactive() return ret @@ -1077,9 +1105,13 @@ def ylim(*args, **kwargs): ylim(ymax=3) # adjust the max leaving min unchanged ylim(ymin=1) # adjust the min leaving max unchanged + Setting limits turns autoscaling off for the y-axis. + The new axis limits are returned as a length 2 tuple. """ ax = gca() + if not args and not kwargs: + return ax.get_ylim() ret = ax.set_ylim(*args, **kwargs) draw_if_interactive() return ret @@ -1099,10 +1131,9 @@ def xscale(*args, **kwargs): %(scale_docs)s """ ax = gca() - ret = ax.set_xscale(*args, **kwargs) + ax.set_xscale(*args, **kwargs) draw_if_interactive() - return ret - + @docstring.dedent_interpd def yscale(*args, **kwargs): """ @@ -1117,10 +1148,9 @@ def yscale(*args, **kwargs): %(scale_docs)s """ ax = gca() - ret = ax.set_yscale(*args, **kwargs) + ax.set_yscale(*args, **kwargs) draw_if_interactive() - return ret - + def xticks(*args, **kwargs): """ Set/Get the xlimits of the current ticklocs and labels:: diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index f318882653cb..f3198d862c7f 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -107,17 +107,6 @@ def validate_backend(s): else: return _validate_standard_backends(s) -def validate_numerix(v): - # 2009/02/24: start warning; later, remove all traces - try: - if v == 'obsolete': - return v - except ValueError: - pass - warnings.warn('rcParams key "numerix" is obsolete and has no effect;\n' - ' please delete it from your matplotlibrc file') - - validate_toolbar = ValidateInStrings('toolbar',[ 'None','classic','toolbar2', ], ignorecase=True) @@ -347,8 +336,6 @@ def __call__(self, s): defaultParams = { 'backend' : ['Agg', validate_backend], # agg is certainly present 'backend_fallback' : [True, validate_bool], # agg is certainly present - #'numerix' : ['obsolete', validate_numerix], - #'maskedarray' : ['obsolete', validate_maskedarray], #to be removed 'toolbar' : ['toolbar2', validate_toolbar], 'datapath' : [None, validate_path_exists], # handled by _get_data_path_cached 'units' : [False, validate_bool], diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 4e85632061b7..adbbf20e3209 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -6,6 +6,7 @@ from cbook import dedent from ticker import NullFormatter, ScalarFormatter, LogFormatterMathtext, Formatter from ticker import NullLocator, LogLocator, AutoLocator, SymmetricalLogLocator, FixedLocator +from ticker import is_decade from transforms import Transform, IdentityTransform from matplotlib import docstring @@ -318,19 +319,22 @@ class SymmetricalLogTransform(Transform): def __init__(self, base, linthresh): Transform.__init__(self) self.base = base - self.linthresh = linthresh + self.linthresh = abs(linthresh) self._log_base = np.log(base) - self._linadjust = (np.log(linthresh) / self._log_base) / linthresh + self._logb_linthresh = np.log(linthresh) / self._log_base + self._logb_minlog = np.floor(self._logb_linthresh - 1e-10) + self._linadjust = np.abs((np.log(linthresh) - self._logb_minlog) / + linthresh) def transform(self, a): a = np.asarray(a) sign = np.sign(a) masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) - log = sign * ma.log(np.abs(masked)) / self._log_base + log = sign * (ma.log(np.abs(masked)) / self._log_base - self._logb_minlog) if masked.mask.any(): return np.asarray(ma.where(masked.mask, - a * self._linadjust, - log)) + a * self._linadjust, + log)) else: return np.asarray(log) diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index 6ba8e1521d52..cd23a1c2de15 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -263,12 +263,10 @@ def run_savefig(plot_path, basename, tmpdir, destdir, formats): return len(fig_managers) + def clear_state(): plt.close('all') - matplotlib.rcdefaults() - # Set a default figure size that doesn't overflow typical browser - # windows. The script is free to override it if necessary. - matplotlib.rcParams['figure.figsize'] = (5.5, 4.5) + matplotlib.rc_file_defaults() def render_figures(plot_path, function_name, plot_code, tmpdir, destdir, formats, context=False): @@ -348,7 +346,7 @@ def _plot_directive(plot_path, basedir, function_name, plot_code, caption, del options['nofigs'] formats = setup.config.plot_formats - if type(formats) == str: + if isinstance(formats, basestring): formats = eval(formats) fname = os.path.basename(plot_path) diff --git a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py index 18218412c093..8d88f464cd7d 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py +++ b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py @@ -79,11 +79,7 @@ def axisinfo( unit, axis ): else: label = None - if ( label == "rad" ): - # If the axis units are in radians, then use a special function for - # applying format control. - majfmt = ticker.FuncFormatter( rad_fn ) - elif ( label == "deg" ) and isinstance( axis.axes, polar.PolarAxes ): + if ( label == "deg" ) and isinstance( axis.axes, polar.PolarAxes ): # If we want degrees for a polar plot, use the PolarPlotFormatter majfmt = polar.PolarAxes.ThetaFormatter() else: diff --git a/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf b/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf new file mode 100644 index 000000000000..c8d6ad974738 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/canonical.png b/lib/matplotlib/tests/baseline_images/test_axes/canonical.png new file mode 100644 index 000000000000..76782c967ae4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/canonical.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg b/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg new file mode 100644 index 000000000000..1ce403f08515 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf b/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf index 8137e3b9ad5e..822c5cdfb03f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.png b/lib/matplotlib/tests/baseline_images/test_axes/symlog.png index 32c6189bf58c..737aa236e78e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/symlog.png and b/lib/matplotlib/tests/baseline_images/test_axes/symlog.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg b/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg index b5169fb78d99..4b177e8548b0 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg @@ -23,9 +23,9 @@ L72.000000 43.200000z"/> - + @@ -57,7 +57,7 @@ L286.272000 381.525282L500.544000 381.525282"/> - + @@ -129,30 +129,33 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + + + + - - + + - + - + - + @@ -162,14 +165,14 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + - + @@ -179,17 +182,17 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + - + @@ -199,17 +202,17 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + - + @@ -219,14 +222,14 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + - + @@ -236,17 +239,17 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + - + @@ -277,227 +280,227 @@ L286.272000 381.525282L500.544000 381.525282"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf index 848e15fe9099..42ea689625a3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf and b/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf differ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 1e40c5c3bf94..cceb110b5eaf 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -279,10 +279,12 @@ def test_polar_wrap(): @image_comparison(baseline_images=['polar_units']) def test_polar_units(): import matplotlib.testing.jpl_units as units + from nose.tools import assert_true units.register() pi = np.pi deg = units.UnitDbl( 1.0, "deg" ) + km = units.UnitDbl( 1.0, "km" ) x1 = [ pi/6.0, pi/4.0, pi/3.0, pi/2.0 ] x2 = [ 30.0*deg, 45.0*deg, 60.0*deg, 90.0*deg ] @@ -299,6 +301,12 @@ def test_polar_units(): fig.savefig( 'polar_units' ) + # make sure runits and theta units work + y1 = [ y*km for y in y1 ] + plt.polar( x2, y1, color = "blue", thetaunits="rad", runits="km" ) + assert_true( isinstance(plt.gca().get_xaxis().get_major_formatter(), units.UnitDblFormatter) ) + + @image_comparison(baseline_images=['polar_rmin']) def test_polar_rmin(): r = np.arange(0, 3.0, 0.01) @@ -474,7 +482,7 @@ def test_symlog(): fig.savefig('symlog') -@image_comparison(baseline_images=['pcolormesh']) +@image_comparison(baseline_images=['pcolormesh'], tol=0.02) def test_pcolormesh(): n = 12 x = np.linspace(-1.5,1.5,n) @@ -504,6 +512,13 @@ def test_pcolormesh(): fig.savefig('pcolormesh') + +@image_comparison(baseline_images=['canonical']) +def test_canonical(): + fig, ax = plt.subplots() + ax.plot([1,2,3]) + fig.savefig('canonical') + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False) diff --git a/lib/matplotlib/tests/test_cbook.py b/lib/matplotlib/tests/test_cbook.py index 848686804d21..227f6eab1fc0 100644 --- a/lib/matplotlib/tests/test_cbook.py +++ b/lib/matplotlib/tests/test_cbook.py @@ -12,3 +12,18 @@ def test_is_string_like(): assert cbook.is_string_like( "hello world" ) assert_equal( cbook.is_string_like(10), False ) + +def test_restrict_dict(): + d = {'foo': 'bar', 1: 2} + d1 = cbook.restrict_dict(d, ['foo', 1]) + assert_equal(d1, d) + d2 = cbook.restrict_dict(d, ['bar', 2]) + assert_equal(d2, {}) + d3 = cbook.restrict_dict(d, {'foo': 1}) + assert_equal(d3, {'foo': 'bar'}) + d4 = cbook.restrict_dict(d, {}) + assert_equal(d4, {}) + d5 = cbook.restrict_dict(d, set(['foo',2])) + assert_equal(d5, {'foo': 'bar'}) + # check that d was not modified + assert_equal(d, {'foo': 'bar', 1: 2}) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index b35732d5b623..ba5aa2b8d6e9 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -143,6 +143,9 @@ class Text(Artist): Handle storing and drawing of text in window or data coordinates. """ zorder = 3 + + cached = maxdict(50) + def __str__(self): return "Text(%g,%g,%s)"%(self._y,self._y,repr(self._text)) @@ -168,7 +171,6 @@ def __init__(self, """ Artist.__init__(self) - self.cached = maxdict(5) self._x, self._y = x, y if color is None: color = rcParams['text.color'] @@ -601,7 +603,7 @@ def get_fontproperties(self): def get_font_properties(self): 'alias for get_fontproperties' - return self.get_fontproperties + return self.get_fontproperties() def get_family(self): "Return the list of font families used for font lookup" @@ -1441,6 +1443,9 @@ def _get_xy(self, renderer, x, y, s): y = float(self.convert_yunits(y)) + if s in ['axes points', 'axes pixel', 'figure points', 'figure pixel']: + return self._get_xy_legacy(renderer, x, y, s) + tr = self._get_xy_transform(renderer, s) x1, y1 = tr.transform_point((x, y)) return x1, y1 diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 9c55604faf3e..6910caac8ac1 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -127,7 +127,6 @@ - class TickHelper: axis = None class DummyAxis: @@ -1174,14 +1173,14 @@ def decade_down(x, base=10): 'floor x to the nearest lower decade' if x == 0.0: return -base - lx = math.floor(math.log(x)/math.log(base)) + lx = np.floor(np.log(x)/np.log(base)) return base**lx def decade_up(x, base=10): 'ceil x to the nearest higher decade' if x == 0.0: return base - lx = math.ceil(math.log(x)/math.log(base)) + lx = np.ceil(np.log(x)/np.log(base)) return base**lx def nearest_long(x): @@ -1194,7 +1193,7 @@ def is_decade(x, base=10): return False if x == 0.0: return True - lx = math.log(x)/math.log(base) + lx = np.log(np.abs(x))/np.log(base) return is_close_to_int(lx) def is_close_to_int(x): @@ -1274,15 +1273,20 @@ def __call__(self): stride += 1 decades = np.arange(math.floor(vmin), - math.ceil(vmax)+stride, stride) - if len(subs) > 1 or (len(subs == 1) and subs[0] != 1.0): - ticklocs = [] - for decadeStart in b**decades: - ticklocs.extend( subs*decadeStart ) + math.ceil(vmax)+stride, stride) + if hasattr(self, '_transform'): + ticklocs = self._transform.inverted().transform(decades) + if len(subs) > 1 or (len(subs == 1) and subs[0] != 1.0): + ticklocs = np.ravel(np.outer(subs, ticklocs)) else: - ticklocs = b**decades + if len(subs) > 1 or (len(subs == 1) and subs[0] != 1.0): + ticklocs = [] + for decadeStart in b**decades: + ticklocs.extend( subs*decadeStart ) + else: + ticklocs = b**decades - return self.raise_if_exceeds(np.array(ticklocs)) + return self.raise_if_exceeds(np.asarray(ticklocs)) def view_limits(self, vmin, vmax): 'Try to choose the view limits intelligently' diff --git a/lib/matplotlib/tri/triplot.py b/lib/matplotlib/tri/triplot.py index 9624e9023271..5702e3459c2e 100644 --- a/lib/matplotlib/tri/triplot.py +++ b/lib/matplotlib/tri/triplot.py @@ -1,4 +1,3 @@ -import matplotlib.axes from matplotlib.cbook import ls_mapper from matplotlib.patches import PathPatch from matplotlib.path import Path @@ -39,6 +38,8 @@ def triplot(ax, *args, **kwargs): .. plot:: mpl_examples/pylab_examples/triplot_demo.py """ + import matplotlib.axes + tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs) x = tri.x diff --git a/lib/mpl_toolkits/axes_grid/colorbar.py b/lib/mpl_toolkits/axes_grid/colorbar.py index b1f06799c2d0..7ab7593a2ecd 100644 --- a/lib/mpl_toolkits/axes_grid/colorbar.py +++ b/lib/mpl_toolkits/axes_grid/colorbar.py @@ -162,7 +162,7 @@ class CbarAxesLocator(object): """ - CbarAxesLocator is a axes_locator for colobar axes. It adjust the + CbarAxesLocator is a axes_locator for colorbar axes. It adjust the position of the axes to make a room for extended ends, i.e., the extended ends are located outside the axes area. """ @@ -194,7 +194,7 @@ def get_original_position(self, axes, renderer): def get_end_vertices(self): """ return a tuple of two vertices for the colorbar extended ends. - The first vertives is for min. end, and the second is for + The first vertices is for min. end, and the second is for max. end. """ # Note that concatenating two vertices needs to make a @@ -390,7 +390,7 @@ def __init__(self, ax, cmap=None, def _get_colorbar_limits(self): """ - initial limits for colorbar range. The returne min, max values + initial limits for colorbar range. The returned min, max values will be used to create colorbar solid(?) and etc. """ if self.boundaries is not None: @@ -407,7 +407,7 @@ def _get_colorbar_limits(self): def _config_axes(self): ''' - Adjust the properties of the axes to be adquate for colorbar display. + Adjust the properties of the axes to be adequate for colorbar display. ''' ax = self.ax @@ -416,7 +416,7 @@ def _config_axes(self): orientation=self.orientation) ax.set_axes_locator(axes_locator) - # overide the get_data_ratio for the aspect works. + # override the get_data_ratio for the aspect works. def _f(): return 1. ax.get_data_ratio = _f @@ -557,7 +557,7 @@ def _add_solids(self, X, Y, C): def add_lines(self, levels, colors, linewidths): ''' - Draw lines on the colorbar. It deletes preexting lines. + Draw lines on the colorbar. It deletes preexisting lines. ''' del self.lines @@ -735,7 +735,7 @@ def add_lines(self, CS): def update_bruteforce(self, mappable): """ Update the colorbar artists to reflect the change of the - assocaited mappable. + associated mappable. """ self.update_artists() diff --git a/lib/mpl_toolkits/axes_grid1/anchored_artists.py b/lib/mpl_toolkits/axes_grid1/anchored_artists.py index 045a4834de8c..1a077553f3a8 100644 --- a/lib/mpl_toolkits/axes_grid1/anchored_artists.py +++ b/lib/mpl_toolkits/axes_grid1/anchored_artists.py @@ -17,7 +17,7 @@ def __init__(self, width, height, xdescent, ydescent, **kwargs): """ *width*, *height*, *xdescent*, *ydescent* : the dimensions of the DrawingArea. - *prop* : font property. this is only used for scaling the paddings. + *prop* : font property. This is only used for scaling the paddings. """ self.da = DrawingArea(width, height, xdescent, ydescent, clip=True) @@ -69,7 +69,7 @@ def __init__(self, transform, size, label, loc, **kwargs): """ Draw a horizontal bar with the size in data coordinate of the give axes. - A label will be drawn underneath (center-alinged). + A label will be drawn underneath (center-aligned). pad, borderpad in fraction of the legend font size (or prop) sep in points. diff --git a/lib/mpl_toolkits/axes_grid1/axes_divider.py b/lib/mpl_toolkits/axes_grid1/axes_divider.py index 69463eff8c5a..54eb01727473 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_divider.py +++ b/lib/mpl_toolkits/axes_grid1/axes_divider.py @@ -3,8 +3,8 @@ multiple axes at the drawing time. Divider: this is the class that is used calculates the axes - position. It divides the given renctangular area into several sub - rectangles. You intialize the divider by setting the horizontal + position. It divides the given rectangular area into several sub + rectangles. You initialize the divider by setting the horizontal and vertical list of sizes that the division will be based on. You then use the new_locator method, whose return value is a callable object that can be used to set the axes_locator of the axes. @@ -23,8 +23,8 @@ class Divider(object): """ This is the class that is used calculates the axes position. It - divides the given renctangular area into several - sub-rectangles. You intialize the divider by setting the + divides the given rectangular area into several + sub-rectangles. You initialize the divider by setting the horizontal and vertical lists of sizes (:mod:`mpl_toolkits.axes_grid.axes_size`) that the division will be based on. You then use the new_locator method to create a @@ -44,11 +44,11 @@ def __init__(self, fig, pos, horizontal, vertical, aspect=None, anchor="C"): :param vertical: list of sizes (:mod:`~mpl_toolkits.axes_grid.axes_size`) for vertical division - :param aspect: if True, the overall rectalngular area is reduced + :param aspect: if True, the overall rectangular area is reduced so that the relative part of the horizontal and vertical scales have same scale. - :param anchor: Detrmine how the reduced rectangle is placed - when aspect is True, + :param anchor: Determine how the reduced rectangle is placed + when aspect is True. """ self._fig = fig @@ -59,15 +59,30 @@ def __init__(self, fig, pos, horizontal, vertical, aspect=None, anchor="C"): self._aspect = aspect self._xrefindex = 0 self._yrefindex = 0 + self._locator = None + + def get_horizontal_sizes(self, renderer): + return [s.get_size(renderer) for s in self.get_horizontal()] + + def get_vertical_sizes(self, renderer): + return [s.get_size(renderer) for s in self.get_vertical()] + + def get_vsize_hsize(self): + + from axes_size import AddList + + vsize = AddList(self.get_vertical()) + hsize = AddList(self.get_horizontal()) + + return vsize, hsize @staticmethod - def _calc_k(l, total_size, renderer): + def _calc_k(l, total_size): rs_sum, as_sum = 0., 0. - for s in l: - _rs, _as = s.get_size(renderer) + for _rs, _as in l: rs_sum += _rs as_sum += _as @@ -79,12 +94,13 @@ def _calc_k(l, total_size, renderer): @staticmethod - def _calc_offsets(l, k, renderer): + def _calc_offsets(l, k): offsets = [0.] - for s in l: - _rs, _as = s.get_size(renderer) + #for s in l: + for _rs, _as in l: + #_rs, _as = s.get_size(renderer) offsets.append(offsets[-1] + _rs*k + _as) return offsets @@ -168,8 +184,19 @@ def get_aspect(self): "return aspect" return self._aspect + def set_locator(self, _locator): + self._locator = _locator + + def get_locator(self): + return self._locator + + def get_position_runtime(self, ax, renderer): + if self._locator is None: + return self.get_position() + else: + return self._locator(ax, renderer).bounds - def locate(self, nx, ny, nx1=None, ny1=None, renderer=None): + def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): """ :param nx, nx1: Integers specifying the column-position of the @@ -182,15 +209,17 @@ def locate(self, nx, ny, nx1=None, ny1=None, renderer=None): figW,figH = self._fig.get_size_inches() - x, y, w, h = self.get_position() + x, y, w, h = self.get_position_runtime(axes, renderer) - k_h = self._calc_k(self._horizontal, figW*w, renderer) - k_v = self._calc_k(self._vertical, figH*h, renderer) + hsizes = self.get_horizontal_sizes(renderer) + vsizes = self.get_vertical_sizes(renderer) + k_h = self._calc_k(hsizes, figW*w) + k_v = self._calc_k(vsizes, figH*h) if self.get_aspect(): k = min(k_h, k_v) - ox = self._calc_offsets(self._horizontal, k, renderer) - oy = self._calc_offsets(self._vertical, k, renderer) + ox = self._calc_offsets(hsizes, k) + oy = self._calc_offsets(vsizes, k) ww = (ox[-1] - ox[0])/figW hh = (oy[-1] - oy[0])/figH @@ -200,8 +229,8 @@ def locate(self, nx, ny, nx1=None, ny1=None, renderer=None): x0, y0 = pb1_anchored.x0, pb1_anchored.y0 else: - ox = self._calc_offsets(self._horizontal, k_h, renderer) - oy = self._calc_offsets(self._vertical, k_v, renderer) + ox = self._calc_offsets(hsizes, k_h) + oy = self._calc_offsets(vsizes, k_v) x0, y0 = x, y @@ -231,11 +260,37 @@ def new_locator(self, nx, ny, nx1=None, ny1=None): """ return AxesLocator(self, nx, ny, nx1, ny1) + def append_size(self, position, size): + + if position == "left": + self._horizontal.insert(0, size) + self._xrefindex += 1 + elif position == "right": + self._horizontal.append(size) + elif position == "bottom": + self._vertical.insert(0, size) + self._yrefindex += 1 + elif position == "top": + self._vertical.append(size) + else: + raise ValueError("the position must be one of left, right, bottom, or top") + + + def add_auto_adjustable_area(self, + use_axes, pad=0.1, + adjust_dirs=["left", "right", "bottom", "top"], + ): + from axes_size import Padded, SizeFromFunc, GetExtentHelper + for d in adjust_dirs: + helper = GetExtentHelper(use_axes, d) + size = SizeFromFunc(helper) + padded_size = Padded(size, pad) # pad in inch + self.append_size(d, padded_size) class AxesLocator(object): """ - A simple callable object, initiallized with AxesDivider class, + A simple callable object, initialized with AxesDivider class, returns the position and size of the given cell. """ def __init__(self, axes_divider, nx, ny, nx1=None, ny1=None): @@ -274,13 +329,14 @@ def __call__(self, axes, renderer): self._ny + _yrefindex, self._nx1 + _xrefindex, self._ny1 + _yrefindex, + axes, renderer) class SubplotDivider(Divider): """ - The Divider class whose rectangle area is specified as a subplot grometry. + The Divider class whose rectangle area is specified as a subplot geometry. """ @@ -378,13 +434,20 @@ class AxesDivider(Divider): Divider based on the pre-existing axes. """ - def __init__(self, axes): + def __init__(self, axes, xref=None, yref=None): """ :param axes: axes """ self._axes = axes - self._xref = Size.AxesX(axes) - self._yref = Size.AxesY(axes) + if xref==None: + self._xref = Size.AxesX(axes) + else: + self._xref = xref + if yref==None: + self._yref = Size.AxesY(axes) + else: + self._yref = yref + Divider.__init__(self, fig=axes.get_figure(), pos=None, horizontal=[self._xref], vertical=[self._yref], aspect=None, anchor="C") @@ -412,18 +475,17 @@ def new_horizontal(self, size, pad=None, pack_start=False, **kwargs): :param size: A width of the axes. A :mod:`~mpl_toolkits.axes_grid.axes_size` instance or if float or string is given, *from_any* - fucntion is used to create one, with *ref_size* set to AxesX instance + function is used to create one, with *ref_size* set to AxesX instance of the current axes. :param pad: pad between the axes. It takes same argument as *size*. :param pack_start: If False, the new axes is appended at the end of the list, i.e., it became the right-most axes. If True, it is - inseted at the start of the list, and becomes the left-most axes. + inserted at the start of the list, and becomes the left-most axes. - All extra keywords argument is passed to when creating a axes. - if *axes_class* is given, the new axes will be created as an + All extra keywords arguments are passed to the created axes. + If *axes_class* is given, the new axes will be created as an instance of the given class. Otherwise, the same class of the - main axes will be used. if Not provided - + main axes will be used. """ if pad: @@ -459,18 +521,17 @@ def new_vertical(self, size, pad=None, pack_start=False, **kwargs): :param size: A height of the axes. A :mod:`~mpl_toolkits.axes_grid.axes_size` instance or if float or string is given, *from_any* - fucntion is used to create one, with *ref_size* set to AxesX instance + function is used to create one, with *ref_size* set to AxesX instance of the current axes. :param pad: pad between the axes. It takes same argument as *size*. :param pack_start: If False, the new axes is appended at the end of the list, i.e., it became the top-most axes. If True, it is - inseted at the start of the list, and becomes the bottom-most axes. + inserted at the start of the list, and becomes the bottom-most axes. - All extra keywords argument is passed to when creating a axes. - if *axes_class* is given, the new axes will be created as an + All extra keywords arguments are passed to the created axes. + If *axes_class* is given, the new axes will be created as an instance of the given class. Otherwise, the same class of the - main axes will be used. if Not provided - + main axes will be used. """ if pad: @@ -553,203 +614,266 @@ def get_anchor(self): -class LocatableAxesBase: - def __init__(self, *kl, **kw): - self._axes_class.__init__(self, *kl, **kw) - self._locator = None - self._locator_renderer = None - def set_axes_locator(self, locator): - self._locator = locator +class HBoxDivider(SubplotDivider): - def get_axes_locator(self): - return self._locator - def apply_aspect(self, position=None): + def __init__(self, fig, *args, **kwargs): + SubplotDivider.__init__(self, fig, *args, **kwargs) - if self.get_axes_locator() is None: - self._axes_class.apply_aspect(self, position) - else: - pos = self.get_axes_locator()(self, self._locator_renderer) - self._axes_class.apply_aspect(self, position=pos) + @staticmethod + def _determine_karray(equivalent_sizes, appended_sizes, + max_equivalent_size, + total_appended_size): - def draw(self, renderer=None, inframe=False): - self._locator_renderer = renderer + n = len(equivalent_sizes) + import numpy as np + A = np.mat(np.zeros((n+1, n+1), dtype="d")) + B = np.zeros((n+1), dtype="d") + # AxK = B - self._axes_class.draw(self, renderer, inframe) + # populated A + for i, (r, a) in enumerate(equivalent_sizes): + A[i,i] = r + A[i,-1] = -1 + B[i] = -a + A[-1,:-1] = [r for r, a in appended_sizes] + B[-1] = total_appended_size - sum([a for rs, a in appended_sizes]) + karray_H = (A.I*np.mat(B).T).A1 + karray = karray_H[:-1] + H = karray_H[-1] + if H > max_equivalent_size: + karray = (max_equivalent_size - \ + np.array([a for r, a in equivalent_sizes])) \ + / np.array([r for r, a in equivalent_sizes]) + return karray -_locatableaxes_classes = {} -def locatable_axes_factory(axes_class): - new_class = _locatableaxes_classes.get(axes_class) - if new_class is None: - new_class = new.classobj("Locatable%s" % (axes_class.__name__), - (LocatableAxesBase, axes_class), - {'_axes_class': axes_class}) - _locatableaxes_classes[axes_class] = new_class + @staticmethod + def _calc_offsets(appended_sizes, karray): + offsets = [0.] - return new_class + #for s in l: + for (r, a), k in zip(appended_sizes, karray): + offsets.append(offsets[-1] + r*k + a) -#if hasattr(maxes.Axes, "get_axes_locator"): -# LocatableAxes = maxes.Axes -#else: + return offsets -def make_axes_locatable(axes): - if not hasattr(axes, "set_axes_locator"): - new_class = locatable_axes_factory(type(axes)) - axes.__class__ = new_class - divider = AxesDivider(axes) - locator = divider.new_locator(nx=0, ny=0) - axes.set_axes_locator(locator) + def new_locator(self, nx, nx1=None): + """ + returns a new locator + (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for + specified cell. - return divider + :param nx, nx1: Integers specifying the column-position of the + cell. When nx1 is None, a single nx-th column is + specified. Otherwise location of columns spanning between nx + to nx1 (but excluding nx1-th column) is specified. + :param ny, ny1: same as nx and nx1, but for row positions. + """ + return AxesLocator(self, nx, 0, nx1, None) -#from matplotlib.axes import Axes -from mpl_axes import Axes -LocatableAxes = locatable_axes_factory(Axes) + + def _locate(self, x, y, w, h, + y_equivalent_sizes, x_appended_sizes, + figW, figH): + """ + + :param nx, nx1: Integers specifying the column-position of the + cell. When nx1 is None, a single nx-th column is + specified. Otherwise location of columns spanning between nx + to nx1 (but excluding nx1-th column) is specified. + + :param ny, ny1: same as nx and nx1, but for row positions. + """ + equivalent_sizes = y_equivalent_sizes + appended_sizes = x_appended_sizes -def get_demo_image(): - # prepare image - delta = 0.5 + max_equivalent_size = figH*h + total_appended_size = figW*w + karray = self._determine_karray(equivalent_sizes, appended_sizes, + max_equivalent_size, + total_appended_size) - extent = (-3,4,-4,3) - import numpy as np - x = np.arange(-3.0, 4.001, delta) - y = np.arange(-4.0, 3.001, delta) - X, Y = np.meshgrid(x, y) - import matplotlib.mlab as mlab - Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) - Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) - Z = (Z1 - Z2) * 10 + ox = self._calc_offsets(appended_sizes, karray) - return Z, extent + ww = (ox[-1] - ox[0])/figW + ref_h = equivalent_sizes[0] + hh = (karray[0]*ref_h[0] + ref_h[1])/figH + pb = mtransforms.Bbox.from_bounds(x, y, w, h) + pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) + pb1_anchored = pb1.anchored(self.get_anchor(), pb) + x0, y0 = pb1_anchored.x0, pb1_anchored.y0 -def demo_locatable_axes(): - import matplotlib.pyplot as plt + return x0, y0, ox, hh - fig1 = plt.figure(1, (6, 6)) - fig1.clf() + def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): + """ - ## PLOT 1 - # simple image & colorbar - ax = fig1.add_subplot(2, 2, 1) + :param nx, nx1: Integers specifying the column-position of the + cell. When nx1 is None, a single nx-th column is + specified. Otherwise location of columns spanning between nx + to nx1 (but excluding nx1-th column) is specified. - Z, extent = get_demo_image() + :param ny, ny1: same as nx and nx1, but for row positions. + """ - im = ax.imshow(Z, extent=extent, interpolation="nearest") - cb = plt.colorbar(im) - plt.setp(cb.ax.get_yticklabels(), visible=False) + figW,figH = self._fig.get_size_inches() + x, y, w, h = self.get_position_runtime(axes, renderer) - ## PLOT 2 - # image and colorbar whose location is adjusted in the drawing time. - # a hard way + y_equivalent_sizes = self.get_vertical_sizes(renderer) + x_appended_sizes = self.get_horizontal_sizes(renderer) + x0, y0, ox, hh = self._locate(x, y, w, h, + y_equivalent_sizes, x_appended_sizes, + figW, figH) + if nx1 is None: + nx1=nx+1 - divider = SubplotDivider(fig1, 2, 2, 2, aspect=True) + x1, w1 = x0 + ox[nx]/figW, (ox[nx1] - ox[nx])/figW + y1, h1 = y0, hh - # axes for image - ax = LocatableAxes(fig1, divider.get_position()) + return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - # axes for coloarbar - ax_cb = LocatableAxes(fig1, divider.get_position()) - h = [Size.AxesX(ax), # main axes - Size.Fixed(0.05), # padding, 0.1 inch - Size.Fixed(0.2), # colorbar, 0.3 inch - ] - v = [Size.AxesY(ax)] +class VBoxDivider(HBoxDivider): + """ + The Divider class whose rectangle area is specified as a subplot geometry. + """ - divider.set_horizontal(h) - divider.set_vertical(v) - ax.set_axes_locator(divider.new_locator(nx=0, ny=0)) - ax_cb.set_axes_locator(divider.new_locator(nx=2, ny=0)) + def new_locator(self, ny, ny1=None): + """ + returns a new locator + (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for + specified cell. - fig1.add_axes(ax) - fig1.add_axes(ax_cb) + :param nx, nx1: Integers specifying the column-position of the + cell. When nx1 is None, a single nx-th column is + specified. Otherwise location of columns spanning between nx + to nx1 (but excluding nx1-th column) is specified. - ax_cb.yaxis.set_ticks_position("right") + :param ny, ny1: same as nx and nx1, but for row positions. + """ + return AxesLocator(self, 0, ny, None, ny1) - Z, extent = get_demo_image() - im = ax.imshow(Z, extent=extent, interpolation="nearest") - plt.colorbar(im, cax=ax_cb) - plt.setp(ax_cb.get_yticklabels(), visible=False) + def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): + """ - plt.draw() - #plt.colorbar(im, cax=ax_cb) + :param nx, nx1: Integers specifying the column-position of the + cell. When nx1 is None, a single nx-th column is + specified. Otherwise location of columns spanning between nx + to nx1 (but excluding nx1-th column) is specified. + :param ny, ny1: same as nx and nx1, but for row positions. + """ - ## PLOT 3 - # image and colorbar whose location is adjusted in the drawing time. - # a easy way - ax = fig1.add_subplot(2, 2, 3) - divider = make_axes_locatable(ax) + figW,figH = self._fig.get_size_inches() + x, y, w, h = self.get_position_runtime(axes, renderer) - ax_cb = divider.new_horizontal(size="5%", pad=0.05) - fig1.add_axes(ax_cb) + x_equivalent_sizes = self.get_horizontal_sizes(renderer) + y_appended_sizes = self.get_vertical_sizes(renderer) - im = ax.imshow(Z, extent=extent, interpolation="nearest") - plt.colorbar(im, cax=ax_cb) - plt.setp(ax_cb.get_yticklabels(), visible=False) + y0, x0, oy, ww = self._locate(y, x, h, w, + x_equivalent_sizes, y_appended_sizes, + figH, figW) + if ny1 is None: + ny1=ny+1 + x1, w1 = x0, ww + y1, h1 = y0 + oy[ny]/figH, (oy[ny1] - oy[ny])/figH - ## PLOT 4 - # two images side by sied with fixed padding. + return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - ax = fig1.add_subplot(2, 2, 4) - divider = make_axes_locatable(ax) - ax2 = divider.new_horizontal(size="100%", pad=0.05) - fig1.add_axes(ax2) - ax.imshow(Z, extent=extent, interpolation="nearest") - ax2.imshow(Z, extent=extent, interpolation="nearest") - plt.setp(ax2.get_yticklabels(), visible=False) - plt.draw() - plt.show() -def demo_fixed_size_axes(): - import matplotlib.pyplot as plt +class LocatableAxesBase: + def __init__(self, *kl, **kw): - fig2 = plt.figure(2, (6, 6)) + self._axes_class.__init__(self, *kl, **kw) - # The first items are for padding and the second items are for the axes. - # sizes are in inch. - h = [Size.Fixed(1.0), Size.Fixed(4.5)] - v = [Size.Fixed(0.7), Size.Fixed(5.)] + self._locator = None + self._locator_renderer = None - divider = Divider(fig2, (0.0, 0.0, 1., 1.), h, v, aspect=False) - # the width and height of the rectangle is ignored. + def set_axes_locator(self, locator): + self._locator = locator - ax = LocatableAxes(fig2, divider.get_position()) - ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) + def get_axes_locator(self): + return self._locator + + def apply_aspect(self, position=None): + + if self.get_axes_locator() is None: + self._axes_class.apply_aspect(self, position) + else: + pos = self.get_axes_locator()(self, self._locator_renderer) + self._axes_class.apply_aspect(self, position=pos) + + + def draw(self, renderer=None, inframe=False): - fig2.add_axes(ax) + self._locator_renderer = renderer + + self._axes_class.draw(self, renderer, inframe) - ax.plot([1,2,3]) - plt.draw() - plt.show() - #plt.colorbar(im, cax=ax_cb) +_locatableaxes_classes = {} +def locatable_axes_factory(axes_class): + new_class = _locatableaxes_classes.get(axes_class) + if new_class is None: + new_class = new.classobj("Locatable%s" % (axes_class.__name__), + (LocatableAxesBase, axes_class), + {'_axes_class': axes_class}) + _locatableaxes_classes[axes_class] = new_class + return new_class + +#if hasattr(maxes.Axes, "get_axes_locator"): +# LocatableAxes = maxes.Axes +#else: + +def make_axes_locatable(axes): + if not hasattr(axes, "set_axes_locator"): + new_class = locatable_axes_factory(type(axes)) + axes.__class__ = new_class + + divider = AxesDivider(axes) + locator = divider.new_locator(nx=0, ny=0) + axes.set_axes_locator(locator) + + return divider + +def make_axes_area_auto_adjustable(ax, + use_axes=None, pad=0.1, + adjust_dirs=["left", "right", "bottom", "top"]): + + divider = make_axes_locatable(ax) + + if use_axes is None: + use_axes = ax + + divider.add_auto_adjustable_area(use_axes=use_axes, pad=pad, + adjust_dirs=adjust_dirs) + +#from matplotlib.axes import Axes +from mpl_axes import Axes +LocatableAxes = locatable_axes_factory(Axes) -if __name__ == "__main__": - demo_locatable_axes() - demo_fixed_size_axes() diff --git a/lib/mpl_toolkits/axes_grid1/axes_grid.py b/lib/mpl_toolkits/axes_grid1/axes_grid.py index 5f8c464d76b0..bd5c2469ddf3 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_grid.py +++ b/lib/mpl_toolkits/axes_grid1/axes_grid.py @@ -187,7 +187,7 @@ def __init__(self, fig, Keyword Default Description ================ ======== ========================================= direction "row" [ "row" | "column" ] - axes_pad 0.02 float| pad betweein axes given in inches + axes_pad 0.02 float| pad between axes given in inches add_all True [ True | False ] share_all False [ True | False ] share_x True [ True | False ] @@ -413,6 +413,24 @@ def set_label_mode(self, mode): ax = self.axes_llc _tick_only(ax, bottom_on=False, left_on=False) + def set_axes_locator(self, locator): + self._divider.set_locator(locator) + + def get_axes_locator(self): + return self._divider.get_locator() + + def get_vsize_hsize(self): + + return self._divider.get_vsize_hsize() +# from axes_size import AddList + +# vsize = AddList(self._divider.get_vertical()) +# hsize = AddList(self._divider.get_horizontal()) + +# return vsize, hsize + + + class ImageGrid(Grid): """ @@ -457,7 +475,7 @@ def __init__(self, fig, Keyword Default Description ================ ======== ========================================= direction "row" [ "row" | "column" ] - axes_pad 0.02 float| pad betweein axes given in inches + axes_pad 0.02 float| pad between axes given in inches add_all True [ True | False ] share_all False [ True | False ] aspect True [ True | False ] diff --git a/lib/mpl_toolkits/axes_grid1/axes_size.py b/lib/mpl_toolkits/axes_grid1/axes_size.py index 82dc26fa3e77..0eda2c822335 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_size.py +++ b/lib/mpl_toolkits/axes_grid1/axes_size.py @@ -1,6 +1,6 @@ """ -provides a classese of simlpe units that will be used with AxesDivider +provides a classes of simple units that will be used with AxesDivider class (or others) to determine the size of each axes. The unit classes define `get_size` method that returns a tuple of two floats, meaning relative and absolute sizes, respectively. @@ -12,11 +12,43 @@ class (or others) to determine the size of each axes. The unit """ import matplotlib.cbook as cbook - +from matplotlib.axes import Axes class _Base(object): "Base class" - pass + + def __rmul__(self, other): + float(other) # just to check if number if given + return Fraction(other, self) + + def __add__(self, other): + if isinstance(other, _Base): + return Add(self, other) + else: + float(other) + other = Fixed(other) + return Add(self, other) + + +class Add(_Base): + def __init__(self, a, b): + self._a = a + self._b = b + + def get_size(self, renderer): + a_rel_size, a_abs_size = self._a.get_size(renderer) + b_rel_size, b_abs_size = self._b.get_size(renderer) + return a_rel_size + b_rel_size, a_abs_size + b_abs_size + +class AddList(_Base): + def __init__(self, add_list): + self._list = add_list + + def get_size(self, renderer): + sum_rel_size = sum([a.get_size(renderer)[0] for a in self._list]) + sum_abs_size = sum([a.get_size(renderer)[1] for a in self._list]) + return sum_rel_size, sum_abs_size + class Fixed(_Base): "Simple fixed size with absolute part = *fixed_size* and relative part = 0" @@ -206,3 +238,54 @@ def from_any(size, fraction_ref=None): raise ValueError("Unknown format") +class SizeFromFunc(_Base): + def __init__(self, func): + self._func = func + + def get_size(self, renderer): + rel_size = 0. + + bb = self._func(renderer) + dpi = renderer.points_to_pixels(72.) + abs_size = bb/dpi + + return rel_size, abs_size + +class GetExtentHelper(object): + def _get_left(tight_bbox, axes_bbox): + return axes_bbox.xmin - tight_bbox.xmin + + def _get_right(tight_bbox, axes_bbox): + return tight_bbox.xmax - axes_bbox.xmax + + def _get_bottom(tight_bbox, axes_bbox): + return axes_bbox.ymin - tight_bbox.ymin + + def _get_top(tight_bbox, axes_bbox): + return tight_bbox.ymax - axes_bbox.ymax + + _get_func_map = dict(left=_get_left, + right=_get_right, + bottom=_get_bottom, + top=_get_top) + + del _get_left, _get_right, _get_bottom, _get_top + + def __init__(self, ax, direction): + if isinstance(ax, Axes): + self._ax_list = [ax] + else: + self._ax_list = ax + + try: + self._get_func = self._get_func_map[direction] + except KeyError: + print "direction must be one of left, right, bottom, top" + raise + + def __call__(self, renderer): + vl = [self._get_func(ax.get_tightbbox(renderer), + ax.bbox) for ax in self._ax_list] + return max(vl) + + diff --git a/lib/mpl_toolkits/axes_grid1/colorbar.py b/lib/mpl_toolkits/axes_grid1/colorbar.py index 36c9d26e5ecc..ba56af317864 100644 --- a/lib/mpl_toolkits/axes_grid1/colorbar.py +++ b/lib/mpl_toolkits/axes_grid1/colorbar.py @@ -162,7 +162,7 @@ class CbarAxesLocator(object): """ - CbarAxesLocator is a axes_locator for colobar axes. It adjust the + CbarAxesLocator is a axes_locator for colorbar axes. It adjust the position of the axes to make a room for extended ends, i.e., the extended ends are located outside the axes area. """ @@ -194,8 +194,8 @@ def get_original_position(self, axes, renderer): def get_end_vertices(self): """ return a tuple of two vertices for the colorbar extended ends. - The first vertives is for min. end, and the second is for - max. end. + The first vertices is for the minimum end, and the second is for + the maximum end. """ # Note that concatenating two vertices needs to make a # vertices for the frame. @@ -390,7 +390,7 @@ def __init__(self, ax, cmap=None, def _get_colorbar_limits(self): """ - initial limits for colorbar range. The returne min, max values + initial limits for colorbar range. The returned min, max values will be used to create colorbar solid(?) and etc. """ if self.boundaries is not None: @@ -407,7 +407,7 @@ def _get_colorbar_limits(self): def _config_axes(self): ''' - Adjust the properties of the axes to be adquate for colorbar display. + Adjust the properties of the axes to be adequate for colorbar display. ''' ax = self.ax @@ -416,7 +416,7 @@ def _config_axes(self): orientation=self.orientation) ax.set_axes_locator(axes_locator) - # overide the get_data_ratio for the aspect works. + # override the get_data_ratio for the aspect works. def _f(): return 1. ax.get_data_ratio = _f @@ -559,7 +559,7 @@ def _add_solids(self, X, Y, C): def add_lines(self, levels, colors, linewidths): ''' - Draw lines on the colorbar. It deletes preexting lines. + Draw lines on the colorbar. It deletes preexisting lines. ''' del self.lines @@ -737,7 +737,7 @@ def add_lines(self, CS): def update_bruteforce(self, mappable): """ Update the colorbar artists to reflect the change of the - assocaited mappable. + associated mappable. """ self.update_artists() diff --git a/lib/mpl_toolkits/axes_grid1/inset_locator.py b/lib/mpl_toolkits/axes_grid1/inset_locator.py index 8fc4491d645e..488d9f2b00a0 100644 --- a/lib/mpl_toolkits/axes_grid1/inset_locator.py +++ b/lib/mpl_toolkits/axes_grid1/inset_locator.py @@ -143,7 +143,7 @@ def __call__(self, ax, renderer): class BboxPatch(Patch): def __init__(self, bbox, **kwargs): if "transform" in kwargs: - raise ValueError("trnasform should nt be set") + raise ValueError("transform should not be set") kwargs["transform"] = IdentityTransform() Patch.__init__(self, **kwargs) @@ -225,7 +225,7 @@ def __init__(self, bbox1, bbox2, loc1, loc2=None, **kwargs): """ if "transform" in kwargs: - raise ValueError("trnasform should nt be set") + raise ValueError("transform should not be set") kwargs["transform"] = IdentityTransform() Patch.__init__(self, **kwargs) diff --git a/lib/mpl_toolkits/axisartist/angle_helper.py b/lib/mpl_toolkits/axisartist/angle_helper.py index f3ff8bfd7a82..a5b864d9bf14 100644 --- a/lib/mpl_toolkits/axisartist/angle_helper.py +++ b/lib/mpl_toolkits/axisartist/angle_helper.py @@ -130,8 +130,8 @@ def select_step(v1, v2, nv, hour=False): levs = np.arange(math.floor(f1/step), math.ceil(f2/step)+0.5, 1, dtype="i") * step - # n : number valid levels. If there is a cycle, e.g., [0, 90, 180, - # 270, 360], the a grid line needs to be extend from 0 to 360, so + # n : number of valid levels. If there is a cycle, e.g., [0, 90, 180, + # 270, 360], the grid line needs to be extended from 0 to 360, so # we need to return the whole array. However, the last level (360) # needs to be ignored often. In this case, so we return n=4. @@ -288,7 +288,7 @@ def __call__(self, transform_xy, x1, y1, x2, y2): get extreme values. x1, y1, x2, y2 in image coordinates (0-based) - nx, ny : number of dvision in each axis + nx, ny : number of divisions in each axis """ x_, y_ = np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny) x, y = np.meshgrid(x_, y_) diff --git a/lib/mpl_toolkits/axisartist/axis_artist.py b/lib/mpl_toolkits/axisartist/axis_artist.py index 3b0204624e20..2e31d5bda138 100644 --- a/lib/mpl_toolkits/axisartist/axis_artist.py +++ b/lib/mpl_toolkits/axisartist/axis_artist.py @@ -10,7 +10,7 @@ The main artist class is a AxisArtist and a GridlinesCollection. The GridlinesCollection is responsible for drawing grid lines and the AxisArtist is responsible for all other artists. The AxisArtist class -has attributest that are associated with each type of artists. +has attributes that are associated with each type of artists. * line : axis line * major_ticks : major tick lines @@ -25,11 +25,14 @@ ax.axis["bottom"] -where *ax* is an instance of axes (mpl_toolkits.axislines.Axes). -Thus, ax.axis["bottom"].line is an artist associated with the axis line, and ax.axis["bottom"].major_ticks is an artist associated with the major tick lines. +where *ax* is an instance of axes (mpl_toolkits.axislines.Axes). Thus, +ax.axis["bottom"].line is an artist associated with the axis line, and +ax.axis["bottom"].major_ticks is an artist associated with the major tick +lines. You can change the colors, fonts, line widths, etc. of these artists -by calling sutable set method. For example, to change the color of the major ticks of the bottom axis to red, +by calling suitable set method. For example, to change the color of the major +ticks of the bottom axis to red, ax.axis["bottom"].major_ticks.set_color("r") @@ -39,7 +42,7 @@ axis_direction -------------- -AxisArtist, AxisLabel, TickLabels have *axis_drection* attribute, +AxisArtist, AxisLabel, TickLabels have *axis_direction* attribute, which adjusts the location, angle, etc.,. The *axis_direction* must be one of [left, right, bottom, top] and they follow the matplotlib convention for the rectangle axis. @@ -62,7 +65,7 @@ ticklabels angle 90 0 -90 180 axislabel angle 180 0 0 180 ticklabel va center baseline center baseline - axislabel va center top center btoom + axislabel va center top center bottom ticklabel ha right center right center axislabel ha right center right center @@ -177,7 +180,7 @@ def set_ref_artist(self, artist): self._ref_artist = artist def get_ref_artist(self): - raise RuntimeError("get_ref_artist must overriden") + raise RuntimeError("get_ref_artist must overridden") #return self._ref_artist def get_attribute_from_ref_artist(self, attr_name, default_value): @@ -257,7 +260,7 @@ def get_tick_out(self): def set_ticksize(self, ticksize): """ - set lenth of the ticks in points. + set length of the ticks in points. """ self._ticksize = ticksize @@ -490,7 +493,7 @@ def test_labelbase(): class AxisLabel(LabelBase, AttributeCopier): """ Axis Label. Derived from Text. The position of the text is updated - in the fly, so chaning text position has no effect. Otherwise, the + in the fly, so changing text position has no effect. Otherwise, the properties can be changed as a normal Text. To change the pad between ticklabels and axis label, use set_pad. @@ -587,7 +590,7 @@ def set_axis_direction(self, d): property left bottom right top ===================== ========== ========= ========== ========== axislabel angle 180 0 0 180 - axislabel va center top center btoom + axislabel va center top center bottom axislabel ha right center right center ===================== ========== ========= ========== ========== @@ -808,7 +811,7 @@ def get_window_extents(self, renderer): def get_texts_widths_heights_descents(self, renderer): """ - return a list of width, height, descent for ticklaels. + return a list of width, height, descent for ticklabels. """ whd_list = [] for (x, y), a, l in self._locs_angles_labels: @@ -981,7 +984,7 @@ def set_axis_direction(self, axis_direction): ticklabel va center baseline center baseline ticklabel ha right center right center axislabel angle 180 0 0 180 - axislabel va center top center btoom + axislabel va center top center bottom axislabel ha right center right center ===================== ========== ========= ========== ========== diff --git a/lib/mpl_toolkits/axisartist/axisline_style.py b/lib/mpl_toolkits/axisartist/axisline_style.py index 13c4fb76b592..8bf67d66c8e5 100644 --- a/lib/mpl_toolkits/axisartist/axisline_style.py +++ b/lib/mpl_toolkits/axisartist/axisline_style.py @@ -6,7 +6,7 @@ class _FancyAxislineStyle: class SimpleArrow(FancyArrowPatch): """ - The artist class that will be returend for SimpleArrow style. + The artist class that will be returned for SimpleArrow style. """ _ARROW_STYLE = "->" @@ -60,7 +60,7 @@ def set_path(self, path): def draw(self, renderer): """ Draw the axis line. - 1) transform the path to the display cooridnate. + 1) transform the path to the display coordinate. 2) extend the path to make a room for arrow 3) update the path of the FancyArrowPatch. 4) draw @@ -75,7 +75,7 @@ def draw(self, renderer): class FilledArrow(SimpleArrow): """ - The artist class that will be returend for SimpleArrow style. + The artist class that will be returned for SimpleArrow style. """ _ARROW_STYLE = "-|>" @@ -115,7 +115,7 @@ class _Base(object): def __init__(self): """ - initializtion. + initialization. """ super(AxislineStyle._Base, self).__init__() diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index cf09a550d24b..ef8ca0ef6e95 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -3,7 +3,7 @@ biggest difference is that the artists responsible to draw axis line, ticks, ticklabel and axis labels are separated out from the mpl's Axis class, which are much more than artists in the original -mpl. Originally, this change was motivated to support curvlinear +mpl. Originally, this change was motivated to support curvilinear grid. Here are a few reasons that I came up with new axes class. @@ -11,7 +11,7 @@ different ticks (tick locations and labels). This is not possible with the current mpl, although some twin axes trick can help. - * Curvelinear grid. + * Curvilinear grid. * angled ticks. @@ -109,7 +109,7 @@ def get_tick_transform(self, axes): return trans def get_tick_iterators(self, axes): - # iter : iteratoable object that yields (c, angle, l) where + # iter : iteratable object that yields (c, angle, l) where # c, angle, l is position, tick angle, and label return iter_major, iter_minor @@ -639,7 +639,7 @@ def _init_gridlines(self, grid_helper=None): self.axes._set_artist_props(gridlines) # gridlines.set_clip_path(self.axes.patch) - # set_clip_path need to be defered after Axes.cla is completed. + # set_clip_path need to be deferred after Axes.cla is completed. # It is done inside the cla. self.gridlines = gridlines @@ -662,7 +662,7 @@ def get_grid_helper(self): def grid(self, b=None, which='major', **kwargs): """ - Toggel the gridlines, and optionally set the properties of the lines. + Toggle the gridlines, and optionally set the properties of the lines. """ # their are some discrepancy between the behavior of grid in # axes_grid and the original mpl's grid, because axes_grid diff --git a/lib/mpl_toolkits/axisartist/clip_path.py b/lib/mpl_toolkits/axisartist/clip_path.py index bf3b06dd0821..f863468ce468 100644 --- a/lib/mpl_toolkits/axisartist/clip_path.py +++ b/lib/mpl_toolkits/axisartist/clip_path.py @@ -10,7 +10,7 @@ def atan2(dy, dx): return math.atan2(dy, dx) # FIXME : The current algorithm seems to return incorrect angle when the line -# ends at the boudnary. +# ends at the boundary. def clip(xlines, ylines, x0, clip="right"): diff --git a/lib/mpl_toolkits/axisartist/floating_axes.py b/lib/mpl_toolkits/axisartist/floating_axes.py index 111495bd34a4..e8d9afc5d3ab 100644 --- a/lib/mpl_toolkits/axisartist/floating_axes.py +++ b/lib/mpl_toolkits/axisartist/floating_axes.py @@ -1,5 +1,5 @@ """ -An experimental support for curvelinear grid. +An experimental support for curvilinear grid. """ @@ -225,7 +225,7 @@ def __call__(self, transform_xy, x1, y1, x2, y2): get extreme values. x1, y1, x2, y2 in image coordinates (0-based) - nx, ny : number of dvision in each axis + nx, ny : number of division in each axis """ #lon_min, lon_max, lat_min, lat_max = self._extremes return self._extremes @@ -241,7 +241,7 @@ def __init__(self, aux_trans, extremes, tick_formatter2=None): """ aux_trans : a transform from the source (curved) coordinate to - target (rectlinear) coordinate. An instance of MPL's Transform + target (rectilinear) coordinate. An instance of MPL's Transform (inverse transform should be defined) or a tuple of two callable objects which defines the transform and its inverse. The callables need take two arguments of array of source coordinates and @@ -320,7 +320,7 @@ def new_fixed_axis(self, loc, return axisline - # new_floating_axis will inheirt the grid_helper's extremes. + # new_floating_axis will inherit the grid_helper's extremes. # def new_floating_axis(self, nth_coord, # value, diff --git a/lib/mpl_toolkits/axisartist/grid_finder.py b/lib/mpl_toolkits/axisartist/grid_finder.py index c052e619331d..5a693811ee66 100644 --- a/lib/mpl_toolkits/axisartist/grid_finder.py +++ b/lib/mpl_toolkits/axisartist/grid_finder.py @@ -19,7 +19,7 @@ def __call__(self, transform_xy, x1, y1, x2, y2): get extreme values. x1, y1, x2, y2 in image coordinates (0-based) - nx, ny : number of dvision in each axis + nx, ny : number of division in each axis """ x_, y_ = np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny) x, y = np.meshgrid(x_, y_) @@ -31,9 +31,10 @@ def __call__(self, transform_xy, x1, y1, x2, y2): return self._add_pad(lon_min, lon_max, lat_min, lat_max) def _add_pad(self, lon_min, lon_max, lat_min, lat_max): - # a small amound of padding is added because the current - # clipping algorithms seems to fail when the gidline ends at - # the bbox boundary. + """ a small amount of padding is added because the current + clipping algorithms seems to fail when the gridline ends at + the bbox boundary. + """ dlon = (lon_max - lon_min) / self.nx dlat = (lat_max - lat_min) / self.ny @@ -205,7 +206,7 @@ def update(self, **kw): "tick_formatter2"]: setattr(self, k, kw[k]) else: - raise ValueError("unknwonw update property") + raise ValueError("unknown update property '%s'" % k) @@ -220,7 +221,7 @@ def __init__(self, tick_formatter1=None, tick_formatter2=None): """ - transform : transfrom from the image coordinate (which will be + transform : transform from the image coordinate (which will be the transData of the axes to the world coordinate. or transform = (transform_xy, inv_transform_xy) @@ -279,21 +280,27 @@ def set_factor(self, f): class FixedLocator(object): def __init__(self, locs): self._locs = locs + self._factor = None def __call__(self, v1, v2): - v1, v2 = sorted([v1, v2]) + if self._factor is None: + v1, v2 = sorted([v1, v2]) + else: + v1, v2 = sorted([v1*self._factor, v2*self._factor]) locs = np.array([l for l in self._locs if ((v1 <= l) and (l <= v2))]) - return locs, len(locs), None + return locs, len(locs), self._factor + def set_factor(self, f): + self._factor = f # Tick Formatter class FormatterPrettyPrint(object): - def __init__(self): - self._fmt = mticker.ScalarFormatter() + def __init__(self, useMathText=True): + self._fmt = mticker.ScalarFormatter(useMathText=useMathText) self._fmt.create_dummy_axis() self._ignore_factor = True diff --git a/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py b/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py index f05bedcd3cb0..3330f52be00c 100644 --- a/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py +++ b/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py @@ -1,5 +1,5 @@ """ -An experimental support for curvelinear grid. +An experimental support for curvilinear grid. """ from itertools import chain @@ -11,6 +11,8 @@ from matplotlib.transforms import Affine2D, IdentityTransform import numpy as np +from matplotlib.path import Path + class FixedAxisArtistHelper(AxisArtistHelper.Fixed): """ Helper class for a fixed axis. @@ -76,6 +78,8 @@ def __init__(self, grid_helper, nth_coord, value, axis_direction=None): self.grid_helper = grid_helper self._extremes = None, None + self._get_line_path = None # a method that returns a Path. + self._line_num_points = 100 # number of points to create a line def set_extremes(self, e1, e2): self._extremes = e1, e2 @@ -125,12 +129,12 @@ def update_lim(self, axes): #e1, e2 = self._extremes # ranges of other coordinates if self.nth_coord == 0: - xx0 = np.linspace(self.value, self.value, 100) - yy0 = np.linspace(extremes[2], extremes[3], 100) + xx0 = np.linspace(self.value, self.value, self._line_num_points) + yy0 = np.linspace(extremes[2], extremes[3], self._line_num_points) xx, yy = grid_finder.transform_xy(xx0, yy0) elif self.nth_coord == 1: - xx0 = np.linspace(extremes[0], extremes[1], 100) - yy0 = np.linspace(self.value, self.value, 100) + xx0 = np.linspace(extremes[0], extremes[1], self._line_num_points) + yy0 = np.linspace(self.value, self.value, self._line_num_points) xx, yy = grid_finder.transform_xy(xx0, yy0) grid_info["line_xy"] = xx, yy @@ -285,10 +289,12 @@ def get_line_transform(self, axes): def get_line(self, axes): self.update_lim(axes) - from matplotlib.path import Path - xx, yy = self.grid_info["line_xy"] + x, y = self.grid_info["line_xy"] - return Path(zip(xx, yy)) + if self._get_line_path is None: + return Path(zip(x, y)) + else: + return self._get_line_path(axes, x, y) @@ -303,7 +309,7 @@ def __init__(self, aux_trans, tick_formatter2=None): """ aux_trans : a transform from the source (curved) coordinate to - target (rectlinear) coordinate. An instance of MPL's Transform + target (rectilinear) coordinate. An instance of MPL's Transform (inverse transform should be defined) or a tuple of two callable objects which defines the transform and its inverse. The callables need take two arguments of array of source coordinates and diff --git a/lib/mpl_toolkits/gtktools.py b/lib/mpl_toolkits/gtktools.py index 7d7d646e08d6..b0daf60a99fe 100644 --- a/lib/mpl_toolkits/gtktools.py +++ b/lib/mpl_toolkits/gtktools.py @@ -158,7 +158,7 @@ def __call__(self, column): val = model.get_value(thisiter, self.i) try: val = float(val.strip().rstrip('%')) except ValueError: pass - if npy.isnan(val): val = npy.inf # force nan to sort uniquely + if mlab.safe_isnan(val): val = npy.inf # force nan to sort uniquely dsu.append((val, rownum)) dsu.sort() if not self.num%2: dsu.reverse() diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 0b25c3976990..a355dd3514df 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -291,8 +291,17 @@ def __init__(self, *args, **kwargs): PatchCollection.__init__(self, *args, **kwargs) self._old_draw = lambda x: PatchCollection.draw(self, x) + def set_sort_zpos(self,val): + '''Set the position to use for z-sorting.''' + self._sort_zpos = val + def set_3d_properties(self, zs, zdir): - xs, ys = zip(*self.get_offsets()) + offsets = self.get_offsets() + if len(offsets) > 0: + xs, ys = zip(*self.get_offsets()) + else: + xs = [0] * len(zs) + ys = [0] * len(zs) self._offsets3d = juggle_axes(xs, ys, zs, zdir) self._facecolor3d = self.get_facecolor() self._edgecolor3d = self.get_edgecolor() diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 9aef760b0e10..1c7764bde060 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -58,7 +58,6 @@ def __init__(self, fig, rect=None, *args, **kwargs): if rect is None: rect = [0.0, 0.0, 1.0, 1.0] - self.fig = fig self._cids = [] self.initial_azim = kwargs.pop('azim', -60) @@ -72,19 +71,27 @@ def __init__(self, fig, rect=None, *args, **kwargs): # they can't be defined until Axes.__init__ has been called self.view_init(self.initial_elev, self.initial_azim) self._ready = 0 - Axes.__init__(self, self.fig, rect, - frameon=True, - xticks=[], yticks=[], *args, **kwargs) + Axes.__init__(self, fig, rect, + frameon=True, + *args, **kwargs) + # Disable drawing of axes by base class + Axes.set_axis_off(self) + self._axis3don = True self.M = None self._ready = 1 self.mouse_init() - self.create_axes() self.set_top_view() self.axesPatch.set_linewidth(0) - self.fig.add_axes(self) + self.figure.add_axes(self) + + def set_axis_off(self): + self._axis3don = False + + def set_axis_on(self): + self._axis3don = True def set_top_view(self): # this happens to be the right view for the viewing coordinates @@ -97,13 +104,23 @@ def set_top_view(self): Axes.set_xlim(self, -xdwl, xdw, auto=None) Axes.set_ylim(self, -ydwl, ydw, auto=None) - def create_axes(self): + def _init_axis(self): + '''Init 3d axes; overrides creation of regular X/Y axes''' self.w_xaxis = axis3d.XAxis('x', self.xy_viewLim.intervalx, self.xy_dataLim.intervalx, self) + self.xaxis = self.w_xaxis self.w_yaxis = axis3d.YAxis('y', self.xy_viewLim.intervaly, self.xy_dataLim.intervaly, self) + self.yaxis = self.w_yaxis self.w_zaxis = axis3d.ZAxis('z', self.zz_viewLim.intervalx, self.zz_dataLim.intervalx, self) + self.zaxis = self.w_zaxis + + for ax in self.xaxis, self.yaxis, self.zaxis: + ax.init3d() + + def get_children(self): + return [self.zaxis,] + Axes.get_children(self) def unit_cube(self, vals=None): minx, maxx, miny, maxy, minz, maxz = vals or self.get_w_lims() @@ -165,12 +182,16 @@ def draw(self, renderer): for i, (z, patch) in enumerate(zlist): patch.zorder = i - axes = (self.w_xaxis, self.w_yaxis, self.w_zaxis) - for ax in axes: - ax.draw_pane(renderer) - for ax in axes: - ax.draw(renderer) + if self._axis3don: + axes = (self.w_xaxis, self.w_yaxis, self.w_zaxis) + # Draw panes first + for ax in axes: + ax.draw_pane(renderer) + # Then axes + for ax in axes: + ax.draw(renderer) + # Then rest Axes.draw(self, renderer) def get_axis_position(self): @@ -204,7 +225,7 @@ def auto_scale_xyz(self, X, Y, Z=None, had_data=None): self.autoscale_view() def autoscale_view(self, scalex=True, scaley=True, scalez=True, **kw): - # This method looks at the rectanglular volume (see above) + # This method looks at the rectangular volume (see above) # of data and decides how to scale the view portal to fit it. self.set_top_view() @@ -240,18 +261,21 @@ def set_xlim3d(self, *args, **kwargs): lims = self._determine_lims(*args, **kwargs) self.xy_viewLim.intervalx = lims return lims + set_xlim = set_xlim3d def set_ylim3d(self, *args, **kwargs): '''Set 3D y limits.''' lims = self._determine_lims(*args, **kwargs) self.xy_viewLim.intervaly = lims return lims + set_ylim = set_ylim3d def set_zlim3d(self, *args, **kwargs): '''Set 3D z limits.''' lims = self._determine_lims(*args, **kwargs) self.zz_viewLim.intervalx = lims return lims + set_zlim = set_zlim3d def get_xlim3d(self): '''Get 3D x limits.''' @@ -264,6 +288,17 @@ def get_ylim3d(self): def get_zlim3d(self): '''Get 3D z limits.''' return self.zz_viewLim.intervalx + get_zlim = get_zlim3d + + def set_zticks(self,*args,**kwargs): + """ + Set 3d z tick locations and (optionally labels). + See set_xticks3d for more details. + """ + return self.w_zaxis.set_ticks(*args, **kwargs) + + def get_zticks(self): + return self.w_zaxis.get_ticks() def clabel(self, *args, **kwargs): return None @@ -661,7 +696,6 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): had_data = self.has_data() rows, cols = Z.shape - tX, tY, tZ = np.transpose(X), np.transpose(Y), np.transpose(Z) rstride = kwargs.pop('rstride', 10) cstride = kwargs.pop('cstride', 10) @@ -684,21 +718,27 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): fcolors = self._shade_colors_lightsource(Z, cmap, lightsource) polys = [] - normals = [] + # Only need these vectors to shade if there is no cmap + if cmap is None and shade : + totpts = int(np.ceil(float(rows - 1) / rstride) * + np.ceil(float(cols - 1) / cstride)) + v1 = np.empty((totpts, 3)) + v2 = np.empty((totpts, 3)) + # This indexes the vertex points + which_pt = 0 + + #colset contains the data for coloring: either average z or the facecolor colset = [] - for rs in np.arange(0, rows-1, rstride): - for cs in np.arange(0, cols-1, cstride): + for rs in xrange(0, rows-1, rstride): + for cs in xrange(0, cols-1, cstride): ps = [] - corners = [] - for a, ta in [(X, tX), (Y, tY), (Z, tZ)]: - ztop = a[rs][cs:min(cols, cs+cstride+1)] - zleft = ta[min(cols-1, cs+cstride)][rs:min(rows, rs+rstride+1)] - zbase = a[min(rows-1, rs+rstride)][cs:min(cols, cs+cstride+1):] - zbase = zbase[::-1] - zright = ta[cs][rs:min(rows, rs+rstride+1):] - zright = zright[::-1] - corners.append([ztop[0], ztop[-1], zbase[0], zbase[-1]]) + for a in (X, Y, Z) : + ztop = a[rs,cs:min(cols, cs+cstride+1)] + zleft = a[rs+1:min(rows, rs+rstride+1), + min(cols-1, cs+cstride)] + zbase = a[min(rows-1, rs+rstride), cs:min(cols, cs+cstride+1):][::-1] + zright = a[rs:min(rows-1, rs+rstride):, cs][::-1] z = np.concatenate((ztop, zleft, zbase, zright)) ps.append(z) @@ -706,13 +746,8 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): # are removed here. ps = zip(*ps) lastp = np.array([]) - ps2 = [] - avgzsum = 0.0 - for p in ps: - if p != lastp: - ps2.append(p) - lastp = p - avgzsum += p[2] + ps2 = [ps[0]] + [ps[i] for i in xrange(1, len(ps)) if ps[i] != ps[i-1]] + avgzsum = sum(p[2] for p in ps2) polys.append(ps2) if fcolors is not None: @@ -722,9 +757,14 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): # Only need vectors to shade if no cmap if cmap is None and shade: - v1 = np.array(ps2[0]) - np.array(ps2[1]) - v2 = np.array(ps2[2]) - np.array(ps2[0]) - normals.append(np.cross(v1, v2)) + i1, i2, i3 = 0, int(len(ps2)/3), int(2*len(ps2)/3) + v1[which_pt] = np.array(ps2[i1]) - np.array(ps2[i2]) + v2[which_pt] = np.array(ps2[i2]) - np.array(ps2[i3]) + which_pt += 1 + if cmap is None and shade: + normals = np.cross(v1, v2) + else : + normals = [] polyc = art3d.Poly3DCollection(polys, *args, **kwargs) @@ -772,24 +812,19 @@ def _shade_colors(self, color, normals): *color* can also be an array of the same length as *normals*. ''' - shade = [] - for n in normals: - n = n / proj3d.mod(n) - shade.append(np.dot(n, [-1, -1, 0.5])) - - shade = np.array(shade) + shade = np.array([np.dot(n / proj3d.mod(n), [-1, -1, 0.5]) + for n in normals]) mask = ~np.isnan(shade) if len(shade[mask]) > 0: norm = Normalize(min(shade[mask]), max(shade[mask])) - if art3d.iscolor(color): - color = color.copy() - color[3] = 1 - colors = [color * (0.5 + norm(v) * 0.5) for v in shade] - else: - colors = [np.array(colorConverter.to_rgba(c)) * \ - (0.5 + norm(v) * 0.5) \ - for c, v in zip(color, shade)] + color = colorConverter.to_rgba_array(color) + # shape of color should be (M, 4) (where M is number of faces) + # shape of shade should be (M,) + # colors should have final shape of (M, 4) + alpha = color[:, 3] + colors = (0.5 + norm(shade)[:, np.newaxis] * 0.5) * color + colors[:, 3] = alpha else: colors = color.copy() @@ -896,6 +931,24 @@ def _3d_extend_contour(self, cset, stride=5): for col in colls: self.collections.remove(col) + def add_contour_set(self, cset, extend3d=False, stride=5, zdir='z', offset=None): + zdir = '-' + zdir + if extend3d: + self._3d_extend_contour(cset, stride) + else: + for z, linec in zip(cset.levels, cset.collections): + if offset is not None: + z = offset + art3d.line_collection_2d_to_3d(linec, z, zdir=zdir) + + def add_contourf_set(self, cset, zdir='z', offset=None) : + zdir = '-' + zdir + for z, linec in zip(cset.levels, cset.collections) : + if offset is not None : + z = offset + art3d.poly_collection_2d_to_3d(linec, z, zdir=zdir) + linec.set_sort_zpos(z) + def contour(self, X, Y, Z, *args, **kwargs): ''' Create a 3D contour plot. @@ -927,26 +980,62 @@ def contour(self, X, Y, Z, *args, **kwargs): jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) cset = Axes.contour(self, jX, jY, jZ, *args, **kwargs) - - zdir = '-' + zdir - if extend3d: - self._3d_extend_contour(cset, stride) - else: - for z, linec in zip(cset.levels, cset.collections): - if offset is not None: - z = offset - art3d.line_collection_2d_to_3d(linec, z, zdir=zdir) + self.add_contour_set(cset, extend3d, stride, zdir, offset) self.auto_scale_xyz(X, Y, Z, had_data) return cset contour3D = contour + def tricontour(self, X, Y, Z, *args, **kwargs): + ''' + Create a 3D contour plot. + + ========== ================================================ + Argument Description + ========== ================================================ + *X*, *Y*, Data values as numpy.arrays + *Z* + *extend3d* Whether to extend contour in 3D (default: False) + *stride* Stride (step size) for extending contour + *zdir* The direction to use: x, y or z (default) + *offset* If specified plot a projection of the contour + lines on this position in plane normal to zdir + ========== ================================================ + + Other keyword arguments are passed on to + :func:`~matplotlib.axes.Axes.tricontour` + + Returns a :class:`~matplotlib.axes.Axes.contour` + ''' + + extend3d = kwargs.pop('extend3d', False) + stride = kwargs.pop('stride', 5) + zdir = kwargs.pop('zdir', 'z') + offset = kwargs.pop('offset', None) + + had_data = self.has_data() + + jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) + cset = Axes.tricontour(self, jX, jY, jZ, *args, **kwargs) + self.add_contour_set(cset, extend3d, stride, zdir, offset) + + self.auto_scale_xyz(X, Y, Z, had_data) + return cset + def contourf(self, X, Y, Z, *args, **kwargs): ''' - Plot filled 3D contours. + Create a 3D contourf plot. - *X*, *Y*, *Z*: data points. + ========== ================================================ + Argument Description + ========== ================================================ + *X*, *Y*, Data values as numpy.arrays + *Z* + *zdir* The direction to use: x, y or z (default) + *offset* If specified plot a projection of the filled contour + on this position in plane normal to zdir + ========== ================================================ The positional and keyword arguments are passed on to :func:`~matplotlib.axes.Axes.contourf` @@ -954,20 +1043,50 @@ def contourf(self, X, Y, Z, *args, **kwargs): Returns a :class:`~matplotlib.axes.Axes.contourf` ''' + zdir = kwargs.pop('zdir', 'z') + offset = kwargs.pop('offset', None) + had_data = self.has_data() - cset = Axes.contourf(self, X, Y, Z, *args, **kwargs) - levels = cset.levels - colls = cset.collections - for z1, z2, linec in zip(levels, levels[1:], colls): - art3d.poly_collection_2d_to_3d(linec, z1) - linec.set_sort_zpos(z1) + jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) + cset = Axes.contourf(self, jX, jY, jZ, *args, **kwargs) + self.add_contourf_set(cset, zdir, offset) self.auto_scale_xyz(X, Y, Z, had_data) return cset contourf3D = contourf + def tricontourf(self, X, Y, Z, offset=None, zdir='z', *args, **kwargs): + ''' + Create a 3D contourf plot. + + ========== ================================================ + Argument Description + ========== ================================================ + *X*, *Y*, Data values as numpy.arrays + *Z* + *extend3d* Whether to extend contour in 3D (default: False) + *stride* Stride (step size) for extending contour + *zdir* The direction to use: x, y or z (default) + *offset* If specified plot a projection of the contour + lines on this position in plane normal to zdir + ========== ================================================ + + Other keyword arguments are passed on to + :func:`~matplotlib.axes.Axes.tricontour` + + Returns a :class:`~matplotlib.axes.Axes.contour` + ''' + + had_data = self.has_data() + + cset = Axes.tricontourf(self, X, Y, Z, *args, **kwargs) + self.add_contourf_set(cset, zdir, offset) + + self.auto_scale_xyz(X, Y, Z, had_data) + return cset + def add_collection3d(self, col, zs=0, zdir='z'): ''' Add a 3d collection object to the plot. @@ -993,20 +1112,31 @@ def add_collection3d(self, col, zs=0, zdir='z'): Axes.add_collection(self, col) - def scatter(self, xs, ys, zs=0, zdir='z', *args, **kwargs): + def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', *args, **kwargs): ''' Create a scatter plot. ========== ================================================ Argument Description - ========== ================================================ + ========== ========================================================== *xs*, *ys* Positions of data points. *zs* Either an array of the same length as *xs* and *ys* or a single value to place all points in the same plane. Default is 0. *zdir* Which direction to use as z ('x', 'y' or 'z') when plotting a 2d set. - ========== ================================================ + *s* size in points^2. It is a scalar or an array of the same + length as *x* and *y*. + + *c* a color. *c* can be a single color format string, or a + sequence of color specifications of length *N*, or a + sequence of *N* numbers to be mapped to colors using the + *cmap* and *norm* specified via kwargs (see below). Note + that *c* should not be a single numeric RGB or RGBA + sequence because that is indistinguishable from an array + of values to be colormapped. *c* can be a 2-D array in + which the rows are RGB or RGBA, however. + ========== ========================================================== Keyword arguments are passed on to :func:`~matplotlib.axes.Axes.scatter`. @@ -1016,7 +1146,25 @@ def scatter(self, xs, ys, zs=0, zdir='z', *args, **kwargs): had_data = self.has_data() - patches = Axes.scatter(self, xs, ys, *args, **kwargs) + xs = np.ma.ravel(xs) + ys = np.ma.ravel(ys) + zs = np.ma.ravel(zs) + if xs.size != ys.size: + raise ValueError("x and y must be the same size") + if xs.size != zs.size and zs.size == 1: + zs = np.array(zs[0] * xs.size) + + s = np.ma.ravel(s) # This doesn't have to match x, y in size. + + cstr = cbook.is_string_like(c) or cbook.is_sequence_of_strings(c) + if not cstr: + c = np.asanyarray(c) + if c.size == xs.size: + c = np.ma.ravel(c) + + xs, ys, zs, s, c = cbook.delete_masked_points(xs, ys, zs, s, c) + + patches = Axes.scatter(self, xs, ys, s=s, c=c, *args, **kwargs) if not cbook.iterable(zs): is_2d = True zs = np.ones(len(xs)) * zs diff --git a/lib/mpl_toolkits/mplot3d/axis3d.py b/lib/mpl_toolkits/mplot3d/axis3d.py index 35e4f0eaeb2e..033b939ec1d6 100644 --- a/lib/mpl_toolkits/mplot3d/axis3d.py +++ b/lib/mpl_toolkits/mplot3d/axis3d.py @@ -73,6 +73,11 @@ def __init__(self, adir, v_intervalx, d_intervalx, axes, *args, **kwargs): self.v_interval = v_intervalx maxis.XAxis.__init__(self, axes, *args, **kwargs) + + self.set_rotate_label(kwargs.get('rotate_label', None)) + + + def init3d(self): self.line = mlines.Line2D(xdata=(0, 0), ydata=(0, 0), linewidth=0.75, color=(0, 0, 0, 1), @@ -80,20 +85,21 @@ def __init__(self, adir, v_intervalx, d_intervalx, axes, *args, **kwargs): ) # Store dummy data in Polygon object - self.has_pane = True self.pane = mpatches.Polygon(np.array([[0,0], [0,1], [1,0], [0,0]]), alpha=0.8, facecolor=(1,1,1,0), edgecolor=(1,1,1,0)) + self.set_pane_color(self._AXINFO[self.adir]['color']) self.axes._set_artist_props(self.line) self.axes._set_artist_props(self.pane) self.gridlines = art3d.Line3DCollection([], ) self.axes._set_artist_props(self.gridlines) self.axes._set_artist_props(self.label) + self.axes._set_artist_props(self.offsetText) # Need to be able to place the label at the correct location self.label._transform = self.axes.transData - self.set_rotate_label(kwargs.get('rotate_label', None)) + self.offsetText._transform = self.axes.transData def get_tick_positions(self): majorLocs = self.major.locator() @@ -111,14 +117,16 @@ def get_major_ticks(self, numticks=None): t.label2.set_transform(self.axes.transData) return ticks - def set_pane(self, xys, color): - if self.has_pane: - xys = np.asarray(xys) - xys = xys[:,:2] - self.pane.xy = xys - self.pane.set_edgecolor(color) - self.pane.set_facecolor(color) - self.pane.set_alpha(color[-1]) + def set_pane_pos(self, xys): + xys = np.asarray(xys) + xys = xys[:,:2] + self.pane.xy = xys + + def set_pane_color(self, color): + '''Set pane color to a RGBA tuple''' + self.pane.set_edgecolor(color) + self.pane.set_facecolor(color) + self.pane.set_alpha(color[-1]) def set_rotate_label(self, val): ''' @@ -162,7 +170,7 @@ def draw_pane(self, renderer): else: plane = self._PLANES[2 * index + 1] xys = [tc[p] for p in plane] - self.set_pane(xys, info['color']) + self.set_pane_pos(xys) self.pane.draw(renderer) renderer.close_group('pane3d') @@ -199,6 +207,7 @@ def draw(self, renderer): edgep2 = edgep1.copy() edgep2[juggled[1]] = get_flip_min_max(edgep2, juggled[1], mins, maxs) pep = proj3d.proj_trans_points([edgep1, edgep2], renderer.M) + centpt = proj3d.proj_transform(centers[0], centers[1], centers[2], renderer.M) self.line.set_data((pep[0][0], pep[0][1]), (pep[1][0], pep[1][1])) self.line.draw(renderer) @@ -237,25 +246,95 @@ def draw(self, renderer): self.label.set_ha('center') self.label.draw(renderer) - # Grid points at end of one plane - xyz1 = copy.deepcopy(xyz0) - newindex = (index + 1) % 3 - newval = get_flip_min_max(xyz1[0], newindex, mins, maxs) - for i in range(len(majorLocs)): - xyz1[i][newindex] = newval - - # Grid points at end of the other plane - xyz2 = copy.deepcopy(xyz0) - newindex = (index + 2) % 3 - newval = get_flip_min_max(xyz2[0], newindex, mins, maxs) - for i in range(len(majorLocs)): - xyz2[i][newindex] = newval - - lines = zip(xyz1, xyz0, xyz2) - if self.axes._draw_grid: - self.gridlines.set_segments(lines) - self.gridlines.set_color([(0.9,0.9,0.9,1)] * len(lines)) - self.gridlines.draw(renderer, project=True) + + # Draw Offset text + + # Which of the two edge points do we want to + # use for locating the offset text? + if juggled[2] == 2 : + outeredgep = edgep1 + outerindex = 0 + else : + outeredgep = edgep2 + outerindex = 1 + + pos = copy.copy(outeredgep) + pos = move_from_center(pos, centers, labeldeltas, axmask) + olx, oly, olz = proj3d.proj_transform(pos[0], pos[1], pos[2], renderer.M) + self.offsetText.set_text( self.major.formatter.get_offset() ) + self.offsetText.set_position( (olx, oly) ) + angle = art3d.norm_text_angle(math.degrees(math.atan2(dy, dx))) + self.offsetText.set_rotation(angle) + # Must set rotation mode to "anchor" so that + # the alignment point is used as the "fulcrum" for rotation. + self.offsetText.set_rotation_mode('anchor') + + #----------------------------------------------------------------------- + # Note: the following statement for determining the proper alignment of + # the offset text. This was determined entirely by trial-and-error + # and should not be in any way considered as "the way". There are + # still some edge cases where alignment is not quite right, but + # this seems to be more of a geometry issue (in other words, I + # might be using the wrong reference points). + # + # (TT, FF, TF, FT) are the shorthand for the tuple of + # (centpt[info['tickdir']] <= peparray[info['tickdir'], outerindex], + # centpt[index] <= peparray[index, outerindex]) + # + # Three-letters (e.g., TFT, FTT) are short-hand for the array + # of bools from the variable 'highs'. + # --------------------------------------------------------------------- + if centpt[info['tickdir']] > peparray[info['tickdir'], outerindex] : + # if FT and if highs has an even number of Trues + if (centpt[index] <= peparray[index, outerindex] + and ((len(highs.nonzero()[0]) % 2) == 0)) : + # Usually, this means align right, except for the FTT case, + # in which offset for axis 1 and 2 are aligned left. + if highs.tolist() == [False, True, True] and index in (1, 2) : + align = 'left' + else : + align = 'right' + else : + # The FF case + align = 'left' + else : + # if TF and if highs has an even number of Trues + if (centpt[index] > peparray[index, outerindex] + and ((len(highs.nonzero()[0]) % 2) == 0)) : + # Usually mean align left, except if it is axis 2 + if index == 2 : + align = 'right' + else : + align = 'left' + else : + # The TT case + align = 'right' + + self.offsetText.set_va('center') + self.offsetText.set_ha(align) + self.offsetText.draw(renderer) + + # Draw grid lines + if len(xyz0) > 0: + # Grid points at end of one plane + xyz1 = copy.deepcopy(xyz0) + newindex = (index + 1) % 3 + newval = get_flip_min_max(xyz1[0], newindex, mins, maxs) + for i in range(len(majorLocs)): + xyz1[i][newindex] = newval + + # Grid points at end of the other plane + xyz2 = copy.deepcopy(xyz0) + newindex = (index + 2) % 3 + newval = get_flip_min_max(xyz2[0], newindex, mins, maxs) + for i in range(len(majorLocs)): + xyz2[i][newindex] = newval + + lines = zip(xyz1, xyz0, xyz2) + if self.axes._draw_grid: + self.gridlines.set_segments(lines) + self.gridlines.set_color([(0.9,0.9,0.9,1)] * len(lines)) + self.gridlines.draw(renderer, project=True) # Draw ticks tickdir = info['tickdir'] @@ -296,19 +375,23 @@ def draw(self, renderer): renderer.close_group('axis3d') def get_view_interval(self): - """return the Interval instance for this axis view limits""" + """return the Interval instance for this 3d axis view limits""" return self.v_interval + + def set_view_interval(self, vmin, vmax, ignore=False): + if ignore: + self.v_interval = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.v_interval = min(vmin, Vmin), max(vmax, Vmax) -# Each type of axis should be looking in a different place for its -# current data limits so we do this with classes. I think there is -# a lot more that I can and should move down into these classes also. +# Use classes to look at different data limits class XAxis(Axis): def get_data_interval(self): 'return the Interval instance for this axis data limits' return self.axes.xy_dataLim.intervalx - class YAxis(Axis): def get_data_interval(self): 'return the Interval instance for this axis data limits' diff --git a/lib/mpl_toolkits/mplot3d/proj3d.py b/lib/mpl_toolkits/mplot3d/proj3d.py index ce4341f769b7..f4d8935b8cee 100644 --- a/lib/mpl_toolkits/mplot3d/proj3d.py +++ b/lib/mpl_toolkits/mplot3d/proj3d.py @@ -51,7 +51,7 @@ def line2d_seg_dist(p1, p2, p0): p0[1] = y(s) intersection point p = p1 + u*(p2-p1) - and intersection point lies within segement if u is between 0 and 1 + and intersection point lies within segment if u is between 0 and 1 """ x21 = p2[0] - p1[0] diff --git a/lib/pytz/__init__.py b/lib/pytz/__init__.py index 8b8f5e873d62..2c1f776f6874 100644 --- a/lib/pytz/__init__.py +++ b/lib/pytz/__init__.py @@ -9,7 +9,7 @@ ''' # The Olson database is updated several times a year. -OLSON_VERSION = '2010h' +OLSON_VERSION = '2010o' VERSION = OLSON_VERSION # Version format for a patch release - only one so far. #VERSION = OLSON_VERSION + '.2' @@ -358,7 +358,7 @@ def __reduce__(self): return FixedOffset, (self._minutes, ) def dst(self, dt): - return None + return ZERO def tzname(self, dt): return None @@ -387,12 +387,16 @@ def FixedOffset(offset, _tzinfos = {}): pytz.FixedOffset(-330) >>> one.utcoffset(datetime.datetime.now()) datetime.timedelta(-1, 66600) + >>> one.dst(datetime.datetime.now()) + datetime.timedelta(0) >>> two = FixedOffset(1380) >>> two pytz.FixedOffset(1380) >>> two.utcoffset(datetime.datetime.now()) datetime.timedelta(0, 82800) + >>> two.dst(datetime.datetime.now()) + datetime.timedelta(0) The datetime.timedelta must be between the range of -1 and 1 day, non-inclusive. @@ -530,6 +534,7 @@ def _test(): 'America/Atikokan', 'America/Atka', 'America/Bahia', + 'America/Bahia_Banderas', 'America/Barbados', 'America/Belem', 'America/Belize', @@ -956,6 +961,7 @@ def _test(): 'Pacific/Apia', 'Pacific/Auckland', 'Pacific/Chatham', + 'Pacific/Chuuk', 'Pacific/Easter', 'Pacific/Efate', 'Pacific/Enderbury', @@ -981,6 +987,7 @@ def _test(): 'Pacific/Pago_Pago', 'Pacific/Palau', 'Pacific/Pitcairn', + 'Pacific/Pohnpei', 'Pacific/Ponape', 'Pacific/Port_Moresby', 'Pacific/Rarotonga', @@ -1095,6 +1102,7 @@ def _test(): 'America/Asuncion', 'America/Atikokan', 'America/Bahia', + 'America/Bahia_Banderas', 'America/Barbados', 'America/Belem', 'America/Belize', @@ -1155,6 +1163,7 @@ def _test(): 'America/Maceio', 'America/Managua', 'America/Manaus', + 'America/Marigot', 'America/Martinique', 'America/Matamoros', 'America/Mazatlan', @@ -1195,6 +1204,8 @@ def _test(): 'America/Santo_Domingo', 'America/Sao_Paulo', 'America/Scoresbysund', + 'America/Shiprock', + 'America/St_Barthelemy', 'America/St_Johns', 'America/St_Kitts', 'America/St_Lucia', @@ -1220,8 +1231,10 @@ def _test(): 'Antarctica/McMurdo', 'Antarctica/Palmer', 'Antarctica/Rothera', + 'Antarctica/South_Pole', 'Antarctica/Syowa', 'Antarctica/Vostok', + 'Arctic/Longyearbyen', 'Asia/Aden', 'Asia/Almaty', 'Asia/Amman', @@ -1331,6 +1344,7 @@ def _test(): 'Europe/Athens', 'Europe/Belgrade', 'Europe/Berlin', + 'Europe/Bratislava', 'Europe/Brussels', 'Europe/Bucharest', 'Europe/Budapest', @@ -1338,35 +1352,46 @@ def _test(): 'Europe/Copenhagen', 'Europe/Dublin', 'Europe/Gibraltar', + 'Europe/Guernsey', 'Europe/Helsinki', + 'Europe/Isle_of_Man', 'Europe/Istanbul', + 'Europe/Jersey', 'Europe/Kaliningrad', 'Europe/Kiev', 'Europe/Lisbon', + 'Europe/Ljubljana', 'Europe/London', 'Europe/Luxembourg', 'Europe/Madrid', 'Europe/Malta', + 'Europe/Mariehamn', 'Europe/Minsk', 'Europe/Monaco', 'Europe/Moscow', 'Europe/Oslo', 'Europe/Paris', + 'Europe/Podgorica', 'Europe/Prague', 'Europe/Riga', 'Europe/Rome', 'Europe/Samara', + 'Europe/San_Marino', + 'Europe/Sarajevo', 'Europe/Simferopol', + 'Europe/Skopje', 'Europe/Sofia', 'Europe/Stockholm', 'Europe/Tallinn', 'Europe/Tirane', 'Europe/Uzhgorod', 'Europe/Vaduz', + 'Europe/Vatican', 'Europe/Vienna', 'Europe/Vilnius', 'Europe/Volgograd', 'Europe/Warsaw', + 'Europe/Zagreb', 'Europe/Zaporozhye', 'Europe/Zurich', 'GMT', @@ -1384,6 +1409,7 @@ def _test(): 'Pacific/Apia', 'Pacific/Auckland', 'Pacific/Chatham', + 'Pacific/Chuuk', 'Pacific/Easter', 'Pacific/Efate', 'Pacific/Enderbury', @@ -1409,14 +1435,13 @@ def _test(): 'Pacific/Pago_Pago', 'Pacific/Palau', 'Pacific/Pitcairn', - 'Pacific/Ponape', + 'Pacific/Pohnpei', 'Pacific/Port_Moresby', 'Pacific/Rarotonga', 'Pacific/Saipan', 'Pacific/Tahiti', 'Pacific/Tarawa', 'Pacific/Tongatapu', - 'Pacific/Truk', 'Pacific/Wake', 'Pacific/Wallis', 'US/Alaska', diff --git a/lib/pytz/tests/test_tzinfo.py b/lib/pytz/tests/test_tzinfo.py index 09b0da7288db..f930c4fe4bd4 100644 --- a/lib/pytz/tests/test_tzinfo.py +++ b/lib/pytz/tests/test_tzinfo.py @@ -16,7 +16,7 @@ # I test for expected version to ensure the correct version of pytz is # actually being tested. -EXPECTED_VERSION='2010h' +EXPECTED_VERSION='2010o' fmt = '%Y-%m-%d %H:%M:%S %Z%z' @@ -44,6 +44,7 @@ def prettydt(dt): dt.hour, dt.minute, dt.second, dt.tzname(), offset) + class BasicTest(unittest.TestCase): def testVersion(self): @@ -643,6 +644,28 @@ def no_testCreateLocaltime(self): '2004-10-31 02:00:00 CET+0100' ) + +class CommonTimezonesTestCase(unittest.TestCase): + def test_bratislava(self): + # Bratislava is the default timezone for Slovakia, but our + # heuristics where not adding it to common_timezones. Ideally, + # common_timezones should be populated from zone.tab at runtime, + # but I'm hesitant to pay the startup cost as loading the list + # on demand whilst remaining backwards compatible seems + # difficult. + self.failUnless('Europe/Bratislava' in pytz.common_timezones) + self.failUnless('Europe/Bratislava' in pytz.common_timezones_set) + + def test_us_eastern(self): + self.failUnless('US/Eastern' in pytz.common_timezones) + self.failUnless('US/Eastern' in pytz.common_timezones_set) + + def test_belfast(self): + # Belfast uses London time. + self.failUnless('Europe/Belfast' in pytz.all_timezones_set) + self.failIf('Europe/Belfast' in pytz.common_timezones) + self.failIf('Europe/Belfast' in pytz.common_timezones_set) + def test_suite(): suite = unittest.TestSuite() suite.addTest(doctest.DocTestSuite('pytz')) @@ -651,6 +674,7 @@ def test_suite(): suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_tzinfo)) return suite + if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff --git a/lib/pytz/zoneinfo/Africa/Bamako b/lib/pytz/zoneinfo/Africa/Bamako index a9259a604ac7..da18d7137740 100644 Binary files a/lib/pytz/zoneinfo/Africa/Bamako and b/lib/pytz/zoneinfo/Africa/Bamako differ diff --git a/lib/pytz/zoneinfo/Africa/Cairo b/lib/pytz/zoneinfo/Africa/Cairo index cd80457fd67c..0b0f374d52c4 100644 Binary files a/lib/pytz/zoneinfo/Africa/Cairo and b/lib/pytz/zoneinfo/Africa/Cairo differ diff --git a/lib/pytz/zoneinfo/Africa/Casablanca b/lib/pytz/zoneinfo/Africa/Casablanca index b9a410f947ab..28ab6bcc93a3 100644 Binary files a/lib/pytz/zoneinfo/Africa/Casablanca and b/lib/pytz/zoneinfo/Africa/Casablanca differ diff --git a/lib/pytz/zoneinfo/Africa/Conakry b/lib/pytz/zoneinfo/Africa/Conakry index 45bcce1cf654..75b8523fb299 100644 Binary files a/lib/pytz/zoneinfo/Africa/Conakry and b/lib/pytz/zoneinfo/Africa/Conakry differ diff --git a/lib/pytz/zoneinfo/Africa/Dar_es_Salaam b/lib/pytz/zoneinfo/Africa/Dar_es_Salaam index 05643e9abce4..3b81079f23bd 100644 Binary files a/lib/pytz/zoneinfo/Africa/Dar_es_Salaam and b/lib/pytz/zoneinfo/Africa/Dar_es_Salaam differ diff --git a/lib/pytz/zoneinfo/Africa/Kampala b/lib/pytz/zoneinfo/Africa/Kampala index 1afbe233fd24..eab63498a625 100644 Binary files a/lib/pytz/zoneinfo/Africa/Kampala and b/lib/pytz/zoneinfo/Africa/Kampala differ diff --git a/lib/pytz/zoneinfo/Africa/Mogadishu b/lib/pytz/zoneinfo/Africa/Mogadishu index 9ce97a66765a..bd08463429de 100644 Binary files a/lib/pytz/zoneinfo/Africa/Mogadishu and b/lib/pytz/zoneinfo/Africa/Mogadishu differ diff --git a/lib/pytz/zoneinfo/Africa/Nairobi b/lib/pytz/zoneinfo/Africa/Nairobi index e557234008f0..933be64c1cfb 100644 Binary files a/lib/pytz/zoneinfo/Africa/Nairobi and b/lib/pytz/zoneinfo/Africa/Nairobi differ diff --git a/lib/pytz/zoneinfo/Africa/Nouakchott b/lib/pytz/zoneinfo/Africa/Nouakchott index 10ca86690c43..ead817afcdd3 100644 Binary files a/lib/pytz/zoneinfo/Africa/Nouakchott and b/lib/pytz/zoneinfo/Africa/Nouakchott differ diff --git a/lib/pytz/zoneinfo/Africa/Timbuktu b/lib/pytz/zoneinfo/Africa/Timbuktu index a9259a604ac7..da18d7137740 100644 Binary files a/lib/pytz/zoneinfo/Africa/Timbuktu and b/lib/pytz/zoneinfo/Africa/Timbuktu differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Catamarca b/lib/pytz/zoneinfo/America/Argentina/Catamarca index 3f8232be8776..b9c987bb5689 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Catamarca and b/lib/pytz/zoneinfo/America/Argentina/Catamarca differ diff --git a/lib/pytz/zoneinfo/America/Argentina/ComodRivadavia b/lib/pytz/zoneinfo/America/Argentina/ComodRivadavia index 3f8232be8776..b9c987bb5689 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/ComodRivadavia and b/lib/pytz/zoneinfo/America/Argentina/ComodRivadavia differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Cordoba b/lib/pytz/zoneinfo/America/Argentina/Cordoba index 2a3eca9d911a..a703e957d5eb 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Cordoba and b/lib/pytz/zoneinfo/America/Argentina/Cordoba differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Jujuy b/lib/pytz/zoneinfo/America/Argentina/Jujuy index 832ba901b3b8..86800f0344a0 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Jujuy and b/lib/pytz/zoneinfo/America/Argentina/Jujuy differ diff --git a/lib/pytz/zoneinfo/America/Argentina/La_Rioja b/lib/pytz/zoneinfo/America/Argentina/La_Rioja index de3878ec1202..333819a15f79 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/La_Rioja and b/lib/pytz/zoneinfo/America/Argentina/La_Rioja differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Mendoza b/lib/pytz/zoneinfo/America/Argentina/Mendoza index 7a9e6860f6ff..76afd5909e0e 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Mendoza and b/lib/pytz/zoneinfo/America/Argentina/Mendoza differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos b/lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos index 5fb3092e47ee..65d0230a2d06 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos and b/lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Salta b/lib/pytz/zoneinfo/America/Argentina/Salta index 1642c198e035..963917a01a26 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Salta and b/lib/pytz/zoneinfo/America/Argentina/Salta differ diff --git a/lib/pytz/zoneinfo/America/Argentina/San_Juan b/lib/pytz/zoneinfo/America/Argentina/San_Juan index a2373bbedfe7..fe7007b85ca4 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/San_Juan and b/lib/pytz/zoneinfo/America/Argentina/San_Juan differ diff --git a/lib/pytz/zoneinfo/America/Argentina/San_Luis b/lib/pytz/zoneinfo/America/Argentina/San_Luis index 6554b0da486a..fa30a68397d2 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/San_Luis and b/lib/pytz/zoneinfo/America/Argentina/San_Luis differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Tucuman b/lib/pytz/zoneinfo/America/Argentina/Tucuman index eb68d6d1d04d..be7bd271639a 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Tucuman and b/lib/pytz/zoneinfo/America/Argentina/Tucuman differ diff --git a/lib/pytz/zoneinfo/America/Argentina/Ushuaia b/lib/pytz/zoneinfo/America/Argentina/Ushuaia index f2c5d6273945..18590effb093 100644 Binary files a/lib/pytz/zoneinfo/America/Argentina/Ushuaia and b/lib/pytz/zoneinfo/America/Argentina/Ushuaia differ diff --git a/lib/pytz/zoneinfo/America/Asuncion b/lib/pytz/zoneinfo/America/Asuncion index 4a377c8e4958..d4014a6b7893 100644 Binary files a/lib/pytz/zoneinfo/America/Asuncion and b/lib/pytz/zoneinfo/America/Asuncion differ diff --git a/lib/pytz/zoneinfo/America/Cambridge_Bay b/lib/pytz/zoneinfo/America/Cambridge_Bay index 9aa642b954e7..99c77c5b2083 100644 Binary files a/lib/pytz/zoneinfo/America/Cambridge_Bay and b/lib/pytz/zoneinfo/America/Cambridge_Bay differ diff --git a/lib/pytz/zoneinfo/America/Cancun b/lib/pytz/zoneinfo/America/Cancun index 3d56e51a457d..90993faa7051 100644 Binary files a/lib/pytz/zoneinfo/America/Cancun and b/lib/pytz/zoneinfo/America/Cancun differ diff --git a/lib/pytz/zoneinfo/America/Caracas b/lib/pytz/zoneinfo/America/Caracas index a2144137a254..d96a5c00bffe 100644 Binary files a/lib/pytz/zoneinfo/America/Caracas and b/lib/pytz/zoneinfo/America/Caracas differ diff --git a/lib/pytz/zoneinfo/America/Catamarca b/lib/pytz/zoneinfo/America/Catamarca index 3f8232be8776..b9c987bb5689 100644 Binary files a/lib/pytz/zoneinfo/America/Catamarca and b/lib/pytz/zoneinfo/America/Catamarca differ diff --git a/lib/pytz/zoneinfo/America/Chicago b/lib/pytz/zoneinfo/America/Chicago index e932c6dcfcab..71aae7246a30 100644 Binary files a/lib/pytz/zoneinfo/America/Chicago and b/lib/pytz/zoneinfo/America/Chicago differ diff --git a/lib/pytz/zoneinfo/America/Chihuahua b/lib/pytz/zoneinfo/America/Chihuahua index 8758bab11149..b2687241cd05 100644 Binary files a/lib/pytz/zoneinfo/America/Chihuahua and b/lib/pytz/zoneinfo/America/Chihuahua differ diff --git a/lib/pytz/zoneinfo/America/Cordoba b/lib/pytz/zoneinfo/America/Cordoba index 2a3eca9d911a..a703e957d5eb 100644 Binary files a/lib/pytz/zoneinfo/America/Cordoba and b/lib/pytz/zoneinfo/America/Cordoba differ diff --git a/lib/pytz/zoneinfo/America/Goose_Bay b/lib/pytz/zoneinfo/America/Goose_Bay index 07c88e593ea7..49ee49fda6a4 100644 Binary files a/lib/pytz/zoneinfo/America/Goose_Bay and b/lib/pytz/zoneinfo/America/Goose_Bay differ diff --git a/lib/pytz/zoneinfo/America/Hermosillo b/lib/pytz/zoneinfo/America/Hermosillo index 08ce31c7ccca..26c269d96748 100644 Binary files a/lib/pytz/zoneinfo/America/Hermosillo and b/lib/pytz/zoneinfo/America/Hermosillo differ diff --git a/lib/pytz/zoneinfo/America/Indiana/Knox b/lib/pytz/zoneinfo/America/Indiana/Knox index 6e66a418902d..33169f459638 100644 Binary files a/lib/pytz/zoneinfo/America/Indiana/Knox and b/lib/pytz/zoneinfo/America/Indiana/Knox differ diff --git a/lib/pytz/zoneinfo/America/Indiana/Tell_City b/lib/pytz/zoneinfo/America/Indiana/Tell_City index de7b730d40b8..97e319e34350 100644 Binary files a/lib/pytz/zoneinfo/America/Indiana/Tell_City and b/lib/pytz/zoneinfo/America/Indiana/Tell_City differ diff --git a/lib/pytz/zoneinfo/America/Iqaluit b/lib/pytz/zoneinfo/America/Iqaluit index a8640e54f675..cea5c2e0f30f 100644 Binary files a/lib/pytz/zoneinfo/America/Iqaluit and b/lib/pytz/zoneinfo/America/Iqaluit differ diff --git a/lib/pytz/zoneinfo/America/Jujuy b/lib/pytz/zoneinfo/America/Jujuy index 832ba901b3b8..86800f0344a0 100644 Binary files a/lib/pytz/zoneinfo/America/Jujuy and b/lib/pytz/zoneinfo/America/Jujuy differ diff --git a/lib/pytz/zoneinfo/America/Knox_IN b/lib/pytz/zoneinfo/America/Knox_IN index 6e66a418902d..33169f459638 100644 Binary files a/lib/pytz/zoneinfo/America/Knox_IN and b/lib/pytz/zoneinfo/America/Knox_IN differ diff --git a/lib/pytz/zoneinfo/America/Managua b/lib/pytz/zoneinfo/America/Managua index 54c8237f3d49..f1c35040ce46 100644 Binary files a/lib/pytz/zoneinfo/America/Managua and b/lib/pytz/zoneinfo/America/Managua differ diff --git a/lib/pytz/zoneinfo/America/Mazatlan b/lib/pytz/zoneinfo/America/Mazatlan index 6486aa1a64e8..43ee12d84a7c 100644 Binary files a/lib/pytz/zoneinfo/America/Mazatlan and b/lib/pytz/zoneinfo/America/Mazatlan differ diff --git a/lib/pytz/zoneinfo/America/Mendoza b/lib/pytz/zoneinfo/America/Mendoza index 7a9e6860f6ff..76afd5909e0e 100644 Binary files a/lib/pytz/zoneinfo/America/Mendoza and b/lib/pytz/zoneinfo/America/Mendoza differ diff --git a/lib/pytz/zoneinfo/America/Menominee b/lib/pytz/zoneinfo/America/Menominee index c07a950c7489..438f5ff0b846 100644 Binary files a/lib/pytz/zoneinfo/America/Menominee and b/lib/pytz/zoneinfo/America/Menominee differ diff --git a/lib/pytz/zoneinfo/America/Merida b/lib/pytz/zoneinfo/America/Merida index 38c794c65994..b46298e1f202 100644 Binary files a/lib/pytz/zoneinfo/America/Merida and b/lib/pytz/zoneinfo/America/Merida differ diff --git a/lib/pytz/zoneinfo/America/Montevideo b/lib/pytz/zoneinfo/America/Montevideo index 40fc865b0147..4745f0dfb2d9 100644 Binary files a/lib/pytz/zoneinfo/America/Montevideo and b/lib/pytz/zoneinfo/America/Montevideo differ diff --git a/lib/pytz/zoneinfo/America/Ojinaga b/lib/pytz/zoneinfo/America/Ojinaga index c77d083c4c3a..37d78301bd10 100644 Binary files a/lib/pytz/zoneinfo/America/Ojinaga and b/lib/pytz/zoneinfo/America/Ojinaga differ diff --git a/lib/pytz/zoneinfo/America/Pangnirtung b/lib/pytz/zoneinfo/America/Pangnirtung index bb428471d71a..80a6009381ef 100644 Binary files a/lib/pytz/zoneinfo/America/Pangnirtung and b/lib/pytz/zoneinfo/America/Pangnirtung differ diff --git a/lib/pytz/zoneinfo/America/Rankin_Inlet b/lib/pytz/zoneinfo/America/Rankin_Inlet index cbc349969802..99195714c4b3 100644 Binary files a/lib/pytz/zoneinfo/America/Rankin_Inlet and b/lib/pytz/zoneinfo/America/Rankin_Inlet differ diff --git a/lib/pytz/zoneinfo/America/Rosario b/lib/pytz/zoneinfo/America/Rosario index 2a3eca9d911a..a703e957d5eb 100644 Binary files a/lib/pytz/zoneinfo/America/Rosario and b/lib/pytz/zoneinfo/America/Rosario differ diff --git a/lib/pytz/zoneinfo/America/St_Johns b/lib/pytz/zoneinfo/America/St_Johns index 48428744e5a6..f5d2855c5b80 100644 Binary files a/lib/pytz/zoneinfo/America/St_Johns and b/lib/pytz/zoneinfo/America/St_Johns differ diff --git a/lib/pytz/zoneinfo/Antarctica/Casey b/lib/pytz/zoneinfo/Antarctica/Casey index 9acead42be0f..76d0794e9565 100644 Binary files a/lib/pytz/zoneinfo/Antarctica/Casey and b/lib/pytz/zoneinfo/Antarctica/Casey differ diff --git a/lib/pytz/zoneinfo/Asia/Aqtau b/lib/pytz/zoneinfo/Asia/Aqtau index 31195d7fc044..27a3d50d3739 100644 Binary files a/lib/pytz/zoneinfo/Asia/Aqtau and b/lib/pytz/zoneinfo/Asia/Aqtau differ diff --git a/lib/pytz/zoneinfo/Asia/Colombo b/lib/pytz/zoneinfo/Asia/Colombo index e5aa06d6b69a..c71c0503d999 100644 Binary files a/lib/pytz/zoneinfo/Asia/Colombo and b/lib/pytz/zoneinfo/Asia/Colombo differ diff --git a/lib/pytz/zoneinfo/Asia/Dili b/lib/pytz/zoneinfo/Asia/Dili index b7ac96e9bf6d..37bfc4b2786b 100644 Binary files a/lib/pytz/zoneinfo/Asia/Dili and b/lib/pytz/zoneinfo/Asia/Dili differ diff --git a/lib/pytz/zoneinfo/Asia/Gaza b/lib/pytz/zoneinfo/Asia/Gaza index b3120cb9109c..043a06ce7371 100644 Binary files a/lib/pytz/zoneinfo/Asia/Gaza and b/lib/pytz/zoneinfo/Asia/Gaza differ diff --git a/lib/pytz/zoneinfo/Asia/Harbin b/lib/pytz/zoneinfo/Asia/Harbin index 292bcb2c7ee4..11e352a51106 100644 Binary files a/lib/pytz/zoneinfo/Asia/Harbin and b/lib/pytz/zoneinfo/Asia/Harbin differ diff --git a/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh b/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh index e8dc8068bb99..6401a10256bb 100644 Binary files a/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh and b/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh differ diff --git a/lib/pytz/zoneinfo/Asia/Hong_Kong b/lib/pytz/zoneinfo/Asia/Hong_Kong index 7ef66519555b..45db6e226144 100644 Binary files a/lib/pytz/zoneinfo/Asia/Hong_Kong and b/lib/pytz/zoneinfo/Asia/Hong_Kong differ diff --git a/lib/pytz/zoneinfo/Asia/Irkutsk b/lib/pytz/zoneinfo/Asia/Irkutsk index 617621f349b5..8e1483e9e2d5 100644 Binary files a/lib/pytz/zoneinfo/Asia/Irkutsk and b/lib/pytz/zoneinfo/Asia/Irkutsk differ diff --git a/lib/pytz/zoneinfo/Asia/Jayapura b/lib/pytz/zoneinfo/Asia/Jayapura index af227c029d7c..0e79d3178813 100644 Binary files a/lib/pytz/zoneinfo/Asia/Jayapura and b/lib/pytz/zoneinfo/Asia/Jayapura differ diff --git a/lib/pytz/zoneinfo/Asia/Jerusalem b/lib/pytz/zoneinfo/Asia/Jerusalem index f64f3afde5f0..4e6410f2b2d3 100644 Binary files a/lib/pytz/zoneinfo/Asia/Jerusalem and b/lib/pytz/zoneinfo/Asia/Jerusalem differ diff --git a/lib/pytz/zoneinfo/Asia/Krasnoyarsk b/lib/pytz/zoneinfo/Asia/Krasnoyarsk index 9b2fb8eb2f45..e0a53b915125 100644 Binary files a/lib/pytz/zoneinfo/Asia/Krasnoyarsk and b/lib/pytz/zoneinfo/Asia/Krasnoyarsk differ diff --git a/lib/pytz/zoneinfo/Asia/Magadan b/lib/pytz/zoneinfo/Asia/Magadan index 7b3d505e35fc..98674195508a 100644 Binary files a/lib/pytz/zoneinfo/Asia/Magadan and b/lib/pytz/zoneinfo/Asia/Magadan differ diff --git a/lib/pytz/zoneinfo/Asia/Makassar b/lib/pytz/zoneinfo/Asia/Makassar index 736a25b4a0a7..f35823303bcd 100644 Binary files a/lib/pytz/zoneinfo/Asia/Makassar and b/lib/pytz/zoneinfo/Asia/Makassar differ diff --git a/lib/pytz/zoneinfo/Asia/Manila b/lib/pytz/zoneinfo/Asia/Manila index efef03eecdb6..0e90ba6326a2 100644 Binary files a/lib/pytz/zoneinfo/Asia/Manila and b/lib/pytz/zoneinfo/Asia/Manila differ diff --git a/lib/pytz/zoneinfo/Asia/Omsk b/lib/pytz/zoneinfo/Asia/Omsk index 77b82ed0fcd4..f47337f62f5a 100644 Binary files a/lib/pytz/zoneinfo/Asia/Omsk and b/lib/pytz/zoneinfo/Asia/Omsk differ diff --git a/lib/pytz/zoneinfo/Asia/Phnom_Penh b/lib/pytz/zoneinfo/Asia/Phnom_Penh index b9768b1c2929..5a52722a1612 100644 Binary files a/lib/pytz/zoneinfo/Asia/Phnom_Penh and b/lib/pytz/zoneinfo/Asia/Phnom_Penh differ diff --git a/lib/pytz/zoneinfo/Asia/Pyongyang b/lib/pytz/zoneinfo/Asia/Pyongyang index e072692c8c1d..9dbd3c1ae006 100644 Binary files a/lib/pytz/zoneinfo/Asia/Pyongyang and b/lib/pytz/zoneinfo/Asia/Pyongyang differ diff --git a/lib/pytz/zoneinfo/Asia/Riyadh87 b/lib/pytz/zoneinfo/Asia/Riyadh87 index 2edb566e5404..ebe16c49957c 100644 Binary files a/lib/pytz/zoneinfo/Asia/Riyadh87 and b/lib/pytz/zoneinfo/Asia/Riyadh87 differ diff --git a/lib/pytz/zoneinfo/Asia/Riyadh88 b/lib/pytz/zoneinfo/Asia/Riyadh88 index 0dac63b4aa8b..7f2224bbb29b 100644 Binary files a/lib/pytz/zoneinfo/Asia/Riyadh88 and b/lib/pytz/zoneinfo/Asia/Riyadh88 differ diff --git a/lib/pytz/zoneinfo/Asia/Riyadh89 b/lib/pytz/zoneinfo/Asia/Riyadh89 index daba1e72f01a..a50ca48a91b9 100644 Binary files a/lib/pytz/zoneinfo/Asia/Riyadh89 and b/lib/pytz/zoneinfo/Asia/Riyadh89 differ diff --git a/lib/pytz/zoneinfo/Asia/Saigon b/lib/pytz/zoneinfo/Asia/Saigon index e8dc8068bb99..6401a10256bb 100644 Binary files a/lib/pytz/zoneinfo/Asia/Saigon and b/lib/pytz/zoneinfo/Asia/Saigon differ diff --git a/lib/pytz/zoneinfo/Asia/Seoul b/lib/pytz/zoneinfo/Asia/Seoul index 1c3c15f9d782..96bb0c36d7e3 100644 Binary files a/lib/pytz/zoneinfo/Asia/Seoul and b/lib/pytz/zoneinfo/Asia/Seoul differ diff --git a/lib/pytz/zoneinfo/Asia/Taipei b/lib/pytz/zoneinfo/Asia/Taipei index 906363660654..70cfb27ca91f 100644 Binary files a/lib/pytz/zoneinfo/Asia/Taipei and b/lib/pytz/zoneinfo/Asia/Taipei differ diff --git a/lib/pytz/zoneinfo/Asia/Tbilisi b/lib/pytz/zoneinfo/Asia/Tbilisi index 6cca2d4f999b..d7e40548acec 100644 Binary files a/lib/pytz/zoneinfo/Asia/Tbilisi and b/lib/pytz/zoneinfo/Asia/Tbilisi differ diff --git a/lib/pytz/zoneinfo/Asia/Tehran b/lib/pytz/zoneinfo/Asia/Tehran index 916694077383..16149ed6bf5b 100644 Binary files a/lib/pytz/zoneinfo/Asia/Tehran and b/lib/pytz/zoneinfo/Asia/Tehran differ diff --git a/lib/pytz/zoneinfo/Asia/Tel_Aviv b/lib/pytz/zoneinfo/Asia/Tel_Aviv index f64f3afde5f0..4e6410f2b2d3 100644 Binary files a/lib/pytz/zoneinfo/Asia/Tel_Aviv and b/lib/pytz/zoneinfo/Asia/Tel_Aviv differ diff --git a/lib/pytz/zoneinfo/Asia/Ujung_Pandang b/lib/pytz/zoneinfo/Asia/Ujung_Pandang index 736a25b4a0a7..f35823303bcd 100644 Binary files a/lib/pytz/zoneinfo/Asia/Ujung_Pandang and b/lib/pytz/zoneinfo/Asia/Ujung_Pandang differ diff --git a/lib/pytz/zoneinfo/Asia/Vientiane b/lib/pytz/zoneinfo/Asia/Vientiane index 9352adfa9a36..7d39589f19e8 100644 Binary files a/lib/pytz/zoneinfo/Asia/Vientiane and b/lib/pytz/zoneinfo/Asia/Vientiane differ diff --git a/lib/pytz/zoneinfo/Asia/Vladivostok b/lib/pytz/zoneinfo/Asia/Vladivostok index 8f880cece23f..514489555fb2 100644 Binary files a/lib/pytz/zoneinfo/Asia/Vladivostok and b/lib/pytz/zoneinfo/Asia/Vladivostok differ diff --git a/lib/pytz/zoneinfo/Asia/Yakutsk b/lib/pytz/zoneinfo/Asia/Yakutsk index 5887a102005c..e25574570c2a 100644 Binary files a/lib/pytz/zoneinfo/Asia/Yakutsk and b/lib/pytz/zoneinfo/Asia/Yakutsk differ diff --git a/lib/pytz/zoneinfo/Atlantic/Stanley b/lib/pytz/zoneinfo/Atlantic/Stanley index 33a6bbe6d038..4cb6097cbeb0 100644 Binary files a/lib/pytz/zoneinfo/Atlantic/Stanley and b/lib/pytz/zoneinfo/Atlantic/Stanley differ diff --git a/lib/pytz/zoneinfo/Canada/Newfoundland b/lib/pytz/zoneinfo/Canada/Newfoundland index 48428744e5a6..f5d2855c5b80 100644 Binary files a/lib/pytz/zoneinfo/Canada/Newfoundland and b/lib/pytz/zoneinfo/Canada/Newfoundland differ diff --git a/lib/pytz/zoneinfo/Egypt b/lib/pytz/zoneinfo/Egypt index cd80457fd67c..0b0f374d52c4 100644 Binary files a/lib/pytz/zoneinfo/Egypt and b/lib/pytz/zoneinfo/Egypt differ diff --git a/lib/pytz/zoneinfo/Europe/Helsinki b/lib/pytz/zoneinfo/Europe/Helsinki index 97229f3157ed..19d7babd531f 100644 Binary files a/lib/pytz/zoneinfo/Europe/Helsinki and b/lib/pytz/zoneinfo/Europe/Helsinki differ diff --git a/lib/pytz/zoneinfo/Europe/Mariehamn b/lib/pytz/zoneinfo/Europe/Mariehamn index 97229f3157ed..19d7babd531f 100644 Binary files a/lib/pytz/zoneinfo/Europe/Mariehamn and b/lib/pytz/zoneinfo/Europe/Mariehamn differ diff --git a/lib/pytz/zoneinfo/Europe/Moscow b/lib/pytz/zoneinfo/Europe/Moscow index eb7619ccde4d..cf001a555fea 100644 Binary files a/lib/pytz/zoneinfo/Europe/Moscow and b/lib/pytz/zoneinfo/Europe/Moscow differ diff --git a/lib/pytz/zoneinfo/Hongkong b/lib/pytz/zoneinfo/Hongkong index 7ef66519555b..45db6e226144 100644 Binary files a/lib/pytz/zoneinfo/Hongkong and b/lib/pytz/zoneinfo/Hongkong differ diff --git a/lib/pytz/zoneinfo/Iran b/lib/pytz/zoneinfo/Iran index 916694077383..16149ed6bf5b 100644 Binary files a/lib/pytz/zoneinfo/Iran and b/lib/pytz/zoneinfo/Iran differ diff --git a/lib/pytz/zoneinfo/Israel b/lib/pytz/zoneinfo/Israel index f64f3afde5f0..4e6410f2b2d3 100644 Binary files a/lib/pytz/zoneinfo/Israel and b/lib/pytz/zoneinfo/Israel differ diff --git a/lib/pytz/zoneinfo/Mexico/BajaSur b/lib/pytz/zoneinfo/Mexico/BajaSur index 6486aa1a64e8..43ee12d84a7c 100644 Binary files a/lib/pytz/zoneinfo/Mexico/BajaSur and b/lib/pytz/zoneinfo/Mexico/BajaSur differ diff --git a/lib/pytz/zoneinfo/Mideast/Riyadh87 b/lib/pytz/zoneinfo/Mideast/Riyadh87 index 2edb566e5404..ebe16c49957c 100644 Binary files a/lib/pytz/zoneinfo/Mideast/Riyadh87 and b/lib/pytz/zoneinfo/Mideast/Riyadh87 differ diff --git a/lib/pytz/zoneinfo/Mideast/Riyadh88 b/lib/pytz/zoneinfo/Mideast/Riyadh88 index 0dac63b4aa8b..7f2224bbb29b 100644 Binary files a/lib/pytz/zoneinfo/Mideast/Riyadh88 and b/lib/pytz/zoneinfo/Mideast/Riyadh88 differ diff --git a/lib/pytz/zoneinfo/Mideast/Riyadh89 b/lib/pytz/zoneinfo/Mideast/Riyadh89 index daba1e72f01a..a50ca48a91b9 100644 Binary files a/lib/pytz/zoneinfo/Mideast/Riyadh89 and b/lib/pytz/zoneinfo/Mideast/Riyadh89 differ diff --git a/lib/pytz/zoneinfo/Pacific/Apia b/lib/pytz/zoneinfo/Pacific/Apia index 52844a9e51ef..8886f365f036 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Apia and b/lib/pytz/zoneinfo/Pacific/Apia differ diff --git a/lib/pytz/zoneinfo/Pacific/Fiji b/lib/pytz/zoneinfo/Pacific/Fiji index e0d580639cac..b2f6cac9c242 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Fiji and b/lib/pytz/zoneinfo/Pacific/Fiji differ diff --git a/lib/pytz/zoneinfo/Pacific/Kosrae b/lib/pytz/zoneinfo/Pacific/Kosrae index 6cac75a51e5a..61b7561589cb 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Kosrae and b/lib/pytz/zoneinfo/Pacific/Kosrae differ diff --git a/lib/pytz/zoneinfo/Pacific/Truk b/lib/pytz/zoneinfo/Pacific/Truk index 4bb15e1fe448..0ef473871d55 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Truk and b/lib/pytz/zoneinfo/Pacific/Truk differ diff --git a/lib/pytz/zoneinfo/Pacific/Yap b/lib/pytz/zoneinfo/Pacific/Yap index 4bb15e1fe448..0ef473871d55 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Yap and b/lib/pytz/zoneinfo/Pacific/Yap differ diff --git a/lib/pytz/zoneinfo/ROC b/lib/pytz/zoneinfo/ROC index 906363660654..70cfb27ca91f 100644 Binary files a/lib/pytz/zoneinfo/ROC and b/lib/pytz/zoneinfo/ROC differ diff --git a/lib/pytz/zoneinfo/ROK b/lib/pytz/zoneinfo/ROK index 1c3c15f9d782..96bb0c36d7e3 100644 Binary files a/lib/pytz/zoneinfo/ROK and b/lib/pytz/zoneinfo/ROK differ diff --git a/lib/pytz/zoneinfo/US/Central b/lib/pytz/zoneinfo/US/Central index e932c6dcfcab..71aae7246a30 100644 Binary files a/lib/pytz/zoneinfo/US/Central and b/lib/pytz/zoneinfo/US/Central differ diff --git a/lib/pytz/zoneinfo/US/Indiana-Starke b/lib/pytz/zoneinfo/US/Indiana-Starke index 6e66a418902d..33169f459638 100644 Binary files a/lib/pytz/zoneinfo/US/Indiana-Starke and b/lib/pytz/zoneinfo/US/Indiana-Starke differ diff --git a/lib/pytz/zoneinfo/W-SU b/lib/pytz/zoneinfo/W-SU index eb7619ccde4d..cf001a555fea 100644 Binary files a/lib/pytz/zoneinfo/W-SU and b/lib/pytz/zoneinfo/W-SU differ diff --git a/lib/pytz/zoneinfo/localtime b/lib/pytz/zoneinfo/localtime index a65f97edd26d..2ee14295f108 100644 Binary files a/lib/pytz/zoneinfo/localtime and b/lib/pytz/zoneinfo/localtime differ diff --git a/lib/pytz/zoneinfo/zone.tab b/lib/pytz/zoneinfo/zone.tab index 52b1770b303c..2bdf92307776 100644 --- a/lib/pytz/zoneinfo/zone.tab +++ b/lib/pytz/zoneinfo/zone.tab @@ -1,5 +1,5 @@ #
-# @(#)zone.tab	8.35
+# @(#)zone.tab	8.38
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 #
@@ -41,7 +41,7 @@ AQ	-6448-06406	Antarctica/Palmer	Palmer Station, Anvers Island
 AQ	-6736+06253	Antarctica/Mawson	Mawson Station, Holme Bay
 AQ	-6835+07758	Antarctica/Davis	Davis Station, Vestfold Hills
 AQ	-6617+11031	Antarctica/Casey	Casey Station, Bailey Peninsula
-AQ	-7824+10654	Antarctica/Vostok	Vostok Station, S Magnetic Pole
+AQ	-7824+10654	Antarctica/Vostok	Vostok Station, Lake Vostok
 AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Terre Adelie
 AQ	-690022+0393524	Antarctica/Syowa	Syowa Station, E Ongul I
 AQ	-5430+15857	Antarctica/Macquarie	Macquarie Island Station, Macquarie Island
@@ -177,8 +177,8 @@ ET	+0902+03842	Africa/Addis_Ababa
 FI	+6010+02458	Europe/Helsinki
 FJ	-1808+17825	Pacific/Fiji
 FK	-5142-05751	Atlantic/Stanley
-FM	+0725+15147	Pacific/Truk	Truk (Chuuk) and Yap
-FM	+0658+15813	Pacific/Ponape	Ponape (Pohnpei)
+FM	+0725+15147	Pacific/Chuuk	Chuuk (Truk) and Yap
+FM	+0658+15813	Pacific/Pohnpei	Pohnpei (Ponape)
 FM	+0519+16259	Pacific/Kosrae	Kosrae
 FO	+6201-00646	Atlantic/Faroe
 FR	+4852+00220	Europe/Paris
@@ -288,6 +288,7 @@ MX	+2934-10425	America/Ojinaga	US Mountain Time - Chihuahua near US border
 MX	+2904-11058	America/Hermosillo	Mountain Standard Time - Sonora
 MX	+3232-11701	America/Tijuana	US Pacific Time - Baja California near US border
 MX	+3018-11452	America/Santa_Isabel	Mexican Pacific Time - Baja California away from US border
+MX	+2048-10515	America/Bahia_Banderas	Mexican Central Time - Bahia de Banderas
 MY	+0310+10142	Asia/Kuala_Lumpur	peninsular Malaysia
 MY	+0133+11020	Asia/Kuching	Sabah & Sarawak
 MZ	-2558+03235	Africa/Maputo
diff --git a/make.osx b/make.osx
index 564b72a9d58f..d3093a731244 100644
--- a/make.osx
+++ b/make.osx
@@ -1,6 +1,6 @@
 # build mpl into a local install dir with
 # PREFIX=/Users/jdhunter/dev make -f make.osx fetch deps mpl_install
-
+MPLVERSION=1.0rc1
 PYVERSION=2.6
 PYTHON=python${PYVERSION}
 ZLIBVERSION=1.2.3
@@ -21,6 +21,9 @@ CFLAGS="-arch i386 -arch x86_64 -I${PREFIX}/include -I${PREFIX}/include/freetype
 LDFLAGS="-arch i386 -arch x86_64 -L${PREFIX}/lib -syslibroot,/Developer/SDKs/MacOSX${OSX_SDK_VER}.sdk"
 FFLAGS="-arch i386 -arch x86_64"
 
+check-prefix:
+	@if [ ! -d "$(PREFIX)" ]; then echo Set PREFIX to a directory - see README.osx; exit 1; fi
+
 clean:
 	rm -rf zlib-${ZLIBVERSION}.tar.gz libpng-${PNGVERSION}.tar.bz2 \
 	freetype-${FREETYPEVERSION}.tar.bz2 bdist_mpkg-${BDISTMPKGVERSION}.tar.gz \
@@ -38,7 +41,7 @@ fetch:
 
 
 
-zlib:
+zlib: check-prefix
 	export PKG_CONFIG_PATH=${PKG_CONFIG_PATH} &&\
 	rm -rf zlib-${ZLIBVERSION} &&\
 	tar xvfz zlib-${ZLIBVERSION}.tar.gz &&\
@@ -50,7 +53,7 @@ zlib:
 	MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} make -j3 install&& \
 	unset MACOSX_DEPLOYMENT_TARGET
 
-png: zlib
+png: zlib check-prefix
 	export PKG_CONFIG_PATH=${PKG_CONFIG_PATH} &&\
 	rm -rf libpng-${PNGVERSION} &&\
 	tar xvfz libpng-${PNGVERSION}.tar.gz && \
@@ -64,7 +67,7 @@ png: zlib
 	unset MACOSX_DEPLOYMENT_TARGET
 
 
-freetype: zlib
+freetype: zlib check-prefix
 	export PKG_CONFIG_PATH=${PKG_CONFIG_PATH} &&\
 	rm -rf ${FREETYPEVERSION} &&\
 	tar xvfj freetype-${FREETYPEVERSION}.tar.bz2 &&\
@@ -88,7 +91,7 @@ mpl_build:
 	export LDFLAGS=${LDFLAGS} &&\
 	${PYTHON} setup.py build
 
-mpl_install:
+mpl_install: check-prefix
 	export PKG_CONFIG_PATH=${PKG_CONFIG_PATH} &&\
 	export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} &&\
 	export CFLAGS=${CFLAGS} &&\
@@ -96,12 +99,12 @@ mpl_install:
 	${PYTHON} setup.py install --prefix=${PREFIX}
 
 
-binaries:
+binaries: check-prefix
 	unset PKG_CONFIG_PATH &&\
 	cp release/osx/data/setup.cfg release/osx/data/ReadMe.txt . &&\
 	export CFLAGS=${CFLAGS} &&\
 	export LDFLAGS=${LDFLAGS} &&\
 	rm -f ${PREFIX}/lib/*.dylib &&\
-	/Library/Frameworks/Python.framework/Versions/${PYVERSION}/bin/bdist_mpkg --readme=ReadMe.txt &&\
-	hdiutil create -srcdir dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx10.5.mpkg  dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx10.5.dmg &&\
-	${PYTHON} setupegg.py bdist_egg
+	VERSIONER_PYTHON_PREFER_32_BIT=yes bdist_mpkg --readme=ReadMe.txt &&\
+	hdiutil create -srcdir dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx${OSX_SDK_VER}.mpkg  dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx${OSX_SDK_VER}.dmg &&\
+	VERSIONER_PYTHON_PREFER_32_BIT=yes ${PYTHON} setupegg.py bdist_egg
diff --git a/setup.cfg.template b/setup.cfg.template
index 6ea8cfe73565..1dd1ca1cbb14 100644
--- a/setup.cfg.template
+++ b/setup.cfg.template
@@ -58,7 +58,6 @@ tag_svn_revision = 1
 #gtk = False
 #gtkagg = False
 #tkagg = False
-#wxagg = False
 #macosx = False
 
 [rc_options]
@@ -74,10 +73,3 @@ tag_svn_revision = 1
 #
 #backend = Agg
 #
-# The numerix module was historically used to provide
-# compatibility between the Numeric, numarray, and NumPy array
-# packages. Now that NumPy has emerge as the universal array
-# package for python, numerix is not really necessary and is
-# maintained to provide backward compatibility. Do not change
-# this unless you have a compelling reason to do so.
-#numerix = numpy
diff --git a/setup.py b/setup.py
index a319228e9646..6510f2538472 100644
--- a/setup.py
+++ b/setup.py
@@ -33,12 +33,12 @@
 
 import glob
 from distutils.core import setup
-from setupext import build_agg, build_gtkagg, build_tkagg, build_wxagg,\
+from setupext import build_agg, build_gtkagg, build_tkagg,\
      build_macosx, build_ft2font, build_image, build_windowing, build_path, \
      build_contour, build_delaunay, build_nxutils, build_gdk, \
      build_ttconv, print_line, print_status, print_message, \
      print_raw, check_for_freetype, check_for_libpng, check_for_gtk, \
-     check_for_tk, check_for_wx, check_for_macosx, check_for_numpy, \
+     check_for_tk, check_for_macosx, check_for_numpy, \
      check_for_qt, check_for_qt4, check_for_cairo, \
      check_provide_pytz, check_provide_dateutil,\
      check_for_dvipng, check_for_ghostscript, check_for_latex, \
@@ -54,20 +54,12 @@
     'matplotlib.testing',
     'matplotlib.testing.jpl_units',
     'matplotlib.tests',
-#   'matplotlib.toolkits',
     'mpl_toolkits',
     'mpl_toolkits.mplot3d',
     'mpl_toolkits.axes_grid',
     'mpl_toolkits.axes_grid1',
     'mpl_toolkits.axisartist',
     'matplotlib.sphinxext',
-    # The following are deprecated and will be removed.
-    'matplotlib.numerix',
-    'matplotlib.numerix.mlab',
-    'matplotlib.numerix.ma',
-    'matplotlib.numerix.linear_algebra',
-    'matplotlib.numerix.random_array',
-    'matplotlib.numerix.fft',
     'matplotlib.tri',
 
     ]
@@ -76,7 +68,7 @@
 
 ext_modules = []
 
-for line in file('lib/matplotlib/__init__.py').readlines():
+for line in open('lib/matplotlib/__init__.py').readlines():
     if (line.startswith('__version__')):
         exec(line.strip())
 
@@ -164,17 +156,6 @@ def chop_package(fname):
         build_tkagg(ext_modules, packages)
         rc['backend'] = 'TkAgg'
 
-if options['build_wxagg']:
-    if check_for_wx() or (options['build_wxagg'] is True):
-        options['build_agg'] = 1
-        import wx
-        if getattr(wx, '__version__', '0.0')[0:3] < '2.8' :
-            build_wxagg(ext_modules, packages)
-            wxagg_backend_status = "yes"
-        else:
-            print_message("WxAgg extension not required for wxPython >= 2.8")
-        rc['backend'] = 'WXAgg'
-
 hasgtk = check_for_gtk()
 if options['build_gtk']:
     if hasgtk or (options['build_gtk'] is True):
@@ -235,7 +216,7 @@ def add_dateutil():
         # only add them if we need them
         if provide_pytz:
             add_pytz()
-            print 'adding pytz'
+            print_raw("adding pytz")
         if provide_dateutil: add_dateutil()
 
 print_raw("")
@@ -251,14 +232,14 @@ def add_dateutil():
 
 # Write the default matplotlibrc file
 if options['backend']: rc['backend'] = options['backend']
-template = file('matplotlibrc.template').read()
-file('lib/matplotlib/mpl-data/matplotlibrc', 'w').write(template%rc)
+template = open('matplotlibrc.template').read()
+open('lib/matplotlib/mpl-data/matplotlibrc', 'w').write(template%rc)
 
 # Write the default matplotlib.conf file
-template = file('lib/matplotlib/mpl-data/matplotlib.conf.template').read()
+template = open('lib/matplotlib/mpl-data/matplotlib.conf.template').read()
 template = template.replace("datapath = ", "#datapath = ")
 template = template.replace("    use = 'Agg'", "    use = '%s'"%rc['backend'])
-file('lib/matplotlib/mpl-data/matplotlib.conf', 'w').write(template)
+open('lib/matplotlib/mpl-data/matplotlib.conf', 'w').write(template)
 
 try: additional_params # has setupegg.py provided
 except NameError: additional_params = {}
@@ -267,8 +248,8 @@ def add_dateutil():
     if options['verbose']:
         mod.extra_compile_args.append('-DVERBOSE')
 
-print 'pymods', py_modules
-print 'packages', packages
+print_raw("pymods %s" % py_modules)
+print_raw("packages %s" % packages)
 distrib = setup(name="matplotlib",
       version= __version__,
       description = "Python plotting package",
diff --git a/setupegg.py b/setupegg.py
index 56a373ae3a8b..0d51b3eeb47e 100644
--- a/setupegg.py
+++ b/setupegg.py
@@ -6,8 +6,5 @@
 execfile('setup.py',
          {'additional_params' :
           {'namespace_packages' : ['mpl_toolkits'],
-           'entry_points': {'nose.plugins':
-                            [
-    'KnownFailure =  matplotlib.testing.noseclasses:KnownFailure',
-    ]
-                            }}})
+           #'entry_points': {'nose.plugins':  ['KnownFailure =  matplotlib.testing.noseclasses:KnownFailure', ] }
+           }})
diff --git a/setupext.py b/setupext.py
index a4c60bf2f7f2..9ee3453e9932 100644
--- a/setupext.py
+++ b/setupext.py
@@ -78,13 +78,21 @@
 }
 
 import sys, os, stat
-if sys.platform != 'win32':
-    import commands
+
 from textwrap import fill
 from distutils.core import Extension
 import glob
-import ConfigParser
-import cStringIO
+
+if sys.version_info[0] < 3:
+    import ConfigParser as configparser
+    from cStringIO import StringIO
+    if sys.platform != 'win32':
+        from commands import getstatusoutput
+else:
+    import configparser
+    from io import StringIO
+    if sys.platform != 'win32':
+        from subprocess import getstatusoutput
 
 BUILT_PNG       = False
 BUILT_AGG       = False
@@ -94,7 +102,6 @@
 BUILT_IMAGE     = False
 BUILT_MACOSX    = False
 BUILT_TKAGG     = False
-BUILT_WXAGG     = False
 BUILT_WINDOWING = False
 BUILT_CONTOUR   = False
 BUILT_DELAUNAY  = False
@@ -119,7 +126,6 @@
            'build_gtk': 'auto',
            'build_gtkagg': 'auto',
            'build_tkagg': 'auto',
-           'build_wxagg': 'auto',
            'build_macosx': 'auto',
            'build_image': True,
            'build_windowing': True,
@@ -130,10 +136,11 @@
         ('PY_ARRAY_UNIQUE_SYMBOL', 'MPL_ARRAY_API'),
         ('PYCXX_ISO_CPP_LIB', '1')]
 
+setup_cfg = os.environ.get('MPLSETUPCFG', 'setup.cfg')
 # Based on the contents of setup.cfg, determine the build options
-if os.path.exists("setup.cfg"):
-    config = ConfigParser.SafeConfigParser()
-    config.read("setup.cfg")
+if os.path.exists(setup_cfg):
+    config = configparser.SafeConfigParser()
+    config.read(setup_cfg)
 
     try: options['display_status'] = not config.getboolean("status", "suppress")
     except: pass
@@ -157,9 +164,6 @@
     try: options['build_tkagg'] = config.getboolean("gui_support", "tkagg")
     except: options['build_tkagg'] = 'auto'
 
-    try: options['build_wxagg'] = config.getboolean("gui_support", "wxagg")
-    except: options['build_wxagg'] = 'auto'
-
     try: options['build_macosx'] = config.getboolean("gui_support", "macosx")
     except: options['build_macosx'] = 'auto'
 
@@ -174,27 +178,27 @@
     basedirlist = options['basedirlist'].split()
 else:
     basedirlist = basedir[sys.platform]
-print "basedirlist is:", basedirlist
+print("basedirlist is: %s" % basedirlist)
 
 if options['display_status']:
     def print_line(char='='):
-        print char * 76
+        print(char * 76)
 
     def print_status(package, status):
         initial_indent = "%22s: " % package
         indent = ' ' * 24
-        print fill(str(status), width=76,
+        print(fill(str(status), width=76,
                    initial_indent=initial_indent,
-                   subsequent_indent=indent)
+                   subsequent_indent=indent))
 
     def print_message(message):
         indent = ' ' * 24 + "* "
-        print fill(str(message), width=76,
+        print(fill(str(message), width=76,
                    initial_indent=indent,
-                   subsequent_indent=indent)
+                   subsequent_indent=indent))
 
     def print_raw(section):
-        print section
+        print(section)
 else:
     def print_line(*args, **kwargs):
         pass
@@ -248,7 +252,7 @@ def has_pkgconfig():
         has_pkgconfig.cache = False
     else:
         #print 'environ',  os.environ['PKG_CONFIG_PATH']
-        status, output = commands.getstatusoutput("pkg-config --help")
+        status, output = getstatusoutput("pkg-config --help")
         has_pkgconfig.cache = (status == 0)
     return has_pkgconfig.cache
 has_pkgconfig.cache = None
@@ -270,7 +274,7 @@ def get_pkgconfig(module,
               '-U': 'undef_macros'}
 
     cmd = "%s %s %s" % (pkg_config_exec, flags, packages)
-    status, output = commands.getstatusoutput(cmd)
+    status, output = getstatusoutput(cmd)
     if status == 0:
         for token in output.split():
             attr = _flags.get(token[:2], None)
@@ -298,7 +302,7 @@ def get_pkgconfig_version(package):
     if not has_pkgconfig():
         return default
 
-    status, output = commands.getstatusoutput(
+    status, output = getstatusoutput(
         "pkg-config %s --modversion" % (package))
     if status == 0:
         return output
@@ -466,7 +470,7 @@ def check_provide_dateutil(hasdatetime=True):
 def check_for_dvipng():
     try:
         stdin, stdout = run_child_process('dvipng -version')
-        print_status("dvipng", stdout.readlines()[1].split()[-1])
+        print_status("dvipng", stdout.readlines()[1].decode().split()[-1])
         return True
     except (IndexError, ValueError):
         print_status("dvipng", "no")
@@ -479,7 +483,7 @@ def check_for_ghostscript():
         else:
             command = 'gs --version'
         stdin, stdout = run_child_process(command)
-        print_status("ghostscript", stdout.read()[:-1])
+        print_status("ghostscript", stdout.read().decode()[:-1])
         return True
     except (IndexError, ValueError):
         print_status("ghostscript", "no")
@@ -488,7 +492,7 @@ def check_for_ghostscript():
 def check_for_latex():
     try:
         stdin, stdout = run_child_process('latex -version')
-        line = stdout.readlines()[0]
+        line = stdout.readlines()[0].decode()
         pattern = '(3\.1\d+)|(MiKTeX \d+.\d+)'
         match = re.search(pattern, line)
         print_status("latex", match.group(0))
@@ -501,6 +505,7 @@ def check_for_pdftops():
     try:
         stdin, stdout = run_child_process('pdftops -v')
         for line in stdout.readlines():
+            line = line.decode()
             if 'version' in line:
                 print_status("pdftops", line.split()[-1])
                 return True
@@ -700,101 +705,9 @@ def add_pygtk_flags(module):
     if sys.platform == 'win32' and win32_compiler == 'msvc' and 'm' in module.libraries:
         module.libraries.remove('m')
 
-
-def check_for_wx():
-    gotit = False
-    explanation = None
-    try:
-        import wx
-    except ImportError:
-        explanation = 'wxPython not found'
-    else:
-        if getattr(wx, '__version__', '0.0')[0:3] >= '2.8':
-            print_status("wxPython", wx.__version__)
-            return True
-        elif sys.platform == 'win32' and win32_compiler == 'mingw32':
-            explanation = "The wxAgg extension can not be built using the mingw32 compiler on Windows, since the default wxPython binary is built using MS Visual Studio"
-        else:
-            wxconfig = find_wx_config()
-            if wxconfig is None:
-                explanation = """
-WXAgg's accelerator requires `wx-config'.
-
-The `wx-config\' executable could not be located in any directory of the
-PATH environment variable. If you want to build WXAgg, and wx-config is
-in some other location or has some other name, set the WX_CONFIG
-environment variable to the full path of the executable like so:
-
-export WX_CONFIG=/usr/lib/wxPython-2.6.1.0-gtk2-unicode/bin/wx-config
-"""
-            elif not check_wxpython_broken_macosx104_version(wxconfig):
-                explanation = 'WXAgg\'s accelerator not building because a broken wxPython (installed by Apple\'s Mac OS X) was found.'
-            else:
-                gotit = True
-
-    if gotit:
-        module = Extension("test", [])
-        add_wx_flags(module, wxconfig)
-        if not find_include_file(
-            module.include_dirs,
-            os.path.join("wx", "wxPython", "wxPython.h")):
-            explanation = ("Could not find wxPython headers in any of %s" %
-                               ", ".join(["'%s'" % x for x in module.include_dirs]))
-
-    if gotit:
-        print_status("wxPython", wx.__version__)
-    else:
-        print_status("wxPython", "no")
-    if explanation is not None:
-        print_message(explanation)
-    return gotit
-
-def find_wx_config():
-    """If the WX_CONFIG environment variable has been set, returns it value.
-    Otherwise, search for `wx-config' in the PATH directories and return the
-    first match found.  Failing that, return None.
-    """
-
-    wxconfig = os.getenv('WX_CONFIG')
-    if wxconfig is not None:
-        return wxconfig
-
-    path = os.getenv('PATH') or ''
-    for dir in path.split(':'):
-        wxconfig = os.path.join(dir, 'wx-config')
-        if os.path.exists(wxconfig):
-            return wxconfig
-
-    return None
-
-def check_wxpython_broken_macosx104_version(wxconfig):
-    """Determines if we're using a broken wxPython installed by Mac OS X 10.4"""
-    if sys.platform == 'darwin':
-        if wxconfig == '/usr/bin/wx-config':
-            version_full = getoutput(wxconfig + ' --version-full')
-            if version_full == '2.5.3.1':
-                return False
-    return True
-
-def add_wx_flags(module, wxconfig):
-    """
-    Add the module flags to build extensions which use wxPython.
-    """
-
-    if sys.platform == 'win32': # just added manually
-        wxlibs = ['wxexpath', 'wxjpegh', 'wxmsw26uh',
-                  'wxmsw26uh_animate', 'wxmsw26uh_gizmos', 'wxmsw26uh_gizmos_xrc',
-                  'wxmsw26uh_gl', 'wxmsw26uh_stc', 'wxpngh', 'wxregexuh', 'wxtiffh', 'wxzlibh']
-        module.libraries.extend(wxlibs)
-        module.libraries.extend(wxlibs)
-        return
-
-    get_pkgconfig(module, '', flags='--cppflags --libs', pkg_config_exec='wx-config')
-
 # Make sure you use the Tk version given by Tkinter.TkVersion
 # or else you'll build for a wrong version of the Tcl
 # interpreter (leading to nasty segfaults).
-
 def check_for_tk():
     gotit = False
     explanation = None
@@ -814,9 +727,15 @@ def check_for_tk():
         module = Extension('test', [])
         try:
             explanation = add_tk_flags(module)
-        except RuntimeError, e:
-            explanation = str(e)
+        except RuntimeError:
+            # This deals with the change in exception handling syntax in
+            # python 3. If we only need to support >= 2.6, we can just use the
+            # commented out lines below.
+            exc_type,exc,tb = sys.exc_info()
+            explanation = str(exc)
             gotit = False
+#        except RuntimeError, e:
+#            explanation = str(e)
         else:
             if not find_include_file(module.include_dirs, "tk.h"):
                 message = 'Tkinter present, but header files are not found. ' + \
@@ -910,23 +829,21 @@ def parse_tcl_config(tcl_lib_dir, tk_lib_dir):
     # So, we push a "[default]" section to a copy of the
     # file in a StringIO object.
     try:
-        tcl_vars_str = cStringIO.StringIO(
-            "[default]\n" + open(tcl_config, "r").read())
-        tk_vars_str = cStringIO.StringIO(
-            "[default]\n" + open(tk_config, "r").read())
+        tcl_vars_str = StringIO("[default]\n" + open(tcl_config, "r").read())
+        tk_vars_str = StringIO("[default]\n" + open(tk_config, "r").read())
     except IOError:
         # if we can't read the file, that's ok, we'll try
         # to guess instead
         return None
 
     tcl_vars_str.seek(0)
-    tcl_vars = ConfigParser.RawConfigParser()
+    tcl_vars = configparser.RawConfigParser()
     tk_vars_str.seek(0)
-    tk_vars = ConfigParser.RawConfigParser()
+    tk_vars = configparser.RawConfigParser()
     try:
         tcl_vars.readfp(tcl_vars_str)
         tk_vars.readfp(tk_vars_str)
-    except ConfigParser.ParsingError:
+    except configparser.ParsingError:
         # if we can't read the file, that's ok, we'll try
         # to guess instead
         return None
@@ -942,7 +859,7 @@ def parse_tcl_config(tcl_lib_dir, tk_lib_dir):
         else:
             # On RHEL4
             tk_inc = tcl_inc
-    except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+    except (configparser.NoSectionError, configparser.NoOptionError):
         return None
 
     if not os.path.exists(os.path.join(tk_inc, 'tk.h')):
@@ -1043,8 +960,8 @@ def add_tk_flags(module):
             #
             tk_include_dirs = [
                 join(F, fw + '.framework', H)
-                for fw in 'Tcl', 'Tk'
-                for H in 'Headers', 'Versions/Current/PrivateHeaders'
+                for fw in ('Tcl', 'Tk')
+                for H in ('Headers', 'Versions/Current/PrivateHeaders')
             ]
 
             # For 8.4a2, the X11 headers are not included. Rather than include a
@@ -1187,25 +1104,6 @@ def build_tkagg(ext_modules, packages):
     BUILT_TKAGG = True
 
 
-def build_wxagg(ext_modules, packages):
-     global BUILT_WXAGG
-     if BUILT_WXAGG:
-         return
-
-     deps = ['src/_wxagg.cpp', 'src/mplutils.cpp']
-     deps.extend(glob.glob('CXX/*.cxx'))
-     deps.extend(glob.glob('CXX/*.c'))
-
-     module = Extension('matplotlib.backends._wxagg', deps)
-
-     add_agg_flags(module)
-     add_ft2font_flags(module)
-     wxconfig = find_wx_config()
-     add_wx_flags(module, wxconfig)
-
-     ext_modules.append(module)
-     BUILT_WXAGG = True
-
 def build_macosx(ext_modules, packages):
     global BUILT_MACOSX
     if BUILT_MACOSX: return # only build it if you you haven't already
diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp
index 36491eba92ab..39ce97f717cb 100644
--- a/src/_backend_agg.cpp
+++ b/src/_backend_agg.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /* A rewrite of _backend_agg using PyCXX to handle ref counting, etc..
  */
 
@@ -1914,13 +1916,15 @@ RendererAgg::draw_gouraud_triangles(const Py::Tuple& args)
     Py::Object        points_obj = args[1];
     Py::Object        colors_obj = args[2];
     agg::trans_affine trans      = py_to_agg_transformation_matrix(args[3].ptr());
+    double            c_points[6];
+    double            c_colors[12];
 
     theRasterizer.reset_clipping();
     rendererBase.reset_clipping(true);
     set_clipbox(gc.cliprect, theRasterizer);
     bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans);
 
-    PyArrayObject* points = (PyArrayObject*)PyArray_ContiguousFromAny
+    PyArrayObject* points = (PyArrayObject*)PyArray_FromObject
         (points_obj.ptr(), PyArray_DOUBLE, 3, 3);
     if (!points ||
         PyArray_DIM(points, 1) != 3 || PyArray_DIM(points, 2) != 2)
@@ -1930,7 +1934,7 @@ RendererAgg::draw_gouraud_triangles(const Py::Tuple& args)
     }
     points_obj = Py::Object((PyObject*)points, true);
 
-    PyArrayObject* colors = (PyArrayObject*)PyArray_ContiguousFromAny
+    PyArrayObject* colors = (PyArrayObject*)PyArray_FromObject
         (colors_obj.ptr(), PyArray_DOUBLE, 3, 3);
     if (!colors ||
         PyArray_DIM(colors, 1) != 3 || PyArray_DIM(colors, 2) != 4)
@@ -1947,9 +1951,20 @@ RendererAgg::draw_gouraud_triangles(const Py::Tuple& args)
 
     for (int i = 0; i < PyArray_DIM(points, 0); ++i)
     {
+        for (int j = 0; j < 3; ++j) {
+            for (int k = 0; k < 2; ++k) {
+                c_points[j*2+k] = *(double *)PyArray_GETPTR3(points, i, j, k);
+            }
+        }
+
+        for (int j = 0; j < 3; ++j) {
+            for (int k = 0; k < 4; ++k) {
+                c_colors[j*4+k] = *(double *)PyArray_GETPTR3(colors, i, j, k);
+            }
+        }
+
         _draw_gouraud_triangle(
-            (double*)PyArray_GETPTR1(points, i),
-            (double*)PyArray_GETPTR1(colors, i), trans, has_clippath);
+                c_points, c_colors, trans, has_clippath);
     }
 
     return Py::Object();
diff --git a/src/_backend_agg.h b/src/_backend_agg.h
index 538a1f54ce3b..633f3e7c8bc9 100644
--- a/src/_backend_agg.h
+++ b/src/_backend_agg.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /* _backend_agg.h - A rewrite of _backend_agg using PyCXX to handle
    ref counting, etc..
 */
diff --git a/src/_gtkagg.cpp b/src/_gtkagg.cpp
index 650c1354c896..5a0b4613fe10 100644
--- a/src/_gtkagg.cpp
+++ b/src/_gtkagg.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include 
 #include 
 
@@ -136,6 +138,7 @@ init_gtkagg(void)
 {
     init_pygobject();
     init_pygtk();
+
     import_array();
     //suppress unused warning by creating in two lines
     static _gtkagg_module* _gtkagg = NULL;
diff --git a/src/_image.cpp b/src/_image.cpp
index 435f13111fc4..66c19053cea6 100644
--- a/src/_image.cpp
+++ b/src/_image.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /* Python API mandates Python.h is included *first* */
 #include "Python.h"
 #include 
@@ -1083,7 +1085,7 @@ _image_module::frombyte(const Py::Tuple& args)
     Py::Object x = args[0];
     int isoutput = Py::Int(args[1]);
 
-    PyArrayObject *A = (PyArrayObject *) PyArray_ContiguousFromObject(x.ptr(), PyArray_UBYTE, 3, 3);
+    PyArrayObject *A = (PyArrayObject *) PyArray_FromObject(x.ptr(), PyArray_UBYTE, 3, 3);
     if (A == NULL)
     {
         throw Py::ValueError("Array must have 3 dimensions");
@@ -1102,35 +1104,86 @@ _image_module::frombyte(const Py::Tuple& args)
 
     agg::int8u *arrbuf;
     agg::int8u *buffer;
+    agg::int8u *dstbuf;
 
     arrbuf = reinterpret_cast(A->data);
 
     size_t NUMBYTES(imo->colsIn * imo->rowsIn * imo->BPP);
-    buffer = new agg::int8u[NUMBYTES];
+    buffer = dstbuf = new agg::int8u[NUMBYTES];
 
     if (buffer == NULL) //todo: also handle allocation throw
     {
         throw Py::MemoryError("_image_module::frombyte could not allocate memory");
     }
 
-    const size_t N = imo->rowsIn * imo->colsIn * imo->BPP;
-    size_t i = 0;
-    if (A->dimensions[2] == 4)
+    if PyArray_ISCONTIGUOUS(A)
+    {
+        if (A->dimensions[2] == 4)
+        {
+            memmove(dstbuf, arrbuf, imo->rowsIn * imo->colsIn * 4);
+        }
+        else
+        {
+            size_t i = imo->rowsIn * imo->colsIn;
+            while (i--)
+            {
+                *dstbuf++ = *arrbuf++;
+                *dstbuf++ = *arrbuf++;
+                *dstbuf++ = *arrbuf++;
+                *dstbuf++ = 255;
+            }
+        }
+    }
+    else if ((A->strides[1] == 4) && (A->strides[2] == 1))
     {
-        memmove(buffer, arrbuf, N);
+        const size_t N = imo->colsIn * 4;
+        const size_t stride = A->strides[0];
+        for (size_t rownum = 0; rownum < imo->rowsIn; rownum++)
+        {
+            memmove(dstbuf, arrbuf, N);
+            arrbuf += stride;
+            dstbuf += N;
+        }
+    }
+    else if ((A->strides[1] == 3) && (A->strides[2] == 1))
+    {
+        const size_t stride = A->strides[0] - imo->colsIn * 3;
+        for (size_t rownum = 0; rownum < imo->rowsIn; rownum++)
+        {
+            for (size_t colnum = 0; colnum < imo->colsIn; colnum++)
+            {
+                *dstbuf++ = *arrbuf++;
+                *dstbuf++ = *arrbuf++;
+                *dstbuf++ = *arrbuf++;
+                *dstbuf++ = 255;
+            }
+            arrbuf += stride;
+        }
     }
     else
     {
-        while (i < N)
+        PyArrayIterObject *iter;
+        iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)A);
+        if (A->dimensions[2] == 4)
+        {
+            while (iter->index < iter->size) {
+                *dstbuf++ = *((unsigned char *)iter->dataptr);
+                PyArray_ITER_NEXT(iter);
+            }
+        }
+        else
         {
-            memmove(buffer, arrbuf, 3);
-            buffer += 3;
-            arrbuf += 3;
-            *buffer++ = 255;
-            i += 4;
+            while (iter->index < iter->size) {
+                *dstbuf++ = *((unsigned char *)iter->dataptr);
+                PyArray_ITER_NEXT(iter);
+                *dstbuf++ = *((unsigned char *)iter->dataptr);
+                PyArray_ITER_NEXT(iter);
+                *dstbuf++ = *((unsigned char *)iter->dataptr);
+                PyArray_ITER_NEXT(iter);
+                *dstbuf++ = 255;
+            }
         }
-        buffer -= N;
-        arrbuf -= imo->rowsIn * imo->colsIn;
+        Py_DECREF(iter);
     }
 
     if (isoutput)
diff --git a/src/_image.h b/src/_image.h
index eb36fbf64109..8a3be548dcb2 100644
--- a/src/_image.h
+++ b/src/_image.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /* image.h
  *
  */
@@ -76,7 +78,7 @@ class Image : public Py::PythonExtension
          };
 
     //enum { BICUBIC=0, BILINEAR, BLACKMAN100, BLACKMAN256, BLACKMAN64,
-    //	 NEAREST, SINC144, SINC256, SINC64, SPLINE16, SPLINE36};
+    //   NEAREST, SINC144, SINC256, SINC64, SPLINE16, SPLINE36};
     enum { ASPECT_PRESERVE = 0, ASPECT_FREE};
 
     agg::int8u *bufferIn;
diff --git a/src/_macosx.m b/src/_macosx.m
index a9d05e920d8f..ad78787df340 100644
--- a/src/_macosx.m
+++ b/src/_macosx.m
@@ -5,6 +5,17 @@
 #include "numpy/arrayobject.h"
 #include "path_cleanup.h"
 
+/* Must define Py_TYPE for Python 2.5 or older */
+#ifndef Py_TYPE
+# define Py_TYPE(o) ((o)->ob_type)
+#endif
+
+/* Must define PyVarObject_HEAD_INIT for Python 2.5 or older */
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size)       \
+        PyObject_HEAD_INIT(type) size,
+#endif
+
 /* Proper way to check for the OS X version we are compiling for, from
    http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development */
 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
@@ -346,6 +357,7 @@ - (void)drawRect:(NSRect)rect;
 - (void)windowDidResize:(NSNotification*)notification;
 - (View*)initWithFrame:(NSRect)rect;
 - (void)setCanvas: (PyObject*)newCanvas;
+- (void)windowWillClose:(NSNotification*)notification;
 - (BOOL)windowShouldClose:(NSNotification*)notification;
 - (BOOL)isFlipped;
 - (void)mouseEntered:(NSEvent*)event;
@@ -487,14 +499,18 @@ static int _get_snap(GraphicsContext* self, enum e_snap_mode* mode)
     ngc--;
     if (ngc==0) _dealloc_atsui();
 
-    self->ob_type->tp_free((PyObject*)self);
+    Py_TYPE(self)->tp_free((PyObject*)self);
 }
 #endif
 
 static PyObject*
 GraphicsContext_repr(GraphicsContext* self)
 {
+#if PY_MAJOR_VERSION >= 3
+    return PyUnicode_FromFormat("GraphicsContext object %p wrapping the Quartz 2D graphics context %p", (void*)self, (void*)(self->cr));
+#else
     return PyString_FromFormat("GraphicsContext object %p wrapping the Quartz 2D graphics context %p", (void*)self, (void*)(self->cr));
+#endif
 }
 
 static PyObject*
@@ -1758,8 +1774,6 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
     /* Preset graphics context properties if possible */
     CGContextSetShouldAntialias(cr, antialiased);
 
-    CGContextSetLineWidth(cr, 0.0);
-
     if (Nfacecolors==1)
     {
         const double r = *(double*)PyArray_GETPTR2(facecolors, 0, 0);
@@ -1822,6 +1836,7 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
 
             CGContextMoveToPoint(cr, points[3].x, points[3].y);
             CGContextAddLines(cr, points, 4);
+            CGContextClosePath(cr);
 
             if (Nfacecolors > 1)
             {
@@ -1876,6 +1891,346 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
     return Py_None;
 }
 
+static int _find_minimum(CGFloat values[3])
+{
+    int i = 0;
+    CGFloat minimum = values[0];
+    if (values[1] < minimum)
+    {
+        minimum = values[1];
+        i = 1;
+    }
+    if (values[2] < minimum)
+        i = 2;
+    return i;
+}
+
+static int _find_maximum(CGFloat values[3])
+{
+    int i = 0;
+    CGFloat maximum = values[0];
+    if (values[1] > maximum)
+    {
+        maximum = values[1];
+        i = 1;
+    }
+    if (values[2] > maximum)
+        i = 2;
+    return i;
+}
+
+static void
+_rgba_color_evaluator(void* info, const CGFloat input[], CGFloat outputs[])
+{
+    const CGFloat c1 = input[0];
+    const CGFloat c0 = 1.0 - c1;
+    CGFloat(* color)[4] = info;
+    outputs[0] = c0 * color[0][0] + c1 * color[1][0];
+    outputs[1] = c0 * color[0][1] + c1 * color[1][1];
+    outputs[2] = c0 * color[0][2] + c1 * color[1][2];
+    outputs[3] = c0 * color[0][3] + c1 * color[1][3];
+}
+
+static void
+_gray_color_evaluator(void* info, const CGFloat input[], CGFloat outputs[])
+{
+    const CGFloat c1 = input[0];
+    const CGFloat c0 = 1.0 - c1;
+    CGFloat(* color)[2] = info;
+    outputs[0] = c0 * color[0][0] + c1 * color[1][0];
+    outputs[1] = c0 * color[0][1] + c1 * color[1][1];
+}
+
+static int
+_shade_one_color(CGContextRef cr, CGFloat colors[3], CGPoint points[3], int icolor)
+{
+    const int imin = _find_minimum(colors);
+    const int imax = _find_maximum(colors);
+
+    float numerator;
+    float denominator;
+    float ac;
+    float as;
+    float phi;
+    float distance;
+    CGPoint start;
+    CGPoint end;
+    static CGFunctionCallbacks callbacks = {0, &_rgba_color_evaluator, free};
+    CGFloat domain[2] = {0.0, 1.0};
+    CGFloat range[8] = {0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0};
+    CGFunctionRef function;
+
+    CGFloat(* rgba)[4] = malloc(2*sizeof(CGFloat[4]));
+    if (!rgba) return -1;
+    else {
+        rgba[0][0] = 0.0;
+        rgba[0][1] = 0.0;
+        rgba[0][2] = 0.0;
+        rgba[0][3] = 1.0;
+        rgba[1][0] = 0.0;
+        rgba[1][1] = 0.0;
+        rgba[1][2] = 0.0;
+        rgba[1][3] = 1.0;
+    }
+
+    denominator = (points[1].x-points[0].x)*(points[2].y-points[0].y)
+                - (points[2].x-points[0].x)*(points[1].y-points[0].y);
+    numerator = (colors[1]-colors[0])*(points[2].y-points[0].y)
+              - (colors[2]-colors[0])*(points[1].y-points[0].y);
+    ac = numerator / denominator;
+    numerator = (colors[2]-colors[0])*(points[1].x-points[0].x)
+              - (colors[1]-colors[0])*(points[2].x-points[0].x);
+    as = numerator / denominator;
+    phi = atan2(as, ac);
+
+    start.x = points[imin].x;
+    start.y = points[imin].y;
+
+    rgba[0][icolor] = colors[imin];
+    rgba[1][icolor] = colors[imax];
+
+    distance = (points[imax].x-points[imin].x) * cos(phi) + (points[imax].y-points[imin].y) * sin(phi);
+
+    end.x = start.x + distance * cos(phi);
+    end.y = start.y + distance * sin(phi);
+
+    function = CGFunctionCreate(rgba,
+                                1, /* one input (position) */
+                                domain,
+                                4, /* rgba output */
+                                range,
+                                &callbacks);
+    if (function)
+    {
+        CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+        CGShadingRef shading = CGShadingCreateAxial(colorspace,
+                                                    start,
+                                                    end,
+                                                    function,
+                                                    true,
+                                                    true);
+        CGFunctionRelease(function);
+        if (shading)
+        {
+            CGContextDrawShading(cr, shading);
+            CGShadingRelease(shading);
+            return 1;
+        }
+    }
+    free(rgba);
+    return -1;
+}
+
+static CGRect _find_enclosing_rect(CGPoint points[3])
+{
+    CGFloat left = points[0].x;
+    CGFloat right = points[0].x;
+    CGFloat bottom = points[0].y;
+    CGFloat top = points[0].y;
+    if (points[1].x < left) left = points[1].x;
+    if (points[1].x > right) right = points[1].x;
+    if (points[2].x < left) left = points[2].x;
+    if (points[2].x > right) right = points[2].x;
+    if (points[1].y < bottom) bottom = points[1].y;
+    if (points[1].y > top) top = points[1].y;
+    if (points[2].y < bottom) bottom = points[2].y;
+    if (points[2].y > top) top = points[2].y;
+    return CGRectMake(left,bottom,right-left,top-bottom);
+}
+
+static int
+_shade_alpha(CGContextRef cr, CGFloat alphas[3], CGPoint points[3])
+{
+    const int imin = _find_minimum(alphas);
+    const int imax = _find_maximum(alphas);
+
+    if (alphas[imin]==1.0) return 0;
+
+    CGRect rect = _find_enclosing_rect(points);
+    const size_t width = (size_t)rect.size.width;
+    const size_t height = (size_t)rect.size.height;
+    if (width==0 || height==0) return 0;
+
+    void* data = malloc(width*height);
+
+    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
+    CGContextRef bitmap = CGBitmapContextCreate(data,
+                                                width,
+                                                height,
+                                                8,
+                                                width,
+                                                colorspace,
+                                                0);
+    CGColorSpaceRelease(colorspace);
+
+    if (imin==imax)
+    {
+        CGRect bitmap_rect = rect;
+        bitmap_rect.origin = CGPointZero;
+        CGContextSetGrayFillColor(bitmap, alphas[0], 1.0);
+        CGContextFillRect(bitmap, bitmap_rect);
+    }
+    else
+    {
+        float numerator;
+        float denominator;
+        float ac;
+        float as;
+        float phi;
+        float distance;
+        CGPoint start;
+        CGPoint end;
+        CGFloat(*gray)[2] = malloc(2*sizeof(CGFloat[2]));
+
+        static CGFunctionCallbacks callbacks = {0, &_gray_color_evaluator, free};
+        CGFloat domain[2] = {0.0, 1.0};
+        CGFloat range[2] = {0.0, 1.0};
+        CGShadingRef shading = NULL;
+        CGFunctionRef function;
+
+        gray[0][1] = 1.0;
+        gray[1][1] = 1.0;
+
+        denominator = (points[1].x-points[0].x)*(points[2].y-points[0].y)
+                    - (points[2].x-points[0].x)*(points[1].y-points[0].y);
+        numerator = (alphas[1]-alphas[0])*(points[2].y-points[0].y)
+                  - (alphas[2]-alphas[0])*(points[1].y-points[0].y);
+        ac = numerator / denominator;
+        numerator = (alphas[2]-alphas[0])*(points[1].x-points[0].x)
+                  - (alphas[1]-alphas[0])*(points[2].x-points[0].x);
+        as = numerator / denominator;
+        phi = atan2(as, ac);
+
+        start.x = points[imin].x - rect.origin.x;
+        start.y = points[imin].y - rect.origin.y;
+
+        gray[0][0] = alphas[imin];
+        gray[1][0] = alphas[imax];
+
+        distance = (points[imax].x-points[imin].x) * cos(phi) + (points[imax].y-points[imin].y) * sin(phi);
+
+        end.x = start.x + distance * cos(phi);
+        end.y = start.y + distance * sin(phi);
+
+        function = CGFunctionCreate(gray,
+                                    1, /* one input (position) */
+                                    domain,
+                                    1, /* one output (gray level) */
+                                    range,
+                                    &callbacks);
+        if (function)
+        {
+            shading = CGShadingCreateAxial(colorspace,
+                                           start,
+                                           end,
+                                           function,
+                                           true,
+                                           true);
+            CGFunctionRelease(function);
+        }
+        if (shading)
+        {
+            CGContextDrawShading(bitmap, shading);
+            CGShadingRelease(shading);
+        }
+        else
+        {
+            free(gray);
+        }
+    }
+
+    CGImageRef mask = CGBitmapContextCreateImage(bitmap);
+    CGContextClipToMask(cr, rect, mask);
+    CGImageRelease(mask);
+    free(data);
+    return 0;
+}
+
+static PyObject*
+GraphicsContext_draw_gouraud_triangle (GraphicsContext* self, PyObject* args)
+
+{
+    PyObject* coordinates;
+    PyObject* colors;
+
+    CGPoint points[3];
+    CGFloat intensity[3];
+
+    int i = 0;
+
+    CGContextRef cr = self->cr;
+    if (!cr)
+    {
+        PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
+        return NULL;
+    }
+
+    if(!PyArg_ParseTuple(args, "OO", &coordinates, &colors)) return NULL;
+
+    /* ------------------- Check coordinates array ------------------------ */
+
+    coordinates = PyArray_FromObject(coordinates, NPY_DOUBLE, 2, 2);
+    if (!coordinates ||
+        PyArray_DIM(coordinates, 0) != 3 || PyArray_DIM(coordinates, 1) != 2)
+    {
+        PyErr_SetString(PyExc_ValueError, "Invalid coordinates array");
+        Py_XDECREF(coordinates);
+        return NULL;
+    }
+    points[0].x = *((double*)(PyArray_GETPTR2(coordinates, 0, 0)));
+    points[0].y = *((double*)(PyArray_GETPTR2(coordinates, 0, 1)));
+    points[1].x = *((double*)(PyArray_GETPTR2(coordinates, 1, 0)));
+    points[1].y = *((double*)(PyArray_GETPTR2(coordinates, 1, 1)));
+    points[2].x = *((double*)(PyArray_GETPTR2(coordinates, 2, 0)));
+    points[2].y = *((double*)(PyArray_GETPTR2(coordinates, 2, 1)));
+
+    /* ------------------- Check colors array ----------------------------- */
+
+    colors = PyArray_FromObject(colors, NPY_DOUBLE, 2, 2);
+    if (!colors ||
+        PyArray_DIM(colors, 0) != 3 || PyArray_DIM(colors, 1) != 4)
+    {
+        PyErr_SetString(PyExc_ValueError, "colors must by a 3x4 array");
+        Py_DECREF(coordinates);
+        Py_XDECREF(colors);
+        return NULL;
+    }
+
+    /* ----- Draw the gradients separately for each color component ------- */
+    CGContextSaveGState(cr);
+    CGContextMoveToPoint(cr, points[0].x, points[0].y);
+    CGContextAddLineToPoint(cr, points[1].x, points[1].y);
+    CGContextAddLineToPoint(cr, points[2].x, points[2].y);
+    CGContextClip(cr);
+    intensity[0] = *((double*)(PyArray_GETPTR2(colors, 0, 3)));
+    intensity[1] = *((double*)(PyArray_GETPTR2(colors, 1, 3)));
+    intensity[2] = *((double*)(PyArray_GETPTR2(colors, 2, 3)));
+    if (_shade_alpha(cr, intensity, points)!=-1) {
+        CGContextBeginTransparencyLayer(cr, NULL);
+        CGContextSetBlendMode(cr, kCGBlendModeScreen);
+        for (i = 0; i < 3; i++)
+        {
+            intensity[0] = *((double*)(PyArray_GETPTR2(colors, 0, i)));
+            intensity[1] = *((double*)(PyArray_GETPTR2(colors, 1, i)));
+            intensity[2] = *((double*)(PyArray_GETPTR2(colors, 2, i)));
+            if (!_shade_one_color(cr, intensity, points, i)) break;
+        }
+        CGContextEndTransparencyLayer(cr);
+    }
+    CGContextRestoreGState(cr);
+
+    Py_DECREF(coordinates);
+    Py_DECREF(colors);
+
+    if (i < 3) /* break encountered */
+    {
+        PyErr_SetString(PyExc_MemoryError, "insufficient memory in draw_gouraud_triangle");
+        return NULL;
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
 
 #ifdef COMPILING_FOR_10_5
 static CTFontRef
@@ -1896,6 +2251,9 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
 #else
     ATSFontRef font = 0;
 #endif
+#if PY_MAJOR_VERSION >= 3
+    PyObject* ascii = NULL;
+#endif
 
     const int k = (strcmp(italic, "italic") ? 0 : 2)
                 + (strcmp(weight, "bold") ? 0 : 1);
@@ -2076,8 +2434,14 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
     for (i = 0; i < n; i++)
     {
         PyObject* item = PyList_GET_ITEM(family, i);
+#if PY_MAJOR_VERSION >= 3
+        ascii = PyUnicode_AsASCIIString(item);
+        if(!ascii) return 0;
+        temp = PyBytes_AS_STRING(ascii);
+#else
         if(!PyString_Check(item)) return 0;
         temp = PyString_AS_STRING(item);
+#endif
         for (j = 0; j < NMAP; j++)
         {    if (!strcmp(map[j].name, temp))
              {    temp = psnames[map[j].index][k];
@@ -2104,6 +2468,10 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
             name = temp;
             break;
         }
+#if PY_MAJOR_VERSION >= 3
+        Py_DECREF(ascii);
+        ascii = NULL;
+#endif
     }
     if(!font)
     {   string = CFStringCreateWithCString(kCFAllocatorDefault,
@@ -2118,6 +2486,9 @@ static BOOL _clip(CGContextRef cr, PyObject* object)
     }
 #ifndef COMPILING_FOR_10_5
     CGContextSelectFont(cr, name, size, kCGEncodingMacRoman);
+#endif
+#if PY_MAJOR_VERSION >= 3
+    Py_XDECREF(ascii);
 #endif
     return font;
 }
@@ -2618,11 +2989,19 @@ static void _data_provider_release(void* info, const void* data, size_t size)
     CGDataProviderRef provider;
     double rect[4] = {0.0, 0.0, self->size.width, self->size.height};
 
+#if PY_MAJOR_VERSION >= 3
+    if (!PyBytes_Check(image))
+    {
+        PyErr_SetString(PyExc_RuntimeError, "image is not a byte array");
+        return NULL;
+    }
+#else
     if (!PyString_Check(image))
     {
         PyErr_SetString(PyExc_RuntimeError, "image is not a string");
         return NULL;
     }
+#endif
 
     const size_t bytesPerComponent = 1;
     const size_t bitsPerComponent = 8 * bytesPerComponent;
@@ -2638,8 +3017,13 @@ static void _data_provider_release(void* info, const void* data, size_t size)
     }
 
     Py_INCREF(image);
+#if PY_MAJOR_VERSION >= 3
+    n = PyByteArray_GET_SIZE(image);
+    data = PyByteArray_AS_STRING(image);
+#else
     n = PyString_GET_SIZE(image);
     data = PyString_AsString(image);
+#endif
 
     provider = CGDataProviderCreateWithData(image,
                                             data,
@@ -2791,6 +3175,11 @@ static void _data_provider_release(void* info, const void* data, size_t size)
      METH_VARARGS,
      "Draws a mesh in the graphics context."
     },
+    {"draw_gouraud_triangle",
+     (PyCFunction)GraphicsContext_draw_gouraud_triangle,
+     METH_VARARGS,
+     "Draws a Gouraud-shaded triangle in the graphics context."
+    },
     {"draw_text",
      (PyCFunction)GraphicsContext_draw_text,
      METH_VARARGS,
@@ -2816,8 +3205,7 @@ static void _data_provider_release(void* info, const void* data, size_t size)
 "set_joinstyle, etc.).\n";
 
 static PyTypeObject GraphicsContextType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /*ob_size*/
+    PyVarObject_HEAD_INIT(NULL, 0)
     "_macosx.GraphicsContext", /*tp_name*/
     sizeof(GraphicsContext),   /*tp_basicsize*/
     0,                         /*tp_itemsize*/
@@ -2902,14 +3290,19 @@ static void _data_provider_release(void* info, const void* data, size_t size)
         [self->view setCanvas: NULL];
         [self->view release];
     }
-    self->ob_type->tp_free((PyObject*)self);
+    Py_TYPE(self)->tp_free((PyObject*)self);
 }
 
 static PyObject*
 FigureCanvas_repr(FigureCanvas* self)
 {
+#if PY_MAJOR_VERSION >= 3
+    return PyUnicode_FromFormat("FigureCanvas object %p wrapping NSView %p",
+                               (void*)self, (void*)(self->view));
+#else
     return PyString_FromFormat("FigureCanvas object %p wrapping NSView %p",
                                (void*)self, (void*)(self->view));
+#endif
 }
 
 static PyObject*
@@ -3243,8 +3636,7 @@ static void _data_provider_release(void* info, const void* data, size_t size)
 "A FigureCanvas object wraps a Cocoa NSView object.\n";
 
 static PyTypeObject FigureCanvasType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /*ob_size*/
+    PyVarObject_HEAD_INIT(NULL, 0)
     "_macosx.FigureCanvas",    /*tp_name*/
     sizeof(FigureCanvas),      /*tp_basicsize*/
     0,                         /*tp_itemsize*/
@@ -3363,7 +3755,6 @@ static void _data_provider_release(void* info, const void* data, size_t size)
     [window setDelegate: view];
     [window makeFirstResponder: view];
     [[window contentView] addSubview: view];
-    [view release];
     [window makeKeyAndOrderFront: nil];
 
     nwin++;
@@ -3375,8 +3766,13 @@ static void _data_provider_release(void* info, const void* data, size_t size)
 static PyObject*
 FigureManager_repr(FigureManager* self)
 {
+#if PY_MAJOR_VERSION >= 3
+    return PyUnicode_FromFormat("FigureManager object %p wrapping NSWindow %p",
+                               (void*) self, (void*)(self->window));
+#else
     return PyString_FromFormat("FigureManager object %p wrapping NSWindow %p",
                                (void*) self, (void*)(self->window));
+#endif
 }
 
 static void
@@ -3389,7 +3785,7 @@ static void _data_provider_release(void* info, const void* data, size_t size)
         [window close];
         [pool release];
     }
-    self->ob_type->tp_free((PyObject*)self);
+    Py_TYPE(self)->tp_free((PyObject*)self);
 }
 
 static PyObject*
@@ -3420,8 +3816,7 @@ static void _data_provider_release(void* info, const void* data, size_t size)
 "A FigureManager object wraps a Cocoa NSWindow object.\n";
 
 static PyTypeObject FigureManagerType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /*ob_size*/
+    PyVarObject_HEAD_INIT(NULL, 0)
     "_macosx.FigureManager",   /*tp_name*/
     sizeof(FigureManager),     /*tp_basicsize*/
     0,                         /*tp_itemsize*/
@@ -3756,13 +4151,17 @@ -(void)save_figure:(id)sender
 NavigationToolbar_dealloc(NavigationToolbar *self)
 {
     [self->handler release];
-    self->ob_type->tp_free((PyObject*)self);
+    Py_TYPE(self)->tp_free((PyObject*)self);
 }
 
 static PyObject*
 NavigationToolbar_repr(NavigationToolbar* self)
 {
+#if PY_MAJOR_VERSION >= 3
+    return PyUnicode_FromFormat("NavigationToolbar object %p", (void*)self);
+#else
     return PyString_FromFormat("NavigationToolbar object %p", (void*)self);
+#endif
 }
 
 static char NavigationToolbar_doc[] =
@@ -3869,7 +4268,11 @@ -(void)save_figure:(id)sender
     {
         if(states[i]==1)
         {
+#if PY_MAJOR_VERSION >= 3
+            PyList_SET_ITEM(list, j, PyLong_FromLong(i));
+#else
             PyList_SET_ITEM(list, j, PyInt_FromLong(i));
+#endif
             j++;
         }
     }
@@ -3892,8 +4295,7 @@ -(void)save_figure:(id)sender
 };
 
 static PyTypeObject NavigationToolbarType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /*ob_size*/
+    PyVarObject_HEAD_INIT(NULL, 0)
     "_macosx.NavigationToolbar", /*tp_name*/
     sizeof(NavigationToolbar), /*tp_basicsize*/
     0,                         /*tp_itemsize*/
@@ -4278,13 +4680,17 @@ -(void)save_figure:(id)sender
 NavigationToolbar2_dealloc(NavigationToolbar2 *self)
 {
     [self->handler release];
-    self->ob_type->tp_free((PyObject*)self);
+    Py_TYPE(self)->tp_free((PyObject*)self);
 }
 
 static PyObject*
 NavigationToolbar2_repr(NavigationToolbar2* self)
 {
+#if PY_MAJOR_VERSION >= 3
+    return PyUnicode_FromFormat("NavigationToolbar2 object %p", (void*)self);
+#else
     return PyString_FromFormat("NavigationToolbar2 object %p", (void*)self);
+#endif
 }
 
 static char NavigationToolbar2_doc[] =
@@ -4299,8 +4705,10 @@ -(void)save_figure:(id)sender
     NSText* messagebox = self->messagebox;
 
     if (messagebox)
-    {   NSString* text = [NSString stringWithUTF8String: message];
+    {   NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+        NSString* text = [NSString stringWithUTF8String: message];
         [messagebox setString: text];
+        [pool release];
     }
 
     Py_INCREF(Py_None);
@@ -4317,8 +4725,7 @@ -(void)save_figure:(id)sender
 };
 
 static PyTypeObject NavigationToolbar2Type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /*ob_size*/
+    PyVarObject_HEAD_INIT(NULL, 0)
     "_macosx.NavigationToolbar2", /*tp_name*/
     sizeof(NavigationToolbar2), /*tp_basicsize*/
     0,                         /*tp_itemsize*/
@@ -4399,16 +4806,6 @@ -(void)save_figure:(id)sender
     return Py_None;
 }
 
-static char show__doc__[] = "Show all the figures and enter the main loop.\nThis function does not return until all Matplotlib windows are closed,\nand is normally not needed in interactive sessions.";
-
-static PyObject*
-show(PyObject* self)
-{
-    if(nwin > 0) [NSApp run];
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
 @implementation Window
 - (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager
 {
@@ -4458,6 +4855,10 @@ - (void)dealloc
     gstate = PyGILState_Ensure();
     Py_DECREF(manager);
     PyGILState_Release(gstate);
+    /* The reference count of the view that was added as a subview to the
+     * content view of this window was increased during the call to addSubview,
+     * and is decreased during the call to [super dealloc].
+     */
     [super dealloc];
 }
 @end
@@ -4601,6 +5002,20 @@ - (void)windowDidResize: (NSNotification*)notification
     [self setNeedsDisplay: YES];
 }
 
+- (void)windowWillClose:(NSNotification*)notification
+{
+    PyGILState_STATE gstate;
+    PyObject* result;
+
+    gstate = PyGILState_Ensure();
+    result = PyObject_CallMethod(canvas, "close_event", "");
+    if(result)
+        Py_DECREF(result);
+    else
+        PyErr_Print();
+    PyGILState_Release(gstate);
+}
+
 - (BOOL)windowShouldClose:(NSNotification*)notification
 {
     NSWindow* window = [self window];
@@ -5139,11 +5554,225 @@ - (int)index
 }
 @end
 
+
+static PyObject*
+show(PyObject* self)
+{
+    if(nwin > 0) [NSApp run];
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject*
+verify_main_display(PyObject* self)
+{
+    CGDirectDisplayID display = CGMainDisplayID();
+    if (display == 0) {
+        PyErr_SetString(PyExc_RuntimeError, "Failed to obtain the display ID of the main display");
+        return NULL;
+    }
+    Py_INCREF(Py_True);
+    return Py_True;
+}
+
+typedef struct {
+    PyObject_HEAD
+    CFRunLoopTimerRef timer;
+} Timer;
+
+static PyObject*
+Timer_new(PyTypeObject* type, PyObject *args, PyObject *kwds)
+{
+    Timer* self = (Timer*)type->tp_alloc(type, 0);
+    if (!self) return NULL;
+    self->timer = NULL;
+    return (PyObject*) self;
+}
+
+static void
+Timer_dealloc(Timer* self)
+{
+    if (self->timer) {
+        PyObject* attribute;
+        CFRunLoopTimerContext context;
+        CFRunLoopTimerGetContext(self->timer, &context);
+        attribute = context.info;
+        Py_DECREF(attribute);
+        CFRunLoopRef runloop = CFRunLoopGetCurrent();
+        if (runloop) {
+            CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
+        }
+        CFRelease(self->timer);
+        self->timer = NULL;
+    }
+    Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject*
+Timer_repr(Timer* self)
+{
+#if PY_MAJOR_VERSION >= 3
+    return PyUnicode_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p",
+                               (void*) self, (void*)(self->timer));
+#else
+    return PyString_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p",
+                               (void*) self, (void*)(self->timer));
+#endif
+}
+
+static char Timer_doc[] =
+"A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop.\n";
+
+static void timer_callback(CFRunLoopTimerRef timer, void* info)
+{
+    PyObject* method = info;
+    PyGILState_STATE gstate = PyGILState_Ensure();
+    PyObject* result = PyObject_CallFunction(method, NULL);
+    if (result==NULL) PyErr_Print();
+    PyGILState_Release(gstate);
+}
+
+static PyObject*
+Timer__timer_start(Timer* self, PyObject* args)
+{
+    CFRunLoopRef runloop;
+    CFRunLoopTimerRef timer;
+    CFRunLoopTimerContext context;
+    double milliseconds;
+    CFTimeInterval interval;
+    PyObject* attribute;
+    PyObject* failure;
+    runloop = CFRunLoopGetCurrent();
+    if (!runloop) {
+        PyErr_SetString(PyExc_RuntimeError, "Failed to obtain run loop");
+        return NULL;
+    }
+    context.version = 0;
+    context.retain = 0;
+    context.release = 0;
+    context.copyDescription = 0;
+    attribute = PyObject_GetAttrString((PyObject*)self, "_interval");
+    if (attribute==NULL)
+    {
+        PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_interval'");
+        return NULL;
+    }
+    milliseconds = PyFloat_AsDouble(attribute);
+    failure = PyErr_Occurred();
+    Py_DECREF(attribute);
+    if (failure) return NULL;
+    attribute = PyObject_GetAttrString((PyObject*)self, "_single");
+    if (attribute==NULL)
+    {
+        PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_single'");
+        return NULL;
+    }
+    switch (PyObject_IsTrue(attribute)) {
+        case 1:
+            interval = 0;
+            break;
+        case 0:
+            interval = milliseconds / 1000.0;
+            break;
+        case -1:
+        default:
+            PyErr_SetString(PyExc_ValueError, "Cannot interpret _single attribute as True of False");
+            return NULL;
+    }
+    attribute = PyObject_GetAttrString((PyObject*)self, "_on_timer");
+    if (attribute==NULL)
+    {
+        PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_on_timer'");
+        return NULL;
+    }
+    if (!PyMethod_Check(attribute)) {
+        PyErr_SetString(PyExc_RuntimeError, "_on_timer should be a Python method");
+        return NULL;
+    }
+    context.info = attribute;
+    timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
+                                 0,
+                                 interval,
+                                 0,
+                                 0,
+                                 timer_callback,
+                                 &context);
+    if (!timer) {
+        PyErr_SetString(PyExc_RuntimeError, "Failed to create timer");
+        return NULL;
+    }
+    Py_INCREF(attribute);
+    if (self->timer) {
+        CFRunLoopTimerGetContext(self->timer, &context);
+        attribute = context.info;
+        Py_DECREF(attribute);
+        CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
+        CFRelease(self->timer);
+    }
+    CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes);
+    /* Don't release the timer here, since the run loop may be destroyed and
+     * the timer lost before we have a chance to decrease the reference count
+     * of the attribute */
+    self->timer = timer;
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyMethodDef Timer_methods[] = {
+    {"_timer_start",
+     (PyCFunction)Timer__timer_start,
+     METH_VARARGS,
+     "Initialize and start the timer."
+    },
+    {NULL}  /* Sentinel */
+};
+
+static PyTypeObject TimerType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_macosx.Timer",           /*tp_name*/
+    sizeof(Timer),             /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)Timer_dealloc,     /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    (reprfunc)Timer_repr,      /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,        /*tp_flags*/
+    Timer_doc,                 /* tp_doc */
+    0,                         /* tp_traverse */
+    0,                         /* tp_clear */
+    0,                         /* tp_richcompare */
+    0,                         /* tp_weaklistoffset */
+    0,                         /* tp_iter */
+    0,                         /* tp_iternext */
+    Timer_methods,             /* tp_methods */
+    0,                         /* tp_members */
+    0,                         /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,                         /* tp_init */
+    0,                         /* tp_alloc */
+    Timer_new,                 /* tp_new */
+};
+
 static struct PyMethodDef methods[] = {
    {"show",
     (PyCFunction)show,
     METH_NOARGS,
-    show__doc__
+    "Show all the figures and enter the main loop.\nThis function does not return until all Matplotlib windows are closed,\nand is normally not needed in interactive sessions."
    },
    {"choose_save_file",
     (PyCFunction)choose_save_file,
@@ -5155,35 +5784,73 @@ - (int)index
     METH_VARARGS,
     "Sets the active cursor."
    },
+   {"verify_main_display",
+    (PyCFunction)verify_main_display,
+    METH_NOARGS,
+    "Verifies if the main display can be found. This function fails if Python is not built as a framework."
+   },
    {NULL,          NULL, 0, NULL}/* sentinel */
 };
 
+#if PY_MAJOR_VERSION >= 3
+
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    "_macosx",
+    "Mac OS X native backend",
+    -1,
+    methods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+PyObject* PyInit__macosx(void)
+
+#else
+
 void init_macosx(void)
-{   PyObject *m;
+#endif
+{   PyObject *module;
+
     import_array();
 
-    if (PyType_Ready(&GraphicsContextType) < 0) return;
-    if (PyType_Ready(&FigureCanvasType) < 0) return;
-    if (PyType_Ready(&FigureManagerType) < 0) return;
-    if (PyType_Ready(&NavigationToolbarType) < 0) return;
-    if (PyType_Ready(&NavigationToolbar2Type) < 0) return;
+    if (PyType_Ready(&GraphicsContextType) < 0
+     || PyType_Ready(&FigureCanvasType) < 0
+     || PyType_Ready(&FigureManagerType) < 0
+     || PyType_Ready(&NavigationToolbarType) < 0
+     || PyType_Ready(&NavigationToolbar2Type) < 0
+     || PyType_Ready(&TimerType) < 0)
+#if PY_MAJOR_VERSION >= 3
+        return NULL;
+#else
+        return;
+#endif
 
-    m = Py_InitModule4("_macosx",
-                       methods,
-                       "Mac OS X native backend",
-                       NULL,
-                       PYTHON_API_VERSION);
+#if PY_MAJOR_VERSION >= 3
+    module = PyModule_Create(&moduledef);
+    if (module==NULL) return NULL;
+#else
+    module = Py_InitModule4("_macosx",
+                            methods,
+                            "Mac OS X native backend",
+                            NULL,
+                            PYTHON_API_VERSION);
+#endif
 
     Py_INCREF(&GraphicsContextType);
     Py_INCREF(&FigureCanvasType);
     Py_INCREF(&FigureManagerType);
     Py_INCREF(&NavigationToolbarType);
     Py_INCREF(&NavigationToolbar2Type);
-    PyModule_AddObject(m, "GraphicsContext", (PyObject*) &GraphicsContextType);
-    PyModule_AddObject(m, "FigureCanvas", (PyObject*) &FigureCanvasType);
-    PyModule_AddObject(m, "FigureManager", (PyObject*) &FigureManagerType);
-    PyModule_AddObject(m, "NavigationToolbar", (PyObject*) &NavigationToolbarType);
-    PyModule_AddObject(m, "NavigationToolbar2", (PyObject*) &NavigationToolbar2Type);
+    Py_INCREF(&TimerType);
+    PyModule_AddObject(module, "GraphicsContext", (PyObject*) &GraphicsContextType);
+    PyModule_AddObject(module, "FigureCanvas", (PyObject*) &FigureCanvasType);
+    PyModule_AddObject(module, "FigureManager", (PyObject*) &FigureManagerType);
+    PyModule_AddObject(module, "NavigationToolbar", (PyObject*) &NavigationToolbarType);
+    PyModule_AddObject(module, "NavigationToolbar2", (PyObject*) &NavigationToolbar2Type);
+    PyModule_AddObject(module, "Timer", (PyObject*) &TimerType);
 
     PyOS_InputHook = wait_for_stdin;
 }
diff --git a/src/_path.cpp b/src/_path.cpp
index e53611c5aff4..54c4492a7d6e 100644
--- a/src/_path.cpp
+++ b/src/_path.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include "agg_py_path_iterator.h"
 #include "agg_py_transforms.h"
 #include "path_converters.h"
diff --git a/src/_png.cpp b/src/_png.cpp
index 9f12389166a4..ccecd39b9a84 100644
--- a/src/_png.cpp
+++ b/src/_png.cpp
@@ -1,3 +1,4 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
 
 /* For linux, png.h must be imported before Python.h because
    png.h needs to be the one to define setjmp.
diff --git a/src/_subprocess.c b/src/_subprocess.c
index c93f84bd1fe7..78dfc9433a2a 100644
--- a/src/_subprocess.c
+++ b/src/_subprocess.c
@@ -1,3 +1,5 @@
+/* -*- mode: c; c-basic-offset: 4 -*- */
+
 /*
  * support routines for subprocess module
  *
@@ -49,8 +51,8 @@
    the wrapper is used to provide Detach and Close methods */
 
 typedef struct {
-	PyObject_HEAD
-	HANDLE handle;
+        PyObject_HEAD
+        HANDLE handle;
 } sp_handle_object;
 
 staticforward PyTypeObject sp_handle_type;
@@ -58,89 +60,89 @@ staticforward PyTypeObject sp_handle_type;
 static PyObject*
 sp_handle_new(HANDLE handle)
 {
-	sp_handle_object* self;
+        sp_handle_object* self;
 
-	self = PyObject_NEW(sp_handle_object, &sp_handle_type);
-	if (self == NULL)
-		return NULL;
+        self = PyObject_NEW(sp_handle_object, &sp_handle_type);
+        if (self == NULL)
+                return NULL;
 
-	self->handle = handle;
+        self->handle = handle;
 
-	return (PyObject*) self;
+        return (PyObject*) self;
 }
 
 static PyObject*
 sp_handle_detach(sp_handle_object* self, PyObject* args)
 {
-	HANDLE handle;
+        HANDLE handle;
 
-	if (! PyArg_ParseTuple(args, ":Detach"))
-		return NULL;
+        if (! PyArg_ParseTuple(args, ":Detach"))
+                return NULL;
 
-	handle = self->handle;
+        handle = self->handle;
 
-	self->handle = NULL;
+        self->handle = NULL;
 
-	/* note: return the current handle, as an integer */
-	return PyInt_FromLong((long) handle);
+        /* note: return the current handle, as an integer */
+        return PyInt_FromLong((long) handle);
 }
 
 static PyObject*
 sp_handle_close(sp_handle_object* self, PyObject* args)
 {
-	if (! PyArg_ParseTuple(args, ":Close"))
-		return NULL;
-
-	if (self->handle != INVALID_HANDLE_VALUE) {
-		CloseHandle(self->handle);
-		self->handle = INVALID_HANDLE_VALUE;
-	}
-	Py_INCREF(Py_None);
-	return Py_None;
+        if (! PyArg_ParseTuple(args, ":Close"))
+                return NULL;
+
+        if (self->handle != INVALID_HANDLE_VALUE) {
+                CloseHandle(self->handle);
+                self->handle = INVALID_HANDLE_VALUE;
+        }
+        Py_INCREF(Py_None);
+        return Py_None;
 }
 
 static void
 sp_handle_dealloc(sp_handle_object* self)
 {
-	if (self->handle != INVALID_HANDLE_VALUE)
-		CloseHandle(self->handle);
-	PyObject_FREE(self);
+        if (self->handle != INVALID_HANDLE_VALUE)
+                CloseHandle(self->handle);
+        PyObject_FREE(self);
 }
 
 static PyMethodDef sp_handle_methods[] = {
-	{"Detach", (PyCFunction) sp_handle_detach, METH_VARARGS},
-	{"Close",  (PyCFunction) sp_handle_close,  METH_VARARGS},
-	{NULL, NULL}
+        {"Detach", (PyCFunction) sp_handle_detach, METH_VARARGS},
+        {"Close",  (PyCFunction) sp_handle_close,  METH_VARARGS},
+        {NULL, NULL}
 };
 
 static PyObject*
 sp_handle_getattr(sp_handle_object* self, char* name)
 {
-	return Py_FindMethod(sp_handle_methods, (PyObject*) self, name);
+        return Py_FindMethod(sp_handle_methods, (PyObject*) self, name);
 }
 
 static PyObject*
 sp_handle_as_int(sp_handle_object* self)
 {
-	return PyInt_FromLong((long) self->handle);
+        return PyInt_FromLong((long) self->handle);
 }
 
 static PyNumberMethods sp_handle_as_number;
 
 statichere PyTypeObject sp_handle_type = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"_subprocess_handle", sizeof(sp_handle_object), 0,
-	(destructor) sp_handle_dealloc, /*tp_dealloc*/
-	0, /*tp_print*/
-	(getattrfunc) sp_handle_getattr,/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	&sp_handle_as_number,		/*tp_as_number */
-	0,				/*tp_as_sequence */
-	0,				/*tp_as_mapping */
-	0				/*tp_hash*/
+        PyObject_HEAD_INIT(NULL)
+        0,                              /*ob_size*/
+        "_subprocess_handle", sizeof(sp_handle_object), 0,
+        (destructor) sp_handle_dealloc, /*tp_dealloc*/
+        0, /*tp_print*/
+        (getattrfunc) sp_handle_getattr,/*tp_getattr*/
+        0,                              /*tp_setattr*/
+        0,                              /*tp_compare*/
+        0,                              /*tp_repr*/
+        &sp_handle_as_number,           /*tp_as_number */
+        0,                              /*tp_as_sequence */
+        0,                              /*tp_as_mapping */
+        0                               /*tp_hash*/
 };
 
 /* -------------------------------------------------------------------- */
@@ -149,99 +151,99 @@ statichere PyTypeObject sp_handle_type = {
 static PyObject *
 sp_GetStdHandle(PyObject* self, PyObject* args)
 {
-	HANDLE handle;
-	int std_handle;
+        HANDLE handle;
+        int std_handle;
 
-	if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle))
-		return NULL;
+        if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle))
+                return NULL;
 
-	Py_BEGIN_ALLOW_THREADS
-	handle = GetStdHandle((DWORD) std_handle);
-	Py_END_ALLOW_THREADS
+        Py_BEGIN_ALLOW_THREADS
+        handle = GetStdHandle((DWORD) std_handle);
+        Py_END_ALLOW_THREADS
 
-	if (handle == INVALID_HANDLE_VALUE)
-		return PyErr_SetFromWindowsErr(GetLastError());
+        if (handle == INVALID_HANDLE_VALUE)
+                return PyErr_SetFromWindowsErr(GetLastError());
 
-	if (! handle) {
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
+        if (! handle) {
+                Py_INCREF(Py_None);
+                return Py_None;
+        }
 
-	/* note: returns integer, not handle object */
-	return PyInt_FromLong((long) handle);
+        /* note: returns integer, not handle object */
+        return PyInt_FromLong((long) handle);
 }
 
 static PyObject *
 sp_GetCurrentProcess(PyObject* self, PyObject* args)
 {
-	if (! PyArg_ParseTuple(args, ":GetCurrentProcess"))
-		return NULL;
+        if (! PyArg_ParseTuple(args, ":GetCurrentProcess"))
+                return NULL;
 
-	return sp_handle_new(GetCurrentProcess());
+        return sp_handle_new(GetCurrentProcess());
 }
 
 static PyObject *
 sp_DuplicateHandle(PyObject* self, PyObject* args)
 {
-	HANDLE target_handle;
-	BOOL result;
-
-	long source_process_handle;
-	long source_handle;
-	long target_process_handle;
-	int desired_access;
-	int inherit_handle;
-	int options = 0;
-
-	if (! PyArg_ParseTuple(args, "lllii|i:DuplicateHandle",
-	                       &source_process_handle,
-	                       &source_handle,
-	                       &target_process_handle,
-	                       &desired_access,
-	                       &inherit_handle,
-	                       &options))
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS
-	result = DuplicateHandle(
-		(HANDLE) source_process_handle,
-		(HANDLE) source_handle,
-		(HANDLE) target_process_handle,
-		&target_handle,
-		desired_access,
-		inherit_handle,
-		options
-	);
-	Py_END_ALLOW_THREADS
-
-	if (! result)
-		return PyErr_SetFromWindowsErr(GetLastError());
-
-	return sp_handle_new(target_handle);
+        HANDLE target_handle;
+        BOOL result;
+
+        long source_process_handle;
+        long source_handle;
+        long target_process_handle;
+        int desired_access;
+        int inherit_handle;
+        int options = 0;
+
+        if (! PyArg_ParseTuple(args, "lllii|i:DuplicateHandle",
+                               &source_process_handle,
+                               &source_handle,
+                               &target_process_handle,
+                               &desired_access,
+                               &inherit_handle,
+                               &options))
+                return NULL;
+
+        Py_BEGIN_ALLOW_THREADS
+        result = DuplicateHandle(
+                (HANDLE) source_process_handle,
+                (HANDLE) source_handle,
+                (HANDLE) target_process_handle,
+                &target_handle,
+                desired_access,
+                inherit_handle,
+                options
+        );
+        Py_END_ALLOW_THREADS
+
+        if (! result)
+                return PyErr_SetFromWindowsErr(GetLastError());
+
+        return sp_handle_new(target_handle);
 }
 
 static PyObject *
 sp_CreatePipe(PyObject* self, PyObject* args)
 {
-	HANDLE read_pipe;
-	HANDLE write_pipe;
-	BOOL result;
+        HANDLE read_pipe;
+        HANDLE write_pipe;
+        BOOL result;
 
-	PyObject* pipe_attributes; /* ignored */
-	int size;
+        PyObject* pipe_attributes; /* ignored */
+        int size;
 
-	if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size))
-		return NULL;
+        if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size))
+                return NULL;
 
-	Py_BEGIN_ALLOW_THREADS
-	result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
-	Py_END_ALLOW_THREADS
+        Py_BEGIN_ALLOW_THREADS
+        result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
+        Py_END_ALLOW_THREADS
 
-	if (! result)
-		return PyErr_SetFromWindowsErr(GetLastError());
+        if (! result)
+                return PyErr_SetFromWindowsErr(GetLastError());
 
-	return Py_BuildValue(
-		"NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe));
+        return Py_BuildValue(
+                "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe));
 }
 
 /* helpers for createprocess */
@@ -249,288 +251,288 @@ sp_CreatePipe(PyObject* self, PyObject* args)
 static int
 getint(PyObject* obj, char* name)
 {
-	PyObject* value;
-	int ret;
-
-	value = PyObject_GetAttrString(obj, name);
-	if (! value) {
-		PyErr_Clear(); /* FIXME: propagate error? */
-		return 0;
-	}
-	ret = (int) PyInt_AsLong(value);
-	Py_DECREF(value);
-	return ret;
+        PyObject* value;
+        int ret;
+
+        value = PyObject_GetAttrString(obj, name);
+        if (! value) {
+                PyErr_Clear(); /* FIXME: propagate error? */
+                return 0;
+        }
+        ret = (int) PyInt_AsLong(value);
+        Py_DECREF(value);
+        return ret;
 }
 
 static HANDLE
 gethandle(PyObject* obj, char* name)
 {
-	sp_handle_object* value;
-	HANDLE ret;
-
-	value = (sp_handle_object*) PyObject_GetAttrString(obj, name);
-	if (! value) {
-		PyErr_Clear(); /* FIXME: propagate error? */
-		return NULL;
-	}
-	if (value->ob_type != &sp_handle_type)
-		ret = NULL;
-	else
-		ret = value->handle;
-	Py_DECREF(value);
-	return ret;
+        sp_handle_object* value;
+        HANDLE ret;
+
+        value = (sp_handle_object*) PyObject_GetAttrString(obj, name);
+        if (! value) {
+                PyErr_Clear(); /* FIXME: propagate error? */
+                return NULL;
+        }
+        if (value->ob_type != &sp_handle_type)
+                ret = NULL;
+        else
+                ret = value->handle;
+        Py_DECREF(value);
+        return ret;
 }
 
 static PyObject*
 getenvironment(PyObject* environment)
 {
-	int i, envsize;
-	PyObject* out = NULL;
-	PyObject* keys;
-	PyObject* values;
-	char* p;
-
-	/* convert environment dictionary to windows enviroment string */
-	if (! PyMapping_Check(environment)) {
-		PyErr_SetString(
-		    PyExc_TypeError, "environment must be dictionary or None");
-		return NULL;
-	}
-
-	envsize = PyMapping_Length(environment);
-
-	keys = PyMapping_Keys(environment);
-	values = PyMapping_Values(environment);
-	if (!keys || !values)
-		goto error;
-
-	out = PyString_FromStringAndSize(NULL, 2048);
-	if (! out)
-		goto error;
-
-	p = PyString_AS_STRING(out);
-
-	for (i = 0; i < envsize; i++) {
-		int ksize, vsize, totalsize;
-		PyObject* key = PyList_GET_ITEM(keys, i);
-		PyObject* value = PyList_GET_ITEM(values, i);
-
-		if (! PyString_Check(key) || ! PyString_Check(value)) {
-			PyErr_SetString(PyExc_TypeError,
-				"environment can only contain strings");
-			goto error;
-		}
-		ksize = PyString_GET_SIZE(key);
-		vsize = PyString_GET_SIZE(value);
-		totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 +
-							     vsize + 1 + 1;
-		if (totalsize > PyString_GET_SIZE(out)) {
-			int offset = p - PyString_AS_STRING(out);
-			_PyString_Resize(&out, totalsize + 1024);
-			p = PyString_AS_STRING(out) + offset;
-		}
-		memcpy(p, PyString_AS_STRING(key), ksize);
-		p += ksize;
-		*p++ = '=';
-		memcpy(p, PyString_AS_STRING(value), vsize);
-		p += vsize;
-		*p++ = '\0';
-	}
-
-	/* add trailing null byte */
-	*p++ = '\0';
-	_PyString_Resize(&out, p - PyString_AS_STRING(out));
-
-	/* PyObject_Print(out, stdout, 0); */
-
-	Py_XDECREF(keys);
-	Py_XDECREF(values);
-
-	return out;
+        int i, envsize;
+        PyObject* out = NULL;
+        PyObject* keys;
+        PyObject* values;
+        char* p;
+
+        /* convert environment dictionary to windows enviroment string */
+        if (! PyMapping_Check(environment)) {
+                PyErr_SetString(
+                    PyExc_TypeError, "environment must be dictionary or None");
+                return NULL;
+        }
+
+        envsize = PyMapping_Length(environment);
+
+        keys = PyMapping_Keys(environment);
+        values = PyMapping_Values(environment);
+        if (!keys || !values)
+                goto error;
+
+        out = PyString_FromStringAndSize(NULL, 2048);
+        if (! out)
+                goto error;
+
+        p = PyString_AS_STRING(out);
+
+        for (i = 0; i < envsize; i++) {
+                int ksize, vsize, totalsize;
+                PyObject* key = PyList_GET_ITEM(keys, i);
+                PyObject* value = PyList_GET_ITEM(values, i);
+
+                if (! PyString_Check(key) || ! PyString_Check(value)) {
+                        PyErr_SetString(PyExc_TypeError,
+                                "environment can only contain strings");
+                        goto error;
+                }
+                ksize = PyString_GET_SIZE(key);
+                vsize = PyString_GET_SIZE(value);
+                totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 +
+                                                             vsize + 1 + 1;
+                if (totalsize > PyString_GET_SIZE(out)) {
+                        int offset = p - PyString_AS_STRING(out);
+                        _PyString_Resize(&out, totalsize + 1024);
+                        p = PyString_AS_STRING(out) + offset;
+                }
+                memcpy(p, PyString_AS_STRING(key), ksize);
+                p += ksize;
+                *p++ = '=';
+                memcpy(p, PyString_AS_STRING(value), vsize);
+                p += vsize;
+                *p++ = '\0';
+        }
+
+        /* add trailing null byte */
+        *p++ = '\0';
+        _PyString_Resize(&out, p - PyString_AS_STRING(out));
+
+        /* PyObject_Print(out, stdout, 0); */
+
+        Py_XDECREF(keys);
+        Py_XDECREF(values);
+
+        return out;
 
  error:
-	Py_XDECREF(out);
-	Py_XDECREF(keys);
-	Py_XDECREF(values);
-	return NULL;
+        Py_XDECREF(out);
+        Py_XDECREF(keys);
+        Py_XDECREF(values);
+        return NULL;
 }
 
 static PyObject *
 sp_CreateProcess(PyObject* self, PyObject* args)
 {
-	BOOL result;
-	PROCESS_INFORMATION pi;
-	STARTUPINFO si;
-	PyObject* environment;
-
-	char* application_name;
-	char* command_line;
-	PyObject* process_attributes; /* ignored */
-	PyObject* thread_attributes; /* ignored */
-	int inherit_handles;
-	int creation_flags;
-	PyObject* env_mapping;
-	char* current_directory;
-	PyObject* startup_info;
-
-	if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess",
-			       &application_name,
-			       &command_line,
-			       &process_attributes,
-			       &thread_attributes,
-			       &inherit_handles,
-			       &creation_flags,
-			       &env_mapping,
-			       ¤t_directory,
-			       &startup_info))
-		return NULL;
-
-	ZeroMemory(&si, sizeof(si));
-	si.cb = sizeof(si);
-
-	/* note: we only support a small subset of all SI attributes */
-	si.dwFlags = getint(startup_info, "dwFlags");
-	si.wShowWindow = getint(startup_info, "wShowWindow");
-	si.hStdInput = gethandle(startup_info, "hStdInput");
-	si.hStdOutput = gethandle(startup_info, "hStdOutput");
-	si.hStdError = gethandle(startup_info, "hStdError");
-
-	if (PyErr_Occurred())
-		return NULL;
-
-	if (env_mapping == Py_None)
-		environment = NULL;
-	else {
-		environment = getenvironment(env_mapping);
-		if (! environment)
-			return NULL;
-	}
-
-	Py_BEGIN_ALLOW_THREADS
-	result = CreateProcess(application_name,
-			       command_line,
-			       NULL,
-			       NULL,
-			       inherit_handles,
-			       creation_flags,
-			       environment ? PyString_AS_STRING(environment) : NULL,
-			       current_directory,
-			       &si,
-			       &pi);
-	Py_END_ALLOW_THREADS
-
-	Py_XDECREF(environment);
-
-	if (! result)
-		return PyErr_SetFromWindowsErr(GetLastError());
-
-	return Py_BuildValue("NNii",
-			     sp_handle_new(pi.hProcess),
-			     sp_handle_new(pi.hThread),
-			     pi.dwProcessId,
-			     pi.dwThreadId);
+        BOOL result;
+        PROCESS_INFORMATION pi;
+        STARTUPINFO si;
+        PyObject* environment;
+
+        char* application_name;
+        char* command_line;
+        PyObject* process_attributes; /* ignored */
+        PyObject* thread_attributes; /* ignored */
+        int inherit_handles;
+        int creation_flags;
+        PyObject* env_mapping;
+        char* current_directory;
+        PyObject* startup_info;
+
+        if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess",
+                               &application_name,
+                               &command_line,
+                               &process_attributes,
+                               &thread_attributes,
+                               &inherit_handles,
+                               &creation_flags,
+                               &env_mapping,
+                               ¤t_directory,
+                               &startup_info))
+                return NULL;
+
+        ZeroMemory(&si, sizeof(si));
+        si.cb = sizeof(si);
+
+        /* note: we only support a small subset of all SI attributes */
+        si.dwFlags = getint(startup_info, "dwFlags");
+        si.wShowWindow = getint(startup_info, "wShowWindow");
+        si.hStdInput = gethandle(startup_info, "hStdInput");
+        si.hStdOutput = gethandle(startup_info, "hStdOutput");
+        si.hStdError = gethandle(startup_info, "hStdError");
+
+        if (PyErr_Occurred())
+                return NULL;
+
+        if (env_mapping == Py_None)
+                environment = NULL;
+        else {
+                environment = getenvironment(env_mapping);
+                if (! environment)
+                        return NULL;
+        }
+
+        Py_BEGIN_ALLOW_THREADS
+        result = CreateProcess(application_name,
+                               command_line,
+                               NULL,
+                               NULL,
+                               inherit_handles,
+                               creation_flags,
+                               environment ? PyString_AS_STRING(environment) : NULL,
+                               current_directory,
+                               &si,
+                               &pi);
+        Py_END_ALLOW_THREADS
+
+        Py_XDECREF(environment);
+
+        if (! result)
+                return PyErr_SetFromWindowsErr(GetLastError());
+
+        return Py_BuildValue("NNii",
+                             sp_handle_new(pi.hProcess),
+                             sp_handle_new(pi.hThread),
+                             pi.dwProcessId,
+                             pi.dwThreadId);
 }
 
 static PyObject *
 sp_TerminateProcess(PyObject* self, PyObject* args)
 {
-	BOOL result;
+        BOOL result;
 
-	long process;
-	int exit_code;
-	if (! PyArg_ParseTuple(args, "li:TerminateProcess", &process,
-			       &exit_code))
-		return NULL;
+        long process;
+        int exit_code;
+        if (! PyArg_ParseTuple(args, "li:TerminateProcess", &process,
+                               &exit_code))
+                return NULL;
 
-	result = TerminateProcess((HANDLE) process, exit_code);
+        result = TerminateProcess((HANDLE) process, exit_code);
 
-	if (! result)
-		return PyErr_SetFromWindowsErr(GetLastError());
+        if (! result)
+                return PyErr_SetFromWindowsErr(GetLastError());
 
-	Py_INCREF(Py_None);
-	return Py_None;
+        Py_INCREF(Py_None);
+        return Py_None;
 }
 
 static PyObject *
 sp_GetExitCodeProcess(PyObject* self, PyObject* args)
 {
-	DWORD exit_code;
-	BOOL result;
+        DWORD exit_code;
+        BOOL result;
 
-	long process;
-	if (! PyArg_ParseTuple(args, "l:GetExitCodeProcess", &process))
-		return NULL;
+        long process;
+        if (! PyArg_ParseTuple(args, "l:GetExitCodeProcess", &process))
+                return NULL;
 
-	result = GetExitCodeProcess((HANDLE) process, &exit_code);
+        result = GetExitCodeProcess((HANDLE) process, &exit_code);
 
-	if (! result)
-		return PyErr_SetFromWindowsErr(GetLastError());
+        if (! result)
+                return PyErr_SetFromWindowsErr(GetLastError());
 
-	return PyInt_FromLong(exit_code);
+        return PyInt_FromLong(exit_code);
 }
 
 static PyObject *
 sp_WaitForSingleObject(PyObject* self, PyObject* args)
 {
-	DWORD result;
+        DWORD result;
 
-	long handle;
-	int milliseconds;
-	if (! PyArg_ParseTuple(args, "li:WaitForSingleObject",
-	                  	     &handle,
-	                  	     &milliseconds))
-		return NULL;
+        long handle;
+        int milliseconds;
+        if (! PyArg_ParseTuple(args, "li:WaitForSingleObject",
+                                     &handle,
+                                     &milliseconds))
+                return NULL;
 
-	Py_BEGIN_ALLOW_THREADS
-	result = WaitForSingleObject((HANDLE) handle, (DWORD) milliseconds);
-	Py_END_ALLOW_THREADS
+        Py_BEGIN_ALLOW_THREADS
+        result = WaitForSingleObject((HANDLE) handle, (DWORD) milliseconds);
+        Py_END_ALLOW_THREADS
 
-	if (result == WAIT_FAILED)
-		return PyErr_SetFromWindowsErr(GetLastError());
+        if (result == WAIT_FAILED)
+                return PyErr_SetFromWindowsErr(GetLastError());
 
-	return PyInt_FromLong((int) result);
+        return PyInt_FromLong((int) result);
 }
 
 static PyObject *
 sp_GetVersion(PyObject* self, PyObject* args)
 {
-	if (! PyArg_ParseTuple(args, ":GetVersion"))
-		return NULL;
+        if (! PyArg_ParseTuple(args, ":GetVersion"))
+                return NULL;
 
-	return PyInt_FromLong((int) GetVersion());
+        return PyInt_FromLong((int) GetVersion());
 }
 
 static PyObject *
 sp_GetModuleFileName(PyObject* self, PyObject* args)
 {
-	BOOL result;
-	long module;
-	TCHAR filename[MAX_PATH];
+        BOOL result;
+        long module;
+        TCHAR filename[MAX_PATH];
 
-	if (! PyArg_ParseTuple(args, "l:GetModuleFileName", &module))
-		return NULL;
+        if (! PyArg_ParseTuple(args, "l:GetModuleFileName", &module))
+                return NULL;
 
-	result = GetModuleFileName((HMODULE)module, filename, MAX_PATH);
-	filename[MAX_PATH-1] = '\0';
+        result = GetModuleFileName((HMODULE)module, filename, MAX_PATH);
+        filename[MAX_PATH-1] = '\0';
 
-	if (! result)
-		return PyErr_SetFromWindowsErr(GetLastError());
+        if (! result)
+                return PyErr_SetFromWindowsErr(GetLastError());
 
-	return PyString_FromString(filename);
+        return PyString_FromString(filename);
 }
 
 static PyMethodDef sp_functions[] = {
-	{"GetStdHandle",	sp_GetStdHandle,	METH_VARARGS},
-	{"GetCurrentProcess",	sp_GetCurrentProcess,	METH_VARARGS},
-	{"DuplicateHandle",	sp_DuplicateHandle,	METH_VARARGS},
-	{"CreatePipe",		sp_CreatePipe,		METH_VARARGS},
-	{"CreateProcess",	sp_CreateProcess,	METH_VARARGS},
-	{"TerminateProcess",	sp_TerminateProcess,	METH_VARARGS},
-	{"GetExitCodeProcess",	sp_GetExitCodeProcess,	METH_VARARGS},
-	{"WaitForSingleObject",	sp_WaitForSingleObject, METH_VARARGS},
-	{"GetVersion",		sp_GetVersion,		METH_VARARGS},
-	{"GetModuleFileName",	sp_GetModuleFileName,	METH_VARARGS},
-	{NULL, NULL}
+        {"GetStdHandle",        sp_GetStdHandle,        METH_VARARGS},
+        {"GetCurrentProcess",   sp_GetCurrentProcess,   METH_VARARGS},
+        {"DuplicateHandle",     sp_DuplicateHandle,     METH_VARARGS},
+        {"CreatePipe",          sp_CreatePipe,          METH_VARARGS},
+        {"CreateProcess",       sp_CreateProcess,       METH_VARARGS},
+        {"TerminateProcess",    sp_TerminateProcess,    METH_VARARGS},
+        {"GetExitCodeProcess",  sp_GetExitCodeProcess,  METH_VARARGS},
+        {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS},
+        {"GetVersion",          sp_GetVersion,          METH_VARARGS},
+        {"GetModuleFileName",   sp_GetModuleFileName,   METH_VARARGS},
+        {NULL, NULL}
 };
 
 /* -------------------------------------------------------------------- */
@@ -538,11 +540,11 @@ static PyMethodDef sp_functions[] = {
 static void
 defint(PyObject* d, const char* name, int value)
 {
-	PyObject* v = PyInt_FromLong((long) value);
-	if (v) {
-		PyDict_SetItemString(d, (char*) name, v);
-		Py_DECREF(v);
-	}
+        PyObject* v = PyInt_FromLong((long) value);
+        if (v) {
+                PyDict_SetItemString(d, (char*) name, v);
+                Py_DECREF(v);
+        }
 }
 
 #if PY_VERSION_HEX >= 0x02030000
@@ -552,27 +554,27 @@ DL_EXPORT(void)
 #endif
 init_subprocess()
 {
-	PyObject *d;
-	PyObject *m;
-
-	/* patch up object descriptors */
-	sp_handle_type.ob_type = &PyType_Type;
-	sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int;
-
-	m = Py_InitModule("_subprocess", sp_functions);
-	if (m == NULL)
-		return;
-	d = PyModule_GetDict(m);
-
-	/* constants */
-	defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE);
-	defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE);
-	defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE);
-	defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS);
-	defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES);
-	defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW);
-	defint(d, "SW_HIDE", SW_HIDE);
-	defint(d, "INFINITE", INFINITE);
-	defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0);
-	defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE);
+        PyObject *d;
+        PyObject *m;
+
+        /* patch up object descriptors */
+        sp_handle_type.ob_type = &PyType_Type;
+        sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int;
+
+        m = Py_InitModule("_subprocess", sp_functions);
+        if (m == NULL)
+                return;
+        d = PyModule_GetDict(m);
+
+        /* constants */
+        defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE);
+        defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE);
+        defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE);
+        defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS);
+        defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES);
+        defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW);
+        defint(d, "SW_HIDE", SW_HIDE);
+        defint(d, "INFINITE", INFINITE);
+        defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0);
+        defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE);
 }
diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp
index f8074aab97b2..925c2b585c34 100644
--- a/src/_tkagg.cpp
+++ b/src/_tkagg.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /*
  * The Python Imaging Library.
  * $Id$
diff --git a/src/_ttconv.cpp b/src/_ttconv.cpp
index 5753de5b7956..b203a138a442 100644
--- a/src/_ttconv.cpp
+++ b/src/_ttconv.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /*
   _ttconv.c
 
diff --git a/src/_windowing.cpp b/src/_windowing.cpp
index 1b4083c76dbc..949944c0539a 100644
--- a/src/_windowing.cpp
+++ b/src/_windowing.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include "Python.h"
 #include 
 
diff --git a/src/_wxagg.cpp b/src/_wxagg.cpp
deleted file mode 100644
index 1586c4f96081..000000000000
--- a/src/_wxagg.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-// File: _wxagg.cpp
-// Purpose: Accelerate WXAgg by doing the agg->wxWidgets conversions in C++.
-// Author: Ken McIvor 
-//
-// Copyright 2005 Illinois Institute of Technology
-// Derived from `_gtkagg.cpp', Copyright 2004-2005 John Hunter
-//
-// See the file "LICENSE" for information on usage and redistribution
-// of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-
-
-// TODO:
-// * Better type checking.
-//
-// * Make the `bbox' argument optional.
-//
-// * Determine if there are any thread-safety issues with this implementation.
-//
-// * Perform some AGG kung-fu to let us slice a region out of a
-//   rendering_buffer and convert it from RGBA to RGB on the fly, rather than
-//   making itermediate copies.  This could be of use in _gtkagg and _tkagg as
-//   well.
-//
-// * Write an agg_to_wx_bitmap() that works more like agg_to_gtk_drawable(),
-//   drawing directly to a bitmap.
-//
-//   This was the initial plan, except that I had not idea how to take a
-//   wx.Bitmap Python shadow class and turn it into a wxBitmap pointer.
-//
-//   It appears that this is the way to do it:
-//       bool success = wxPyConvertSwigPtr(pyBitmap, (void**)&bitmap,
-//           _T("wxBitmap"));
-//
-//   I'm not sure this will speed things up much, since wxWidgets requires you
-//   to go AGG->wx.Image->wx.Bitmap before you can blit using a MemoryDC.
-
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "agg_basics.h"
-#include "_backend_agg.h"
-#include "agg_pixfmt_rgba.h"
-#include "util/agg_color_conv_rgb8.h"
-#include "agg_py_transforms.h"
-
-#include 
-#include 
-#include 
-
-
-// forward declarations
-static wxImage  *convert_agg2image(RendererAgg *aggRenderer, Py::Object clipbox);
-static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Py::Object clipbox);
-
-
-// the extension module
-class _wxagg_module : public Py::ExtensionModule<_wxagg_module>
-{
-public:
-
-    _wxagg_module()
-            : Py::ExtensionModule<_wxagg_module>("_wxkagg")
-    {
-        add_varargs_method("convert_agg_to_wx_image",
-                           &_wxagg_module::convert_agg_to_wx_image,
-                           "Convert the region of the agg buffer bounded by bbox to a wx.Image."
-                           "  If bbox\nis None, the entire buffer is converted.\n\nNote: agg must"
-                           " be a backend_agg.RendererAgg instance.");
-
-        add_varargs_method("convert_agg_to_wx_bitmap",
-                           &_wxagg_module::convert_agg_to_wx_bitmap,
-                           "Convert the region of the agg buffer bounded by bbox to a wx.Bitmap."
-                           "  If bbox\nis None, the entire buffer is converted.\n\nNote: agg must"
-                           " be a backend_agg.RendererAgg instance.");
-
-        initialize("The _wxagg module");
-    }
-
-    virtual ~_wxagg_module() {}
-
-private:
-
-    Py::Object convert_agg_to_wx_image(const Py::Tuple &args)
-    {
-        args.verify_length(2);
-
-        RendererAgg* aggRenderer = static_cast(
-                                       args[0].getAttr("_renderer").ptr());
-
-        Py::Object clipbox = args[1];
-
-        // convert the buffer
-        wxImage *image = convert_agg2image(aggRenderer, clipbox);
-
-        // wrap a wx.Image around the result and return it
-        PyObject *pyWxImage = wxPyConstructObject(image, _T("wxImage"), 1);
-        if (pyWxImage == NULL)
-        {
-            throw Py::MemoryError(
-                "_wxagg.convert_agg_to_wx_image(): could not create the wx.Image");
-        }
-
-        return Py::asObject(pyWxImage);
-    }
-
-
-    Py::Object convert_agg_to_wx_bitmap(const Py::Tuple &args)
-    {
-        args.verify_length(2);
-
-        RendererAgg* aggRenderer = static_cast(
-            args[0].getAttr("_renderer").ptr());
-
-        Py::Object clipbox = args[1];
-
-        // convert the buffer
-        wxBitmap *bitmap = convert_agg2bitmap(aggRenderer, clipbox);
-
-        // wrap a wx.Bitmap around the result and return it
-        PyObject *pyWxBitmap = wxPyConstructObject(bitmap, _T("wxBitmap"), 1);
-        if (pyWxBitmap == NULL)
-        {
-            throw Py::MemoryError(
-                "_wxagg.convert_agg_to_wx_bitmap(): could not create the wx.Bitmap");
-        }
-
-        return Py::asObject(pyWxBitmap);
-    }
-};
-
-
-//
-// Implementation Functions
-//
-
-static wxImage *convert_agg2image(RendererAgg *aggRenderer, Py::Object clipbox)
-{
-    int srcWidth  = 1;
-    int srcHeight = 1;
-    int srcStride = 1;
-
-    bool deleteSrcBuffer = false;
-    agg::int8u *srcBuffer = NULL;
-
-    double l, b, r, t;
-
-    if (!py_convert_bbox(clipbox.ptr(), l, b, r, t))
-    {
-        // Convert everything: rgba => rgb -> image
-        srcBuffer = aggRenderer->pixBuffer;
-        srcWidth  = (int) aggRenderer->get_width();
-        srcHeight = (int) aggRenderer->get_height();
-        srcStride = (int) aggRenderer->get_width() * 4;
-    }
-    else
-    {
-        // Convert a region: rgba => clipped rgba => rgb -> image
-        srcWidth = (int)(r - l);
-        srcHeight = (int)(t - b);
-        srcStride = srcWidth * 4;
-
-        deleteSrcBuffer = true;
-        srcBuffer = new agg::int8u[srcStride*srcHeight];
-        if (srcBuffer == NULL)
-        {
-            throw Py::MemoryError(
-                "_wxagg::convert_agg2image(): could not allocate `srcBuffer'");
-        }
-
-        int h = (int) aggRenderer->get_height();
-        agg::rect_base region(
-            (int) l,      // x1
-            h - (int) t,  // y1
-            (int) r,      // x2
-            h - (int) b); // y2
-
-        agg::rendering_buffer rbuf;
-        rbuf.attach(srcBuffer, srcWidth, srcHeight, srcStride);
-        pixfmt pf(rbuf);
-        renderer_base rndr(pf);
-        rndr.copy_from(aggRenderer->renderingBuffer, ®ion,
-                       (int) - l, (int)(t - h));
-    }
-
-    // allocate the RGB data array
-
-    // use malloc(3) because wxImage will use free(3)
-    agg::int8u *destBuffer = (agg::int8u *) malloc(
-                                 sizeof(agg::int8u) * srcWidth * 3 * srcHeight);
-
-    if (destBuffer == NULL)
-    {
-        if (deleteSrcBuffer)
-        {
-            delete [] srcBuffer;
-        }
-
-        throw Py::MemoryError(
-            "_wxagg::convert_agg2image(): could not allocate `destBuffer'");
-    }
-
-    // convert from RGBA to RGB
-    agg::rendering_buffer rbSource;
-    rbSource.attach(srcBuffer, srcWidth, srcHeight, srcStride);
-
-    agg::rendering_buffer rbDest;
-    rbDest.attach(destBuffer, srcWidth, srcHeight, srcWidth*3);
-
-    agg::color_conv(&rbDest, &rbSource, agg::color_conv_rgba32_to_rgb24());
-
-    // Create a wxImage using the RGB data
-    wxImage *image = new wxImage(srcWidth, srcHeight, destBuffer);
-    if (image == NULL)
-    {
-        if (deleteSrcBuffer)
-        {
-            delete [] srcBuffer;
-        }
-
-        free(destBuffer);
-        throw Py::MemoryError(
-            "_wxagg::convert_agg2image(): could not allocate `image'");
-    }
-
-    if (deleteSrcBuffer)
-    {
-        delete [] srcBuffer;
-    }
-
-    return image;
-}
-
-
-static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Py::Object clipbox)
-{
-    // Convert everything: rgba => rgb -> image => bitmap
-    // Convert a region:   rgba => clipped rgba => rgb -> image => bitmap
-    wxImage *image = convert_agg2image(aggRenderer, clipbox);
-    wxBitmap *bitmap = new wxBitmap(*image);
-
-    image->Destroy();
-    delete image;
-
-    if (bitmap == NULL)
-    {
-        throw Py::MemoryError(
-            "_wxagg::convert_agg2bitmap(): could not allocate `bitmap'");
-    }
-
-    return bitmap;
-}
-
-
-//
-// Module Initialization
-//
-
-extern "C"
-    DL_EXPORT(void)
-    init_wxagg(void)
-{
-    wxPyCoreAPI_IMPORT();
-    //suppress an unused variable warning by creating _wxagg_module in two lines
-    static _wxagg_module* _wxagg = NULL;
-    _wxagg = new _wxagg_module;
-};
diff --git a/src/agg_py_path_iterator.h b/src/agg_py_path_iterator.h
index b014739ae89a..8449dd2054d8 100644
--- a/src/agg_py_path_iterator.h
+++ b/src/agg_py_path_iterator.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #ifndef __AGG_PY_PATH_ITERATOR_H__
 #define __AGG_PY_PATH_ITERATOR_H__
 
diff --git a/src/agg_py_transforms.cpp b/src/agg_py_transforms.cpp
index bee369cfb0a7..457d5e7f602c 100644
--- a/src/agg_py_transforms.cpp
+++ b/src/agg_py_transforms.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include 
 
 #define NO_IMPORT_ARRAY
@@ -75,7 +77,7 @@ py_convert_bbox(PyObject* bbox_obj, double& l, double& b, double& r, double& t)
         if (!bbox || PyArray_NDIM(bbox) != 2 || PyArray_DIM(bbox, 0) != 2 || PyArray_DIM(bbox, 1) != 2)
         {
             throw Py::TypeError
-            ("Argument 3 to agg_to_gtk_drawable must be a Bbox object.");
+            ("Expected a bbox array");
         }
 
         l = *(double*)PyArray_GETPTR2(bbox, 0, 0);
diff --git a/src/agg_py_transforms.h b/src/agg_py_transforms.h
index 4b5abdd657a5..db66a2ff4d79 100644
--- a/src/agg_py_transforms.h
+++ b/src/agg_py_transforms.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #ifndef __AGG_PY_TRANSFORMS_H__
 #define __AGG_PY_TRANSFORMS_H__
 
diff --git a/src/cntr.c b/src/cntr.c
index b1118aa84673..631471f89542 100644
--- a/src/cntr.c
+++ b/src/cntr.c
@@ -1,3 +1,5 @@
+/* -*- mode: c; c-basic-offset: 4 -*- */
+
 /*
   cntr.c
   General purpose contour tracer for quadrilateral meshes.
@@ -18,7 +20,7 @@
 #include "structmember.h"
 #include 
 #include 
-#include "numerix.h"
+#include "numpy/arrayobject.h"
 
 /* Note that all arrays in these routines are Fortran-style,
    in the sense that the "i" index varies fastest; the dimensions
@@ -1804,7 +1806,7 @@ Cntr_init(Cntr *self, PyObject *args, PyObject *kwds)
                                                       PyArray_DOUBLE, 2, 2);
     if (marg)
         mpa = (PyArrayObject *) PyArray_ContiguousFromObject(marg,
-                                                      PyArray_SBYTE, 2, 2);
+                                                      PyArray_BYTE, 2, 2);
     else
         mpa = NULL;
 
diff --git a/src/ft2font.cpp b/src/ft2font.cpp
index 1f334cc40e88..0bfb26e432d6 100644
--- a/src/ft2font.cpp
+++ b/src/ft2font.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include "ft2font.h"
 #include "mplutils.h"
 #include 
diff --git a/src/ft2font.h b/src/ft2font.h
index 86b5a130ef8d..827622c19b9a 100644
--- a/src/ft2font.h
+++ b/src/ft2font.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /* A python interface to freetype2 */
 #ifndef _FT2FONT_H
 #define _FT2FONT_H
diff --git a/src/mplutils.cpp b/src/mplutils.cpp
index 766173b189ba..febb97ac81a0 100644
--- a/src/mplutils.cpp
+++ b/src/mplutils.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include 
 #include 
 #include 
diff --git a/src/mplutils.h b/src/mplutils.h
index d3c269f3d1d4..e0305f142f50 100644
--- a/src/mplutils.h
+++ b/src/mplutils.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /* mplutils.h   --
  *
  * $Header$
diff --git a/src/numerix.h b/src/numerix.h
deleted file mode 100644
index d4aa83aa757e..000000000000
--- a/src/numerix.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* numerix.h	-- John Hunter
- */
-
-#ifndef _NUMERIX_H
-#define _NUMERIX_H
-#include "numpy/arrayobject.h"
-#if (NDARRAY_VERSION >= 0x00090908)
-#include "numpy/oldnumeric.h"
-#endif
-
-#endif
diff --git a/src/nxutils.c b/src/nxutils.c
index bf8b35374b62..c88bdf40c6df 100644
--- a/src/nxutils.c
+++ b/src/nxutils.c
@@ -1,3 +1,5 @@
+/* -*- mode: c; c-basic-offset: 4 -*- */
+
 #include 
 #include "structmember.h"
 #include 
@@ -24,8 +26,8 @@ int pnpoly_api(int npol, double *xp, double *yp, double x, double y)
   int i, j, c = 0;
   for (i = 0, j = npol-1; i < npol; j = i++) {
     if ((((yp[i]<=y) && (ydimensions[1]!=2)
     {
       PyErr_SetString(PyExc_ValueError,
-		      "Arguments verts must be a Nx2 array.");
+                      "Arguments verts must be a Nx2 array.");
       Py_XDECREF(verts);
       return NULL;
 
@@ -118,7 +120,7 @@ points_inside_poly(PyObject *self, PyObject *args)
   if (verts == NULL)
     {
       PyErr_SetString(PyExc_ValueError,
-		      "Argument verts must be a Nx2 array.");
+                      "Argument verts must be a Nx2 array.");
       Py_XDECREF(verts);
       return NULL;
 
@@ -129,7 +131,7 @@ points_inside_poly(PyObject *self, PyObject *args)
   if (verts->dimensions[1]!=2)
     {
       PyErr_SetString(PyExc_ValueError,
-		      "Arguments verts must be a Nx2 array.");
+                      "Arguments verts must be a Nx2 array.");
       Py_XDECREF(verts);
       return NULL;
 
@@ -163,7 +165,7 @@ points_inside_poly(PyObject *self, PyObject *args)
   if (xypoints == NULL)
     {
       PyErr_SetString(PyExc_ValueError,
-		      "Arguments xypoints must an Nx2 array.");
+                      "Arguments xypoints must an Nx2 array.");
       Py_XDECREF(verts);
       Py_XDECREF(xypoints);
       PyMem_Free(xv);
@@ -175,7 +177,7 @@ points_inside_poly(PyObject *self, PyObject *args)
   if (xypoints->dimensions[1]!=2)
     {
       PyErr_SetString(PyExc_ValueError,
-		      "Arguments xypoints must be a Nx2 array.");
+                      "Arguments xypoints must be a Nx2 array.");
 
       Py_XDECREF(verts);
       Py_XDECREF(xypoints);
diff --git a/src/path_cleanup.cpp b/src/path_cleanup.cpp
index 708509390799..7e9bee6367aa 100644
--- a/src/path_cleanup.cpp
+++ b/src/path_cleanup.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #include 
 #define NO_IMPORT_ARRAY
 #include "numpy/arrayobject.h"
diff --git a/src/path_cleanup.h b/src/path_cleanup.h
index 43bdcb983230..e5f781f9d9a0 100644
--- a/src/path_cleanup.h
+++ b/src/path_cleanup.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #ifndef PATH_CLEANUP_H
 #define PATH_CLEANUP_H
 
diff --git a/src/path_converters.h b/src/path_converters.h
index 7d6c1ea4eb98..c45ff862c6f6 100644
--- a/src/path_converters.h
+++ b/src/path_converters.h
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 #ifndef __PATH_CONVERTERS_H__
 #define __PATH_CONVERTERS_H__
 
diff --git a/test/_buildbot_doc.sh b/test/_buildbot_doc.sh
index 71feaded6b1f..6551ee0d2d3b 100755
--- a/test/_buildbot_doc.sh
+++ b/test/_buildbot_doc.sh
@@ -8,8 +8,8 @@ source $TARGET/bin/activate
 echo "removing MPL config dir"
 python -c "import shutil,matplotlib; x=matplotlib.get_configdir(); shutil.rmtree(x)"
 
-echo "calling 'easy_install sphinx'"
-easy_install sphinx
+echo "calling 'easy_install Sphinx'"
+easy_install Sphinx
 
 echo "calling 'cd doc'"
 cd doc
diff --git a/test/_buildbot_mac_sage.sh b/test/_buildbot_mac_sage.sh
index 63ee5e7fb876..31235d5d8122 100755
--- a/test/_buildbot_mac_sage.sh
+++ b/test/_buildbot_mac_sage.sh
@@ -1,12 +1,19 @@
 #!/bin/bash
 set -e
-rm -rf ${HOME}/.matplotlib/*
 rm -rf build
 
+export MPLCONFIGDIR=${HOME}/.matplotlib_buildbot
 export PATH=${HOME}/dev/bin:$PATH
-export PYTHON=${HOME}/dev/bin/python
-export PREFIX=${HOME}/devbb 
+export PYTHON=/usr/bin/python2.6
+export PREFIX=${HOME}/devbb
 export PYTHONPATH=${PREFIX}/lib/python2.6/site-packages:${HOME}/dev/lib/python2.6/site-packages
+export LD_LIBRARY_PATH=${PREFIX}/lib
+export MPLSETUPCFG=test/setup.sageosx.cfg
+rm -rf ${MPLCONFIGDIR}/*
+rm -rf ${PREFIX}/lib/python2.6/site-packages/matplotlib*
+echo 'backend : Agg' > $MPLCONFIGDIR/matplotlibrc
+
+
 
 make -f make.osx mpl_install
 echo ${PYTHONPATH}
diff --git a/test/setup.sageosx.cfg b/test/setup.sageosx.cfg
new file mode 100644
index 000000000000..9e6b7a48ca32
--- /dev/null
+++ b/test/setup.sageosx.cfg
@@ -0,0 +1,83 @@
+# Rename this file to setup.cfg to modify matplotlib's
+# build options.
+
+[egg_info]
+tag_svn_revision = 1
+
+[directories]
+# Uncomment to override the default basedir in setupext.py.
+# This can be a single directory or a space-delimited list of directories.
+#basedirlist = /usr
+
+[status]
+# To suppress display of the dependencies and their versions
+# at the top of the build log, uncomment the following line:
+#suppress = True
+#
+# Uncomment to insert lots of diagnostic prints in extension code
+#verbose = True
+
+[provide_packages]
+# By default, matplotlib checks for a few dependencies and
+# installs them if missing. This feature can be turned off
+# by uncommenting the following lines. Acceptible values are:
+#     True: install, overwrite an existing installation
+#     False: do not install
+#     auto: install only if the package is unavailable. This
+#           is the default behavior
+#
+## Date/timezone support:
+#pytz = False
+#dateutil = False
+
+[gui_support]
+# Matplotlib supports multiple GUI toolkits, including Cocoa,
+# GTK, Fltk, MacOSX, Qt, Qt4, Tk, and WX. Support for many of
+# these toolkits requires AGG, the Anti-Grain Geometry library,
+# which is provided by matplotlib and built by default.
+#
+# Some backends are written in pure Python, and others require
+# extension code to be compiled. By default, matplotlib checks
+# for these GUI toolkits during installation and, if present,
+# compiles the required extensions to support the toolkit. GTK
+# support requires the GTK runtime environment and PyGTK. Wx
+# support requires wxWidgets and wxPython. Tk support requires
+# Tk and Tkinter. The other GUI toolkits do not require any
+# extension code, and can be used as long as the libraries are
+# installed on your system.
+#
+# You can uncomment any the following lines if you know you do
+# not want to use the GUI toolkit. Acceptible values are:
+#     True: build the extension. Exits with a warning if the
+#           required dependencies are not available
+#     False: do not build the extension
+#     auto: build if the required dependencies are available,
+#           otherwise skip silently. This is the default
+#           behavior
+#
+gtk = False
+gtkagg = False
+tkagg = False
+wxagg = False
+macosx = False
+
+[rc_options]
+# User-configurable options
+#
+# Default backend, one of: Agg, Cairo, CocoaAgg, GTK, GTKAgg, GTKCairo,
+# FltkAgg, MacOSX, Pdf, Ps, QtAgg, Qt4Agg, SVG, TkAgg, WX, WXAgg.
+#
+# The Agg, Ps, Pdf and SVG backends do not require external
+# dependencies. Do not choose GTK, GTKAgg, GTKCairo, MacOSX, TkAgg or WXAgg
+# if you have disabled the relevent extension modules.  Agg will be used
+# by default.
+#
+backend = Agg
+#
+# The numerix module was historically used to provide
+# compatibility between the Numeric, numarray, and NumPy array
+# packages. Now that NumPy has emerge as the universal array
+# package for python, numerix is not really necessary and is
+# maintained to provide backward compatibility. Do not change
+# this unless you have a compelling reason to do so.
+#numerix = numpy
diff --git a/ttconv/global_defines.h b/ttconv/global_defines.h
index 0a6f84d314b7..04dd41e02ac1 100644
--- a/ttconv/global_defines.h
+++ b/ttconv/global_defines.h
@@ -1,3 +1,5 @@
+/* -*- mode: c; c-basic-offset: 4 -*- */
+
 /*
  * Modified for use within matplotlib
  * 5 July 2007
@@ -18,8 +20,8 @@
 **
 ** The PPR project was begun 28 December 1992.
 **
-** There are many things in this file you may want to change.  This file 
-** should be the first include file.  It is the header file for the whole 
+** There are many things in this file you may want to change.  This file
+** should be the first include file.  It is the header file for the whole
 ** project.
 **
 ** This file was last modified 22 December 1995.
diff --git a/ttconv/truetype.h b/ttconv/truetype.h
index 283163b30c2e..86be14fe3705 100644
--- a/ttconv/truetype.h
+++ b/ttconv/truetype.h
@@ -1,3 +1,5 @@
+/* -*- mode: c; c-basic-offset: 4 -*- */
+
 /*
  * Modified for use within matplotlib
  * 5 July 2007
@@ -48,37 +50,37 @@ struct TTFONT
     TTFONT();
     ~TTFONT();
 
-    const char *filename;		/* Name of TT file */
-    FILE *file;				/* the open TT file */
-    font_type_enum  target_type;	/* 42 or 3 for PS, or -3 for PDF */
+    const char *filename;               /* Name of TT file */
+    FILE *file;                         /* the open TT file */
+    font_type_enum  target_type;        /* 42 or 3 for PS, or -3 for PDF */
 
-    ULONG numTables;			/* number of tables present */
-    char *PostName;			/* Font's PostScript name */
-    char *FullName;			/* Font's full name */
-    char *FamilyName;			/* Font's family name */
-    char *Style;			/* Font's style string */
-    char *Copyright;			/* Font's copyright string */
-    char *Version;			/* Font's version string */
-    char *Trademark;			/* Font's trademark string */
-    int llx,lly,urx,ury;		/* bounding box */
+    ULONG numTables;                    /* number of tables present */
+    char *PostName;                     /* Font's PostScript name */
+    char *FullName;                     /* Font's full name */
+    char *FamilyName;                   /* Font's family name */
+    char *Style;                        /* Font's style string */
+    char *Copyright;                    /* Font's copyright string */
+    char *Version;                      /* Font's version string */
+    char *Trademark;                    /* Font's trademark string */
+    int llx,lly,urx,ury;                /* bounding box */
 
-    Fixed TTVersion;			/* Truetype version number from offset table */
-    Fixed MfrRevision;			/* Revision number of this font */
+    Fixed TTVersion;                    /* Truetype version number from offset table */
+    Fixed MfrRevision;                  /* Revision number of this font */
 
-    BYTE *offset_table; 		/* Offset table in memory */
-    BYTE *post_table;			/* 'post' table in memory */
+    BYTE *offset_table;                 /* Offset table in memory */
+    BYTE *post_table;                   /* 'post' table in memory */
 
-    BYTE *loca_table;			/* 'loca' table in memory */
-    BYTE *glyf_table;			/* 'glyf' table in memory */
-    BYTE *hmtx_table;			/* 'hmtx' table in memory */
+    BYTE *loca_table;                   /* 'loca' table in memory */
+    BYTE *glyf_table;                   /* 'glyf' table in memory */
+    BYTE *hmtx_table;                   /* 'hmtx' table in memory */
 
     USHORT numberOfHMetrics;
-    int unitsPerEm;			/* unitsPerEm converted to int */
-    int HUPM;				/* half of above */
+    int unitsPerEm;                     /* unitsPerEm converted to int */
+    int HUPM;                           /* half of above */
 
-    int numGlyphs;			/* from 'post' table */
+    int numGlyphs;                      /* from 'post' table */
 
-    int indexToLocFormat;		/* short or long offsets */
+    int indexToLocFormat;               /* short or long offsets */
 };
 
 ULONG getULONG(BYTE *p);
diff --git a/ttconv/ttutil.cpp b/ttconv/ttutil.cpp
index e9976d5af0a5..52c3c8bf75c5 100644
--- a/ttconv/ttutil.cpp
+++ b/ttconv/ttutil.cpp
@@ -1,3 +1,5 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
 /*
  * Modified for use within matplotlib
  * 5 July 2007