diff --git a/.gitignore b/.gitignore index 23cd2f707940..40671a929598 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *~ *$ *.bak +*.kdev4 .project .pydevproject @@ -34,6 +35,7 @@ dist # OS generated files # ###################### +.directory .gdb_history .DS_Store? ehthumbs.db @@ -51,3 +53,4 @@ doc/examples doc/_templates/gallery.html doc/users/installing.rst doc/_static/matplotlibrc +lib/dateutil diff --git a/.travis.yml b/.travis.yml index 27f3008405ae..2066611a045c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,20 @@ python: - 3.3 install: - - pip -q install --use-mirrors nose numpy + - pip install -q --use-mirrors nose python-dateutil numpy pep8 + # This is a workaround to install the latest versions of pyparsing, + # which are not yet available on PyPI + - 'if [ ${TRAVIS_PYTHON_VERSION:0:1} == "3" ]; then pip -q install http://sourceforge.net/projects/pyparsing/files/pyparsing/pyparsing-2.0.0/pyparsing-2.0.0.tar.gz; fi' + - 'if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then pip -q install http://sourceforge.net/projects/pyparsing/files/pyparsing/pyparsing-1.5.7/pyparsing-1.5.7.tar.gz; fi' - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip -q install --use-mirrors PIL; fi - - sudo apt-get -qq update && sudo apt-get -qq install inkscape + - sudo apt-get update && sudo apt-get -qq install inkscape - python setup.py install script: - mkdir ../tmp_test_dir - cd ../tmp_test_dir - - python ../matplotlib/tests.py -sv + # The number of processes is hardcoded, because using too many causes the + # Travis VM to run out of memory (since so many copies of inkscape and + # ghostscript are running at the same time). + - echo Testing using 8 processes + - python ../matplotlib/tests.py -sv --processes=8 --process-timeout=300 diff --git a/CHANGELOG b/CHANGELOG index 8e17358c5407..8d2c91c224cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,55 @@ +2013-05-18 Added support for arbitrary rasterization resolutions to the + SVG backend. Previously the resolution was hard coded to 72 + dpi. Now the backend class takes a image_dpi argument for + its constructor, adjusts the image bounding box accordingly + and forwards a magnification factor to the image renderer. + The code and results now resemble those of the PDF backend. + - MW + +2013-05-08 Changed behavior of hist when given stacked=True and normed=True. + Histograms are now stacked first, then the sum is normalized. + Previously, each histogram was normalized, then they were stacked. + +2013-04-25 Changed all instances of: + + from matplotlib import MatplotlibDeprecationWarning as mplDeprecation + to: + + from cbook import mplDeprecation + + and removed the import into the matplotlib namespace in __init__.py + Thomas Caswell + + +2013-04-15 Added 'axes.xmargin' and 'axes.ymargin' to rpParams to set default + margins on auto-scaleing. - TAC + +2013-04-16 Added patheffect support for Line2D objects. -JJL + +2013-03-19 Added support for passing `linestyle` kwarg to `step` so all `plot` + kwargs are passed to the underlying `plot` call. -TAC + +2013-02-25 Added classes CubicTriInterpolator, UniformTriRefiner, TriAnalyzer + to matplotlib.tri module. - GBy + +2013-01-23 Add 'savefig.directory' to rcParams to remember and fill in the last + directory saved to for figure save dialogs - Martin Spacek + +2013-01-13 Add eventplot method to axes and pyplot and EventCollection class + to collections. + +2013-01-08 Added two extra titles to axes which are flush with the left and + right edges of the plot respectively. + Andrew Dawson + +2013-01-07 Add framealpha keyword argument to legend - PO + +2013-01-16 Till Stensitzki added a baseline feature to stackplot + +2012-12-22 Added classes for interpolation within triangular grids + (LinearTriInterpolator) and to find the triangles in which points + lie (TrapezoidMapTriFinder) to matplotlib.tri module. - IMT + 2012-12-05 Added MatplotlibDeprecationWarning class for signaling deprecation. Matplotlib developers can use this class as follows: @@ -8,6 +60,42 @@ for the signaling of deprecation, but via UserWarnings which are not ignored by default. - PI +2012-11-27 Added the *mtext* parameter for supplying matplotlib.text.Text + instances to RendererBase.draw_tex and RendererBase.draw_text. + This allows backends to utilize additional text attributes, like + the alignment of text elements. - pwuertz + +2012-11-26 deprecate matplotlib/mpl.py, which was used only in pylab.py and is + now replaced by the more suitable `import matplotlib as mpl`. - PI + +2012-11-25 Make rc_context available via pyplot interface - PI + +2012-11-16 plt.set_cmap no longer throws errors if there is not already + an active colorable artist, such as an image, and just sets + up the colormap to use from that point forward. - PI + +2012-11-16 Added the funcction _get_rbga_face, which is identical to + _get_rbg_face except it return a (r,g,b,a) tuble, to line2D. + Modified Line2D.draw to use _get_rbga_face to get the markerface + color so that any alpha set by markerfacecolor will respected. + - Thomas Caswell + +2012-11-13 Add a symmetric log normalization class to colors.py. + Also added some tests for the normalization class. + Till Stensitzki + +2012-11-12 Make axes.stem take at least one argument. + Uses a default range(n) when the first arg not provided. + Damon McDougall + +2012-11-09 Make plt.subplot() without arguments act as subplot(111) - PI + +2012-11-08 Replaced plt.figure and plt.subplot calls by the newer, more + convenient single call to plt.subplots() in the documentation + examples - PI + +2012-10-05 Add support for saving animations as animated GIFs. - JVDP + 2012-08-11 Fix path-closing bug in patches.Polygon, so that regardless of whether the path is the initial one or was subsequently set by set_xy(), get_xy() will return a closed path if and @@ -980,7 +1068,7 @@ 2009-02-02 Change default resolution on polar plot to 1 - MGD 2009-02-02 Avoid malloc errors in ttconv for fonts that don't have - e.g. PostName (a version of Tahoma triggered this) - JKS + e.g., PostName (a version of Tahoma triggered this) - JKS 2009-01-30 Remove support for pyExcelerator in exceltools -- use xlwt instead - JDH @@ -1054,7 +1142,7 @@ (slanting and extending). - JKS 2008-12-29 Fix a bug in pdf usetex support, which occurred if the same - Type-1 font was used with different encodings, e.g. with + Type-1 font was used with different encodings, e.g., with Minion Pro and MnSymbol. - JKS 2008-12-20 fix the dpi-dependent offset of Shadow. - JJL @@ -1153,7 +1241,7 @@ 2008-12-08 Some of the changes Michael made to improve the output of the property tables in the rest docs broke of made - difficult to use some of the interactive doc helpers, eg + difficult to use some of the interactive doc helpers, e.g., setp and getp. Having all the rest markup in the ipython shell also confused the docstrings. I added a new rc param docstring.harcopy, to format the docstrings differently for @@ -1177,7 +1265,7 @@ 2008-12-05 Fixed a bug that the handlelength of the new legend class set too short when numpoints=1 -JJL -2008-12-04 Added support for data with units (e.g. dates) to +2008-12-04 Added support for data with units (e.g., dates) to Axes.fill_between. -RM 2008-12-04 Added fancybox keyword to legend. Also applied some changes @@ -1258,7 +1346,7 @@ Tollerud and Jae-Joon Lee. - MM 2008-10-11 Fixed bug in pdf backend: if you pass a file object for - output instead of a filename, e.g. in a wep app, we now + output instead of a filename, e.g., in a wep app, we now flush the object at the end. - JKS 2008-10-08 Add path simplification support to paths with gaps. - EF @@ -1471,7 +1559,7 @@ 2008-06-20 Added set/get_closed method to Polygon; fixes error in hist - MM -2008-06-19 Use relative font sizes (e.g. 'medium' and 'large') in +2008-06-19 Use relative font sizes (e.g., 'medium' and 'large') in rcsetup.py and matplotlibrc.template so that text will be scaled by default when changing rcParams['font.size'] - EF @@ -2103,8 +2191,8 @@ 2007-07-31 Refactoring of distutils scripts. - Will not fail on the entire build if an optional Python - package (e.g. Tkinter) is installed but its development - headers are not (e.g. tk-devel). Instead, it will + package (e.g., Tkinter) is installed but its development + headers are not (e.g., tk-devel). Instead, it will continue to build all other extensions. - Provide an overview at the top of the output to display what dependencies and their versions were found, and (by @@ -2136,7 +2224,7 @@ should be changed to ${\cal R}$. Alternatively, you may use the new LaTeX-style font commands (\mathcal, \mathrm, \mathit, \mathtt) which do affect the following group, - eg. $\mathcal{R}$. + e.g., $\mathcal{R}$. Other new features include: @@ -2146,10 +2234,10 @@ - Sub/superscripts are less likely to accidentally overlap. - - Support for sub/superscripts in either order, eg. $x^i_j$ + - Support for sub/superscripts in either order, e.g., $x^i_j$ and $x_j^i$ are equivalent. - - Double sub/superscripts (eg. $x_i_j$) are considered + - Double sub/superscripts (e.g., $x_i_j$) are considered ambiguous and raise an exception. Use braces to disambiguate. - $\frac{x}{y}$ can be used for displaying fractions. @@ -2412,7 +2500,7 @@ color-setting operations in the pdf backend. The idea is that you include the resulting file in another program and set the colors (both stroke and fill color) there, so you - can use the same pdf file for e.g. a paper and a + can use the same pdf file for e.g., a paper and a presentation and have them in the surrounding color. You will probably not want to draw figure and axis frames in that case, since they would be filled in the same color. - JKS @@ -2501,7 +2589,7 @@ frameowrk. Artists will define their own pick method with a configurable epsilon tolerance and return pick attrs. All artists that meet the tolerance threshold will fire a - PickEvent with artist dependent attrs; eg, a Line2D can set + PickEvent with artist dependent attrs; e.g., a Line2D can set the indices attribute that shows the indices into the line that are within epsilon of the pick point. See examples/pick_event_demo.py. The implementation of pick @@ -2611,7 +2699,7 @@ 2006-11-19 Added semi-automatic docstring generation detailing all the kwargs that functions take using the artist introspection - tools; eg 'help text now details the scatter kwargs + tools; e.g., 'help text now details the scatter kwargs that control the Text properties - JDH 2006-11-17 Removed obsolete scatter_classic, leaving a stub to @@ -2901,7 +2989,7 @@ 2006-06-16 Added a pointer to parent in figure canvas so you can access the container with fig.canvas.manager. Useful if - you want to set the window title, eg in gtk + you want to set the window title, e.g., in gtk fig.canvas.manager.window.set_title, though a GUI neutral method would be preferable JDH @@ -3370,7 +3458,7 @@ 2005-12-03 Modified scipy patch to support Numeric, scipy and numarray Some work remains to be done because some of the scipy - imports are broken if only the core is installed. Eg + imports are broken if only the core is installed. e.g., apparently we need from scipy.basic.fftpack import * rather than from scipy.fftpack import * @@ -3619,7 +3707,7 @@ 2005-07-06 Made HOME/.matplotlib the new config dir where the matplotlibrc file, the ttf.cache, and the tex.cache live. The new default filenames in .matplotlib have no leading - dot and are not hidden. Eg, the new names are matplotlibrc + dot and are not hidden. e.g., the new names are matplotlibrc tex.cache ttffont.cache. This is how ipython does it so it must be right. If old files are found, a warning is issued and they are moved to the new location. Also fixed @@ -3893,7 +3981,7 @@ 2005-04-11 Applied a variant of rick's xlim/ylim/axis patch. These functions now take kwargs to let you selectively alter only - the min or max if desired. Eg xlim(xmin=2) or + the min or max if desired. e.g., xlim(xmin=2) or axis(ymax=3). They always return the new lim. - JDH @@ -4022,7 +4110,7 @@ 2005-02-23 Added rc param ps.useafm so backend ps can use native afm fonts or truetype. afme breaks mathtext but causes much smaller font sizes and may result in images that display - better in some contexts (eg pdfs incorporated into latex + better in some contexts (e.g., pdfs incorporated into latex docs viewed in acrobat reader). I would like to extend this approach to allow the user to use truetype only for mathtext, which should be easy. @@ -4150,9 +4238,9 @@ 2005-01-18 Added accents to mathtext: \hat, \breve, \grave, \bar, \acute, \tilde, \vec, \dot, \ddot. All of them have the - same syntax, eg to make an overbar you do \bar{o} or to + same syntax, e.g., to make an overbar you do \bar{o} or to make an o umlaut you do \ddot{o}. The shortcuts are also - provided, eg: \"o \'e \`e \~n \.x \^y - JDH + provided, e.g., \"o \'e \`e \~n \.x \^y - JDH 2005-01-18 Plugged image resize memory leaks - JDH @@ -4319,7 +4407,7 @@ 2004-12-04 Fixed some legend bugs JDH -2004-11-30 Added over command for oneoff over plots. Eg over(plot, x, +2004-11-30 Added over command for oneoff over plots. e.g., over(plot, x, y, lw=2). Works with any plot function. 2004-11-30 Added bbox property to text - JDH @@ -4495,7 +4583,7 @@ 2004-09-17 Added coords formatter attributes. These must be callable, and return a string for the x or y data. These will be used to format the x and y data for the coords box. Default is - the axis major formatter. Eg + the axis major formatter. e.g.: # format the coords message box def price(x): return '$%1.2f'%x diff --git a/CXX/IndirectPythonInterface.cxx b/CXX/IndirectPythonInterface.cxx index 7286cdf65737..256bd7ebda80 100644 --- a/CXX/IndirectPythonInterface.cxx +++ b/CXX/IndirectPythonInterface.cxx @@ -34,10 +34,524 @@ // DAMAGE. // //----------------------------------------------------------------------------- -#include "CXX/WrapPython.h" +#include "CXX/IndirectPythonInterface.hxx" + +namespace Py +{ +bool _CFunction_Check( PyObject *op ) { return op->ob_type == _CFunction_Type(); } +bool _Complex_Check( PyObject *op ) { return op->ob_type == _Complex_Type(); } +bool _Dict_Check( PyObject *op ) { return op->ob_type == _Dict_Type(); } +bool _Float_Check( PyObject *op ) { return op->ob_type == _Float_Type(); } +bool _Function_Check( PyObject *op ) { return op->ob_type == _Function_Type(); } +bool _Boolean_Check( PyObject *op ) { return op->ob_type == _Bool_Type(); } +bool _List_Check( PyObject *op ) { return op->ob_type == _List_Type(); } +bool _Long_Check( PyObject *op ) { return op->ob_type == _Long_Type(); } +bool _Method_Check( PyObject *op ) { return op->ob_type == _Method_Type(); } +bool _Module_Check( PyObject *op ) { return op->ob_type == _Module_Type(); } +bool _Range_Check( PyObject *op ) { return op->ob_type == _Range_Type(); } +bool _Slice_Check( PyObject *op ) { return op->ob_type == _Slice_Type(); } +bool _TraceBack_Check( PyObject *op ) { return op->ob_type == _TraceBack_Type(); } +bool _Tuple_Check( PyObject *op ) { return op->ob_type == _Tuple_Type(); } +bool _Type_Check( PyObject *op ) { return op->ob_type == _Type_Type(); } +bool _Unicode_Check( PyObject *op ) { return op->ob_type == _Unicode_Type(); } #if PY_MAJOR_VERSION == 2 -#include "Python2/IndirectPythonInterface.cxx" +bool _String_Check( PyObject *op ) { return op->ob_type == _String_Type(); } +bool _Int_Check( PyObject *op ) { return op->ob_type == _Int_Type(); } +bool _CObject_Check( PyObject *op ) { return op->ob_type == _CObject_Type(); } +#endif +#if PY_MAJOR_VERSION >= 3 +bool _Bytes_Check( PyObject *op ) { return op->ob_type == _Bytes_Type(); } +#endif + +#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) + +#if defined(MS_WINDOWS) +#include + + +static HMODULE python_dll; + +static PyObject *ptr__Exc_ArithmeticError = NULL; +static PyObject *ptr__Exc_AssertionError = NULL; +static PyObject *ptr__Exc_AttributeError = NULL; +static PyObject *ptr__Exc_EnvironmentError = NULL; +static PyObject *ptr__Exc_EOFError = NULL; +static PyObject *ptr__Exc_Exception = NULL; +static PyObject *ptr__Exc_FloatingPointError = NULL; +static PyObject *ptr__Exc_ImportError = NULL; +static PyObject *ptr__Exc_IndexError = NULL; +static PyObject *ptr__Exc_IOError = NULL; +static PyObject *ptr__Exc_KeyboardInterrupt = NULL; +static PyObject *ptr__Exc_KeyError = NULL; +static PyObject *ptr__Exc_LookupError = NULL; +static PyObject *ptr__Exc_MemoryError = NULL; +static PyObject *ptr__Exc_NameError = NULL; +static PyObject *ptr__Exc_NotImplementedError = NULL; +static PyObject *ptr__Exc_OSError = NULL; +static PyObject *ptr__Exc_OverflowError = NULL; +static PyObject *ptr__Exc_RuntimeError = NULL; +static PyObject *ptr__Exc_StandardError = NULL; +static PyObject *ptr__Exc_SyntaxError = NULL; +static PyObject *ptr__Exc_SystemError = NULL; +static PyObject *ptr__Exc_SystemExit = NULL; +static PyObject *ptr__Exc_TypeError = NULL; +static PyObject *ptr__Exc_ValueError = NULL; +static PyObject *ptr__Exc_ZeroDivisionError = NULL; + +#ifdef MS_WINDOWS +static PyObject *ptr__Exc_WindowsError = NULL; +#endif + +static PyObject *ptr__Exc_IndentationError = NULL; +static PyObject *ptr__Exc_TabError = NULL; +static PyObject *ptr__Exc_UnboundLocalError = NULL; +static PyObject *ptr__Exc_UnicodeError = NULL; +static PyObject *ptr__PyNone = NULL; +static PyObject *ptr__PyFalse = NULL; +static PyObject *ptr__PyTrue = NULL; +static PyTypeObject *ptr__CFunction_Type = NULL; +static PyTypeObject *ptr__Complex_Type = NULL; +static PyTypeObject *ptr__Dict_Type = NULL; +static PyTypeObject *ptr__Float_Type = NULL; +static PyTypeObject *ptr__Function_Type = NULL; +static PyTypeObject *ptr__Bool_Type = NULL; +static PyTypeObject *ptr__List_Type = NULL; +static PyTypeObject *ptr__Long_Type = NULL; +static PyTypeObject *ptr__Method_Type = NULL; +static PyTypeObject *ptr__Module_Type = NULL; +static PyTypeObject *ptr__Range_Type = NULL; +static PyTypeObject *ptr__Slice_Type = NULL; +static PyTypeObject *ptr__TraceBack_Type = NULL; +static PyTypeObject *ptr__Tuple_Type = NULL; +static PyTypeObject *ptr__Type_Type = NULL; +#if PY_MAJOR_VERSION == 2 +static PyTypeObject *ptr__Int_Type = NULL; +static PyTypeObject *ptr__String_Type = NULL; +static PyTypeObject *ptr__CObject_Type = NULL; +#endif +#if PY_MAJOR_VERSION >= 3 +static PyTypeObject *ptr__Bytes_Type = NULL; +#endif + + +static int *ptr_Py_DebugFlag = NULL; +static int *ptr_Py_InteractiveFlag = NULL; +static int *ptr_Py_OptimizeFlag = NULL; +static int *ptr_Py_NoSiteFlag = NULL; +static int *ptr_Py_VerboseFlag = NULL; + +static char **ptr__Py_PackageContext = NULL; + +#ifdef Py_REF_DEBUG +int *ptr_Py_RefTotal; +#endif + + +//-------------------------------------------------------------------------------- +class GetAddressException +{ +public: + GetAddressException( const char *_name ) + : name( _name ) + {} + virtual ~GetAddressException() {} + const char *name; +}; + + +//-------------------------------------------------------------------------------- +static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyObject **)addr; +} + +static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyObject *)addr; +} + +static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyTypeObject **)addr; +} + +static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyTypeObject *)addr; +} + +static int *GetInt_as_IntPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (int *)addr; +} + +static char **GetCharPointer_as_CharPointerPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (char **)addr; +} + + +#ifdef _DEBUG +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; #else -#include "Python3/IndirectPythonInterface.cxx" +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; +#endif + +//-------------------------------------------------------------------------------- +bool InitialisePythonIndirectInterface() +{ + char python_dll_name[sizeof(python_dll_name_format)]; + + _snprintf( python_dll_name, sizeof(python_dll_name_format) / sizeof(char) - 1, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); + + python_dll = LoadLibraryA( python_dll_name ); + if( python_dll == NULL ) + return false; + + try + { +#ifdef Py_REF_DEBUG + ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); +#endif + ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); + ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); + ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); + ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); + ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); + ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); + + ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); + ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); + ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); + ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); + ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); + ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); + ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); + ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); + ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); + ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); + ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); + ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); + ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); + ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); + ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); + ptr__Exc_NotImplementedError= GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); + ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); + ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); + ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); + ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); + ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); + ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); + ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); + ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); + ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); +#ifdef MS_WINDOWS + ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); +#endif + ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); + ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); + ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); + ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); + ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); + ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); + + ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); + ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); + + ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); + ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); + ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); + ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); + ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); + ptr__Bool_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBool_Type" ); + ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); + ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); + ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); + ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); + ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); + ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); + ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); + ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); + ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); + ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); +#if PY_MAJOR_VERSION == 2 + ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); + ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); + ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); +#endif +#if PY_MAJOR_VERSION >= 3 + ptr__Bytes_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBytes_Type" ); +#endif + } + catch( GetAddressException &e ) + { + OutputDebugStringA( python_dll_name ); + OutputDebugStringA( " does not contain symbol " ); + OutputDebugStringA( e.name ); + OutputDebugStringA( "\n" ); + + return false; + } + + return true; +} + +// +// Wrap variables as function calls +// +PyObject *_Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } +PyObject *_Exc_AssertionError() { return ptr__Exc_AssertionError; } +PyObject *_Exc_AttributeError() { return ptr__Exc_AttributeError; } +PyObject *_Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } +PyObject *_Exc_EOFError() { return ptr__Exc_EOFError; } +PyObject *_Exc_Exception() { return ptr__Exc_Exception; } +PyObject *_Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } +PyObject *_Exc_ImportError() { return ptr__Exc_ImportError; } +PyObject *_Exc_IndexError() { return ptr__Exc_IndexError; } +PyObject *_Exc_IOError() { return ptr__Exc_IOError; } +PyObject *_Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } +PyObject *_Exc_KeyError() { return ptr__Exc_KeyError; } +PyObject *_Exc_LookupError() { return ptr__Exc_LookupError; } +PyObject *_Exc_MemoryError() { return ptr__Exc_MemoryError; } +PyObject *_Exc_NameError() { return ptr__Exc_NameError; } +PyObject *_Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } +PyObject *_Exc_OSError() { return ptr__Exc_OSError; } +PyObject *_Exc_OverflowError() { return ptr__Exc_OverflowError; } +PyObject *_Exc_RuntimeError() { return ptr__Exc_RuntimeError; } +PyObject *_Exc_StandardError() { return ptr__Exc_StandardError; } +PyObject *_Exc_SyntaxError() { return ptr__Exc_SyntaxError; } +PyObject *_Exc_SystemError() { return ptr__Exc_SystemError; } +PyObject *_Exc_SystemExit() { return ptr__Exc_SystemExit; } +PyObject *_Exc_TypeError() { return ptr__Exc_TypeError; } +PyObject *_Exc_ValueError() { return ptr__Exc_ValueError; } +#ifdef MS_WINDOWS +PyObject *_Exc_WindowsError() { return ptr__Exc_WindowsError; } +#endif +PyObject *_Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } +PyObject *_Exc_IndentationError() { return ptr__Exc_IndentationError; } +PyObject *_Exc_TabError() { return ptr__Exc_TabError; } +PyObject *_Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } +PyObject *_Exc_UnicodeError() { return ptr__Exc_UnicodeError; } + +// +// wrap items in Object.h +// +PyObject *_None() { return ptr__PyNone; } + +PyObject *_False() { return ptr__PyFalse; } +PyObject *_True() { return ptr__PyTrue; } + +PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } +PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } +PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } +PyTypeObject *_Float_Type() { return ptr__Float_Type; } +PyTypeObject *_Function_Type() { return ptr__Function_Type; } +PyTypeObject *_Bool_Type() { return ptr__Bool_Type; } +PyTypeObject *_List_Type() { return ptr__List_Type; } +PyTypeObject *_Long_Type() { return ptr__Long_Type; } +PyTypeObject *_Method_Type() { return ptr__Method_Type; } +PyTypeObject *_Module_Type() { return ptr__Module_Type; } +PyTypeObject *_Range_Type() { return ptr__Range_Type; } +PyTypeObject *_Slice_Type() { return ptr__Slice_Type; } +PyTypeObject *_TraceBack_Type() { return ptr__TraceBack_Type; } +PyTypeObject *_Tuple_Type() { return ptr__Tuple_Type; } +PyTypeObject *_Type_Type() { return ptr__Type_Type; } +PyTypeObject *_Unicode_Type() { return ptr__Unicode_Type; } +#if PY_MAJOR_VERSION == 2 +PyTypeObject *_String_Type() { return ptr__String_Type; } +PyTypeObject *_Int_Type() { return ptr__Int_Type; } +PyTypeObject *_CObject_Type() { return ptr__CObject_Type; } +#endif +#if PY_MAJOR_VERSION >= 3 +PyTypeObject *_Bytes_Type() { return ptr__Bytes_Type; } +#endif + +char *__Py_PackageContext() { return *ptr__Py_PackageContext; } + + +// +// wrap the Python Flag variables +// +int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } +int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } +int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } + +#if 0 +#define Py_INCREF(op) ( \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + ((PyObject*)(op))->ob_refcnt++) + +#define Py_DECREF(op) \ + if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ + --((PyObject*)(op))->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(op) \ + else \ + _Py_Dealloc((PyObject *)(op)) +#endif + +void _XINCREF( PyObject *op ) +{ + // This function must match the contents of Py_XINCREF(op) + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)++; +#endif + (op)->ob_refcnt++; + +} + +void _XDECREF( PyObject *op ) +{ + // This function must match the contents of Py_XDECREF(op); + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)--; +#endif + + if (--(op)->ob_refcnt == 0) + _Py_Dealloc((PyObject *)(op)); +} + + +#else +#error "Can only delay load under Win32" +#endif + +#else + +//================================================================================ +// +// Map onto Macros +// +//================================================================================ + +// +// Wrap variables as function calls +// + +PyObject *_Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } +PyObject *_Exc_AssertionError() { return ::PyExc_AssertionError; } +PyObject *_Exc_AttributeError() { return ::PyExc_AttributeError; } +PyObject *_Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } +PyObject *_Exc_EOFError() { return ::PyExc_EOFError; } +PyObject *_Exc_Exception() { return ::PyExc_Exception; } +PyObject *_Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } +PyObject *_Exc_ImportError() { return ::PyExc_ImportError; } +PyObject *_Exc_IndexError() { return ::PyExc_IndexError; } +PyObject *_Exc_IOError() { return ::PyExc_IOError; } +PyObject *_Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } +PyObject *_Exc_KeyError() { return ::PyExc_KeyError; } +PyObject *_Exc_LookupError() { return ::PyExc_LookupError; } +PyObject *_Exc_MemoryError() { return ::PyExc_MemoryError; } +PyObject *_Exc_NameError() { return ::PyExc_NameError; } +PyObject *_Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } +PyObject *_Exc_OSError() { return ::PyExc_OSError; } +PyObject *_Exc_OverflowError() { return ::PyExc_OverflowError; } +PyObject *_Exc_RuntimeError() { return ::PyExc_RuntimeError; } +PyObject *_Exc_SyntaxError() { return ::PyExc_SyntaxError; } +PyObject *_Exc_SystemError() { return ::PyExc_SystemError; } +PyObject *_Exc_SystemExit() { return ::PyExc_SystemExit; } +PyObject *_Exc_TypeError() { return ::PyExc_TypeError; } +PyObject *_Exc_ValueError() { return ::PyExc_ValueError; } +PyObject *_Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } +PyObject *_Exc_IndentationError() { return ::PyExc_IndentationError; } +PyObject *_Exc_TabError() { return ::PyExc_TabError; } +PyObject *_Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } +PyObject *_Exc_UnicodeError() { return ::PyExc_UnicodeError; } + +#ifdef MS_WINDOWS +PyObject *_Exc_WindowsError() { return ::PyExc_WindowsError; } +#endif + + + + +// +// wrap items in Object.h +// +PyObject *_None() { return &::_Py_NoneStruct; } + +PyObject *_False() { return Py_False; } +PyObject *_True() { return Py_True; } + +PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } +PyTypeObject *_Complex_Type() { return &PyComplex_Type; } +PyTypeObject *_Dict_Type() { return &PyDict_Type; } +PyTypeObject *_Float_Type() { return &PyFloat_Type; } +PyTypeObject *_Function_Type() { return &PyFunction_Type; } +PyTypeObject *_Bool_Type() { return &PyBool_Type; } +PyTypeObject *_List_Type() { return &PyList_Type; } +PyTypeObject *_Long_Type() { return &PyLong_Type; } +PyTypeObject *_Method_Type() { return &PyMethod_Type; } +PyTypeObject *_Module_Type() { return &PyModule_Type; } +PyTypeObject *_Range_Type() { return &PyRange_Type; } +PyTypeObject *_Slice_Type() { return &PySlice_Type; } +PyTypeObject *_TraceBack_Type() { return &PyTraceBack_Type; } +PyTypeObject *_Tuple_Type() { return &PyTuple_Type; } +PyTypeObject *_Type_Type() { return &PyType_Type; } +PyTypeObject *_Unicode_Type() { return &PyUnicode_Type; } +#if PY_MAJOR_VERSION == 2 +PyTypeObject *_String_Type() { return &PyString_Type; } +PyTypeObject *_Int_Type() { return &PyInt_Type; } +PyTypeObject *_CObject_Type() { return &PyCObject_Type; } +#endif +#if PY_MAJOR_VERSION >= 3 +PyTypeObject *_Bytes_Type() { return &PyBytes_Type; } +#endif + +// +// wrap flags +// +int &_Py_DebugFlag() { return Py_DebugFlag; } +int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } +int &_Py_VerboseFlag() { return Py_VerboseFlag; } +char *__Py_PackageContext() { return _Py_PackageContext; } + +// +// Needed to keep the abstactions for delayload interface +// +void _XINCREF( PyObject *op ) +{ + Py_XINCREF( op ); +} + +void _XDECREF( PyObject *op ) +{ + Py_XDECREF( op ); +} + #endif +} diff --git a/CXX/Python2/ExtensionModule.hxx b/CXX/Python2/ExtensionModule.hxx index dde3ec6f854b..3eb436d00048 100644 --- a/CXX/Python2/ExtensionModule.hxx +++ b/CXX/Python2/ExtensionModule.hxx @@ -66,9 +66,6 @@ namespace Py const std::string m_module_name; const std::string m_full_module_name; MethodTable m_method_table; -#if PY3 - PyModuleDef m_module_def; -#endif PyObject *m_module; private: @@ -136,19 +133,11 @@ namespace Py { MethodDefExt *method_def = (*i).second; - #if PY_VERSION_HEX < 0x02070000 - static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); - #else - static PyObject *self = PyCapsule_New( this, NULL, NULL ); - #endif + static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); Tuple args( 2 ); - args[0] = Object( self ); - #if PY_VERSION_HEX < 0x02070000 - args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) ); - #else - args[1] = Object( PyCapsule_New( method_def, NULL, NULL ) ); - #endif + args[0] = Object( self, true ); + args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); PyObject *func = PyCFunction_New ( diff --git a/CXX/Python2/ExtensionOldType.hxx b/CXX/Python2/ExtensionOldType.hxx index 9702b00e7455..cfd2fbe6a578 100644 --- a/CXX/Python2/ExtensionOldType.hxx +++ b/CXX/Python2/ExtensionOldType.hxx @@ -178,11 +178,8 @@ namespace Py Tuple self( 2 ); self[0] = Object( this ); - #if PY_VERSION_HEX < 0x02070000 - self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); - #else - self[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); - #endif + self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); + PyObject *func = PyCFunction_New( &method_def->ext_meth_def, self.ptr() ); return Object(func, true); @@ -238,12 +235,8 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - #if PY_VERSION_HEX < 0x02070000 - void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); - #else - void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); - #endif - MethodDefExt *meth_def = reinterpret_cast *>( capsule ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Object result; // Adding try & catch in case of STL debug-mode exceptions. @@ -278,12 +271,8 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - #if PY_VERSION_HEX < 0x02070000 - void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); - #else - void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); - #endif - MethodDefExt *meth_def = reinterpret_cast *>( capsule ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Tuple args( _args ); Object result; @@ -319,12 +308,8 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - #if PY_VERSION_HEX < 0x02070000 - void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); - #else - void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); - #endif - MethodDefExt *meth_def = reinterpret_cast *>( capsule ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Tuple args( _args ); diff --git a/CXX/Python2/ExtensionTypeBase.hxx b/CXX/Python2/ExtensionTypeBase.hxx index ad11029e71dc..1dfe4243619a 100644 --- a/CXX/Python2/ExtensionTypeBase.hxx +++ b/CXX/Python2/ExtensionTypeBase.hxx @@ -70,9 +70,7 @@ namespace Py virtual void reinit( Tuple &args, Dict &kwds ); // object basics -#if defined( PYCXX_PYTHON_2TO3 ) || !defined( PY3 ) virtual int print( FILE *, int ); -#endif virtual Object getattr( const char * ); virtual int setattr( const char *, const Object & ); virtual Object getattro( const String & ); diff --git a/CXX/Python2/IndirectPythonInterface.cxx b/CXX/Python2/IndirectPythonInterface.cxx deleted file mode 100644 index 203f3f9170ff..000000000000 --- a/CXX/Python2/IndirectPythonInterface.cxx +++ /dev/null @@ -1,607 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#include "CXX/IndirectPythonInterface.hxx" - -namespace Py -{ -bool _Buffer_Check( PyObject *op ) { return (op)->ob_type == _Buffer_Type(); } -bool _CFunction_Check( PyObject *op ) { return (op)->ob_type == _CFunction_Type(); } -bool _Class_Check( PyObject *op ) { return (op)->ob_type == _Class_Type(); } -#if PY_VERSION_HEX < 0x02070000 -bool _CObject_Check( PyObject *op ) { return (op)->ob_type == _CObject_Type(); } -#endif -bool _Complex_Check( PyObject *op ) { return (op)->ob_type == _Complex_Type(); } -bool _Dict_Check( PyObject *op ) { return (op)->ob_type == _Dict_Type(); } -bool _File_Check( PyObject *op ) { return (op)->ob_type == _File_Type(); } -bool _Float_Check( PyObject *op ) { return (op)->ob_type == _Float_Type(); } -bool _Function_Check( PyObject *op ) { return (op)->ob_type == _Function_Type(); } -bool _Instance_Check( PyObject *op ) { return (op)->ob_type == _Instance_Type(); } -bool _Boolean_Check( PyObject *op ) { return (op)->ob_type == _Bool_Type(); } -bool _Int_Check( PyObject *op ) { return (op)->ob_type == _Int_Type(); } -bool _List_Check( PyObject *o ) { return o->ob_type == _List_Type(); } -bool _Long_Check( PyObject *op ) { return (op)->ob_type == _Long_Type(); } -bool _Method_Check( PyObject *op ) { return (op)->ob_type == _Method_Type(); } -bool _Module_Check( PyObject *op ) { return (op)->ob_type == _Module_Type(); } -bool _Range_Check( PyObject *op ) { return (op)->ob_type == _Range_Type(); } -bool _Slice_Check( PyObject *op ) { return (op)->ob_type == _Slice_Type(); } -bool _String_Check( PyObject *o ) { return o->ob_type == _String_Type(); } -bool _TraceBack_Check( PyObject *v ) { return (v)->ob_type == _TraceBack_Type(); } -bool _Tuple_Check( PyObject *op ) { return (op)->ob_type == _Tuple_Type(); } -bool _Type_Check( PyObject *op ) { return (op)->ob_type == _Type_Type(); } - -#if PY_MAJOR_VERSION >= 2 -bool _Unicode_Check( PyObject *op ) { return (op)->ob_type == _Unicode_Type(); } -#endif - - - -#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) - -#if defined(MS_WINDOWS) -#include - - -static HMODULE python_dll; - -static PyObject *ptr__Exc_ArithmeticError = NULL; -static PyObject *ptr__Exc_AssertionError = NULL; -static PyObject *ptr__Exc_AttributeError = NULL; -static PyObject *ptr__Exc_EnvironmentError = NULL; -static PyObject *ptr__Exc_EOFError = NULL; -static PyObject *ptr__Exc_Exception = NULL; -static PyObject *ptr__Exc_FloatingPointError = NULL; -static PyObject *ptr__Exc_ImportError = NULL; -static PyObject *ptr__Exc_IndexError = NULL; -static PyObject *ptr__Exc_IOError = NULL; -static PyObject *ptr__Exc_KeyboardInterrupt = NULL; -static PyObject *ptr__Exc_KeyError = NULL; -static PyObject *ptr__Exc_LookupError = NULL; -static PyObject *ptr__Exc_MemoryError = NULL; -static PyObject *ptr__Exc_MemoryErrorInst = NULL; -static PyObject *ptr__Exc_NameError = NULL; -static PyObject *ptr__Exc_NotImplementedError = NULL; -static PyObject *ptr__Exc_OSError = NULL; -static PyObject *ptr__Exc_OverflowError = NULL; -static PyObject *ptr__Exc_RuntimeError = NULL; -static PyObject *ptr__Exc_StandardError = NULL; -static PyObject *ptr__Exc_SyntaxError = NULL; -static PyObject *ptr__Exc_SystemError = NULL; -static PyObject *ptr__Exc_SystemExit = NULL; -static PyObject *ptr__Exc_TypeError = NULL; -static PyObject *ptr__Exc_ValueError = NULL; -static PyObject *ptr__Exc_ZeroDivisionError = NULL; - -#ifdef MS_WINDOWS -static PyObject *ptr__Exc_WindowsError = NULL; -#endif - -#if PY_MAJOR_VERSION >= 2 -static PyObject *ptr__Exc_IndentationError = NULL; -static PyObject *ptr__Exc_TabError = NULL; -static PyObject *ptr__Exc_UnboundLocalError = NULL; -static PyObject *ptr__Exc_UnicodeError = NULL; -#endif - -static PyObject *ptr__PyNone = NULL; - -static PyObject *ptr__PyFalse = NULL; -static PyObject *ptr__PyTrue = NULL; - -static PyTypeObject *ptr__Buffer_Type = NULL; -static PyTypeObject *ptr__CFunction_Type = NULL; -static PyTypeObject *ptr__Class_Type = NULL; -#if PY_VERSION_HEX < 0x02070000 -static PyTypeObject *ptr__CObject_Type = NULL; -#endif -static PyTypeObject *ptr__Complex_Type = NULL; -static PyTypeObject *ptr__Dict_Type = NULL; -static PyTypeObject *ptr__File_Type = NULL; -static PyTypeObject *ptr__Float_Type = NULL; -static PyTypeObject *ptr__Function_Type = NULL; -static PyTypeObject *ptr__Instance_Type = NULL; -static PyTypeObject *ptr__Int_Type = NULL; -static PyTypeObject *ptr__List_Type = NULL; -static PyTypeObject *ptr__Long_Type = NULL; -static PyTypeObject *ptr__Method_Type = NULL; -static PyTypeObject *ptr__Module_Type = NULL; -static PyTypeObject *ptr__Range_Type = NULL; -static PyTypeObject *ptr__Slice_Type = NULL; -static PyTypeObject *ptr__String_Type = NULL; -static PyTypeObject *ptr__TraceBack_Type = NULL; -static PyTypeObject *ptr__Tuple_Type = NULL; -static PyTypeObject *ptr__Type_Type = NULL; - -#if PY_MAJOR_VERSION >= 2 -static PyTypeObject *ptr__Unicode_Type = NULL; -#endif - -static int *ptr_Py_DebugFlag = NULL; -static int *ptr_Py_InteractiveFlag = NULL; -static int *ptr_Py_OptimizeFlag = NULL; -static int *ptr_Py_NoSiteFlag = NULL; -static int *ptr_Py_TabcheckFlag = NULL; -static int *ptr_Py_VerboseFlag = NULL; - -#if PY_MAJOR_VERSION >= 2 -static int *ptr_Py_UnicodeFlag = NULL; -#endif - -static char **ptr__Py_PackageContext = NULL; - -#ifdef Py_REF_DEBUG -int *ptr_Py_RefTotal; -#endif - - -//-------------------------------------------------------------------------------- -class GetAddressException -{ -public: - GetAddressException( const char *_name ) - : name( _name ) - {} - virtual ~GetAddressException() {} - const char *name; -}; - - -//-------------------------------------------------------------------------------- -static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyObject **)addr; -} - -static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyObject *)addr; -} - -static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyTypeObject **)addr; -} - -static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyTypeObject *)addr; -} - -static int *GetInt_as_IntPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (int *)addr; -} - -static char **GetCharPointer_as_CharPointerPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (char **)addr; -} - - -#ifdef _DEBUG -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; -#else -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; -#endif - -//-------------------------------------------------------------------------------- -bool InitialisePythonIndirectInterface() -{ - char python_dll_name[sizeof(python_dll_name_format)]; - - sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); - - python_dll = LoadLibrary( python_dll_name ); - if( python_dll == NULL ) - return false; - - try -{ -#ifdef Py_REF_DEBUG - ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); -#endif - ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); - ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); - ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); - ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); - ptr_Py_TabcheckFlag = GetInt_as_IntPointer( "Py_TabcheckFlag" ); - ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); -#if PY_MAJOR_VERSION >= 2 - ptr_Py_UnicodeFlag = GetInt_as_IntPointer( "Py_UnicodeFlag" ); -#endif - ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); - - ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); - ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); - ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); - ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); - ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); - ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); - ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); - ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); - ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); - ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); - ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); - ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); - ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); - ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); - ptr__Exc_MemoryErrorInst = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryErrorInst" ); - ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); - ptr__Exc_NotImplementedError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); - ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); - ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); - ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); - ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); - ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); - ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); - ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); - ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); - ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); -#ifdef MS_WINDOWS - ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); -#endif - ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); - -#if PY_MAJOR_VERSION >= 2 - ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); - ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); - ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); - ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); -#endif - ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); - - ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); - ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); - - ptr__Buffer_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBuffer_Type" ); - ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); - ptr__Class_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyClass_Type" ); -#if PY_VERSION_HEX < 0x02070000 - ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); -#endif - ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); - ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); - ptr__File_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFile_Type" ); - ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); - ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); - ptr__Instance_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInstance_Type" ); - ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); - ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); - ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); - ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); - ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); - ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); - ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); - ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); - ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); - ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); - ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); - -#if PY_MAJOR_VERSION >= 2 - ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); -#endif -} - catch( GetAddressException &e ) - { - OutputDebugString( python_dll_name ); - OutputDebugString( " does not contain symbol "); - OutputDebugString( e.name ); - OutputDebugString( "\n" ); - - return false; - } - - return true; -} - -// -// Wrap variables as function calls -// -PyObject * _Exc_ArithmeticError(){ return ptr__Exc_ArithmeticError; } -PyObject * _Exc_AssertionError(){ return ptr__Exc_AssertionError; } -PyObject * _Exc_AttributeError(){ return ptr__Exc_AttributeError; } -PyObject * _Exc_EnvironmentError(){ return ptr__Exc_EnvironmentError; } -PyObject * _Exc_EOFError() { return ptr__Exc_EOFError; } -PyObject * _Exc_Exception() { return ptr__Exc_Exception; } -PyObject * _Exc_FloatingPointError(){ return ptr__Exc_FloatingPointError; } -PyObject * _Exc_ImportError() { return ptr__Exc_ImportError; } -PyObject * _Exc_IndexError() { return ptr__Exc_IndexError; } -PyObject * _Exc_IOError() { return ptr__Exc_IOError; } -PyObject * _Exc_KeyboardInterrupt(){ return ptr__Exc_KeyboardInterrupt; } -PyObject * _Exc_KeyError() { return ptr__Exc_KeyError; } -PyObject * _Exc_LookupError() { return ptr__Exc_LookupError; } -PyObject * _Exc_MemoryError() { return ptr__Exc_MemoryError; } -PyObject * _Exc_MemoryErrorInst(){ return ptr__Exc_MemoryErrorInst; } -PyObject * _Exc_NameError() { return ptr__Exc_NameError; } -PyObject * _Exc_NotImplementedError(){ return ptr__Exc_NotImplementedError; } -PyObject * _Exc_OSError() { return ptr__Exc_OSError; } -PyObject * _Exc_OverflowError() { return ptr__Exc_OverflowError; } -PyObject * _Exc_RuntimeError() { return ptr__Exc_RuntimeError; } -PyObject * _Exc_StandardError() { return ptr__Exc_StandardError; } -PyObject * _Exc_SyntaxError() { return ptr__Exc_SyntaxError; } -PyObject * _Exc_SystemError() { return ptr__Exc_SystemError; } -PyObject * _Exc_SystemExit() { return ptr__Exc_SystemExit; } -PyObject * _Exc_TypeError() { return ptr__Exc_TypeError; } -PyObject * _Exc_ValueError() { return ptr__Exc_ValueError; } -#ifdef MS_WINDOWS -PyObject * _Exc_WindowsError() { return ptr__Exc_WindowsError; } -#endif -PyObject * _Exc_ZeroDivisionError(){ return ptr__Exc_ZeroDivisionError; } - -#if PY_MAJOR_VERSION >= 2 -PyObject * _Exc_IndentationError(){ return ptr__Exc_IndentationError; } -PyObject * _Exc_TabError() { return ptr__Exc_TabError; } -PyObject * _Exc_UnboundLocalError(){ return ptr__Exc_UnboundLocalError; } -PyObject * _Exc_UnicodeError() { return ptr__Exc_UnicodeError; } -#endif - -// -// wrap items in Object.h -// -PyObject * _None() { return ptr__PyNone; } - -PyObject * _False() { return ptr__PyFalse; } -PyObject * _True() { return ptr__PyTrue; } - -PyTypeObject * _Buffer_Type() { return ptr__Buffer_Type; } -PyTypeObject * _CFunction_Type(){ return ptr__CFunction_Type; } -PyTypeObject * _Class_Type() { return ptr__Class_Type; } -#if PY_VERSION_HEX < 0x02070000 -PyTypeObject * _CObject_Type() { return ptr__CObject_Type; } -#endif -PyTypeObject * _Complex_Type() { return ptr__Complex_Type; } -PyTypeObject * _Dict_Type() { return ptr__Dict_Type; } -PyTypeObject * _File_Type() { return ptr__File_Type; } -PyTypeObject * _Float_Type() { return ptr__Float_Type; } -PyTypeObject * _Function_Type() { return ptr__Function_Type; } -PyTypeObject * _Instance_Type() { return ptr__Instance_Type; } -PyTypeObject * _Bool_Type() { return ptr__Bool_Type; } -PyTypeObject * _Int_Type() { return ptr__Int_Type; } -PyTypeObject * _List_Type() { return ptr__List_Type; } -PyTypeObject * _Long_Type() { return ptr__Long_Type; } -PyTypeObject * _Method_Type() { return ptr__Method_Type; } -PyTypeObject * _Module_Type() { return ptr__Module_Type; } -PyTypeObject * _Range_Type() { return ptr__Range_Type; } -PyTypeObject * _Slice_Type() { return ptr__Slice_Type; } -PyTypeObject * _String_Type() { return ptr__String_Type; } -PyTypeObject * _TraceBack_Type(){ return ptr__TraceBack_Type; } -PyTypeObject * _Tuple_Type() { return ptr__Tuple_Type; } -PyTypeObject * _Type_Type() { return ptr__Type_Type; } - -#if PY_MAJOR_VERSION >= 2 -PyTypeObject * _Unicode_Type() { return ptr__Unicode_Type; } -#endif - -char *__Py_PackageContext() { return *ptr__Py_PackageContext; } - - -// -// wrap the Python Flag variables -// -int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } -int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } -int &_Py_TabcheckFlag() { return *ptr_Py_TabcheckFlag; } -int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } -#if PY_MAJOR_VERSION >= 2 -int &_Py_UnicodeFlag() { return *ptr_Py_UnicodeFlag; } -#endif - -void _XINCREF( PyObject *op ) -{ - // This function must match the contents of Py_XINCREF(op) - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)++; -#endif - (op)->ob_refcnt++; - -} - -void _XDECREF( PyObject *op ) -{ - // This function must match the contents of Py_XDECREF(op); - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)--; -#endif - - if (--(op)->ob_refcnt == 0) - _Py_Dealloc((PyObject *)(op)); -} - - -#else -#error "Can only delay load under Win32" -#endif - -#else - -// -// Duplicated these declarations from rangeobject.h which is missing the -// extern "C". This has been reported as a bug upto and include 2.1 -// -extern "C" DL_IMPORT(PyTypeObject) PyRange_Type; -extern "C" DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); - - -//================================================================================ -// -// Map onto Macros -// -//================================================================================ - -// -// Wrap variables as function calls -// - -PyObject * _Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } -PyObject * _Exc_AssertionError() { return ::PyExc_AssertionError; } -PyObject * _Exc_AttributeError() { return ::PyExc_AttributeError; } -PyObject * _Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } -PyObject * _Exc_EOFError() { return ::PyExc_EOFError; } -PyObject * _Exc_Exception() { return ::PyExc_Exception; } -PyObject * _Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } -PyObject * _Exc_ImportError() { return ::PyExc_ImportError; } -PyObject * _Exc_IndexError() { return ::PyExc_IndexError; } -PyObject * _Exc_IOError() { return ::PyExc_IOError; } -PyObject * _Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } -PyObject * _Exc_KeyError() { return ::PyExc_KeyError; } -PyObject * _Exc_LookupError() { return ::PyExc_LookupError; } -PyObject * _Exc_MemoryError() { return ::PyExc_MemoryError; } -PyObject * _Exc_MemoryErrorInst() { return ::PyExc_MemoryErrorInst; } -PyObject * _Exc_NameError() { return ::PyExc_NameError; } -PyObject * _Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } -PyObject * _Exc_OSError() { return ::PyExc_OSError; } -PyObject * _Exc_OverflowError() { return ::PyExc_OverflowError; } -PyObject * _Exc_RuntimeError() { return ::PyExc_RuntimeError; } -PyObject * _Exc_StandardError() { return ::PyExc_StandardError; } -PyObject * _Exc_SyntaxError() { return ::PyExc_SyntaxError; } -PyObject * _Exc_SystemError() { return ::PyExc_SystemError; } -PyObject * _Exc_SystemExit() { return ::PyExc_SystemExit; } -PyObject * _Exc_TypeError() { return ::PyExc_TypeError; } -PyObject * _Exc_ValueError() { return ::PyExc_ValueError; } -PyObject * _Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } - -#ifdef MS_WINDOWS -PyObject * _Exc_WindowsError() { return ::PyExc_WindowsError; } -#endif - - -#if PY_MAJOR_VERSION >= 2 -PyObject * _Exc_IndentationError() { return ::PyExc_IndentationError; } -PyObject * _Exc_TabError() { return ::PyExc_TabError; } -PyObject * _Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } -PyObject * _Exc_UnicodeError() { return ::PyExc_UnicodeError; } -#endif - - -// -// wrap items in Object.h -// -PyObject * _None() { return &::_Py_NoneStruct; } - -PyObject * _False() { return Py_False; } -PyObject * _True() { return Py_True; } - -PyTypeObject * _Buffer_Type() { return &PyBuffer_Type; } -PyTypeObject * _CFunction_Type() { return &PyCFunction_Type; } -PyTypeObject * _Class_Type() { return &PyClass_Type; } -#if PY_VERSION_HEX < 0x02070000 -PyTypeObject * _CObject_Type() { return &PyCObject_Type; } -#endif -PyTypeObject * _Complex_Type() { return &PyComplex_Type; } -PyTypeObject * _Dict_Type() { return &PyDict_Type; } -PyTypeObject * _File_Type() { return &PyFile_Type; } -PyTypeObject * _Float_Type() { return &PyFloat_Type; } -PyTypeObject * _Function_Type() { return &PyFunction_Type; } -PyTypeObject * _Instance_Type() { return &PyInstance_Type; } -PyTypeObject * _Bool_Type() { return &PyBool_Type; } -PyTypeObject * _Int_Type() { return &PyInt_Type; } -PyTypeObject * _List_Type() { return &PyList_Type; } -PyTypeObject * _Long_Type() { return &PyLong_Type; } -PyTypeObject * _Method_Type() { return &PyMethod_Type; } -PyTypeObject * _Module_Type() { return &PyModule_Type; } -PyTypeObject * _Range_Type() { return &PyRange_Type; } -PyTypeObject * _Slice_Type() { return &PySlice_Type; } -PyTypeObject * _String_Type() { return &PyString_Type; } -PyTypeObject * _TraceBack_Type() { return &PyTraceBack_Type; } -PyTypeObject * _Tuple_Type() { return &PyTuple_Type; } -PyTypeObject * _Type_Type() { return &PyType_Type; } - -#if PY_MAJOR_VERSION >= 2 -PyTypeObject * _Unicode_Type() { return &PyUnicode_Type; } -#endif - -// -// wrap flags -// -int &_Py_DebugFlag() { return Py_DebugFlag; } -int &_Py_InteractiveFlag(){ return Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } -int &_Py_TabcheckFlag() { return Py_TabcheckFlag; } -int &_Py_VerboseFlag() { return Py_VerboseFlag; } -#if PY_MAJOR_VERSION >= 2 -int &_Py_UnicodeFlag() { return Py_UnicodeFlag; } -#endif -char *__Py_PackageContext(){ return _Py_PackageContext; } - -// -// Needed to keep the abstactions for delayload interface -// -void _XINCREF( PyObject *op ) -{ - Py_XINCREF(op); -} - -void _XDECREF( PyObject *op ) -{ - Py_XDECREF(op); -} - -#endif -} diff --git a/CXX/Python2/IndirectPythonInterface.hxx b/CXX/Python2/IndirectPythonInterface.hxx index 33d4b83f34fc..a29a394c6c6a 100644 --- a/CXX/Python2/IndirectPythonInterface.hxx +++ b/CXX/Python2/IndirectPythonInterface.hxx @@ -113,10 +113,8 @@ bool _Instance_Check( PyObject *op ); PyTypeObject * _Method_Type(); bool _Method_Check( PyObject *op ); -#if PY_VERSION_HEX < 0x02070000 PyTypeObject * _CObject_Type(); bool _CObject_Check( PyObject *op ); -#endif PyTypeObject * _Complex_Type(); bool _Complex_Check( PyObject *op ); diff --git a/CXX/Python2/PythonType.hxx b/CXX/Python2/PythonType.hxx index a89a6c90481e..fc45a4bc6c5e 100644 --- a/CXX/Python2/PythonType.hxx +++ b/CXX/Python2/PythonType.hxx @@ -57,17 +57,15 @@ namespace Py PythonType &doc( const char *d ); PythonType &supportClass( void ); -#if !defined( PY3 ) PythonType &dealloc( void (*f)( PyObject* ) ); -#endif -#if defined( PYCXX_PYTHON_2TO3 ) || !defined( PY3 ) +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &supportPrint( void ); #endif PythonType &supportGetattr( void ); PythonType &supportSetattr( void ); PythonType &supportGetattro( void ); PythonType &supportSetattro( void ); -#if defined( PYCXX_PYTHON_2TO3 ) || !defined( PY3 ) +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &supportCompare( void ); #endif PythonType &supportRichCompare( void ); diff --git a/CXX/Python2/cxx_extensions.cxx b/CXX/Python2/cxx_extensions.cxx index 6ae62c7cfb05..611a335d1164 100644 --- a/CXX/Python2/cxx_extensions.cxx +++ b/CXX/Python2/cxx_extensions.cxx @@ -254,12 +254,16 @@ extern "C" // All the following functions redirect the call from Python // onto the matching virtual function in PythonExtensionBase // +#if defined( PYCXX_PYTHON_2TO3 ) static int print_handler( PyObject *, FILE *, int ); +#endif static PyObject *getattr_handler( PyObject *, char * ); static int setattr_handler( PyObject *, char *, PyObject * ); static PyObject *getattro_handler( PyObject *, PyObject * ); static int setattro_handler( PyObject *, PyObject *, PyObject * ); +#if defined( PYCXX_PYTHON_2TO3 ) static int compare_handler( PyObject *, PyObject * ); +#endif static PyObject *rich_compare_handler( PyObject *, PyObject *, int ); static PyObject *repr_handler( PyObject * ); static PyObject *str_handler( PyObject * ); @@ -290,9 +294,7 @@ extern "C" static PyObject *number_invert_handler( PyObject * ); static PyObject *number_int_handler( PyObject * ); static PyObject *number_float_handler( PyObject * ); -#if !defined( PY3 ) static PyObject *number_long_handler( PyObject * ); -#endif static PyObject *number_oct_handler( PyObject * ); static PyObject *number_hex_handler( PyObject * ); static PyObject *number_add_handler( PyObject *, PyObject * ); @@ -335,13 +337,9 @@ PythonType &PythonType::supportSequenceType() sequence_table->sq_concat = sequence_concat_handler; sequence_table->sq_repeat = sequence_repeat_handler; sequence_table->sq_item = sequence_item_handler; -#if !defined( PY3 ) sequence_table->sq_slice = sequence_slice_handler; -#endif sequence_table->sq_ass_item = sequence_ass_item_handler; // BAS setup seperately? -#if !defined( PY3 ) sequence_table->sq_ass_slice = sequence_ass_slice_handler; // BAS setup seperately? -#endif } return *this; } @@ -370,36 +368,26 @@ PythonType &PythonType::supportNumberType() number_table->nb_add = number_add_handler; number_table->nb_subtract = number_subtract_handler; number_table->nb_multiply = number_multiply_handler; -#if !defined( PY3 ) number_table->nb_divide = number_divide_handler; -#endif number_table->nb_remainder = number_remainder_handler; number_table->nb_divmod = number_divmod_handler; number_table->nb_power = number_power_handler; number_table->nb_negative = number_negative_handler; number_table->nb_positive = number_positive_handler; number_table->nb_absolute = number_absolute_handler; -#if !defined( PY3 ) number_table->nb_nonzero = number_nonzero_handler; -#endif number_table->nb_invert = number_invert_handler; number_table->nb_lshift = number_lshift_handler; number_table->nb_rshift = number_rshift_handler; number_table->nb_and = number_and_handler; number_table->nb_xor = number_xor_handler; number_table->nb_or = number_or_handler; -#if !defined( PY3 ) number_table->nb_coerce = 0; -#endif number_table->nb_int = number_int_handler; -#if !defined( PY3 ) number_table->nb_long = number_long_handler; -#endif number_table->nb_float = number_float_handler; -#if !defined( PY3 ) number_table->nb_oct = number_oct_handler; number_table->nb_hex = number_hex_handler; -#endif } return *this; } @@ -411,11 +399,9 @@ PythonType &PythonType::supportBufferType() buffer_table = new PyBufferProcs; memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 table->tp_as_buffer = buffer_table; -#if !defined( PY3 ) buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler; buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler; buffer_table->bf_getsegcount = buffer_getsegcount_handler; -#endif } return *this; } @@ -434,10 +420,9 @@ PythonType::PythonType( size_t basic_size, int itemsize, const char *default_nam memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 *reinterpret_cast( table ) = py_object_initializer; -#if !defined( PY3 ) table->ob_type = _Type_Type(); table->ob_size = 0; -#endif + table->tp_name = const_cast( default_name ); table->tp_basicsize = basic_size; table->tp_itemsize = itemsize; @@ -575,11 +560,13 @@ PythonType &PythonType::dealloc( void( *f )( PyObject * )) return *this; } +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &PythonType::supportPrint() { table->tp_print = print_handler; return *this; } +#endif PythonType &PythonType::supportGetattr() { @@ -605,11 +592,13 @@ PythonType &PythonType::supportSetattro() return *this; } +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &PythonType::supportCompare() { table->tp_compare = compare_handler; return *this; } +#endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) PythonType &PythonType::supportRichCompare() @@ -669,6 +658,7 @@ PythonExtensionBase *getPythonExtensionBase( PyObject *self ) } +#if defined( PYCXX_PYTHON_2TO3 ) extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) { try @@ -681,6 +671,7 @@ extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) return -1; // indicate error } } +#endif extern "C" PyObject *getattr_handler( PyObject *self, char *name ) { @@ -734,6 +725,7 @@ extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value } } +#if defined( PYCXX_PYTHON_2TO3 ) extern "C" int compare_handler( PyObject *self, PyObject *other ) { try @@ -746,6 +738,7 @@ extern "C" int compare_handler( PyObject *self, PyObject *other ) return -1; // indicate error } } +#endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) extern "C" PyObject *rich_compare_handler( PyObject *self, PyObject *other, int op ) @@ -1719,11 +1712,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - #if PY_VERSION_HEX < 0x02070000 - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); - #else - void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); - #endif + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; @@ -1739,11 +1728,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - #if PY_VERSION_HEX < 0x02070000 - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), - #else - PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), - #endif + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args, keywords ) @@ -1759,11 +1744,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - #if PY_VERSION_HEX < 0x02070000 - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), - #else - PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), - #endif + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args, keywords ) @@ -1785,11 +1766,7 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - #if PY_VERSION_HEX < 0x02070000 - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); - #else - void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); - #endif + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; @@ -1800,11 +1777,7 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_varargs ( - #if PY_VERSION_HEX < 0x02070000 - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), - #else - PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), - #endif + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args ) ); diff --git a/CXX/Python3/ExtensionModule.hxx b/CXX/Python3/ExtensionModule.hxx index a892a6f8cde5..75eb77568ae4 100644 --- a/CXX/Python3/ExtensionModule.hxx +++ b/CXX/Python3/ExtensionModule.hxx @@ -135,8 +135,8 @@ namespace Py static PyObject *self = PyCapsule_New( this, NULL, NULL ); Tuple args( 2 ); - args[0] = Object( self ); - args[1] = Object( PyCapsule_New( method_def, NULL, NULL ) ); + args[0] = Object( self, true ); + args[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); PyObject *func = PyCFunction_New ( diff --git a/CXX/Python3/IndirectPythonInterface.cxx b/CXX/Python3/IndirectPythonInterface.cxx deleted file mode 100644 index 2b7ff41b75da..000000000000 --- a/CXX/Python3/IndirectPythonInterface.cxx +++ /dev/null @@ -1,518 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#include "CXX/IndirectPythonInterface.hxx" - -namespace Py -{ -bool _CFunction_Check( PyObject *op ) { return op->ob_type == _CFunction_Type(); } -bool _Complex_Check( PyObject *op ) { return op->ob_type == _Complex_Type(); } -bool _Dict_Check( PyObject *op ) { return op->ob_type == _Dict_Type(); } -bool _Float_Check( PyObject *op ) { return op->ob_type == _Float_Type(); } -bool _Function_Check( PyObject *op ) { return op->ob_type == _Function_Type(); } -bool _Boolean_Check( PyObject *op ) { return op->ob_type == _Bool_Type(); } -bool _List_Check( PyObject *op ) { return op->ob_type == _List_Type(); } -bool _Long_Check( PyObject *op ) { return op->ob_type == _Long_Type(); } -bool _Method_Check( PyObject *op ) { return op->ob_type == _Method_Type(); } -bool _Module_Check( PyObject *op ) { return op->ob_type == _Module_Type(); } -bool _Range_Check( PyObject *op ) { return op->ob_type == _Range_Type(); } -bool _Slice_Check( PyObject *op ) { return op->ob_type == _Slice_Type(); } -bool _TraceBack_Check( PyObject *op ) { return op->ob_type == _TraceBack_Type(); } -bool _Tuple_Check( PyObject *op ) { return op->ob_type == _Tuple_Type(); } -bool _Type_Check( PyObject *op ) { return op->ob_type == _Type_Type(); } -bool _Unicode_Check( PyObject *op ) { return op->ob_type == _Unicode_Type(); } -bool _Bytes_Check( PyObject *op ) { return op->ob_type == _Bytes_Type(); } - -#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) - -#if defined(MS_WINDOWS) -#include - - -static HMODULE python_dll; - -static PyObject *ptr__Exc_ArithmeticError = NULL; -static PyObject *ptr__Exc_AssertionError = NULL; -static PyObject *ptr__Exc_AttributeError = NULL; -static PyObject *ptr__Exc_EnvironmentError = NULL; -static PyObject *ptr__Exc_EOFError = NULL; -static PyObject *ptr__Exc_Exception = NULL; -static PyObject *ptr__Exc_FloatingPointError = NULL; -static PyObject *ptr__Exc_ImportError = NULL; -static PyObject *ptr__Exc_IndexError = NULL; -static PyObject *ptr__Exc_IOError = NULL; -static PyObject *ptr__Exc_KeyboardInterrupt = NULL; -static PyObject *ptr__Exc_KeyError = NULL; -static PyObject *ptr__Exc_LookupError = NULL; -static PyObject *ptr__Exc_MemoryError = NULL; -static PyObject *ptr__Exc_NameError = NULL; -static PyObject *ptr__Exc_NotImplementedError = NULL; -static PyObject *ptr__Exc_OSError = NULL; -static PyObject *ptr__Exc_OverflowError = NULL; -static PyObject *ptr__Exc_RuntimeError = NULL; -static PyObject *ptr__Exc_StandardError = NULL; -static PyObject *ptr__Exc_SyntaxError = NULL; -static PyObject *ptr__Exc_SystemError = NULL; -static PyObject *ptr__Exc_SystemExit = NULL; -static PyObject *ptr__Exc_TypeError = NULL; -static PyObject *ptr__Exc_ValueError = NULL; -static PyObject *ptr__Exc_ZeroDivisionError = NULL; - -#ifdef MS_WINDOWS -static PyObject *ptr__Exc_WindowsError = NULL; -#endif - -static PyObject *ptr__Exc_IndentationError = NULL; -static PyObject *ptr__Exc_TabError = NULL; -static PyObject *ptr__Exc_UnboundLocalError = NULL; -static PyObject *ptr__Exc_UnicodeError = NULL; -static PyObject *ptr__PyNone = NULL; -static PyObject *ptr__PyFalse = NULL; -static PyObject *ptr__PyTrue = NULL; -static PyTypeObject *ptr__CFunction_Type = NULL; -static PyTypeObject *ptr__Complex_Type = NULL; -static PyTypeObject *ptr__Dict_Type = NULL; -static PyTypeObject *ptr__Float_Type = NULL; -static PyTypeObject *ptr__Function_Type = NULL; -static PyTypeObject *ptr__List_Type = NULL; -static PyTypeObject *ptr__Long_Type = NULL; -static PyTypeObject *ptr__Method_Type = NULL; -static PyTypeObject *ptr__Module_Type = NULL; -static PyTypeObject *ptr__Range_Type = NULL; -static PyTypeObject *ptr__Slice_Type = NULL; -static PyTypeObject *ptr__TraceBack_Type = NULL; -static PyTypeObject *ptr__Tuple_Type = NULL; -static PyTypeObject *ptr__Type_Type = NULL; - -static int *ptr_Py_DebugFlag = NULL; -static int *ptr_Py_InteractiveFlag = NULL; -static int *ptr_Py_OptimizeFlag = NULL; -static int *ptr_Py_NoSiteFlag = NULL; -static int *ptr_Py_VerboseFlag = NULL; - -static char **ptr__Py_PackageContext = NULL; - -#ifdef Py_REF_DEBUG -int *ptr_Py_RefTotal; -#endif - - -//-------------------------------------------------------------------------------- -class GetAddressException -{ -public: - GetAddressException( const char *_name ) - : name( _name ) - {} - virtual ~GetAddressException() {} - const char *name; -}; - - -//-------------------------------------------------------------------------------- -static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyObject **)addr; -} - -static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyObject *)addr; -} - -static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyTypeObject **)addr; -} - -static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyTypeObject *)addr; -} - -static int *GetInt_as_IntPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (int *)addr; -} - -static char **GetCharPointer_as_CharPointerPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (char **)addr; -} - - -#ifdef _DEBUG -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; -#else -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; -#endif - -//-------------------------------------------------------------------------------- -bool InitialisePythonIndirectInterface() -{ - char python_dll_name[sizeof(python_dll_name_format)]; - - sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); - - python_dll = LoadLibrary( python_dll_name ); - if( python_dll == NULL ) - return false; - - try - { -#ifdef Py_REF_DEBUG - ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); -#endif - ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); - ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); - ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); - ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); - ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); - ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); - - ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); - ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); - ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); - ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); - ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); - ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); - ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); - ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); - ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); - ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); - ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); - ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); - ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); - ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); - ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); - ptr__Exc_NotImplementedError= GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); - ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); - ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); - ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); - ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); - ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); - ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); - ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); - ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); - ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); -#ifdef MS_WINDOWS - ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); -#endif - ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); - ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); - ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); - ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); - ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); - ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); - - ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); - ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); - - ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); - ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); - ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); - ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); - ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); - ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); - ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); - ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); - ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); - ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); - ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); - ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); - ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); - ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); - ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); - ptr__Bytes_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBytes_Type" ); - } - catch( GetAddressException &e ) - { - OutputDebugString( python_dll_name ); - OutputDebugString( " does not contain symbol "); - OutputDebugString( e.name ); - OutputDebugString( "\n" ); - - return false; - } - - return true; -} - -// -// Wrap variables as function calls -// -PyObject *_Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } -PyObject *_Exc_AssertionError() { return ptr__Exc_AssertionError; } -PyObject *_Exc_AttributeError() { return ptr__Exc_AttributeError; } -PyObject *_Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } -PyObject *_Exc_EOFError() { return ptr__Exc_EOFError; } -PyObject *_Exc_Exception() { return ptr__Exc_Exception; } -PyObject *_Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } -PyObject *_Exc_ImportError() { return ptr__Exc_ImportError; } -PyObject *_Exc_IndexError() { return ptr__Exc_IndexError; } -PyObject *_Exc_IOError() { return ptr__Exc_IOError; } -PyObject *_Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } -PyObject *_Exc_KeyError() { return ptr__Exc_KeyError; } -PyObject *_Exc_LookupError() { return ptr__Exc_LookupError; } -PyObject *_Exc_MemoryError() { return ptr__Exc_MemoryError; } -PyObject *_Exc_NameError() { return ptr__Exc_NameError; } -PyObject *_Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } -PyObject *_Exc_OSError() { return ptr__Exc_OSError; } -PyObject *_Exc_OverflowError() { return ptr__Exc_OverflowError; } -PyObject *_Exc_RuntimeError() { return ptr__Exc_RuntimeError; } -PyObject *_Exc_StandardError() { return ptr__Exc_StandardError; } -PyObject *_Exc_SyntaxError() { return ptr__Exc_SyntaxError; } -PyObject *_Exc_SystemError() { return ptr__Exc_SystemError; } -PyObject *_Exc_SystemExit() { return ptr__Exc_SystemExit; } -PyObject *_Exc_TypeError() { return ptr__Exc_TypeError; } -PyObject *_Exc_ValueError() { return ptr__Exc_ValueError; } -#ifdef MS_WINDOWS -PyObject *_Exc_WindowsError() { return ptr__Exc_WindowsError; } -#endif -PyObject *_Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } -PyObject *_Exc_IndentationError() { return ptr__Exc_IndentationError; } -PyObject *_Exc_TabError() { return ptr__Exc_TabError; } -PyObject *_Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } -PyObject *_Exc_UnicodeError() { return ptr__Exc_UnicodeError; } - -// -// wrap items in Object.h -// -PyObject *_None() { return ptr__PyNone; } - -PyObject *_False() { return ptr__PyFalse; } -PyObject *_True() { return ptr__PyTrue; } - -PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } -PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } -PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } -PyTypeObject *_Float_Type() { return ptr__Float_Type; } -PyTypeObject *_Function_Type() { return ptr__Function_Type; } -PyTypeObject *_Bool_Type() { return ptr__Bool_Type; } -PyTypeObject *_List_Type() { return ptr__List_Type; } -PyTypeObject *_Long_Type() { return ptr__Long_Type; } -PyTypeObject *_Method_Type() { return ptr__Method_Type; } -PyTypeObject *_Module_Type() { return ptr__Module_Type; } -PyTypeObject *_Range_Type() { return ptr__Range_Type; } -PyTypeObject *_Slice_Type() { return ptr__Slice_Type; } -PyTypeObject *_TraceBack_Type() { return ptr__TraceBack_Type; } -PyTypeObject *_Tuple_Type() { return ptr__Tuple_Type; } -PyTypeObject *_Type_Type() { return ptr__Type_Type; } -PyTypeObject *_Unicode_Type() { return ptr__Unicode_Type; } -PyTypeObject *_Bytes_Type() { return ptr__Bytes_Type; } - -char *__Py_PackageContext() { return *ptr__Py_PackageContext; } - - -// -// wrap the Python Flag variables -// -int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } -int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } -int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } - -#if 0 -#define Py_INCREF(op) ( \ - _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ - ((PyObject*)(op))->ob_refcnt++) - -#define Py_DECREF(op) \ - if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ - --((PyObject*)(op))->ob_refcnt != 0) \ - _Py_CHECK_REFCNT(op) \ - else \ - _Py_Dealloc((PyObject *)(op)) -#endif - -void _XINCREF( PyObject *op ) -{ - // This function must match the contents of Py_XINCREF(op) - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)++; -#endif - (op)->ob_refcnt++; - -} - -void _XDECREF( PyObject *op ) -{ - // This function must match the contents of Py_XDECREF(op); - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)--; -#endif - - if (--(op)->ob_refcnt == 0) - _Py_Dealloc((PyObject *)(op)); -} - - -#else -#error "Can only delay load under Win32" -#endif - -#else - -//================================================================================ -// -// Map onto Macros -// -//================================================================================ - -// -// Wrap variables as function calls -// - -PyObject *_Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } -PyObject *_Exc_AssertionError() { return ::PyExc_AssertionError; } -PyObject *_Exc_AttributeError() { return ::PyExc_AttributeError; } -PyObject *_Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } -PyObject *_Exc_EOFError() { return ::PyExc_EOFError; } -PyObject *_Exc_Exception() { return ::PyExc_Exception; } -PyObject *_Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } -PyObject *_Exc_ImportError() { return ::PyExc_ImportError; } -PyObject *_Exc_IndexError() { return ::PyExc_IndexError; } -PyObject *_Exc_IOError() { return ::PyExc_IOError; } -PyObject *_Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } -PyObject *_Exc_KeyError() { return ::PyExc_KeyError; } -PyObject *_Exc_LookupError() { return ::PyExc_LookupError; } -PyObject *_Exc_MemoryError() { return ::PyExc_MemoryError; } -PyObject *_Exc_NameError() { return ::PyExc_NameError; } -PyObject *_Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } -PyObject *_Exc_OSError() { return ::PyExc_OSError; } -PyObject *_Exc_OverflowError() { return ::PyExc_OverflowError; } -PyObject *_Exc_RuntimeError() { return ::PyExc_RuntimeError; } -PyObject *_Exc_SyntaxError() { return ::PyExc_SyntaxError; } -PyObject *_Exc_SystemError() { return ::PyExc_SystemError; } -PyObject *_Exc_SystemExit() { return ::PyExc_SystemExit; } -PyObject *_Exc_TypeError() { return ::PyExc_TypeError; } -PyObject *_Exc_ValueError() { return ::PyExc_ValueError; } -PyObject *_Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } -PyObject *_Exc_IndentationError() { return ::PyExc_IndentationError; } -PyObject *_Exc_TabError() { return ::PyExc_TabError; } -PyObject *_Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } -PyObject *_Exc_UnicodeError() { return ::PyExc_UnicodeError; } - -#ifdef MS_WINDOWS -PyObject *_Exc_WindowsError() { return ::PyExc_WindowsError; } -#endif - - - - -// -// wrap items in Object.h -// -PyObject *_None() { return &::_Py_NoneStruct; } - -PyObject *_False() { return Py_False; } -PyObject *_True() { return Py_True; } - -PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } -PyTypeObject *_Complex_Type() { return &PyComplex_Type; } -PyTypeObject *_Dict_Type() { return &PyDict_Type; } -PyTypeObject *_Float_Type() { return &PyFloat_Type; } -PyTypeObject *_Function_Type() { return &PyFunction_Type; } -PyTypeObject *_Bool_Type() { return &PyBool_Type; } -PyTypeObject *_List_Type() { return &PyList_Type; } -PyTypeObject *_Long_Type() { return &PyLong_Type; } -PyTypeObject *_Method_Type() { return &PyMethod_Type; } -PyTypeObject *_Module_Type() { return &PyModule_Type; } -PyTypeObject *_Range_Type() { return &PyRange_Type; } -PyTypeObject *_Slice_Type() { return &PySlice_Type; } -PyTypeObject *_TraceBack_Type() { return &PyTraceBack_Type; } -PyTypeObject *_Tuple_Type() { return &PyTuple_Type; } -PyTypeObject *_Type_Type() { return &PyType_Type; } -PyTypeObject *_Unicode_Type() { return &PyUnicode_Type; } -PyTypeObject *_Bytes_Type() { return &PyBytes_Type; } - -// -// wrap flags -// -int &_Py_DebugFlag() { return Py_DebugFlag; } -int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } -int &_Py_VerboseFlag() { return Py_VerboseFlag; } -char *__Py_PackageContext() { return _Py_PackageContext; } - -// -// Needed to keep the abstactions for delayload interface -// -void _XINCREF( PyObject *op ) -{ - Py_XINCREF( op ); -} - -void _XDECREF( PyObject *op ) -{ - Py_XDECREF( op ); -} - -#endif -} diff --git a/CXX/Python3/Objects.hxx b/CXX/Python3/Objects.hxx index 2847512f065a..927618f0ba06 100644 --- a/CXX/Python3/Objects.hxx +++ b/CXX/Python3/Objects.hxx @@ -413,7 +413,7 @@ namespace Py { } - virtual bool accepts( PyObject *pyob ) const + virtual bool accepts( PyObject *pyob ) { return pyob == NULL; } @@ -1328,7 +1328,6 @@ namespace Py } // Assignment acquires new ownership of pointer - SeqBase &operator=( const Object &rhs ) { return *this = *rhs; @@ -1520,7 +1519,7 @@ namespace Py int operator-( const iterator &other ) const { - if( seq->ptr() != other.seq->ptr() ) + if( seq->ptr() != other.seq->ptr() ) throw RuntimeError( "SeqBase::iterator comparison error" ); return count - other.count; @@ -2192,8 +2191,8 @@ namespace Py } } } - // Assignment acquires new ownership of pointer + // Assignment acquires new ownership of pointer Tuple &operator=( const Object &rhs ) { return *this = *rhs; @@ -2380,8 +2379,8 @@ namespace Py { return max_size(); } - // Assignment acquires new ownership of pointer + // Assignment acquires new ownership of pointer List &operator=( const Object &rhs ) { return *this = *rhs; @@ -3074,8 +3073,8 @@ namespace Py set( PyDict_New(), true ); validate(); } - // Assignment acquires new ownership of pointer + // Assignment acquires new ownership of pointer Dict &operator=( const Object &rhs ) { return *this = *rhs; diff --git a/CXX/Python3/cxx_extensions.cxx b/CXX/Python3/cxx_extensions.cxx index 59874ad95576..8f2a4886c251 100644 --- a/CXX/Python3/cxx_extensions.cxx +++ b/CXX/Python3/cxx_extensions.cxx @@ -366,7 +366,7 @@ PythonType::PythonType( size_t basic_size, int itemsize, const char *default_nam memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 *reinterpret_cast( table ) = py_object_initializer; - // QQQ table->ob_type = _Type_Type(); + reinterpret_cast( table )->ob_type = _Type_Type(); // QQQ table->ob_size = 0; table->tp_name = const_cast( default_name ); table->tp_basicsize = basic_size; @@ -440,10 +440,10 @@ PythonType::PythonType( size_t basic_size, int itemsize, const char *default_nam table->tp_version_tag = 0; #ifdef COUNT_ALLOCS - table->tp_allocs = 0; - table->tp_frees = 0; + table->tp_alloc = 0; + table->tp_free = 0; table->tp_maxalloc = 0; - table->tp_prev = 0; + table->tp_orev = 0; table->tp_next = 0; #endif } @@ -1602,9 +1602,6 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple } } -extern "C" void do_not_dealloc( void * ) -{} - //-------------------------------------------------------------------------------- // diff --git a/CXX/WrapPython.h b/CXX/WrapPython.h index 118a8740f8ad..6a73545d2d3d 100644 --- a/CXX/WrapPython.h +++ b/CXX/WrapPython.h @@ -57,4 +57,15 @@ // pull in python definitions #include +// fix issue with Python assuming that isspace, toupper etc are macros +#if defined(isspace) +#undef isspace +#undef isupper +#undef islower +#undef isalnum +#undef isalpha +#undef toupper +#undef tolower +#endif + #endif diff --git a/INSTALL b/INSTALL index fa03255b5844..679f0c7ba191 100644 --- a/INSTALL +++ b/INSTALL @@ -183,7 +183,7 @@ the libraries themselves. `Download python `_. :term:`numpy` |minimum_numpy_version| (or later) - array support for python (`download `_) + array support for python (`download numpy `_) libpng 1.2 (or later) library for loading and saving :term:`PNG` files (`download @@ -196,6 +196,16 @@ libpng 1.2 (or later) user, you can ignore this since we build support into the matplotlib single click installer. +:term:`dateutil` 1.1 or later + Provides extensions to python datetime handling. If using pip, + easy_install or installing from source, the installer will attempt + to download and install `python_dateutil` from PyPI. + +`pyparsing` + Required for matplotlib's mathtext math rendering support. If + using pip, easy_install or installing from source, the installer + will attempt to download and install `pyparsing` from PyPI. + **Optional** These are optional packages which you may want to install to use @@ -206,9 +216,6 @@ backends and the capabilities they provide. :term:`tk` 8.3 or later The TCL/Tk widgets library used by the TkAgg backend -:term:`pyqt` 3.1 or later - The Qt3 widgets library python wrappers for the QtAgg backend - :term:`pyqt` 4.0 or later The Qt4 widgets library python wrappers for the Qt4Agg backend @@ -220,9 +227,6 @@ backends and the capabilities they provide. The python wrappers for the wx widgets library for use with the WX or WXAgg backend -:term:`pyfltk` 1.0 or later - The python wrappers of the FLTK widgets library for use with FLTKAgg - **Required libraries that ship with matplotlib** :term:`agg` 2.4 @@ -230,17 +234,8 @@ backends and the capabilities they provide. agg template source statically, so it will not affect anything on your system outside of matplotlib. -:term:`pytz` 2007g or later - timezone handling for python datetime objects. By default, - matplotlib will install pytz if it isn't already installed on your - system. To override the default, use :file:`setup.cfg` to force or - prevent installation of pytz. - -:term:`dateutil` 1.1 or later - provides extensions to python datetime handling. By default, matplotlib - will install dateutil if it isn't already installed on your - system. To override the default, use :file:`setup.cfg` to force - or prevent installation of dateutil. +`PyCXX` 6.2.4 + A library for writing Python extensions in C++. .. _build_osx: diff --git a/MANIFEST.in b/MANIFEST.in index 9838df35c44b..0ee8e71c2677 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,20 +1,16 @@ -include CHANGELOG KNOWN_BUGS INSTALL +include CHANGELOG INSTALL include INTERACTIVE TODO CONTRIBUTING.md -include Makefile make.osx MANIFEST.in MANIFEST +include Makefile MANIFEST.in MANIFEST include matplotlibrc.template setup.cfg.template -include __init__.py setupext.py setup.py setupegg.py -include examples/data/* -include lib/mpl_toolkits -include lib/matplotlib/mpl-data/matplotlib.conf -include lib/matplotlib/mpl-data/matplotlib.conf.template +include setupext.py setup.py setupegg.py include lib/matplotlib/mpl-data/lineprops.glade include lib/matplotlib/mpl-data/matplotlibrc include lib/matplotlib/mpl-data/images/* include lib/matplotlib/mpl-data/fonts/ttf/* include lib/matplotlib/mpl-data/fonts/pdfcorefonts/* include lib/matplotlib/mpl-data/fonts/afm/* -recursive-include lib/matplotlib/mpl-data/sample_data/* -recursive-include license LICENSE* +recursive-include lib/matplotlib/mpl-data/sample_data/ * +recursive-include LICENSE * recursive-include examples * recursive-include doc * recursive-include src *.cpp *.c *.h *.m diff --git a/Makefile b/Makefile index 8ac97ffe718b..d333f7f88901 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,11 @@ jdh_doc_snapshot: python make.py html latex sf sfpdf; +test: + ${PYTHON} tests.py +test-coverage: + ${PYTHON} tests.py --with-coverage --cover-package=matplotlib + diff --git a/README.osx b/README.osx index 3afcd9074578..c2ca0a59afce 100644 --- a/README.osx +++ b/README.osx @@ -9,7 +9,7 @@ homebrew. Example usage:: - brew install libpng freetype + brew install libpng freetype pkgconfig If you are using MacPorts, execute the following instead: diff --git a/README.rst b/README.rst new file mode 100644 index 000000000000..6e01ea7275cc --- /dev/null +++ b/README.rst @@ -0,0 +1,26 @@ +########## +matplotlib +########## + +matplotlib is a python 2D plotting library which produces publication +quality figures in a variety of hardcopy formats and interactive +environments across platforms. matplotlib can be used in python +scripts, the python and ipython shell (ala matlab or mathematica), web +application servers, and various graphical user interface toolkits. + +`Home page `_ + +Installation +============= + +For installation instructions and requirements, see the INSTALL file. + +Testing +======= + +After installation, you can launch the test suite:: + + python tests.py + +Consider reading http://matplotlib.org/devel/coding_guide.html#testing for +more information. diff --git a/README.txt b/README.txt deleted file mode 100644 index d00538e0e8ad..000000000000 --- a/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -matplotlib is a python 2D plotting library which produces publication -quality figures in a variety of hardcopy formats and interactive -environments across platforms. matplotlib can be used in python -scripts, the python and ipython shell (ala matlab or mathematica), web -application servers, and various graphical user interface toolkits. - -Home page: - -For installation instructions and requirements, see the INSTALL file. diff --git a/agg24/include/agg_rasterizer_cells_aa.h b/agg24/include/agg_rasterizer_cells_aa.h index c8f2cb80d49d..2be0efeca175 100755 --- a/agg24/include/agg_rasterizer_cells_aa.h +++ b/agg24/include/agg_rasterizer_cells_aa.h @@ -29,8 +29,7 @@ #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED #define AGG_RASTERIZER_CELLS_AA_INCLUDED -#include "CXX/Exception.hxx" -#include +#include #include #include #include "agg_math.h" @@ -183,9 +182,9 @@ namespace agg { if((m_num_cells & cell_block_mask) == 0) { - if(m_num_blocks >= cell_block_limit) { - throw Py::OverflowError( - "Agg rendering complexity exceeded. Consider downsampling or decimating your data."); + if (m_num_blocks >= cell_block_limit) + { + throw std::overflow_error("Allocated too many blocks"); } allocate_block(); } diff --git a/boilerplate.py b/boilerplate.py index ab13a04b17b2..b7839c72beeb 100644 --- a/boilerplate.py +++ b/boilerplate.py @@ -108,6 +108,7 @@ def boilerplate_gen(): 'contourf', 'csd', 'errorbar', + 'eventplot', 'fill', 'fill_between', 'fill_betweenx', @@ -169,7 +170,7 @@ def boilerplate_gen(): #'spy' : 'sci(%(ret)s)', ### may return image or Line2D 'quiver' : 'sci(%(ret)s)', 'specgram' : 'sci(%(ret)s[-1])', - 'streamplot' : 'sci(%(ret)s)', + 'streamplot' : 'sci(%(ret)s.lines)', 'tricontour' : 'if %(ret)s._A is not None: sci(%(ret)s)', 'tricontourf': 'if %(ret)s._A is not None: sci(%(ret)s)', 'tripcolor' : 'sci(%(ret)s)', diff --git a/distribute_setup.py b/distribute_setup.py new file mode 100755 index 000000000000..8f5b0637bf39 --- /dev/null +++ b/distribute_setup.py @@ -0,0 +1,515 @@ +#!python +"""Bootstrap distribute installation + +If you want to use setuptools in your package's setup.py, just include this +file in the same directory with it, and add this to the top of your setup.py:: + + from distribute_setup import use_setuptools + use_setuptools() + +If you want to require a specific version of setuptools, set a download +mirror, or use an alternate download directory, you can do so by supplying +the appropriate options to ``use_setuptools()``. + +This file can also be run as a script to install or upgrade setuptools. +""" +import os +import sys +import time +import fnmatch +import tempfile +import tarfile +from distutils import log + +try: + from site import USER_SITE +except ImportError: + USER_SITE = None + +try: + import subprocess + + def _python_cmd(*args): + args = (sys.executable,) + args + return subprocess.call(args) == 0 + +except ImportError: + # will be used for python 2.3 + def _python_cmd(*args): + args = (sys.executable,) + args + # quoting arguments if windows + if sys.platform == 'win32': + def quote(arg): + if ' ' in arg: + return '"%s"' % arg + return arg + args = [quote(arg) for arg in args] + return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 + +DEFAULT_VERSION = "0.6.28" +DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" +SETUPTOOLS_FAKED_VERSION = "0.6c11" + +SETUPTOOLS_PKG_INFO = """\ +Metadata-Version: 1.0 +Name: setuptools +Version: %s +Summary: xxxx +Home-page: xxx +Author: xxx +Author-email: xxx +License: xxx +Description: xxx +""" % SETUPTOOLS_FAKED_VERSION + + +def _install(tarball, install_args=()): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # installing + log.warn('Installing Distribute') + if not _python_cmd('setup.py', 'install', *install_args): + log.warn('Something went wrong during the installation.') + log.warn('See the error message above.') + finally: + os.chdir(old_wd) + + +def _build_egg(egg, tarball, to_dir): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # building an egg + log.warn('Building a Distribute egg in %s', to_dir) + _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) + + finally: + os.chdir(old_wd) + # returning the result + log.warn(egg) + if not os.path.exists(egg): + raise IOError('Could not build the egg.') + + +def _do_download(version, download_base, to_dir, download_delay): + egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' + % (version, sys.version_info[0], sys.version_info[1])) + if not os.path.exists(egg): + tarball = download_setuptools(version, download_base, + to_dir, download_delay) + _build_egg(egg, tarball, to_dir) + sys.path.insert(0, egg) + import setuptools + setuptools.bootstrap_install_from = egg + + +def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, download_delay=15, no_fake=True): + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + was_imported = 'pkg_resources' in sys.modules or \ + 'setuptools' in sys.modules + try: + try: + import pkg_resources + if not hasattr(pkg_resources, '_distribute'): + if not no_fake: + _fake_setuptools() + raise ImportError + except ImportError: + return _do_download(version, download_base, to_dir, download_delay) + try: + pkg_resources.require("distribute>=" + version) + return + except pkg_resources.VersionConflict: + e = sys.exc_info()[1] + if was_imported: + sys.stderr.write( + "The required version of distribute (>=%s) is not available,\n" + "and can't be installed while this script is running. Please\n" + "install a more recent version first, using\n" + "'easy_install -U distribute'." + "\n\n(Currently using %r)\n" % (version, e.args[0])) + sys.exit(2) + else: + del pkg_resources, sys.modules['pkg_resources'] # reload ok + return _do_download(version, download_base, to_dir, + download_delay) + except pkg_resources.DistributionNotFound: + return _do_download(version, download_base, to_dir, + download_delay) + finally: + if not no_fake: + _create_fake_setuptools_pkg_info(to_dir) + + +def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, delay=15): + """Download distribute from a specified location and return its filename + + `version` should be a valid distribute version number that is available + as an egg for download under the `download_base` URL (which should end + with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download + attempt. + """ + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + tgz_name = "distribute-%s.tar.gz" % version + url = download_base + tgz_name + saveto = os.path.join(to_dir, tgz_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + log.warn("Downloading %s", url) + src = urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = src.read() + dst = open(saveto, "wb") + dst.write(data) + finally: + if src: + src.close() + if dst: + dst.close() + return os.path.realpath(saveto) + + +def _no_sandbox(function): + def __no_sandbox(*args, **kw): + try: + from setuptools.sandbox import DirectorySandbox + if not hasattr(DirectorySandbox, '_old'): + def violation(*args): + pass + DirectorySandbox._old = DirectorySandbox._violation + DirectorySandbox._violation = violation + patched = True + else: + patched = False + except ImportError: + patched = False + + try: + return function(*args, **kw) + finally: + if patched: + DirectorySandbox._violation = DirectorySandbox._old + del DirectorySandbox._old + + return __no_sandbox + + +def _patch_file(path, content): + """Will backup the file then patch it""" + existing_content = open(path).read() + if existing_content == content: + # already patched + log.warn('Already patched.') + return False + log.warn('Patching...') + _rename_path(path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + return True + +_patch_file = _no_sandbox(_patch_file) + + +def _same_content(path, content): + return open(path).read() == content + + +def _rename_path(path): + new_name = path + '.OLD.%s' % time.time() + log.warn('Renaming %s into %s', path, new_name) + os.rename(path, new_name) + return new_name + + +def _remove_flat_installation(placeholder): + if not os.path.isdir(placeholder): + log.warn('Unkown installation at %s', placeholder) + return False + found = False + for file in os.listdir(placeholder): + if fnmatch.fnmatch(file, 'setuptools*.egg-info'): + found = True + break + if not found: + log.warn('Could not locate setuptools*.egg-info') + return + + log.warn('Removing elements out of the way...') + pkg_info = os.path.join(placeholder, file) + if os.path.isdir(pkg_info): + patched = _patch_egg_dir(pkg_info) + else: + patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) + + if not patched: + log.warn('%s already patched.', pkg_info) + return False + # now let's move the files out of the way + for element in ('setuptools', 'pkg_resources.py', 'site.py'): + element = os.path.join(placeholder, element) + if os.path.exists(element): + _rename_path(element) + else: + log.warn('Could not find the %s element of the ' + 'Setuptools distribution', element) + return True + +_remove_flat_installation = _no_sandbox(_remove_flat_installation) + + +def _after_install(dist): + log.warn('After install bootstrap.') + placeholder = dist.get_command_obj('install').install_purelib + _create_fake_setuptools_pkg_info(placeholder) + + +def _create_fake_setuptools_pkg_info(placeholder): + if not placeholder or not os.path.exists(placeholder): + log.warn('Could not find the install location') + return + pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) + setuptools_file = 'setuptools-%s-py%s.egg-info' % \ + (SETUPTOOLS_FAKED_VERSION, pyver) + pkg_info = os.path.join(placeholder, setuptools_file) + if os.path.exists(pkg_info): + log.warn('%s already exists', pkg_info) + return + + if not os.access(pkg_info, os.W_OK): + log.warn("Don't have permissions to write %s, skipping", pkg_info) + + log.warn('Creating %s', pkg_info) + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + + pth_file = os.path.join(placeholder, 'setuptools.pth') + log.warn('Creating %s', pth_file) + f = open(pth_file, 'w') + try: + f.write(os.path.join(os.curdir, setuptools_file)) + finally: + f.close() + +_create_fake_setuptools_pkg_info = _no_sandbox( + _create_fake_setuptools_pkg_info +) + + +def _patch_egg_dir(path): + # let's check if it's already patched + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + if os.path.exists(pkg_info): + if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): + log.warn('%s already patched.', pkg_info) + return False + _rename_path(path) + os.mkdir(path) + os.mkdir(os.path.join(path, 'EGG-INFO')) + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + return True + +_patch_egg_dir = _no_sandbox(_patch_egg_dir) + + +def _before_install(): + log.warn('Before install bootstrap.') + _fake_setuptools() + + +def _under_prefix(location): + if 'install' not in sys.argv: + return True + args = sys.argv[sys.argv.index('install') + 1:] + for index, arg in enumerate(args): + for option in ('--root', '--prefix'): + if arg.startswith('%s=' % option): + top_dir = arg.split('root=')[-1] + return location.startswith(top_dir) + elif arg == option: + if len(args) > index: + top_dir = args[index + 1] + return location.startswith(top_dir) + if arg == '--user' and USER_SITE is not None: + return location.startswith(USER_SITE) + return True + + +def _fake_setuptools(): + log.warn('Scanning installed packages') + try: + import pkg_resources + except ImportError: + # we're cool + log.warn('Setuptools or Distribute does not seem to be installed.') + return + ws = pkg_resources.working_set + try: + setuptools_dist = ws.find( + pkg_resources.Requirement.parse('setuptools', replacement=False) + ) + except TypeError: + # old distribute API + setuptools_dist = ws.find( + pkg_resources.Requirement.parse('setuptools') + ) + + if setuptools_dist is None: + log.warn('No setuptools distribution found') + return + # detecting if it was already faked + setuptools_location = setuptools_dist.location + log.warn('Setuptools installation detected at %s', setuptools_location) + + # if --root or --preix was provided, and if + # setuptools is not located in them, we don't patch it + if not _under_prefix(setuptools_location): + log.warn('Not patching, --root or --prefix is installing Distribute' + ' in another location') + return + + # let's see if its an egg + if not setuptools_location.endswith('.egg'): + log.warn('Non-egg installation') + res = _remove_flat_installation(setuptools_location) + if not res: + return + else: + log.warn('Egg installation') + pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') + if (os.path.exists(pkg_info) and + _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): + log.warn('Already patched.') + return + log.warn('Patching...') + # let's create a fake egg replacing setuptools one + res = _patch_egg_dir(setuptools_location) + if not res: + return + log.warn('Patched done.') + _relaunch() + + +def _relaunch(): + log.warn('Relaunching...') + # we have to relaunch the process + # pip marker to avoid a relaunch bug + _cmd = ['-c', 'install', '--single-version-externally-managed'] + if sys.argv[:3] == _cmd: + sys.argv[0] = 'setup.py' + args = [sys.executable] + sys.argv + sys.exit(subprocess.call(args)) + + +def _extractall(self, path=".", members=None): + """Extract all members from the archive to the current working + directory and set owner, modification time and permissions on + directories afterwards. `path' specifies a different directory + to extract to. `members' is optional and must be a subset of the + list returned by getmembers(). + """ + import copy + import operator + from tarfile import ExtractError + directories = [] + + if members is None: + members = self + + for tarinfo in members: + if tarinfo.isdir(): + # Extract directories with a safe mode. + directories.append(tarinfo) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 448 # decimal for oct 0700 + self.extract(tarinfo, path) + + # Reverse sort directories. + if sys.version_info < (2, 4): + def sorter(dir1, dir2): + return cmp(dir1.name, dir2.name) + directories.sort(sorter) + directories.reverse() + else: + directories.sort(key=operator.attrgetter('name'), reverse=True) + + # Set correct owner, mtime and filemode on directories. + for tarinfo in directories: + dirpath = os.path.join(path, tarinfo.name) + try: + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) + except ExtractError: + e = sys.exc_info()[1] + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + +def _build_install_args(argv): + install_args = [] + user_install = '--user' in argv + if user_install and sys.version_info < (2, 6): + log.warn("--user requires Python 2.6 or later") + raise SystemExit(1) + if user_install: + install_args.append('--user') + return install_args + + +def main(argv, version=DEFAULT_VERSION): + """Install or upgrade setuptools and EasyInstall""" + tarball = download_setuptools() + _install(tarball, _build_install_args(argv)) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/doc/README.txt b/doc/README.txt index 7d0ca4b68378..9ae05cb477bc 100644 --- a/doc/README.txt +++ b/doc/README.txt @@ -39,6 +39,15 @@ for the initial run (which builds the example gallery) to be done, then run "python make.py html" again. The top file of the results will be ./build/html/index.html +Note that Sphinx uses the installed version of the package to build +the documentation, so matplotlib must be installed *before* the docs +can be generated. Even if that is the case, one of the files needed +to do this, '../lib/matplotlib/mpl-data/matplotlibrc', is not version +controlled, but created when matplotlib is built. This means that the +documentation cannot be generated immediately after checking out the +source code, even if matplotlib is installed on your system: you will +have to run ``python setup.py build`` first. + To build a smaller version of the documentation (without high-resolution PNGs and PDF examples), type "python make.py --small html". diff --git a/doc/_static/logo_sidebar_horiz.png b/doc/_static/logo_sidebar_horiz.png index b9bf002c1c62..cb543d4101a1 100644 Binary files a/doc/_static/logo_sidebar_horiz.png and b/doc/_static/logo_sidebar_horiz.png differ diff --git a/doc/_static/mpl.css b/doc/_static/mpl.css index 7aa01b731654..bd174f670d49 100644 --- a/doc/_static/mpl.css +++ b/doc/_static/mpl.css @@ -505,3 +505,64 @@ ul.search li div.context { ul.keywordmatches li.goodmatch a { font-weight: bold; } + +table.docutils { + border-spacing: 2px; + border-collapse: collapse; + border-top-width: 1px; + border-right-width: 0px; + border-bottom-width: 1px; + border-left-width: 0px; +} + +table.docutils tr:nth-child(even) { + background-color: #F3F3FF; +} +table.docutils tr:nth-child(odd) { + background-color: #FFFFEE; +} + +table.docutils tr { + border-style: solid none solid none; + border-width: 1px 0 1px 0; + border-color: #AAAAAA; +} + +table.docutils th { + padding: 1px 8px 1px 5px; +} + +table.docutils td { + border-width: 1px 0 1px 0; +} + +#matplotlib-examples ul li{ + font-size: large; +} + +#matplotlib-examples ul li ul{ + margin-bottom:20px; + overflow:hidden; + border-top:1px solid #ccc; +} + +#matplotlib-examples ul li ul li { + font-size: small; + line-height:1.75em; + display:inline; + float: left; + width: 22em; +} + +#overview ul li ul{ + margin-bottom:20px; + overflow:hidden; + border-top:1px solid #ccc; +} + +#overview ul li ul li { + display:inline; + float: left; + width: 30em; +} + diff --git a/doc/_static/webagg_screenshot.png b/doc/_static/webagg_screenshot.png new file mode 100644 index 000000000000..7480241a593d Binary files /dev/null and b/doc/_static/webagg_screenshot.png differ diff --git a/doc/_templates/index.html b/doc/_templates/index.html index 1d88871b96f6..2768472bc8c8 100644 --- a/doc/_templates/index.html +++ b/doc/_templates/index.html @@ -1,34 +1,44 @@ {% extends "layout.html" %} {% set title = 'matplotlib: python plotting' %} +{% block extrahead %} + + + {{ super() }} +{% endblock %} {% block body %} -

John Hunter (1968-2012)

- - - - - - -
- - -

- On August 28 2012, John D. Hunter, the creator of matplotlib, died - from complications arising from cancer treatment, after a brief but - intense battle with this terrible illness. John is survived by his - wife Miriam, his three daughters Rahel, Ava and Clara, his sisters - Layne and Mary, and his mother Sarah.

- -

- If you have benefited from John's many contributions, please say - thanks in the way that would matter most to him. Please consider - making a donation to - the John Hunter Memorial - Fund.

-
-

Introduction

matplotlib is a python 2D plotting library which produces @@ -66,6 +76,32 @@

Introduction

properties, axes properties, etc, via an object oriented interface or via a set of functions familiar to MATLAB users.

+
+

John Hunter (1968-2012)

+ + + + + +
+ + +

+ On August 28 2012, John D. Hunter, the creator of matplotlib, died + from complications arising from cancer treatment, after a brief but + intense battle with this terrible illness. John is survived by his + wife Miriam, his three daughters Rahel, Ava and Clara, his sisters + Layne and Mary, and his mother Sarah.

+ +

+ If you have benefited from John's many contributions, please say + thanks in the way that would matter most to him. Please consider + making a donation to + the John Hunter Memorial + Fund.

+
+
+

Download

Visit the @@ -132,41 +168,41 @@

Need help?

Toolkits

-

There are several matplotlib add-on toolkits, including the projection -and mapping toolkit -basemap, 3d plotting with mplot3d, axes and axis helpers in axes_grid and more. +

There are several matplotlib add-on toolkits, +including a choice of two projection and mapping toolkits basemap and +cartopy, +3d plotting with mplot3d, +axes and axis helpers in axes_grid and more.

Citing matplotlib

- matplotlib is the brainchild of John Hunter (1968-2012), who has put an - inordinate amount of effort into producing a piece of software utilized by - thousands of scientists worldwide. + matplotlib is the brainchild of John Hunter (1968-2012), who, along with its many + contributors, have put an immeasurable amount of time and effort into producing a + piece of software utilized by thousands of scientists worldwide. If matplotlib contributes to a project that leads to a scientific publication, - please acknowledge this fact by citing the project. You can use this + please acknowledge this work by citing the project. You can use this ready-made citation entry.

Open source

-

Please -consider donating -to support matplotlib development or to -the John Hunter Memorial -Fund.

+

+Please consider donating +to support matplotlib development or to the John Hunter Memorial Fund. +

-

The matplotlib license -is based on the Python Software Foundation -(PSF) license.

+

+The matplotlib license is based on the Python Software Foundation +(PSF) license. +

-

There is an active developer community and a long list of people -who have made significant contributions.

+

+There is an active developer community and a long list of people +who have made significant contributions. +

@@ -178,6 +214,4 @@

Open source

Mathematica is a registered trademark of Wolfram Research, Inc.

- - {% endblock %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index ea623edd65e4..890ffcc2f009 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -1,44 +1,10 @@ {% extends "!layout.html" %} - - {% block rootrellink %}
  • home
  • -
  • downloads
  • -
  • search
  • examples
  • gallery
  • -
  • citation
  • +
  • pyplot
  • docs »
  • {% endblock %} diff --git a/doc/_templates/search.html b/doc/_templates/search.html index 83fd18e7d70b..f24c6ab13fd8 100644 --- a/doc/_templates/search.html +++ b/doc/_templates/search.html @@ -10,7 +10,7 @@

    {{ _('Search') }}

    words. Pages containing less words won't appear in the result list.{% endtrans %} If you want to limit your search to working code examples, include the keyword "codex" (mnemonic for code example) in your - search, eg "codex ellipse"; + search, e.g., "codex ellipse"; see search examples.

    diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index f15e608c0596..a80ce9a223d7 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -11,6 +11,187 @@ help figure out possible sources of the changes you are experiencing. For new features that were added to matplotlib, please see :ref:`whats-new`. + +.. _changes_in_1_3: + +Changes in 1.3.x +================ + +* On Linux, the user-specific `matplotlibrc` configuration file is now + located in `~/.config/matplotlib/matplotlibrc` to conform to the + `XDG Base Directory Specification + `_. + +* The following items that were deprecated in version 1.2 or earlier + have now been removed completely. + + - The Qt 3.x backends (`qt` and `qtagg`) have been removed in + favor of the Qt 4.x backends (`qt4` and `qt4agg`). + + - The FltkAgg and Emf backends have been removed. + + - The `matplotlib.nxutils` module has been removed. Use the + functionality on `matplotlib.path.Path.contains_point` and + friends instead. + + - Instead of `axes.Axes.get_frame`, use `axes.Axes.patch`. + + - The following `kwargs` to the `legend` function have been + renamed: + + - `pad` -> `borderpad` + - `labelsep` -> `labelspacing` + - `handlelen` -> `handlelength` + - `handletextsep` -> `handletextpad` + - `axespad` -> `borderaxespad` + + Related to this, the following rcParams have been removed: + + - `legend.pad`, `legend.labelsep`, `legend.handlelen`, + `legend.handletextsep` and `legend.axespad` + + - For the `hist` function, instead of `width`, use `rwidth` + (relative width). + + - On `patches.Circle`, the `resolution` kwarg has been removed. + For a circle made up of line segments, use + `patches.CirclePolygon`. + + - The printing functions in the Wx backend have been removed due + to the burden of keeping them up-to-date. + + - `mlab.liaupunov` has been removed. + + - `mlab.save`, `mlab.load`, `pylab.save` and `pylab.load` have + been removed. We recommend using `numpy.savetxt` and + `numpy.loadtxt` instead. + + - `widgets.HorizontalSpanSelector` has been removed. Use + `widgets.SpanSelector` instead. + +* The CocoaAgg backend has been deprecated, with the possibility for + deletion or resurrection in a future release. + +* The top-level functions in `matplotlib.path` that are implemented in + C++ were never meant to be public. Instead, users should use the + Pythonic wrappers for them in the `path.Path` and + `collections.Collection` classes. Use the following mapping to update + your code: + + - `point_in_path` -> `path.Path.contains_point` + - `get_path_extents` -> `path.Path.get_extents` + - `point_in_path_collection` -> `collection.Collection.contains` + - `path_in_path` -> `path.Path.contains_path` + - `path_intersects_path` -> `path.Path.intersects_path` + - `convert_path_to_polygons` -> `path.Path.to_polygons` + - `cleanup_path` -> `path.Path.cleaned` + - `points_in_path` -> `path.Path.contains_points` + - `clip_path_to_rect` -> `path.Path.clip_to_bbox` + +* `Path` objects can now be marked as `readonly` by passing + `readonly=True` to its constructor. The built-in path singletons, + obtained through `Path.unit*` class methods return readonly paths. + If you have code that modified these, you will need to make a + deepcopy first, using either:: + + import copy + path = copy.deepcopy(Path.unit_circle()) + + # or + + path = Path.unit_circle().deepcopy() + + Deep copying a `Path` always creates an editable (i.e. non-readonly) + `Path`. + +* matplotlib.colors.normalize and matplotlib.colors.no_norm have been + deprecated in favour of matplotlib.colors.Normalize and + matplotlib.colors.NoNorm respectively. + +* The `font.*` rcParams now affect only text objects created after the + rcParam has been set, and will not retroactively affect already + existing text objects. This brings their behavior in line with most + other rcParams. + +* To support XKCD style plots, the :func:`matplotlib.path.cleanup_path` + method's signature was updated to require a sketch argument. Users of + :func:`matplotlib.path.cleanup_path` are encouraged to use the new + :meth:`~matplotlib.path.Path.cleaned` Path method. + +* The list at ``Path.NUM_VERTICES`` was replaced by a dictionary mapping + Path codes to the number of expected vertices at + :attr:`~matplotlib.path.Path.NUM_VERTICES_FOR_CODE`. + +* Fixed a bug in setting the position for the right/top spine with data + position type. Previously, it would draw the right or top spine at + +1 data offset. + +* The ScalarMappable class' set_colorbar is now deprecated. Instead, the + :attr:`matplotlib.cm.ScalarMappable.colorbar` attribute should be used. + In previous matplotlib versions this attribute was an undocumented tuple + of ``(colorbar_instance, colorbar_axes)`` but is now just + ``colorbar_instance``. To get the colorbar axes it is possible to just use + the :attr:`~matplotlib.colorbar.ColorbarBase.ax` attribute on a colorbar + isntance. + +* In :class:`~matplotlib.patches.FancyArrow`, the default arrow head width, + ``head_width``, has been made larger to produce a visible arrow head. The new + value of this kwarg is ``head_width = 20 * width``. + +* Removed call of :meth:`~matplotlib.axes.Axes.grid` in + :meth:`~matplotlib.pyplot.plotfile`. To draw the axes grid, set the + ``axes.grid`` rcParam to *True*, or explicitly call + :meth:`~matplotlib.axes.Axes.grid`. + +* It is now posible to provide ``number of levels + 1`` colors in the case of + `extend='both'` for contourf (or just ``number of levels`` colors for an + extend value ``min`` or ``max``) such that the resulting colormap's + ``set_under`` and ``set_over`` are defined appropriately. Any other number + of colors will continue to behave as before (if more colors are provided + than levels, the colors will be unused). A similar change has been applied + to contour, where ``extend='both'`` would expect ``number of levels + 2`` + colors. + +* A new keyword *extendrect* in :meth:`~matplotlib.pyplot.colorbar` and + :class:`~matplotlib.colorbar.ColorbarBase` allows one to control the shape + of colorbar extensions. + +* The `~matplotlib.mpl` module is now deprecated. Those who relied on this + module should transition to simply using ``import matplotlib as mpl``. + +* The extension of :class:`~matplotlib.widgets.MultiCursor` to both vertical + (default) and/or horizontal cursor implied that ``self.line`` is replaced + by ``self.vline`` for vertical cursors lines and ``self.hline`` is added + for the horizontal cursors lines. + +* On POSIX platforms, the :func:`~matplotlib.cbook.report_memory` function + raises :class:`NotImplementedError` instead of :class:`OSError` if the + :command:`ps` command cannot be run. + +* The :func:`matplotlib.cbook.check_output` function has been moved to + :func:`matplotlib.compat.subprocess`. + +* :class:`~matplotlib.patches.Patch` now fully supports using RGBA values for + its ``facecolor`` and ``edgecolor`` attributes, which enables faces and + edges to have different alpha values. If the + :class:`~matplotlib.patches.Patch` object's ``alpha`` attribute is set to + anything other than ``None``, that value will override any alpha-channel + value in both the face and edge colors. Previously, if + :class:`~matplotlib.patches.Patch` had ``alpha=None``, the alpha component + of ``edgecolor`` would be applied to both the edge and face. + +* The optional ``isRGB`` argument to + :meth:`~matplotlib.backend_bases.GraphicsContextBase.set_foreground` (and + the other GraphicsContext classes that descend from it) has been renamed to + ``isRGBA``, and should now only be set to ``True`` if the ``fg`` color + argument is known to be an RGBA tuple. + +* For :class:`~matplotlib.patches.Patch`, the ``capstyle`` used is now + ``butt``, to be consistent with the default for most other objects, and to + avoid problems with non-solid ``linestyle`` appearing solid when using a + large ``linewidth``. Previously, :class:`~matplotlib.patches.Patch` used + ``capstyle='projecting'``. + Changes in 1.2.x ================ @@ -66,7 +247,7 @@ Changes in 1.2.x projection = kwargs.pop('projection', None) if ispolar: if projection is not None and projection != 'polar': - raise ValuError('polar and projection args are inconsistent') + raise ValueError('polar and projection args are inconsistent') projection = 'polar' ax = projection_factory(projection, self, rect, **kwargs) key = self._make_key(*args, **kwargs) @@ -325,7 +506,7 @@ Changes in 0.99 * Axes instances no longer have a "frame" attribute. Instead, use the new "spines" attribute. Spines is a dictionary where the keys are - the names of the spines (e.g. 'left','right' and so on) and the + the names of the spines (e.g., 'left','right' and so on) and the values are the artists that draw the spines. For normal (rectilinear) axes, these artists are Line2D instances. For other axes (such as polar axes), these artists may be Patch instances. @@ -517,7 +698,7 @@ The view intervals are now stored only in one place -- in the as well. This means locators must get their limits from their :class:`matplotlib.axis.Axis`, which in turn looks up its limits from the :class:`~matplotlib.axes.Axes`. If a locator is used temporarily -and not assigned to an Axis or Axes, (e.g. in +and not assigned to an Axis or Axes, (e.g., in :mod:`matplotlib.contour`), a dummy axis must be created to store its bounds. Call :meth:`matplotlib.ticker.Locator.create_dummy_axis` to do so. @@ -794,7 +975,7 @@ Changes for 0.91.0 * Changed :func:`cbook.reversed` so it yields a tuple rather than a (index, tuple). This agrees with the python reversed builtin, - and cbook only defines reversed if python doesnt provide the + and cbook only defines reversed if python doesn't provide the builtin. * Made skiprows=1 the default on :func:`csv2rec` @@ -812,7 +993,7 @@ Changes for 0.91.0 fonts. Currently it simply reads pfa and pfb format files and stores the data in a way that is suitable for embedding in pdf files. In the future the class might actually parse the font to - allow e.g. subsetting. + allow e.g., subsetting. * :mod:`matplotlib.FT2Font` now supports :meth:`FT_Attach_File`. In practice this can be used to read an afm file in addition to a @@ -832,7 +1013,7 @@ Changes for 0.91.0 should be changed to ``${\cal R}$``. Alternatively, you may use the new LaTeX-style font commands (``\mathcal``, ``\mathrm``, ``\mathit``, ``\mathtt``) which do affect the following group, - eg. ``$\mathcal{R}$``. + e.g., ``$\mathcal{R}$``. * Text creation commands have a new default linespacing and a new ``linespacing`` kwarg, which is a multiple of the maximum vertical @@ -879,13 +1060,13 @@ Changes for 0.90.1 units.AxisInfo object rather than a tuple. This will make it easier to add axis info functionality (eg I added a default label on this iteration) w/o having to change the tuple length and hence - the API of the client code everytime new functionality is added. + the API of the client code every time new functionality is added. Also, units.ConversionInterface.convert_to_value is now simply named units.ConversionInterface.convert. Axes.errorbar uses Axes.vlines and Axes.hlines to draw its error limits int he vertical and horizontal direction. As you'll see - in the changes below, these funcs now return a LineCollection + in the changes below, these functions now return a LineCollection rather than a list of lines. The new return signature for errorbar is ylins, caplines, errorcollections where errorcollections is a xerrcollection, yerrcollection @@ -903,7 +1084,7 @@ Changes for 0.90.1 Barh now takes a **kwargs dict instead of most of the old arguments. This helps ensure that bar and barh are kept in sync, - but as a side effect you can no longer pass e.g. color as a + but as a side effect you can no longer pass e.g., color as a positional argument. ft2font.get_charmap() now returns a dict that maps character codes @@ -970,7 +1151,7 @@ Changes for 0.87.7 markeredgecolor and markerfacecolor cannot be configured in matplotlibrc any more. Instead, markers are generally colored automatically based on the color of the line, unless marker colors - are explicitely set as kwargs - NN + are explicitly set as kwargs - NN Changed default comment character for load to '#' - JDH @@ -1146,7 +1327,7 @@ Changes for 0.83 - Made HOME/.matplotlib the new config dir where the matplotlibrc file, the ttf.cache, and the tex.cache live. The new default filenames in .matplotlib have no leading dot and are not hidden. - Eg, the new names are matplotlibrc, tex.cache, and ttffont.cache. + e.g., the new names are matplotlibrc, tex.cache, and ttffont.cache. This is how ipython does it so it must be right. If old files are found, a warning is issued and they are moved to @@ -1185,7 +1366,7 @@ Changes for 0.82 I see that hist uses the linspace function to create the bins and then uses searchsorted to put the values in their correct - bin. Thats all good but I am confused over the use of linspace + bin. That's all good but I am confused over the use of linspace for the bin creation. I wouldn't have thought that it does what is needed, to quote the docstring it creates a "Linear spaced array from min to max". For it to work correctly @@ -1381,7 +1562,7 @@ Changes for 0.65.1 removed add_axes and add_subplot from backend_bases. Use figure.add_axes and add_subplot instead. The figure now manages the - current axes with gca and sca for get and set current axe. If you + current axes with gca and sca for get and set current axes. If you have code you are porting which called, eg, figmanager.add_axes, you can now simply do figmanager.canvas.figure.add_axes. @@ -1415,7 +1596,7 @@ Changes for 0.63 Most of the date tick locators have a different meaning in their constructors. In the prior implementation, the first argument was a - base and multiples of the base were ticked. Eg + base and multiples of the base were ticked. e.g., HourLocator(5) # old: tick every 5 minutes @@ -1449,7 +1630,7 @@ Changes for 0.61 canvas.connect is now deprecated for event handling. use mpl_connect and mpl_disconnect instead. The callback signature is - func(event) rather than func(widget, evet) + func(event) rather than func(widget, event) Changes for 0.60 ================ @@ -1593,7 +1774,7 @@ Bounding boxes bbox = clickBBox = lbwh_to_bbox(left, bottom, width, height) - The Bbox has a different API than the Bound2D. Eg, if you want to + The Bbox has a different API than the Bound2D. e.g., if you want to get the width and height of the bbox OLD:: @@ -1613,7 +1794,7 @@ Object constructors You no longer pass the bbox, dpi, or transforms to the various Artist constructors. The old way or creating lines and rectangles was cumbersome because you had to pass so many attributes to the - Line2D and Rectangle classes not related directly to the gemoetry + Line2D and Rectangle classes not related directly to the geometry and properties of the object. Now default values are added to the object when you call axes.add_line or axes.add_patch, so they are hidden from the user. @@ -1642,18 +1823,18 @@ Transformations The entire transformation architecture has been rewritten. Previously the x and y transformations where stored in the xaxis and - yaxis insstances. The problem with this approach is it only allows + yaxis instances. The problem with this approach is it only allows for separable transforms (where the x and y transformations don't depend on one another). But for cases like polar, they do. Now transformations operate on x,y together. There is a new base class matplotlib.transforms.Transformation and two concrete - implemetations, matplotlib.transforms.SeparableTransformation and + implementations, matplotlib.transforms.SeparableTransformation and matplotlib.transforms.Affine. The SeparableTransformation is constructed with the bounding box of the input (this determines the rectangular coordinate system of the input, ie the x and y view - limits), the bounding box of the display, and possibily nonlinear + limits), the bounding box of the display, and possibly nonlinear transformations of x and y. The 2 most frequently used - transformations, data cordinates -> display and axes coordinates -> + transformations, data coordinates -> display and axes coordinates -> display are available as ax.transData and ax.transAxes. See alignment_demo.py which uses axes coords. @@ -1741,7 +1922,7 @@ Changes for 0.50 There is one important API change for application developers. Figure instances used subclass GUI widgets that enabled them to be - placed directly into figures. Eg, FigureGTK subclassed + placed directly into figures. e.g., FigureGTK subclassed gtk.DrawingArea. Now the Figure class is independent of the backend, and FigureCanvas takes over the functionality formerly handled by Figure. In order to include figures into your apps, @@ -1783,7 +1964,7 @@ Changes for 0.42 * backend_bases.AxisTextBase is now text.Text module - * All the erase and reset functionality removed frmo AxisText - not + * All the erase and reset functionality removed from AxisText - not needed with double buffered drawing. Ditto with state change. Text instances have a get_prop_tup method that returns a hashable tuple of text properties which you can use to see if text props diff --git a/doc/api/cm_api.rst b/doc/api/cm_api.rst index 86b87cd4cda7..6cf4a262a62d 100644 --- a/doc/api/cm_api.rst +++ b/doc/api/cm_api.rst @@ -2,7 +2,6 @@ cm (colormap) ************* - :mod:`matplotlib.cm` ==================== diff --git a/doc/api/colors_api.rst b/doc/api/colors_api.rst index 766eb763f612..bd577af02ed4 100644 --- a/doc/api/colors_api.rst +++ b/doc/api/colors_api.rst @@ -2,6 +2,9 @@ colors ****** +For a visual representation of the matplotlib colormaps, see the +"Color" section in the gallery. + :mod:`matplotlib.colors` ======================== diff --git a/doc/api/index.rst b/doc/api/index.rst index f6c05695b3dd..1713b439c411 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -31,14 +31,15 @@ font_manager_api.rst gridspec_api.rst legend_api.rst + markers_api.rst mathtext_api.rst mlab_api.rst - nxutils_api.rst path_api.rst pyplot_api.rst sankey_api.rst spines_api.rst ticker_api.rst tight_layout_api.rst + tri_api.rst units_api.rst widgets_api.rst diff --git a/doc/api/markers_api.rst b/doc/api/markers_api.rst new file mode 100644 index 000000000000..11e35f98638e --- /dev/null +++ b/doc/api/markers_api.rst @@ -0,0 +1,12 @@ +******* +Markers +******* + + +:mod:`matplotlib.markers` +========================= + +.. automodule:: matplotlib.markers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/matplotlib_configuration_api.rst b/doc/api/matplotlib_configuration_api.rst index e8788289d162..2abbae33678d 100644 --- a/doc/api/matplotlib_configuration_api.rst +++ b/doc/api/matplotlib_configuration_api.rst @@ -1,13 +1,37 @@ -************* -configuration -************* +The top level :mod:`matplotlib` module +====================================== -:mod:`matplotlib` -================= +.. py:currentmodule:: matplotlib -.. automodule:: matplotlib - :members: rc, rcdefaults, use - :undoc-members: - :show-inheritance: +.. autofunction:: use +.. autofunction:: get_backend + +.. py:data:: matplotlib.rcParams + + An instance of :class:`RcParams` for handling default matplotlib values. + +.. autofunction:: rc + +.. autofunction::rcdefaults + +.. autofunction::rc_file + +.. autofunction::rc_context + +.. autofunction:: matplotlib_fname + +.. autofunction::rc_file_defaults + +.. autofunction::interactive + +.. autofunction::is_interactive + +.. autoclass:: RcParams + +.. autofunction:: rc_params + +.. autofunction:: rc_params_from_file + +.. autoclass:: rc_context diff --git a/doc/api/nxutils_api.rst b/doc/api/nxutils_api.rst deleted file mode 100644 index 6c17d8341370..000000000000 --- a/doc/api/nxutils_api.rst +++ /dev/null @@ -1,12 +0,0 @@ -******* -nxutils -******* - -:mod:`matplotlib.nxutils` -=========================== - -.. automodule:: matplotlib.nxutils - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/api/tri_api.rst b/doc/api/tri_api.rst new file mode 100644 index 000000000000..8ede2a9beb28 --- /dev/null +++ b/doc/api/tri_api.rst @@ -0,0 +1,35 @@ +**************** +triangular grids +**************** + +:mod:`matplotlib.tri` +===================== +.. automodule:: matplotlib.tri + +.. autoclass:: matplotlib.tri.Triangulation + :members: + +.. autoclass:: matplotlib.tri.TriFinder + +.. autoclass:: matplotlib.tri.TrapezoidMapTriFinder + :members: __call__ + :show-inheritance: + +.. autoclass:: matplotlib.tri.TriInterpolator + +.. autoclass:: matplotlib.tri.LinearTriInterpolator + :members: __call__, gradient + :show-inheritance: + +.. autoclass:: matplotlib.tri.CubicTriInterpolator + :members: __call__, gradient + :show-inheritance: + +.. autoclass:: matplotlib.tri.TriRefiner + +.. autoclass:: matplotlib.tri.UniformTriRefiner + :show-inheritance: + :members: + +.. autoclass:: matplotlib.tri.TriAnalyzer + :members: diff --git a/doc/conf.py b/doc/conf.py index 2127500966fb..0c786ba2fa04 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -11,7 +11,9 @@ # All configuration values have a default value; values that are commented out # serve to show the default value. -import sys, os +import os +import sys +import sphinx # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it @@ -25,10 +27,25 @@ # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['matplotlib.sphinxext.mathmpl', 'sphinxext.math_symbol_table', 'sphinx.ext.autodoc', 'matplotlib.sphinxext.only_directives', - 'sphinx.ext.doctest', + 'sphinx.ext.doctest', 'sphinx.ext.autosummary', 'matplotlib.sphinxext.plot_directive', 'sphinx.ext.inheritance_diagram', 'sphinxext.gen_gallery', 'sphinxext.gen_rst', - 'matplotlib.sphinxext.ipython_console_highlighting', 'sphinxext.github'] + 'matplotlib.sphinxext.ipython_console_highlighting', + 'sphinxext.github', + 'numpydoc'] + + +try: + import numpydoc +except ImportError: + raise ImportError("No module named numpydoc - you need to install " + "numpydoc to build the documentation.") + + +autosummary_generate = True + +if sphinx.__version__ >= 1.1: + autodoc_docstring_signature = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -47,7 +64,12 @@ # other places throughout the built documents. # # The short X.Y version. -import matplotlib +try: + import matplotlib +except ImportError: + msg = "Error: matplotlib must be installed before building the documentation" + sys.exit(msg) + version = matplotlib.__version__ # The full version, including alpha/beta/rc tags. release = version @@ -82,6 +104,28 @@ plot_formats = [('png', 80), ('hires.png', 200), ('pdf', 50)] +# Subdirectories in 'examples/' directory of package and titles for gallery +mpl_example_sections = ( + ('lines_bars_and_markers', 'Lines, bars, and markers'), + ('shapes_and_collections', 'Shapes and collections'), + ('statistics', 'Statistical plots'), + ('images_contours_and_fields', 'Images, contours, and fields'), + ('pie_and_polar_charts', 'Pie and polar charts'), + ('color', 'Color'), + ('text_labels_and_annotations', 'Text, labels, and annotations'), + ('ticks_and_spines', 'Ticks and spines'), + ('subplots_axes_and_figures', 'Subplots, axes, and figures'), + ('specialty_plots', 'Specialty plots'), + ('showcase', 'Showcase'), + ('api', 'API'), + ('pylab_examples', 'pylab examples'), + ('mplot3d', 'mplot3d toolkit'), + ('axes_grid', 'axes_grid toolkit'), + ('units', 'units'), + ('widgets', 'widgets'), + ) + + # Github extension github_project_url = "http://github.com/matplotlib/matplotlib/" @@ -133,10 +177,13 @@ # Additional templates that should be rendered to pages, maps page names to # template names. -html_additional_pages = {'index': 'index.html', 'gallery':'gallery.html', 'citing':'citing.html'} +html_additional_pages = {'index': 'index.html', + 'gallery':'gallery.html', + 'citing': 'citing.html'} # If false, no module index is generated. #html_use_modindex = True +html_domain_indices = ["py-modindex"] # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True @@ -203,3 +250,9 @@ 'Matplotlib', "Python plotting package", 'Programming', 1), ] + + +################# numpydoc config #################### +numpydoc_show_class_members = False + + diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst index a796d57afce2..7273fb38313d 100644 --- a/doc/devel/coding_guide.rst +++ b/doc/devel/coding_guide.rst @@ -105,6 +105,25 @@ Installation ones, make sure the new files included in the match patterns in :file:`MANIFEST.in`, and/or in `package_data` in `setup.py`. +C/C++ extensions +---------------- + +* Extensions may be written in C or C++. + +* Code style should conform to PEP7 (understanding that PEP7 doesn't + address C++, but most of its admonitions still apply). + +* Interfacing with Python may be done either with the raw Python/C API + or Cython. Use of PyCXX is discouraged for new code. + +* Python/C interface code should be kept separate from the core C/C++ + code. The interface code should be named `FOO_wrap.cpp`. + +* Header file documentation (aka docstrings) should be in Numpydoc + format. We don't plan on using automated tools for these + docstrings, and the Numpydoc format is well understood in the + scientific Python community. + Style guide =========== diff --git a/doc/devel/documenting_mpl.rst b/doc/devel/documenting_mpl.rst index 24c3c0341b06..f43977cb4008 100644 --- a/doc/devel/documenting_mpl.rst +++ b/doc/devel/documenting_mpl.rst @@ -7,9 +7,9 @@ Documenting matplotlib Getting started =============== -The documentation for matplotlib is generated from ReStructured Text -using the Sphinx_ documentation generation tool. Sphinx-1.0 or later -is required. +The documentation for matplotlib is generated from ReStructured Text using the +Sphinx_ documentation generation tool. Sphinx-1.0 or later and numpydoc 0.4 or +later is required. The documentation sources are found in the :file:`doc/` directory in the trunk. To build the users guide in html format, cd into @@ -62,7 +62,7 @@ method in the :class:`~matplotlib.artist.Artist` class. Yes, this is not ideal given python properties or enthought traits, but it is a historical legacy for now. The setter methods use the docstring with the ACCEPTS token to indicate the type of argument the method accepts. -Eg. in :class:`matplotlib.lines.Line2D`:: +e.g., in :class:`matplotlib.lines.Line2D`:: # in lines.py def set_linestyle(self, linestyle): @@ -72,7 +72,7 @@ Eg. in :class:`matplotlib.lines.Line2D`:: ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' | ' ' | '' ] """ -Since matplotlib uses a lot of pass-through ``kwargs``, eg. in every +Since matplotlib uses a lot of pass-through ``kwargs``, e.g., in every function that creates a line (:func:`~matplotlib.pyplot.plot`, :func:`~matplotlib.pyplot.semilogx`, :func:`~matplotlib.pyplot.semilogy`, etc...), it can be difficult for @@ -98,7 +98,7 @@ docstring of ``kwargs``. Here is an example from artist.kwdocd['Line2D'] = artist.kwdoc(Line2D) Then in any function accepting :class:`~matplotlib.lines.Line2D` -pass-through ``kwargs``, eg. :meth:`matplotlib.axes.Axes.plot`:: +pass-through ``kwargs``, e.g., :meth:`matplotlib.axes.Axes.plot`:: # in axes.py def plot(self, *args, **kwargs): @@ -117,7 +117,7 @@ pass-through ``kwargs``, eg. :meth:`matplotlib.axes.Axes.plot`:: plot.__doc__ = cbook.dedent(plot.__doc__) % artist.kwdocd Note there is a problem for :class:`~matplotlib.artist.Artist` -``__init__`` methods, eg. :meth:`matplotlib.patches.Patch.__init__`, +``__init__`` methods, e.g., :meth:`matplotlib.patches.Patch.__init__`, which supports ``Patch`` ``kwargs``, since the artist inspector cannot work until the class is fully defined and we can't modify the ``Patch.__init__.__doc__`` docstring outside the class definition. @@ -139,7 +139,7 @@ working with Sphinx in general. Here are a few additional things to keep in mind ``:file:`` directive. * Function arguments and keywords should be referred to using the *emphasis* - role. This will keep matplotlib's documentation consistant with Python's + role. This will keep matplotlib's documentation consistent with Python's documentation:: Here is a description of *argument* @@ -360,7 +360,7 @@ Referring to mpl documents ========================== In the documentation, you may want to include to a document in the -matplotlib src, e.g. a license file or an image file from `mpl-data`, +matplotlib src, e.g., a license file or an image file from `mpl-data`, refer to it via a relative path from the document where the rst file resides, eg, in :file:`users/navigation_toolbar.rst`, we refer to the image icons with:: @@ -401,7 +401,7 @@ Internal section references =========================== To maximize internal consistency in section labeling and references, -use hypen separated, descriptive labels for section references, eg:: +use hyphen separated, descriptive labels for section references, eg:: .. _howto-webapp: @@ -411,7 +411,7 @@ and refer to it using the standard reference syntax:: Keep in mind that we may want to reorganize the contents later, so let's avoid top level names in references like ``user`` or ``devel`` -or ``faq`` unless necesssary, because for example the FAQ "what is a +or ``faq`` unless necessary, because for example the FAQ "what is a backend?" could later become part of the users guide, so the label:: .. _what-is-a-backend @@ -464,7 +464,7 @@ Emacs helpers There is an emacs mode `rst.el `_ which -automates many important ReST tasks like building and updateing +automates many important ReST tasks like building and updating table-of-contents, and promoting or demoting section headings. Here is the basic ``.emacs`` configuration:: diff --git a/doc/devel/gitwash/development_workflow.rst b/doc/devel/gitwash/development_workflow.rst index 147d94f9e6ba..2ef9ecbfb42a 100644 --- a/doc/devel/gitwash/development_workflow.rst +++ b/doc/devel/gitwash/development_workflow.rst @@ -106,7 +106,8 @@ In more detail Asking for code review ====================== -#. Go to your repo URL |emdash| e.g. ``http://github.com/your-user-name/matplotlib``. +#. Go to your repo URL |emdash| e.g., + ``http://github.com/your-user-name/matplotlib``. #. Click on the *Branch list* button: .. image:: branch_list.png diff --git a/doc/devel/release_guide.rst b/doc/devel/release_guide.rst index 7bb165803659..3cdc2740d6e8 100644 --- a/doc/devel/release_guide.rst +++ b/doc/devel/release_guide.rst @@ -1,8 +1,8 @@ .. _release-guide: -************************* -Doing a matplolib release -************************* +************************** +Doing a matplotlib release +************************** A guide for developers who are doing a matplotlib release. diff --git a/doc/devel/testing.rst b/doc/devel/testing.rst index cc1fafae7990..7d778041c68a 100644 --- a/doc/devel/testing.rst +++ b/doc/devel/testing.rst @@ -38,7 +38,7 @@ The script can take any of the usual `nosetest arguments`_, such as To run a single test from the command line, you can provide a dot-separated path to the module followed by the function separated by -a colon, eg. (this is assuming the test is installed):: +a colon, e.g., (this is assuming the test is installed):: python tests.py matplotlib.tests.test_simplification:test_clipping @@ -73,7 +73,7 @@ example, here is a test from :mod:`matplotlib.tests.test_basic`:: Nose determines which functions are tests by searching for functions beginning with "test" in their name. -If the test as side effects that need to be cleaned up, such as +If the test has side effects that need to be cleaned up, such as creating figures using the pyplot interface, use the ``@cleanup`` decorator:: @@ -182,8 +182,8 @@ Using tox `Tox `_ is a tool for running tests against multiple Python environments, including multiple versions of Python -(e.g.: 2.6, 2.7, 3.2, etc.) and even different Python implementations -altogether (e.g.: CPython, PyPy, Jython, etc.) +(e.g., 2.6, 2.7, 3.2, etc.) and even different Python implementations +altogether (e.g., CPython, PyPy, Jython, etc.) Testing all 4 versions of Python (2.6, 2.7, 3.1, and 3.2) requires having four versions of Python installed on your system and on the @@ -215,7 +215,7 @@ parallelized version of tox called ``detox``. Give this a try: $ detox Tox is configured using a file called ``tox.ini``. You may need to -edit this file if you want to add new environments to test (e.g.: +edit this file if you want to add new environments to test (e.g., ``py33``) or if you want to tweak the dependencies or the way the tests are run. For more info on the ``tox.ini`` file, see the `Tox Configuration Specification diff --git a/doc/faq/howto_faq.rst b/doc/faq/howto_faq.rst index 75b8c3d0578f..d3cf31e515c4 100644 --- a/doc/faq/howto_faq.rst +++ b/doc/faq/howto_faq.rst @@ -55,7 +55,7 @@ the alpha properties directly. The figure has a :class:`~matplotlib.patches.Rectangle` instance called *patch* and the axes has a Rectangle instance called *patch*. You can set any property on them directly (*facecolor*, *edgecolor*, *linewidth*, -*linestyle*, *alpha*). Eg:: +*linestyle*, *alpha*). e.g.:: fig = plt.figure() fig.patch.set_alpha(0.5) @@ -64,7 +64,7 @@ any property on them directly (*facecolor*, *edgecolor*, *linewidth*, If you need *all* the figure elements to be transparent, there is currently no global alpha setting, but you can set the alpha channel -on individual elements, eg:: +on individual elements, e.g.:: ax.plot(x, y, alpha=0.5) ax.set_xlabel('volts', alpha=0.5) @@ -496,7 +496,7 @@ and :ref:`what-is-a-backend`). Therefore, multiple calls to ``show`` are now allowed. Having ``show`` block further execution of the script or the python -interperator depends on whether matplotlib is set for interactive mode +interpreter depends on whether matplotlib is set for interactive mode or not. In non-interactive mode (the default setting), execution is paused until the last figure window is closed. In interactive mode, the execution is not paused, which allows you to create additional figures (but the script diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst index 6374d94875cd..ab2c90c7c92d 100644 --- a/doc/faq/installing_faq.rst +++ b/doc/faq/installing_faq.rst @@ -139,7 +139,7 @@ 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):: - > python setupegg.py develop + > python setup.py develop This creates links in the right places and installs the command line script to the appropriate places. diff --git a/doc/faq/troubleshooting_faq.rst b/doc/faq/troubleshooting_faq.rst index 9a98ac70a83a..4fa757e21aa5 100644 --- a/doc/faq/troubleshooting_faq.rst +++ b/doc/faq/troubleshooting_faq.rst @@ -37,10 +37,10 @@ and printing the ``__file__`` attribute:: :file:`.matplotlib` directory location ====================================== -Each user has a :file:`.matplotlib/` directory which may contain a -:ref:`matplotlibrc ` file and various -caches to improve matplotlib's performance. To locate your :file:`.matplotlib/` -directory, use :func:`matplotlib.get_configdir`:: +Each user has a matplotlib configuration directory which may contain a +:ref:`matplotlibrc ` file. To +locate your :file:`.matplotlib/` directory, use +:func:`matplotlib.get_configdir`:: >>> import matplotlib as mpl >>> mpl.get_configdir() @@ -86,7 +86,7 @@ please provide the following information in your e-mail to the python -c `import matplotlib; print matplotlib.__version__` - * where you obtained matplotlib (e.g. your Linux distribution's + * where you obtained matplotlib (e.g., your Linux distribution's packages or the matplotlib Sourceforge site, or the enthought python distribution `EPD `_). diff --git a/doc/faq/usage_faq.rst b/doc/faq/usage_faq.rst index e107c1e6ae7e..5d17b9c34e36 100644 --- a/doc/faq/usage_faq.rst +++ b/doc/faq/usage_faq.rst @@ -164,12 +164,11 @@ others in web application servers to dynamically serve up graphs. To support all of these use cases, matplotlib can target different outputs, and each of these capabilities is called a backend; the "frontend" is the user facing code, ie the plotting code, whereas the -"backend" does all the hard work behind-the-scenes to make the -figure. There are two types of backends: user interface backends (for -use in pygtk, wxpython, tkinter, qt, macosx, or fltk; also -referred to as "interactive backends") and hardcopy backends to -make image files (PNG, SVG, PDF, PS; also referred to as "non-interactive -backends"). +"backend" does all the hard work behind-the-scenes to make the figure. +There are two types of backends: user interface backends (for use in +pygtk, wxpython, tkinter, qt4, or macosx; also referred to as +"interactive backends") and hardcopy backends to make image files +(PNG, SVG, PDF, PS; also referred to as "non-interactive backends"). There are a two primary ways to configure your backend. One is to set the ``backend`` parameter in your ``matplotlibrc`` file (see @@ -266,12 +265,7 @@ WXAgg Agg rendering to to a :term:`wxWidgets` canvas WX Native :term:`wxWidgets` drawing to a :term:`wxWidgets` Canvas (not recommended) (requires wxPython_) TkAgg Agg rendering to a :term:`Tk` canvas (requires TkInter_) -QtAgg Agg rendering to a :term:`Qt` canvas (requires PyQt_) - (deprecated; use Qt4Agg) Qt4Agg Agg rendering to a :term:`Qt4` canvas (requires PyQt4_) -FLTKAgg Agg rendering to a :term:`FLTK` canvas (requires pyFLTK_) - (not widely used; consider TKAgg, GTKAgg, WXAgg, or - QT4Agg instead) macosx Cocoa rendering in OSX windows (presently lacks blocking show() behavior when matplotlib is in non-interactive mode) @@ -288,9 +282,7 @@ macosx Cocoa rendering in OSX windows .. _pycairo: http://www.cairographics.org/pycairo/ .. _wxPython: http://www.wxpython.org/ .. _TkInter: http://wiki.python.org/moin/TkInter -.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/intro .. _PyQt4: http://www.riverbankcomputing.co.uk/software/pyqt/intro -.. _pyFLTK: http://pyfltk.sourceforge.net diff --git a/doc/glossary/index.rst b/doc/glossary/index.rst index b2b0ee492f62..de17328cffca 100644 --- a/doc/glossary/index.rst +++ b/doc/glossary/index.rst @@ -22,10 +22,6 @@ Glossary EPS Encapsulated Postscript (`EPS `_) - FLTK - `FLTK `_ (pronounced "fulltick") is a cross-platform C++ GUI toolkit for - UNIX/Linux (X11), Microsoft Windows, and MacOS X - freetype `freetype `_ is a font rasterization library used by matplotlib which supports TrueType, Type 1, and @@ -63,16 +59,11 @@ Glossary PS Postscript (`PS `_) is a vector graphics ASCII text language widely used in printers and - publishing. Postscript was developerd by adobe systems and is + publishing. Postscript was developed by adobe systems and is starting to show its age: for example is does not have an alpha channel. PDF was designed in part as a next-generation document format to replace postscript - pyfltk - `pyfltk `_ provides python - wrappers for the :term:`FLTK` widgets library for use with - FLTKAgg - pygtk `pygtk `_ provides python wrappers for the :term:`GTK` widgets library for use with the GTK or GTKAgg @@ -81,7 +72,7 @@ Glossary pyqt `pyqt `_ provides python - wrappers for the :term:`Qt` widgets library and is requied by + wrappers for the :term:`Qt` widgets library and is required by the matplotlib QtAgg and Qt4Agg backends. Widely used on linux and windows; many linux distributions package this as 'python-qt3' or 'python-qt4'. @@ -155,4 +146,3 @@ Glossary tools library for GTK, MS Windows, and MacOS. It uses native widgets for each operating system, so applications will have the look-and-feel that users on that operating system expect. - diff --git a/doc/make.py b/doc/make.py index a8f12ab808e6..4025da223fe1 100755 --- a/doc/make.py +++ b/doc/make.py @@ -110,7 +110,15 @@ def copytree(src, dst, symlinks=False, ignore=None): def copy_if_out_of_date(original, derived): if (not os.path.exists(derived) or os.stat(derived).st_mtime < os.stat(original).st_mtime): - shutil.copyfile(original, derived) + try: + shutil.copyfile(original, derived) + except IOError: + if os.path.basename(original) == 'matplotlibrc': + msg = "'%s' not found. " % original + \ + "Did you run `python setup.py build`?" + raise IOError(msg) + else: + raise def check_build(): build_dirs = ['build', 'build/doctrees', 'build/html', 'build/latex', diff --git a/doc/mpl_toolkits/axes_grid/users/overview.rst b/doc/mpl_toolkits/axes_grid/users/overview.rst index c2cef96d2084..c9b70fcdca23 100644 --- a/doc/mpl_toolkits/axes_grid/users/overview.rst +++ b/doc/mpl_toolkits/axes_grid/users/overview.rst @@ -114,7 +114,7 @@ AxesGrid takes following arguments, ============= ======== ================================================ fig rect - nrows_ncols number of rows and cols. e.g. (2,2) + nrows_ncols number of rows and cols. e.g., (2,2) ngrids None number of grids. nrows x ncols if None direction "row" increasing direction of axes number. [row|column] axes_pad 0.02 pad between axes in inches diff --git a/doc/mpl_toolkits/index.rst b/doc/mpl_toolkits/index.rst index b3c17fa92cb9..1166e3ff63de 100644 --- a/doc/mpl_toolkits/index.rst +++ b/doc/mpl_toolkits/index.rst @@ -5,7 +5,7 @@ axes_grid/index.rst mplot3d/index.rst - + ######## Toolkits @@ -22,13 +22,31 @@ Toolkits are collections of application-specific functions that extend matplotli .. _toolkit_basemap: -Basemap -======= +Basemap (*Not distributed with matplotlib*) +============================================ Plots data on map projections, with continental and political -boundaries, see `basemap `_ +boundaries, see `basemap `_ docs. +.. image:: http://matplotlib.org/basemap/_images/contour1.png + :height: 400px + + + +Cartopy (*Not distributed with matplotlib*) +============================================ +An alternative mapping library written for matplotlib ``v1.2`` and beyond. +`Cartopy `_ builds on top of +matplotlib to provide object oriented map projection definitions and close +integration with Shapely for powerful yet easy-to-use vector data processing +tools. An example plot from the +`Cartopy gallery `_: + +.. image:: http://scitools.org.uk/cartopy/docs/latest/_images/hurricane_katrina_01_00.png + :height: 400px + + .. _toolkit_gtk: GTK Tools @@ -38,6 +56,7 @@ mpl_toolkits.gtktools provides some utilities for working with GTK. This toolkit ships with matplotlib, but requires `pygtk `_. + .. _toolkit_excel: Excel Tools @@ -47,10 +66,11 @@ mpl_toolkits.exceltools provides some utilities for working with Excel. This toolkit ships with matplotlib, but requires `xlwt `_ + .. _toolkit_natgrid: -Natgrid -======== +Natgrid (*Not distributed with matplotlib*) +=========================================== mpl_toolkits.natgrid is an interface to natgrid C library for gridding irregularly spaced data. This requires a separate installation of the @@ -58,27 +78,26 @@ natgrid toolkit from the sourceforge `download `_ page. + .. _toolkit_mplot3d: mplot3d =========== -mpl_toolkits.mplot3d provides some basic 3D plotting (scatter, surf, +:ref:`mpl_toolkits.mplot3d ` provides some basic 3D plotting (scatter, surf, line, mesh) tools. Not the fastest or feature complete 3D library out there, but ships with matplotlib and thus may be a lighter weight solution for some use cases. -See :ref:`toolkit_mplot3d-index` for more documentation and examples. +.. plot:: mpl_examples/mplot3d/contourf3d_demo2.py .. _toolkit_axes_grid: AxesGrid ======== -The matplotlib AxesGrid toolkit is a collection of helper classes to +The matplotlib :ref:`AxesGrid ` toolkit is a collection of helper classes to ease displaying multiple images in matplotlib. The AxesGrid toolkit is distributed with matplotlib source. -.. image:: ../_static/demo_axes_grid.png - -See :ref:`toolkit_axesgrid-index` for documentations. +.. image:: /_static/demo_axes_grid.png diff --git a/doc/pyplots/tex_demo.py b/doc/pyplots/tex_demo.py index 3bdbb77a8168..a5288d749d86 100644 --- a/doc/pyplots/tex_demo.py +++ b/doc/pyplots/tex_demo.py @@ -1,5 +1,6 @@ -#!/usr/bin/env python """ +Demo of TeX rendering. + You can use TeX to render all of your matplotlib text if the rc parameter text.usetex is set. This works currently on the agg and ps backends, and requires that you have tex and the other dependencies @@ -10,26 +11,25 @@ ~/.tex.cache """ -from matplotlib import rc -from numpy import arange, cos, pi -from matplotlib.pyplot import figure, axes, plot, xlabel, ylabel, title, \ - grid, savefig, show +import numpy as np +import matplotlib.pyplot as plt -rc('text', usetex=True) -rc('font', family='serif') -figure(1, figsize=(6,4)) -ax = axes([0.1, 0.1, 0.8, 0.7]) -t = arange(0.0, 1.0+0.01, 0.01) -s = cos(2*2*pi*t)+2 -plot(t, s) +# Example data +t = np.arange(0.0, 1.0 + 0.01, 0.01) +s = np.cos(4 * np.pi * t) + 2 -xlabel(r'\textbf{time (s)}') -ylabel(r'\textit{voltage (mV)}',fontsize=16) -title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='r') -grid(True) -savefig('tex_demo') +plt.rc('text', usetex=True) +plt.rc('font', family='serif') +plt.plot(t, s) +plt.xlabel(r'\textbf{time} (s)') +plt.ylabel(r'\textit{voltage} (mV)',fontsize=16) +plt.title(r"\TeX\ is Number " + r"$\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", + fontsize=16, color='gray') +# Make room for the ridiculously large title. +plt.subplots_adjust(top=0.8) -show() +plt.savefig('tex_demo') +plt.show() diff --git a/doc/sphinxext/gen_gallery.py b/doc/sphinxext/gen_gallery.py index 0e2eb25c09f5..1c4c2b56a9a6 100644 --- a/doc/sphinxext/gen_gallery.py +++ b/doc/sphinxext/gen_gallery.py @@ -1,37 +1,62 @@ # -*- coding: UTF-8 -*- +import os +import re +import glob +import warnings + +import sphinx.errors + +import matplotlib.image as image + + +exclude_example_sections = ['units'] +multiimage = re.compile('(.*?)(_\d\d){1,2}') # generate a thumbnail gallery of examples -template = """\ -{%% extends "layout.html" %%} -{%% set title = "Thumbnail gallery" %%} +gallery_template = """\ +{{% extends "layout.html" %}} +{{% set title = "Thumbnail gallery" %}} -{%% block body %%} +{{% block body %}}

    Click on any image to see full size image and source code


    -
  • Gallery
      -%s -
    +
  • Gallery +
      + {toc} +
  • -%s -{%% endblock %%} +{gallery} + +{{% endblock %}} """ -import os, glob, re, sys, warnings -import matplotlib.image as image +header_template = """\ +
    +

    + {title}¶ +

    """ + +link_template = """\ +{basename} +""" + +toc_template = """\ +
  • {title}
  • """ -multiimage = re.compile('(.*?)(_\d\d){1,2}') def make_thumbnail(args): image.thumbnail(args[0], args[1], 0.3) + def out_of_date(original, derived): return (not os.path.exists(derived) or os.stat(derived).st_mtime < os.stat(original).st_mtime) + def gen_gallery(app, doctree): if app.builder.name != 'html': return @@ -39,6 +64,11 @@ def gen_gallery(app, doctree): outdir = app.builder.outdir rootdir = 'plot_directive/mpl_examples' + example_sections = list(app.builder.config.mpl_example_sections) + for i, (subdir, title) in enumerate(example_sections): + if subdir in exclude_example_sections: + example_sections.pop(i) + # images we want to skip for the gallery because they are an unusual # size that doesn't layout well in a table, or because they may be # redundant with other images or uninteresting @@ -53,21 +83,9 @@ def gen_gallery(app, doctree): rows = [] toc_rows = [] - link_template = """\ - %s - """ - - header_template = """
    \ -

    %s¶

    """ - - toc_template = """\ -
  • %s
  • """ - - dirs = ('api', 'pylab_examples', 'mplot3d', 'widgets', 'axes_grid' ) - - for subdir in dirs : - rows.append(header_template % (subdir, subdir, subdir)) - toc_rows.append(toc_template % (subdir, subdir)) + for subdir, title in example_sections: + rows.append(header_template.format(title=title, section=subdir)) + toc_rows.append(toc_template.format(title=title, section=subdir)) origdir = os.path.join('build', rootdir, subdir) thumbdir = os.path.join(outdir, rootdir, subdir, 'thumbnails') @@ -99,13 +117,12 @@ def gen_gallery(app, doctree): data.append((subdir, basename, os.path.join(rootdir, subdir, 'thumbnails', filename))) - - - for (subdir, basename, thumbfile) in data: if thumbfile is not None: link = 'examples/%s/%s.html'%(subdir, basename) - rows.append(link_template%(link, thumbfile, basename)) + rows.append(link_template.format(link=link, + thumb=thumbfile, + basename=basename)) if len(data) == 0: warnings.warn("No thumbnails were found in %s" % subdir) @@ -113,28 +130,37 @@ def gen_gallery(app, doctree): # Close out the
    opened up at the top of this loop rows.append("
    ") - content = template % ('\n'.join(toc_rows), - '\n'.join(rows)) + content = gallery_template.format(toc='\n'.join(toc_rows), + gallery='\n'.join(rows)) # Only write out the file if the contents have actually changed. # Otherwise, this triggers a full rebuild of the docs - gallery_path = os.path.join(app.builder.srcdir, '_templates', 'gallery.html') + gallery_path = os.path.join(app.builder.srcdir, + '_templates', 'gallery.html') if os.path.exists(gallery_path): fh = open(gallery_path, 'r') regenerate = fh.read() != content fh.close() else: regenerate = True + if regenerate: fh = open(gallery_path, 'w') fh.write(content) fh.close() for key in app.builder.status_iterator( - iter(thumbnails.keys()), "generating thumbnails... ", - length=len(thumbnails)): - image.thumbnail(key, thumbnails[key], 0.3) + iter(thumbnails.keys()), "generating thumbnails... ", + length=len(thumbnails)): + if out_of_date(key, thumbnails[key]): + image.thumbnail(key, thumbnails[key], 0.3) + def setup(app): app.connect('env-updated', gen_gallery) + + try: # multiple plugins may use mpl_example_sections + app.add_config_value('mpl_example_sections', [], True) + except sphinx.errors.ExtensionError: + pass # mpl_example_sections already defined diff --git a/doc/sphinxext/gen_rst.py b/doc/sphinxext/gen_rst.py index be78956295ff..fecd56b85e42 100644 --- a/doc/sphinxext/gen_rst.py +++ b/doc/sphinxext/gen_rst.py @@ -3,33 +3,41 @@ """ from __future__ import print_function import io -import os, glob - import os import re import sys -fileList = [] + +import sphinx.errors + + +exclude_example_sections = ['widgets'] +noplot_regex = re.compile(r"#\s*-\*-\s*noplot\s*-\*-") + def out_of_date(original, derived): """ Returns True if derivative is out-of-date wrt original, both of which are full file paths. - TODO: this check isn't adequate in some cases. Eg, if we discover + TODO: this check isn't adequate in some cases. e.g., if we discover a bug when building the examples, the original and derived will be unchanged but we still want to force a rebuild. """ return (not os.path.exists(derived) or os.stat(derived).st_mtime < os.stat(original).st_mtime) -noplot_regex = re.compile(r"#\s*-\*-\s*noplot\s*-\*-") - def generate_example_rst(app): rootdir = os.path.join(app.builder.srcdir, 'mpl_examples') exampledir = os.path.join(app.builder.srcdir, 'examples') if not os.path.exists(exampledir): os.makedirs(exampledir) + example_sections = list(app.builder.config.mpl_example_sections) + for i, (subdir, title) in enumerate(example_sections): + if subdir in exclude_example_sections: + example_sections.pop(i) + example_subdirs, titles = zip(*example_sections) + datad = {} for root, subFolders, files in os.walk(rootdir): for fname in files: @@ -115,13 +123,8 @@ def generate_example_rst(app): fhsubdirIndex.write(' %s <%s>\n'%(os.path.basename(basename),rstfile)) - do_plot = (subdir in ('api', - 'pylab_examples', - 'units', - 'mplot3d', - 'axes_grid', - ) and - not noplot_regex.search(contents)) + do_plot = (subdir in example_subdirs + and not noplot_regex.search(contents)) if not do_plot: fhstatic = io.open(outputfile, 'w', encoding='utf-8') fhstatic.write(contents) @@ -158,3 +161,8 @@ def generate_example_rst(app): def setup(app): app.connect('builder-inited', generate_example_rst) + + try: # multiple plugins may use mpl_example_sections + app.add_config_value('mpl_example_sections', [], True) + except sphinx.errors.ExtensionError: + pass # mpl_example_sections already defined diff --git a/doc/users/annotations_guide.rst b/doc/users/annotations_guide.rst index bd4d036d6587..fa585eb9e30e 100644 --- a/doc/users/annotations_guide.rst +++ b/doc/users/annotations_guide.rst @@ -324,7 +324,7 @@ more control, it supports a few other options. annotate("Test", xy=(0.5, 1), xycoords=("data", "axes fraction")) 0.5 is in data coordinate, and 1 is in normalized axes coordinate. - You may use an atist or transform as with a tuple. For example, + You may use an artist or transform as with a tuple. For example, .. plot:: users/plotting/examples/annotate_simple_coord02.py :include-source: diff --git a/doc/users/annotations_intro.rst b/doc/users/annotations_intro.rst index 1b235d230384..0b83e1523b3e 100644 --- a/doc/users/annotations_intro.rst +++ b/doc/users/annotations_intro.rst @@ -30,10 +30,10 @@ argument coordinate system ==================== ==================================================== 'figure points' points from the lower left corner of the figure 'figure pixels' pixels from the lower left corner of the figure - 'figure fraction' 0,0 is lower left of figure and 1,1 is upper, right + 'figure fraction' 0,0 is lower left of figure and 1,1 is upper right 'axes points' points from lower left corner of axes 'axes pixels' pixels from lower left corner of axes - 'axes fraction' 0,1 is lower left of axes and 1,1 is upper right + 'axes fraction' 0,0 is lower left of axes and 1,1 is upper right 'data' use the axes data coordinate system ==================== ==================================================== @@ -66,7 +66,7 @@ shrink move the tip and base some percent away from the annotated point and text \*\*kwargs any key for :class:`matplotlib.patches.Polygon`, - e.g. ``facecolor`` + e.g., ``facecolor`` ==================== ===================================================== diff --git a/doc/users/artists.rst b/doc/users/artists.rst index c25933aa4b98..cff65522de08 100644 --- a/doc/users/artists.rst +++ b/doc/users/artists.rst @@ -19,8 +19,24 @@ the ``Artist`` handles all the high level constructs like representing and laying out the figure, text, and lines. The typical user will spend 95% of his time working with the ``Artists``. -There are two types of ``Artists``: primitives and containers. The primitives represent the standard graphical objects we want to paint onto our canvas: :class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.patches.Rectangle`, :class:`~matplotlib.text.Text`, :class:`~matplotlib.image.AxesImage`, etc., and the containers are places to put them (:class:`~matplotlib.axis.Axis`, :class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The standard use is to create a :class:`~matplotlib.figure.Figure` instance, use the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` or :class:`~matplotlib.axes.Subplot` instances, and use the ``Axes`` instance helper methods to create the primitives. In the example below, we create a ``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a convenience method for instantiating ``Figure`` instances and connecting them with your user interface or drawing toolkit ``FigureCanvas``. As we will discuss below, this is not necessary -- you -can work directly with PostScript, PDF Gtk+, or wxPython ``FigureCanvas`` instances, instantiate your ``Figures`` directly and connect them yourselves -- but since we are focusing here on the ``Artist`` API we'll let :mod:`~matplotlib.pyplot` handle some of those details for us:: +There are two types of ``Artists``: primitives and containers. The primitives +represent the standard graphical objects we want to paint onto our canvas: +:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.patches.Rectangle`, +:class:`~matplotlib.text.Text`, :class:`~matplotlib.image.AxesImage`, etc., and +the containers are places to put them (:class:`~matplotlib.axis.Axis`, +:class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The +standard use is to create a :class:`~matplotlib.figure.Figure` instance, use +the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` or +:class:`~matplotlib.axes.Subplot` instances, and use the ``Axes`` instance +helper methods to create the primitives. In the example below, we create a +``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a +convenience method for instantiating ``Figure`` instances and connecting them +with your user interface or drawing toolkit ``FigureCanvas``. As we will +discuss below, this is not necessary -- you can work directly with PostScript, +PDF Gtk+, or wxPython ``FigureCanvas`` instances, instantiate your ``Figures`` +directly and connect them yourselves -- but since we are focusing here on the +``Artist`` API we'll let :mod:`~matplotlib.pyplot` handle some of those details +for us:: import matplotlib.pyplot as plt fig = plt.figure() @@ -38,8 +54,8 @@ graphics primitives (:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.text.Text`, :class:`~matplotlib.patches.Rectangle`, :class:`~matplotlib.image.Image`, respectively). These helper methods -will take your data (eg. ``numpy`` arrays and strings) and create -primitive ``Artist`` instances as needed (eg. ``Line2D``), add them to +will take your data (e.g., ``numpy`` arrays and strings) and create +primitive ``Artist`` instances as needed (e.g., ``Line2D``), add them to the relevant containers, and draw them when requested. Most of you are probably familiar with the :class:`~matplotlib.axes.Subplot`, which is just a special case of an ``Axes`` that lives on a regular @@ -136,7 +152,7 @@ transparency, and other properties of the Axes. These instances are stored as member variables :attr:`Figure.patch ` and :attr:`Axes.patch ` ("Patch" is a name inherited from -MATLAB, and is a 2D "patch" of color on the figure, eg. rectangles, +MATLAB, and is a 2D "patch" of color on the figure, e.g., rectangles, circles and polygons). Every matplotlib ``Artist`` has the following properties @@ -151,7 +167,7 @@ clip_on Whether clipping is enabled clip_path The path the artist is clipped to contains A picking function to test whether the artist contains the pick point figure The figure instance the artist lives in, possibly None -label A text label (eg. for auto-labeling) +label A text label (e.g., for auto-labeling) picker A python object that controls object picking transform The transformation visible A boolean whether the artist should be drawn @@ -176,7 +192,7 @@ inspect the ``Artist`` properties is to use the :func:`matplotlib.artist.getp` function (simply :func:`~matplotlib.pylab.getp` in pylab), which lists the properties and their values. This works for classes derived from ``Artist`` as -well, eg. ``Figure`` and ``Rectangle``. Here are the ``Figure`` rectangle +well, e.g., ``Figure`` and ``Rectangle``. Here are the ``Figure`` rectangle properties mentioned above: .. sourcecode:: ipython @@ -346,7 +362,7 @@ determines the shape, background and border of the plotting region:: rect = ax.patch # a Rectangle instance rect.set_facecolor('green') -When you call a plotting method, eg. the canonical +When you call a plotting method, e.g., the canonical :meth:`~matplotlib.axes.Axes.plot` and pass in arrays or lists of values, the method will create a :meth:`matplotlib.lines.Line2D` instance, update the line with all the ``Line2D`` properties passed as @@ -517,7 +533,18 @@ and zooming, as well as the :class:`~matplotlib.ticker.Locator` and :class:`~matplotlib.ticker.Formatter` instances which control where the ticks are placed and how they are represented as strings. -Each ``Axis`` object contains a :attr:`~matplotlib.axis.Axis.label` attribute (this is what :mod:`~matplotlib.pylab` modifies in calls to :func:`~matplotlib.pylab.xlabel` and :func:`~matplotlib.pylab.ylabel`) as well as a list of major and minor ticks. The ticks are :class:`~matplotlib.axis.XTick` and :class:`~matplotlib.axis.YTick` instances, which contain the actual line and text primitives that render the ticks and ticklabels. Because the ticks are dynamically created as needed (eg. when panning and zooming), you should access the lists of major and minor ticks through their accessor methods :meth:`~matplotlib.axis.Axis.get_major_ticks` and :meth:`~matplotlib.axis.Axis.get_minor_ticks`. Although the ticks contain all the primitives and will be covered below, the ``Axis`` methods contain accessor methods to return the tick lines, tick labels, tick locations etc.: +Each ``Axis`` object contains a :attr:`~matplotlib.axis.Axis.label` attribute +(this is what :mod:`~matplotlib.pylab` modifies in calls to +:func:`~matplotlib.pylab.xlabel` and :func:`~matplotlib.pylab.ylabel`) as well +as a list of major and minor ticks. The ticks are +:class:`~matplotlib.axis.XTick` and :class:`~matplotlib.axis.YTick` instances, +which contain the actual line and text primitives that render the ticks and +ticklabels. Because the ticks are dynamically created as needed (e.g., when +panning and zooming), you should access the lists of major and minor ticks +through their accessor methods :meth:`~matplotlib.axis.Axis.get_major_ticks` +and :meth:`~matplotlib.axis.Axis.get_minor_ticks`. Although the ticks contain +all the primitives and will be covered below, the ``Axis`` methods contain +accessor methods to return the tick lines, tick labels, tick locations etc.: .. sourcecode:: ipython diff --git a/doc/users/credits.rst b/doc/users/credits.rst index 50930f7d5e79..980828786bdd 100644 --- a/doc/users/credits.rst +++ b/doc/users/credits.rst @@ -121,7 +121,7 @@ Baptiste Carvello Jeffrey Whitaker at `NOAA `_ wrote the - :ref:`toolkit_basemap` tookit + :ref:`toolkit_basemap` toolkit Sigve Tjoraand, Ted Drain, James Evans and colleagues at the `JPL `_ collaborated @@ -163,7 +163,7 @@ Jouni K. Seppänen fixes to the code, to tex support and to the get_sample_data handler Paul Kienzle - improved the picking infrastruture for interactive plots, and with + improved the picking infrastructure for interactive plots, and with Alex Mont contributed fast rendering code for quadrilateral meshes. Michael Droettboom diff --git a/doc/users/customizing.rst b/doc/users/customizing.rst index de5716ac3ff1..035d8276e3e3 100644 --- a/doc/users/customizing.rst +++ b/doc/users/customizing.rst @@ -18,21 +18,31 @@ locations, in the following order: 1. :file:`matplotlibrc` in the current working directory, usually used for specific customizations that you do not want to apply elsewhere. -2. :file:`.matplotlib/matplotlibrc`, for the user's default customizations. See - :ref:`locating-matplotlib-config-dir`. -3. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where :file:`{INSTALL}` - is something like :file:`/usr/lib/python2.5/site-packages` on Linux, and - maybe :file:`C:\\Python25\\Lib\\site-packages` on Windows. Every time you - install matplotlib, this file will be overwritten, so if you want your - customizations to be saved, please move this file to your :file:`.matplotlib` - directory. + +2. It next looks in a user-specific place, depending on your platform: + + - On Linux, it looks in :file:`.config/matplotlib/matplotlibrc` (or + `$XDG_CONFIG_HOME/matplotlib/matplotlibrc` if you've customized + your environment. + + - On other platforms, it looks in :file:`.matplotlib/matplotlibrc`. + + See :ref:`locating-matplotlib-config-dir`. + +3. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where + :file:`{INSTALL}` is something like + :file:`/usr/lib/python2.5/site-packages` on Linux, and maybe + :file:`C:\\Python25\\Lib\\site-packages` on Windows. Every time you + install matplotlib, this file will be overwritten, so if you want + your customizations to be saved, please move this file to your + user-specific matplotlib directory. To display where the currently active :file:`matplotlibrc` file was loaded from, one can do the following:: >>> import matplotlib >>> matplotlib.matplotlib_fname() - '/home/foo/.matplotlib/matplotlibrc' + '/home/foo/.config/matplotlib/matplotlibrc' See below for a sample :ref:`matplotlibrc file`. diff --git a/doc/users/event_handling.rst b/doc/users/event_handling.rst index 5b99d9b40881..452e159aa0d7 100644 --- a/doc/users/event_handling.rst +++ b/doc/users/event_handling.rst @@ -4,19 +4,19 @@ Event handling and picking ************************** -matplotlib works with 6 user interface toolkits (wxpython, tkinter, -qt, gtk, fltk and macosx) and in order to support features like interactive -panning and zooming of figures, it is helpful to the developers to -have an API for interacting with the figure via key presses and mouse -movements that is "GUI neutral" so we don't have to repeat a lot of -code across the different user interfaces. Although the event -handling API is GUI neutral, it is based on the GTK model, which was -the first user interface matplotlib supported. The events that are -triggered are also a bit richer vis-a-vis matplotlib than standard GUI -events, including information like which :class:`matplotlib.axes.Axes` -the event occurred in. The events also understand the matplotlib -coordinate system, and report event locations in both pixel and data -coordinates. +matplotlib works with a number of user interface toolkits (wxpython, +tkinter, qt4, gtk, and macosx) and in order to support features like +interactive panning and zooming of figures, it is helpful to the +developers to have an API for interacting with the figure via key +presses and mouse movements that is "GUI neutral" so we don't have to +repeat a lot of code across the different user interfaces. Although +the event handling API is GUI neutral, it is based on the GTK model, +which was the first user interface matplotlib supported. The events +that are triggered are also a bit richer vis-a-vis matplotlib than +standard GUI events, including information like which +:class:`matplotlib.axes.Axes` the event occurred in. The events also +understand the matplotlib coordinate system, and report event +locations in both pixel and data coordinates. .. _event-connections: @@ -444,7 +444,7 @@ There are a variety of meanings of the ``picker`` property: After you have enabled an artist for picking by setting the ``picker`` property, you need to connect to the figure canvas pick_event to get -pick callbacks on mouse press events. Eg:: +pick callbacks on mouse press events. e.g.:: def pick_handler(event): mouseevent = event.mouseevent diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst index 667ac5491eeb..b6b4384a0185 100644 --- a/doc/users/github_stats.rst +++ b/doc/users/github_stats.rst @@ -1,5 +1,6 @@ .. _github-stats: + Github stats ============ @@ -102,7 +103,7 @@ The following 90 authors contributed 1618 commits. We closed a total of 1222 issues, 435 pull requests and 787 regular issues; -this is the full list (generated with the script +this is the full list (generated with the script :file:`tools/github_stats.py`): Pull Requests (435): @@ -151,7 +152,7 @@ Pull Requests (435): * :ghpull:`1762`: Make cbook safe to import while removing duplicate is_string_like; * :ghpull:`1252`: Properly passing on horiz-/vertOn to Cursor() * :ghpull:`1686`: Fix lost ticks -* :ghpull:`1640`: Fix bugs in legend positioning with loc='best' +* :ghpull:`1640`: Fix bugs in legend positioning with loc='best' * :ghpull:`1687`: Update lib/matplotlib/backends/backend_cairo.py * :ghpull:`1760`: Improved the subplot function documentation and fixed the autogeneration from boilerplate. * :ghpull:`1716`: PEP8 fixes on the figure module @@ -202,7 +203,7 @@ Pull Requests (435): * :ghpull:`1657`: Add EventCollection and eventplot * :ghpull:`1641`: PEP8 fixes on the rcsetup module * :ghpull:`1650`: _png.read_png crashes on Python 3 with urllib.request object -* :ghpull:`1568`: removed deprecated methods from the axes module. +* :ghpull:`1568`: removed deprecated methods from the axes module. * :ghpull:`1589`: Fix shifted ylabels (Issue #1571) * :ghpull:`1634`: add scatterpoints to rcParam * :ghpull:`1654`: added explicit 'zorder' kwarg to `Colection` and `LineCollection`. @@ -353,7 +354,7 @@ Pull Requests (435): * :ghpull:`1333`: PEP8 fixes on collections.py * :ghpull:`1336`: PEP8 fixes to colorbar.py * :ghpull:`1347`: Remove nonfunctioning cbook.isvector -* :ghpull:`1327`: plt.subplots: Set the visibility of the offset text to false on the shared axes. +* :ghpull:`1327`: plt.subplots: Set the visibility of the offset text to false on the shared axes. * :ghpull:`1335`: PEP8 fixes on cbook.py * :ghpull:`1334`: PEP8 fixes on blocking_input.py * :ghpull:`1332`: PEP8 fixes on cm.py @@ -371,7 +372,7 @@ Pull Requests (435): * :ghpull:`1285`: Hide Tk root window until later * :ghpull:`1305`: Fix pointer syntax error * :ghpull:`1294`: Update lib/mpl_toolkits/mplot3d/axes3d.py -* :ghpull:`1300`: Pcolormesh and colorbar documentation. +* :ghpull:`1300`: Pcolormesh and colorbar documentation. * :ghpull:`1296`: Make Container._remove_method call correctly * :ghpull:`1293`: Fixed to contour to support the _as_mpl_transform api. * :ghpull:`1284`: Fix Image Tutorial: plt.imshow instead of mpimg.imshow. @@ -383,7 +384,7 @@ Pull Requests (435): * :ghpull:`1277`: Fixed bug in MaxNLocator.bin_boundaries * :ghpull:`1273`: Handled baseline image folder identification for non matplotlib projects... * :ghpull:`1230`: Fix dpi issue for bitmaps on the OS X backend -* :ghpull:`1251`: backend_pgf. Enable custom dashstyles in the pgf backend +* :ghpull:`1251`: backend_pgf. Enable custom dashstyles in the pgf backend * :ghpull:`1264`: Re-added the matplotlib.dates import on axes * :ghpull:`1271`: Set axis limits in test_stackplot * :ghpull:`1269`: Fix typo in docstring @@ -406,7 +407,7 @@ Pull Requests (435): * :ghpull:`1231`: fix Typesetting in plot() docstring * :ghpull:`1215`: PEP8 on lib/matplotlib.afm.py * :ghpull:`1216`: PEP8 fixes on the animation module -* :ghpull:`1208`: FAIL: matplotlib.tests.test_text.test_contains.test +* :ghpull:`1208`: FAIL: matplotlib.tests.test_text.test_contains.test * :ghpull:`1209`: Pass linewidth to Mac context properly * :ghpull:`847`: Add stacked kwarg to hist and implement stacked hists for step histtype * :ghpull:`1228`: backend_pgf: pep8 edits @@ -469,7 +470,7 @@ Pull Requests (435): * :ghpull:`983`: Issues with dateutil and pytz * :ghpull:`1133`: figure.py: import warnings, and make imports absolute * :ghpull:`1132`: clean out obsolete matplotlibrc-related bits to close #1123 -* :ghpull:`1131`: Cleanup after the gca test. +* :ghpull:`1131`: Cleanup after the gca test. * :ghpull:`563`: sankey.add() has mutable defaults * :ghpull:`731`: Plot limit with transform * :ghpull:`1107`: Added %s support for labels. @@ -493,7 +494,7 @@ Pull Requests (435): * :ghpull:`1074`: Added broadcasting support in some mplot3d methods * :ghpull:`1064`: Locator interface * :ghpull:`850`: Added tripcolor triangle-centred colour values. -* :ghpull:`1093`: Exposed the callback id for the default key press handler so that it can be easily diabled. Fixes #215. +* :ghpull:`1093`: Exposed the callback id for the default key press handler so that it can be easily disabled. Fixes #215. * :ghpull:`1065`: fixed conversion from pt to inch in tight_layout * :ghpull:`1082`: doc: in pcolormesh docstring, say what it does. * :ghpull:`1078`: doc: note that IDLE doesn't work with interactive mode. @@ -523,10 +524,10 @@ Pull Requests (435): * :ghpull:`1002`: Fixed potential overflow exception in the lines.contains() method * :ghpull:`1025`: Timers * :ghpull:`989`: Animation subprocess bug -* :ghpull:`898`: Added warnings for easily confusible subplot/subplots invokations +* :ghpull:`898`: Added warnings for easily confusable subplot/subplots invocations * :ghpull:`963`: Add detection of file extension for file-like objects * :ghpull:`973`: Fix sankey.py pep8 and py3 compatibility -* :ghpull:`972`: Force closing PIL image files +* :ghpull:`972`: Force closing PIL image files * :ghpull:`981`: Fix pathpatch3d_demo.py on Python 3 * :ghpull:`980`: Fix basic_units.py on Python 3. PEP8 and PyLint cleanup. * :ghpull:`1014`: qt4: remove duplicate file save button; and remove trailing whitespace @@ -540,7 +541,7 @@ Pull Requests (435): * :ghpull:`851`: Simple GUI interface enhancements * :ghpull:`979`: Fix test_mouseclicks.py on Python 3 * :ghpull:`977`: Fix lasso_selector_demo.py on Python 3 -* :ghpull:`970`: Fix tiff and jpeg export via PIL +* :ghpull:`970`: Fix tiff and jpeg export via PIL * :ghpull:`961`: Issue 807 auto minor locator Issues (787): @@ -632,7 +633,7 @@ Issues (787): * :ghissue:`1252`: Properly passing on horiz-/vertOn to Cursor() * :ghissue:`1632`: Fix build on Ubuntu 12.10 * :ghissue:`1686`: Fix lost ticks -* :ghissue:`1640`: Fix bugs in legend positioning with loc='best' +* :ghissue:`1640`: Fix bugs in legend positioning with loc='best' * :ghissue:`1687`: Update lib/matplotlib/backends/backend_cairo.py * :ghissue:`1760`: Improved the subplot function documentation and fixed the autogeneration from boilerplate. * :ghissue:`1647`: WIP: Deprecation of the cbook module @@ -725,7 +726,7 @@ Issues (787): * :ghissue:`1657`: Add EventCollection and eventplot * :ghissue:`1641`: PEP8 fixes on the rcsetup module * :ghissue:`1650`: _png.read_png crashes on Python 3 with urllib.request object -* :ghissue:`1568`: removed deprecated methods from the axes module. +* :ghissue:`1568`: removed deprecated methods from the axes module. * :ghissue:`1571`: Y-labels shifted * :ghissue:`1589`: Fix shifted ylabels (Issue #1571) * :ghissue:`1276`: Fix overwriting suptitle @@ -748,7 +749,7 @@ Issues (787): * :ghissue:`1582`: Linear tri interpolator * :ghissue:`1637`: change cbook to relative import * :ghissue:`1645`: add get_segments method to collections.LineCollection - updated -* :ghissue:`1639`: Rename web_static to web_backend in setup.py +* :ghissue:`1639`: Rename web_static to web_backend in setup.py * :ghissue:`1618`: Mplot3d/crashfixes * :ghissue:`1636`: hexbin log scale is broken in matplotlib 1.2.0 * :ghissue:`1624`: implemented inverse transform for Mollweide axes @@ -756,13 +757,13 @@ Issues (787): * :ghissue:`1139`: Make Axes.stem take at least one argument. * :ghissue:`1426`: WebAgg backend * :ghissue:`1606`: Document the C/C++ code guidelines -* :ghissue:`1622`: zorder is not respected by all parts of `errorbar` +* :ghissue:`1622`: zorder is not respected by all parts of `errorbar` * :ghissue:`1628`: Fix errorbar zorder v1.2 * :ghissue:`1625`: saving pgf to a stream is not supported * :ghissue:`1588`: Annotations appear in incorrect locations * :ghissue:`1620`: Fix bug in _AnnotationBase * :ghissue:`1621`: Package for python 3.3 on OS X -* :ghissue:`1616`: Legend: Also calc the bbox of the legend when the frame is not drawn. +* :ghissue:`1616`: Legend: Also calc the bbox of the legend when the frame is not drawn. * :ghissue:`1587`: Mac OS X 10.5 needs an autoreleasepool here to avoid memory leaks. Newer... * :ghissue:`1597`: new MatplotlibDeprecationWarning class (against master) * :ghissue:`1596`: new MatplotlibDeprecationWarning class (against 1.2.x) @@ -918,7 +919,7 @@ Issues (787): * :ghissue:`1424`: pcolor fails if edgecolors is not a string * :ghissue:`1427`: Fix AttrituteError for .lower on tuple of strings * :ghissue:`1425`: Rebase of #1418 on v1.2.x -* :ghissue:`1418`: Tables: Fix get_window_extent for table +* :ghissue:`1418`: Tables: Fix get_window_extent for table * :ghissue:`1411`: Fix transparent markers in PDF backend. Closes #1410 * :ghissue:`1410`: Open markers incorrect in PDF output * :ghissue:`1416`: backend_pdf: optional rgbFace arg in fillp replaces code in draw_markers. Closes #1410 @@ -981,7 +982,7 @@ Issues (787): * :ghissue:`1333`: PEP8 fixes on collections.py * :ghissue:`1336`: PEP8 fixes to colorbar.py * :ghissue:`1347`: Remove nonfunctioning cbook.isvector -* :ghissue:`1327`: plt.subplots: Set the visibility of the offset text to false on the shared axes. +* :ghissue:`1327`: plt.subplots: Set the visibility of the offset text to false on the shared axes. * :ghissue:`1335`: PEP8 fixes on cbook.py * :ghissue:`1334`: PEP8 fixes on blocking_input.py * :ghissue:`1332`: PEP8 fixes on cm.py @@ -1005,7 +1006,7 @@ Issues (787): * :ghissue:`156`: Multicursor not displayed with zoom on * :ghissue:`1320`: Cursor widget now uses widgetlock; closes Issue #156 * :ghissue:`1321`: pgf backend. Y-labels in subplot are not alligned after baseline but bottom of letter -* :ghissue:`1301`: Colorbar Add kw arguement to colorbar to reenable edges around faces +* :ghissue:`1301`: Colorbar Add kw arguement to colorbar to reenable edges around faces * :ghissue:`1315`: Add documentation of colorbar issue #1188 to colorbar documentation. * :ghissue:`1303`: twinx/twiny misses settings axes * :ghissue:`1307`: Marker not round with markersize=3 @@ -1017,8 +1018,8 @@ Issues (787): * :ghissue:`1294`: Update lib/mpl_toolkits/mplot3d/axes3d.py * :ghissue:`159`: Autoscale in hist() with step and log * :ghissue:`167`: windows x64 support in _tkagg.so -* :ghissue:`1300`: Pcolormesh and colorbar documentation. -* :ghissue:`1178`: Make colorbar draw edge with facecolor around the faces. +* :ghissue:`1300`: Pcolormesh and colorbar documentation. +* :ghissue:`1178`: Make colorbar draw edge with facecolor around the faces. * :ghissue:`1205`: New 'gridon' keyword in plotfile * :ghissue:`1295`: Exception when using Container.remove * :ghissue:`1296`: Make Container._remove_method call correctly @@ -1052,7 +1053,7 @@ Issues (787): * :ghissue:`1273`: Handled baseline image folder identification for non matplotlib projects... * :ghissue:`1230`: Fix dpi issue for bitmaps on the OS X backend * :ghissue:`1274`: backend_pgf: Custom dashstyles and consistency with other backends -* :ghissue:`1251`: backend_pgf. Enable custom dashstyles in the pgf backend +* :ghissue:`1251`: backend_pgf. Enable custom dashstyles in the pgf backend * :ghissue:`1264`: Re-added the matplotlib.dates import on axes * :ghissue:`1271`: Set axis limits in test_stackplot * :ghissue:`1269`: Fix typo in docstring @@ -1086,7 +1087,7 @@ Issues (787): * :ghissue:`1231`: fix Typesetting in plot() docstring * :ghissue:`1215`: PEP8 on lib/matplotlib.afm.py * :ghissue:`1216`: PEP8 fixes on the animation module -* :ghissue:`1208`: FAIL: matplotlib.tests.test_text.test_contains.test +* :ghissue:`1208`: FAIL: matplotlib.tests.test_text.test_contains.test * :ghissue:`786`: savefig() renders paths and text differently than show() * :ghissue:`1209`: Pass linewidth to Mac context properly * :ghissue:`847`: Add stacked kwarg to hist and implement stacked hists for step histtype @@ -1136,7 +1137,7 @@ Issues (787): * :ghissue:`557`: Crash during date axis setup * :ghissue:`600`: errorbar(): kwarg 'markevery' not working as expected. * :ghissue:`174`: Memory leak in example simple_idle_wx.py -* :ghissue:`232`: format in plot_direcitive sphinx>=1.0.6 compatible patch +* :ghissue:`232`: format in plot_directive sphinx>=1.0.6 compatible patch * :ghissue:`1162`: FIX nose.tools.assert_is is only supported with python2.7 * :ghissue:`1165`: tight_layout fails on twinx, twiny * :ghissue:`803`: Return arrow collection as 2nd argument of streamplot. @@ -1179,7 +1180,7 @@ Issues (787): * :ghissue:`1141`: backend_pgf: fix parentheses typo * :ghissue:`1114`: Make grid accept alpha rcParam * :ghissue:`1118`: ERROR: matplotlib.tests.test_backend_pgf.test_pdflatex on Python 3.x -* :ghissue:`1116`: ERROR: matplotlib.tests.test_backend_pgf.test_xelatex +* :ghissue:`1116`: ERROR: matplotlib.tests.test_backend_pgf.test_xelatex * :ghissue:`1124`: PGF backend, fix #1116, #1118 and #1128 * :ghissue:`745`: Cannot run tests with Python 3.x on MacOS 10.7 * :ghissue:`983`: Issues with dateutil and pytz @@ -1188,7 +1189,7 @@ Issues (787): * :ghissue:`1133`: figure.py: import warnings, and make imports absolute * :ghissue:`1123`: Rationalize the number of ancillary (default matplotlibrc) files * :ghissue:`1132`: clean out obsolete matplotlibrc-related bits to close #1123 -* :ghissue:`1131`: Cleanup after the gca test. +* :ghissue:`1131`: Cleanup after the gca test. * :ghissue:`563`: sankey.add() has mutable defaults * :ghissue:`238`: patch for qt4 backend * :ghissue:`731`: Plot limit with transform @@ -1238,7 +1239,7 @@ Issues (787): * :ghissue:`850`: Added tripcolor triangle-centred colour values. * :ghissue:`1059`: Matplotlib figure window freezes during interactive mode * :ghissue:`215`: skipping mpl-axes-interaction during key_press_event\'s -* :ghissue:`1093`: Exposed the callback id for the default key press handler so that it can be easily diabled. Fixes #215. +* :ghissue:`1093`: Exposed the callback id for the default key press handler so that it can be easily disabled. Fixes #215. * :ghissue:`909`: Log Formatter for tick labels can't handle non-integer base * :ghissue:`1065`: fixed conversion from pt to inch in tight_layout * :ghissue:`1086`: Problem with subplot / matplotlib.dates interaction @@ -1295,10 +1296,10 @@ Issues (787): * :ghissue:`1002`: Fixed potential overflow exception in the lines.contains() method * :ghissue:`1025`: Timers * :ghissue:`989`: Animation subprocess bug -* :ghissue:`898`: Added warnings for easily confusible subplot/subplots invokations +* :ghissue:`898`: Added warnings for easily confusable subplot/subplots invocations * :ghissue:`963`: Add detection of file extension for file-like objects * :ghissue:`973`: Fix sankey.py pep8 and py3 compatibility -* :ghissue:`972`: Force closing PIL image files +* :ghissue:`972`: Force closing PIL image files * :ghissue:`981`: Fix pathpatch3d_demo.py on Python 3 * :ghissue:`980`: Fix basic_units.py on Python 3. PEP8 and PyLint cleanup. * :ghissue:`996`: macosx backend broken by #901: QuadMesh fails so colorbar fails @@ -1322,7 +1323,7 @@ Issues (787): * :ghissue:`851`: Simple GUI interface enhancements * :ghissue:`979`: Fix test_mouseclicks.py on Python 3 * :ghissue:`977`: Fix lasso_selector_demo.py on Python 3 -* :ghissue:`970`: Fix tiff and jpeg export via PIL +* :ghissue:`970`: Fix tiff and jpeg export via PIL * :ghissue:`707`: key_press_event in pyqt4 embedded matplotlib * :ghissue:`243`: Debug version/symbols for win32 * :ghissue:`255`: Classes in _transforms.h in global namespace diff --git a/doc/users/image_tutorial.rst b/doc/users/image_tutorial.rst index a7ed0b87e99d..dbc74d66ea79 100644 --- a/doc/users/image_tutorial.rst +++ b/doc/users/image_tutorial.rst @@ -229,11 +229,9 @@ object: imgplot = plt.imshow(lum_img) imgplot.set_cmap('spectral') -There are many other colormap schemes available. See the `list of -colormaps -`_ -and `images of the colormaps -`_. +There are many other colormap schemes available. See the `list and +images of the colormaps +`_. .. _`Color Bars`: diff --git a/doc/users/legend_guide.rst b/doc/users/legend_guide.rst index 811b64042ddb..7c718de5d3f9 100644 --- a/doc/users/legend_guide.rst +++ b/doc/users/legend_guide.rst @@ -51,7 +51,7 @@ used as text labels. If label attribute is empty string or starts with Therefore, plots drawn by some *pyplot* commands are not supported by legend. For example, :func:`~matplotlib.pyplot.fill_between` creates :class:`~matplotlib.collections.PolyCollection` that is not -supported. Also support is limted for some commands that creat +supported. Also support is limited for some commands that create multiple artists. For example, :func:`~matplotlib.pyplot.errorbar` creates multiples :class:`~matplotlib.lines.Line2D` instances. @@ -253,7 +253,7 @@ For each *p_i*, matplotlib in the handler_map -Unless specified, the defaul handler_map is used. Below is a partial +Unless specified, the default handler_map is used. Below is a partial list of key-handler pairs included in the default handler map. * Line2D : legend_handler.HandlerLine2D() @@ -281,7 +281,7 @@ instances (p1 and p2). :: In the above example, only *p1* will be handled by *my_handler*, while others will be handled by default handlers. -The curent default handler_map has handlers for errorbar and bar +The current default handler_map has handlers for errorbar and bar plots. Also, it includes an entry for `tuple` which is mapped to `HandlerTuple`. It simply plots over all the handles for items in the given tuple. For example, @@ -310,7 +310,7 @@ Handler can be any callable object with following signature. :: Where *legend* is the legend itself, *orig_handle* is the original plot (*p_i* in the above example), *fontsize* is the fontsize in -pixles, and *handlebox* is a OffsetBox instance. Within the call, you +pixels, and *handlebox* is a OffsetBox instance. Within the call, you create relevant artists (using relevant properties from the *legend* and/or *orig_handle*) and add them into the handlebox. The artists needs to be scaled according to the fontsize (note that the size is in diff --git a/doc/users/mathtext.rst b/doc/users/mathtext.rst index 8fd934c6d598..833e86455fef 100644 --- a/doc/users/mathtext.rst +++ b/doc/users/mathtext.rst @@ -14,7 +14,7 @@ provides a ``usetex`` option for those who do want to call out to TeX to generate their text (see :ref:`usetex-tutorial`). Any text element can use math text. You should use raw strings -(preceed the quotes with an ``'r'``), and surround the math text with +(precede the quotes with an ``'r'``), and surround the math text with dollar signs ($), as in TeX. Regular text and mathtext can be interleaved within the same string. Mathtext can use the Computer Modern fonts (from (La)TeX), `STIX `_ @@ -46,7 +46,7 @@ produces ":math:`\alpha > \beta`". .. note:: Mathtext should be placed between a pair of dollar signs ($). To - make it easy to display monetary values, e.g. "$100.00", if a + make it easy to display monetary values, e.g., "$100.00", if a single dollar sign is present in the entire string, it will be displayed verbatim as a dollar sign. This is a small change from regular TeX, where the dollar sign in non-math text would have to diff --git a/doc/users/pgf.rst b/doc/users/pgf.rst index 0855e2b2a1f4..84d48294a803 100644 --- a/doc/users/pgf.rst +++ b/doc/users/pgf.rst @@ -45,7 +45,7 @@ Rc parameters that control the behavior of the pgf backend: .. note:: - TeX defines a set of secial characters, such as:: + TeX defines a set of special characters, such as:: # $ % & ~ _ ^ \ { } diff --git a/doc/users/pyplot_tutorial.rst b/doc/users/pyplot_tutorial.rst index 258b74200822..9c67249ac9f0 100644 --- a/doc/users/pyplot_tutorial.rst +++ b/doc/users/pyplot_tutorial.rst @@ -248,8 +248,8 @@ you can write a TeX expression surrounded by dollar signs:: plt.title(r'$\sigma_i=15$') -The ``r`` preceeding the title string is important -- it signifies -that the string is a *raw* string and not to treate backslashes and +The ``r`` preceding the title string is important -- it signifies +that the string is a *raw* string and not to treat backslashes and python escapes. matplotlib has a built-in TeX expression parser and layout engine, and ships its own math fonts -- for details see :ref:`mathtext-tutorial`. Thus you can use mathematical text across platforms @@ -280,4 +280,3 @@ variety of other coordinate systems one can choose -- see :ref:`annotations-tutorial` and :ref:`plotting-guide-annotation` for details. More examples can be found in :ref:`pylab_examples-annotation_demo`. - diff --git a/doc/users/recipes.rst b/doc/users/recipes.rst index 0ea5f6f58c9c..216630f9e92f 100644 --- a/doc/users/recipes.rst +++ b/doc/users/recipes.rst @@ -40,7 +40,7 @@ Easily creating subplots In early versions of matplotlib, if you wanted to use the pythonic API and create a figure instance and from that create a grid of subplots, possibly with shared axes, it involved a fair amount of boilerplate -code. Eg +code. e.g. .. sourcecode:: python @@ -258,7 +258,7 @@ the boolean mask is True. In the example below, we simulate a single random walker and compute the analytic mean and standard deviation of the population positions. The population mean is shown as the black dashed line, and the plus/minus one sigma deviation from the mean is -showsn as the yellow filled region. We use the where mask +shown as the yellow filled region. We use the where mask ``X>upper_bound`` to find the region where the walker is above the one sigma boundary, and shade that region blue. @@ -358,7 +358,7 @@ argument takes a dictionary with keys that are Patch properties. textstr = '$\mu=%.2f$\n$\mathrm{median}=%.2f$\n$\sigma=%.2f$'%(mu, median, sigma) ax.hist(x, 50) - # these are matplotlib.patch.Patch properies + # these are matplotlib.patch.Patch properties props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) # place a text box in upper left in axes coords diff --git a/doc/users/screenshots.rst b/doc/users/screenshots.rst index f3853d88e930..2f9b04443300 100644 --- a/doc/users/screenshots.rst +++ b/doc/users/screenshots.rst @@ -4,13 +4,13 @@ Screenshots ********************** -Here you will find a host of example figures with the code that -generated them +Here you'll find a host of example plots with the code that +generated them. Simple Plot =========== -The most basic :func:`~matplotlib.pyplot.plot`, with text labels +Here's a very basic :func:`~matplotlib.pyplot.plot` with text labels: .. plot:: mpl_examples/pylab_examples/simple_plot.py @@ -19,10 +19,10 @@ The most basic :func:`~matplotlib.pyplot.plot`, with text labels Subplot demo ============ -Multiple regular axes (numrows by numcolumns) are created with the -:func:`~matplotlib.pyplot.subplot` command. +Multiple axes (i.e. subplots) are created with the +:func:`~matplotlib.pyplot.subplot` command: -.. plot:: mpl_examples/pylab_examples/subplot_demo.py +.. plot:: mpl_examples/subplots_axes_and_figures/subplot_demo.py .. _screenshots_histogram_demo: @@ -30,9 +30,9 @@ Histograms ========== The :func:`~matplotlib.pyplot.hist` command automatically generates -histograms and will return the bin counts or probabilities +histograms and returns the bin counts or probabilities: -.. plot:: mpl_examples/pylab_examples/histogram_demo.py +.. plot:: mpl_examples/statistics/histogram_demo_features.py .. _screenshots_path_demo: @@ -40,10 +40,10 @@ histograms and will return the bin counts or probabilities Path demo ========= -You can add aribitrary paths in matplotlib as of release 0.98. See -the :mod:`matplotlib.path`. +You can add arbitrary paths in matplotlib using the +:mod:`matplotlib.path` module: -.. plot:: mpl_examples/api/path_patch_demo.py +.. plot:: mpl_examples/shapes_and_collections/path_patch_demo.py .. _screenshots_mplot3d_surface: @@ -52,27 +52,41 @@ mplot3d The mplot3d toolkit (see :ref:`toolkit_mplot3d-tutorial` and :ref:`mplot3d-examples-index`) has support for simple 3d graphs -including surface, wireframe, scatter, and bar charts (added in -matlpotlib-0.99). Thanks to John Porter, Jonathon Taylor and Reinier -Heeres for the mplot3d toolkit. The toolkit is included with all -standard matplotlib installs. +including surface, wireframe, scatter, and bar charts. .. plot:: mpl_examples/mplot3d/surface3d_demo.py +Thanks to John Porter, Jonathon Taylor, Reinier Heeres, and Ben Root for +the `mplot3d` toolkit. This toolkit is included with all standard matplotlib +installs. + .. _screenshots_ellipse_demo: +Streamplot +========== + +The :meth:`~matplotlib.pyplot.streamplot` function plots the streamlines of +a vector field. In addition to simply plotting the streamlines, it allows you +to map the colors and/or line widths of streamlines to a separate parameter, +such as the speed or local intensity of the vector field. + +.. plot:: mpl_examples/images_contours_and_fields/streamplot_demo_features.py + +This feature complements the :meth:`~matplotlib.pyplot.quiver` function for +plotting vector fields. Thanks to Tom Flannaghan and Tony Yu for adding the +streamplot function. + + Ellipses ======== In support of the `Phoenix `_ mission to -Mars, which used matplotlib in ground tracking of the spacecraft, -Michael Droettboom built on work by Charlie Moad to provide an -extremely accurate 8-spline approximation to elliptical arcs (see -:class:`~matplotlib.patches.Arc`) in the viewport. This -provides a scale free, accurate graph of the arc regardless of zoom -level +Mars (which used matplotlib to display ground tracking of spacecraft), +Michael Droettboom built on work by Charlie Moad to provide an extremely +accurate 8-spline approximation to elliptical arcs (see +:class:`~matplotlib.patches.Arc`), which are insensitive to zoom level. .. plot:: mpl_examples/pylab_examples/ellipse_demo.py @@ -81,52 +95,54 @@ level Bar charts ========== -The :func:`~matplotlib.pyplot.bar` -command takes error bars as an optional argument. You can also use up -and down bars, stacked bars, candlestick bars, etc, ... See -`bar_stacked.py `_ for another example. -You can make horizontal bar charts with the -:func:`~matplotlib.pyplot.barh` command. +Bar charts are simple to create using the :func:`~matplotlib.pyplot.bar` +command, which includes customizations such as error bars: .. plot:: mpl_examples/pylab_examples/barchart_demo.py +It's also simple to create stacked bars +(`bar_stacked.py `_), +candlestick bars +(`finance_demo.py `_), +and horizontal bar charts +(`barh_demo.py `_). + .. _screenshots_pie_demo: Pie charts ========== -The :func:`~matplotlib.pyplot.pie` command -uses a MATLAB compatible syntax to produce pie charts. Optional -features include auto-labeling the percentage of area, exploding one -or more wedges out from the center of the pie, and a shadow effect. -Take a close look at the attached code that produced this figure; nine -lines of code. +The :func:`~matplotlib.pyplot.pie` command allows you to easily create pie +charts. Optional features include auto-labeling the percentage of area, +exploding one or more wedges from the center of the pie, and a shadow effect. +Take a close look at the attached code, which generates this figure in just +a few lines of code. -.. plot:: mpl_examples/pylab_examples/pie_demo.py +.. plot:: mpl_examples/pie_and_polar_charts/pie_demo_features.py .. _screenshots_table_demo: Table demo ========== -The :func:`~matplotlib.pyplot.table` command will place a text table -on the axes +The :func:`~matplotlib.pyplot.table` command adds a text table +to an axes. .. plot:: mpl_examples/pylab_examples/table_demo.py .. _screenshots_scatter_demo: + Scatter demo ============ The :func:`~matplotlib.pyplot.scatter` command makes a scatter plot -with (optional) size and color arguments. This example plots changes -in Google stock price from one day to the next with the sizes coding -trading volume and the colors coding price change in day i. Here the -alpha attribute is used to make semitransparent circle markers with -the Agg backend (see :ref:`what-is-a-backend`) +with (optional) size and color arguments. This example plots changes +in Google's stock price, with marker sizes reflecting the +trading volume and colors varying with time. Here, the +alpha attribute is used to make semitransparent circle markers. .. plot:: mpl_examples/pylab_examples/scatter_demo2.py @@ -138,8 +154,8 @@ Slider demo Matplotlib has basic GUI widgets that are independent of the graphical user interface you are using, allowing you to write cross GUI figures -and widgets. See matplotlib.widgets and the widget `examples -` +and widgets. See :mod:`matplotlib.widgets` and the +`widget examples <../examples/widgets/index.html>`_. .. plot:: mpl_examples/widgets/slider_demo.py @@ -150,34 +166,33 @@ Fill demo ========= The :func:`~matplotlib.pyplot.fill` command lets you -plot filled polygons. Thanks to Andrew Straw for providing this -function +plot filled curves and polygons: -.. plot:: mpl_examples/pylab_examples/fill_demo.py +.. plot:: mpl_examples/lines_bars_and_markers/fill_demo.py +Thanks to Andrew Straw for adding this function. .. _screenshots_date_demo: Date demo ========= -You can plot date data with major and minor ticks and custom tick -formatters for both the major and minor ticks; see matplotlib.ticker -and matplotlib.dates for details and usage. +You can plot date data with major and minor ticks and custom tick formatters +for both. .. plot:: mpl_examples/api/date_demo.py +See :mod:`matplotlib.ticker` and :mod:`matplotlib.dates` for details and usage. + .. _screenshots_jdh_demo: Financial charts ================ -You can make much more sophisticated financial plots. This example -emulates one of the `ChartDirector -`_ financial plots. -Some of the data in the plot, are real financial data, some are random -traces that I used since the goal was to illustrate plotting -techniques, not market analysis! +You can make sophisticated financial plots by combining the various +plot functions, layout commands, and labeling tools provided by matplotlib. +The following example emulates one of the financial plots in +`ChartDirector `_: .. plot:: mpl_examples/pylab_examples/finance_work2.py @@ -188,9 +203,7 @@ techniques, not market analysis! Basemap demo ============ -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. +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 @@ -201,16 +214,14 @@ Log plots The :func:`~matplotlib.pyplot.semilogx`, :func:`~matplotlib.pyplot.semilogy` and -:func:`~matplotlib.pyplot.loglog` functions generate log scaling on the -respective axes. The lower subplot uses a base10 log on the xaxis and -a base 4 log on the yaxis. Thanks to Andrew Straw, Darren Dale and -Gregory Lielens for contributions to the log scaling -infrastructure. - - +:func:`~matplotlib.pyplot.loglog` functions simplify the creation of +logarithmic plots. .. plot:: mpl_examples/pylab_examples/log_demo.py +Thanks to Andrew Straw, Darren Dale and Gregory Lielens for contributions +log-scaling infrastructure. + .. _screenshots_polar_demo: Polar plots @@ -222,40 +233,43 @@ The :func:`~matplotlib.pyplot.polar` command generates polar plots. .. _screenshots_legend_demo: + Legends ======= The :func:`~matplotlib.pyplot.legend` command automatically -generates figure legends, with MATLAB compatible legend placement -commands. Thanks to Charles Twardy for input on the legend -command +generates figure legends, with MATLAB-compatible legend placement +commands. .. plot:: mpl_examples/pylab_examples/legend_demo.py +Thanks to Charles Twardy for input on the legend command. + .. _screenshots_mathtext_examples_demo: Mathtext_examples ================= -A sampling of the many TeX expressions now supported by matplotlib's -internal mathtext engine. The mathtext module provides TeX style -mathematical expressions using `freetype2 -`_ and the BaKoMa -computer modern or `STIX `_ fonts. See the -:mod:`matplotlib.mathtext` module for additional. matplotlib mathtext -is an independent implementation, and does not required TeX or any -external packages installed on your computer. See the tutorial at -:ref:`mathtext-tutorial`. +Below is a sampling of the many TeX expressions now supported by matplotlib's +internal mathtext engine. The mathtext module provides TeX style mathematical +expressions using `freetype2 `_ +and the BaKoMa computer modern or `STIX `_ fonts. +See the :mod:`matplotlib.mathtext` module for additional details. .. plot:: mpl_examples/pylab_examples/mathtext_examples.py +Matplotlib's mathtext infrastructure is an independent implementation and +does not require TeX or any external packages installed on your computer. See +the tutorial at :ref:`mathtext-tutorial`. + + .. _screenshots_tex_demo: Native TeX rendering ==================== Although matplotlib's internal math rendering engine is quite -powerful, sometimes you need TeX, and matplotlib supports external TeX +powerful, sometimes you need TeX. Matplotlib supports external TeX rendering of strings with the *usetex* option. .. plot:: pyplots/tex_demo.py @@ -265,17 +279,28 @@ rendering of strings with the *usetex* option. EEG demo ========= -You can embed matplotlib into pygtk, wxpython, Tk, FLTK or Qt -applications. Here is a screenshot of an eeg viewer called pbrain -which is part of the NeuroImaging in Python suite `NIPY -`_. Pbrain is written in pygtk using -matplotlib. The lower axes uses :func:`~matplotlib.pyplot.specgram` -to plot the spectrogram of one of the EEG channels. For an example of -how to use the navigation toolbar in your applications, see -:ref:`user_interfaces-embedding_in_gtk2`. If you want to use -matplotlib in a wx application, see -:ref:`user_interfaces-embedding_in_wx2`. If you want to work with -`glade `_, see -:ref:`user_interfaces-mpl_with_glade`. +You can embed matplotlib into pygtk, wx, Tk, FLTK, or Qt +applications. Here is a screenshot of an EEG viewer called pbrain, +which is part of the NeuroImaging in Python suite +`NIPY `_. .. image:: ../_static/eeg_small.png + +The lower axes uses :func:`~matplotlib.pyplot.specgram` +to plot the spectrogram of one of the EEG channels. + +For examples of how to embed matplotlib in different toolkits, see: + + * :ref:`user_interfaces-embedding_in_gtk2` + * :ref:`user_interfaces-embedding_in_wx2` + * :ref:`user_interfaces-mpl_with_glade` + * :ref:`user_interfaces-embedding_in_qt` + * :ref:`user_interfaces-embedding_in_tk` + +XKCD-style sketch plots +======================= + +matplotlib supports plotting in the style of `xkcd +`. + +.. plot:: mpl_examples/showcase/xkcd.py diff --git a/doc/users/shell.rst b/doc/users/shell.rst index 8eafd25bb623..bdc0ff329f3a 100644 --- a/doc/users/shell.rst +++ b/doc/users/shell.rst @@ -66,7 +66,7 @@ Other python interpreters ========================= If you can't use ipython, and still want to use matplotlib/pylab from -an interactive python shell, e.g. the plain-ole standard python +an interactive python shell, e.g., the plain-ole standard python interactive interpreter, you are going to need to understand what a matplotlib backend is :ref:`what-is-a-backend`. diff --git a/doc/users/text_intro.rst b/doc/users/text_intro.rst index 38cf26654cfe..d4de28a33dce 100644 --- a/doc/users/text_intro.rst +++ b/doc/users/text_intro.rst @@ -51,7 +51,7 @@ interface in the API. All of these functions create and return a -:func:`matplotlib.text.Text` instance, which can bew configured with a +:func:`matplotlib.text.Text` instance, which can be configured with a variety of font and other properties. The example below shows all of these commands in action. diff --git a/doc/users/tight_layout_guide.rst b/doc/users/tight_layout_guide.rst index 7aa831683315..4a28c3d2b9bc 100644 --- a/doc/users/tight_layout_guide.rst +++ b/doc/users/tight_layout_guide.rst @@ -287,7 +287,7 @@ Colorbar If you create a colorbar with the :func:`~matplotlib.pyplot.colorbar` command, the created colorbar is an instance of Axes, *not* Subplot, so tight_layout does not work. With Matplotlib v1.1, you may create a -colobar as a subplot using the gridspec. +colorbar as a subplot using the gridspec. .. plot:: :include-source: diff --git a/doc/users/transforms_tutorial.rst b/doc/users/transforms_tutorial.rst index 7c77c8cb8565..b5fdf38e4819 100644 --- a/doc/users/transforms_tutorial.rst +++ b/doc/users/transforms_tutorial.rst @@ -161,7 +161,7 @@ your axes or subplot, (0.5, 0.5) is the center, and (1.0, 1.0) is the top right. You can also refer to points outside the range, so (-0.1, 1.1) is to the left and above your axes. This coordinate system is extremely useful when placing text in your axes, because you often -want a text bubble in a fixed, location, eg. the upper left of the axes +want a text bubble in a fixed, location, e.g., the upper left of the axes pane, and have that location remain fixed when you pan or zoom. Here is a simple example that creates four panels and labels them 'A', 'B', 'C', 'D' as you often see in journals. @@ -419,7 +419,7 @@ and we can use this same inverted transformation to go from the unit Out[90]: array([ 2.5, -0.5]) The final piece is the ``self.transScale`` attribute, which is -responsible for the optional non-linear scaling of the data, eg. for +responsible for the optional non-linear scaling of the data, e.g., for logarithmic axes. When an Axes is initially setup, this is just set to the identity transform, since the basic matplotlib axes has linear scale, but when you call a logarithmic scaling function like @@ -441,7 +441,7 @@ the typical separable matplotlib Axes, with one additional piece (self.transProjectionAffine + self.transAxes) ``transProjection`` handles the projection from the space, -eg. latitude and longitude for map data, or radius and theta for polar +e.g., latitude and longitude for map data, or radius and theta for polar data, to a separable Cartesian coordinate system. There are several projection examples in the ``matplotlib.projections`` package, and the best way to learn more is to open the source for those packages and diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 0ef4d78e35ca..a35600a772e2 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -17,6 +17,255 @@ revision, see the :ref:`github-stats`. .. contents:: Table of Contents +.. _whats-new-1-3: + +new in matplotlib-1.3 +===================== + +Housecleaning +------------- + +A number of features that were deprecated in 1.2 or earlier, or have +not been in a working state for a long time have been removed. +Highlights include removing the Qt version 3 backends, and the FltkAgg +and Emf backends. See :ref:`changes_in_1_3` for a complete list. + +New setup script +---------------- + +matplotlib 1.3 includes an entirely rewritten setup script. We now +ship fewer dependencies with the tarballs and installers themselves. +Notably, `pytz`, `dateutil` and `pyparsing` are no longer included +with matplotlib. You can either install them manually first, or let +`pip` install them as depdencies along with matplotlib. It is now +possible to not include certain subcomponents, such as the unit test +data, in the install. See `setup.cfg.template` for more information. + +`xkcd`-style sketch plotting +---------------------------- + +To give your plots a sense of authority that they may be missing, +Michael Droettboom (inspired by the work of many others in +:ghpull:`1329`) has added an `xkcd-style `_ sketch +plotting mode. To use it, simply call :func:`matplotlib.pyplot.xkcd` +before creating your plot. For really fine control, it is also possible +to modify each artist's sketch parameters individually with +:meth:`matplotlib.artist.Artist.set_sketch_params`. + +.. plot:: mpl_examples/showcase/xkcd.py + +WebAgg backend +-------------- + +Michael Droettboom, Phil Elson and others have developed a new +backend, WebAgg, to display figures in a web browser. It works with +animations as well as being fully interactive. + +.. image:: /_static/webagg_screenshot.png + +Future versions of matplotlib will integrate this backend with the +IPython notebook for a fully web browser based plotting frontend. + +XDG base directory support +-------------------------- +On Linux, matplotlib now uses the `XDG base directory specification +` +to find the `matplotlibrc` configuration file. `matplotlibrc` should +now be kept in `~/.config/matplotlib`, rather than `~/.matplotlib`. If +your configuration is found in the old location, it will still be used, +but a warning will be displayed. + +Path effects on lines +--------------------- +Thanks to Jae-Joon Lee, path effects now also work on plot lines. + +.. plot:: mpl_examples/pylab_examples/patheffect_demo.py + +Changes to font rcParams +------------------------ +The `font.*` rcParams now affect only text objects created after the +rcParam has been set, and will not retroactively affect already +existing text objects. This brings their behavior in line with most +other rcParams. + +Easier creation of colormap and normalizer for levels with colors +----------------------------------------------------------------- +Phil Elson added the :func:`matplotlib.colors.from_levels_and_colors` +function to easily create a colormap and normalizer for representation +of discrete colors for plot types such as +:func:`matplotlib.pyplot.pcolormesh`, with a similar interface to that of +contourf. + +Catch opening too many figures using pyplot +------------------------------------------- +Figures created through `pyplot.figure` are retained until they are +explicitly closed. It is therefore common for new users of matplotlib +to run out of memory when creating a large series of figures in a +loop without closing them. + +matplotlib will now display a `RuntimeWarning` when too many figures +have been opened at once. By default, this is displayed for 20 or +more figures, but the exact number may be controlled using the +``figure.max_num_figures`` rcParam. + +``axes.xmargin`` and ``axes.ymargin`` added to rcParams +------------------------------------------------------- +``rcParam`` values (``axes.xmargin`` and ``axes.ymargin``) were added +to configure the default margins used. Previously they were +hard-coded to default to 0, default value of both rcParam values is 0. + +New eventplot plot type +------------------------------------- +Todd Jennings added a :func:`~matplotlib.pyplot.eventplot` function to +create multiple rows or columns of identical line segments + +New EventCollection collections class +------------------------------------- +Todd Jennings created the new :class:`~matplotlib.collections.EventCollection` +class that allows for plotting and manipulating rows or columns of identical +line segments + +Baselines for stackplot +----------------------- +Till Stensitzki added non-zero baselines to :func:`~matplotlib.pyplot.stackplot`. +They may be symmetric or weighted. + +.. plot:: mpl_examples/pylab_examples/stackplot_demo2.py + +Improved ``bbox_inches="tight"`` functionality +---------------------------------------------- +Passing ``bbox_inches="tight"`` through to :func:`plt.save` now takes into account +*all* artists on a figure - this was previously not the case and led to several +corner cases which did not function as expected. + +Remember save directory +----------------------- +Martin Spacek made the save figure dialog remember the last directory saved +to. The default is configurable with the new `savefig.directory` setting +in `matplotlibrc`. + +Initialize a rotated rectangle +------------------------------ +Damon McDougall extended the :class:`~matplotlib.patches.Rectangle` constructor +to accept an `angle` kwarg, specifying the rotation of a rectangle in degrees. + +Rectangular colorbar extensions +------------------------------- +Andrew Dawson added a new keyword argument *extendrect* to +:meth:`~matplotlib.pyplot.colorbar` to optionally make colorbar +extensions rectangular instead of triangular. + +Examples now use subplots() +--------------------------- +For the sake of brevity and clarity, most of the :ref:`examples +` now use the newer :func:`~matplotlib.pyplot.subplots`, which +creates a figure and one (or multiple) axes object(s) in one call. The old way +involved a call to :func:`~matplotlib.pyplot.figure`, followed by one (or +multiple) :func:`~matplotlib.pyplot.subplot` calls. + +Calling subplot() without arguments +----------------------------------- +A call to :func:`~matplotlib.pyplot.subplot` without any arguments now +acts the same as `subplot(111)` or `subplot(1,1,1)` -- it creates one axes for +the whole figure. This was already the behavior for both +:func:`~matplotlib.pyplot.axes` and :func:`~matplotlib.pyplot.subplots`, and +now this consistency is shared with :func:`~matplotlib.pyplot.subplot`. + +Anchored text support +--------------------- +The `svg` and `pgf` backends are now able to save text alignment information +to their output formats. This allows to edit text elements in saved figures, +using Inkscape for example, while preserving their intended position. For +`svg` please note that you'll have to disable the default text-to-path +conversion (`mpl.rc('svg', fonttype='none')`). + +More robust boxplots +-------------------- +Paul Hobson provided a fix to the :func:`~matplotlib.pyplot.boxplot` +method that prevent whiskers from being drawn inside the box for +oddly distributed data sets. + +Triangular grid interpolation +----------------------------- +Geoffroy Billotey and Ian Thomas added classes to perform interpolation within +triangular grids: (:class:`~matplotlib.tri.LinearTriInterpolator` and +:class:`~matplotlib.tri.CubicTriInterpolator`) and a utility class to find +the triangles in which points lie ( +:class:`~matplotlib.tri.TrapezoidMapTriFinder`). +A helper class to perform mesh refinement and smooth contouring was also added +(:class:`~matplotlib.tri.UniformTriRefiner`). +Finally, a class implementing some basic tools for triangular mesh improvement +was added (:class:`~matplotlib.tri.TriAnalyzer`). + +.. plot:: mpl_examples/pylab_examples/tricontour_smooth_user.py + +Left and right side axes titles +------------------------------- +Andrew Dawson added the ability to add axes titles flush with the left and +right sides of the top of the axes using a new keyword argument `loc` to +:func:`~matplotlib.pyplot.title`. + +Improved manual contour plot label positioning +---------------------------------------------- + +Brian Mattern modified the manual contour plot label positioning code to +interpolate along line segments and find the actual closest point on a +contour to the requested position. Previously, the closest path vertex was +used, which, in the case of straight contours was sometimes quite distant +from the requested location. Much more precise label positioning is now +possible. + +Quickly find rcParams +--------------------- +Phil Elson made it easier to search for rcParameters by passing a +valid regular expression to :func:`matplotlib.RcParams.find_all`. +:class:`matplotlib.RcParams` now also has a pretty repr and str representation +so that search results are printed prettily: + + >>> import matplotlib + >>> print(matplotlib.rcParams.find_all('\.size')) + RcParams({'font.size': 12, + 'xtick.major.size': 4, + 'xtick.minor.size': 2, + 'ytick.major.size': 4, + 'ytick.minor.size': 2}) + +Better vertical text alignment +------------------------------ + +The vertical alignment of text is now consistent across backends. You +may see small differences in text placement, particularly with rotated +text. + +If you are using a custom backend, note that the `draw_text` renderer +method is now passed the location of the baseline, not the location of +the bottom of the text bounding box. + +``savefig.jpeg_quality`` added to rcParams +------------------------------------------------------------------------------ +``rcParam`` value ``savefig.jpeg_quality`` was added so that the user can +configure the default quality used when a figure is written as a JPEG. The +default quality is 95; previously, the default quality was 75. This change +minimizes the artifacting inherent in JPEG images, particularly with images +that have sharp changes in color as plots often do. + +Full control of the background color +------------------------------------ +Wes Campaigne and Phil Elson fixed the Agg backend such that PNGs are now +saved with the correct background color when :meth:`fig.patch.get_alpha` is +not 1. + +Independent alpha values for face and edge colors +------------------------------------------------- +Wes Campaigne modified how :class:`~matplotlib.patches.Patch` objects are +drawn such that (for backends supporting transparency) you can set different +alpha values for faces and edges, by specifying their colors in RGBA format. +Note that if you set the alpha attribute for the patch object (e.g. using +:meth:`~matplotlib.patches.Patch.set_alpha` or the ``alpha`` keyword +argument), that value will override the alpha components set in both the +face and edge colors. + + .. _whats-new-1-2-2: new in matplotlib 1.2.2 @@ -181,7 +430,7 @@ In addition to simply plotting the streamlines of the vector field, line widths of the streamlines to a separate parameter, such as the speed or local intensity of the vector field. -.. plot:: mpl_examples/pylab_examples/streamplot_demo.py +.. plot:: mpl_examples/images_contours_and_fields/streamplot_demo_features.py New hist functionality @@ -270,7 +519,7 @@ Tight Layout A frequent issue raised by users of matplotlib is the lack of a layout engine to nicely space out elements of the plots. While matplotlib still -adheres to the philosphy of giving users complete control over the placement +adheres to the philosophy of giving users complete control over the placement of plot elements, Jae-Joon Lee created the :mod:`~matplotlib.tight_layout` module and introduced a new command :func:`~matplotlib.pyplot.tight_layout` @@ -284,7 +533,7 @@ to address the most common layout issues. fig, axes_list = plt.subplots(2, 1) for ax in axes_list.flat: ax.set(xlabel="x-label", ylabel="y-label", title="before tight_layout") - ax.locator_params(nbins=3) + ax.locator_params(nbins=3) plt.show() @@ -294,7 +543,7 @@ to address the most common layout issues. fig, axes_list = plt.subplots(2, 1) for ax in axes_list.flat: ax.set(xlabel="x-label", ylabel="y-label", title="after tight_layout") - ax.locator_params(nbins=3) + ax.locator_params(nbins=3) plt.tight_layout() plt.show() @@ -428,7 +677,7 @@ Other improvements * Pim Schellart added a new colormap called "cubehelix". Sameer Grover also added a colormap called "coolwarm". See it and all - other colormaps :ref:`here `. + other colormaps :ref:`here `. * Many bug fixes and documentation improvements. @@ -465,7 +714,7 @@ Fernando Perez got tired of all the boilerplate code needed to create a figure and multiple subplots when using the matplotlib API, and wrote a :func:`~matplotlib.pyplot.subplots` helper function. Basic usage allows you to create the figure and an array of subplots with numpy -indexing (starts with 0). Eg:: +indexing (starts with 0). e.g.:: fig, axarr = plt.subplots(2, 2) axarr[0,0].plot([1,2,3]) # upper, left @@ -659,7 +908,7 @@ multiple columns and rows, as well as fancy box drawing. See Fancy annotations and arrows ----------------------------- -Jae-Joon has added lot's of support to annotations for drawing fancy +Jae-Joon has added lots of support to annotations for drawing fancy boxes and connectors in annotations. See :func:`~matplotlib.pyplot.annotate` and :class:`~matplotlib.patches.BoxStyle`, @@ -693,7 +942,7 @@ Ryan May did a lot of work to rationalize the amplitude scaling of :func:`~matplotlib.pyplot.psd` and friends. See :ref:`pylab_examples-psd_demo2`. and :ref:`pylab_examples-psd_demo3`. The changes should increase MATLAB -compatabililty and increase scaling options. +compatibility and increase scaling options. .. _fill-between: @@ -703,7 +952,7 @@ Fill between Added a :func:`~matplotlib.pyplot.fill_between` function to make it easier to do shaded region plots in the presence of masked data. You can pass an *x* array and a *ylower* and *yupper* array to fill -betweem, and an optional *where* argument which is a logical mask +between, and an optional *where* argument which is a logical mask where you want to do the filling. .. plot:: pyplots/whats_new_98_4_fill_between.py @@ -716,14 +965,14 @@ Here are the 0.98.4 notes from the CHANGELOG:: Added mdehoon's native macosx backend from sf patch 2179017 - JDH Removed the prints in the set_*style commands. Return the list of - pprinted strings instead - JDH + pretty-printed strings instead - JDH Some of the changes Michael made to improve the output of the property tables in the rest docs broke of made difficult to use some of the interactive doc helpers, eg setp and getp. Having all the rest markup in the ipython shell also confused the docstrings. I added a new rc param docstring.harcopy, to format the docstrings - differently for hardcopy and other use. Ther ArtistInspector + differently for hardcopy and other use. The ArtistInspector could use a little refactoring now since there is duplication of effort between the rest out put and the non-rest output - JDH @@ -743,7 +992,7 @@ Here are the 0.98.4 notes from the CHANGELOG:: Fixed a bug that the handlelength of the new legend class set too short when numpoints=1 -JJL - Added support for data with units (e.g. dates) to + Added support for data with units (e.g., dates) to Axes.fill_between. -RM Added fancybox keyword to legend. Also applied some changes for @@ -755,19 +1004,19 @@ Here are the 0.98.4 notes from the CHANGELOG:: are added. -JJL Fixed a bug in the new legend class that didn't allowed a tuple of - coordinate vlaues as loc. -JJL + coordinate values as loc. -JJL Improve checks for external dependencies, using subprocess (instead of deprecated popen*) and distutils (for version checking) - DSD - Reimplementaion of the legend which supports baseline alignement, + Reimplementation of the legend which supports baseline alignment, multi-column, and expand mode. - JJL Fixed histogram autoscaling bug when bins or range are given explicitly (fixes Debian bug 503148) - MM - Added rcParam axes.unicode_minus which allows plain hypen for + Added rcParam axes.unicode_minus which allows plain hyphen for minus when False - JDH Added scatterpoints support in Legend. patch by Erik Tollerud - @@ -791,7 +1040,7 @@ Here are the 0.98.4 notes from the CHANGELOG:: Add 'pad_to' and 'sides' parameters to mlab.psd() to allow controlling of zero padding and returning of negative frequency - components, respecitively. These are added in a way that does not + components, respectively. These are added in a way that does not change the API. - RM Fix handling of c kwarg by scatter; generalize is_string_like to @@ -820,7 +1069,7 @@ Here are the 0.98.4 notes from the CHANGELOG:: Jae-Joon Lee. - MM Fixed bug in pdf backend: if you pass a file object for output - instead of a filename, e.g. in a wep app, we now flush the object + instead of a filename, e.g., in a wep app, we now flush the object at the end. - JKS Add path simplification support to paths with gaps. - EF @@ -902,3 +1151,7 @@ Here are the 0.98.4 notes from the CHANGELOG:: off automatically when infs or NaNs are present. Also masked arrays are now converted to arrays with NaNs for consistent handling of masks and NaNs - MGD and EF + + Added support for arbitrary rasterization resolutions to the SVG + backend. - MW + diff --git a/examples/animation/animate_decay.py b/examples/animation/animate_decay.py index 90267c605032..a8694615e99b 100644 --- a/examples/animation/animate_decay.py +++ b/examples/animation/animate_decay.py @@ -11,8 +11,7 @@ def data_gen(): yield t, np.sin(2*np.pi*t) * np.exp(-t/10.) data_gen.t = 0 -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() line, = ax.plot([], [], lw=2) ax.set_ylim(-1.1, 1.1) ax.set_xlim(0, 5) diff --git a/examples/animation/bayes_update.py b/examples/animation/bayes_update.py new file mode 100644 index 000000000000..e3ba5a356a20 --- /dev/null +++ b/examples/animation/bayes_update.py @@ -0,0 +1,47 @@ +# update a distribution based on new data. +import numpy as np +import matplotlib.pyplot as plt +import scipy.stats as ss +from matplotlib.animation import FuncAnimation + +class UpdateDist(object): + def __init__(self, ax, prob=0.5): + self.success = 0 + self.prob = prob + self.line, = ax.plot([], [], 'k-') + self.x = np.linspace(0, 1, 200) + self.ax = ax + + # Set up plot parameters + self.ax.set_xlim(0, 1) + self.ax.set_ylim(0, 15) + self.ax.grid(True) + + # This vertical line represents the theoretical value, to + # which the plotted distribution should converge. + self.ax.axvline(prob, linestyle='--', color='black') + + def init(self): + self.success = 0 + self.line.set_data([], []) + return self.line, + + def __call__(self, i): + # This way the plot can continuously run and we just keep + # watching new realizations of the process + if i == 0: + return self.init() + + # Choose success based on exceed a threshold with a uniform pick + if np.random.rand(1,) < self.prob: + self.success += 1 + y = ss.beta.pdf(self.x, self.success + 1, (i - self.success) + 1) + self.line.set_data(self.x, y) + return self.line, + +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1) +ud = UpdateDist(ax, prob=0.7) +anim = FuncAnimation(fig, ud, frames=np.arange(100), init_func=ud.init, + interval=100, blit=True) +plt.show() diff --git a/examples/animation/histogram.py b/examples/animation/histogram.py index b1aa9249dff7..f81d4f397269 100644 --- a/examples/animation/histogram.py +++ b/examples/animation/histogram.py @@ -9,8 +9,7 @@ import matplotlib.path as path import matplotlib.animation as animation -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() # histogram our data with numpy data = np.random.randn(1000) diff --git a/examples/animation/old_animation/animate_decay_tk_blit.py b/examples/animation/old_animation/animate_decay_tk_blit.py index cae4c4a2b973..36e451f803f6 100644 --- a/examples/animation/old_animation/animate_decay_tk_blit.py +++ b/examples/animation/old_animation/animate_decay_tk_blit.py @@ -10,8 +10,7 @@ def data_gen(): return np.sin(2*np.pi*t) * np.exp(-t/10.) data_gen.t = 0 -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() line, = ax.plot([], [], animated=True, lw=2) ax.set_ylim(-1.1, 1.1) ax.set_xlim(0, 5) diff --git a/examples/animation/old_animation/animation_blit_fltk.py b/examples/animation/old_animation/animation_blit_fltk.py deleted file mode 100644 index 9a178bc540ff..000000000000 --- a/examples/animation/old_animation/animation_blit_fltk.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import print_function -import sys -import fltk -import matplotlib -matplotlib.use('FltkAgg') -import pylab as p -import numpy as npy -import time - - -# save the clean slate background -- everything but the animated line -# is drawn and saved in the pixel buffer background -class animator: - def __init__(self,ax): - self.ax=ax - self.canvas=ax.figure.canvas - self.canvas.mpl_connect('draw_event',self.clear) - self.cnt=0 - self.background=None - - # for profiling - self.tstart = time.time() - - def clear(self,event): - self.background = self.canvas.copy_from_bbox(self.ax.bbox) - - def update(self,ptr): - # restore the clean slate background - if self.background is None: - self.background = self.canvas.copy_from_bbox(self.ax.bbox) - self.canvas.restore_region(self.background) - # update the data - line.set_ydata(npy.sin(x+self.cnt/10.0)) - # just draw the animated artist - self.ax.draw_artist(line) - # just redraw the axes rectangle - self.canvas.blit(ax.bbox) - self.cnt+=1 - if self.cnt==1000: - # print the timing info and quit - print('FPS:' , 1000/(time.time()-self.tstart)) - sys.exit() - return True - -ax = p.subplot(111) -p.subplots_adjust(left=0.3, bottom=0.3) # check for flipy bugs -p.grid() # to ensure proper background restore -# create the initial line -x = npy.arange(0,2*npy.pi,0.01) -line, = p.plot(x, npy.sin(x), animated=True) -p.draw() -anim=animator(ax) - -fltk.Fl.add_idle(anim.update) -fltk.Fl.run() diff --git a/examples/animation/old_animation/animation_blit_gtk.py b/examples/animation/old_animation/animation_blit_gtk.py index a13fed6d3ff8..9200daf778f7 100755 --- a/examples/animation/old_animation/animation_blit_gtk.py +++ b/examples/animation/old_animation/animation_blit_gtk.py @@ -16,8 +16,7 @@ import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() canvas = fig.canvas fig.subplots_adjust(left=0.3, bottom=0.3) # check for flipy bugs diff --git a/examples/animation/old_animation/animation_blit_gtk2.py b/examples/animation/old_animation/animation_blit_gtk2.py index b15b1ab177a6..58673fd95c2d 100755 --- a/examples/animation/old_animation/animation_blit_gtk2.py +++ b/examples/animation/old_animation/animation_blit_gtk2.py @@ -148,9 +148,8 @@ def update_line(self, *args): plt.rcParams["text.usetex"] = False -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.xaxis.set_animated(True) ax.yaxis.set_animated(True) canvas = fig.canvas diff --git a/examples/animation/old_animation/animation_blit_qt.py b/examples/animation/old_animation/animation_blit_qt.py deleted file mode 100644 index 272997315e93..000000000000 --- a/examples/animation/old_animation/animation_blit_qt.py +++ /dev/null @@ -1,66 +0,0 @@ -# For detailed comments on animation and the techniqes used here, see -# the wiki entry http://www.scipy.org/Cookbook/Matplotlib/Animations - -from __future__ import print_function - -import os, sys -import matplotlib -matplotlib.use('QtAgg') # qt3 example - -from qt import * -# Note: color-intensive applications may require a different color allocation -# strategy. -QApplication.setColorSpec(QApplication.NormalColor) - -TRUE = 1 -FALSE = 0 -ITERS = 1000 - -import pylab as p -import numpy as npy -import time - -class BlitQT(QObject): - def __init__(self): - QObject.__init__(self, None, "app") - - self.ax = p.subplot(111) - self.canvas = self.ax.figure.canvas - self.cnt = 0 - - # create the initial line - self.x = npy.arange(0,2*npy.pi,0.01) - self.line, = p.plot(self.x, npy.sin(self.x), animated=True, lw=2) - - self.background = None - - def timerEvent(self, evt): - if self.background is None: - self.background = self.canvas.copy_from_bbox(self.ax.bbox) - - # restore the clean slate background - self.canvas.restore_region(self.background) - # update the data - self.line.set_ydata(npy.sin(self.x+self.cnt/10.0)) - # just draw the animated artist - self.ax.draw_artist(self.line) - # just redraw the axes rectangle - self.canvas.blit(self.ax.bbox) - - if self.cnt==ITERS: - # print the timing info and quit - print('FPS:', ITERS/(time.time()-self.tstart)) - sys.exit() - - else: - self.cnt += 1 - -p.subplots_adjust(left=0.3, bottom=0.3) # check for flipy bugs -p.grid() # to ensure proper background restore - -app = BlitQT() -# for profiling -app.tstart = time.time() -app.startTimer(0) - -p.show() diff --git a/examples/animation/old_animation/animation_blit_tk.py b/examples/animation/old_animation/animation_blit_tk.py index 54e288efd621..19779aba4a15 100644 --- a/examples/animation/old_animation/animation_blit_tk.py +++ b/examples/animation/old_animation/animation_blit_tk.py @@ -7,17 +7,17 @@ matplotlib.use('TkAgg') import sys -import pylab as p +import matplotlib.pyplot as plt import numpy as npy import time -ax = p.subplot(111) -canvas = ax.figure.canvas +fig, ax = plt.subplots() +canvas = fig.canvas # create the initial line x = npy.arange(0,2*npy.pi,0.01) -line, = p.plot(x, npy.sin(x), animated=True, lw=2) +line, = plt.plot(x, npy.sin(x), animated=True, lw=2) def run(*args): background = canvas.copy_from_bbox(ax.bbox) @@ -43,12 +43,12 @@ def run(*args): run.cnt = 0 -p.subplots_adjust(left=0.3, bottom=0.3) # check for flipy bugs -p.grid() # to ensure proper background restore -manager = p.get_current_fig_manager() +plt.subplots_adjust(left=0.3, bottom=0.3) # check for flipy bugs +plt.grid() # to ensure proper background restore +manager = plt.get_current_fig_manager() manager.window.after(100, run) -p.show() +plt.show() diff --git a/examples/animation/old_animation/animation_blit_wx.py b/examples/animation/old_animation/animation_blit_wx.py index f2ad18be03d7..dc7d90c75bc6 100644 --- a/examples/animation/old_animation/animation_blit_wx.py +++ b/examples/animation/old_animation/animation_blit_wx.py @@ -10,6 +10,7 @@ import matplotlib matplotlib.use('WXAgg') matplotlib.rcParams['toolbar'] = 'None' +import matplotlib.pyplot as plt import wx import sys @@ -24,8 +25,8 @@ matplotlib.backends.backend_wxagg._use_accelerator(False) -ax = p.subplot(111) -canvas = ax.figure.canvas +fig, ax = plt.subplots() +canvas = fig.canvas p.subplots_adjust(left=0.3, bottom=0.3) # check for flipy bugs diff --git a/examples/animation/old_animation/draggable_legend.py b/examples/animation/old_animation/draggable_legend.py index 93895a78d046..2a6d8041b6b8 100644 --- a/examples/animation/old_animation/draggable_legend.py +++ b/examples/animation/old_animation/draggable_legend.py @@ -1,13 +1,12 @@ import matplotlib.pyplot as plt - -ax = plt.subplot(111) +fig, ax = plt.subplots() ax.plot([1,2,3], label="test") l = ax.legend() d1 = l.draggable() -xy = 1, 2 +xy = 1, 2 txt = ax.annotate("Test", xy, xytext=(-30, 30), textcoords="offset points", bbox=dict(boxstyle="round",fc=(0.2, 1, 1)), diff --git a/examples/animation/old_animation/gtk_timeout.py b/examples/animation/old_animation/gtk_timeout.py index b35e2b659dd1..d76f609cdb9e 100644 --- a/examples/animation/old_animation/gtk_timeout.py +++ b/examples/animation/old_animation/gtk_timeout.py @@ -5,8 +5,7 @@ import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() line, = ax.plot(np.random.rand(10)) ax.set_ylim(0, 1) diff --git a/examples/animation/old_animation/histogram_tkagg.py b/examples/animation/old_animation/histogram_tkagg.py index 5536e4477d32..ff37fc48bc7d 100644 --- a/examples/animation/old_animation/histogram_tkagg.py +++ b/examples/animation/old_animation/histogram_tkagg.py @@ -2,7 +2,6 @@ This example shows how to use a path patch to draw a bunch of rectangles for an animated histogram """ -import time import numpy as np import matplotlib matplotlib.use('TkAgg') # do this before importing pylab @@ -11,8 +10,7 @@ import matplotlib.patches as patches import matplotlib.path as path -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() # histogram our data with numpy data = np.random.randn(1000) diff --git a/examples/animation/old_animation/simple_anim_gtk.py b/examples/animation/old_animation/simple_anim_gtk.py index 6a851edd18db..ecdec7333640 100644 --- a/examples/animation/old_animation/simple_anim_gtk.py +++ b/examples/animation/old_animation/simple_anim_gtk.py @@ -9,9 +9,7 @@ import matplotlib.pyplot as plt -fig = plt.figure() - -ax = fig.add_subplot(111) +fig, ax = plt.subplots() def animate(): tstart = time.time() # for profiling diff --git a/examples/animation/old_animation/simple_anim_tkagg.py b/examples/animation/old_animation/simple_anim_tkagg.py index 427323ff14b2..e8a3a5ca314e 100755 --- a/examples/animation/old_animation/simple_anim_tkagg.py +++ b/examples/animation/old_animation/simple_anim_tkagg.py @@ -10,8 +10,7 @@ matplotlib.use('TkAgg') # do this before importing pylab import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() def animate(): tstart = time.time() # for profiling diff --git a/examples/animation/old_animation/simple_idle_wx.py b/examples/animation/old_animation/simple_idle_wx.py index bcc77df9137b..16541597623b 100644 --- a/examples/animation/old_animation/simple_idle_wx.py +++ b/examples/animation/old_animation/simple_idle_wx.py @@ -2,16 +2,13 @@ A simple example of an animated plot using a wx backend """ from __future__ import print_function -import time import numpy as np import matplotlib matplotlib.use('WXAgg') # do this before importing pylab import matplotlib.pyplot as plt -fig = plt.figure() - -ax = fig.add_subplot(111) +fig, ax = plt.subplots() t = np.arange(0, 2*np.pi, 0.1) line, = ax.plot(t, np.sin(t)) dt = 0.05 diff --git a/examples/animation/old_animation/simple_timer_wx.py b/examples/animation/old_animation/simple_timer_wx.py index 6e7b1607c591..a427524effd6 100644 --- a/examples/animation/old_animation/simple_timer_wx.py +++ b/examples/animation/old_animation/simple_timer_wx.py @@ -2,16 +2,13 @@ """ A simple example of an animated plot using a wx backend """ -import time import numpy as np import matplotlib matplotlib.use('WXAgg') # do this before importing pylab import matplotlib.pyplot as plt -fig = plt.figure() - -ax = fig.add_subplot(111) +fig, ax = plt.subplots() t = np.arange(0, 2*np.pi, 0.1) line, = ax.plot(t, np.sin(t)) dt = 0.05 diff --git a/examples/animation/old_animation/strip_chart_demo.py b/examples/animation/old_animation/strip_chart_demo.py index ac7587a261d3..7f659afd020e 100644 --- a/examples/animation/old_animation/strip_chart_demo.py +++ b/examples/animation/old_animation/strip_chart_demo.py @@ -13,6 +13,7 @@ import matplotlib matplotlib.use('GTKAgg') import numpy as np +import matplotlib.pyplot as plt from matplotlib.lines import Line2D @@ -62,11 +63,8 @@ def update(self, *args): return True -from pylab import figure, show - -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() scope = Scope(ax) gobject.idle_add(scope.update) -show() +plt.show() diff --git a/examples/animation/random_data.py b/examples/animation/random_data.py index 1a31e963a246..c3044a3dee61 100644 --- a/examples/animation/random_data.py +++ b/examples/animation/random_data.py @@ -2,8 +2,7 @@ import matplotlib.pyplot as plt import matplotlib.animation as animation -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() line, = ax.plot(np.random.rand(10)) ax.set_ylim(0, 1) diff --git a/examples/animation/simple_anim.py b/examples/animation/simple_anim.py index 78c9cdfc3ae2..d19196337522 100644 --- a/examples/animation/simple_anim.py +++ b/examples/animation/simple_anim.py @@ -5,8 +5,7 @@ import matplotlib.pyplot as plt import matplotlib.animation as animation -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() x = np.arange(0, 2*np.pi, 0.01) # x-array line, = ax.plot(x, np.sin(x)) diff --git a/examples/animation/strip_chart_demo.py b/examples/animation/strip_chart_demo.py index 119fac9f6719..2ca94cf5a1ac 100644 --- a/examples/animation/strip_chart_demo.py +++ b/examples/animation/strip_chart_demo.py @@ -2,7 +2,6 @@ Emulate an oscilloscope. Requires the animation API introduced in matplotlib 1.0 SVN. """ -import matplotlib import numpy as np from matplotlib.lines import Line2D import matplotlib.pyplot as plt @@ -44,8 +43,7 @@ def emitter(p=0.03): else: yield np.random.rand(1) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() scope = Scope(ax) # pass a generator in "emitter" to produce data for the update func diff --git a/examples/api/README.txt b/examples/api/README.txt index dec5d9da970d..a0b901f9d20c 100644 --- a/examples/api/README.txt +++ b/examples/api/README.txt @@ -29,8 +29,7 @@ A simple example of the recommended style is:: import numpy as np import matplotlib.pyplot as plt - fig = plt.figure() - ax = fig.add_subplot(111) # or add_axes + fig, ax = plt.subplots() ax.plot(np.random.rand(10)) ax.set_xlabel('some x data') ax.set_ylabel('some y data') diff --git a/examples/api/artist_demo.py b/examples/api/artist_demo.py deleted file mode 100644 index 35dc77759c63..000000000000 --- a/examples/api/artist_demo.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Show examples of matplotlib artists -http://matplotlib.org/api/artist_api.html - -Several examples of standard matplotlib graphics primitives (artists) -are drawn using matplotlib API. Full list of artists and the -documentation is available at -http://matplotlib.org/api/artist_api.html - -Copyright (c) 2010, Bartosz Telenczuk - -License: This work is licensed under the BSD. A copy should be -included with this source code, and is also available at -http://www.opensource.org/licenses/bsd-license.php -""" - - -import numpy as np -import matplotlib.pyplot as plt -import matplotlib -from matplotlib.collections import PatchCollection -import matplotlib.path as mpath -import matplotlib.patches as mpatches -import matplotlib.lines as mlines - -font = "sans-serif" -fig = plt.figure(figsize=(5,5)) -ax = plt.axes([0,0,1,1]) - -# create 3x3 grid to plot the artists -pos = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1) - -patches = [] - -# add a circle -art = mpatches.Circle(pos[:,0], 0.1,ec="none") -patches.append(art) -plt.text(pos[0,0], pos[1,0]-0.15, "Circle", ha="center", - family=font, size=14) - -# add a rectangle -art = mpatches.Rectangle(pos[:,1] - np.array([0.025, 0.05]), 0.05, 0.1, - ec="none") -patches.append(art) -plt.text(pos[0,1], pos[1,1]-0.15, "Rectangle", ha="center", - family=font, size=14) - -# add a wedge -wedge = mpatches.Wedge(pos[:,2], 0.1, 30, 270, ec="none") -patches.append(wedge) -plt.text(pos[0,2], pos[1,2]-0.15, "Wedge", ha="center", - family=font, size=14) - -# add a Polygon -polygon = mpatches.RegularPolygon(pos[:,3], 5, 0.1) -patches.append(polygon) -plt.text(pos[0,3], pos[1,3]-0.15, "Polygon", ha="center", - family=font, size=14) - -#add an ellipse -ellipse = mpatches.Ellipse(pos[:,4], 0.2, 0.1) -patches.append(ellipse) -plt.text(pos[0,4], pos[1,4]-0.15, "Ellipse", ha="center", - family=font, size=14) - -#add an arrow -arrow = mpatches.Arrow(pos[0,5]-0.05, pos[1,5]-0.05, 0.1, 0.1, width=0.1) -patches.append(arrow) -plt.text(pos[0,5], pos[1,5]-0.15, "Arrow", ha="center", - family=font, size=14) - -# add a path patch -Path = mpath.Path -verts = np.array([ - (0.158, -0.257), - (0.035, -0.11), - (-0.175, 0.20), - (0.0375, 0.20), - (0.085, 0.115), - (0.22, 0.32), - (0.3, 0.005), - (0.20, -0.05), - (0.158, -0.257), - ]) -verts = verts-verts.mean(0) -codes = [Path.MOVETO, - Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.LINETO, - Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY] - -path = mpath.Path(verts/2.5+pos[:,6], codes) -patch = mpatches.PathPatch(path) -patches.append(patch) -plt.text(pos[0,6], pos[1,6]-0.15, "PathPatch", ha="center", - family=font, size=14) - -# add a fancy box -fancybox = mpatches.FancyBboxPatch( - pos[:,7]-np.array([0.025, 0.05]), 0.05, 0.1, - boxstyle=mpatches.BoxStyle("Round", pad=0.02)) -patches.append(fancybox) -plt.text(pos[0,7], pos[1,7]-0.15, "FancyBoxPatch", ha="center", - family=font, size=14) - -# add a line -x,y = np.array([[-0.06, 0.0, 0.1], [0.05,-0.05, 0.05]]) -line = mlines.Line2D(x+pos[0,8], y+pos[1,8], lw=5., - alpha=0.4) -plt.text(pos[0,8], pos[1,8]-0.15, "Line2D", ha="center", - family=font, size=14) - -colors = 100*np.random.rand(len(patches)) -collection = PatchCollection(patches, cmap=matplotlib.cm.jet, alpha=0.4) -collection.set_array(np.array(colors)) -ax.add_collection(collection) -ax.add_line(line) -ax.set_xticks([]) -ax.set_yticks([]) - -plt.show() diff --git a/examples/api/barchart_demo.py b/examples/api/barchart_demo.py index 2c3468a47625..a717eb7541ec 100644 --- a/examples/api/barchart_demo.py +++ b/examples/api/barchart_demo.py @@ -11,8 +11,7 @@ ind = np.arange(N) # the x locations for the groups width = 0.35 # the width of the bars -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd) womenMeans = (25, 32, 34, 20, 25) diff --git a/examples/api/clippath_demo.py b/examples/api/clippath_demo.py deleted file mode 100644 index 7a07467524ba..000000000000 --- a/examples/api/clippath_demo.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -Clipping to arbitrary patches and paths -""" -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.patches as patches - - -fig = plt.figure() -ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[]) - -im = ax.imshow(np.random.rand(10,10)) - -patch = patches.Circle((300,300), radius=100) -im.set_clip_path(patch) - -plt.show() - - diff --git a/examples/api/collections_demo.py b/examples/api/collections_demo.py index c967be18ba22..243f1464fa47 100644 --- a/examples/api/collections_demo.py +++ b/examples/api/collections_demo.py @@ -41,69 +41,63 @@ # Make a list of colors cycling through the rgbcmyk series. colors = [colorConverter.to_rgba(c) for c in ('r','g','b','c','y','m','k')] -fig = plt.figure() +fig, axes = plt.subplots(2,2) +((ax1, ax2), (ax3, ax4)) = axes # unpack the axes + -a = fig.add_subplot(2,2,1) col = collections.LineCollection([spiral], offsets=xyo, - transOffset=a.transData) + transOffset=ax1.transData) trans = fig.dpi_scale_trans + transforms.Affine2D().scale(1.0/72.0) col.set_transform(trans) # the points to pixels transform # Note: the first argument to the collection initializer # must be a list of sequences of x,y tuples; we have only # one sequence, but we still have to put it in a list. -a.add_collection(col, autolim=True) +ax1.add_collection(col, autolim=True) # autolim=True enables autoscaling. For collections with # offsets like this, it is neither efficient nor accurate, # but it is good enough to generate a plot that you can use # as a starting point. If you know beforehand the range of # x and y that you want to show, it is better to set them # explicitly, leave out the autolim kwarg (or set it to False), - # and omit the 'a.autoscale_view()' call below. + # and omit the 'ax1.autoscale_view()' call below. # Make a transform for the line segments such that their size is # given in points: col.set_color(colors) -a.autoscale_view() # See comment above, after a.add_collection. -a.set_title('LineCollection using offsets') +ax1.autoscale_view() # See comment above, after ax1.add_collection. +ax1.set_title('LineCollection using offsets') # The same data as above, but fill the curves. - -a = fig.add_subplot(2,2,2) - col = collections.PolyCollection([spiral], offsets=xyo, - transOffset=a.transData) + transOffset=ax2.transData) trans = transforms.Affine2D().scale(fig.dpi/72.0) col.set_transform(trans) # the points to pixels transform -a.add_collection(col, autolim=True) +ax2.add_collection(col, autolim=True) col.set_color(colors) -a.autoscale_view() -a.set_title('PolyCollection using offsets') +ax2.autoscale_view() +ax2.set_title('PolyCollection using offsets') # 7-sided regular polygons -a = fig.add_subplot(2,2,3) - col = collections.RegularPolyCollection(7, sizes = np.fabs(xx)*10.0, offsets=xyo, - transOffset=a.transData) + transOffset=ax3.transData) trans = transforms.Affine2D().scale(fig.dpi/72.0) col.set_transform(trans) # the points to pixels transform -a.add_collection(col, autolim=True) +ax3.add_collection(col, autolim=True) col.set_color(colors) -a.autoscale_view() -a.set_title('RegularPolyCollection using offsets') +ax3.autoscale_view() +ax3.set_title('RegularPolyCollection using offsets') # Simulate a series of ocean current profiles, successively # offset by 0.1 m/s so that they form what is sometimes called # a "waterfall" plot or a "stagger" plot. -a = fig.add_subplot(2,2,4) - nverts = 60 ncurves = 20 offs = (0.1, 0.0) @@ -118,14 +112,14 @@ segs.append(curve) col = collections.LineCollection(segs, offsets=offs) -a.add_collection(col, autolim=True) +ax4.add_collection(col, autolim=True) col.set_color(colors) -a.autoscale_view() -a.set_title('Successive data offsets') -a.set_xlabel('Zonal velocity component (m/s)') -a.set_ylabel('Depth (m)') +ax4.autoscale_view() +ax4.set_title('Successive data offsets') +ax4.set_xlabel('Zonal velocity component (m/s)') +ax4.set_ylabel('Depth (m)') # Reverse the y-axis so depth increases downward -a.set_ylim(a.get_ylim()[::-1]) +ax4.set_ylim(ax4.get_ylim()[::-1]) plt.show() diff --git a/examples/api/color_cycle.py b/examples/api/color_cycle.py deleted file mode 100644 index 6b2abe873cd2..000000000000 --- a/examples/api/color_cycle.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -Illustrate the API for changing the cycle of colors used -when plotting multiple lines on a single Axes. -""" - -import numpy as np -import matplotlib.pyplot as plt -import matplotlib as mpl - -yy = np.arange(24) -yy.shape = 6,4 - -mpl.rc('lines', linewidth=4) - -fig = plt.figure() -mpl.rcParams['axes.color_cycle'] = ['r', 'g', 'b', 'c'] -ax = fig.add_subplot(2,1,1) -ax.plot(yy) -ax.set_title('Changed default color cycle to rgbc') - -ax = fig.add_subplot(2,1,2) -ax.set_color_cycle(['c', 'm', 'y', 'k']) -ax.plot(yy) -ax.set_title('This axes only, cycle is cmyk') - -plt.show() - - diff --git a/examples/api/colorbar_only.py b/examples/api/colorbar_only.py index 0e1837e95f19..b270c2bf85c7 100644 --- a/examples/api/colorbar_only.py +++ b/examples/api/colorbar_only.py @@ -2,7 +2,8 @@ Make a colorbar as a separate figure. ''' -from matplotlib import pyplot, mpl +from matplotlib import pyplot +import matplotlib as mpl # Make a figure and axes with dimensions as desired. fig = pyplot.figure(figsize=(8,3)) @@ -71,4 +72,3 @@ cb3.set_label('Custom extension lengths, some other units') pyplot.show() - diff --git a/examples/api/compound_path.py b/examples/api/compound_path.py index 3155010954b9..ea52986c7c95 100644 --- a/examples/api/compound_path.py +++ b/examples/api/compound_path.py @@ -23,8 +23,7 @@ pathpatch = PathPatch(path, facecolor='None', edgecolor='green') -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.add_patch(pathpatch) ax.set_title('A compound path') diff --git a/examples/api/date_demo.py b/examples/api/date_demo.py index 4348c2105064..1de554387718 100644 --- a/examples/api/date_demo.py +++ b/examples/api/date_demo.py @@ -28,8 +28,7 @@ datafile = cbook.get_sample_data('goog.npy') r = np.load(datafile).view(np.recarray) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(r.date, r.adj_close) diff --git a/examples/api/date_index_formatter.py b/examples/api/date_index_formatter.py index 7b4843aac9ce..691e4a1e66fd 100644 --- a/examples/api/date_index_formatter.py +++ b/examples/api/date_index_formatter.py @@ -19,8 +19,7 @@ # first we'll do it the default way, with gaps on weekends -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(r.date, r.adj_close, 'o-') fig.autofmt_xdate() @@ -32,8 +31,7 @@ def format_date(x, pos=None): thisind = np.clip(int(x+0.5), 0, N-1) return r.date[thisind].strftime('%Y-%m-%d') -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(ind, r.adj_close, 'o-') ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) fig.autofmt_xdate() diff --git a/examples/api/demo_affine_image.py b/examples/api/demo_affine_image.py index 68e416fbfd29..036f4a526898 100644 --- a/examples/api/demo_affine_image.py +++ b/examples/api/demo_affine_image.py @@ -32,8 +32,8 @@ def imshow_affine(ax, z, *kl, **kwargs): if 1: # image rotation - - ax1 = plt.subplot(121) + + fig, (ax1, ax2) = plt.subplots(1,2) Z = get_image() im1 = imshow_affine(ax1, Z, interpolation='none', cmap=cm.jet, origin='lower', @@ -55,7 +55,6 @@ def imshow_affine(ax, z, *kl, **kwargs): # image skew - ax2 = plt.subplot(122) im2 = ax2.imshow(Z, interpolation='none', cmap=cm.jet, origin='lower', extent=[-2, 4, -3, 2], clip_on=True) diff --git a/examples/api/donut_demo.py b/examples/api/donut_demo.py index 4bc56b1be886..b36b0e7f3291 100644 --- a/examples/api/donut_demo.py +++ b/examples/api/donut_demo.py @@ -18,8 +18,7 @@ def make_circle(r): Path = mpath.Path -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() inside_vertices = make_circle(0.5) outside_vertices = make_circle(1.0) diff --git a/examples/api/engineering_formatter.py b/examples/api/engineering_formatter.py index a71f5e230450..e70803885269 100644 --- a/examples/api/engineering_formatter.py +++ b/examples/api/engineering_formatter.py @@ -7,7 +7,7 @@ from matplotlib.ticker import EngFormatter -ax = plt.subplot(111) +fig, ax = plt.subplots() ax.set_xscale('log') formatter = EngFormatter(unit='Hz', places=1) ax.xaxis.set_major_formatter(formatter) diff --git a/examples/api/fahrenheit_celsius_scales.py b/examples/api/fahrenheit_celsius_scales.py index 5250dfb34ae1..72a52f4fa41b 100644 --- a/examples/api/fahrenheit_celsius_scales.py +++ b/examples/api/fahrenheit_celsius_scales.py @@ -4,9 +4,8 @@ import matplotlib.pyplot as plt -fig = plt.figure() -ax1 = fig.add_subplot(111) # the Fahrenheit scale -ax2 = ax1.twinx() # the Celsius scale +fig, ax1 = plt.subplots() # ax1 is the Fahrenheit scale +ax2 = ax1.twinx() # ax2 is the Celsius scale def Tc(Tf): return (5./9.)*(Tf-32) diff --git a/examples/api/font_family_rc.py b/examples/api/font_family_rc.py index d379e3163471..d3b2d4acca37 100644 --- a/examples/api/font_family_rc.py +++ b/examples/api/font_family_rc.py @@ -22,8 +22,7 @@ rcParams['font.sans-serif'] = ['Tahoma'] import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot([1,2,3], label='test') ax.legend() diff --git a/examples/api/font_file.py b/examples/api/font_file.py index 495b1905f679..e5f4127d1c9d 100644 --- a/examples/api/font_file.py +++ b/examples/api/font_file.py @@ -11,8 +11,7 @@ import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot([1,2,3]) if sys.platform == 'win32': diff --git a/examples/api/hinton_demo.py b/examples/api/hinton_demo.py deleted file mode 100644 index 700e13c1bb65..000000000000 --- a/examples/api/hinton_demo.py +++ /dev/null @@ -1,60 +0,0 @@ -#Initial idea from David Warde-Farley on the SciPy Cookbook -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.patches import Rectangle -from matplotlib.ticker import NullLocator -#from matplotlib.collections import RegularPolyCollection -#from matplotlib.colors import BoundaryNorm, ListedColormap - -def hinton(W, maxWeight=None, ax=None): - """ - Draws a Hinton diagram for visualizing a weight matrix. - """ - if not ax: - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1) - - if not maxWeight: - maxWeight = 2**np.ceil(np.log(np.abs(W).max())/np.log(2)) - - ax.patch.set_facecolor('gray') - ax.set_aspect('equal', 'box') - ax.xaxis.set_major_locator(NullLocator()) - ax.yaxis.set_major_locator(NullLocator()) - - for (x,y),w in np.ndenumerate(W): - if w > 0: color = 'white' - else: color = 'black' - size = np.sqrt(np.abs(w)) - rect = Rectangle([x - size / 2, y - size / 2], size, size, - facecolor=color, edgecolor=color) - ax.add_patch(rect) - ax.autoscale_view() - - # Reverse the yaxis limits - ax.set_ylim(*ax.get_ylim()[::-1]) - -## Potential way using polygon collections that just has an issue with -## easily getting the squares scaled by the data. - -# height,width = W.shape -# x = np.arange(width) -# y = np.arange(height) -# X,Y = np.meshgrid(x, y) -# xy = np.array([X.flatten(),Y.flatten()]).T -# scaled_data = W.flatten() / maxWeight -# cmap = ListedColormap(['black', 'white']) -# norm = BoundaryNorm([-1., 0., 1.], cmap.N) - -# rect_col = RegularPolyCollection(4, rotation=np.pi/4, -# sizes=np.abs(scaled_data) * 72 / ax.figure.get_dpi(), offsets=xy, -# transOffset=ax.transData, norm=norm, cmap=cmap, edgecolor='none') -# ax.add_collection(rect_col) -# rect_col.set_array(scaled_data) -# ax.autoscale_view() - -if __name__ == '__main__': - hinton(np.random.rand(20, 20) - 0.5) - plt.title('Hinton Example') - plt.show() - diff --git a/examples/api/histogram_demo.py b/examples/api/histogram_demo.py deleted file mode 100644 index 11c4b0adaba1..000000000000 --- a/examples/api/histogram_demo.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Make a histogram of normally distributed random numbers and plot the -analytic PDF over it -""" -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.mlab as mlab - -mu, sigma = 100, 15 -x = mu + sigma * np.random.randn(10000) - -fig = plt.figure() -ax = fig.add_subplot(111) - -# the histogram of the data -n, bins, patches = ax.hist(x, 50, normed=1, facecolor='green', alpha=0.75) - -# hist uses np.histogram under the hood to create 'n' and 'bins'. -# np.histogram returns the bin edges, so there will be 50 probability -# density values in n, 51 bin edges in bins and 50 patches. To get -# everything lined up, we'll compute the bin centers -bincenters = 0.5*(bins[1:]+bins[:-1]) -# add a 'best fit' line for the normal PDF -y = mlab.normpdf( bincenters, mu, sigma) -l = ax.plot(bincenters, y, 'r--', linewidth=1) - -ax.set_xlabel('Smarts') -ax.set_ylabel('Probability') -#ax.set_title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') -ax.set_xlim(40, 160) -ax.set_ylim(0, 0.03) -ax.grid(True) - -plt.show() diff --git a/examples/api/histogram_path_demo.py b/examples/api/histogram_path_demo.py index 9b21b509d800..0789264b7bca 100644 --- a/examples/api/histogram_path_demo.py +++ b/examples/api/histogram_path_demo.py @@ -15,8 +15,7 @@ import matplotlib.patches as patches import matplotlib.path as path -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() # histogram our data with numpy data = np.random.randn(1000) diff --git a/examples/api/image_zcoord.py b/examples/api/image_zcoord.py index 170f8df5e5be..69b40135075f 100644 --- a/examples/api/image_zcoord.py +++ b/examples/api/image_zcoord.py @@ -8,8 +8,7 @@ X = 10*np.random.rand(5,3) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.imshow(X, cmap=cm.jet, interpolation='nearest') numrows, numcols = X.shape diff --git a/examples/api/joinstyle.py b/examples/api/joinstyle.py index dc1a4661f52d..ce3847da79f9 100644 --- a/examples/api/joinstyle.py +++ b/examples/api/joinstyle.py @@ -4,7 +4,6 @@ """ import numpy as np -import matplotlib import matplotlib.pyplot as plt def plot_angle(ax, x, y, angle, style): @@ -17,8 +16,7 @@ def plot_angle(ax, x, y, angle, style): ax.plot(xx[1:2], yy[1:2], 'o', color='red', markersize=3) ax.text(x,y+.2,'%.0f degrees' % angle) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.set_title('Join style') for x,style in enumerate((('miter', 'round', 'bevel'))): diff --git a/examples/api/legend_demo.py b/examples/api/legend_demo.py index 31d257f1e831..63f25a46bb26 100644 --- a/examples/api/legend_demo.py +++ b/examples/api/legend_demo.py @@ -1,41 +1,42 @@ +""" +Demo of the legend function with a few features. + +In addition to the basic legend, this demo shows a few optional features: + + * Custom legend placement. + * A keyword argument to a drop-shadow. + * Setting the background color. + * Setting the font size. + * Setting the line width. +""" import numpy as np import matplotlib.pyplot as plt -a = np.arange(0,3,.02) -b = np.arange(0,3,.02) + +# Example data +a = np.arange(0,3, .02) +b = np.arange(0,3, .02) c = np.exp(a) d = c[::-1] -fig = plt.figure() -ax = fig.add_subplot(111) -ax.plot(a,c,'k--',a,d,'k:',a,c+d,'k') -leg = ax.legend(('Model length', 'Data length', 'Total message length'), - 'upper center', shadow=True) -ax.set_ylim([-1,20]) -ax.grid(False) -ax.set_xlabel('Model complexity --->') -ax.set_ylabel('Message length --->') -ax.set_title('Minimum Message Length') - -ax.set_yticklabels([]) -ax.set_xticklabels([]) - -# set some legend properties. All the code below is optional. The -# defaults are usually sensible but if you need more control, this -# shows you how - -# the matplotlib.patches.Rectangle instance surrounding the legend -frame = leg.get_frame() -frame.set_facecolor('0.80') # set the frame face color to light gray - -# matplotlib.text.Text instances -for t in leg.get_texts(): - t.set_fontsize('small') # the legend text fontsize - -# matplotlib.lines.Line2D instances -for l in leg.get_lines(): - l.set_linewidth(1.5) # the legend line width -plt.show() +# Create plots with pre-defined labels. +# Alternatively, you can pass labels explicitly when calling `legend`. +fig, ax = plt.subplots() +ax.plot(a, c, 'k--', label='Model length') +ax.plot(a, d, 'k:', label='Data length') +ax.plot(a, c+d, 'k', label='Total message length') + +# Now add the legend with some customizations. +legend = ax.legend(loc='upper center', shadow=True) +# The frame is matplotlib.patches.Rectangle instance surrounding the legend. +frame = legend.get_frame() +frame.set_facecolor('0.90') +# Set the fontsize +for label in legend.get_texts(): + label.set_fontsize('large') +for label in legend.get_lines(): + label.set_linewidth(1.5) # the legend line width +plt.show() diff --git a/examples/api/line_with_text.py b/examples/api/line_with_text.py index 87be46d43edb..6c72aa2dfac0 100644 --- a/examples/api/line_with_text.py +++ b/examples/api/line_with_text.py @@ -50,8 +50,7 @@ def draw(self, renderer): -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() x, y = np.random.rand(2, 20) line = MyLine(x, y, mfc='red', ms=12, label='line label') #line.text.set_text('line label') diff --git a/examples/api/patch_collection.py b/examples/api/patch_collection.py index 44d3d403a19e..98b4ca4f6b58 100644 --- a/examples/api/patch_collection.py +++ b/examples/api/patch_collection.py @@ -5,8 +5,7 @@ import matplotlib.pyplot as plt -fig=plt.figure() -ax=fig.add_subplot(111) +fig, ax = plt.subplots() resolution = 50 # the number of vertices N = 3 diff --git a/examples/api/path_patch_demo.py b/examples/api/path_patch_demo.py deleted file mode 100644 index d28fa2c37015..000000000000 --- a/examples/api/path_patch_demo.py +++ /dev/null @@ -1,36 +0,0 @@ -import numpy as np -import matplotlib.path as mpath -import matplotlib.patches as mpatches -import matplotlib.pyplot as plt - -Path = mpath.Path - -fig = plt.figure() -ax = fig.add_subplot(111) - -pathdata = [ - (Path.MOVETO, (1.58, -2.57)), - (Path.CURVE4, (0.35, -1.1)), - (Path.CURVE4, (-1.75, 2.0)), - (Path.CURVE4, (0.375, 2.0)), - (Path.LINETO, (0.85, 1.15)), - (Path.CURVE4, (2.2, 3.2)), - (Path.CURVE4, (3, 0.05)), - (Path.CURVE4, (2.0, -0.5)), - (Path.CLOSEPOLY, (1.58, -2.57)), - ] - -codes, verts = zip(*pathdata) -path = mpath.Path(verts, codes) -patch = mpatches.PathPatch(path, facecolor='red', edgecolor='yellow', alpha=0.5) -ax.add_patch(patch) - -x, y = zip(*path.vertices) -line, = ax.plot(x, y, 'go-') -ax.grid() -ax.set_xlim(-3,4) -ax.set_ylim(-3,4) -ax.set_title('spline paths') -plt.show() - - diff --git a/examples/api/quad_bezier.py b/examples/api/quad_bezier.py index 5314dfb936b2..07e85d479e3c 100644 --- a/examples/api/quad_bezier.py +++ b/examples/api/quad_bezier.py @@ -1,12 +1,10 @@ -import numpy as np import matplotlib.path as mpath import matplotlib.patches as mpatches import matplotlib.pyplot as plt Path = mpath.Path -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() pp1 = mpatches.PathPatch( Path([(0, 0), (1, 0), (1, 1), (0, 0)], [Path.MOVETO, Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY]), diff --git a/examples/api/sankey_demo_old.py b/examples/api/sankey_demo_old.py index b11a8b221d3a..f8b73696bc76 100755 --- a/examples/api/sankey_demo_old.py +++ b/examples/api/sankey_demo_old.py @@ -24,7 +24,7 @@ def sankey(ax, w: output arrow shoulder inangle: input dip angle offset: text offset - **kwargs: propagated to Patch (e.g. fill=False) + **kwargs: propagated to Patch (e.g., fill=False) Return (patch,[intexts,outtexts]). """ diff --git a/examples/api/sankey_demo_rankine.py b/examples/api/sankey_demo_rankine.py index 13e5a5ffbf7d..b334acf51754 100644 --- a/examples/api/sankey_demo_rankine.py +++ b/examples/api/sankey_demo_rankine.py @@ -5,7 +5,7 @@ from matplotlib.sankey import Sankey -fig = plt.figure(figsize=(8, 12)) +fig = plt.figure(figsize=(8, 9)) ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") diff --git a/examples/api/scatter_piecharts.py b/examples/api/scatter_piecharts.py index 48997fb11d57..424fa70411a2 100644 --- a/examples/api/scatter_piecharts.py +++ b/examples/api/scatter_piecharts.py @@ -32,8 +32,7 @@ xy3 = list(zip(x,y)) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.scatter( np.arange(3), np.arange(3), marker=(xy1,0), s=sizes, facecolor='blue' ) ax.scatter( np.arange(3), np.arange(3), marker=(xy2,0), s=sizes, facecolor='green' ) ax.scatter( np.arange(3), np.arange(3), marker=(xy3,0), s=sizes, facecolor='red' ) diff --git a/examples/api/span_regions.py b/examples/api/span_regions.py index 7acc223e1708..1cfbdcf3dd10 100644 --- a/examples/api/span_regions.py +++ b/examples/api/span_regions.py @@ -14,8 +14,7 @@ s2 = 1.2*np.sin(4*np.pi*t) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.set_title('using span_where') ax.plot(t, s1, color='black') ax.axhline(0, color='black', lw=2) diff --git a/examples/api/two_scales.py b/examples/api/two_scales.py index 475f3ac666f7..356c81336905 100644 --- a/examples/api/two_scales.py +++ b/examples/api/two_scales.py @@ -24,8 +24,7 @@ import numpy as np import matplotlib.pyplot as plt -fig = plt.figure() -ax1 = fig.add_subplot(111) +fig, ax1 = plt.subplots() t = np.arange(0.01, 10.0, 0.01) s1 = np.exp(t) ax1.plot(t, s1, 'b-') diff --git a/examples/api/unicode_minus.py b/examples/api/unicode_minus.py index 5fc352668997..d84fb04f5b03 100644 --- a/examples/api/unicode_minus.py +++ b/examples/api/unicode_minus.py @@ -11,8 +11,7 @@ import matplotlib.pyplot as plt matplotlib.rcParams['axes.unicode_minus'] = False -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(10*np.random.randn(100), 10*np.random.randn(100), 'o') ax.set_title('Using hypen instead of unicode minus') plt.show() diff --git a/examples/api/watermark_image.py b/examples/api/watermark_image.py index 3d437193a05a..9b6425070ea5 100644 --- a/examples/api/watermark_image.py +++ b/examples/api/watermark_image.py @@ -3,7 +3,6 @@ """ from __future__ import print_function import numpy as np -import matplotlib import matplotlib.cbook as cbook import matplotlib.image as image import matplotlib.pyplot as plt @@ -13,8 +12,7 @@ im = image.imread(datafile) im[:,:,-1] = 0.5 # set the alpha channel -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=0.7, mfc='orange') ax.grid() diff --git a/examples/api/watermark_text.py b/examples/api/watermark_text.py index 7d87de100032..0d09141050a9 100644 --- a/examples/api/watermark_text.py +++ b/examples/api/watermark_text.py @@ -7,9 +7,7 @@ import matplotlib.pyplot as plt -fig = plt.figure() - -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=0.7, mfc='orange') ax.grid() diff --git a/examples/axes_grid/demo_axes_divider.py b/examples/axes_grid/demo_axes_divider.py index 5a0652cf1052..df56d9f3f532 100644 --- a/examples/axes_grid/demo_axes_divider.py +++ b/examples/axes_grid/demo_axes_divider.py @@ -75,7 +75,7 @@ def demo_locatable_axes_easy(ax): ax_cb.yaxis.tick_right() -def demo_images_side_by_sied(ax): +def demo_images_side_by_side(ax): from mpl_toolkits.axes_grid1 import make_axes_locatable divider = make_axes_locatable(ax) @@ -120,7 +120,7 @@ def demo(): # two images side by side with fixed padding. ax = fig1.add_subplot(2, 2, 4) - demo_images_side_by_sied(ax) + demo_images_side_by_side(ax) plt.draw() plt.show() diff --git a/examples/axes_grid/demo_axes_hbox_divider.py b/examples/axes_grid/demo_axes_hbox_divider.py index fe72bdc14195..f63061ac45e7 100644 --- a/examples/axes_grid/demo_axes_hbox_divider.py +++ b/examples/axes_grid/demo_axes_hbox_divider.py @@ -23,19 +23,15 @@ def make_heights_equal(fig, rect, ax1, ax2, pad): 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) - + fig, (ax1, ax2) = plt.subplots(1,2) 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 + make_heights_equal(fig, rect, ax1, ax2, pad=0.5) # pad in inches for ax in [ax1, ax2]: ax.locator_params(nbins=4) @@ -44,7 +40,9 @@ def make_heights_equal(fig, rect, ax1, ax2, pad): 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), + 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")) diff --git a/examples/axes_grid/demo_axes_rgb.py b/examples/axes_grid/demo_axes_rgb.py index 08c704c08ed2..b7374c2766d6 100644 --- a/examples/axes_grid/demo_axes_rgb.py +++ b/examples/axes_grid/demo_axes_rgb.py @@ -41,10 +41,7 @@ def make_cube(r, g, b): def demo_rgb(): - fig = plt.figure(1) - fig.clf() - - ax = fig.add_subplot(111) + fig, ax = plt.subplots() ax_r, ax_g, ax_b = make_rgb_axes(ax, pad=0.02) #fig.add_axes(ax_r) #fig.add_axes(ax_g) diff --git a/examples/axes_grid/demo_colorbar_with_inset_locator.py b/examples/axes_grid/demo_colorbar_with_inset_locator.py index bc5cd79cfc6c..1085e45d95ee 100644 --- a/examples/axes_grid/demo_colorbar_with_inset_locator.py +++ b/examples/axes_grid/demo_colorbar_with_inset_locator.py @@ -2,10 +2,7 @@ from mpl_toolkits.axes_grid1.inset_locator import inset_axes -fig = plt.figure(1, [6, 3]) - -# first subplot -ax1 = fig.add_subplot(121) +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=[6, 3]) axins1 = inset_axes(ax1, width="50%", # width = 10% of parent_bbox width @@ -16,15 +13,12 @@ plt.colorbar(im1, cax=axins1, orientation="horizontal", ticks=[1,2,3]) axins1.xaxis.set_ticks_position("bottom") -# first subplot -ax = fig.add_subplot(122) - -axins = inset_axes(ax, +axins = inset_axes(ax2, width="5%", # width = 10% of parent_bbox width height="50%", # height : 50% loc=3, bbox_to_anchor=(1.05, 0., 1, 1), - bbox_transform=ax.transAxes, + bbox_transform=ax2.transAxes, borderpad=0, ) @@ -32,7 +26,7 @@ # of the legend. you may want to play with the borderpad value and # the bbox_to_anchor coordinate. -im=ax.imshow([[1,2],[2, 3]]) +im=ax2.imshow([[1,2],[2, 3]]) plt.colorbar(im, cax=axins, ticks=[1,2,3]) plt.draw() diff --git a/examples/axes_grid/inset_locator_demo.py b/examples/axes_grid/inset_locator_demo.py index 9dfe0024feb7..1a1f5d0e3784 100644 --- a/examples/axes_grid/inset_locator_demo.py +++ b/examples/axes_grid/inset_locator_demo.py @@ -14,10 +14,9 @@ def add_sizebar(ax, size): ax.add_artist(asb) -fig = plt.figure(1, [5.5, 3]) +fig, (ax, ax2) = plt.subplots(1, 2, figsize=[5.5, 3]) # first subplot -ax = fig.add_subplot(1,2,1) ax.set_aspect(1.) axins = inset_axes(ax, @@ -30,15 +29,14 @@ def add_sizebar(ax, size): # second subplot -ax = fig.add_subplot(1,2,2) -ax.set_aspect(1.) +ax2.set_aspect(1.) -axins = zoomed_inset_axes(ax, 0.5, loc=1) # zoom = 0.5 +axins = zoomed_inset_axes(ax2, 0.5, loc=1) # zoom = 0.5 plt.xticks(visible=False) plt.yticks(visible=False) -add_sizebar(ax, 0.5) +add_sizebar(ax2, 0.5) add_sizebar(axins, 0.5) plt.draw() diff --git a/examples/axes_grid/inset_locator_demo2.py b/examples/axes_grid/inset_locator_demo2.py index a4e08be34931..211faa4bffd8 100644 --- a/examples/axes_grid/inset_locator_demo2.py +++ b/examples/axes_grid/inset_locator_demo2.py @@ -13,9 +13,7 @@ def get_demo_image(): # z is a numpy array of 15x15 return z, (-3,4,-4,3) - -fig = plt.figure(1, [5,4]) -ax = fig.add_subplot(111) +fig, ax = plt.subplots(figsize=[5,4]) # prepare the demo image Z, extent = get_demo_image() diff --git a/examples/axes_grid/scatter_hist.py b/examples/axes_grid/scatter_hist.py index b846704e0e71..273ae5d9348c 100644 --- a/examples/axes_grid/scatter_hist.py +++ b/examples/axes_grid/scatter_hist.py @@ -1,17 +1,15 @@ import numpy as np import matplotlib.pyplot as plt +from mpl_toolkits.axes_grid1 import make_axes_locatable # the random data x = np.random.randn(1000) y = np.random.randn(1000) -fig = plt.figure(1, figsize=(5.5,5.5)) - -from mpl_toolkits.axes_grid1 import make_axes_locatable +fig, axScatter = plt.subplots(figsize=(5.5,5.5)) # the scatter plot: -axScatter = plt.subplot(111) axScatter.scatter(x, y) axScatter.set_aspect(1.) diff --git a/examples/color/color_cycle_demo.py b/examples/color/color_cycle_demo.py new file mode 100644 index 000000000000..b453de4c1aed --- /dev/null +++ b/examples/color/color_cycle_demo.py @@ -0,0 +1,34 @@ +""" +Demo of custom color-cycle settings to control colors for multi-line plots. + +This example demonstrates two different APIs: + + 1. Setting the default rc-parameter specifying the color cycle. + This affects all subsequent plots. + 2. Setting the color cycle for a specific axes. This only affects a single + axes. +""" +import numpy as np +import matplotlib.pyplot as plt + +x = np.linspace(0, 2 * np.pi) +offsets = np.linspace(0, 2*np.pi, 4, endpoint=False) +# Create array with shifted-sine curve along each column +yy = np.transpose([np.sin(x + phi) for phi in offsets]) + +plt.rc('lines', linewidth=4) +fig, (ax0, ax1) = plt.subplots(nrows=2) + +plt.rc('axes', color_cycle=['r', 'g', 'b', 'y']) +ax0.plot(yy) +ax0.set_title('Set default color cycle to rgby') + +ax1.set_color_cycle(['c', 'm', 'y', 'k']) +ax1.plot(yy) +ax1.set_title('Set axes color cycle to cmyk') + +# Tweak spacing between subplots to prevent labels from overlapping +plt.subplots_adjust(hspace=0.3) +plt.show() + + diff --git a/examples/color/colormaps_reference.py b/examples/color/colormaps_reference.py new file mode 100644 index 000000000000..1c433794e4e1 --- /dev/null +++ b/examples/color/colormaps_reference.py @@ -0,0 +1,79 @@ +""" +Reference for colormaps included with Matplotlib. + +This reference example shows all colormaps included with Matplotlib. Note that +any colormap listed here can be reversed by appending "_r" (e.g., "pink_r"). +These colormaps are divided into the following categories: + +Sequential: + These colormaps are approximately monochromatic colormaps varying smoothly + between two color tones---usually from low saturation (e.g. white) to high + saturation (e.g. a bright blue). Sequential colormaps are ideal for + representing most scientific data since they show a clear progression from + low-to-high values. + +Diverging: + These colormaps have a median value (usually light in color) and vary + smoothly to two different color tones at high and low values. Diverging + colormaps are ideal when your data has a median value that is significant + (e.g. 0, such that positive and negative values are represented by + different colors of the colormap). + +Qualitative: + These colormaps vary rapidly in color. Qualitative colormaps are useful for + choosing a set of discrete colors. For example:: + + color_list = plt.cm.Set3(np.linspace(0, 1, 12)) + + gives a list of RGB colors that are good for plotting a series of lines on + a dark background. + +Miscellaneous: + Colormaps that don't fit into the categories above. + +""" +import numpy as np +import matplotlib.pyplot as plt + + +cmaps = [('Sequential', ['binary', 'Blues', 'BuGn', 'BuPu', 'gist_yarg', + 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', + 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', + 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), + ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', + 'gist_gray', 'gist_heat', 'gray', 'hot', 'pink', + 'spring', 'summer', 'winter']), + ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', + 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'seismic']), + ('Qualitative', ['Accent', 'Dark2', 'hsv', 'Paired', 'Pastel1', + 'Pastel2', 'Set1', 'Set2', 'Set3', 'spectral']), + ('Miscellaneous', ['gist_earth', 'gist_ncar', 'gist_rainbow', + 'gist_stern', 'jet', 'brg', 'CMRmap', 'cubehelix', + 'gnuplot', 'gnuplot2', 'ocean', 'rainbow', + 'terrain', 'flag', 'prism'])] + + +nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) +gradient = np.linspace(0, 1, 256) +gradient = np.vstack((gradient, gradient)) + +def plot_color_gradients(cmap_category, cmap_list): + fig, axes = plt.subplots(nrows=nrows) + fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) + axes[0].set_title(cmap_category + ' colormaps', fontsize=14) + + for ax, name in zip(axes, cmap_list): + ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) + pos = list(ax.get_position().bounds) + x_text = pos[0] - 0.01 + y_text = pos[1] + pos[3]/2. + fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) + + # Turn off *all* ticks & spines, not just the ones with colormaps. + for ax in axes: + ax.set_axis_off() + +for cmap_category, cmap_list in cmaps: + plot_color_gradients(cmap_category, cmap_list) + +plt.show() diff --git a/examples/event_handling/data_browser.py b/examples/event_handling/data_browser.py index 7e11c3fade42..d4c9692552ee 100644 --- a/examples/event_handling/data_browser.py +++ b/examples/event_handling/data_browser.py @@ -70,11 +70,9 @@ def update(self): xs = np.mean(X, axis=1) ys = np.std(X, axis=1) - fig = plt.figure() - ax = fig.add_subplot(211) + fig, (ax, ax2) = plt.subplots(2, 1) ax.set_title('click on point to plot time series') line, = ax.plot(xs, ys, 'o', picker=5) # 5 points tolerance - ax2 = fig.add_subplot(212) browser = PointBrowser() diff --git a/examples/event_handling/figure_axes_enter_leave.py b/examples/event_handling/figure_axes_enter_leave.py index 7b9175ff3860..af6de53e8e60 100644 --- a/examples/event_handling/figure_axes_enter_leave.py +++ b/examples/event_handling/figure_axes_enter_leave.py @@ -25,20 +25,16 @@ def leave_figure(event): event.canvas.figure.patch.set_facecolor('grey') event.canvas.draw() -fig1 = plt.figure() +fig1, (ax, ax2) = plt.subplots(2, 1) fig1.suptitle('mouse hover over figure or axes to trigger events') -ax1 = fig1.add_subplot(211) -ax2 = fig1.add_subplot(212) fig1.canvas.mpl_connect('figure_enter_event', enter_figure) fig1.canvas.mpl_connect('figure_leave_event', leave_figure) fig1.canvas.mpl_connect('axes_enter_event', enter_axes) fig1.canvas.mpl_connect('axes_leave_event', leave_axes) -fig2 = plt.figure() +fig2, (ax, ax2) = plt.subplots(2, 1) fig2.suptitle('mouse hover over figure or axes to trigger events') -ax1 = fig2.add_subplot(211) -ax2 = fig2.add_subplot(212) fig2.canvas.mpl_connect('figure_enter_event', enter_figure) fig2.canvas.mpl_connect('figure_leave_event', leave_figure) diff --git a/examples/event_handling/idle_and_timeout.py b/examples/event_handling/idle_and_timeout.py index 6dbff324a390..a6de8195f10e 100644 --- a/examples/event_handling/idle_and_timeout.py +++ b/examples/event_handling/idle_and_timeout.py @@ -7,8 +7,7 @@ import numpy as np import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() t = np.arange(0.0, 2.0, 0.01) y1 = np.sin(2*np.pi*t) diff --git a/examples/event_handling/keypress_demo.py b/examples/event_handling/keypress_demo.py index 501798f84d2a..d814c8ce334b 100755 --- a/examples/event_handling/keypress_demo.py +++ b/examples/event_handling/keypress_demo.py @@ -4,19 +4,20 @@ Show how to connect to keypress events """ from __future__ import print_function +import sys import numpy as np import matplotlib.pyplot as plt def press(event): print('press', event.key) + sys.stdout.flush() if event.key=='x': visible = xl.get_visible() xl.set_visible(not visible) fig.canvas.draw() -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() fig.canvas.mpl_connect('key_press_event', press) diff --git a/examples/event_handling/legend_picking.py b/examples/event_handling/legend_picking.py index 4505b09bd971..1c37ad3c6e85 100644 --- a/examples/event_handling/legend_picking.py +++ b/examples/event_handling/legend_picking.py @@ -8,8 +8,7 @@ y1 = 2*np.sin(2*np.pi*t) y2 = 4*np.sin(2*np.pi*2*t) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.set_title('Click on legend line to toggle line on/off') line1, = ax.plot(t, y1, lw=2, color='red', label='1 HZ') line2, = ax.plot(t, y2, lw=2, color='blue', label='2 HZ') diff --git a/examples/event_handling/looking_glass.py b/examples/event_handling/looking_glass.py index 3ceeb68f8231..eb98998d0832 100644 --- a/examples/event_handling/looking_glass.py +++ b/examples/event_handling/looking_glass.py @@ -3,8 +3,7 @@ import matplotlib.patches as patches x, y = np.random.rand(2, 200) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() circ = patches.Circle( (0.5, 0.5), 0.25, alpha=0.8, fc='yellow') ax.add_patch(circ) diff --git a/examples/event_handling/path_editor.py b/examples/event_handling/path_editor.py index 38148c78dffc..a7458efdea1f 100644 --- a/examples/event_handling/path_editor.py +++ b/examples/event_handling/path_editor.py @@ -5,8 +5,7 @@ Path = mpath.Path -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() pathdata = [ (Path.MOVETO, (1.58, -2.57)), @@ -72,7 +71,7 @@ def pathpatch_changed(self, pathpatch): 'this method is called whenever the pathpatchgon object is called' # only copy the artist props to the line (except visibility) vis = self.line.get_visible() - Artist.update_from(self.line, pathpatch) + plt.Artist.update_from(self.line, pathpatch) self.line.set_visible(vis) # don't use the pathpatch visibility state diff --git a/examples/event_handling/pick_event_demo.py b/examples/event_handling/pick_event_demo.py index 68a27e4c221a..57bfa0b6b10b 100755 --- a/examples/event_handling/pick_event_demo.py +++ b/examples/event_handling/pick_event_demo.py @@ -65,7 +65,7 @@ def pick_handler(event): """ from __future__ import print_function -from matplotlib.pyplot import figure, show +import matplotlib.pyplot as plt from matplotlib.lines import Line2D from matplotlib.patches import Rectangle from matplotlib.text import Text @@ -74,15 +74,12 @@ def pick_handler(event): from numpy.random import rand if 1: # simple picking, lines, rectangles and text - fig = figure() - ax1 = fig.add_subplot(211) + fig, (ax1, ax2) = plt.subplots(2,1) ax1.set_title('click on points, rectangles or text', picker=True) ax1.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red')) line, = ax1.plot(rand(100), 'o', picker=5) # 5 points tolerance # pick the rectangle - ax2 = fig.add_subplot(212) - bars = ax2.bar(range(10), rand(10), picker=True) for label in ax2.get_xticklabels(): # make the xtick labels pickable label.set_picker(True) @@ -140,10 +137,9 @@ def line_picker(line, mouseevent): def onpick2(event): print('onpick2 line:', event.pickx, event.picky) - fig = figure() - ax1 = fig.add_subplot(111) - ax1.set_title('custom picker for line data') - line, = ax1.plot(rand(100), rand(100), 'o', picker=line_picker) + fig, ax = plt.subplots() + ax.set_title('custom picker for line data') + line, = ax.plot(rand(100), rand(100), 'o', picker=line_picker) fig.canvas.mpl_connect('pick_event', onpick2) @@ -154,20 +150,18 @@ def onpick3(event): ind = event.ind print('onpick3 scatter:', ind, np.take(x, ind), np.take(y, ind)) - fig = figure() - ax1 = fig.add_subplot(111) - col = ax1.scatter(x, y, 100*s, c, picker=True) + fig, ax = plt.subplots() + col = ax.scatter(x, y, 100*s, c, picker=True) #fig.savefig('pscoll.eps') fig.canvas.mpl_connect('pick_event', onpick3) if 1: # picking images (matplotlib.image.AxesImage) - fig = figure() - ax1 = fig.add_subplot(111) - im1 = ax1.imshow(rand(10,5), extent=(1,2,1,2), picker=True) - im2 = ax1.imshow(rand(5,10), extent=(3,4,1,2), picker=True) - im3 = ax1.imshow(rand(20,25), extent=(1,2,3,4), picker=True) - im4 = ax1.imshow(rand(30,12), extent=(3,4,3,4), picker=True) - ax1.axis([0,5,0,5]) + fig, ax = plt.subplots() + im1 = ax.imshow(rand(10,5), extent=(1,2,1,2), picker=True) + im2 = ax.imshow(rand(5,10), extent=(3,4,1,2), picker=True) + im3 = ax.imshow(rand(20,25), extent=(1,2,3,4), picker=True) + im4 = ax.imshow(rand(30,12), extent=(3,4,3,4), picker=True) + ax.axis([0,5,0,5]) def onpick4(event): artist = event.artist @@ -179,5 +173,5 @@ def onpick4(event): fig.canvas.mpl_connect('pick_event', onpick4) -show() +plt.show() diff --git a/examples/event_handling/pick_event_demo2.py b/examples/event_handling/pick_event_demo2.py index 0f4513309be8..3d2a18e685a0 100644 --- a/examples/event_handling/pick_event_demo2.py +++ b/examples/event_handling/pick_event_demo2.py @@ -11,8 +11,7 @@ xs = numpy.mean(X, axis=1) ys = numpy.std(X, axis=1) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.set_title('click on point to plot time series') line, = ax.plot(xs, ys, 'o', picker=5) # 5 points tolerance diff --git a/examples/event_handling/pipong.py b/examples/event_handling/pipong.py index 7433aaf2c463..be1352218f07 100755 --- a/examples/event_handling/pipong.py +++ b/examples/event_handling/pipong.py @@ -250,7 +250,6 @@ def key_press(self,event): if event.key == 'g': #self.ax.clear() - #self.ax.grid() # seems to be necessary for qt backend self.on = not self.on if event.key == 't': self.inst = not self.inst diff --git a/examples/event_handling/poly_editor.py b/examples/event_handling/poly_editor.py index c7d96df66d51..191740cd242d 100644 --- a/examples/event_handling/poly_editor.py +++ b/examples/event_handling/poly_editor.py @@ -145,7 +145,6 @@ def motion_notify_callback(self, event): import matplotlib.pyplot as plt from matplotlib.patches import Polygon - fig = plt.figure() theta = np.arange(0, 2*np.pi, 0.1) r = 1.5 @@ -154,7 +153,7 @@ def motion_notify_callback(self, event): poly = Polygon(list(zip(xs, ys)), animated=True) - ax = plt.subplot(111) + fig, ax = plt.subplots() ax.add_patch(poly) p = PolygonInteractor(ax, poly) diff --git a/examples/event_handling/pong_gtk.py b/examples/event_handling/pong_gtk.py index fb8479f6301a..24469a123dfc 100755 --- a/examples/event_handling/pong_gtk.py +++ b/examples/event_handling/pong_gtk.py @@ -16,8 +16,7 @@ import pipong -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() canvas = ax.figure.canvas diff --git a/examples/event_handling/pong_qt.py b/examples/event_handling/pong_qt.py deleted file mode 100644 index d27b6c1101e7..000000000000 --- a/examples/event_handling/pong_qt.py +++ /dev/null @@ -1,40 +0,0 @@ -# For detailed comments on animation and the techniqes used here, see -# the wiki entry http://www.scipy.org/Cookbook/Matplotlib/Animations - -from __future__ import print_function - -import matplotlib -matplotlib.use('QtAgg') # qt3 example - -from qt import * -# Note: color-intensive applications may require a different color allocation -# strategy. -QApplication.setColorSpec(QApplication.NormalColor) - -TRUE = 1 -FALSE = 0 -ITERS = 1000 - -import matplotlib.pyplot as plt -import time -import pipong - -class BlitQT(QObject): - def __init__(self): - QObject.__init__(self, None, "app") - - self.ax = plt.subplot(111) - self.animation = pipong.Game(self.ax) - - def timerEvent(self, evt): - self.animation.draw(evt) - -plt.grid() # to ensure proper background restore - -app = BlitQT() -# for profiling -app.tstart = time.time() -app.startTimer(10) - -plt.show() -print('FPS:' , app.animation.cnt/(time.time()-app.tstart)) diff --git a/examples/event_handling/resample.py b/examples/event_handling/resample.py index a9df778cd3e4..76c9514d3a76 100644 --- a/examples/event_handling/resample.py +++ b/examples/event_handling/resample.py @@ -39,8 +39,7 @@ def update(self, ax): d = DataDisplayDownsampler(xdata, ydata) -fig = plt.figure() -ax = fig.add_subplot(1, 1, 1) +fig, ax = plt.subplots() #Hook up the line xdata, ydata = d.downsample(xdata[0], xdata[-1]) diff --git a/examples/event_handling/test_mouseclicks.py b/examples/event_handling/test_mouseclicks.py index 450d2c63d628..506ee5b1cd7b 100755 --- a/examples/event_handling/test_mouseclicks.py +++ b/examples/event_handling/test_mouseclicks.py @@ -5,7 +5,6 @@ #matplotlib.use("WxAgg") #matplotlib.use("TkAgg") #matplotlib.use("GTKAgg") -#matplotlib.use("QtAgg") #matplotlib.use("Qt4Agg") #matplotlib.use("CocoaAgg") #matplotlib.use("MacOSX") diff --git a/examples/event_handling/timers.py b/examples/event_handling/timers.py index 2541f11aae3e..0e293a84975c 100644 --- a/examples/event_handling/timers.py +++ b/examples/event_handling/timers.py @@ -8,8 +8,7 @@ def update_title(axes): axes.set_title(datetime.now()) axes.figure.canvas.draw() -fig = plt.figure() -ax = fig.add_subplot(1, 1, 1) +fig, ax = plt.subplots() x = np.linspace(-3, 3) ax.plot(x, x*x) diff --git a/examples/event_handling/trifinder_event_demo.py b/examples/event_handling/trifinder_event_demo.py new file mode 100644 index 000000000000..fd7ccc77d400 --- /dev/null +++ b/examples/event_handling/trifinder_event_demo.py @@ -0,0 +1,59 @@ +""" +Example showing the use of a TriFinder object. As the mouse is moved over the +triangulation, the triangle under the cursor is highlighted and the index of +the triangle is displayed in the plot title. +""" +import matplotlib.pyplot as plt +from matplotlib.tri import Triangulation +from matplotlib.patches import Polygon +import numpy as np +import math + + +def update_polygon(tri): + if tri == -1: + points = [0, 0, 0] + else: + points = triangulation.triangles[tri] + xs = triangulation.x[points] + ys = triangulation.y[points] + polygon.set_xy(zip(xs, ys)) + + +def motion_notify(event): + if event.inaxes is None: + tri = -1 + else: + tri = trifinder(event.xdata, event.ydata) + update_polygon(tri) + plt.title('In triangle %i' % tri) + event.canvas.draw() + + +# Create a Triangulation. +n_angles = 16 +n_radii = 5 +min_radius = 0.25 +radii = np.linspace(min_radius, 0.95, n_radii) +angles = np.linspace(0, 2*math.pi, n_angles, endpoint=False) +angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1) +angles[:, 1::2] += math.pi / n_angles +x = (radii*np.cos(angles)).flatten() +y = (radii*np.sin(angles)).flatten() +triangulation = Triangulation(x, y) +xmid = x[triangulation.triangles].mean(axis=1) +ymid = y[triangulation.triangles].mean(axis=1) +mask = np.where(xmid*xmid + ymid*ymid < min_radius*min_radius, 1, 0) +triangulation.set_mask(mask) + +# Use the triangulation's default TriFinder object. +trifinder = triangulation.get_trifinder() + +# Setup plot and callbacks. +plt.subplot(111, aspect='equal') +plt.triplot(triangulation, 'bo-') +polygon = Polygon([[0, 0], [0, 0]], facecolor='y') # dummy data for xs,ys +update_polygon(-1) +plt.gca().add_patch(polygon) +plt.gcf().canvas.mpl_connect('motion_notify_event', motion_notify) +plt.show() diff --git a/examples/event_handling/viewlims.py b/examples/event_handling/viewlims.py index fe5838cbc6c6..be2565366af5 100644 --- a/examples/event_handling/viewlims.py +++ b/examples/event_handling/viewlims.py @@ -58,11 +58,8 @@ def ax_update(self, ax): md = MandlebrotDisplay() Z = md(-2., 0.5, -1.25, 1.25) -fig = plt.figure() -ax1 = fig.add_subplot(1, 2, 1) +fig1, (ax1, ax2) = plt.subplots(1, 2) ax1.imshow(Z, origin='lower', extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max())) - -ax2 = fig.add_subplot(1, 2, 2) ax2.imshow(Z, origin='lower', extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max())) rect = UpdatingRect([0, 0], 0, 0, facecolor='None', edgecolor='black') diff --git a/examples/images_contours_and_fields/image_demo.py b/examples/images_contours_and_fields/image_demo.py new file mode 100644 index 000000000000..83e49217816f --- /dev/null +++ b/examples/images_contours_and_fields/image_demo.py @@ -0,0 +1,13 @@ +""" +Simple demo of the imshow function. +""" +import matplotlib.pyplot as plt +import matplotlib.cbook as cbook + +image_file = cbook.get_sample_data('ada.png') +image = plt.imread(image_file) + +plt.imshow(image) +plt.axis('off') # clear x- and y-axes +plt.show() + diff --git a/examples/images_contours_and_fields/image_demo_clip_path.py b/examples/images_contours_and_fields/image_demo_clip_path.py new file mode 100644 index 000000000000..77a7f7718b7f --- /dev/null +++ b/examples/images_contours_and_fields/image_demo_clip_path.py @@ -0,0 +1,18 @@ +""" +Demo of image that's been clipped by a circular patch. +""" +import matplotlib.pyplot as plt +import matplotlib.patches as patches +import matplotlib.cbook as cbook + + +image_file = cbook.get_sample_data('grace_hopper.png') +image = plt.imread(image_file) + +fig, ax = plt.subplots() +im = ax.imshow(image) +patch = patches.Circle((260, 200), radius=200, transform=ax.transData) +im.set_clip_path(patch) + +plt.axis('off') +plt.show() diff --git a/examples/images_contours_and_fields/pcolormesh_levels.py b/examples/images_contours_and_fields/pcolormesh_levels.py new file mode 100644 index 000000000000..a042e9236d33 --- /dev/null +++ b/examples/images_contours_and_fields/pcolormesh_levels.py @@ -0,0 +1,53 @@ +""" +Shows how to combine Normalization and Colormap instances to draw +"levels" in pcolor, pcolormesh and imshow type plots in a similar +way to the levels keyword argument to contour/contourf. + +""" + +import matplotlib.pyplot as plt +from matplotlib.colors import BoundaryNorm +from matplotlib.ticker import MaxNLocator +import numpy as np + + +# make these smaller to increase the resolution +dx, dy = 0.05, 0.05 + +# generate 2 2d grids for the x & y bounds +y, x = np.mgrid[slice(1, 5 + dy, dy), + slice(1, 5 + dx, dx)] + +z = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x) + +# x and y are bounds, so z should be the value *inside* those bounds. +# Therefore, remove the last value from the z array. +z = z[:-1, :-1] +levels = MaxNLocator(nbins=15).tick_values(z.min(), z.max()) + + +# pick the desired colormap, sensible levels, and define a normalization +# instance which takes data values and translates those into levels. +cmap = plt.get_cmap('PiYG') +norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True) + +plt.subplot(2, 1, 1) +im = plt.pcolormesh(x, y, z, cmap=cmap, norm=norm) +plt.colorbar() +# set the limits of the plot to the limits of the data +plt.axis([x.min(), x.max(), y.min(), y.max()]) +plt.title('pcolormesh with levels') + + + +plt.subplot(2, 1, 2) +# contours are *point* based plots, so convert our bound into point +# centers +plt.contourf(x[:-1, :-1] + dx / 2., + y[:-1, :-1] + dy / 2., z, levels=levels, + cmap=cmap) +plt.colorbar() +plt.title('contourf with levels') + + +plt.show() \ No newline at end of file diff --git a/examples/images_contours_and_fields/streamplot_demo_features.py b/examples/images_contours_and_fields/streamplot_demo_features.py new file mode 100644 index 000000000000..2cc10bf877e8 --- /dev/null +++ b/examples/images_contours_and_fields/streamplot_demo_features.py @@ -0,0 +1,29 @@ +""" +Demo of the `streamplot` function. + +A streamplot, or streamline plot, is used to display 2D vector fields. This +example shows a few features of the stream plot function: + + * Varying the color along a streamline. + * Varying the density of streamlines. + * Varying the line width along a stream line. +""" +import numpy as np +import matplotlib.pyplot as plt + +Y, X = np.mgrid[-3:3:100j, -3:3:100j] +U = -1 - X**2 + Y +V = 1 + X - Y**2 +speed = np.sqrt(U*U + V*V) + +plt.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=plt.cm.autumn) +plt.colorbar() + +f, (ax1, ax2) = plt.subplots(ncols=2) +ax1.streamplot(X, Y, U, V, density=[0.5, 1]) + +lw = 5*speed/speed.max() +ax2.streamplot(X, Y, U, V, density=0.6, color='k', linewidth=lw) + +plt.show() + diff --git a/examples/images_contours_and_fields/streamplot_demo_masking.py b/examples/images_contours_and_fields/streamplot_demo_masking.py new file mode 100644 index 000000000000..ce0ac99b9410 --- /dev/null +++ b/examples/images_contours_and_fields/streamplot_demo_masking.py @@ -0,0 +1,27 @@ +""" +Demo of the streamplot function with masking. + +This example shows how streamlines created by the streamplot function skips +masked regions and NaN values. +""" +import numpy as np +import matplotlib.pyplot as plt + +w = 3 +Y, X = np.mgrid[-w:w:100j, -w:w:100j] +U = -1 - X**2 + Y +V = 1 + X - Y**2 +speed = np.sqrt(U*U + V*V) + +mask = np.zeros(U.shape, dtype=bool) +mask[40:60, 40:60] = 1 +U = np.ma.array(U, mask=mask) +U[:20, :20] = np.nan + +plt.streamplot(X, Y, U, V, color='r') + +plt.imshow(~mask, extent=(-w, w, -w, w), alpha=0.5, + interpolation='nearest', cmap=plt.cm.gray) + +plt.show() + diff --git a/examples/lines_bars_and_markers/barh_demo.py b/examples/lines_bars_and_markers/barh_demo.py new file mode 100644 index 000000000000..2016824cc2ad --- /dev/null +++ b/examples/lines_bars_and_markers/barh_demo.py @@ -0,0 +1,20 @@ +""" +Simple demo of a horizontal bar chart. +""" +import matplotlib.pyplot as plt; plt.rcdefaults() +import numpy as np +import matplotlib.pyplot as plt + + +# Example data +people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim') +y_pos = np.arange(len(people)) +performance = 3 + 10 * np.random.rand(len(people)) +error = np.random.rand(len(people)) + +plt.barh(y_pos, performance, xerr=error, align='center', alpha=0.4) +plt.yticks(y_pos, people) +plt.xlabel('Performance') +plt.title('How fast do you want to go today?') + +plt.show() diff --git a/examples/lines_bars_and_markers/fill_demo.py b/examples/lines_bars_and_markers/fill_demo.py new file mode 100644 index 000000000000..fff88f2e503a --- /dev/null +++ b/examples/lines_bars_and_markers/fill_demo.py @@ -0,0 +1,13 @@ +""" +Simple demo of the fill function. +""" +import numpy as np +import matplotlib.pyplot as plt + + +x = np.linspace(0, 1) +y = np.sin(4 * np.pi * x) * np.exp(-5 * x) + +plt.fill(x, y, 'r') +plt.grid(True) +plt.show() diff --git a/examples/lines_bars_and_markers/fill_demo_features.py b/examples/lines_bars_and_markers/fill_demo_features.py new file mode 100644 index 000000000000..230f1631c0ad --- /dev/null +++ b/examples/lines_bars_and_markers/fill_demo_features.py @@ -0,0 +1,17 @@ +""" +Demo of the fill function with a few features. + +In addition to the basic fill plot, this demo shows a few optional features: + + * Multiple curves with a single command. + * Setting the fill color. + * Setting the opacity (alpha value). +""" +import numpy as np +import matplotlib.pyplot as plt + +x = np.linspace(0, 2 * np.pi, 100) +y1 = np.sin(x) +y2 = np.sin(3 * x) +plt.fill(x, y1, 'b', x, y2, 'r', alpha=0.3) +plt.show() diff --git a/examples/lines_bars_and_markers/line_demo_dash_control.py b/examples/lines_bars_and_markers/line_demo_dash_control.py new file mode 100644 index 000000000000..b884c7e28675 --- /dev/null +++ b/examples/lines_bars_and_markers/line_demo_dash_control.py @@ -0,0 +1,17 @@ +""" +Demo of a simple plot with a custom dashed line. + +A Line object's ``set_dashes`` method allows you to specify dashes with +a series of on/off lengths (in points). +""" +import numpy as np +import matplotlib.pyplot as plt + + +x = np.linspace(0, 10) +line, = plt.plot(x, np.sin(x), '--', linewidth=2) + +dashes = [10, 5, 100, 5] # 10 points on, 5 off, 100 on, 5 off +line.set_dashes(dashes) + +plt.show() diff --git a/examples/misc/longshort.py b/examples/misc/longshort.py index 06b0302b80d0..9cb2a2a50890 100644 --- a/examples/misc/longshort.py +++ b/examples/misc/longshort.py @@ -38,8 +38,7 @@ tr = (1+g).cumprod() # the total return # plot the return -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(r.date, tr) ax.set_title('total return: long APPL, short GOOG') ax.grid() diff --git a/examples/misc/multiprocess.py b/examples/misc/multiprocess.py index 09aa4ed94462..1d2b12b30476 100644 --- a/examples/misc/multiprocess.py +++ b/examples/misc/multiprocess.py @@ -53,9 +53,7 @@ def __call__(self, pipe): print('starting plotter...') self.pipe = pipe - self.fig = plt.figure() - - self.ax = self.fig.add_subplot(111) + self.fig, self.ax = plt.subplots() self.gid = gobject.timeout_add(1000, self.poll_draw()) print('...done') diff --git a/examples/misc/rasterization_demo.py b/examples/misc/rasterization_demo.py index a03daaac9278..067099c56a28 100644 --- a/examples/misc/rasterization_demo.py +++ b/examples/misc/rasterization_demo.py @@ -8,19 +8,17 @@ xx = x*np.cos(theta) - y*np.sin(theta) yy = x*np.sin(theta) + y*np.cos(theta) -ax1 = plt.subplot(221) +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) ax1.set_aspect(1) ax1.pcolormesh(xx, yy, d) ax1.set_title("No Rasterization") -ax2 = plt.subplot(222) ax2.set_aspect(1) ax2.set_title("Rasterization") m = ax2.pcolormesh(xx, yy, d) m.set_rasterized(True) -ax3 = plt.subplot(223) ax3.set_aspect(1) ax3.pcolormesh(xx, yy, d) ax3.text(0.5, 0.5, "Text", alpha=0.2, @@ -29,7 +27,6 @@ ax3.set_title("No Rasterization") -ax4 = plt.subplot(224) ax4.set_aspect(1) m = ax4.pcolormesh(xx, yy, d) m.set_zorder(-20) diff --git a/examples/misc/rc_traits.py b/examples/misc/rc_traits.py index ffad4701a282..ee74f750f8b5 100644 --- a/examples/misc/rc_traits.py +++ b/examples/misc/rc_traits.py @@ -127,7 +127,7 @@ class PatchRC(traits.HasTraits): antialiased = flexible_true_trait timezones = 'UTC', 'US/Central', 'ES/Eastern' # fixme: and many more -backends = ('GTKAgg', 'Cairo', 'FltkAgg', 'GDK', 'GTK', 'Agg', +backends = ('GTKAgg', 'Cairo', 'GDK', 'GTK', 'Agg', 'GTKCairo', 'PS', 'SVG', 'Template', 'TkAgg', 'WX') @@ -192,6 +192,3 @@ def __init__(self, print() print('Patch') p.print_traits() - - - diff --git a/examples/mplot3d/lorenz_attractor.py b/examples/mplot3d/lorenz_attractor.py index 318f4657ef9a..e88e4f6b4c44 100644 --- a/examples/mplot3d/lorenz_attractor.py +++ b/examples/mplot3d/lorenz_attractor.py @@ -44,6 +44,7 @@ def lorenz(x, y, z, s=10, r=28, b=2.667) : ax.set_xlabel("X Axis") ax.set_ylabel("Y Axis") ax.set_zlabel("Z Axis") +ax.set_title("Lorenz Attractor") plt.show() diff --git a/examples/mplot3d/trisurf3d_demo2.py b/examples/mplot3d/trisurf3d_demo2.py new file mode 100644 index 000000000000..bb86564ca8ed --- /dev/null +++ b/examples/mplot3d/trisurf3d_demo2.py @@ -0,0 +1,55 @@ +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +import matplotlib.tri as mtri + +# u, v are parameterisation variables +u = (np.linspace(0, 2.0 * np.pi, endpoint=True, num=50) * np.ones((10, 1))).flatten() +v = np.repeat(np.linspace(-0.5, 0.5, endpoint=True, num=10), repeats=50).flatten() + +# This is the Mobius mapping, taking a u, v pair and returning an x, y, z +# triple +x = (1 + 0.5 * v * np.cos(u / 2.0)) * np.cos(u) +y = (1 + 0.5 * v * np.cos(u / 2.0)) * np.sin(u) +z = 0.5 * v * np.sin(u / 2.0) + +# Triangulate parameter space to determine the triangles +tri = mtri.Triangulation(u, v) + +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, projection='3d') + +# The triangles in parameter space determine which x, y, z points are +# connected by an edge +ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap=plt.cm.Spectral) + +ax.set_zlim(-1, 1) + +# First create the x and y coordinates of the points. +n_angles = 36 +n_radii = 8 +min_radius = 0.25 +radii = np.linspace(min_radius, 0.95, n_radii) + +angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False) +angles = np.repeat(angles[...,np.newaxis], n_radii, axis=1) +angles[:,1::2] += np.pi/n_angles + +x = (radii*np.cos(angles)).flatten() +y = (radii*np.sin(angles)).flatten() +z = (np.cos(radii)*np.cos(angles*3.0)).flatten() + +# Create the Triangulation; no triangles so Delaunay triangulation created. +triang = mtri.Triangulation(x, y) + +# Mask off unwanted triangles. +xmid = x[triang.triangles].mean(axis=1) +ymid = y[triang.triangles].mean(axis=1) +mask = np.where(xmid*xmid + ymid*ymid < min_radius*min_radius, 1, 0) +triang.set_mask(mask) + +# tripcolor plot. +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, projection='3d') +ax.plot_trisurf(triang, z, cmap=plt.cm.CMRmap) +plt.show() diff --git a/examples/pie_and_polar_charts/pie_demo_features.py b/examples/pie_and_polar_charts/pie_demo_features.py new file mode 100644 index 000000000000..763d38461aee --- /dev/null +++ b/examples/pie_and_polar_charts/pie_demo_features.py @@ -0,0 +1,32 @@ +""" +Demo of a basic pie chart plus a few additional features. + +In addition to the basic pie chart, this demo shows a few optional features: + + * slice labels + * auto-labeling the percentage + * offsetting a slice with "explode" + * drop-shadow + * custom start angle + +Note about the custom start angle: + +The default ``startangle`` is 0, which would start the "Frogs" slice on the +positive x-axis. This example sets ``startangle = 90`` such that everything is +rotated counter-clockwise by 90 degrees, and the frog slice starts on the +positive y-axis. +""" +import matplotlib.pyplot as plt + + +# The slices will be ordered and plotted counter-clockwise. +labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' +sizes = [15, 30, 45, 10] +colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral'] +explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs') + +plt.pie(sizes, explode=explode, labels=labels, colors=colors, + autopct='%1.1f%%', shadow=True, startangle=90) +# Set aspect ratio to be equal so that pie is drawn as a circle. +plt.axis('equal') +plt.show() diff --git a/examples/pie_and_polar_charts/polar_bar_demo.py b/examples/pie_and_polar_charts/polar_bar_demo.py new file mode 100644 index 000000000000..459dd6f958f1 --- /dev/null +++ b/examples/pie_and_polar_charts/polar_bar_demo.py @@ -0,0 +1,21 @@ +""" +Demo of bar plot on a polar axis. +""" +import numpy as np +import matplotlib.pyplot as plt + + +N = 20 +theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False) +radii = 10 * np.random.rand(N) +width = np.pi / 4 * np.random.rand(N) + +ax = plt.subplot(111, polar=True) +bars = ax.bar(theta, radii, width=width, bottom=0.0) + +# Use custom colors and opacity +for r, bar in zip(radii, bars): + bar.set_facecolor(plt.cm.jet(r / 10.)) + bar.set_alpha(0.5) + +plt.show() diff --git a/examples/pie_and_polar_charts/polar_scatter_demo.py b/examples/pie_and_polar_charts/polar_scatter_demo.py new file mode 100644 index 000000000000..90eea4e2b3a8 --- /dev/null +++ b/examples/pie_and_polar_charts/polar_scatter_demo.py @@ -0,0 +1,21 @@ +""" +Demo of scatter plot on a polar axis. + +Size increases radially in this example and color increases with angle (just to +verify the symbols are being scattered correctly). +""" +import numpy as np +import matplotlib.pyplot as plt + + +N = 150 +r = 2 * np.random.rand(N) +theta = 2 * np.pi * np.random.rand(N) +area = 200 * r**2 * np.random.rand(N) +colors = theta + +ax = plt.subplot(111, polar=True) +c = plt.scatter(theta, r, c=colors, s=area, cmap=plt.cm.hsv) +c.set_alpha(0.75) + +plt.show() diff --git a/examples/pylab_examples/README b/examples/pylab_examples/README index 231b7b4ba9aa..e45e071ea9ce 100644 --- a/examples/pylab_examples/README +++ b/examples/pylab_examples/README @@ -13,7 +13,7 @@ Here are some demos of how to use the matplotlib. -- subplot_demo.py - how to do multiple axes on a single plot --- vline_demo.py - working with straight lines +-- vline_hline_demo.py - working with straight lines -- stock_demo.py - working with large datasets. Click on the plot and launch the navigation tool; wheel mouse over the navigation diff --git a/examples/pylab_examples/agg_buffer_to_array.py b/examples/pylab_examples/agg_buffer_to_array.py index a391fb2ca7cd..a52434b282ff 100644 --- a/examples/pylab_examples/agg_buffer_to_array.py +++ b/examples/pylab_examples/agg_buffer_to_array.py @@ -1,10 +1,8 @@ -import matplotlib -from pylab import figure, show +import matplotlib.pyplot as plt import numpy as np # make an agg figure -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot([1,2,3]) ax.set_title('a simple figure') fig.canvas.draw() @@ -18,7 +16,7 @@ X.shape = h,w,4 # now display the array X as an Axes in a new figure -fig2 = figure() +fig2 = plt.figure() ax2 = fig2.add_subplot(111, frameon=False) ax2.imshow(X) -show() +plt.show() diff --git a/examples/pylab_examples/annotation_demo3.py b/examples/pylab_examples/annotation_demo3.py index cf78da77cdbb..31261ae66bb6 100644 --- a/examples/pylab_examples/annotation_demo3.py +++ b/examples/pylab_examples/annotation_demo3.py @@ -1,10 +1,6 @@ import matplotlib.pyplot as plt -fig = plt.figure(1) -fig.clf() - -ax1 = plt.subplot(121) -ax2 = plt.subplot(122) +fig, (ax1, ax2) = plt.subplots(1, 2) bbox_args = dict(boxstyle="round", fc="0.8") arrow_args = dict(arrowstyle="->") diff --git a/examples/pylab_examples/aspect_loglog.py b/examples/pylab_examples/aspect_loglog.py index 4ce384633e91..db22322d8be6 100644 --- a/examples/pylab_examples/aspect_loglog.py +++ b/examples/pylab_examples/aspect_loglog.py @@ -1,6 +1,6 @@ import matplotlib.pyplot as plt -ax1 = plt.subplot(121) +fig, (ax1, ax2) = plt.subplots(1, 2) ax1.set_xscale("log") ax1.set_yscale("log") ax1.set_xlim(1e1, 1e3) @@ -8,7 +8,6 @@ ax1.set_aspect(1) ax1.set_title("adjustable = box") -ax2 = plt.subplot(122) ax2.set_xscale("log") ax2.set_yscale("log") ax2.set_adjustable("datalim") diff --git a/examples/pylab_examples/axes_props.py b/examples/pylab_examples/axes_props.py index 7fe564ef7d49..6f1324b5ad53 100644 --- a/examples/pylab_examples/axes_props.py +++ b/examples/pylab_examples/axes_props.py @@ -36,7 +36,7 @@ t = arange(0.0, 2.0, 0.01) s = sin(2*pi*t) -ax = subplot(111) +fig, ax = plt.subplots() ax.plot(t, s) ax.grid(True) diff --git a/examples/pylab_examples/barchart_demo.py b/examples/pylab_examples/barchart_demo.py index e5f86cf4d2c5..2cc9860d3889 100644 --- a/examples/pylab_examples/barchart_demo.py +++ b/examples/pylab_examples/barchart_demo.py @@ -1,44 +1,41 @@ - -#!/usr/bin/env python +""" +Bar chart demo with pairs of bars grouped for easy comparison. +""" import numpy as np import matplotlib.pyplot as plt -N = 5 -menMeans = (20, 35, 30, 35, 27) -menStd = (2, 3, 4, 1, 2) - -ind = np.arange(N) # the x locations for the groups -width = 0.35 # the width of the bars +n_groups = 5 -plt.subplot(111) -rects1 = plt.bar(ind, menMeans, width, - color='r', - yerr=menStd, - error_kw=dict(elinewidth=6, ecolor='pink')) +means_women = (25, 32, 34, 20, 25) +std_women = (3, 5, 2, 3, 3) +fig, ax = plt.subplots() -womenMeans = (25, 32, 34, 20, 25) -womenStd = (3, 5, 2, 3, 3) -rects2 = plt.bar(ind+width, womenMeans, width, - color='y', - yerr=womenStd, - error_kw=dict(elinewidth=6, ecolor='yellow')) +index = np.arange(n_groups) +bar_width = 0.35 -# add some -plt.ylabel('Scores') -plt.title('Scores by group and gender') -plt.xticks(ind+width, ('G1', 'G2', 'G3', 'G4', 'G5') ) +opacity = 0.4 +error_config = {'ecolor': '0.3'} -plt.legend( (rects1[0], rects2[0]), ('Men', 'Women') ) +rects1 = plt.bar(index, means_men, bar_width, + alpha=opacity, + color='b', + yerr=std_men, + error_kw=error_config, + label='Men') -def autolabel(rects): - # attach some text labels - for rect in rects: - height = rect.get_height() - plt.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height), - ha='center', va='bottom') +rects2 = plt.bar(index + bar_width, means_women, bar_width, + alpha=opacity, + color='r', + yerr=std_women, + error_kw=error_config, + label='Women') -autolabel(rects1) -autolabel(rects2) +plt.xlabel('Group') +plt.ylabel('Scores') +plt.title('Scores by group and gender') +plt.xticks(index + bar_width, ('A', 'B', 'C', 'D', 'E')) +plt.legend() +plt.tight_layout() plt.show() diff --git a/examples/pylab_examples/barchart_demo2.py b/examples/pylab_examples/barchart_demo2.py index 53ffdc419688..54681c888ee6 100644 --- a/examples/pylab_examples/barchart_demo2.py +++ b/examples/pylab_examples/barchart_demo2.py @@ -11,7 +11,6 @@ import numpy as np import matplotlib.pyplot as plt import pylab -from matplotlib.patches import Polygon from matplotlib.ticker import MaxNLocator @@ -28,8 +27,8 @@ scores = ['7', '48', '12:52', '17', '14'] rankings = np.round(np.random.uniform(0, 1, numTests)*100, 0) -fig = plt.figure(figsize=(9,7)) -ax1 = fig.add_subplot(111) + +fig, ax1 = plt.subplots(figsize=(9,7)) plt.subplots_adjust(left=0.115, right=0.88) fig.canvas.set_window_title('Eldorado K-8 Fitness Chart') pos = np.arange(numTests)+0.5 #Center bars on the Y-axis ticks @@ -81,7 +80,7 @@ def withnew(i, scr): width = int(rect.get_width()) # Figure out what the last digit (width modulo 10) so we can add - # the appropriate numerical suffix (e.g. 1st, 2nd, 3rd, etc) + # the appropriate numerical suffix (e.g., 1st, 2nd, 3rd, etc) lastDigit = width % 10 # Note that 11, 12, and 13 are special cases if (width == 11) or (width == 12) or (width == 13): diff --git a/examples/pylab_examples/barh_demo.py b/examples/pylab_examples/barh_demo.py deleted file mode 100644 index 0daef263fd37..000000000000 --- a/examples/pylab_examples/barh_demo.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python -# make a horizontal bar chart - -from pylab import * -val = 3+10*rand(5) # the bar lengths -pos = arange(5)+.5 # the bar centers on the y axis - -figure(1) -barh(pos,val, align='center') -yticks(pos, ('Tom', 'Dick', 'Harry', 'Slim', 'Jim')) -xlabel('Performance') -title('How fast do you want to go today?') -grid(True) - -figure(2) -barh(pos,val, xerr=rand(5), ecolor='r', align='center') -yticks(pos, ('Tom', 'Dick', 'Harry', 'Slim', 'Jim')) -xlabel('Performance') - -show() diff --git a/examples/pylab_examples/boxplot_demo2.py b/examples/pylab_examples/boxplot_demo2.py index 6f4c9ad3e878..5a5b8a4e1c27 100644 --- a/examples/pylab_examples/boxplot_demo2.py +++ b/examples/pylab_examples/boxplot_demo2.py @@ -34,9 +34,8 @@ data = [norm, normBoot, logn, lognBoot, expo, expoBoot, gumb, gumbBoot, tria, triaBoot] -fig = plt.figure(figsize=(10,6)) +fig, ax1 = plt.subplots(figsize=(10,6)) fig.canvas.set_window_title('A Boxplot Example') -ax1 = fig.add_subplot(111) plt.subplots_adjust(left=0.075, right=0.95, top=0.9, bottom=0.25) bp = plt.boxplot(data, notch=0, sym='+', vert=1, whis=1.5) diff --git a/examples/pylab_examples/boxplot_demo3.py b/examples/pylab_examples/boxplot_demo3.py index fe7e5b77a3d5..98883c6f1bc8 100644 --- a/examples/pylab_examples/boxplot_demo3.py +++ b/examples/pylab_examples/boxplot_demo3.py @@ -1,5 +1,4 @@ import matplotlib.pyplot as plt -import matplotlib.transforms as mtransforms import numpy as np def fakeBootStrapper(n): @@ -34,8 +33,7 @@ def fakeBootStrapper(n): medians = [None, None, med1, med2] conf_intervals = [None, None, CI1, CI2] -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() pos = np.array(range(len(treatments)))+1 bp = ax.boxplot(treatments, sym='k+', positions=pos, notch=1, bootstrap=5000, diff --git a/examples/pylab_examples/broken_barh.py b/examples/pylab_examples/broken_barh.py index 3d427e61f618..9d8085f52252 100644 --- a/examples/pylab_examples/broken_barh.py +++ b/examples/pylab_examples/broken_barh.py @@ -3,8 +3,7 @@ """ import matplotlib.pyplot as plt -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.broken_barh([ (110, 30), (150, 10) ] , (10, 9), facecolors='blue') ax.broken_barh([ (10, 50), (100, 20), (130, 10)] , (20, 9), facecolors=('red', 'yellow', 'green')) diff --git a/examples/pylab_examples/centered_ticklabels.py b/examples/pylab_examples/centered_ticklabels.py index b6e40deb50fd..ba496dde7955 100644 --- a/examples/pylab_examples/centered_ticklabels.py +++ b/examples/pylab_examples/centered_ticklabels.py @@ -12,9 +12,7 @@ # between the major ticks. Here is an example that labels the months, # centered between the ticks -import datetime import numpy as np -import matplotlib import matplotlib.cbook as cbook import matplotlib.dates as dates import matplotlib.ticker as ticker @@ -25,8 +23,7 @@ r = np.load(fh); fh.close() r = r[-250:] # get the last 250 days -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(r.date, r.adj_close) ax.xaxis.set_major_locator(dates.MonthLocator()) diff --git a/examples/pylab_examples/colorbar_tick_labelling_demo.py b/examples/pylab_examples/colorbar_tick_labelling_demo.py index 63c84232a04e..1a368da458f2 100644 --- a/examples/pylab_examples/colorbar_tick_labelling_demo.py +++ b/examples/pylab_examples/colorbar_tick_labelling_demo.py @@ -9,8 +9,7 @@ from numpy.random import randn # Make plot with vertical (default) colorbar -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() data = np.clip(randn(250, 250), -1, 1) @@ -22,8 +21,7 @@ cbar.ax.set_yticklabels(['< -1', '0', '> 1'])# vertically oriented colorbar # Make plot with horizontal colorbar -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() data = np.clip(randn(250, 250), -1, 1) diff --git a/examples/pylab_examples/coords_demo.py b/examples/pylab_examples/coords_demo.py index 9f6cdcb87000..fb92f73943e0 100755 --- a/examples/pylab_examples/coords_demo.py +++ b/examples/pylab_examples/coords_demo.py @@ -10,7 +10,7 @@ t = arange(0.0, 1.0, 0.01) s = sin(2*pi*t) -ax = subplot(111) +fig, ax = plt.subplots() ax.plot(t,s) diff --git a/examples/pylab_examples/coords_report.py b/examples/pylab_examples/coords_report.py index 9710e887b82f..44e72237869a 100644 --- a/examples/pylab_examples/coords_report.py +++ b/examples/pylab_examples/coords_report.py @@ -10,7 +10,7 @@ def millions(x): x = rand(20) y = 1e7*rand(20) -ax = subplot(111) +fig, ax = subplots() ax.fmt_ydata = millions plot(x, y, 'o') diff --git a/examples/pylab_examples/cursor_demo.py b/examples/pylab_examples/cursor_demo.py index e98854f02c37..834d52201ea1 100755 --- a/examples/pylab_examples/cursor_demo.py +++ b/examples/pylab_examples/cursor_demo.py @@ -68,7 +68,7 @@ def mouse_move(self, event): t = arange(0.0, 1.0, 0.01) s = sin(2*2*pi*t) -ax = subplot(111) +fig, ax = subplots() cursor = Cursor(ax) #cursor = SnaptoCursor(ax, t, s) diff --git a/examples/pylab_examples/custom_ticker1.py b/examples/pylab_examples/custom_ticker1.py index 8dc453f7acad..91559a05387c 100755 --- a/examples/pylab_examples/custom_ticker1.py +++ b/examples/pylab_examples/custom_ticker1.py @@ -11,9 +11,10 @@ millions of dollars on the y axis """ from matplotlib.ticker import FuncFormatter -from pylab import * +import matplotlib.pyplot as plt +import numpy as np -x = arange(4) +x = np.arange(4) money = [1.5e5, 2.5e6, 5.5e6, 2.0e7] def millions(x, pos): @@ -22,8 +23,8 @@ def millions(x, pos): formatter = FuncFormatter(millions) -ax = subplot(111) +fig, ax = plt.subplots() ax.yaxis.set_major_formatter(formatter) -bar(x, money) -xticks( x + 0.5, ('Bill', 'Fred', 'Mary', 'Sue') ) -show() +plt.bar(x, money) +plt.xticks( x + 0.5, ('Bill', 'Fred', 'Mary', 'Sue') ) +plt.show() diff --git a/examples/pylab_examples/dash_control.py b/examples/pylab_examples/dash_control.py deleted file mode 100644 index 1100882b8873..000000000000 --- a/examples/pylab_examples/dash_control.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python - -""" -You can precisely specify dashes with an on/off ink rect sequence in -points. -""" -from pylab import * - -dashes = [5,2,10,5] # 5 points on, 2 off, 3 on, 1 off - -l, = plot(arange(20), '--') -l.set_dashes(dashes) - -show() diff --git a/examples/pylab_examples/dashpointlabel.py b/examples/pylab_examples/dashpointlabel.py index fe5149d5f878..7a1ab43bb9f8 100644 --- a/examples/pylab_examples/dashpointlabel.py +++ b/examples/pylab_examples/dashpointlabel.py @@ -1,4 +1,4 @@ -import pylab +import matplotlib.pyplot as plt DATA = ((1, 3), (2, 4), @@ -15,9 +15,7 @@ (1, 20, 30, 60, 10), ) -fig = pylab.figure() -ax = fig.add_subplot(111) - +fig, ax = plt.subplots() (x,y) = zip(*DATA) ax.plot(x, y, marker='o') @@ -36,5 +34,5 @@ ax.set_xlim((0.0, 5.0)) ax.set_ylim((0.0, 5.0)) -pylab.show() +plt.show() diff --git a/examples/pylab_examples/date_demo1.py b/examples/pylab_examples/date_demo1.py index bc5370bef52c..51b852a4951e 100644 --- a/examples/pylab_examples/date_demo1.py +++ b/examples/pylab_examples/date_demo1.py @@ -14,7 +14,7 @@ yahoo finance to get the data for plotting """ -from pylab import figure, show +import matplotlib.pyplot as plt from matplotlib.finance import quotes_historical_yahoo from matplotlib.dates import YearLocator, MonthLocator, DateFormatter import datetime @@ -33,8 +33,7 @@ dates = [q[0] for q in quotes] opens = [q[1] for q in quotes] -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot_date(dates, opens, '-') # format the ticks @@ -50,4 +49,4 @@ def price(x): return '$%1.2f'%x ax.grid(True) fig.autofmt_xdate() -show() +plt.show() diff --git a/examples/pylab_examples/date_demo2.py b/examples/pylab_examples/date_demo2.py index 6fa276cf233c..d6420f97674c 100755 --- a/examples/pylab_examples/date_demo2.py +++ b/examples/pylab_examples/date_demo2.py @@ -7,7 +7,7 @@ """ from __future__ import print_function import datetime -from pylab import figure, show +import matplotlib.pyplot as plt from matplotlib.dates import MONDAY from matplotlib.finance import quotes_historical_yahoo from matplotlib.dates import MonthLocator, WeekdayLocator, DateFormatter @@ -32,8 +32,7 @@ dates = [q[0] for q in quotes] opens = [q[1] for q in quotes] -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot_date(dates, opens, '-') ax.xaxis.set_major_locator(months) ax.xaxis.set_major_formatter(monthsFmt) @@ -45,4 +44,4 @@ fig.autofmt_xdate() -show() +plt.show() diff --git a/examples/pylab_examples/date_demo_convert.py b/examples/pylab_examples/date_demo_convert.py index d2ad0d096146..7ccb7c6f649d 100644 --- a/examples/pylab_examples/date_demo_convert.py +++ b/examples/pylab_examples/date_demo_convert.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import datetime -from matplotlib.pyplot import figure, show +import matplotlib.pyplot as plt from matplotlib.dates import DayLocator, HourLocator, DateFormatter, drange from numpy import arange @@ -12,8 +12,7 @@ y = arange( len(dates)*1.0) -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot_date(dates, y*y) # this is superfluous, since the autoscaler should get it right, but @@ -31,4 +30,4 @@ ax.fmt_xdata = DateFormatter('%Y-%m-%d %H:%M:%S') fig.autofmt_xdate() -show() +plt.show() diff --git a/examples/pylab_examples/date_demo_rrule.py b/examples/pylab_examples/date_demo_rrule.py index d0df79caec30..c8dbef935396 100644 --- a/examples/pylab_examples/date_demo_rrule.py +++ b/examples/pylab_examples/date_demo_rrule.py @@ -5,8 +5,9 @@ See https://moin.conectiva.com.br/DateUtil for help with rrules """ -from pylab import * +import matplotlib.pyplot as plt from matplotlib.dates import YEARLY, DateFormatter, rrulewrapper, RRuleLocator, drange +import numpy as np import datetime # tick every 5th easter @@ -18,14 +19,14 @@ delta = datetime.timedelta(days=100) dates = drange(date1, date2, delta) -s = rand(len(dates)) # make up some random y values +s = np.random.rand(len(dates)) # make up some random y values -ax = subplot(111) -plot_date(dates, s) +fig, ax = plt.subplots() +plt.plot_date(dates, s) ax.xaxis.set_major_locator(loc) ax.xaxis.set_major_formatter(formatter) labels = ax.get_xticklabels() -setp(labels, rotation=30, fontsize=10) +plt.setp(labels, rotation=30, fontsize=10) -show() +plt.show() diff --git a/examples/pylab_examples/date_index_formatter.py b/examples/pylab_examples/date_index_formatter.py index 9b1144544283..270ee2d319ca 100644 --- a/examples/pylab_examples/date_index_formatter.py +++ b/examples/pylab_examples/date_index_formatter.py @@ -11,7 +11,7 @@ from __future__ import print_function import numpy from matplotlib.mlab import csv2rec -from pylab import figure, show +import matplotlib.pyplot as plt import matplotlib.cbook as cbook from matplotlib.ticker import Formatter @@ -33,9 +33,8 @@ def __call__(self, x, pos=0): formatter = MyFormatter(r.date) -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.xaxis.set_major_formatter(formatter) ax.plot(numpy.arange(len(r)), r.close, 'o-') fig.autofmt_xdate() -show() +plt.show() diff --git a/examples/pylab_examples/demo_annotation_box.py b/examples/pylab_examples/demo_annotation_box.py index ed1fd71943c4..169c52c8d8e0 100644 --- a/examples/pylab_examples/demo_annotation_box.py +++ b/examples/pylab_examples/demo_annotation_box.py @@ -6,9 +6,7 @@ import numpy as np if 1: - fig = plt.gcf() - fig.clf() - ax = plt.subplot(111) + fig, ax = plt.subplots() offsetbox = TextArea("Test 1", minimumdescent=False) diff --git a/examples/pylab_examples/demo_ribbon_box.py b/examples/pylab_examples/demo_ribbon_box.py index 9ab0be183ec1..617c731588ab 100644 --- a/examples/pylab_examples/demo_ribbon_box.py +++ b/examples/pylab_examples/demo_ribbon_box.py @@ -96,9 +96,7 @@ def draw(self, renderer, *args, **kwargs): from matplotlib.transforms import Bbox, TransformedBbox from matplotlib.ticker import ScalarFormatter - fig = plt.gcf() - fig.clf() - ax = plt.subplot(111) + fig, ax = plt.subplots() years = np.arange(2004, 2009) box_colors = [(0.8, 0.2, 0.2), diff --git a/examples/pylab_examples/dolphin.py b/examples/pylab_examples/dolphin.py index f457ccc0c796..e02fa41200a7 100644 --- a/examples/pylab_examples/dolphin.py +++ b/examples/pylab_examples/dolphin.py @@ -11,8 +11,7 @@ x = r * np.cos(t) y = r * np.sin(t) -fig = plt.figure(figsize=(6,6)) -ax = plt.subplot(111) +fig, ax = plt.subplots(figsize=(6,6)) circle = Circle((0, 0), 1, facecolor='none', edgecolor=(0,0.8,0.8), linewidth=3, alpha=0.5) ax.add_patch(circle) diff --git a/examples/pylab_examples/ellipse_collection.py b/examples/pylab_examples/ellipse_collection.py index bc228db77e89..a6a06a5f4054 100644 --- a/examples/pylab_examples/ellipse_collection.py +++ b/examples/pylab_examples/ellipse_collection.py @@ -13,7 +13,7 @@ aa = X*9 -ax = plt.subplot(1,1,1) +fig, ax = plt.subplots() ec = EllipseCollection( ww, diff --git a/examples/pylab_examples/errorbar_demo.py b/examples/pylab_examples/errorbar_demo.py deleted file mode 100644 index dbe6bdb2cd64..000000000000 --- a/examples/pylab_examples/errorbar_demo.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -import numpy as np -import matplotlib.pyplot as plt - -# example data -x = np.arange(0.1, 4, 0.5) -y = np.exp(-x) - -# example variable error bar values -yerr = 0.1 + 0.2*np.sqrt(x) -xerr = 0.1 + yerr - -# First illustrate basic pyplot interface, using defaults where possible. -plt.figure() -plt.errorbar(x, y, xerr=0.2, yerr=0.4) -plt.title("Simplest errorbars, 0.2 in x, 0.4 in y") - -# Now switch to a more OO interface to exercise more features. -fig, axs = plt.subplots(nrows=2, ncols=2, sharex=True) -ax = axs[0,0] -ax.errorbar(x, y, yerr=yerr, fmt='o') -ax.set_title('Vert. symmetric') - -# With 4 subplots, reduce the number of axis ticks to avoid crowding. -ax.locator_params(nbins=4) - -ax = axs[0,1] -ax.errorbar(x, y, xerr=xerr, fmt='o') -ax.set_title('Hor. symmetric') - -ax = axs[1,0] -ax.errorbar(x, y, yerr=[yerr, 2*yerr], xerr=[xerr, 2*xerr], fmt='--o') -ax.set_title('H, V asymmetric') - -ax = axs[1,1] -ax.set_yscale('log') -# Here we have to be careful to keep all y values positive: -ylower = np.maximum(1e-2, y - yerr) -yerr_lower = y - ylower - -ax.errorbar(x, y, yerr=[yerr_lower, 2*yerr], xerr=xerr, - fmt='o', ecolor='g', capthick=2) -ax.set_title('Mixed sym., log y') - -fig.suptitle('Variable errorbars') - -plt.show() - diff --git a/examples/pylab_examples/eventcollection_demo.py b/examples/pylab_examples/eventcollection_demo.py new file mode 100644 index 000000000000..3510a70479ae --- /dev/null +++ b/examples/pylab_examples/eventcollection_demo.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- Coding:utf-8 -*- +'''Plot two curves, then use EventCollections to mark the locations of the x +and y data points on the respective axes for each curve''' + +import matplotlib.pyplot as plt +from matplotlib.collections import EventCollection +import numpy as np + +# create random data +np.random.seed(50) +xdata = np.random.random([2, 10]) + +# split the data into two parts +xdata1 = xdata[0, :] +xdata2 = xdata[1, :] + +# sort the data so it makes clean curves +xdata1.sort() +xdata2.sort() + +# create some y data points +ydata1 = xdata1 ** 2 +ydata2 = 1 - xdata2 ** 3 + +# plot the data +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1) +ax.plot(xdata1, ydata1, 'r', xdata2, ydata2, 'b') + +# create the events marking the x data points +xevents1 = EventCollection(xdata1, color=[1, 0, 0], linelength=0.05) +xevents2 = EventCollection(xdata2, color=[0, 0, 1], linelength=0.05) + +# create the events marking the y data points +yevents1 = EventCollection(ydata1, color=[1, 0, 0], linelength=0.05, + orientation='vertical') +yevents2 = EventCollection(ydata2, color=[0, 0, 1], linelength=0.05, + orientation='vertical') + +# add the events to the axis +ax.add_collection(xevents1) +ax.add_collection(xevents2) +ax.add_collection(yevents1) +ax.add_collection(yevents2) + +# set the limits +ax.set_xlim([0, 1]) +ax.set_ylim([0, 1]) + +ax.set_title('line plot with data points') + +# display the plot +plt.show() diff --git a/examples/pylab_examples/eventplot_demo.py b/examples/pylab_examples/eventplot_demo.py new file mode 100644 index 000000000000..8af41530aa9c --- /dev/null +++ b/examples/pylab_examples/eventplot_demo.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- Coding:utf-8 -*- +'''an eventplot showing sequences of events with various line properties +the plot is shown in both horizontal and vertical orientations''' + +import matplotlib.pyplot as plt +import numpy as np + +# set the random seed +np.random.seed(0) + +# create random data +data1 = np.random.random([6, 50]) + +# set different colors for each set of positions +colors1 = np.array([[1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 1, 0], + [1, 0, 1], + [0, 1, 1]]) + +# set different line properties for each set of positions +# note that some overlap +lineoffsets1 = np.array([-15, -3, 1, 1.5, 6, 10]) +linelengths1 = [5, 2, 1, 1, 3, 1.5] + +fig = plt.figure() + +# create a horizontal plot +ax1 = fig.add_subplot(221) +ax1.eventplot(data1, colors=colors1, lineoffsets=lineoffsets1, + linelengths=linelengths1) +ax1.set_title('horizontal eventplot 1') + + +# create a vertical plot +ax2 = fig.add_subplot(223) +ax2.eventplot(data1, colors=colors1, lineoffsets=lineoffsets1, + linelengths=linelengths1, orientation='vertical') +ax2.set_title('vertical eventplot 1') + +# create another set of random data. +# the gamma distribution is only used fo aesthetic purposes +data2 = np.random.gamma(4, size=[60, 50]) + +# use individual values for the parameters this time +# these values will be used for all data sets (except lineoffsets2, which +# sets the increment between each data set in this usage) +colors2 = [[0, 0, 0]] +lineoffsets2 = 1 +linelengths2 = 1 + +# create a horizontal plot +ax1 = fig.add_subplot(222) +ax1.eventplot(data2, colors=colors2, lineoffsets=lineoffsets2, + linelengths=linelengths2) +ax1.set_title('horizontal eventplot 2') + + +# create a vertical plot +ax2 = fig.add_subplot(224) +ax2.eventplot(data2, colors=colors2, lineoffsets=lineoffsets2, + linelengths=linelengths2, orientation='vertical') +ax2.set_title('vertical eventplot 2') + +plt.show() diff --git a/examples/pylab_examples/fill_between_demo.py b/examples/pylab_examples/fill_between_demo.py index 1dd2dc2ea36d..ebf8d76bb677 100644 --- a/examples/pylab_examples/fill_between_demo.py +++ b/examples/pylab_examples/fill_between_demo.py @@ -1,16 +1,12 @@ #!/usr/bin/env python -import matplotlib.mlab as mlab -from matplotlib.pyplot import figure, show +import matplotlib.pyplot as plt import numpy as np x = np.arange(0.0, 2, 0.01) y1 = np.sin(2*np.pi*x) y2 = 1.2*np.sin(4*np.pi*x) -fig = figure() -ax1 = fig.add_subplot(311) -ax2 = fig.add_subplot(312, sharex=ax1) -ax3 = fig.add_subplot(313, sharex=ax1) +fig, (ax1, ax2, ax3) = plt.subplots(3,1, sharex=True) ax1.fill_between(x, 0, y1) ax1.set_ylabel('between y1 and 0') @@ -26,8 +22,7 @@ # this is different than calling # fill_between(x[where], y1[where],y2[where] # because of edge effects over multiple contiguous regions. -fig = figure() -ax = fig.add_subplot(211) +fig, (ax, ax1) = plt.subplots(2, 1, sharex=True) ax.plot(x, y1, x, y2, color='black') ax.fill_between(x, y1, y2, where=y2>=y1, facecolor='green', interpolate=True) ax.fill_between(x, y1, y2, where=y2<=y1, facecolor='red', interpolate=True) @@ -35,7 +30,6 @@ # Test support for masked arrays. y2 = np.ma.masked_greater(y2, 1.0) -ax1 = fig.add_subplot(212, sharex=ax) ax1.plot(x, y1, x, y2, color='black') ax1.fill_between(x, y1, y2, where=y2>=y1, facecolor='green', interpolate=True) ax1.fill_between(x, y1, y2, where=y2<=y1, facecolor='red', interpolate=True) @@ -47,8 +41,7 @@ # arrays to a very fine grid before plotting. # show how to use transforms to create axes spans where a certain condition is satisfied -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() y = np.sin(4*np.pi*x) ax.plot(x, y, color='black') @@ -62,6 +55,4 @@ ax.fill_between(x, 0, 1, where=y<-theta, facecolor='red', alpha=0.5, transform=trans) - -show() - +plt.show() diff --git a/examples/pylab_examples/fill_demo.py b/examples/pylab_examples/fill_demo.py deleted file mode 100644 index 1cfded4d60cb..000000000000 --- a/examples/pylab_examples/fill_demo.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import numpy as np -import matplotlib.pyplot as plt - -t = np.arange(0.0, 1.01, 0.01) -s = np.sin(2*2*np.pi*t) - -plt.fill(t, s*np.exp(-5*t), 'r') -plt.grid(True) -plt.show() diff --git a/examples/pylab_examples/fill_demo2.py b/examples/pylab_examples/fill_demo2.py deleted file mode 100644 index 77b86d79017e..000000000000 --- a/examples/pylab_examples/fill_demo2.py +++ /dev/null @@ -1,10 +0,0 @@ -from matplotlib.pyplot import figure, show -from numpy import arange, sin, pi - -fig = figure() -ax = fig.add_subplot(111) -t = arange(0.0,3.01,0.01) -s = sin(2*pi*t) -c = sin(4*pi*t) -ax.fill(t, s, 'b', t, c, 'g', alpha=0.2) -show() diff --git a/examples/pylab_examples/finance_demo.py b/examples/pylab_examples/finance_demo.py index 81aac7a2bd9d..9d0318e2f234 100644 --- a/examples/pylab_examples/finance_demo.py +++ b/examples/pylab_examples/finance_demo.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -from pylab import * +import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ DayLocator, MONDAY from matplotlib.finance import quotes_historical_yahoo, candlestick,\ @@ -12,16 +12,15 @@ mondays = WeekdayLocator(MONDAY) # major ticks on the mondays alldays = DayLocator() # minor ticks on the days -weekFormatter = DateFormatter('%b %d') # Eg, Jan 12 -dayFormatter = DateFormatter('%d') # Eg, 12 +weekFormatter = DateFormatter('%b %d') # e.g., Jan 12 +dayFormatter = DateFormatter('%d') # e.g., 12 quotes = quotes_historical_yahoo('INTC', date1, date2) if len(quotes) == 0: raise SystemExit -fig = figure() +fig, ax = plt.subplots() fig.subplots_adjust(bottom=0.2) -ax = fig.add_subplot(111) ax.xaxis.set_major_locator(mondays) ax.xaxis.set_minor_locator(alldays) ax.xaxis.set_major_formatter(weekFormatter) @@ -32,7 +31,7 @@ ax.xaxis_date() ax.autoscale_view() -setp( gca().get_xticklabels(), rotation=45, horizontalalignment='right') +plt.setp( plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right') -show() +plt.show() diff --git a/examples/pylab_examples/findobj_demo.py b/examples/pylab_examples/findobj_demo.py index 73e61f783bd3..0fd96f1dd824 100644 --- a/examples/pylab_examples/findobj_demo.py +++ b/examples/pylab_examples/findobj_demo.py @@ -10,8 +10,7 @@ c = np.exp(a) d = c[::-1] -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() plt.plot(a,c,'k--',a,d,'k:',a,c+d,'k') plt.legend(('Model length', 'Data length', 'Total message length'), 'upper center', shadow=True) diff --git a/examples/pylab_examples/gradient_bar.py b/examples/pylab_examples/gradient_bar.py index fb747157079f..9133a89c59bb 100644 --- a/examples/pylab_examples/gradient_bar.py +++ b/examples/pylab_examples/gradient_bar.py @@ -24,5 +24,5 @@ def gbar(ax, x, y, width=0.5, bottom=0): x = arange(N)+0.25 y = rand(N) gbar(ax, x, y, width=0.7) -ax.set_aspect('normal') +ax.set_aspect('auto') show() diff --git a/examples/pylab_examples/hist_colormapped.py b/examples/pylab_examples/hist_colormapped.py index cce35e889fdc..6a5fb69d13ae 100644 --- a/examples/pylab_examples/hist_colormapped.py +++ b/examples/pylab_examples/hist_colormapped.py @@ -1,12 +1,11 @@ -import numpy as n -from pylab import figure, show +import numpy as np +import matplotlib.pyplot as plt import matplotlib.cm as cm import matplotlib.colors as colors -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() Ntotal = 1000 -N, bins, patches = ax.hist(n.random.rand(Ntotal), 20) +N, bins, patches = ax.hist(np.random.rand(Ntotal), 20) #I'll color code by height, but you could use any scalar @@ -21,4 +20,4 @@ thispatch.set_facecolor(color) -show() +plt.show() diff --git a/examples/pylab_examples/histogram_demo.py b/examples/pylab_examples/histogram_demo.py deleted file mode 100644 index 00919f78ea67..000000000000 --- a/examples/pylab_examples/histogram_demo.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -import numpy as np -import matplotlib.mlab as mlab -import matplotlib.pyplot as plt - -mu, sigma = 100, 15 -x = mu + sigma*np.random.randn(10000) - -# the histogram of the data -n, bins, patches = plt.hist(x, 50, normed=1, facecolor='green', alpha=0.75) - -# add a 'best fit' line -y = mlab.normpdf( bins, mu, sigma) -l = plt.plot(bins, y, 'r--', linewidth=1) - -plt.xlabel('Smarts') -plt.ylabel('Probability') -plt.title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') -plt.axis([40, 160, 0, 0.03]) -plt.grid(True) - -plt.show() diff --git a/examples/pylab_examples/hline_demo.py b/examples/pylab_examples/hline_demo.py deleted file mode 100755 index 8d02cca3e8f5..000000000000 --- a/examples/pylab_examples/hline_demo.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -import numpy as np -import matplotlib.pyplot as plt - -def f(t): - s1 = np.sin(2*np.pi*t) - e1 = np.exp(-t) - return np.absolute((s1*e1))+.05 - - -t = np.arange(0.0, 5.0, 0.1) -s = f(t) -nse = np.random.normal(0.0, 0.3, t.shape) * s - - -plt.plot(s+nse, t, 'b^') -plt.hlines(t, [0], s, lw=2) -plt.xlabel('time (s)') -plt.title('Comparison of model with data') - -plt.xlim(xmin=0) -plt.show() - diff --git a/examples/pylab_examples/image_demo3.py b/examples/pylab_examples/image_demo3.py deleted file mode 100644 index 73a7c0af98c5..000000000000 --- a/examples/pylab_examples/image_demo3.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python -from pylab import * -try: - from PIL import Image -except ImportError: - raise SystemExit("PIL must be installed to run this example") - -import matplotlib.cbook as cbook - -datafile = cbook.get_sample_data('grace_hopper.jpg') -lena = Image.open(datafile) -dpi = rcParams['figure.dpi'] -figsize = lena.size[0]/dpi, lena.size[1]/dpi - -figure(figsize=figsize) -ax = axes([0,0,1,1], frameon=False) -ax.set_axis_off() -im = imshow(lena) - -show() - diff --git a/examples/pylab_examples/image_interp.py b/examples/pylab_examples/image_interp.py index dff0e7c96311..8f9b9b130448 100644 --- a/examples/pylab_examples/image_interp.py +++ b/examples/pylab_examples/image_interp.py @@ -15,7 +15,7 @@ matplotlib._image module which takes advantage of this fix, no longer makes this necessary. To prevent edge effects, when doing interpolation, the matplotlib._image module now pads the input array -with identical pixels around the edge. Eg, if you have a 5x5 array +with identical pixels around the edge. e.g., if you have a 5x5 array with colors a-y as below diff --git a/examples/pylab_examples/integral_demo.py b/examples/pylab_examples/integral_demo.py deleted file mode 100644 index 436482ce189a..000000000000 --- a/examples/pylab_examples/integral_demo.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - -# implement the example graphs/integral from pyx -from pylab import * -from matplotlib.patches import Polygon - -def func(x): - return (x-3)*(x-5)*(x-7)+85 - -ax = subplot(111) - -a, b = 2, 9 # integral area -x = arange(0, 10, 0.01) -y = func(x) -plot(x, y, linewidth=1) - -# make the shaded region -ix = arange(a, b, 0.01) -iy = func(ix) -verts = [(a,0)] + list(zip(ix,iy)) + [(b,0)] -poly = Polygon(verts, facecolor='0.8', edgecolor='k') -ax.add_patch(poly) - -text(0.5 * (a + b), 30, - r"$\int_a^b f(x)\mathrm{d}x$", horizontalalignment='center', - fontsize=20) - -axis([0,10, 0, 180]) -figtext(0.9, 0.05, 'x') -figtext(0.1, 0.9, 'y') -ax.set_xticks((a,b)) -ax.set_xticklabels(('a','b')) -ax.set_yticks([]) -show() diff --git a/examples/pylab_examples/interp_demo.py b/examples/pylab_examples/interp_demo.py index 0f7375475d18..911781f07d3d 100644 --- a/examples/pylab_examples/interp_demo.py +++ b/examples/pylab_examples/interp_demo.py @@ -1,4 +1,4 @@ -from matplotlib.pyplot import figure, show +import matplotlib.pyplot as plt from numpy import pi, sin, linspace from matplotlib.mlab import stineman_interp @@ -7,8 +7,7 @@ xi = linspace(x[0],x[-1],100); yi = stineman_interp(xi,x,y,yp); -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.plot(x,y,'ro',xi,yi,'-b.') -show() +plt.show() diff --git a/examples/pylab_examples/legend_auto.py b/examples/pylab_examples/legend_auto.py index a29a746d13ae..bcab13df3375 100644 --- a/examples/pylab_examples/legend_auto.py +++ b/examples/pylab_examples/legend_auto.py @@ -18,7 +18,7 @@ def fig_1(): figure(1) t = arange(0, 40.0 * pi, 0.1) l, = plot(t, 100*sin(t), 'r', label='sine') - legend() + legend(framealpha=0.5) def fig_2(): figure(2) diff --git a/examples/pylab_examples/legend_demo.py b/examples/pylab_examples/legend_demo.py index 5151dfe203a0..fefc97ea7937 100644 --- a/examples/pylab_examples/legend_demo.py +++ b/examples/pylab_examples/legend_demo.py @@ -1,45 +1,42 @@ -#!/usr/bin/env python -# Thanks to Charles Twardy for this example -# -#See http://matplotlib.sf.net/examples/legend_demo2.py for an example -#controlling which lines the legend uses and the order +""" +Demo of the legend function with a few features. +In addition to the basic legend, this demo shows a few optional features: + + * Custom legend placement. + * A keyword argument to a drop-shadow. + * Setting the background color. + * Setting the font size. + * Setting the line width. +""" import numpy as np import matplotlib.pyplot as plt -a = np.arange(0,3,.02) -b = np.arange(0,3,.02) + +# Example data +a = np.arange(0,3, .02) +b = np.arange(0,3, .02) c = np.exp(a) d = c[::-1] -ax = plt.subplot(111) -plt.plot(a,c,'k--',a,d,'k:',a,c+d,'k') -plt.legend(('Model length', 'Data length', 'Total message length'), - 'upper center', shadow=True, fancybox=True) -plt.ylim([-1,20]) -plt.grid(False) -plt.xlabel('Model complexity --->') -plt.ylabel('Message length --->') -plt.title('Minimum Message Length') - -plt.setp(plt.gca(), 'yticklabels', []) -plt.setp(plt.gca(), 'xticklabels', []) - -# set some legend properties. All the code below is optional. The -# defaults are usually sensible but if you need more control, this -# shows you how -leg = plt.gca().get_legend() -ltext = leg.get_texts() # all the text.Text instance in the legend -llines = leg.get_lines() # all the lines.Line2D instance in the legend -frame = leg.get_frame() # the patch.Rectangle instance surrounding the legend - -# see text.Text, lines.Line2D, and patches.Rectangle for more info on -# the settable properties of lines, text, and rectangles -frame.set_facecolor('0.80') # set the frame face color to light gray -plt.setp(ltext, fontsize='small') # the legend text fontsize -plt.setp(llines, linewidth=1.5) # the legend linewidth -#leg.draw_frame(False) # don't draw the legend frame -plt.show() +# Create plots with pre-defined labels. +# Alternatively, you can pass labels explicitly when calling `legend`. +fig, ax = plt.subplots() +ax.plot(a, c, 'k--', label='Model length') +ax.plot(a, d, 'k:', label='Data length') +ax.plot(a, c+d, 'k', label='Total message length') +# Now add the legend with some customizations. +legend = ax.legend(loc='upper center', shadow=True) +# The frame is matplotlib.patches.Rectangle instance surrounding the legend. +frame = legend.get_frame() +frame.set_facecolor('0.90') +# Set the fontsize +for label in legend.get_texts(): + label.set_fontsize('large') + +for label in legend.get_lines(): + label.set_linewidth(1.5) # the legend line width +plt.show() diff --git a/examples/pylab_examples/legend_demo2.py b/examples/pylab_examples/legend_demo2.py index d8db01bc6f71..f1209eea920c 100644 --- a/examples/pylab_examples/legend_demo2.py +++ b/examples/pylab_examples/legend_demo2.py @@ -1,24 +1,23 @@ -#!/usr/bin/env python -# # Make a legend for specific lines. -from pylab import * +import matplotlib.pyplot as plt +import numpy as np -t1 = arange(0.0, 2.0, 0.1) -t2 = arange(0.0, 2.0, 0.01) + +t1 = np.arange(0.0, 2.0, 0.1) +t2 = np.arange(0.0, 2.0, 0.01) # note that plot returns a list of lines. The "l1, = plot" usage -# extracts the first element of the list inot l1 using tuple +# extracts the first element of the list into l1 using tuple # unpacking. So l1 is a Line2D instance, not a sequence of lines -l1, = plot(t2, exp(-t2)) -l2, l3 = plot(t2, sin(2*pi*t2), '--go', t1, log(1+t1), '.') -l4, = plot(t2, exp(-t2)*sin(2*pi*t2), 'rs-.') +l1, = plt.plot(t2, np.exp(-t2)) +l2, l3 = plt.plot(t2, np.sin(2 * np.pi * t2), '--go', t1, np.log(1 + t1), '.') +l4, = plt.plot(t2, np.exp(-t2) * np.sin(2 * np.pi * t2), 'rs-.') -legend( (l2, l4), ('oscillatory', 'damped'), 'upper right', shadow=True) -xlabel('time') -ylabel('volts') -title('Damped oscillation') -#axis([0,2,-1,1]) -show() +plt.legend( (l2, l4), ('oscillatory', 'damped'), 'upper right', shadow=True) +plt.xlabel('time') +plt.ylabel('volts') +plt.title('Damped oscillation') +plt.show() diff --git a/examples/pylab_examples/major_minor_demo1.py b/examples/pylab_examples/major_minor_demo1.py index 81090b065d7a..ec9db4673414 100644 --- a/examples/pylab_examples/major_minor_demo1.py +++ b/examples/pylab_examples/major_minor_demo1.py @@ -30,7 +30,8 @@ """ -from pylab import * +import matplotlib.pyplot as plt +import numpy as np from matplotlib.ticker import MultipleLocator, FormatStrFormatter majorLocator = MultipleLocator(20) @@ -38,11 +39,11 @@ minorLocator = MultipleLocator(5) -t = arange(0.0, 100.0, 0.1) -s = sin(0.1*pi*t)*exp(-t*0.01) +t = np.arange(0.0, 100.0, 0.1) +s = np.sin(0.1*np.pi*t)*np.exp(-t*0.01) -ax = subplot(111) -plot(t,s) +fig, ax = plt.subplots() +plt.plot(t,s) ax.xaxis.set_major_locator(majorLocator) ax.xaxis.set_major_formatter(majorFormatter) @@ -50,4 +51,4 @@ #for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) -show() +plt.show() diff --git a/examples/pylab_examples/major_minor_demo2.py b/examples/pylab_examples/major_minor_demo2.py index eaeed688ac86..bb0a2633faca 100644 --- a/examples/pylab_examples/major_minor_demo2.py +++ b/examples/pylab_examples/major_minor_demo2.py @@ -22,7 +22,7 @@ t = np.arange(0.0, 100.0, 0.01) s = np.sin(2*np.pi*t)*np.exp(-t*0.01) -ax = plt.subplot(111) +fig, ax = plt.subplots() plt.plot(t,s) ax.xaxis.set_minor_locator(minorLocator) diff --git a/examples/pylab_examples/marker_path.py b/examples/pylab_examples/marker_path.py index f8e53c7ed3f0..ac18d1335133 100644 --- a/examples/pylab_examples/marker_path.py +++ b/examples/pylab_examples/marker_path.py @@ -5,9 +5,9 @@ star = mpath.Path.unit_regular_star(6) circle = mpath.Path.unit_circle() -# concatenate the star with an internal cutout of the circle -verts = np.concatenate([star.vertices, circle.vertices[::-1, ...]]) -codes = np.concatenate([star.codes, circle.codes]) +# concatenate the circle with an internal cutout of the star +verts = np.concatenate([circle.vertices, star.vertices[::-1, ...]]) +codes = np.concatenate([circle.codes, star.codes]) cut_star = mpath.Path(verts, codes) diff --git a/examples/pylab_examples/mathtext_examples.py b/examples/pylab_examples/mathtext_examples.py index d71c47fb50b4..ec6269e8d70c 100755 --- a/examples/pylab_examples/mathtext_examples.py +++ b/examples/pylab_examples/mathtext_examples.py @@ -1,89 +1,118 @@ -#!/usr/bin/env python - +""" +Selected features of Matplotlib's math rendering engine. +""" from __future__ import print_function +import matplotlib.pyplot as plt +import os +import sys +import re +import gc -import os, sys, re +# Selection of features following "Writing mathematical expressions" tutorial +mathtext_titles = { + 0: "Header demo", + 1: "Subscripts and superscripts", + 2: "Fractions, binomials and stacked numbers", + 3: "Radicals", + 4: "Fonts", + 5: "Accents", + 6: "Greek, Hebrew", + 7: "Delimiters, functions and Symbols"} +n_lines = len(mathtext_titles) -import gc +# Randomly picked examples +mathext_demos = { + 0: r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = " + r"U^{3\beta}_{\delta_1 \rho_1} + \frac{1}{8 \pi 2} " + r"\int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 \left[\frac{ " + r"U^{2\beta}_{\delta_1 \rho_1} - \alpha^\prime_2U^{1\beta}_" + r"{\rho_1 \sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$", + + 1: r"$\alpha_i > \beta_i,\ " + r"\alpha_{i+1}^j = {\rm sin}(2\pi f_j t_i) e^{-5 t_i/\tau},\ " + r"\ldots$", + + 2: r"$\frac{3}{4},\ \binom{3}{4},\ \stackrel{3}{4},\ " + r"\left(\frac{5 - \frac{1}{x}}{4}\right),\ \ldots$", + + 3: r"$\sqrt{2},\ \sqrt[3]{x},\ \ldots$", + + 4: r"$\mathrm{Roman}\ , \ \mathit{Italic}\ , \ \mathtt{Typewriter} \ " + r"\mathrm{or}\ \mathcal{CALLIGRAPHY}$", + + 5: r"$\acute a,\ \bar a,\ \breve a,\ \dot a,\ \ddot a, \ \grave a, \ " + r"\hat a,\ \tilde a,\ \vec a,\ \widehat{xyz},\ \widetilde{xyz},\ " + r"\ldots$", + + 6: r"$\alpha,\ \beta,\ \chi,\ \delta,\ \lambda,\ \mu,\ " + r"\Delta,\ \Gamma,\ \Omega,\ \Phi,\ \Pi,\ \Upsilon,\ \nabla,\ " + r"\aleph,\ \beth,\ \daleth,\ \gimel,\ \ldots$", + + 7: r"$\coprod,\ \int,\ \oint,\ \prod,\ \sum,\ " + r"\log,\ \sin,\ \approx,\ \oplus,\ \star,\ \varpropto,\ " + r"\infty,\ \partial,\ \Re,\ \leftrightsquigarrow, \ \ldots$"} -stests = [ - r'$a+b+\dots+\dot{s}+\ldots$', - r'$x \doteq y$', - r'\$100.00 $\alpha \_$', - r'$\frac{\$100.00}{y}$', - r'$x y$', - r'$x+y\ x=y\ x 0xffff: -# stests.append(ur'$\mathrm{\ue0f2 \U0001D538}$') - - -from pylab import * def doall(): - tests = stests + # Colors used in mpl online documentation. + mpl_blue_rvb = (191./255., 209./256., 212./255.) + mpl_orange_rvb = (202/255., 121/256., 0./255.) + mpl_grey_rvb = (51./255., 51./255., 51./255.) + + # Creating figure and axis. + plt.figure(figsize=(6, 7)) + plt.axes([0.01, 0.01, 0.98, 0.90], axisbg="white", frameon=True) + plt.gca().set_xlim(0., 1.) + plt.gca().set_ylim(0., 1.) + plt.gca().set_title("Matplotlib's math rendering engine", + color=mpl_grey_rvb, fontsize=14, weight='bold') + plt.gca().set_xticklabels("", visible=False) + plt.gca().set_yticklabels("", visible=False) + + # Gap between lines in axes coords + line_axesfrac = (1. / (n_lines)) + + # Plotting header demonstration formula + full_demo = mathext_demos[0] + plt.annotate(full_demo, + xy=(0.5, 1. - 0.59*line_axesfrac), + xycoords='data', color=mpl_orange_rvb, ha='center', + fontsize=20) - figure(figsize=(8, (len(tests) * 1) + 2)) - plot([0, 0], 'r') - grid(False) - axis([0, 3, -len(tests), 0]) - yticks(arange(len(tests)) * -1) - for i, s in enumerate(tests): - print (i, s) - text(0.1, -i, s, fontsize=20) + # Plotting features demonstration formulae + for i_line in range(1, n_lines): + baseline = 1. - (i_line)*line_axesfrac + baseline_next = baseline - line_axesfrac*1. + title = mathtext_titles[i_line] + ":" + fill_color = ['white', mpl_blue_rvb][i_line % 2] + plt.fill_between([0., 1.], [baseline, baseline], + [baseline_next, baseline_next], + color=fill_color, alpha=0.5) + plt.annotate(title, + xy=(0.07, baseline - 0.3*line_axesfrac), + xycoords='data', color=mpl_grey_rvb, weight='bold') + demo = mathext_demos[i_line] + plt.annotate(demo, + xy=(0.05, baseline - 0.75*line_axesfrac), + xycoords='data', color=mpl_grey_rvb, + fontsize=16) - #savefig('mathtext_examples') - #close('all') - show() + for i in range(n_lines): + s = mathext_demos[i] + print(i, s) + plt.show() if '--latex' in sys.argv: + # Run: python mathtext_examples.py --latex + # Need amsmath and amssymb packages. fd = open("mathtext_examples.ltx", "w") fd.write("\\documentclass{article}\n") + fd.write("\\usepackage{amsmath, amssymb}\n") fd.write("\\begin{document}\n") fd.write("\\begin{enumerate}\n") - for i, s in enumerate(stests): + for i in range(n_lines): + s = mathext_demos[i] s = re.sub(r"(?", connectionstyle="angle3", lw=2), - size=20, ha="center") - - txt.set_path_effects([PathEffects.withStroke(linewidth=3, + size=20, ha="center", path_effects=[PathEffects.withStroke(linewidth=3, foreground="w")]) - txt.arrow_patch.set_path_effects([PathEffects.Stroke(linewidth=5, - foreground="w"), - PathEffects.Normal()]) + txt.arrow_patch.set_path_effects([ + PathEffects.Stroke(linewidth=5, foreground="w"), + PathEffects.Normal()]) + + ax1.grid(True, linestyle="-") + + pe = [PathEffects.withStroke(linewidth=3, + foreground="w")] + for l in ax1.get_xgridlines() + ax1.get_ygridlines(): + l.set_path_effects(pe) ax2 = plt.subplot(132) arr = np.arange(25).reshape((5,5)) ax2.imshow(arr) cntr = ax2.contour(arr, colors="k") - clbls = ax2.clabel(cntr, fmt="%2.0f", use_clabeltext=True) - plt.setp(clbls, - path_effects=[PathEffects.withStroke(linewidth=3, - foreground="w")]) + plt.setp(cntr.collections, path_effects=[ + PathEffects.withStroke(linewidth=3, foreground="w")]) + + clbls = ax2.clabel(cntr, fmt="%2.0f", use_clabeltext=True) + plt.setp(clbls, path_effects=[ + PathEffects.withStroke(linewidth=3, foreground="w")]) # shadow as a path effect ax3 = plt.subplot(133) @@ -34,4 +41,3 @@ leg.legendPatch.set_path_effects([PathEffects.withSimplePatchShadow()]) plt.show() - diff --git a/examples/pylab_examples/pcolor_demo.py b/examples/pylab_examples/pcolor_demo.py index 015b4a7f63d8..4a1639c03c42 100644 --- a/examples/pylab_examples/pcolor_demo.py +++ b/examples/pylab_examples/pcolor_demo.py @@ -1,28 +1,57 @@ -#!/usr/bin/env python """ -See pcolor_demo2 for an alternative way of generating pcolor plots -using imshow that is likely faster for large grids +Demonstrates similarities between pcolor, pcolormesh, imshow and pcolorfast +for drawing quadrilateral grids. + """ -from __future__ import division -from matplotlib.patches import Patch -from pylab import * +import matplotlib.pyplot as plt +import numpy as np -def func3(x,y): - return (1- x/2 + x**5 + y**3)*exp(-x**2-y**2) +# make these smaller to increase the resolution +dx, dy = 0.15, 0.05 +# generate 2 2d grids for the x & y bounds +y, x = np.mgrid[slice(-3, 3 + dy, dy), + slice(-3, 3 + dx, dx)] +z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2) +# x and y are bounds, so z should be the value *inside* those bounds. +# Therefore, remove the last value from the z array. +z = z[:-1, :-1] +z_min, z_max = -np.abs(z).max(), np.abs(z).max() + + + +plt.subplot(2, 2, 1) +plt.pcolor(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max) +plt.title('pcolor') +# set the limits of the plot to the limits of the data +plt.axis([x.min(), x.max(), y.min(), y.max()]) +plt.colorbar() + + + +plt.subplot(2, 2, 2) +plt.pcolormesh(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max) +plt.title('pcolormesh') +# set the limits of the plot to the limits of the data +plt.axis([x.min(), x.max(), y.min(), y.max()]) +plt.colorbar() + + + +plt.subplot(2, 2, 3) +plt.imshow(z, cmap='RdBu', vmin=z_min, vmax=z_max, + extent=[x.min(), x.max(), y.min(), y.max()], + interpolation='nearest', origin='lower') +plt.title('image (interp. nearest)') +plt.colorbar() -# make these smaller to increase the resolution -dx, dy = 0.05, 0.05 -x = arange(-3.0, 3.0001, dx) -y = arange(-3.0, 3.0001, dy) -X,Y = meshgrid(x, y) -Z = func3(X, Y) -pcolor(X, Y, Z, cmap=cm.RdBu, vmax=abs(Z).max(), vmin=-abs(Z).max()) -colorbar() -axis([-3,3,-3,3]) +ax = plt.subplot(2, 2, 4) +ax.pcolorfast(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max) +plt.title('pcolorfast') +plt.colorbar() -show() +plt.show() \ No newline at end of file diff --git a/examples/pylab_examples/pcolor_demo2.py b/examples/pylab_examples/pcolor_demo2.py deleted file mode 100644 index f5ae2c9fa3ea..000000000000 --- a/examples/pylab_examples/pcolor_demo2.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -""" -See pcolor_demo2 for a much faster way of generating pcolor plots -""" -from __future__ import division -from pylab import * - -def func3(x,y): - return (1- x/2 + x**5 + y**3)*exp(-x**2-y**2) - - -# make these smaller to increase the resolution -dx, dy = 0.05, 0.05 - -x = arange(-3.0, 3.0, dx) -y = arange(-3.0, 3.0, dy) -X,Y = meshgrid(x, y) - -Z = func3(X, Y) - - -ax = subplot(111) -im = imshow(Z, cmap=cm.RdBu, vmax=abs(Z).max(), vmin=-abs(Z).max()) -#im.set_interpolation('nearest') -#im.set_interpolation('bicubic') -im.set_interpolation('bilinear') -#ax.set_image_extent(-3, 3, -3, 3) - -show() - - diff --git a/examples/pylab_examples/pcolor_log.py b/examples/pylab_examples/pcolor_log.py index 4cdb9bf2a2bb..84f831bca17e 100644 --- a/examples/pylab_examples/pcolor_log.py +++ b/examples/pylab_examples/pcolor_log.py @@ -1,27 +1,25 @@ -from pylab import * - +import matplotlib.pyplot as plt from matplotlib.colors import LogNorm +import numpy as np +from matplotlib.mlab import bivariate_normal N = 100 -x = linspace(-3.0, 3.0, N) -y = linspace(-2.0, 2.0, N) - -X, Y = meshgrid(x, y) +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] # A low hump with a spike coming out of the top right. # Needs to have z/colour axis on a log scale so we see both hump and spike. # linear scale only shows the spike. -Z1 = bivariate_normal(X, Y, 0.1, 0.2, 1.0, 1.0) + 0.1*bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) +Z1 = bivariate_normal(X, Y, 0.1, 0.2, 1.0, 1.0) + 0.1 * bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) -subplot(2,1,1) -pcolor(X, Y, Z1, norm=LogNorm(vmin=Z1.min(), vmax=Z1.max()), cmap=cm.PuBu_r) -colorbar() +plt.subplot(2,1,1) +plt.pcolor(X, Y, Z1, norm=LogNorm(vmin=Z1.min(), vmax=Z1.max()), cmap='PuBu_r') +plt.colorbar() -subplot(2,1,2) -pcolor(X, Y, Z1, cmap=cm.PuBu_r) -colorbar() +plt.subplot(2,1,2) +plt.pcolor(X, Y, Z1, cmap='PuBu_r') +plt.colorbar() -show() +plt.show() diff --git a/examples/pylab_examples/pcolor_small.py b/examples/pylab_examples/pcolor_small.py index b957b463502f..3ecd09d8aeac 100644 --- a/examples/pylab_examples/pcolor_small.py +++ b/examples/pylab_examples/pcolor_small.py @@ -1,15 +1,14 @@ -#!/usr/bin/env python - -from pylab import * +import matplotlib.pyplot as plt +from numpy.random import rand Z = rand(6,10) -subplot(2,1,1) -c = pcolor(Z) -title('default: no edges') +plt.subplot(2,1,1) +c = plt.pcolor(Z) +plt.title('default: no edges') -subplot(2,1,2) -c = pcolor(Z, edgecolors='k', linewidths=4) -title('thick edges') +plt.subplot(2,1,2) +c = plt.pcolor(Z, edgecolors='k', linewidths=4) +plt.title('thick edges') -show() +plt.show() diff --git a/examples/pylab_examples/pie_demo.py b/examples/pylab_examples/pie_demo.py deleted file mode 100644 index 0b0e9a3b8a7c..000000000000 --- a/examples/pylab_examples/pie_demo.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Make a pie chart - see -http://matplotlib.sf.net/matplotlib.pylab.html#-pie for the docstring. - -This example shows a basic pie chart with labels optional features, -like autolabeling the percentage, offsetting a slice with "explode", -adding a shadow, and changing the starting angle. - -""" -from pylab import * - -# make a square figure and axes -figure(1, figsize=(6,6)) -ax = axes([0.1, 0.1, 0.8, 0.8]) - -# The slices will be ordered and plotted counter-clockwise. -labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' -fracs = [15, 30, 45, 10] -explode=(0, 0.05, 0, 0) - -pie(fracs, explode=explode, labels=labels, - autopct='%1.1f%%', shadow=True, startangle=90) - # The default startangle is 0, which would start - # the Frogs slice on the x-axis. With startangle=90, - # everything is rotated counter-clockwise by 90 degrees, - # so the plotting starts on the positive y-axis. - -title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5}) - -show() diff --git a/examples/pylab_examples/pie_demo2.py b/examples/pylab_examples/pie_demo2.py index 9e37ea513bcf..c3cd16fcb37e 100644 --- a/examples/pylab_examples/pie_demo2.py +++ b/examples/pylab_examples/pie_demo2.py @@ -1,19 +1,19 @@ """ Make a pie charts of varying size - see -http://matplotlib.sf.net/matplotlib.pylab.html#-pie for the docstring. +http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.pie for the docstring. This example shows a basic pie charts with labels optional features, like autolabeling the percentage, offsetting a slice with "explode" and adding a shadow, in different sizes. """ -from pylab import * +import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec # Some data labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' -fracs = [15,30,45, 10] +fracs = [15, 30, 45, 10] explode=(0, 0.05, 0, 0) @@ -21,21 +21,19 @@ the_grid = GridSpec(2, 2) -figure(1, figsize=(6,6)) +plt.subplot(the_grid[0, 0], aspect=1) -subplot(the_grid[0, 0]) +plt.pie(fracs, labels=labels, autopct='%1.1f%%', shadow=True) -pie(fracs, labels=labels, autopct='%1.1f%%', shadow=True) +plt.subplot(the_grid[0, 1], aspect=1) -subplot(the_grid[0, 1]) +plt.pie(fracs, explode=explode, labels=labels, autopct='%.0f%%', shadow=True) -pie(fracs, explode=explode, labels=labels, autopct='%.0f%%', shadow=True) +plt.subplot(the_grid[1, 0], aspect=1) -subplot(the_grid[1, 0]) - -patches, texts, autotexts = pie(fracs, labels=labels, - autopct='%.0f%%', - shadow=True, radius=0.5) +patches, texts, autotexts = plt.pie(fracs, labels=labels, + autopct='%.0f%%', + shadow=True, radius=0.5) # Make the labels on the small plot easier to read. for t in texts: @@ -44,9 +42,9 @@ t.set_size('x-small') autotexts[0].set_color('y') -subplot(the_grid[1, 1]) +plt.subplot(the_grid[1, 1], aspect=1) -patches, texts, autotexts = pie(fracs, explode=explode, +patches, texts, autotexts = plt.pie(fracs, explode=explode, labels=labels, autopct='%.0f%%', shadow=False, radius=0.5) # Turn off shadow for tiny plot @@ -57,4 +55,4 @@ t.set_size('x-small') autotexts[0].set_color('y') -show() +plt.show() diff --git a/examples/pylab_examples/polar_bar.py b/examples/pylab_examples/polar_bar.py deleted file mode 100644 index 14d8d7de0b43..000000000000 --- a/examples/pylab_examples/polar_bar.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python - -import numpy as np -import matplotlib.cm as cm -from matplotlib.pyplot import figure, show, rc - - -# force square figure and square axes looks better for polar, IMO -fig = figure(figsize=(8,8)) -ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True) - -N = 20 -theta = np.arange(0.0, 2*np.pi, 2*np.pi/N) -radii = 10*np.random.rand(N) -width = np.pi/4*np.random.rand(N) -bars = ax.bar(theta, radii, width=width, bottom=0.0) -for r,bar in zip(radii, bars): - bar.set_facecolor( cm.jet(r/10.)) - bar.set_alpha(0.5) - -show() diff --git a/examples/pylab_examples/polar_demo.py b/examples/pylab_examples/polar_demo.py index 0c27aeeb24bb..3127cb55fde2 100644 --- a/examples/pylab_examples/polar_demo.py +++ b/examples/pylab_examples/polar_demo.py @@ -1,64 +1,17 @@ -#!/usr/bin/env python -# -# matplotlib now has a PolarAxes class and a polar function in the -# matplotlib interface. This is considered alpha and the interface -# may change as we work out how polar axes should best be integrated -# -# The only function that has been tested on polar axes is "plot" (the -# pylab interface function "polar" calls ax.plot where ax is a -# PolarAxes) -- other axes plotting functions may work on PolarAxes -# but haven't been tested and may need tweaking. -# -# you can get a PolarSubplot instance by doing, for example -# -# subplot(211, polar=True) -# -# or a PolarAxes instance by doing -# axes([left, bottom, width, height], polar=True) -# -# The view limits (eg xlim and ylim) apply to the lower left and upper -# right of the rectangular box that surrounds to polar axes. Eg if -# you have -# -# r = arange(0,1,0.01) -# theta = 2*pi*r -# -# the lower left corner is 5/4pi, sqrt(2) and the -# upper right corner is 1/4pi, sqrt(2) -# -# you could change the radial bounding box (zoom out) by setting the -# ylim (radial coordinate is the second argument to the plot command, -# as in MATLAB, though this is not advised currently because it is not -# clear to me how the axes should behave in the change of view limits. -# Please advise me if you have opinions. Likewise, the pan/zoom -# controls probably do not do what you think they do and are better -# left alone on polar axes. Perhaps I will disable them for polar -# axes unless we come up with a meaningful, useful and functional -# implementation for them. -# -# See the pylab rgrids and thetagrids functions for -# information on how to customize the grid locations and labels -import matplotlib +""" +Demo of a line plot on a polar axis. +""" import numpy as np -from matplotlib.pyplot import figure, show, rc, grid +import matplotlib.pyplot as plt -# radar green, solid grid lines -rc('grid', color='#316931', linewidth=1, linestyle='-') -rc('xtick', labelsize=15) -rc('ytick', labelsize=15) - -# force square figure and square axes looks better for polar, IMO -width, height = matplotlib.rcParams['figure.figsize'] -size = min(width, height) -# make a square figure -fig = figure(figsize=(size, size)) -ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, axisbg='#d5de9c') r = np.arange(0, 3.0, 0.01) -theta = 2*np.pi*r -ax.plot(theta, r, color='#ee8d18', lw=3) +theta = 2 * np.pi * r + +ax = plt.subplot(111, polar=True) +ax.plot(theta, r, color='r', linewidth=3) ax.set_rmax(2.0) -grid(True) +ax.grid(True) -ax.set_title("And there was much rejoicing!", fontsize=20) -show() +ax.set_title("A line plot on a polar axis", va='bottom') +plt.show() diff --git a/examples/pylab_examples/polar_scatter.py b/examples/pylab_examples/polar_scatter.py deleted file mode 100644 index 196f6e847290..000000000000 --- a/examples/pylab_examples/polar_scatter.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -# a polar scatter plot; size increases radially in this example and -# color increases with angle (just to verify the symbols are being -# scattered correctly). In a real example, this would be wasting -# dimensionality of the plot -from pylab import * - -N = 150 -r = 2*rand(N) -theta = 2*pi*rand(N) -area = 200*r**2*rand(N) -colors = theta -ax = subplot(111, polar=True) -c = scatter(theta, r, c=colors, s=area, cmap=cm.hsv) -c.set_alpha(0.75) - -show() diff --git a/examples/pylab_examples/poormans_contour.py b/examples/pylab_examples/poormans_contour.py deleted file mode 100644 index 5a518e1a6963..000000000000 --- a/examples/pylab_examples/poormans_contour.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python -""" -Use a pcolor or imshow with a custom colormap to make a contour plot. - -Since this example was initially written, a proper contour routine was -added to matplotlib - see contour_demo.py and -http://matplotlib.sf.net/matplotlib.pylab.html#-contour. -""" - -from pylab import * - - -delta = 0.01 -x = arange(-3.0, 3.0, delta) -y = arange(-3.0, 3.0, delta) -X,Y = meshgrid(x, y) -Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) -Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) -Z = Z2 - Z1 # difference of Gaussians - -cmap = cm.get_cmap('PiYG', 11) # 11 discrete colors - -im = imshow(Z, cmap=cmap, interpolation='bilinear', - vmax=abs(Z).max(), vmin=-abs(Z).max()) -axis('off') -colorbar() - -show() - diff --git a/examples/pylab_examples/scatter_custom_symbol.py b/examples/pylab_examples/scatter_custom_symbol.py index 602e2a97d2f9..845d5194c8f4 100644 --- a/examples/pylab_examples/scatter_custom_symbol.py +++ b/examples/pylab_examples/scatter_custom_symbol.py @@ -1,5 +1,5 @@ -from matplotlib.pyplot import figure, show -from numpy import arange, pi, cos, sin, pi +import matplotlib.pyplot as plt +from numpy import arange, pi, cos, sin from numpy.random import rand # unit area ellipse @@ -11,8 +11,7 @@ x,y,s,c = rand(4, 30) s*= 10**2. -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.scatter(x,y,s,c,marker=None,verts =verts) -show() +plt.show() diff --git a/examples/pylab_examples/scatter_demo.py b/examples/pylab_examples/scatter_demo.py deleted file mode 100644 index 3adf52b1dd1f..000000000000 --- a/examples/pylab_examples/scatter_demo.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -from pylab import * - -N = 30 -x = 0.9*rand(N) -y = 0.9*rand(N) -area = pi*(10 * rand(N))**2 # 0 to 10 point radiuses -scatter(x,y,s=area, marker='^', c='r') - -show() diff --git a/examples/pylab_examples/scatter_demo2.py b/examples/pylab_examples/scatter_demo2.py index 6c06adf27980..a6ad75ffbdad 100644 --- a/examples/pylab_examples/scatter_demo2.py +++ b/examples/pylab_examples/scatter_demo2.py @@ -1,40 +1,32 @@ """ -make a scatter plot with varying color and size arguments +Demo of scatter plot with varying marker colors and sizes. """ -import matplotlib import numpy as np import matplotlib.pyplot as plt -import matplotlib.mlab as mlab import matplotlib.cbook as cbook -# load a numpy record array from yahoo csv data with fields date, +# Load a numpy record array from yahoo csv data with fields date, # open, close, volume, adj_close from the mpl-data/example directory. # The record array stores python datetime.date as an object array in # the date column datafile = cbook.get_sample_data('goog.npy') -r = np.load(datafile).view(np.recarray) -r = r[-250:] # get the most recent 250 trading days +price_data = np.load(datafile).view(np.recarray) +price_data = price_data[-250:] # get the most recent 250 trading days -delta1 = np.diff(r.adj_close)/r.adj_close[:-1] +delta1 = np.diff(price_data.adj_close)/price_data.adj_close[:-1] -# size in points ^2 -volume = (15*r.volume[:-2]/r.volume[0])**2 -close = 0.003*r.close[:-2]/0.003*r.open[:-2] +# Marker size in units of points^2 +volume = (15 * price_data.volume[:-2] / price_data.volume[0])**2 +close = 0.003 * price_data.close[:-2] / 0.003 * price_data.open[:-2] -fig = plt.figure() -ax = fig.add_subplot(111) -ax.scatter(delta1[:-1], delta1[1:], c=close, s=volume, alpha=0.75) - -#ticks = arange(-0.06, 0.061, 0.02) -#xticks(ticks) -#yticks(ticks) +fig, ax = plt.subplots() +ax.scatter(delta1[:-1], delta1[1:], c=close, s=volume, alpha=0.5) ax.set_xlabel(r'$\Delta_i$', fontsize=20) ax.set_ylabel(r'$\Delta_{i+1}$', fontsize=20) ax.set_title('Volume and percent change') + ax.grid(True) +fig.tight_layout() plt.show() - - - diff --git a/examples/pylab_examples/set_and_get.py b/examples/pylab_examples/set_and_get.py index 7ca05540a4b5..45d92095bce9 100644 --- a/examples/pylab_examples/set_and_get.py +++ b/examples/pylab_examples/set_and_get.py @@ -23,7 +23,7 @@ set operates on a single instance or a list of instances. If you are in query mode introspecting the possible values, only the first instance in the sequence is used. When actually setting values, all - the instances will be set. Eg, suppose you have a list of two lines, + the instances will be set. e.g., suppose you have a list of two lines, the following will make both lines thicker and red >>> x = arange(0,1.0,0.01) diff --git a/examples/pylab_examples/show_colormaps.py b/examples/pylab_examples/show_colormaps.py deleted file mode 100644 index 0146a93c07ed..000000000000 --- a/examples/pylab_examples/show_colormaps.py +++ /dev/null @@ -1,25 +0,0 @@ -# This example comes from the Cookbook on www.scipy.org. According to the -# history, Andrew Straw did the conversion from an old page, but it is -# unclear who the original author is. -import numpy as np -import matplotlib.pyplot as plt - -a = np.linspace(0, 1, 256).reshape(1,-1) -a = np.vstack((a,a)) - -# Get a list of the colormaps in matplotlib. Ignore the ones that end with -# '_r' because these are simply reversed versions of ones that don't end -# with '_r' -maps = sorted(m for m in plt.cm.datad if not m.endswith("_r")) -nmaps = len(maps) + 1 - -fig = plt.figure(figsize=(5,10)) -fig.subplots_adjust(top=0.99, bottom=0.01, left=0.2, right=0.99) -for i,m in enumerate(maps): - ax = plt.subplot(nmaps, 1, i+1) - plt.axis("off") - plt.imshow(a, aspect='auto', cmap=plt.get_cmap(m), origin='lower') - pos = list(ax.get_position().bounds) - fig.text(pos[0] - 0.01, pos[1], m, fontsize=10, horizontalalignment='right') - -plt.show() diff --git a/examples/pylab_examples/simple_plot.py b/examples/pylab_examples/simple_plot.py index 972a6d78a6e3..157e6e4851aa 100644 --- a/examples/pylab_examples/simple_plot.py +++ b/examples/pylab_examples/simple_plot.py @@ -2,7 +2,7 @@ t = arange(0.0, 2.0, 0.01) s = sin(2*pi*t) -plot(t, s, linewidth=1.0) +plot(t, s) xlabel('time (s)') ylabel('voltage (mV)') diff --git a/examples/pylab_examples/spine_placement_demo.py b/examples/pylab_examples/spine_placement_demo.py index 2e80f68f7601..42f925371c43 100644 --- a/examples/pylab_examples/spine_placement_demo.py +++ b/examples/pylab_examples/spine_placement_demo.py @@ -1,31 +1,6 @@ -import sys -import matplotlib.pyplot as plt import numpy as np -from matplotlib.pyplot import show - -fig = plt.figure() -x = np.linspace(0,2*np.pi,100) -y = 2*np.sin(x) -ax = fig.add_subplot(1,2,1) -ax.set_title('dropped spines') -ax.plot(x,y) -for loc, spine in ax.spines.items(): - if loc in ['left','bottom']: - spine.set_position(('outward',10)) # outward by 10 points - elif loc in ['right','top']: - spine.set_color('none') # don't draw spine - else: - raise ValueError('unknown spine location: %s'%loc) - -# turn off ticks where there is no spine -ax.xaxis.set_ticks_position('bottom') -ax.yaxis.set_ticks_position('left') - -ax = fig.add_subplot(1,2,2,sharex=ax) -ax.plot(x,y) -ax.set_title('normal spines') +import matplotlib.pyplot as plt -# ---------------------------------------------------- fig = plt.figure() x = np.linspace(-np.pi,np.pi,100) @@ -122,40 +97,4 @@ def adjust_spines(ax,spines): ax.plot(x,y) adjust_spines(ax,['bottom']) -# ---------------------------------------------------- - -fig = plt.figure() - -x = np.linspace(0,2*np.pi,50) -y = np.sin(x) -y2 = y + 0.1*np.random.normal( size=x.shape ) - -# plot data -ax = fig.add_subplot(1,1,1) -line1,=ax.plot(x,y,'--') -line2,=ax.plot(x,y2,'bo') - -# adjust the spines -adjust_spines(ax,['left','bottom']) - -# set ticks and tick labels -# x -ax.set_xlim((0,2*np.pi)) -ax.set_xticks([0,np.pi,2*np.pi]) -if sys.version_info[0] < 3: - pichr = unichr(0x03C0) -else: - pichr = chr(0x03C0) -ax.set_xticklabels(['0',pichr,'2 '+pichr]) - -# y -ax.set_yticks([-1,0,1]) - -# disable clipping of data points by axes range -for artist in (line1,line2): - artist.set_clip_on(False) - -# adjust spine to be within ticks -ax.spines['left'].set_bounds( -1, 1 ) - -show() +plt.show() diff --git a/examples/pylab_examples/stackplot_demo.py b/examples/pylab_examples/stackplot_demo.py index 0148dd8430a9..63eafc15a500 100644 --- a/examples/pylab_examples/stackplot_demo.py +++ b/examples/pylab_examples/stackplot_demo.py @@ -7,12 +7,10 @@ y1, y2, y3 = fnx(), fnx(), fnx() -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.stackplot(x, y) plt.show() -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.stackplot(x, y1, y2, y3) plt.show() diff --git a/examples/pylab_examples/stackplot_demo2.py b/examples/pylab_examples/stackplot_demo2.py new file mode 100644 index 000000000000..f3b2eefcce0c --- /dev/null +++ b/examples/pylab_examples/stackplot_demo2.py @@ -0,0 +1,26 @@ +import numpy as np +import matplotlib.pyplot as plt + +np.random.seed(0) +def layers(n, m): + """ + Return *n* random Gaussian mixtures, each of length *m*. + """ + def bump(a): + x = 1 / (.1 + np.random.random()) + y = 2 * np.random.random() - .5 + z = 10 / (.1 + np.random.random()) + for i in range(m): + w = (i / float(m) - y) * z + a[i] += x * np.exp(-w * w) + a = np.zeros((m, n)) + for i in range(n): + for j in range(5): + bump(a[:, i]) + return a + +d = layers(3, 100) + +plt.subplots() +plt.stackplot(range(100), d.T, baseline='wiggle') +plt.show() diff --git a/examples/pylab_examples/stock_demo.py b/examples/pylab_examples/stock_demo.py index 6c2aec82d709..e95b3391ec7c 100644 --- a/examples/pylab_examples/stock_demo.py +++ b/examples/pylab_examples/stock_demo.py @@ -6,7 +6,7 @@ d1, p1, d2, p2 = get_two_stock_data() -ax = subplot(111) +fig, ax = subplots() lines = plot(d1, p1, 'bs', d2, p2, 'go') xlabel('Days') ylabel('Normalized price') diff --git a/examples/pylab_examples/streamplot_demo.py b/examples/pylab_examples/streamplot_demo.py deleted file mode 100644 index f67e3515c908..000000000000 --- a/examples/pylab_examples/streamplot_demo.py +++ /dev/null @@ -1,19 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -Y, X = np.mgrid[-3:3:100j, -3:3:100j] -U = -1 - X**2 + Y -V = 1 + X - Y**2 -speed = np.sqrt(U*U + V*V) - -plt.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=plt.cm.autumn) -plt.colorbar() - -f, (ax1, ax2) = plt.subplots(ncols=2) -ax1.streamplot(X, Y, U, V, density=[0.5, 1]) - -lw = 5*speed/speed.max() -ax2.streamplot(X, Y, U, V, density=0.6, color='k', linewidth=lw) - -plt.show() - diff --git a/examples/pylab_examples/streamplot_with_mask.py b/examples/pylab_examples/streamplot_with_mask.py deleted file mode 100644 index c989b0060620..000000000000 --- a/examples/pylab_examples/streamplot_with_mask.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Demonstrate the use of the `streamplot` function using a masked array -and NaN values. -""" -import numpy as np -import matplotlib.pyplot as plt - -w = 3 -Y, X = np.mgrid[-w:w:100j, -w:w:100j] -U = -1 - X**2 + Y -V = 1 + X - Y**2 -speed = np.sqrt(U*U + V*V) - -mask = np.zeros(U.shape, dtype=bool) -mask[40:60, 40:60] = 1 -U = np.ma.array(U, mask=mask) -U[:20, :20] = np.nan - -plt.streamplot(X, Y, U, V, color='r') -plt.imshow(~mask, extent=(-w, w, -w, w), alpha=0.5, interpolation='nearest') - -plt.show() - diff --git a/examples/pylab_examples/subplot_demo.py b/examples/pylab_examples/subplot_demo.py index 509b7f1db2b8..6e9598eab725 100644 --- a/examples/pylab_examples/subplot_demo.py +++ b/examples/pylab_examples/subplot_demo.py @@ -1,25 +1,24 @@ -#!/usr/bin/env python -from pylab import * +""" +Simple demo with multiple subplots. +""" +import numpy as np +import matplotlib.pyplot as plt -def f(t): - s1 = cos(2*pi*t) - e1 = exp(-t) - return multiply(s1,e1) -t1 = arange(0.0, 5.0, 0.1) -t2 = arange(0.0, 5.0, 0.02) -t3 = arange(0.0, 2.0, 0.01) +x1 = np.linspace(0.0, 5.0) +x2 = np.linspace(0.0, 2.0) -subplot(211) -l = plot(t1, f(t1), 'bo', t2, f(t2), 'k--', markerfacecolor='green') -grid(True) -title('A tale of 2 subplots') -ylabel('Damped oscillation') +y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) +y2 = np.cos(2 * np.pi * x2) -subplot(212) -plot(t3, cos(2*pi*t3), 'r.') -grid(True) -xlabel('time (s)') -ylabel('Undamped') -show() +plt.subplot(2, 1, 1) +plt.plot(x1, y1, 'ko-') +plt.title('A tale of 2 subplots') +plt.ylabel('Damped oscillation') +plt.subplot(2, 1, 2) +plt.plot(x2, y2, 'r.-') +plt.xlabel('time (s)') +plt.ylabel('Undamped') + +plt.show() diff --git a/examples/pylab_examples/system_monitor.py b/examples/pylab_examples/system_monitor.py index 4a20679a0e27..76b0b965f0c6 100644 --- a/examples/pylab_examples/system_monitor.py +++ b/examples/pylab_examples/system_monitor.py @@ -22,8 +22,7 @@ def get_stats(): # interactive mode, you'll need to use a GUI event handler/timer. ion() -fig = figure(1) -ax = subplot(111) +fig, ax = plt.subplots() ind = arange(1,4) pm, pc, pn = bar(ind, get_stats()) centers = ind + 0.5*pm.get_width() diff --git a/examples/pylab_examples/table_demo.py b/examples/pylab_examples/table_demo.py index a4495fb97174..8e80056c347d 100644 --- a/examples/pylab_examples/table_demo.py +++ b/examples/pylab_examples/table_demo.py @@ -1,57 +1,9 @@ -#!/usr/bin/env python -import matplotlib +""" +Demo of table function to display a table within a plot. +""" +import numpy as np +import matplotlib.pyplot as plt -from pylab import * -from matplotlib.colors import colorConverter - - -#Some simple functions to generate colours. -def pastel(colour, weight=2.4): - """ Convert colour into a nice pastel shade""" - rgb = asarray(colorConverter.to_rgb(colour)) - # scale colour - maxc = max(rgb) - if maxc < 1.0 and maxc > 0: - # scale colour - scale = 1.0 / maxc - rgb = rgb * scale - # now decrease saturation - total = sum(rgb) - slack = 0 - for x in rgb: - slack += 1.0 - x - - # want to increase weight from total to weight - # pick x s.t. slack * x == weight - total - # x = (weight - total) / slack - x = (weight - total) / slack - - rgb = [c + (x * (1.0-c)) for c in rgb] - - return rgb - -def get_colours(n): - """ Return n pastel colours. """ - base = asarray([[1,0,0], [0,1,0], [0,0,1]]) - - if n <= 3: - return base[0:n] - - # how many new colours to we need to insert between - # red and green and between green and blue? - needed = (((n - 3) + 1) / 2, (n - 3) / 2) - - colours = [] - for start in (0, 1): - for x in linspace(0, 1, needed[start]+2): - colours.append((base[start] * (1.0 - x)) + - (base[start+1] * x)) - - return [pastel(c) for c in colours[0:n]] - - - -axes([0.2, 0.2, 0.7, 0.6]) # leave room below the axes for the table data = [[ 66386, 174296, 75131, 577908, 32015], [ 58230, 381139, 78045, 99308, 160454], @@ -59,34 +11,45 @@ def get_colours(n): [ 78415, 81858, 150656, 193263, 69638], [ 139361, 331509, 343164, 781380, 52269]] -colLabels = ('Freeze', 'Wind', 'Flood', 'Quake', 'Hail') -rowLabels = ['%d year' % x for x in (100, 50, 20, 10, 5)] +columns = ('Freeze', 'Wind', 'Flood', 'Quake', 'Hail') +rows = ['%d year' % x for x in (100, 50, 20, 10, 5)] + +values = np.arange(0, 2500, 500) +value_increment = 1000 -# Get some pastel shades for the colours -colours = get_colours(len(colLabels)) -colours.reverse() -rows = len(data) +# Get some pastel shades for the colors +colors = plt.cm.BuPu(np.linspace(0, 0.5, len(columns))) +n_rows = len(data) -ind = arange(len(colLabels)) + 0.3 # the x locations for the groups -cellText = [] -width = 0.4 # the width of the bars -yoff = array([0.0] * len(colLabels)) # the bottom values for stacked bar chart -for row in range(rows): - bar(ind, data[row], width, bottom=yoff, color=colours[row]) - yoff = yoff + data[row] - cellText.append(['%1.1f' % (x/1000.0) for x in yoff]) +index = np.arange(len(columns)) + 0.3 +bar_width = 0.4 + +# Initialize the vertical-offset for the stacked bar chart. +y_offset = np.array([0.0] * len(columns)) + +# Plot bars and create text labels for the table +cell_text = [] +for row in range(n_rows): + plt.bar(index, data[row], bar_width, bottom=y_offset, color=colors[row]) + y_offset = y_offset + data[row] + cell_text.append(['%1.1f' % (x/1000.0) for x in y_offset]) +# Reverse colors and text labels to display the last value at the top. +colors = colors[::-1] +cell_text.reverse() # Add a table at the bottom of the axes -colours.reverse() -cellText.reverse() -the_table = table(cellText=cellText, - rowLabels=rowLabels, rowColours=colours, - colLabels=colLabels, - loc='bottom') -ylabel("Loss $1000's") -vals = arange(0, 2500, 500) -yticks(vals*1000, ['%d' % val for val in vals]) -xticks([]) -title('Loss by Disaster') +the_table = plt.table(cellText=cell_text, + rowLabels=rows, + rowColours=colors, + colLabels=columns, + loc='bottom') + +# Adjust layout to make room for the table: +plt.subplots_adjust(left=0.2, bottom=0.2) + +plt.ylabel("Loss in ${0}'s".format(value_increment)) +plt.yticks(values * value_increment, ['%d' % val for val in values]) +plt.xticks([]) +plt.title('Loss by Disaster') -show() +plt.show() diff --git a/examples/pylab_examples/tex_demo.py b/examples/pylab_examples/tex_demo.py index 64e10386e3b6..c9963d4b4506 100644 --- a/examples/pylab_examples/tex_demo.py +++ b/examples/pylab_examples/tex_demo.py @@ -1,33 +1,30 @@ -#!/usr/bin/env python """ You can use TeX to render all of your matplotlib text if the rc parameter text.usetex is set. This works currently on the agg and ps backends, and requires that you have tex and the other dependencies -described at http://matplotlib.sf.net/matplotlib.texmanager.html +described at http://matplotlib.org/users/usetex.html properly installed on your system. The first time you run a script you will see a lot of output from tex and associated tools. The next time, the run may be silent, as a lot of the information is cached in ~/.tex.cache """ -from matplotlib import rc -from numpy import arange, cos, pi -from matplotlib.pyplot import figure, axes, plot, xlabel, ylabel, title, \ - grid, savefig, show +import numpy as np +import matplotlib.pyplot as plt -rc('text', usetex=True) -rc('font', family='serif') -figure(1, figsize=(6,4)) -ax = axes([0.1, 0.1, 0.8, 0.7]) -t = arange(0.0, 1.0+0.01, 0.01) -s = cos(2*2*pi*t)+2 -plot(t, s) +plt.rc('text', usetex=True) +plt.rc('font', family='serif') +plt.figure(1, figsize=(6,4)) +ax = plt.axes([0.1, 0.1, 0.8, 0.7]) +t = np.linspace(0.0, 1.0, 100) +s = np.cos(4 * np.pi * t) + 2 +plt.plot(t, s) -xlabel(r'\textbf{time (s)}') -ylabel(r'\textit{voltage (mV)}',fontsize=16) -title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='r') -grid(True) -savefig('tex_demo') -show() +plt.xlabel(r'\textbf{time (s)}') +plt.ylabel(r'\textit{voltage (mV)}',fontsize=16) +plt.title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty" + r"\frac{-e^{i\pi}}{2^n}$!", fontsize=16, color='r') +plt.grid(True) +plt.savefig('tex_demo') +plt.show() diff --git a/examples/pylab_examples/text_handles.py b/examples/pylab_examples/text_handles.py index bd4bb2d0b9ca..2a1a21fae8e0 100644 --- a/examples/pylab_examples/text_handles.py +++ b/examples/pylab_examples/text_handles.py @@ -17,7 +17,7 @@ def f(t): t2 = arange(0.0, 5.0, 0.02) -subplot(111) +fig, ax = plt.subplots() plot(t1, f(t1), 'bo', t2, f(t2), 'k') text(3.0, 0.6, 'f(t) = exp(-t) sin(2 pi t)') ttext = title('Fun with text!') diff --git a/examples/pylab_examples/text_themes.py b/examples/pylab_examples/text_themes.py deleted file mode 100644 index 43dfc39064f8..000000000000 --- a/examples/pylab_examples/text_themes.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -from pylab import * - -font = {'family' : 'serif', - 'color' : 'r', - 'weight' : 'normal', - 'size' : 12, - } - -def f(t): - s1 = cos(2*pi*t) - e1 = exp(-t) - return multiply(s1,e1) - -t1 = arange(0.0, 5.0, 0.1) -t2 = arange(0.0, 5.0, 0.02) - -plot(t1, f(t1), 'bo', t2, f(t2), 'k') -title('Damped exponential decay', font, size='large', color='r') -text(2, 0.65, r'$\cos(2 \pi t) \exp(-t)$', color='k') -xlabel('time (s)', font, style='italic') -ylabel('voltage (mV)', font) - -show() diff --git a/examples/pylab_examples/titles_demo.py b/examples/pylab_examples/titles_demo.py new file mode 100644 index 000000000000..ae132be59f9d --- /dev/null +++ b/examples/pylab_examples/titles_demo.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +""" +matplotlib can display plot titles centered, flush with the left side of +a set of axes, and flush with the right side of a set of axes. + +""" +import matplotlib.pyplot as plt + +plt.plot(range(10)) + +plt.title('Center Title') +plt.title('Left Title', loc='left') +plt.title('Right Title', loc='right') + +plt.show() diff --git a/examples/pylab_examples/to_numeric.py b/examples/pylab_examples/to_numeric.py old mode 100644 new mode 100755 index 5db1e7c3305c..bb30bf73f00b --- a/examples/pylab_examples/to_numeric.py +++ b/examples/pylab_examples/to_numeric.py @@ -30,5 +30,7 @@ X.shape = h, w, 3 im = Image.fromstring( "RGB", (w,h), s) -im.show() +# Uncomment this line to display the image using ImageMagick's +# `display` tool. +# im.show() diff --git a/examples/pylab_examples/tricontour_smooth_delaunay.py b/examples/pylab_examples/tricontour_smooth_delaunay.py new file mode 100644 index 000000000000..27b2695b2b05 --- /dev/null +++ b/examples/pylab_examples/tricontour_smooth_delaunay.py @@ -0,0 +1,133 @@ +""" +Demonstrates high-resolution tricontouring of a random set of points ; +a matplotlib.tri.TriAnalyzer is used to improve the plot quality. + +The initial data points and triangular grid for this demo are: + - a set of random points is instantiated, inside [-1, 1] x [-1, 1] square + - A Delaunay triangulation of these points is then computed, of which a + random subset of triangles is masked out by the user (based on + *init_mask_frac* parameter). This simulates invalidated data. + +The proposed generic procedure to obtain a high resolution contouring of such +a data set is the following: + 1) Compute an extended mask with a matplotlib.tri.TriAnalyzer, which will + exclude badly shaped (flat) triangles from the border of the + triangulation. Apply the mask to the triangulation (using set_mask). + 2) Refine and interpolate the data using a + matplotlib.tri.UniformTriRefiner. + 3) Plot the refined data with tricontour. + +""" +from matplotlib.tri import Triangulation, TriAnalyzer, UniformTriRefiner +import matplotlib.pyplot as plt +import matplotlib.cm as cm +import numpy as np + + +#----------------------------------------------------------------------------- +# Analytical test function +#----------------------------------------------------------------------------- +def experiment_res(x, y): + """ An analytic function representing experiment results """ + x = 2.*x + r1 = np.sqrt((0.5-x)**2 + (0.5-y)**2) + theta1 = np.arctan2(0.5-x, 0.5-y) + r2 = np.sqrt((-x-0.2)**2 + (-y-0.2)**2) + theta2 = np.arctan2(-x-0.2, -y-0.2) + z = (4*(np.exp((r1/10)**2)-1)*30. * np.cos(3*theta1) + + (np.exp((r2/10)**2)-1)*30. * np.cos(5*theta2) + + 2*(x**2 + y**2)) + return (np.max(z)-z)/(np.max(z)-np.min(z)) + +#----------------------------------------------------------------------------- +# Generating the initial data test points and triangulation for the demo +#----------------------------------------------------------------------------- +# User parameters for data test points +n_test = 200 # Number of test data points, tested from 3 to 5000 for subdiv=3 + +subdiv = 3 # Number of recursive subdivisions of the initial mesh for smooth + # plots. Values >3 might result in a very high number of triangles + # for the refine mesh: new triangles numbering = (4**subdiv)*ntri + +init_mask_frac = 0.0 # Float > 0. adjusting the proportion of + # (invalid) initial triangles which will be masked + # out. Enter 0 for no mask. + +min_circle_ratio = .01 # Minimum circle ratio - border triangles with circle + # ratio below this will be masked if they touch a + # border. Suggested value 0.01 ; Use -1 to keep + # all triangles. + +# Random points +random_gen = np.random.mtrand.RandomState(seed=127260) +x_test = random_gen.uniform(-1., 1., size=n_test) +y_test = random_gen.uniform(-1., 1., size=n_test) +z_test = experiment_res(x_test, y_test) + +# meshing with Delaunay triangulation +tri = Triangulation(x_test, y_test) +ntri = tri.triangles.shape[0] + +# Some invalid data are masked out +mask_init = np.zeros(ntri, dtype=np.bool) +masked_tri = random_gen.randint(0, ntri, int(ntri*init_mask_frac)) +mask_init[masked_tri] = True +tri.set_mask(mask_init) + + +#----------------------------------------------------------------------------- +# Improving the triangulation before high-res plots: removing flat triangles +#----------------------------------------------------------------------------- +# masking badly shaped triangles at the border of the triangular mesh. +mask = TriAnalyzer(tri).get_flat_tri_mask(min_circle_ratio) +tri.set_mask(mask) + +# refining the data +refiner = UniformTriRefiner(tri) +tri_refi, z_test_refi = refiner.refine_field(z_test, subdiv=subdiv) + +# analytical 'results' for comparison +z_expected = experiment_res(tri_refi.x, tri_refi.y) + +# for the demo: loading the 'flat' triangles for plot +flat_tri = Triangulation(x_test, y_test) +flat_tri.set_mask(~mask) + + +#----------------------------------------------------------------------------- +# Now the plots +#----------------------------------------------------------------------------- +# User options for plots +plot_tri = True # plot of the base triangulation +plot_masked_tri = True # plot of the excessively flat excluded triangles +plot_refi_tri = False # plot of the refined triangulation +plot_expected = False # plot of the analytical function values for comparison + + +# Graphical options for tricontouring +levels = np.arange(0., 1., 0.025) +cmap = cm.get_cmap(name='Blues', lut=None) + +plt.figure() +plt.gca().set_aspect('equal') +plt.title("Filtering a Delaunay mesh\n" + + "(application to high-resolution tricontouring)") + +# 1) plot of the refined (computed) data countours: +plt.tricontour(tri_refi, z_test_refi, levels=levels, cmap=cmap, + linewidths=[2.0, 0.5, 1.0, 0.5]) +# 2) plot of the expected (analytical) data countours (dashed): +if plot_expected: + plt.tricontour(tri_refi, z_expected, levels=levels, cmap=cmap, + linestyles='--') +# 3) plot of the fine mesh on which interpolation was done: +if plot_refi_tri: + plt.triplot(tri_refi, color='0.97') +# 4) plot of the initial 'coarse' mesh: +if plot_tri: + plt.triplot(tri, color='0.7') +# 4) plot of the unvalidated triangles from naive Delaunay Triangulation: +if plot_masked_tri: + plt.triplot(flat_tri, color='red') + +plt.show() diff --git a/examples/pylab_examples/tricontour_smooth_user.py b/examples/pylab_examples/tricontour_smooth_user.py new file mode 100644 index 000000000000..33551956aa2b --- /dev/null +++ b/examples/pylab_examples/tricontour_smooth_user.py @@ -0,0 +1,76 @@ +""" +Demonstrates high-resolution tricontouring on user-defined triangular grids +with matplotlib.tri.UniformTriRefiner +""" +from matplotlib.tri import Triangulation, UniformTriRefiner +import matplotlib.pyplot as plt +import matplotlib.cm as cm +import numpy as np +import math + + +#----------------------------------------------------------------------------- +# Analytical test function +#----------------------------------------------------------------------------- +def function_z(x, y): + """ A function of 2 variables """ + r1 = np.sqrt((0.5-x)**2 + (0.5-y)**2) + theta1 = np.arctan2(0.5-x, 0.5-y) + r2 = np.sqrt((-x-0.2)**2 + (-y-0.2)**2) + theta2 = np.arctan2(-x-0.2, -y-0.2) + z = -(2*(np.exp((r1/10)**2)-1)*30. * np.cos(7.*theta1) + + (np.exp((r2/10)**2)-1)*30. * np.cos(11.*theta2) + + 0.7*(x**2 + y**2)) + return (np.max(z)-z)/(np.max(z)-np.min(z)) + +#----------------------------------------------------------------------------- +# Creating a Triangulation +#----------------------------------------------------------------------------- +# First create the x and y coordinates of the points. +n_angles = 20 +n_radii = 10 +min_radius = 0.15 +radii = np.linspace(min_radius, 0.95, n_radii) + +angles = np.linspace(0, 2*math.pi, n_angles, endpoint=False) +angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1) +angles[:, 1::2] += math.pi/n_angles + +x = (radii*np.cos(angles)).flatten() +y = (radii*np.sin(angles)).flatten() +z = function_z(x, y) + +# Now create the Triangulation. +# (Creating a Triangulation without specifying the triangles results in the +# Delaunay triangulation of the points.) +triang = Triangulation(x, y) + +# Mask off unwanted triangles. +xmid = x[triang.triangles].mean(axis=1) +ymid = y[triang.triangles].mean(axis=1) +mask = np.where(xmid*xmid + ymid*ymid < min_radius*min_radius, 1, 0) +triang.set_mask(mask) + +#----------------------------------------------------------------------------- +# Refine data +#----------------------------------------------------------------------------- +refiner = UniformTriRefiner(triang) +tri_refi, z_test_refi = refiner.refine_field(z, subdiv=3) + +#----------------------------------------------------------------------------- +# Plot the triangulation and the high-res iso-contours +#----------------------------------------------------------------------------- +plt.figure() +plt.gca().set_aspect('equal') +plt.triplot(triang, lw=0.5, color='white') + +levels = np.arange(0., 1., 0.025) +cmap = cm.get_cmap(name='terrain', lut=None) +plt.tricontourf(tri_refi, z_test_refi, levels=levels, cmap=cmap) +plt.tricontour(tri_refi, z_test_refi, levels=levels, + colors=['0.25', '0.5', '0.5', '0.5', '0.5'], + linewidths=[1.0, 0.5, 0.5, 0.5, 0.5]) + +plt.title("High-resolution tricontouring") + +plt.show() diff --git a/examples/pylab_examples/trigradient_demo.py b/examples/pylab_examples/trigradient_demo.py new file mode 100644 index 000000000000..c8967b5397be --- /dev/null +++ b/examples/pylab_examples/trigradient_demo.py @@ -0,0 +1,81 @@ +""" +Demonstrates computation of gradient with matplotlib.tri.CubicTriInterpolator. +""" +from matplotlib.tri import Triangulation, UniformTriRefiner,\ + CubicTriInterpolator +import matplotlib.pyplot as plt +import matplotlib.cm as cm +import numpy as np +import math + + +#----------------------------------------------------------------------------- +# Electrical potential of a dipole +#----------------------------------------------------------------------------- +def dipole_potential(x, y): + """ The electric dipole potential V """ + r_sq = x**2 + y**2 + theta = np.arctan2(y, x) + z = np.cos(theta)/r_sq + return (np.max(z)-z) / (np.max(z)-np.min(z)) + + +#----------------------------------------------------------------------------- +# Creating a Triangulation +#----------------------------------------------------------------------------- +# First create the x and y coordinates of the points. +n_angles = 30 +n_radii = 10 +min_radius = 0.2 +radii = np.linspace(min_radius, 0.95, n_radii) + +angles = np.linspace(0, 2*math.pi, n_angles, endpoint=False) +angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1) +angles[:, 1::2] += math.pi/n_angles + +x = (radii*np.cos(angles)).flatten() +y = (radii*np.sin(angles)).flatten() +V = dipole_potential(x, y) + +# Create the Triangulation; no triangles specified so Delaunay triangulation +# created. +triang = Triangulation(x, y) + +# Mask off unwanted triangles. +xmid = x[triang.triangles].mean(axis=1) +ymid = y[triang.triangles].mean(axis=1) +mask = np.where(xmid*xmid + ymid*ymid < min_radius*min_radius, 1, 0) +triang.set_mask(mask) + +#----------------------------------------------------------------------------- +# Refine data - interpolates the electrical potential V +#----------------------------------------------------------------------------- +refiner = UniformTriRefiner(triang) +tri_refi, z_test_refi = refiner.refine_field(V, subdiv=3) + +#----------------------------------------------------------------------------- +# Computes the electrical field (Ex, Ey) as gradient of electrical potential +#----------------------------------------------------------------------------- +tci = CubicTriInterpolator(triang, -V) +# Gradient requested here at the mesh nodes but could be anywhere else: +(Ex, Ey) = tci.gradient(triang.x, triang.y) +E_norm = np.sqrt(Ex**2 + Ey**2) + +#----------------------------------------------------------------------------- +# Plot the triangulation, the potential iso-contours and the vector field +#----------------------------------------------------------------------------- +plt.figure() +plt.gca().set_aspect('equal') +plt.triplot(triang, color='0.8') + +levels = np.arange(0., 1., 0.01) +cmap = cm.get_cmap(name='hot', lut=None) +plt.tricontour(tri_refi, z_test_refi, levels=levels, cmap=cmap, + linewidths=[2.0, 1.0, 1.0, 1.0]) +# Plots direction of the electrical vector field +plt.quiver(triang.x, triang.y, Ex/E_norm, Ey/E_norm, + units='xy', scale=10., zorder=3, color='blue', + width=0.007, headwidth=3., headlength=4.) + +plt.title('Gradient plot: an electrical dipole') +plt.show() diff --git a/examples/pylab_examples/triinterp_demo.py b/examples/pylab_examples/triinterp_demo.py new file mode 100644 index 000000000000..70fac4ebf568 --- /dev/null +++ b/examples/pylab_examples/triinterp_demo.py @@ -0,0 +1,57 @@ +""" +Interpolation from triangular grid to quad grid. +""" +import matplotlib.pyplot as plt +import matplotlib.tri as mtri +import numpy as np + +# Create triangulation. +x = np.asarray([0, 1, 2, 3, 0.5, 1.5, 2.5, 1, 2, 1.5]) +y = np.asarray([0, 0, 0, 0, 1.0, 1.0, 1.0, 2, 2, 3.0]) +triangles = [[0, 1, 4], [1, 2, 5], [2, 3, 6], [1, 5, 4], [2, 6, 5], [4, 5, 7], + [5, 6, 8], [5, 8, 7], [7, 8, 9]] +triang = mtri.Triangulation(x, y, triangles) + +# Interpolate to regularly-spaced quad grid. +z = np.cos(1.5*x)*np.cos(1.5*y) +xi, yi = np.meshgrid(np.linspace(0, 3, 20), np.linspace(0, 3, 20)) + +interp_lin = mtri.LinearTriInterpolator(triang, z) +zi_lin = interp_lin(xi, yi) + +interp_cubic_geom = mtri.CubicTriInterpolator(triang, z, kind='geom') +zi_cubic_geom = interp_cubic_geom(xi, yi) + +interp_cubic_min_E = mtri.CubicTriInterpolator(triang, z, kind='min_E') +zi_cubic_min_E = interp_cubic_min_E(xi, yi) + + +# Plot the triangulation. +plt.subplot(221) +plt.tricontourf(triang, z) +plt.triplot(triang, 'ko-') +plt.title('Triangular grid') + +# Plot linear interpolation to quad grid. +plt.subplot(222) +plt.contourf(xi, yi, zi_lin) +plt.plot(xi, yi, 'k-', alpha=0.5) +plt.plot(xi.T, yi.T, 'k-', alpha=0.5) +plt.title("Linear interpolation") + +# Plot cubic interpolation to quad grid, kind=geom +plt.subplot(223) +plt.contourf(xi, yi, zi_cubic_geom) +plt.plot(xi, yi, 'k-', alpha=0.5) +plt.plot(xi.T, yi.T, 'k-', alpha=0.5) +plt.title("Cubic interpolation,\nkind='geom'") + +# Plot cubic interpolation to quad grid, kind=min_E +plt.subplot(224) +plt.contourf(xi, yi, zi_cubic_min_E) +plt.plot(xi, yi, 'k-', alpha=0.5) +plt.plot(xi.T, yi.T, 'k-', alpha=0.5) +plt.title("Cubic interpolation,\nkind='min_E'") + +plt.tight_layout() +plt.show() diff --git a/examples/pylab_examples/unicode_demo.py b/examples/pylab_examples/unicode_demo.py deleted file mode 100755 index bba623482a26..000000000000 --- a/examples/pylab_examples/unicode_demo.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -import pylab - -pylab.plot([1, 2, 4]) -pylab.title('Développés et fabriqués') -pylab.xlabel("réactivité nous permettent d'être sélectionnés et adoptés") -pylab.ylabel('André was here!') -pylab.text( 0.5, 2.5, 'Institut für Festkörperphysik', rotation=45) -pylab.text( 1, 1.5, 'AVA (check kerning)') - -pylab.show() diff --git a/examples/pylab_examples/vertical_ticklabels.py b/examples/pylab_examples/vertical_ticklabels.py deleted file mode 100644 index 2416a785bfc1..000000000000 --- a/examples/pylab_examples/vertical_ticklabels.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -from pylab import * - -plot([1,2,3,4], [1,4,9,16]) -locs, labels = xticks([1,2,3,4], ['Frogs', 'Hogs', 'Bogs', 'Slogs']) -setp(labels, 'rotation', 'vertical') -show() diff --git a/examples/pylab_examples/vline_demo.py b/examples/pylab_examples/vline_demo.py deleted file mode 100644 index 98b512f50aec..000000000000 --- a/examples/pylab_examples/vline_demo.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python -from matplotlib.pyplot import * -from numpy import sin, exp, absolute, pi, arange -from numpy.random import normal - -def f(t): - s1 = sin(2*pi*t) - e1 = exp(-t) - return absolute((s1*e1))+.05 - - -t = arange(0.0, 5.0, 0.1) -s = f(t) -nse = normal(0.0, 0.3, t.shape) * s - -plot(t, s+nse, 'b^') -vlines(t, [0], s) -xlabel('time (s)') -title('Comparison of model with data') -show() - diff --git a/examples/pylab_examples/vline_hline_demo.py b/examples/pylab_examples/vline_hline_demo.py new file mode 100644 index 000000000000..fe85582a527d --- /dev/null +++ b/examples/pylab_examples/vline_hline_demo.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +""" +Small demonstration of the hlines and vlines plots. +""" + +from matplotlib import pyplot as plt +from numpy import sin, exp, absolute, pi, arange +from numpy.random import normal + + +def f(t): + s1 = sin(2 * pi * t) + e1 = exp(-t) + return absolute((s1 * e1)) + .05 + + +t = arange(0.0, 5.0, 0.1) +s = f(t) +nse = normal(0.0, 0.3, t.shape) * s + +fig = plt.figure(figsize=(12, 6)) +vax = fig.add_subplot(121) +hax = fig.add_subplot(122) + +vax.plot(t, s + nse, 'b^') +vax.vlines(t, [0], s) +vax.set_xlabel('time (s)') +vax.set_title('Vertical lines demo') + +hax.plot(s + nse, t, 'b^') +hax.hlines(t, [0], s, lw=2) +hax.set_xlabel('time (s)') +hax.set_title('Horizontal lines demo') + +plt.show() diff --git a/examples/pylab_examples/webapp_demo.py b/examples/pylab_examples/webapp_demo.py index fb8e3bd8f6a9..ad3702a62bf9 100644 --- a/examples/pylab_examples/webapp_demo.py +++ b/examples/pylab_examples/webapp_demo.py @@ -1,66 +1,59 @@ #!/usr/bin/env python # -*- noplot -*- -# This example shows how to use the agg backend directly to create -# images, which may be of use to web application developers who want -# full control over their code without using the pylab interface to -# manage figures, figure closing etc. -# -# The rc command is used to create per-script default figure -# customizations of the rc parameters; see -# http://matplotlib.sf.net/matplotlibrc . You may prefer to set the -# rc parameters in the rc file itself. Note that you can keep -# directory level default configurations by placing different rc files -# in the directory that the script runs in. -# -# I am making no effort here to make a figure that looks good -- -# rather I am just trying to show the various ways to use matplotlib -# to customize your figure using the matplotlib API +""" +This example shows how to use the agg backend directly to create +images, which may be of use to web application developers who want +full control over their code without using the pyplot interface to +manage figures, figure closing etc. + +.. note:: + + It is not necessary to avoid using the pyplot interface in order to + create figures without a graphical front-end - simply setting + the backend to "Agg" would be sufficient. + + +It is also worth noting that, because matplotlib can save figures to file-like +object, matplotlib can also be used inside a cgi-script *without* needing to +write a figure to disk. + +""" -import matplotlib -matplotlib.use('Agg') # force the antigrain backend -from matplotlib import rc from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.figure import Figure -from matplotlib.cbook import iterable import numpy as np + def make_fig(): """ - make a figure + Make a figure and save it to "webagg.png". - No need to close figures or clean up since the objects will be - destroyed when they go out of scope """ fig = Figure() - #ax = fig.add_subplot(111) # add a standard subplot - - # add an axes at left, bottom, width, height; by making the bottom - # at 0.3, we save some extra room for tick labels - ax = fig.add_axes([0.2, 0.3, 0.7, 0.6]) + ax = fig.add_subplot(1, 1, 1) - line, = ax.plot([1,2,3], 'ro--', markersize=12, markerfacecolor='g') + ax.plot([1, 2, 3], 'ro--', markersize=12, markerfacecolor='g') # make a translucent scatter collection x = np.random.rand(100) y = np.random.rand(100) - area = np.pi*(10 * np.random.rand(100))**2 # 0 to 10 point radiuses - c = ax.scatter(x,y,area) + area = np.pi * (10 * np.random.rand(100)) ** 2 # 0 to 10 point radiuses + c = ax.scatter(x, y, area) c.set_alpha(0.5) # add some text decoration ax.set_title('My first image') ax.set_ylabel('Some numbers') - ax.set_xticks( (.2,.4,.6,.8) ) + ax.set_xticks((.2, .4, .6, .8)) labels = ax.set_xticklabels(('Bill', 'Fred', 'Ted', 'Ed')) # To set object properties, you can either iterate over the # objects manually, or define you own set command, as in setapi # above. - for l in labels: - l.set_rotation(45) - l.set_fontsize(12) + for label in labels: + label.set_rotation(45) + label.set_fontsize(12) - canvas = FigureCanvasAgg(fig) - canvas.print_figure('webapp', dpi=150) + FigureCanvasAgg(fig).print_png('webapp.png', dpi=150) -make_fig() +make_fig() \ No newline at end of file diff --git a/examples/shapes_and_collections/artist_reference.py b/examples/shapes_and_collections/artist_reference.py new file mode 100644 index 000000000000..29c2192dfc50 --- /dev/null +++ b/examples/shapes_and_collections/artist_reference.py @@ -0,0 +1,103 @@ +""" +Reference for matplotlib artists + +This example displays several of matplotlib's graphics primitives (artists) +drawn using matplotlib API. A full list of artists and the documentation is +available at http://matplotlib.org/api/artist_api.html. + +Copyright (c) 2010, Bartosz Telenczuk +BSD License +""" +import matplotlib.pyplot as plt; plt.rcdefaults() + +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.path as mpath +import matplotlib.lines as mlines +import matplotlib.patches as mpatches +from matplotlib.collections import PatchCollection + + +def label(xy, text): + y = xy[1] - 0.15 # shift y-value for label so that it's below the artist + plt.text(xy[0], y, text, ha="center", family='sans-serif', size=14) + + +fig, ax = plt.subplots() +# create 3x3 grid to plot the artists +grid = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1).T + +patches = [] + +# add a circle +circle = mpatches.Circle(grid[0], 0.1,ec="none") +patches.append(circle) +label(grid[0], "Circle") + +# add a rectangle +rect = mpatches.Rectangle(grid[1] - [0.025, 0.05], 0.05, 0.1, ec="none") +patches.append(rect) +label(grid[1], "Rectangle") + +# add a wedge +wedge = mpatches.Wedge(grid[2], 0.1, 30, 270, ec="none") +patches.append(wedge) +label(grid[2], "Wedge") + +# add a Polygon +polygon = mpatches.RegularPolygon(grid[3], 5, 0.1) +patches.append(polygon) +label(grid[3], "Polygon") + +#add an ellipse +ellipse = mpatches.Ellipse(grid[4], 0.2, 0.1) +patches.append(ellipse) +label(grid[4], "Ellipse") + +#add an arrow +arrow = mpatches.Arrow(grid[5, 0]-0.05, grid[5, 1]-0.05, 0.1, 0.1, width=0.1) +patches.append(arrow) +label(grid[5], "Arrow") + +# add a path patch +Path = mpath.Path +path_data = [ + (Path.MOVETO, [ 0.018, -0.11 ]), + (Path.CURVE4, [-0.031, -0.051]), + (Path.CURVE4, [-0.115, 0.073]), + (Path.CURVE4, [-0.03 , 0.073]), + (Path.LINETO, [-0.011, 0.039]), + (Path.CURVE4, [ 0.043, 0.121]), + (Path.CURVE4, [ 0.075, -0.005]), + (Path.CURVE4, [ 0.035, -0.027]), + (Path.CLOSEPOLY, [0.018, -0.11]) + ] +codes, verts = zip(*path_data) +path = mpath.Path(verts + grid[6], codes) +patch = mpatches.PathPatch(path) +patches.append(patch) +label(grid[6], "PathPatch") + +# add a fancy box +fancybox = mpatches.FancyBboxPatch( + grid[7] - [0.025, 0.05], 0.05, 0.1, + boxstyle=mpatches.BoxStyle("Round", pad=0.02)) +patches.append(fancybox) +label(grid[7], "FancyBoxPatch") + +# add a line +x,y = np.array([[-0.06, 0.0, 0.1], [0.05, -0.05, 0.05]]) +line = mlines.Line2D(x + grid[8, 0], y + grid[8, 1], lw=5., alpha=0.3) +label(grid[8], "Line2D") + +colors = np.linspace(0, 1, len(patches)) +collection = PatchCollection(patches, cmap=plt.cm.hsv, alpha=0.3) +collection.set_array(np.array(colors)) +ax.add_collection(collection) +ax.add_line(line) + +plt.subplots_adjust(left=0, right=1, bottom=0, top=1) +plt.axis('equal') +plt.axis('off') + +plt.show() diff --git a/examples/shapes_and_collections/path_patch_demo.py b/examples/shapes_and_collections/path_patch_demo.py new file mode 100644 index 000000000000..fb0c8aa47592 --- /dev/null +++ b/examples/shapes_and_collections/path_patch_demo.py @@ -0,0 +1,34 @@ +""" +Demo of a PathPatch object. +""" +import matplotlib.path as mpath +import matplotlib.patches as mpatches +import matplotlib.pyplot as plt + + +fig, ax = plt.subplots() + +Path = mpath.Path +path_data = [ + (Path.MOVETO, (1.58, -2.57)), + (Path.CURVE4, (0.35, -1.1)), + (Path.CURVE4, (-1.75, 2.0)), + (Path.CURVE4, (0.375, 2.0)), + (Path.LINETO, (0.85, 1.15)), + (Path.CURVE4, (2.2, 3.2)), + (Path.CURVE4, (3, 0.05)), + (Path.CURVE4, (2.0, -0.5)), + (Path.CLOSEPOLY, (1.58, -2.57)), + ] +codes, verts = zip(*path_data) +path = mpath.Path(verts, codes) +patch = mpatches.PathPatch(path, facecolor='r', alpha=0.5) +ax.add_patch(patch) + +# plot control points and connecting lines +x, y = zip(*path.vertices) +line, = ax.plot(x, y, 'go-') + +ax.grid() +ax.axis('equal') +plt.show() diff --git a/examples/shapes_and_collections/scatter_demo.py b/examples/shapes_and_collections/scatter_demo.py new file mode 100644 index 000000000000..317b647ce94c --- /dev/null +++ b/examples/shapes_and_collections/scatter_demo.py @@ -0,0 +1,14 @@ +""" +Simple demo of a scatter plot. +""" +import numpy as np +import matplotlib.pyplot as plt + + +N = 50 +x = np.random.rand(N) +y = np.random.rand(N) +area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radiuses + +plt.scatter(x, y, s=area, alpha=0.5) +plt.show() diff --git a/examples/showcase/integral_demo.py b/examples/showcase/integral_demo.py new file mode 100644 index 000000000000..d55f551fab80 --- /dev/null +++ b/examples/showcase/integral_demo.py @@ -0,0 +1,51 @@ +""" +Plot demonstrating the integral as the area under a curve. + +Although this is a simple example, it demonstrates some important tweaks: + + * A simple line plot with custom color and line width. + * A shaded region created using a Polygon patch. + * A text label with mathtext rendering. + * figtext calls to label the x- and y-axes. + * Use of axis spines to hide the top and right spines. + * Custom tick placement and labels. +""" +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.patches import Polygon + + +def func(x): + return (x - 3) * (x - 5) * (x - 7) + 85 + + +a, b = 2, 9 # integral limits +x = np.linspace(0, 10) +y = func(x) + +fig, ax = plt.subplots() +plt.plot(x, y, 'r', linewidth=2) +plt.ylim(ymin=0) + +# Make the shaded region +ix = np.linspace(a, b) +iy = func(ix) +verts = [(a, 0)] + list(zip(ix, iy)) + [(b, 0)] +poly = Polygon(verts, facecolor='0.9', edgecolor='0.5') +ax.add_patch(poly) + +plt.text(0.5 * (a + b), 30, r"$\int_a^b f(x)\mathrm{d}x$", + horizontalalignment='center', fontsize=20) + +plt.figtext(0.9, 0.05, '$x$') +plt.figtext(0.1, 0.9, '$y$') + +ax.spines['right'].set_visible(False) +ax.spines['top'].set_visible(False) +ax.xaxis.set_ticks_position('bottom') + +ax.set_xticks((a, b)) +ax.set_xticklabels(('$a$', '$b$')) +ax.set_yticks([]) + +plt.show() diff --git a/examples/showcase/xkcd.py b/examples/showcase/xkcd.py new file mode 100644 index 000000000000..5c731c5a1dd2 --- /dev/null +++ b/examples/showcase/xkcd.py @@ -0,0 +1,54 @@ +import matplotlib.pyplot as plt +import numpy as np + +with plt.xkcd(): + # Based on "Stove Ownership" from XKCD by Randall Monroe + # http://xkcd.com/418/ + + fig = plt.figure() + ax = fig.add_axes((0.1, 0.2, 0.8, 0.7)) + ax.spines['right'].set_color('none') + ax.spines['top'].set_color('none') + plt.xticks([]) + plt.yticks([]) + ax.set_ylim([-30, 10]) + + data = np.ones(100) + data[70:] -= np.arange(30) + + plt.annotate( + 'THE DAY I REALIZED\nI COULD COOK BACON\nWHENEVER I WANTED', + xy=(70, 1), arrowprops=dict(arrowstyle='->'), xytext=(15, -10)) + + plt.plot(data) + + plt.xlabel('time') + plt.ylabel('my overall health') + fig.text( + 0.5, 0.05, + '"Stove Ownership" from xkcd by Randall Monroe', + ha='center') + + # Based on "The Data So Far" from XKCD by Randall Monroe + # http://xkcd.com/373/ + + fig = plt.figure() + ax = fig.add_axes((0.1, 0.2, 0.8, 0.7)) + ax.bar([-0.125, 1.0-0.125], [0, 100], 0.25) + ax.spines['right'].set_color('none') + ax.spines['top'].set_color('none') + ax.xaxis.set_ticks_position('bottom') + ax.set_xticks([0, 1]) + ax.set_xlim([-0.5, 1.5]) + ax.set_ylim([0, 110]) + ax.set_xticklabels(['CONFIRMED BY\nEXPERIMENT', 'REFUTED BY\nEXPERIMENT']) + plt.yticks([]) + + plt.title("CLAIMS OF SUPERNATURAL POWERS") + + fig.text( + 0.5, 0.05, + '"The Data So Far" from xkcd by Randall Monroe', + ha='center') + +plt.show() diff --git a/examples/specialty_plots/hinton_demo.py b/examples/specialty_plots/hinton_demo.py new file mode 100644 index 000000000000..201b321283c1 --- /dev/null +++ b/examples/specialty_plots/hinton_demo.py @@ -0,0 +1,41 @@ +""" +Demo of a function to create Hinton diagrams. + +Hinton diagrams are useful for visualizing the values of a 2D array (e.g. +a weight matrix): Positive and negative values are represented by white and +black squares, respectively, and the size of each square represents the +magnitude of each value. + +Initial idea from David Warde-Farley on the SciPy Cookbook +""" +import numpy as np +import matplotlib.pyplot as plt + + +def hinton(matrix, max_weight=None, ax=None): + """Draw Hinton diagram for visualizing a weight matrix.""" + ax = ax if ax is not None else plt.gca() + + if not max_weight: + max_weight = 2**np.ceil(np.log(np.abs(matrix).max())/np.log(2)) + + ax.patch.set_facecolor('gray') + ax.set_aspect('equal', 'box') + ax.xaxis.set_major_locator(plt.NullLocator()) + ax.yaxis.set_major_locator(plt.NullLocator()) + + for (x,y),w in np.ndenumerate(matrix): + color = 'white' if w > 0 else 'black' + size = np.sqrt(np.abs(w)) + rect = plt.Rectangle([x - size / 2, y - size / 2], size, size, + facecolor=color, edgecolor=color) + ax.add_patch(rect) + + ax.autoscale_view() + ax.invert_yaxis() + + +if __name__ == '__main__': + hinton(np.random.rand(20, 20) - 0.5) + plt.show() + diff --git a/examples/statistics/errorbar_demo.py b/examples/statistics/errorbar_demo.py new file mode 100644 index 000000000000..4801f46a8218 --- /dev/null +++ b/examples/statistics/errorbar_demo.py @@ -0,0 +1,13 @@ +""" +Demo of the errorbar function. +""" +import numpy as np +import matplotlib.pyplot as plt + +# example data +x = np.arange(0.1, 4, 0.5) +y = np.exp(-x) + +plt.errorbar(x, y, xerr=0.2, yerr=0.4) +plt.show() + diff --git a/examples/statistics/errorbar_demo_features.py b/examples/statistics/errorbar_demo_features.py new file mode 100644 index 000000000000..2252d1fb4a8c --- /dev/null +++ b/examples/statistics/errorbar_demo_features.py @@ -0,0 +1,39 @@ +""" +Demo of errorbar function with different ways of specifying error bars. + +Errors can be specified as a constant value (as shown in `errorbar_demo.py`), +or as demonstrated in this example, they can be specified by an N x 1 or 2 x N, +where N is the number of data points. + +N x 1: + Error varies for each point, but the error values are symmetric (i.e. the + lower and upper values are equal). + +2 x N: + Error varies for each point, and the lower and upper limits (in that order) + are different (asymmetric case) + +In addition, this example demonstrates how to use log scale with errorbar. +""" +import numpy as np +import matplotlib.pyplot as plt + +# example data +x = np.arange(0.1, 4, 0.5) +y = np.exp(-x) +# example error bar values that vary with x-position +error = 0.1 + 0.2 * x +# error bar values w/ different -/+ errors +lower_error = 0.4 * error +upper_error = error +asymmetric_error = [lower_error, upper_error] + +fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True) +ax0.errorbar(x, y, yerr=error, fmt='-o') +ax0.set_title('variable, symmetric error') + +ax1.errorbar(x, y, xerr=asymmetric_error, fmt='o') +ax1.set_title('variable, asymmetric error') +ax1.set_yscale('log') +plt.show() + diff --git a/examples/statistics/histogram_demo_features.py b/examples/statistics/histogram_demo_features.py new file mode 100644 index 000000000000..299f9bfeb70c --- /dev/null +++ b/examples/statistics/histogram_demo_features.py @@ -0,0 +1,35 @@ +""" +Demo of the histogram (hist) function with a few features. + +In addition to the basic histogram, this demo shows a few optional features: + + * Setting the number of data bins + * The ``normed`` flag, which normalizes bin heights so that the integral of + the histogram is 1. The resulting histogram is a probability density. + * Setting the face color of the bars + * Setting the opacity (alpha value). + +""" +import numpy as np +import matplotlib.mlab as mlab +import matplotlib.pyplot as plt + + +# example data +mu = 100 # mean of distribution +sigma = 15 # standard deviation of distribution +x = mu + sigma * np.random.randn(10000) + +num_bins = 50 +# the histogram of the data +n, bins, patches = plt.hist(x, num_bins, normed=1, facecolor='green', alpha=0.5) +# add a 'best fit' line +y = mlab.normpdf(bins, mu, sigma) +plt.plot(bins, y, 'r--') +plt.xlabel('Smarts') +plt.ylabel('Probability') +plt.title(r'Histogram of IQ: $\mu=100$, $\sigma=15$') + +# Tweak spacing to prevent clipping of ylabel +plt.subplots_adjust(left=0.15) +plt.show() diff --git a/examples/subplots_axes_and_figures/subplot_demo.py b/examples/subplots_axes_and_figures/subplot_demo.py new file mode 100644 index 000000000000..b90b53d899e9 --- /dev/null +++ b/examples/subplots_axes_and_figures/subplot_demo.py @@ -0,0 +1,24 @@ +""" +Simple demo with multiple subplots. +""" +import numpy as np +import matplotlib.pyplot as plt + + +x1 = np.linspace(0.0, 5.0) +x2 = np.linspace(0.0, 2.0) + +y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) +y2 = np.cos(2 * np.pi * x2) + +plt.subplot(2, 1, 1) +plt.plot(x1, y1, 'yo-') +plt.title('A tale of 2 subplots') +plt.ylabel('Damped oscillation') + +plt.subplot(2, 1, 2) +plt.plot(x2, y2, 'r.-') +plt.xlabel('time (s)') +plt.ylabel('Undamped') + +plt.show() diff --git a/examples/tests/backend_driver.py b/examples/tests/backend_driver.py index 9f1c28bb7606..1c7a4587538f 100755 --- a/examples/tests/backend_driver.py +++ b/examples/tests/backend_driver.py @@ -20,21 +20,87 @@ switches with a --. """ -import os, time, sys, glob, string +import os +import time +import sys +import glob from optparse import OptionParser + import matplotlib.rcsetup as rcsetup from matplotlib.cbook import Bunch, dedent + all_backends = list(rcsetup.all_backends) # to leave the original list alone # actual physical directory for each dir -dirs = dict(pylab = os.path.join('..', 'pylab_examples'), +dirs = dict(files=os.path.join('..', 'lines_bars_and_markers'), + shapes=os.path.join('..', 'shapes_and_collections'), + images=os.path.join('..', 'images_contours_and_fields'), + pie=os.path.join('..', 'pie_and_polar_charts'), + text=os.path.join('..', 'text_labels_and_annotations'), + ticks=os.path.join('..', 'ticks_and_spines'), + subplots=os.path.join('..', 'subplots_axes_and_figures'), + specialty=os.path.join('..', 'specialty_plots'), + showcase=os.path.join('..', 'showcase'), + pylab = os.path.join('..', 'pylab_examples'), api = os.path.join('..', 'api'), units = os.path.join('..', 'units'), mplot3d = os.path.join('..', 'mplot3d')) + # files in each dir files = dict() + +files['lines'] = [ + 'barh_demo.py', + 'fill_demo.py', + 'fill_demo_features.py', + 'line_demo_dash_control.py', + ] + +files['shapes'] = [ + 'path_patch_demo.py', + 'scatter_demo.py', + ] + +files['colors'] = [ + 'color_cycle_demo.py', + ] + +files['images'] = [ + 'imshow_demo.py', + ] + +files['statistics'] = [ + 'errorbar_demo.py', + 'errorbar_demo_features.py', + 'histogram_demo_features.py', + ] + +files['pie'] = [ + 'pie_demo.py', + 'polar_bar_demo.py', + 'polar_scatter_demo.py', + ] + +files['text_labels_and_annotations'] = [ + 'text_demo_fontdict.py', + 'unicode_demo.py', + ] + +files['ticks_and_spines'] = [ + 'spines_demo_bounds.py', + 'ticklabels_demo_rotation.py', + ] + +files['subplots_axes_and_figures'] = [ + 'subplot_demo.py', + ] + +files['showcase'] = [ + 'integral_demo.py', + ] + files['pylab'] = [ 'accented_text.py', 'alignment_test.py', @@ -53,7 +119,6 @@ 'barb_demo.py', 'barchart_demo.py', 'barcode_demo.py', - 'barh_demo.py', 'boxplot_demo.py', 'broken_barh.py', 'clippedline.py', @@ -74,7 +139,6 @@ 'custom_figure_class.py', 'custom_ticker1.py', 'customize_rc.py', - 'dash_control.py', 'dashpointlabel.py', 'date_demo1.py', 'date_demo2.py', @@ -86,7 +150,6 @@ 'ellipse_demo.py', 'ellipse_rotated.py', 'equal_aspect_ratio.py', - 'errorbar_demo.py', 'errorbar_limits.py', 'fancyarrow_demo.py', 'fancybox_demo.py', @@ -96,8 +159,6 @@ 'figlegend_demo.py', 'figure_title.py', 'fill_between_demo.py', - 'fill_demo.py', - 'fill_demo2.py', 'fill_spiral.py', 'finance_demo.py', 'findobj_demo.py', @@ -111,20 +172,17 @@ 'hexbin_demo.py', 'hexbin_demo2.py', 'hist_colormapped.py', - 'histogram_demo.py', 'histogram_demo_extended.py', - 'hline_demo.py', + 'vline_hline_demo.py', 'image_clip_path.py', 'image_demo.py', 'image_demo2.py', - 'image_demo3.py', 'image_interp.py', 'image_masked.py', 'image_nonuniform.py', 'image_origin.py', 'image_slices_viewer.py', - 'integral_demo.py', 'interp_demo.py', 'invert_axes.py', 'layer_images.py', @@ -155,24 +213,18 @@ 'nan_test.py', 'newscalarformatter_demo.py', 'pcolor_demo.py', - 'pcolor_demo2.py', 'pcolor_log.py', 'pcolor_small.py', - 'pie_demo.py', 'pie_demo2.py', 'plotfile_demo.py', - 'polar_bar.py', 'polar_demo.py', 'polar_legend.py', - 'polar_scatter.py', - 'poormans_contour.py', 'psd_demo.py', 'psd_demo2.py', 'psd_demo3.py', 'quadmesh_demo.py', 'quiver_demo.py', 'scatter_custom_symbol.py', - 'scatter_demo.py', 'scatter_demo2.py', 'scatter_masked.py', 'scatter_profile.py', @@ -188,18 +240,13 @@ 'step_demo.py', 'stix_fonts_demo.py', 'stock_demo.py', - 'subplot_demo.py', 'subplots_adjust.py', 'symlog_demo.py', 'table_demo.py', 'text_handles.py', 'text_rotation.py', 'text_rotation_relative_to_line.py', - 'text_themes.py', 'transoffset.py', - 'unicode_demo.py', - 'vertical_ticklabels.py', - 'vline_demo.py', 'xcorr_demo.py', 'zorder_demo.py', ] @@ -210,7 +257,6 @@ 'barchart_demo.py', 'bbox_intersect.py', 'collections_demo.py', - 'color_cycle.py', 'colorbar_only.py', 'custom_projection_example.py', 'custom_scale_example.py', @@ -218,7 +264,6 @@ 'date_index_formatter.py', 'donut_demo.py', 'font_family_rc.py', - 'histogram_demo.py', 'image_zcoord.py', 'joinstyle.py', 'legend_demo.py', @@ -226,7 +271,6 @@ 'logo2.py', 'mathtext_asarray.py', 'patch_collection.py', - 'path_patch_demo.py', 'quad_bezier.py', 'scatter_piecharts.py', 'span_regions.py', diff --git a/examples/text_labels_and_annotations/text_demo_fontdict.py b/examples/text_labels_and_annotations/text_demo_fontdict.py new file mode 100644 index 000000000000..a0dcf3f48d3a --- /dev/null +++ b/examples/text_labels_and_annotations/text_demo_fontdict.py @@ -0,0 +1,25 @@ +""" +Demo using fontdict to control style of text and labels. +""" +import numpy as np +import matplotlib.pyplot as plt + + +font = {'family' : 'serif', + 'color' : 'darkred', + 'weight' : 'normal', + 'size' : 16, + } + +x = np.linspace(0.0, 5.0, 100) +y = np.cos(2 * np.pi * x) * np.exp(-x) + +plt.plot(x, y, 'k') +plt.title('Damped exponential decay', fontdict=font) +plt.text(2, 0.65, r'$\cos(2 \pi t) \exp(-t)$', fontdict=font) +plt.xlabel('time (s)', fontdict=font) +plt.ylabel('voltage (mV)', fontdict=font) + +# Tweak spacing to prevent clipping of ylabel +plt.subplots_adjust(left=0.15) +plt.show() diff --git a/examples/text_labels_and_annotations/unicode_demo.py b/examples/text_labels_and_annotations/unicode_demo.py new file mode 100644 index 000000000000..295b3c4aa5fd --- /dev/null +++ b/examples/text_labels_and_annotations/unicode_demo.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +""" +Demo of unicode support in text and labels. +""" +from __future__ import unicode_literals + +import matplotlib.pyplot as plt + + +plt.title('Développés et fabriqués') +plt.xlabel("réactivité nous permettent d'être sélectionnés et adoptés") +plt.ylabel('André was here!') +plt.text( 0.2, 0.8, 'Institut für Festkörperphysik', rotation=45) +plt.text( 0.4, 0.2, 'AVA (check kerning)') + +plt.show() diff --git a/examples/ticks_and_spines/spines_demo.py b/examples/ticks_and_spines/spines_demo.py new file mode 100644 index 000000000000..a720131e845c --- /dev/null +++ b/examples/ticks_and_spines/spines_demo.py @@ -0,0 +1,31 @@ +""" +Basic demo of axis spines. + +This demo compares a normal axes, with spines on all four sides, and an axes +with spines only on the left and bottom. +""" +import numpy as np +import matplotlib.pyplot as plt + + +x = np.linspace(0, 2 * np.pi, 100) +y = 2 * np.sin(x) + +fig, (ax0, ax1) = plt.subplots(nrows=2) + +ax0.plot(x, y) +ax0.set_title('normal spines') + +ax1.plot(x, y) +ax1.set_title('bottom-left spines') + +# Hide the right and top spines +ax1.spines['right'].set_visible(False) +ax1.spines['top'].set_visible(False) +# Only show ticks on the left and bottom spines +ax1.yaxis.set_ticks_position('left') +ax1.xaxis.set_ticks_position('bottom') + +# Tweak spacing between subplots to prevent labels from overlapping +plt.subplots_adjust(hspace=0.5) +plt.show() diff --git a/examples/ticks_and_spines/spines_demo_bounds.py b/examples/ticks_and_spines/spines_demo_bounds.py new file mode 100644 index 000000000000..9db2591abcae --- /dev/null +++ b/examples/ticks_and_spines/spines_demo_bounds.py @@ -0,0 +1,32 @@ +""" +Demo of spines using custom bounds to limit the extent of the spine. +""" +import numpy as np +import matplotlib.pyplot as plt + + +x = np.linspace(0, 2*np.pi, 50) +y = np.sin(x) +y2 = y + 0.1 * np.random.normal(size=x.shape) + +fig, ax = plt.subplots() +ax.plot(x, y, 'k--') +ax.plot(x, y2, 'ro') + +# set ticks and tick labels +ax.set_xlim((0, 2*np.pi)) +ax.set_xticks([0, np.pi, 2*np.pi]) +ax.set_xticklabels(['0', '$\pi$','2$\pi$']) +ax.set_ylim((-1.5, 1.5)) +ax.set_yticks([-1, 0, 1]) + +# Only draw spine between the y-ticks +ax.spines['left'].set_bounds(-1, 1) +# Hide the right and top spines +ax.spines['right'].set_visible(False) +ax.spines['top'].set_visible(False) +# Only show ticks on the left and bottom spines +ax.yaxis.set_ticks_position('left') +ax.xaxis.set_ticks_position('bottom') + +plt.show() diff --git a/examples/ticks_and_spines/spines_demo_dropped.py b/examples/ticks_and_spines/spines_demo_dropped.py new file mode 100644 index 000000000000..1a11e8f58f59 --- /dev/null +++ b/examples/ticks_and_spines/spines_demo_dropped.py @@ -0,0 +1,24 @@ +""" +Demo of spines offset from the axes (a.k.a. "dropped spines"). +""" +import numpy as np +import matplotlib.pyplot as plt + + +fig, ax = plt.subplots() + +image = np.random.uniform(size=(10, 10)) +ax.imshow(image, cmap=plt.cm.gray, interpolation='nearest') +ax.set_title('dropped spines') + +# Move left and bottom spines outward by 10 points +ax.spines['left'].set_position(('outward', 10)) +ax.spines['bottom'].set_position(('outward', 10)) +# Hide the right and top spines +ax.spines['right'].set_visible(False) +ax.spines['top'].set_visible(False) +# Only show ticks on the left and bottom spines +ax.yaxis.set_ticks_position('left') +ax.xaxis.set_ticks_position('bottom') + +plt.show() diff --git a/examples/ticks_and_spines/ticklabels_demo_rotation.py b/examples/ticks_and_spines/ticklabels_demo_rotation.py new file mode 100644 index 000000000000..9c1c49b2e4d6 --- /dev/null +++ b/examples/ticks_and_spines/ticklabels_demo_rotation.py @@ -0,0 +1,18 @@ +""" +Demo of custom tick-labels with user-defined rotation. +""" +import matplotlib.pyplot as plt + + +x = [1, 2, 3, 4] +y = [1, 4, 9, 6] +labels = ['Frogs', 'Hogs', 'Bogs', 'Slogs'] + +plt.plot(x, y, 'ro') +# You can specify a rotation for the tick labels in degrees or with keywords. +plt.xticks(x, labels, rotation='vertical') +# Pad margins so that markers don't get clipped by the axes +plt.margins(0.2) +# Tweak spacing to prevent clipping of tick-labels +plt.subplots_adjust(bottom=0.15) +plt.show() diff --git a/examples/units/annotate_with_units.py b/examples/units/annotate_with_units.py index deb06f378295..19a99c3b2187 100644 --- a/examples/units/annotate_with_units.py +++ b/examples/units/annotate_with_units.py @@ -1,9 +1,7 @@ import matplotlib.pyplot as plt from basic_units import cm -fig = plt.figure() -ax = fig.add_subplot(111) - +fig, ax = plt.subplots() ax.annotate( "Note 01", [0.5*cm, 0.5*cm] ) diff --git a/examples/units/artist_tests.py b/examples/units/artist_tests.py index aa88496085f5..38a699d208db 100644 --- a/examples/units/artist_tests.py +++ b/examples/units/artist_tests.py @@ -11,14 +11,12 @@ import matplotlib.patches as patches import matplotlib.text as text import matplotlib.collections as collections -import matplotlib.units as units from basic_units import cm, inch import numpy as np -from matplotlib.pyplot import figure, show +import matplotlib.pyplot as plt -fig = figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ax.xaxis.set_units(cm) ax.yaxis.set_units(cm) @@ -51,5 +49,5 @@ #ax.xaxis.set_units(inch) ax.grid(True) ax.set_title("Artists with units") -show() +plt.show() diff --git a/examples/units/bar_unit_demo.py b/examples/units/bar_unit_demo.py index 9d5a1175cd46..f7f7715cde2a 100644 --- a/examples/units/bar_unit_demo.py +++ b/examples/units/bar_unit_demo.py @@ -8,8 +8,7 @@ menMeans = (150*cm, 160*cm, 146*cm, 172*cm, 155*cm) menStd = ( 20*cm, 30*cm, 32*cm, 10*cm, 20*cm) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() ind = np.arange(N) # the x locations for the groups width = 0.35 # the width of the bars diff --git a/examples/user_interfaces/embedding_in_qt.py b/examples/user_interfaces/embedding_in_qt.py deleted file mode 100755 index 311fd9e961f7..000000000000 --- a/examples/user_interfaces/embedding_in_qt.py +++ /dev/null @@ -1,137 +0,0 @@ -#! /usr/bin/env python - -# embedding_in_qt.py --- Simple Qt application embedding matplotlib canvases -# -# Copyright (C) 2005 Florent Rougon -# -# This file is an example program for matplotlib. It may be used and -# modified with no restriction; raw copies as well as modified versions -# may be distributed without limitation. - -from __future__ import unicode_literals -import sys, os, random -from qt import * - -from numpy import arange, sin, pi -from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas -from matplotlib.figure import Figure - -# This seems to be what PyQt expects, according to the examples shipped in -# its distribution. -TRUE = 1 -FALSE = 0 - -progname = os.path.basename(sys.argv[0]) -progversion = "0.1" - -# Note: color-intensive applications may require a different color allocation -# strategy. -#QApplication.setColorSpec(QApplication.NormalColor) -app = QApplication(sys.argv) - -class MyMplCanvas(FigureCanvas): - """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.).""" - def __init__(self, parent=None, width=5, height=4, dpi=100): - self.fig = Figure(figsize=(width, height), dpi=dpi) - self.axes = self.fig.add_subplot(111) - # We want the axes cleared every time plot() is called - self.axes.hold(False) - - self.compute_initial_figure() - - FigureCanvas.__init__(self, self.fig) - self.reparent(parent, QPoint(0, 0)) - - FigureCanvas.setSizePolicy(self, - QSizePolicy.Expanding, - QSizePolicy.Expanding) - FigureCanvas.updateGeometry(self) - - def sizeHint(self): - w, h = self.get_width_height() - return QSize(w, h) - - def minimumSizeHint(self): - return QSize(10, 10) - - -class MyStaticMplCanvas(MyMplCanvas): - """Simple canvas with a sine plot.""" - def compute_initial_figure(self): - t = arange(0.0, 3.0, 0.01) - s = sin(2*pi*t) - self.axes.plot(t, s) - - -class MyDynamicMplCanvas(MyMplCanvas): - """A canvas that updates itself every second with a new plot.""" - def __init__(self, *args, **kwargs): - MyMplCanvas.__init__(self, *args, **kwargs) - timer = QTimer(self, "canvas update timer") - QObject.connect(timer, SIGNAL("timeout()"), self.update_figure) - timer.start(1000, FALSE) - - def compute_initial_figure(self): - self.axes.plot([0, 1, 2, 3], [1, 2, 0, 4], 'r') - - def update_figure(self): - # Build a list of 4 random integers between 0 and 10 (both inclusive) - l = [ random.randint(0, 10) for i in range(4) ] - - self.axes.plot([0, 1, 2, 3], l, 'r') - self.draw() - - -class ApplicationWindow(QMainWindow): - def __init__(self): - QMainWindow.__init__(self, None, - "application main window", - Qt.WType_TopLevel | Qt.WDestructiveClose) - - self.file_menu = QPopupMenu(self) - self.file_menu.insertItem('&Quit', self.fileQuit, Qt.CTRL + Qt.Key_Q) - self.menuBar().insertItem('&File', self.file_menu) - - self.help_menu = QPopupMenu(self) - self.menuBar().insertSeparator() - self.menuBar().insertItem('&Help', self.help_menu) - - self.help_menu.insertItem('&About', self.about) - - self.main_widget = QWidget(self, "Main widget") - - l = QVBoxLayout(self.main_widget) - sc = MyStaticMplCanvas(self.main_widget, width=5, height=4, dpi=100) - dc = MyDynamicMplCanvas(self.main_widget, width=5, height=4, dpi=100) - l.addWidget(sc) - l.addWidget(dc) - - self.main_widget.setFocus() - self.setCentralWidget(self.main_widget) - - self.statusBar().message("All hail matplotlib!", 2000) - - def fileQuit(self): - qApp.exit(0) - - def closeEvent(self, ce): - self.fileQuit() - - def about(self): - QMessageBox.about(self, "About %s" % progname, -"""%(prog)s version %(version)s -Copyright \N{COPYRIGHT SIGN} 2005 Florent Rougon - -This program is a simple example of a Qt application embedding matplotlib -canvases. - -It may be used and modified with no restriction; raw copies as well as -modified versions may be distributed without limitation.""" - % {"prog": progname, "version": progversion}) - - -aw = ApplicationWindow() -aw.setCaption("%s" % progname) -qApp.setMainWidget(aw) -aw.show() -sys.exit(qApp.exec_loop()) diff --git a/examples/user_interfaces/fourier_demo_wx.py b/examples/user_interfaces/fourier_demo_wx.py index a7788a24fbc7..aa52809ff1c0 100644 --- a/examples/user_interfaces/fourier_demo_wx.py +++ b/examples/user_interfaces/fourier_demo_wx.py @@ -12,7 +12,7 @@ class Knob: """ Knob - simple class with a "setKnob" method. - A Knob instance is attached to a Param instance, e.g. param.attach(knob) + A Knob instance is attached to a Param instance, e.g., param.attach(knob) Base class is for documentation purposes. """ def setKnob(self, value): diff --git a/examples/user_interfaces/lineprops_dialog_gtk.py b/examples/user_interfaces/lineprops_dialog_gtk.py index f7c86b47c5df..828120249b97 100644 --- a/examples/user_interfaces/lineprops_dialog_gtk.py +++ b/examples/user_interfaces/lineprops_dialog_gtk.py @@ -14,8 +14,7 @@ def f(t): t2 = np.arange(0.0, 5.0, 0.02) t3 = np.arange(0.0, 2.0, 0.01) -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() l1, = ax.plot(t1, f(t1), 'bo', label='line 1') l2, = ax.plot(t2, f(t2), 'k--', label='line 2') diff --git a/examples/user_interfaces/pylab_with_gtk.py b/examples/user_interfaces/pylab_with_gtk.py index 4aca382ffe3c..7f89334378be 100644 --- a/examples/user_interfaces/pylab_with_gtk.py +++ b/examples/user_interfaces/pylab_with_gtk.py @@ -8,7 +8,7 @@ import matplotlib.pyplot as plt -ax = plt.subplot(111) +fig, ax = plt.subplots() plt.plot([1,2,3], 'ro-', label='easy as 1 2 3') plt.plot([1,4,9], 'gs--', label='easy as 1 2 3 squared') plt.legend() diff --git a/examples/user_interfaces/svg_tooltip.py b/examples/user_interfaces/svg_tooltip.py index 15a435c1fe7f..6ec48307b4ab 100644 --- a/examples/user_interfaces/svg_tooltip.py +++ b/examples/user_interfaces/svg_tooltip.py @@ -28,8 +28,7 @@ ET.register_namespace("","http://www.w3.org/2000/svg") -fig = plt.figure() -ax = fig.add_subplot(111) +fig, ax = plt.subplots() # Create patches to which tooltips will be assigned. circle = plt.Circle((0,0), 5, fc='blue') diff --git a/examples/widgets/buttons.py b/examples/widgets/buttons.py index 6c3d68423f24..d5695e6b9436 100644 --- a/examples/widgets/buttons.py +++ b/examples/widgets/buttons.py @@ -5,7 +5,7 @@ freqs = np.arange(2, 20, 3) -ax = plt.subplot(111) +fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.2) t = np.arange(0.0, 1.0, 0.001) s = np.sin(2*np.pi*freqs[0]*t) diff --git a/examples/widgets/check_buttons.py b/examples/widgets/check_buttons.py index 2ef55709cf0c..843bad9abd19 100644 --- a/examples/widgets/check_buttons.py +++ b/examples/widgets/check_buttons.py @@ -7,7 +7,7 @@ s1 = np.sin(4*np.pi*t) s2 = np.sin(6*np.pi*t) -ax = plt.subplot(111) +fig, ax = plt.subplots() l0, = ax.plot(t, s0, visible=False, lw=2) l1, = ax.plot(t, s1, lw=2) l2, = ax.plot(t, s2, lw=2) diff --git a/examples/widgets/radio_buttons.py b/examples/widgets/radio_buttons.py index 8d4f32c3d03a..43c5e986b2d2 100644 --- a/examples/widgets/radio_buttons.py +++ b/examples/widgets/radio_buttons.py @@ -7,7 +7,7 @@ s1 = np.sin(4*np.pi*t) s2 = np.sin(8*np.pi*t) -ax = plt.subplot(111) +fig, ax = plt.subplots() l, = ax.plot(t, s0, lw=2, color='red') plt.subplots_adjust(left=0.3) diff --git a/examples/widgets/rectangle_selector.py b/examples/widgets/rectangle_selector.py index ed3d2eacbb5f..fa21a30d23df 100644 --- a/examples/widgets/rectangle_selector.py +++ b/examples/widgets/rectangle_selector.py @@ -29,7 +29,7 @@ def toggle_selector(event): toggle_selector.RS.set_active(True) -current_ax = plt.subplot(111) # make a new plotingrange +fig, current_ax = plt.subplots() # make a new plotingrange N = 100000 # If N is large one can see x = np.linspace(0.0, 10.0, N) # improvement by use blitting! diff --git a/examples/widgets/slider_demo.py b/examples/widgets/slider_demo.py index d3db0a027130..c75cf92681af 100644 --- a/examples/widgets/slider_demo.py +++ b/examples/widgets/slider_demo.py @@ -2,7 +2,7 @@ import matplotlib.pyplot as plt from matplotlib.widgets import Slider, Button, RadioButtons -ax = plt.subplot(111) +fig, ax = plt.subplots() plt.subplots_adjust(left=0.25, bottom=0.25) t = np.arange(0.0, 1.0, 0.001) a0 = 5 @@ -22,7 +22,7 @@ def update(val): amp = samp.val freq = sfreq.val l.set_ydata(amp*np.sin(2*np.pi*freq*t)) - plt.draw() + fig.canvas.draw_idle() sfreq.on_changed(update) samp.on_changed(update) @@ -37,8 +37,7 @@ def reset(event): radio = RadioButtons(rax, ('red', 'blue', 'green'), active=0) def colorfunc(label): l.set_color(label) - plt.draw() + fig.canvas.draw_idle() radio.on_clicked(colorfunc) plt.show() - diff --git a/lib/dateutil_py2/LICENSE b/lib/dateutil_py2/LICENSE deleted file mode 100644 index c5b5923c55e5..000000000000 --- a/lib/dateutil_py2/LICENSE +++ /dev/null @@ -1,259 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations (now Zope -Corporation, see http://www.zope.com). In 2001, the Python Software -Foundation (PSF, see http://www.python.org/psf/) was formed, a -non-profit organization created specifically to own Python-related -Intellectual Property. Zope Corporation is a sponsoring member of -the PSF. - -All Python releases are Open Source (see http://www.opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.2 2.1.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2.1 2.2 2002 PSF yes - 2.2.2 2.2.1 2002 PSF yes - 2.2.3 2.2.2 2003 PSF yes - 2.3 2.2.2 2002-2003 PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -PSF LICENSE AGREEMENT FOR PYTHON 2.3 ------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python 2.3 software in source or binary form and its -associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 2.3 -alone or in any derivative version, provided, however, that PSF's -License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -2001, 2002, 2003 Python Software Foundation; All Rights Reserved" are -retained in Python 2.3 alone or in any derivative version prepared by -Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 2.3 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 2.3. - -4. PSF is making Python 2.3 available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python 2.3, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the Internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the Internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/lib/dateutil_py2/NEWS b/lib/dateutil_py2/NEWS deleted file mode 100644 index 8738e849e29c..000000000000 --- a/lib/dateutil_py2/NEWS +++ /dev/null @@ -1,143 +0,0 @@ - -Version 1.5 ------------ - -- As reported by Mathieu Bridon, rrules were matching the bysecond rules - incorrectly against byminute in some circumstances when the SECONDLY - frequency was in use, due to a copy & paste bug. The problem has been - unittested and corrected. - -- Adam Ryan reported a problem in the relativedelta implementation which - affected the yearday parameter in the month of January specifically. - This has been unittested and fixed. - -- Updated timezone information. - - -Version 1.4.1 -------------- - -- Updated timezone information. - - -Version 1.4 ------------ - -- Fixed another parser precision problem on conversion of decimal seconds - to microseconds, as reported by Erik Brown. Now these issues are gone - for real since it's not using floating point arithmetic anymore. - -- Fixed case where tzrange.utcoffset and tzrange.dst() might fail due - to a date being used where a datetime was expected (reported and fixed - by Lennart Regebro). - -- Prevent tzstr from introducing daylight timings in strings that didn't - specify them (reported by Lennart Regebro). - -- Calls like gettz("GMT+3") and gettz("UTC-2") will now return the - expected values, instead of the TZ variable behavior. - -- Fixed DST signal handling in zoneinfo files. Reported by - Nicholas F. Fabry and John-Mark Gurney. - - -Version 1.3 ------------ - -- Fixed precision problem on conversion of decimal seconds to - microseconds, as reported by Skip Montanaro. - -- Fixed bug in constructor of parser, and converted parser classes to - new-style classes. Original report and patch by Michael Elsdörfer. - -- Initialize tzid and comps in tz.py, to prevent the code from ever - raising a NameError (even with broken files). Johan Dahlin suggested - the fix after a pyflakes run. - -- Version is now published in dateutil.__version__, as requested - by Darren Dale. - -- All code is compatible with new-style division. - - -Version 1.2 ------------ - -- Now tzfile will round timezones to full-minutes if necessary, - since Python's datetime doesn't support sub-minute offsets. - Thanks to Ilpo Nyyssönen for reporting the issue. - -- Removed bare string exceptions, as reported and fixed by - Wilfredo Sánchez Vega. - -- Fix bug in leap count parsing (reported and fixed by Eugene Oden). - - -Version 1.1 ------------ - -- Fixed rrule byyearday handling. Abramo Bagnara pointed out that - RFC2445 allows negative numbers. - -- Fixed --prefix handling in setup.py (by Sidnei da Silva). - -- Now tz.gettz() returns a tzlocal instance when not given any - arguments and no other timezone information is found. - -- Updating timezone information to version 2005q. - - -Version 1.0 ------------ - -- Fixed parsing of XXhXXm formatted time after day/month/year - has been parsed. - -- Added patch by Jeffrey Harris optimizing rrule.__contains__. - - -Version 0.9 ------------ - -- Fixed pickling of timezone types, as reported by - Andreas Köhler. - -- Implemented internal timezone information with binary - timezone files [1]. datautil.tz.gettz() function will now - try to use the system timezone files, and fallback to - the internal versions. It's also possible to ask for - the internal versions directly by using - dateutil.zoneinfo.gettz(). - -- New tzwin timezone type, allowing access to Windows - internal timezones (contributed by Jeffrey Harris). - -- Fixed parsing of unicode date strings. - -- Accept parserinfo instances as the parser constructor - parameter, besides parserinfo (sub)classes. - -- Changed weekday to spell the not-set n value as None - instead of 0. - -- Fixed other reported bugs. - -[1] http://www.twinsun.com/tz/tz-link.htm - - -Version 0.5 ------------ - -- Removed FREQ_ prefix from rrule frequency constants - WARNING: this breaks compatibility with previous versions. - -- Fixed rrule.between() for cases where "after" is achieved - before even starting, as reported by Andreas Köhler. - -- Fixed two digit zero-year parsing (such as 31-Dec-00), as - reported by Jim Abramson, and included test case for this. - -- Sort exdate and rdate before iterating over them, so that - it's not necessary to sort them before adding to the rruleset, - as reported by Nicholas Piper. - diff --git a/lib/dateutil_py2/README b/lib/dateutil_py2/README deleted file mode 100644 index dbe7988ce499..000000000000 --- a/lib/dateutil_py2/README +++ /dev/null @@ -1,1970 +0,0 @@ -## This file is in the moin format. The latest version is found -## at https://moin.conectiva.com.br/DateUtil - -== Contents == -[[TableOfContents]] - -== Description == -The '''dateutil''' module provides powerful extensions to -the standard '''datetime''' module, available in Python 2.3+. - -== Features == - - * Computing of relative deltas (next month, next year, - next monday, last week of month, etc); - - * Computing of relative deltas between two given - date and/or datetime objects; - - * Computing of dates based on very flexible recurrence rules, - using a superset of the - [ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] - specification. Parsing of RFC strings is supported as well. - - * Generic parsing of dates in almost any string format; - - * Timezone (tzinfo) implementations for tzfile(5) format - files (/etc/localtime, /usr/share/zoneinfo, etc), TZ - environment string (in all known formats), iCalendar - format files, given ranges (with help from relative deltas), - local machine timezone, fixed offset timezone, UTC timezone, - and Windows registry-based time zones. - - * Internal up-to-date world timezone information based on - Olson's database. - - * Computing of Easter Sunday dates for any given year, - using Western, Orthodox or Julian algorithms; - - * More than 400 test cases. - -== Quick example == -Here's a snapshot, just to give an idea about the power of the -package. For more examples, look at the documentation below. - -Suppose you want to know how much time is left, in -years/months/days/etc, before the next easter happening on a -year with a Friday 13th in August, and you want to get today's -date out of the "date" unix system command. Here is the code: -{{{ -from dateutil.relativedelta import * -from dateutil.easter import * -from dateutil.rrule import * -from dateutil.parser import * -from datetime import * -import commands -import os -now = parse(commands.getoutput("date")) -today = now.date() -year = rrule(YEARLY,bymonth=8,bymonthday=13,byweekday=FR)[0].year -rdelta = relativedelta(easter(year), today) -print "Today is:", today -print "Year with next Aug 13th on a Friday is:", year -print "How far is the Easter of that year:", rdelta -print "And the Easter of that year is:", today+rdelta -}}} - -And here's the output: -{{{ -Today is: 2003-10-11 -Year with next Aug 13th on a Friday is: 2004 -How far is the Easter of that year: relativedelta(months=+6) -And the Easter of that year is: 2004-04-11 -}}} - -{i} Being exactly 6 months ahead was '''really''' a coincidence :) - -== Download == -The following files are available. - * attachment:python-dateutil-1.0.tar.bz2 - * attachment:python-dateutil-1.0-1.noarch.rpm - -== Author == -The dateutil module was written by GustavoNiemeyer . - -== Documentation == -The following modules are available. - -=== relativedelta === -This module offers the '''relativedelta''' type, which is based -on the specification of the excelent work done by M.-A. Lemburg in his -[http://www.egenix.com/files/python/mxDateTime.html mxDateTime] -extension. However, notice that this type '''does not''' implement the -same algorithm as his work. Do not expect it to behave like -{{{mxDateTime}}}'s counterpart. - -==== relativedelta type ==== - -There's two different ways to build a relativedelta instance. The -first one is passing it two {{{date}}}/{{{datetime}}} instances: -{{{ -relativedelta(datetime1, datetime2) -}}} - -This will build the relative difference between {{{datetime1}}} and -{{{datetime2}}}, so that the following constraint is always true: -{{{ -datetime2+relativedelta(datetime1, datetime2) == datetime1 -}}} - -Notice that instead of {{{datetime}}} instances, you may use -{{{date}}} instances, or a mix of both. - -And the other way is to use any of the following keyword arguments: - - year, month, day, hour, minute, second, microsecond:: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds:: - Relative information, may be negative. - - weekday:: - One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These - instances may receive a parameter {{{n}}}, specifying the {{{n}}}th - weekday, which could be positive or negative (like {{{MO(+2)}}} or - {{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}. - You can also use an integer, where {{{0=MO}}}. Notice that, - for example, if the calculated date is already Monday, using - {{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context), - won't change the day. - - leapdays:: - Will add given days to the date found, but only if the computed - year is a leap year and the computed date is post 28 of february. - - yearday, nlyearday:: - Set the yearday or the non-leap year day (jump leap days). - These are converted to {{{day}}}/{{{month}}}/{{{leapdays}}} - information. - -==== Behavior of operations ==== -If you're curious about exactly how the relative delta will act -on operations, here is a description of its behavior. - - 1. Calculate the absolute year, using the {{{year}}} argument, or the - original datetime year, if the argument is not present. - 1. Add the relative {{{years}}} argument to the absolute year. - 1. Do steps 1 and 2 for {{{month}}}/{{{months}}}. - 1. Calculate the absolute day, using the {{{day}}} argument, or the - original datetime day, if the argument is not present. Then, subtract - from the day until it fits in the year and month found after their - operations. - 1. Add the relative {{{days}}} argument to the absolute day. Notice - that the {{{weeks}}} argument is multiplied by 7 and added to {{{days}}}. - 1. If {{{leapdays}}} is present, the computed year is a leap year, and - the computed month is after february, remove one day from the found date. - 1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}}, - {{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}. - 1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th - occurrence of the given weekday. - -==== Examples ==== - -Let's begin our trip. -{{{ ->>> from datetime import *; from dateutil.relativedelta import * ->>> import calendar -}}} - -Store some values. -{{{ ->>> NOW = datetime.now() ->>> TODAY = date.today() ->>> NOW -datetime.datetime(2003, 9, 17, 20, 54, 47, 282310) ->>> TODAY -datetime.date(2003, 9, 17) -}}} - -Next month. -{{{ ->>> NOW+relativedelta(months=+1) -datetime.datetime(2003, 10, 17, 20, 54, 47, 282310) -}}} - -Next month, plus one week. -{{{ ->>> NOW+relativedelta(months=+1, weeks=+1) -datetime.datetime(2003, 10, 24, 20, 54, 47, 282310) -}}} - -Next month, plus one week, at 10am. -{{{ ->>> TODAY+relativedelta(months=+1, weeks=+1, hour=10) -datetime.datetime(2003, 10, 24, 10, 0) -}}} - -Let's try the other way around. Notice that the -hour setting we get in the relativedelta is relative, -since it's a difference, and the weeks parameter -has gone. -{{{ ->>> relativedelta(datetime(2003, 10, 24, 10, 0), TODAY) -relativedelta(months=+1, days=+7, hours=+10) -}}} - -One month before one year. -{{{ ->>> NOW+relativedelta(years=+1, months=-1) -datetime.datetime(2004, 8, 17, 20, 54, 47, 282310) -}}} - -How does it handle months with different numbers of days? -Notice that adding one month will never cross the month -boundary. -{{{ ->>> date(2003,1,27)+relativedelta(months=+1) -datetime.date(2003, 2, 27) ->>> date(2003,1,31)+relativedelta(months=+1) -datetime.date(2003, 2, 28) ->>> date(2003,1,31)+relativedelta(months=+2) -datetime.date(2003, 3, 31) -}}} - -The logic for years is the same, even on leap years. -{{{ ->>> date(2000,2,28)+relativedelta(years=+1) -datetime.date(2001, 2, 28) ->>> date(2000,2,29)+relativedelta(years=+1) -datetime.date(2001, 2, 28) - ->>> date(1999,2,28)+relativedelta(years=+1) -datetime.date(2000, 2, 28) ->>> date(1999,3,1)+relativedelta(years=+1) -datetime.date(2000, 3, 1) - ->>> date(2001,2,28)+relativedelta(years=-1) -datetime.date(2000, 2, 28) ->>> date(2001,3,1)+relativedelta(years=-1) -datetime.date(2000, 3, 1) -}}} - -Next friday. -{{{ ->>> TODAY+relativedelta(weekday=FR) -datetime.date(2003, 9, 19) - ->>> TODAY+relativedelta(weekday=calendar.FRIDAY) -datetime.date(2003, 9, 19) -}}} - -Last friday in this month. -{{{ ->>> TODAY+relativedelta(day=31, weekday=FR(-1)) -datetime.date(2003, 9, 26) -}}} - -Next wednesday (it's today!). -{{{ ->>> TODAY+relativedelta(weekday=WE(+1)) -datetime.date(2003, 9, 17) -}}} - -Next wednesday, but not today. -{{{ ->>> TODAY+relativedelta(days=+1, weekday=WE(+1)) -datetime.date(2003, 9, 24) -}}} - -Following -[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation] -find the first day of the 15th week of 1997. -{{{ ->>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14) -datetime.datetime(1997, 4, 7, 0, 0) -}}} - -How long ago has the millennium changed? -{{{ ->>> relativedelta(NOW, date(2001,1,1)) -relativedelta(years=+2, months=+8, days=+16, - hours=+20, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -How old is John? -{{{ ->>> johnbirthday = datetime(1978, 4, 5, 12, 0) ->>> relativedelta(NOW, johnbirthday) -relativedelta(years=+25, months=+5, days=+12, - hours=+8, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -It works with dates too. -{{{ ->>> relativedelta(TODAY, johnbirthday) -relativedelta(years=+25, months=+5, days=+11, hours=+12) -}}} - -Obtain today's date using the yearday: -{{{ ->>> date(2003, 1, 1)+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -We can use today's date, since yearday should be absolute -in the given year: -{{{ ->>> TODAY+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -Last year it should be in the same day: -{{{ ->>> date(2002, 1, 1)+relativedelta(yearday=260) -datetime.date(2002, 9, 17) -}}} - -But not in a leap year: -{{{ ->>> date(2000, 1, 1)+relativedelta(yearday=260) -datetime.date(2000, 9, 16) -}}} - -We can use the non-leap year day to ignore this: -{{{ ->>> date(2000, 1, 1)+relativedelta(nlyearday=260) -datetime.date(2000, 9, 17) -}}} - -=== rrule === -The rrule module offers a small, complete, and very fast, implementation -of the recurrence rules documented in the -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar RFC], including -support for caching of results. - -==== rrule type ==== -That's the base of the rrule operation. It accepts all the keywords -defined in the RFC as its constructor parameters (except {{{byday}}}, -which was renamed to {{{byweekday}}}) and more. The constructor -prototype is: -{{{ -rrule(freq) -}}} - -Where {{{freq}}} must be one of {{{YEARLY}}}, {{{MONTHLY}}}, -{{{WEEKLY}}}, {{{DAILY}}}, {{{HOURLY}}}, {{{MINUTELY}}}, -or {{{SECONDLY}}}. - -Additionally, it supports the following keyword arguments: - - cache:: - If given, it must be a boolean value specifying to enable - or disable caching of results. If you will use the same - {{{rrule}}} instance multiple times, enabling caching will - improve the performance considerably. - - dtstart:: - The recurrence start. Besides being the base for the - recurrence, missing parameters in the final recurrence - instances will also be extracted from this date. If not - given, {{{datetime.now()}}} will be used instead. - - interval:: - The interval between each {{{freq}}} iteration. For example, - when using {{{YEARLY}}}, an interval of {{{2}}} means - once every two years, but with {{{HOURLY}}}, it means - once every two hours. The default interval is {{{1}}}. - - wkst:: - The week start day. Must be one of the {{{MO}}}, {{{TU}}}, - {{{WE}}} constants, or an integer, specifying the first day - of the week. This will affect recurrences based on weekly - periods. The default week start is got from - {{{calendar.firstweekday()}}}, and may be modified by - {{{calendar.setfirstweekday()}}}. - - count:: - How many occurrences will be generated. - - until:: - If given, this must be a {{{datetime}}} instance, that will - specify the limit of the recurrence. If a recurrence instance - happens to be the same as the {{{datetime}}} instance given - in the {{{until}}} keyword, this will be the last occurrence. - - bysetpos:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each given integer will - specify an occurrence number, corresponding to the nth - occurrence of the rule inside the frequency period. For - example, a {{{bysetpos}}} of {{{-1}}} if combined with a - {{{MONTHLY}}} frequency, and a {{{byweekday}}} of - {{{(MO, TU, WE, TH, FR)}}}, will result in the last work - day of every month. - - bymonth:: - If given, it must be either an integer, or a sequence of - integers, meaning the months to apply the recurrence to. - - bymonthday:: - If given, it must be either an integer, or a sequence of - integers, meaning the month days to apply the recurrence to. - - byyearday:: - If given, it must be either an integer, or a sequence of - integers, meaning the year days to apply the recurrence to. - - byweekno:: - If given, it must be either an integer, or a sequence of - integers, meaning the week numbers to apply the recurrence - to. Week numbers have the meaning described in ISO8601, - that is, the first week of the year is that containing at - least four days of the new year. - - byweekday:: - If given, it must be either an integer ({{{0 == MO}}}), a - sequence of integers, one of the weekday constants - ({{{MO}}}, {{{TU}}}, etc), or a sequence of these constants. - When given, these variables will define the weekdays where - the recurrence will be applied. It's also possible to use - an argument {{{n}}} for the weekday instances, which will - mean the {{{n}}}''th'' occurrence of this weekday in the - period. For example, with {{{MONTHLY}}}, or with - {{{YEARLY}}} and {{{BYMONTH}}}, using {{{FR(+1)}}} - in {{{byweekday}}} will specify the first friday of the - month where the recurrence happens. Notice that in the RFC - documentation, this is specified as {{{BYDAY}}}, but was - renamed to avoid the ambiguity of that keyword. - - byhour:: - If given, it must be either an integer, or a sequence of - integers, meaning the hours to apply the recurrence to. - - byminute:: - If given, it must be either an integer, or a sequence of - integers, meaning the minutes to apply the recurrence to. - - bysecond:: - If given, it must be either an integer, or a sequence of - integers, meaning the seconds to apply the recurrence to. - - byeaster:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each integer will define - an offset from the Easter Sunday. Passing the offset - {{{0}}} to {{{byeaster}}} will yield the Easter Sunday - itself. This is an extension to the RFC specification. - -==== rrule methods ==== -The following methods are available in {{{rrule}}} instances: - - rrule.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.between(after, before, inc=False):: - Returns all the occurrences of the rrule between {{{after}}} - and {{{before}}}. The {{{inc}}} keyword defines what happens - if {{{after}}} and/or {{{before}}} are themselves occurrences. - With {{{inc == True}}}, they will be included in the list, - if they are found in the recurrence set. - - rrule.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rrule}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -rr = rrule(...) -if datetime(...) in rr: - ... -print rr[0] -print rr[-1] -print rr[1:2] -print rr[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== Notes ==== - - * The rrule type has no {{{byday}}} keyword. The equivalent keyword - has been replaced by the {{{byweekday}}} keyword, to remove the - ambiguity present in the original keyword. - - * Unlike documented in the RFC, the starting datetime ({{{dtstart}}}) - is not the first recurrence instance, unless it does fit in the - specified rules. In a python module context, this behavior makes more - sense than otherwise. Notice that you can easily get the original - behavior by using a rruleset and adding the {{{dtstart}}} as an - {{{rdate}}} recurrence. - - * Unlike documented in the RFC, every keyword is valid on every - frequency (the RFC documents that {{{byweekno}}} is only valid - on yearly frequencies, for example). - - * In addition to the documented keywords, a {{{byeaster}}} keyword - was introduced, making it easy to compute recurrent events relative - to the Easter Sunday. - -==== rrule examples ==== -These examples were converted from the RFC. - -Prepare the environment. -{{{ ->>> from dateutil.rrule import * ->>> from dateutil.parser import * ->>> from datetime import * - ->>> import pprint ->>> import sys ->>> sys.displayhook = pprint.pprint -}}} - -Daily, for 10 occurrences. -{{{ ->>> list(rrule(DAILY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0)] -}}} - -Daily until December 24, 1997 -{{{ ->>> list(rrule(DAILY, - dtstart=parse("19970902T090000"), - until=parse("19971224T000000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - (...) - datetime.datetime(1997, 12, 21, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1997, 12, 23, 9, 0)] -}}} - -Every other day, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=2, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0)] -}}} - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=10, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Everyday in January, for 3 years. -{{{ ->>> list(rrule(YEARLY, bymonth=1, byweekday=range(7), - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -[datetime.datetime(1998, 1, 1, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - (...) - datetime.datetime(1998, 1, 30, 9, 0), - datetime.datetime(1998, 1, 31, 9, 0), - datetime.datetime(1999, 1, 1, 9, 0), - datetime.datetime(1999, 1, 2, 9, 0), - (...) - datetime.datetime(1999, 1, 30, 9, 0), - datetime.datetime(1999, 1, 31, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0), - (...) - datetime.datetime(2000, 1, 29, 9, 0), - datetime.datetime(2000, 1, 31, 9, 0)] -}}} - -Same thing, in another way. -{{{ ->>> list(rrule(DAILY, bymonth=1, - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -(...) -}}} - -Weekly for 10 occurrences. -{{{ ->>> list(rrule(WEEKLY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 21, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Every other week, 6 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 11, 9, 0)] -}}} - -Weekly on Tuesday and Thursday for 5 weeks. -{{{ ->>> list(rrule(WEEKLY, count=10, wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 25, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0)] -}}} - -Every other week on Tuesday and Thursday, for 8 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=8, - wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 16, 9, 0)] -}}} - -Monthly on the 1st Friday for ten occurrences. -{{{ ->>> list(rrule(MONTHLY, count=10, byweekday=FR(1), - dtstart=parse("19970905T090000"))) -[datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 10, 3, 9, 0), - datetime.datetime(1997, 11, 7, 9, 0), - datetime.datetime(1997, 12, 5, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - datetime.datetime(1998, 2, 6, 9, 0), - datetime.datetime(1998, 3, 6, 9, 0), - datetime.datetime(1998, 4, 3, 9, 0), - datetime.datetime(1998, 5, 1, 9, 0), - datetime.datetime(1998, 6, 5, 9, 0)] -}}} - -Every other month on the 1st and last Sunday of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=10, - byweekday=(SU(1), SU(-1)), - dtstart=parse("19970907T090000"))) -[datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0), - datetime.datetime(1998, 1, 4, 9, 0), - datetime.datetime(1998, 1, 25, 9, 0), - datetime.datetime(1998, 3, 1, 9, 0), - datetime.datetime(1998, 3, 29, 9, 0), - datetime.datetime(1998, 5, 3, 9, 0), - datetime.datetime(1998, 5, 31, 9, 0)] -}}} - -Monthly on the second to last Monday of the month for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, byweekday=MO(-2), - dtstart=parse("19970922T090000"))) -[datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 20, 9, 0), - datetime.datetime(1997, 11, 17, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1998, 1, 19, 9, 0), - datetime.datetime(1998, 2, 16, 9, 0)] -}}} - -Monthly on the third to the last day of the month, for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, bymonthday=-3, - dtstart=parse("19970928T090000"))) -[datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 10, 29, 9, 0), - datetime.datetime(1997, 11, 28, 9, 0), - datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1998, 1, 29, 9, 0), - datetime.datetime(1998, 2, 26, 9, 0)] -}}} - -Monthly on the 2nd and 15th of the month for 5 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(2,15), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 15, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0)] -}}} - -Monthly on the first and last day of the month for 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(-1,1,), - dtstart=parse("1997090 -2T090000"))) -[datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 1, 9, 0), - datetime.datetime(1997, 10, 31, 9, 0), - datetime.datetime(1997, 11, 1, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0)] -}}} - -Every 18 months on the 10th thru 15th of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=18, count=10, - bymonthday=range(10,16), - dtstart=parse("19970910T090000"))) -[datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 13, 9, 0), - datetime.datetime(1997, 9, 14, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1999, 3, 10, 9, 0), - datetime.datetime(1999, 3, 11, 9, 0), - datetime.datetime(1999, 3, 12, 9, 0), - datetime.datetime(1999, 3, 13, 9, 0)] -}}} - -Every Tuesday, every other month, 6 occurences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=6, byweekday=TU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Yearly in June and July for 10 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, bymonth=(6,7), - dtstart=parse("19970610T0900 -00"))) -[datetime.datetime(1997, 6, 10, 9, 0), - datetime.datetime(1997, 7, 10, 9, 0), - datetime.datetime(1998, 6, 10, 9, 0), - datetime.datetime(1998, 7, 10, 9, 0)] -}}} - -Every 3rd year on the 1st, 100th and 200th day for 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, interval=3, byyearday=(1,100,200), - dtstart=parse("19970101T090000"))) -[datetime.datetime(1997, 1, 1, 9, 0), - datetime.datetime(1997, 4, 10, 9, 0), - datetime.datetime(1997, 7, 19, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0)] -}}} - -Every 20th Monday of the year, 3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekday=MO(20), - dtstart=parse("19970519T090000"))) -[datetime.datetime(1997, 5, 19, 9, 0), - datetime.datetime(1998, 5, 18, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -Monday of week number 20 (where the default start of the week is Monday), -3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekno=20, byweekday=MO, - dtstart=parse("19970512T090000"))) -[datetime.datetime(1997, 5, 12, 9, 0), - datetime.datetime(1998, 5, 11, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -The week number 1 may be in the last year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=1, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1999, 1, 4, 9, 0), - datetime.datetime(2000, 1, 3, 9, 0)] -}}} - -And the week numbers greater than 51 may be in the next year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=52, byweekday=SU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 28, 9, 0), - datetime.datetime(1998, 12, 27, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0)] -}}} - -Only some years have week number 53: -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=53, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 12, 28, 9, 0), - datetime.datetime(2004, 12, 27, 9, 0), - datetime.datetime(2009, 12, 28, 9, 0)] -}}} - -Every Friday the 13th, 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, byweekday=FR, bymonthday=13, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 2, 13, 9, 0), - datetime.datetime(1998, 3, 13, 9, 0), - datetime.datetime(1998, 11, 13, 9, 0), - datetime.datetime(1999, 8, 13, 9, 0)] -}}} - -Every four years, the first Tuesday after a Monday in November, -3 occurrences (U.S. Presidential Election day): -{{{ ->>> list(rrule(YEARLY, interval=4, count=3, bymonth=11, - byweekday=TU, bymonthday=(2,3,4,5,6,7,8), - dtstart=parse("19961105T090000"))) -[datetime.datetime(1996, 11, 5, 9, 0), - datetime.datetime(2000, 11, 7, 9, 0), - datetime.datetime(2004, 11, 2, 9, 0)] -}}} - -The 3rd instance into the month of one of Tuesday, Wednesday or -Thursday, for the next 3 months: -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(TU,WE,TH), - bysetpos=3, dtstart=parse("19970904T090000"))) -[datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 11, 6, 9, 0)] -}}} - -The 2nd to last weekday of the month, 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(MO,TU,WE,TH,FR), - bysetpos=-2, dtstart=parse("19970929T090000"))) -[datetime.datetime(1997, 9, 29, 9, 0), - datetime.datetime(1997, 10, 30, 9, 0), - datetime.datetime(1997, 11, 27, 9, 0)] -}}} - -Every 3 hours from 9:00 AM to 5:00 PM on a specific day. -{{{ ->>> list(rrule(HOURLY, interval=3, - dtstart=parse("19970902T090000"), - until=parse("19970902T170000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 15, 0)] -}}} - -Every 15 minutes for 6 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=15, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 15), - datetime.datetime(1997, 9, 2, 9, 30), - datetime.datetime(1997, 9, 2, 9, 45), - datetime.datetime(1997, 9, 2, 10, 0), - datetime.datetime(1997, 9, 2, 10, 15)] -}}} - -Every hour and a half for 4 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=90, count=4, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 10, 30), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 13, 30)] -}}} - -Every 20 minutes from 9:00 AM to 4:40 PM for two days. -{{{ ->>> list(rrule(MINUTELY, interval=20, count=48, - byhour=range(9,17), byminute=(0,20,40), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 20), - (...) - datetime.datetime(1997, 9, 2, 16, 20), - datetime.datetime(1997, 9, 2, 16, 40), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 3, 9, 20), - (...) - datetime.datetime(1997, 9, 3, 16, 20), - datetime.datetime(1997, 9, 3, 16, 40)] -}}} - -An example where the days generated makes a difference because of {{{wkst}}}. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=MO, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 10, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 24, 9, 0)] - ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=SU, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 17, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 31, 9, 0)] -}}} - -==== rruleset type ==== -The {{{rruleset}}} type allows more complex recurrence setups, mixing -multiple rules, dates, exclusion rules, and exclusion dates. -The type constructor takes the following keyword arguments: - - cache:: - If True, caching of results will be enabled, improving performance - of multiple queries considerably. - -==== rruleset methods ==== -The following methods are available: - - rruleset.rrule(rrule):: - Include the given {{{rrule}}} instance in the recurrence set - generation. - - rruleset.rdate(dt):: - Include the given {{{datetime}}} instance in the recurrence - set generation. - - rruleset.exrule(rrule):: - Include the given {{{rrule}}} instance in the recurrence set - exclusion list. Dates which are part of the given recurrence - rules will not be generated, even if some inclusive {{{rrule}}} - or {{{rdate}}} matches them. - - rruleset.exdate(dt):: - Include the given {{{datetime}}} instance in the recurrence set - exclusion list. Dates included that way will not be generated, - even if some inclusive {{{rrule}}} or {{{rdate}}} matches them. - - rruleset.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.between(after, before, inc=False):: - Returns all the occurrences of the rrule between {{{after}}} - and {{{before}}}. The {{{inc}}} keyword defines what happens - if {{{after}}} and/or {{{before}}} are themselves occurrences. - With {{{inc == True}}}, they will be included in the list, - if they are found in the recurrence set. - - rruleset.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rruleset}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -set = rruleset(...) -if datetime(...) in set: - ... -print set[0] -print set[-1] -print set[1:2] -print set[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== rruleset examples ==== -Daily, for 7 days, jumping Saturday and Sunday occurrences. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(DAILY, count=7, - dtstart=parse("19970902T090000"))) ->>> set.exrule(rrule(YEARLY, byweekday=(SA,SU), - dtstart=parse("19970902T090000"))) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0)] -}}} - -Weekly, for 4 weeks, plus one time on day 7, and not on day 16. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(WEEKLY, count=4, - dtstart=parse("19970902T090000"))) ->>> set.rdate(datetime.datetime(1997, 9, 7, 9, 0)) ->>> set.exdate(datetime.datetime(1997, 9, 16, 9, 0)) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0)] -}}} - -==== rrulestr() function ==== -The {{{rrulestr()}}} function is a parser for ''RFC-like'' syntaxes. -The function prototype is: -{{{ -rrulestr(str) -}}} - -The string passed as parameter may be a multiple line string, a -single line string, or just the {{{RRULE}}} property value. - -Additionally, it accepts the following keyword arguments: - - cache:: - If {{{True}}}, the {{{rruleset}}} or {{{rrule}}} created instance - will cache its results. Default is not to cache. - - dtstart:: - If given, it must be a {{{datetime}}} instance that will be used - when no {{{DTSTART}}} property is found in the parsed string. If - it is not given, and the property is not found, {{{datetime.now()}}} - will be used instead. - - unfold:: - If set to {{{True}}}, lines will be unfolded following the RFC - specification. It defaults to {{{False}}}, meaning that spaces - before every line will be stripped. - - forceset:: - If set to {{{True}}} a {{{rruleset}}} instance will be returned, - even if only a single rule is found. The default is to return an - {{{rrule}}} if possible, and an {{{rruleset}}} if necessary. - - compatible:: - If set to {{{True}}}, the parser will operate in RFC-compatible - mode. Right now it means that {{{unfold}}} will be turned on, - and if a {{{DTSTART}}} is found, it will be considered the first - recurrence instance, as documented in the RFC. - - ignoretz:: - If set to {{{True}}}, the date parser will ignore timezone - information available in the {{{DTSTART}}} property, or the - {{{UNTIL}}} attribute. - - tzinfos:: - If set, it will be passed to the datetime string parser to - resolve unknown timezone settings. For more information about - what could be used here, check the parser documentation. - -==== rrulestr() examples ==== - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """)) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Same thing, but passing only the {{{RRULE}}} value. -{{{ ->>> list(rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Notice that when using a single rule, it returns an -{{{rrule}}} instance, unless {{{forceset}}} was used. -{{{ ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5") - - ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """) - - ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", forceset=True) - -}}} - -But when an {{{rruleset}}} is needed, it is automatically used. -{{{ ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... RRULE:FREQ=DAILY;INTERVAL=5;COUNT=3 -... """) - -}}} - -=== parser === -This module offers a generic date/time string parser which is -able to parse most known formats to represent a date and/or -time. - -==== parse() function ==== -That's probably the only function you'll need from this module. -It offers you an interface to access the parser functionality and -extract a {{{datetime}}} type out of a string. - -The prototype of this function is: -{{{ -parse(timestr) -}}} - -Additionally, the following keyword arguments are available: - - default:: - If given, this must be a {{{datetime}}} instance. Any fields - missing in the parsed date will be copied from this instance. - The default value is the current date, at 00:00:00am. - - ignoretz:: - If this is true, even if a timezone is found in the string, - the parser will not use it. - - tzinfos:: - Using this keyword argument you may provide custom timezones - to the parser. If given, it must be either a dictionary with - the timezone abbreviation as key, or a function accepting a - timezone abbreviation and offset as argument. The dictionary - values and the function return must be a timezone offset - in seconds, a tzinfo subclass, or a string defining the - timezone (in the TZ environment variable format). - - dayfirst:: - This option allow one to change the precedence in which - days are parsed in date strings. The default is given in the - parserinfo instance (the default parserinfo has it set to - False). If {{{dayfirst}}} is False, the {{{MM-DD-YYYY}}} - format will have precedence over {{{DD-MM-YYYY}}} in an - ambiguous date. - - yearfirst:: - This option allow one to change the precedence in which - years are parsed in date strings. The default is given in - the parserinfo instance (the default parserinfo has it set - to False). If {{{yearfirst}}} is false, the {{{MM-DD-YY}}} - format will have precedence over {{{YY-MM-DD}}} in an - ambiguous date. - - fuzzy:: - If {{{fuzzy}}} is set to True, unknown tokens in the string - will be ignored. - - parserinfo:: - This parameter allows one to change how the string is parsed, - by using a different parserinfo class instance. Using it you - may, for example, intenationalize the parser strings, or make - it ignore additional words. - -==== Format precedence ==== -Whenever an ambiguous date is found, the {{{dayfirst}}} and -{{{yearfirst}}} parameters will control how the information -is processed. Here is the precedence in each case: - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{False}}}, -(default, if no parameter is given): - - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{False}}}: - - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - -==== Converting two digit years ==== -When a two digit year is found, it is processed considering -the current year, so that the computed year is never more -than 49 years after the current year, nor 50 years before the -current year. In other words, if we are in year 2003, and the -year 30 is found, it will be considered as 2030, but if the -year 60 is found, it will be considered 1960. - -==== Examples ==== -The following code will prepare the environment: -{{{ ->>> from dateutil.parser import * ->>> from dateutil.tz import * ->>> from datetime import * ->>> TZOFFSETS = {"BRST": -10800} ->>> BRSTTZ = tzoffset(-10800, "BRST") ->>> DEFAULT = datetime(2003, 9, 25) -}}} - -Some simple examples based on the {{{date}}} command, using the -{{{TZOFFSET}}} dictionary to provide the BRST timezone offset. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) - ->>> parse("2003 10:36:28 BRST 25 Sep Thu", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) -}}} - -Notice that since BRST is my local timezone, parsing it without -further timezone settings will yield a {{{tzlocal}}} timezone. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzlocal()) -}}} - -We can also ask to ignore the timezone explicitly: -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", ignoretz=True) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -That's the same as processing a string without timezone: -{{{ ->>> parse("Thu Sep 25 10:36:28 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Without the year, but passing our {{{DEFAULT}}} datetime to return -the same year, no mattering what year we currently are in: -{{{ ->>> parse("Thu Sep 25 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Strip it further: -{{{ ->>> parse("Thu Sep 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) - ->>> parse("10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) ->>> -}}} - -Strip in a different way: -{{{ ->>> parse("Thu Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Another format, based on {{{date -R}}} (RFC822): -{{{ ->>> parse("Thu, 25 Sep 2003 10:49:41 -0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -ISO format: -{{{ ->>> parse("2003-09-25T10:49:41.5-03:00") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzoffset(None, -10800)) -}}} - -Some variations: -{{{ ->>> parse("2003-09-25T10:49:41") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("2003-09-25T10:49") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("2003-09-25T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -ISO format, without separators: -{{{ ->>> parse("20030925T104941.5-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("20030925T1049") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("20030925T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("20030925") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Everything together. -{{{ ->>> parse("199709020900") -datetime.datetime(1997, 9, 2, 9, 0) ->>> parse("19970902090059") -datetime.datetime(1997, 9, 2, 9, 0, 59) -}}} - -Different date orderings: -{{{ ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003-Sep-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-Sep-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("09-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-09-2003") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Check some ambiguous dates: -{{{ ->>> parse("10-09-2003") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-2003", dayfirst=True) -datetime.datetime(2003, 9, 10, 0, 0) - ->>> parse("10-09-03") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-03", yearfirst=True) -datetime.datetime(2010, 9, 3, 0, 0) -}}} - -Other date separators are allowed: -{{{ ->>> parse("2003.Sep.25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003/09/25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Even with spaces: -{{{ ->>> parse("2003 Sep 25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003 09 25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Hours with letters work: -{{{ ->>> parse("10h36m28.5s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28, 500000) - ->>> parse("01s02h03m", default=DEFAULT) -datetime.datetime(2003, 9, 25, 2, 3, 1) - ->>> parse("01h02m03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 1, 2) - ->>> parse("01h02", default=DEFAULT) -datetime.datetime(2003, 9, 2, 1, 0) - ->>> parse("01h02s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 1, 0, 2) -}}} - -With AM/PM: -{{{ ->>> parse("10h am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("10pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 22, 0) - ->>> parse("12:00am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("12pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 12, 0) -}}} - -Some special treating for ''pertain'' relations: -{{{ ->>> parse("Sep 03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 0, 0) - ->>> parse("Sep of 03", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Fuzzy parsing: -{{{ ->>> s = "Today is 25 of September of 2003, exactly " \ -... "at 10:49:41 with timezone -03:00." ->>> parse(s, fuzzy=True) -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -Other random formats: -{{{ ->>> parse("Wed, July 10, '96") -datetime.datetime(1996, 7, 10, 0, 0) - ->>> parse("1996.07.10 AD at 15:08:56 PDT", ignoretz=True) -datetime.datetime(1996, 7, 10, 15, 8, 56) - ->>> parse("Tuesday, April 12, 1952 AD 3:30:42pm PST", ignoretz=True) -datetime.datetime(1952, 4, 12, 15, 30, 42) - ->>> parse("November 5, 1994, 8:15:30 am EST", ignoretz=True) -datetime.datetime(1994, 11, 5, 8, 15, 30) - ->>> parse("3rd of May 2001") -datetime.datetime(2001, 5, 3, 0, 0) - ->>> parse("5:50 A.M. on June 13, 1990") -datetime.datetime(1990, 6, 13, 5, 50) -}}} - -=== easter === -This module offers a generic easter computing method for -any given year, using Western, Orthodox or Julian algorithms. - -==== easter() function ==== -This method was ported from the work done by -[http://users.chariot.net.au/~gmarts/eastalg.htm GM Arts], -on top of the algorithm by -[http://www.tondering.dk/claus/calendar.html Claus Tondering], -which was based in part on the algorithm of Ouding (1940), -as quoted in "Explanatory Supplement to the Astronomical -Almanac", P. Kenneth Seidelmann, editor. - -This algorithm implements three different easter -calculation methods: - - 1. Original calculation in Julian calendar, valid in - dates after 326 AD - 1. Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 1. Revised method, in Gregorian calendar, valid in - years 1583 to 4099 as well - -These methods are represented by the constants: -{{{ -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 -}}} - -The default method is method 3. - -=== tz === -This module offers timezone implementations subclassing -the abstract {{{datetime.tzinfo}}} type. There are -classes to handle [http://www.twinsun.com/tz/tz-link.htm tzfile] -format files (usually are in /etc/localtime, -/usr/share/zoneinfo, etc), TZ environment string (in all -known formats), given ranges (with help from relative -deltas), local machine timezone, fixed offset timezone, -and UTC timezone. - -==== tzutc type ==== -This type implements a basic UTC timezone. The constructor of this -type accepts no parameters. - -==== tzutc examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now() -datetime.datetime(2003, 9, 27, 9, 40, 1, 521290) - ->>> datetime.now(tzutc()) -datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc()) - ->>> datetime.now(tzutc()).tzname() -'UTC' -}}} - -==== tzoffset type ==== -This type implements a fixed offset timezone, with no -support to daylight saving times. Here is the prototype of the -type constructor: -{{{ -tzoffset(name, offset) -}}} - -The {{{name}}} parameter may be optionally set to {{{None}}}, and -{{{offset}}} must be given in seconds. - -==== tzoffset examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzoffset("BRST", -10800)) -datetime.datetime(2003, 9, 27, 9, 52, 43, 624904, - tzinfo=tzinfo=tzoffset('BRST', -10800)) - ->>> datetime.now(tzoffset("BRST", -10800)).tzname() -'BRST' - ->>> datetime.now(tzoffset("BRST", -10800)).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 12, 53, 11, 446419, - tzinfo=tzutc()) -}}} - -==== tzlocal type ==== -This type implements timezone settings as known by the -operating system. The constructor of this type accepts no -parameters. - -==== tzlocal examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzlocal()) -datetime.datetime(2003, 9, 27, 10, 1, 43, 673605, - tzinfo=tzlocal()) - ->>> datetime.now(tzlocal()).tzname() -'BRST' - ->>> datetime.now(tzlocal()).astimezone(tzoffset(None, 0)) -datetime.datetime(2003, 9, 27, 13, 3, 0, 11493, - tzinfo=tzoffset(None, 0)) -}}} - -==== tzstr type ==== -This type implements timezone settings extracted from a -string in known TZ environment variable formats. Here is the prototype -of the constructor: -{{{ -tzstr(str) -}}} - -==== tzstr examples ==== -Here are examples of the recognized formats: - - * {{{EST5EDT}}} - * {{{EST5EDT,4,0,6,7200,10,0,26,7200,3600}}} - * {{{EST5EDT,4,1,0,7200,10,-1,0,7200,3600}}} - * {{{EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00}}} - * {{{EST5EDT4,95/02:00:00,298/02:00}}} - * {{{EST5EDT4,J96/02:00:00,J299/02:00}}} - -Notice that if daylight information is not present, but a -daylight abbreviation was provided, {{{tzstr}}} will follow the -convention of using the first sunday of April to start daylight -saving, and the last sunday of October to end it. If start or -end time is not present, 2AM will be used, and if the daylight -offset is not present, the standard offset plus one hour will -be used. This convention is the same as used in the GNU libc. - -This also means that some of the above examples are exactly -equivalent, and all of these examples are equivalent -in the year of 2003. - -Here is the example mentioned in the -[http://www.python.org/doc/current/lib/module-time.html time module documentation]. -{{{ ->>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'16:08:12 05/08/03 AEST' -}}} - -And here is an example showing the same information using {{{tzstr}}}, -without touching system settings. -{{{ ->>> tz1 = tzstr('EST+05EDT,M4.1.0,M10.5.0') ->>> tz2 = tzstr('AEST-10AEDT-11,M10.5.0,M3.5.0') ->>> dt = datetime(2003, 5, 8, 2, 7, 36, tzinfo=tz1) ->>> dt.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> dt.astimezone(tz2).strftime('%X %x %Z') -'16:07:36 05/08/03 AEST' -}}} - -Are these really equivalent? -{{{ ->>> tzstr('EST5EDT') == tzstr('EST5EDT,4,1,0,7200,10,-1,0,7200,3600') -True -}}} - -Check the daylight limit. -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzrange type ==== -This type offers the same functionality as the {{{tzstr}}} type, but -instead of timezone strings, information is passed using -{{{relativedelta}}}s which are applied to a datetime set to the first -day of the year. Here is the prototype of this type's constructor: -{{{ -tzrange(stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, - start=None, end=None): -}}} - -Offsets must be given in seconds. Information not provided will be -set to the defaults, as explained in the {{{tzstr}}} section above. - -==== tzrange examples ==== -{{{ ->>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT") -True - ->>> from dateutil.relativedelta import * ->>> range1 = tzrange("EST", -18000, "EDT") ->>> range2 = tzrange("EST", -18000, "EDT", -14400, -... relativedelta(hours=+2, month=4, day=1, - weekday=SU(+1)), -... relativedelta(hours=+1, month=10, day=31, - weekday=SU(-1))) ->>> tzstr('EST5EDT') == range1 == range2 -True -}}} - -Notice a minor detail in the last example: while the DST should end -at 2AM, the delta will catch 1AM. That's because the daylight saving -time should end at 2AM standard time (the difference between STD and -DST is 1h in the given example) instead of the DST time. That's how -the {{{tzinfo}}} subtypes should deal with the extra hour that happens -when going back to the standard time. Check -[http://www.python.org/doc/current/lib/datetime-tzinfo.html tzinfo documentation] -for more information. - -==== tzfile type ==== -This type allows one to use tzfile(5) format timezone files to extract -current and historical zone information. Here is the type constructor -prototype: -{{{ -tzfile(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzfile examples ==== -{{{ ->>> tz = tzfile("/etc/localtime") ->>> datetime.now(tz) -datetime.datetime(2003, 9, 27, 12, 3, 48, 392138, - tzinfo=tzfile('/etc/localtime')) - ->>> datetime.now(tz).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 15, 3, 53, 70863, - tzinfo=tzutc()) - ->>> datetime.now(tz).tzname() -'BRST' ->>> datetime(2003, 1, 1, tzinfo=tz).tzname() -'BRDT' -}}} - -Check the daylight limit. -{{{ ->>> tz = tzfile('/usr/share/zoneinfo/EST5EDT') ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzical type ==== -This type is able to parse -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] -style {{{VTIMEZONE}}} sessions into a Python timezone object. -The constuctor prototype is: -{{{ -tzical(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzical methods ==== - - tzical.get(tzid=None):: - Since a single iCalendar file may contain more than one timezone, - you must ask for the timezone you want with this method. If there's - more than one timezone in the parsed file, you'll need to pass the - {{{tzid}}} parameter. Otherwise, leaving it empty will yield the only - available timezone. - -==== tzical examples ==== -Here is a sample file extracted from the RFC. This file defines -the {{{EST5EDT}}} timezone, and will be used in the following example. -{{{ -BEGIN:VTIMEZONE -TZID:US-Eastern -LAST-MODIFIED:19870101T000000Z -TZURL:http://zones.stds_r_us.net/tz/US-Eastern -BEGIN:STANDARD -DTSTART:19671029T020000 -RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 -TZOFFSETFROM:-0400 -TZOFFSETTO:-0500 -TZNAME:EST -END:STANDARD -BEGIN:DAYLIGHT -DTSTART:19870405T020000 -RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 -TZOFFSETFROM:-0500 -TZOFFSETTO:-0400 -TZNAME:EDT -END:DAYLIGHT -END:VTIMEZONE -}}} - -And here is an example exploring a {{{tzical}}} type: -{{{ ->>> from dateutil.tz import *; from datetime import * - ->>> tz = tzical('EST5EDT.ics') ->>> tz.keys() -['US-Eastern'] - ->>> est = tz.get('US-Eastern') ->>> est - - ->>> datetime.now(est) -datetime.datetime(2003, 10, 6, 19, 44, 18, 667987, - tzinfo=) - ->>> est == tz.get() -True -}}} - -Let's check the daylight ranges, as usual: -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=est).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=est).tzname() -'EDT' - ->>> datetime(2003, 10, 26, 0, 59, tzinfo=est).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=est).tzname() -'EST' -}}} - -==== tzwin type ==== -This type offers access to internal registry-based Windows timezones. -The constuctor prototype is: -{{{ -tzwin(name) -}}} - -Where {{{name}}} is the timezone name. There's a static {{{tzwin.list()}}} -method to check the available names, - -==== tzwin methods ==== - - tzwin.display():: - This method returns the timezone extended name. - - tzwin.list():: - This static method lists all available timezone names. - -==== tzwin examples ==== -{{{ ->>> tz = tzwin("E. South America Standard Time") -}}} - -==== tzwinlocal type ==== -This type offers access to internal registry-based Windows timezones. -The constructor accepts no parameters, so the prototype is: -{{{ -tzwinlocal() -}}} - -==== tzwinlocal methods ==== - - tzwinlocal.display():: - This method returns the timezone extended name, and returns - {{{None}}} if one is not available. - -==== tzwinlocal examples ==== -{{{ ->>> tz = tzwinlocal() -}}} - -==== gettz() function ==== -This function is a helper that will try its best to get the right -timezone for your environment, or for the given string. The prototype -is as follows: -{{{ -gettz(name=None) -}}} - -If given, the parameter may be a filename, a path relative to the base -of the timezone information path (the base could be -{{{/usr/share/zoneinfo}}}, for example), a string timezone -specification, or a timezone abbreviation. If {{{name}}} is not given, -and the {{{TZ}}} environment variable is set, it's used instead. If the -parameter is not given, and {{{TZ}}} is not set, the default tzfile -paths will be tried. Then, if no timezone information is found, -an internal compiled database of timezones is used. When running -on Windows, the internal registry-based Windows timezones are also -considered. - -Example: -{{{ ->>> from dateutil.tz import * ->>> gettz() -tzfile('/etc/localtime') - ->>> gettz("America/Sao Paulo") -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> gettz("EST5EDT") -tzfile('/usr/share/zoneinfo/EST5EDT') - ->>> gettz("EST5") -tzstr('EST5') - ->>> gettz('BRST') -tzlocal() - ->>> os.environ["TZ"] = "America/Sao Paulo" ->>> gettz() -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> os.environ["TZ"] = "BRST" ->>> gettz() -tzlocal() - ->>> gettz("Unavailable") ->>> -}}} - -=== zoneinfo === -This module provides direct access to the internal compiled -database of timezones. The timezone data and the compiling tools -are obtained from the following project: - - http://www.twinsun.com/tz/tz-link.htm - -==== gettz() function ==== -This function will try to retrieve the given timezone information -from the internal compiled database, and will cache its results. - -Example: -{{{ ->>> from dateutil import zoneinfo ->>> zoneinfo.gettz("Brazil/East") -tzfile('Brazil/East') -}}} - -## vim:ft=moin diff --git a/lib/dateutil_py2/__init__.py b/lib/dateutil_py2/__init__.py deleted file mode 100644 index 44895a0d388e..000000000000 --- a/lib/dateutil_py2/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" -__version__ = "1.5-mpl" diff --git a/lib/dateutil_py2/easter.py b/lib/dateutil_py2/easter.py deleted file mode 100644 index d7944104beb1..000000000000 --- a/lib/dateutil_py2/easter.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime - -__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] - -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 - -def easter(year, method=EASTER_WESTERN): - """ - This method was ported from the work done by GM Arts, - on top of the algorithm by Claus Tondering, which was - based in part on the algorithm of Ouding (1940), as - quoted in "Explanatory Supplement to the Astronomical - Almanac", P. Kenneth Seidelmann, editor. - - This algorithm implements three different easter - calculation methods: - - 1 - Original calculation in Julian calendar, valid in - dates after 326 AD - 2 - Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 3 - Revised method, in Gregorian calendar, valid in - years 1583 to 4099 as well - - These methods are represented by the constants: - - EASTER_JULIAN = 1 - EASTER_ORTHODOX = 2 - EASTER_WESTERN = 3 - - The default method is method 3. - - More about the algorithm may be found at: - - http://users.chariot.net.au/~gmarts/eastalg.htm - - and - - http://www.tondering.dk/claus/calendar.html - - """ - - if not (1 <= method <= 3): - raise ValueError, "invalid method" - - # g - Golden year - 1 - # c - Century - # h - (23 - Epact) mod 30 - # i - Number of days from March 21 to Paschal Full Moon - # j - Weekday for PFM (0=Sunday, etc) - # p - Number of days from March 21 to Sunday on or before PFM - # (-6 to 28 methods 1 & 3, to 56 for method 2) - # e - Extra days to add for method 2 (converting Julian - # date to Gregorian date) - - y = year - g = y % 19 - e = 0 - if method < 3: - # Old method - i = (19*g+15)%30 - j = (y+y//4+i)%7 - if method == 2: - # Extra dates to convert Julian to Gregorian date - e = 10 - if y > 1600: - e = e+y//100-16-(y//100-16)//4 - else: - # New method - c = y//100 - h = (c-c//4-(8*c+13)//25+19*g+15)%30 - i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11)) - j = (y+y//4+i+2-c+c//4)%7 - - # p can be from -6 to 56 corresponding to dates 22 March to 23 May - # (later dates apply to method 2, although 23 May never actually occurs) - p = i-j+e - d = 1+(p+27+(p+6)//40)%31 - m = 3+(p+26)//30 - return datetime.date(int(y),int(m),int(d)) - diff --git a/lib/dateutil_py2/parser.py b/lib/dateutil_py2/parser.py deleted file mode 100644 index 5d824e411f32..000000000000 --- a/lib/dateutil_py2/parser.py +++ /dev/null @@ -1,886 +0,0 @@ -# -*- coding:iso-8859-1 -*- -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime -import string -import time -import sys -import os - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -import relativedelta -import tz - - -__all__ = ["parse", "parserinfo"] - - -# Some pointers: -# -# http://www.cl.cam.ac.uk/~mgk25/iso-time.html -# http://www.iso.ch/iso/en/prods-services/popstds/datesandtime.html -# http://www.w3.org/TR/NOTE-datetime -# http://ringmaster.arc.nasa.gov/tools/time_formats.html -# http://search.cpan.org/author/MUIR/Time-modules-2003.0211/lib/Time/ParseDate.pm -# http://stein.cshl.org/jade/distrib/docs/java.text.SimpleDateFormat.html - - -class _timelex(object): - - def __init__(self, instream): - if isinstance(instream, basestring): - instream = StringIO(instream) - self.instream = instream - self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' - 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' - 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ') - self.numchars = '0123456789' - self.whitespace = ' \t\r\n' - self.charstack = [] - self.tokenstack = [] - self.eof = False - - def get_token(self): - if self.tokenstack: - return self.tokenstack.pop(0) - seenletters = False - token = None - state = None - wordchars = self.wordchars - numchars = self.numchars - whitespace = self.whitespace - while not self.eof: - if self.charstack: - nextchar = self.charstack.pop(0) - else: - nextchar = self.instream.read(1) - while nextchar == '\x00': - nextchar = self.instream.read(1) - if not nextchar: - self.eof = True - break - elif not state: - token = nextchar - if nextchar in wordchars: - state = 'a' - elif nextchar in numchars: - state = '0' - elif nextchar in whitespace: - token = ' ' - break # emit token - else: - break # emit token - elif state == 'a': - seenletters = True - if nextchar in wordchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0': - if nextchar in numchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == 'a.': - seenletters = True - if nextchar == '.' or nextchar in wordchars: - token += nextchar - elif nextchar in numchars and token[-1] == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0.': - if nextchar == '.' or nextchar in numchars: - token += nextchar - elif nextchar in wordchars and token[-1] == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - if (state in ('a.', '0.') and - (seenletters or token.count('.') > 1 or token[-1] == '.')): - l = token.split('.') - token = l[0] - for tok in l[1:]: - self.tokenstack.append('.') - if tok: - self.tokenstack.append(tok) - return token - - def __iter__(self): - return self - - def next(self): - token = self.get_token() - if token is None: - raise StopIteration - return token - - def split(cls, s): - return list(cls(s)) - split = classmethod(split) - - -class _resultbase(object): - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def _repr(self, classname): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, `value`)) - return "%s(%s)" % (classname, ", ".join(l)) - - def __repr__(self): - return self._repr(self.__class__.__name__) - - -class parserinfo(object): - - # m from a.m/p.m, t from ISO T separator - JUMP = [" ", ".", ",", ";", "-", "/", "'", - "at", "on", "and", "ad", "m", "t", "of", - "st", "nd", "rd", "th"] - - WEEKDAYS = [("Mon", "Monday"), - ("Tue", "Tuesday"), - ("Wed", "Wednesday"), - ("Thu", "Thursday"), - ("Fri", "Friday"), - ("Sat", "Saturday"), - ("Sun", "Sunday")] - MONTHS = [("Jan", "January"), - ("Feb", "February"), - ("Mar", "March"), - ("Apr", "April"), - ("May", "May"), - ("Jun", "June"), - ("Jul", "July"), - ("Aug", "August"), - ("Sep", "September"), - ("Oct", "October"), - ("Nov", "November"), - ("Dec", "December")] - HMS = [("h", "hour", "hours"), - ("m", "minute", "minutes"), - ("s", "second", "seconds")] - AMPM = [("am", "a"), - ("pm", "p")] - UTCZONE = ["UTC", "GMT", "Z"] - PERTAIN = ["of"] - TZOFFSET = {} - - def __init__(self, dayfirst=False, yearfirst=False): - self._jump = self._convert(self.JUMP) - self._weekdays = self._convert(self.WEEKDAYS) - self._months = self._convert(self.MONTHS) - self._hms = self._convert(self.HMS) - self._ampm = self._convert(self.AMPM) - self._utczone = self._convert(self.UTCZONE) - self._pertain = self._convert(self.PERTAIN) - - self.dayfirst = dayfirst - self.yearfirst = yearfirst - - self._year = time.localtime().tm_year - self._century = self._year//100*100 - - def _convert(self, lst): - dct = {} - for i in range(len(lst)): - v = lst[i] - if isinstance(v, tuple): - for v in v: - dct[v.lower()] = i - else: - dct[v.lower()] = i - return dct - - def jump(self, name): - return name.lower() in self._jump - - def weekday(self, name): - if len(name) >= 3: - try: - return self._weekdays[name.lower()] - except KeyError: - pass - return None - - def month(self, name): - if len(name) >= 3: - try: - return self._months[name.lower()]+1 - except KeyError: - pass - return None - - def hms(self, name): - try: - return self._hms[name.lower()] - except KeyError: - return None - - def ampm(self, name): - try: - return self._ampm[name.lower()] - except KeyError: - return None - - def pertain(self, name): - return name.lower() in self._pertain - - def utczone(self, name): - return name.lower() in self._utczone - - def tzoffset(self, name): - if name in self._utczone: - return 0 - return self.TZOFFSET.get(name) - - def convertyear(self, year): - if year < 100: - year += self._century - if abs(year-self._year) >= 50: - if year < self._year: - year += 100 - else: - year -= 100 - return year - - def validate(self, res): - # move to info - if res.year is not None: - res.year = self.convertyear(res.year) - if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z': - res.tzname = "UTC" - res.tzoffset = 0 - elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): - res.tzoffset = 0 - return True - - -class parser(object): - - def __init__(self, info=None): - self.info = info or parserinfo() - - def parse(self, timestr, default=None, - ignoretz=False, tzinfos=None, - **kwargs): - if not default: - default = datetime.datetime.now().replace(hour=0, minute=0, - second=0, microsecond=0) - res = self._parse(timestr, **kwargs) - if res is None: - raise ValueError, "unknown string format" - repl = {} - for attr in ["year", "month", "day", "hour", - "minute", "second", "microsecond"]: - value = getattr(res, attr) - if value is not None: - repl[attr] = value - ret = default.replace(**repl) - if res.weekday is not None and not res.day: - ret = ret+relativedelta.relativedelta(weekday=res.weekday) - if not ignoretz: - if callable(tzinfos) or tzinfos and res.tzname in tzinfos: - if callable(tzinfos): - tzdata = tzinfos(res.tzname, res.tzoffset) - else: - tzdata = tzinfos.get(res.tzname) - if isinstance(tzdata, datetime.tzinfo): - tzinfo = tzdata - elif isinstance(tzdata, basestring): - tzinfo = tz.tzstr(tzdata) - elif isinstance(tzdata, int): - tzinfo = tz.tzoffset(res.tzname, tzdata) - else: - raise ValueError, "offset must be tzinfo subclass, " \ - "tz string, or int offset" - ret = ret.replace(tzinfo=tzinfo) - elif res.tzname and res.tzname in time.tzname: - ret = ret.replace(tzinfo=tz.tzlocal()) - elif res.tzoffset == 0: - ret = ret.replace(tzinfo=tz.tzutc()) - elif res.tzoffset: - ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) - return ret - - class _result(_resultbase): - __slots__ = ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond", - "tzname", "tzoffset"] - - def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False): - info = self.info - if dayfirst is None: - dayfirst = info.dayfirst - if yearfirst is None: - yearfirst = info.yearfirst - res = self._result() - l = _timelex.split(timestr) - try: - - # year/month/day list - ymd = [] - - # Index of the month string in ymd - mstridx = -1 - - len_l = len(l) - i = 0 - while i < len_l: - - # Check if it's a number - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - value = None - - if value is not None: - # Token is a number - len_li = len(l[i]) - i += 1 - if (len(ymd) == 3 and len_li in (2, 4) - and (i >= len_l or (l[i] != ':' and - info.hms(l[i]) is None))): - # 19990101T23[59] - s = l[i-1] - res.hour = int(s[:2]) - if len_li == 4: - res.minute = int(s[2:]) - elif len_li == 6 or (len_li > 6 and l[i-1].find('.') == 6): - # YYMMDD or HHMMSS[.ss] - s = l[i-1] - if not ymd and l[i-1].find('.') == -1: - ymd.append(info.convertyear(int(s[:2]))) - ymd.append(int(s[2:4])) - ymd.append(int(s[4:])) - else: - # 19990101T235959[.59] - res.hour = int(s[:2]) - res.minute = int(s[2:4]) - res.second, res.microsecond = _parsems(s[4:]) - elif len_li == 8: - # YYYYMMDD - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:])) - elif len_li in (12, 14): - # YYYYMMDDhhmm[ss] - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:8])) - res.hour = int(s[8:10]) - res.minute = int(s[10:12]) - if len_li == 14: - res.second = int(s[12:]) - elif ((i < len_l and info.hms(l[i]) is not None) or - (i+1 < len_l and l[i] == ' ' and - info.hms(l[i+1]) is not None)): - # HH[ ]h or MM[ ]m or SS[.ss][ ]s - if l[i] == ' ': - i += 1 - idx = info.hms(l[i]) - while True: - if idx == 0: - res.hour = int(value) - if value%1: - res.minute = int(60*(value%1)) - elif idx == 1: - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - elif idx == 2: - res.second, res.microsecond = \ - _parsems(value_repr) - i += 1 - if i >= len_l or idx == 2: - break - # 12h00 - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - break - else: - i += 1 - idx += 1 - if i < len_l: - newidx = info.hms(l[i]) - if newidx is not None: - idx = newidx - elif i+1 < len_l and l[i] == ':': - # HH:MM[:SS[.ss]] - res.hour = int(value) - i += 1 - value = float(l[i]) - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - i += 1 - if i < len_l and l[i] == ':': - res.second, res.microsecond = _parsems(l[i+1]) - i += 2 - elif i < len_l and l[i] in ('-', '/', '.'): - sep = l[i] - ymd.append(int(value)) - i += 1 - if i < len_l and not info.jump(l[i]): - try: - # 01-01[-01] - ymd.append(int(l[i])) - except ValueError: - # 01-Jan[-01] - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - else: - return None - i += 1 - if i < len_l and l[i] == sep: - # We have three members - i += 1 - value = info.month(l[i]) - if value is not None: - ymd.append(value) - mstridx = len(ymd)-1 - assert mstridx == -1 - else: - ymd.append(int(l[i])) - i += 1 - elif i >= len_l or info.jump(l[i]): - if i+1 < len_l and info.ampm(l[i+1]) is not None: - # 12 am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i+1]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i+1]) == 0: - res.hour = 0 - i += 1 - else: - # Year, month or day - ymd.append(int(value)) - i += 1 - elif info.ampm(l[i]) is not None: - # 12am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i]) == 0: - res.hour = 0 - i += 1 - elif not fuzzy: - return None - else: - i += 1 - continue - - # Check weekday - value = info.weekday(l[i]) - if value is not None: - res.weekday = value - i += 1 - continue - - # Check month name - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - i += 1 - if i < len_l: - if l[i] in ('-', '/'): - # Jan-01[-99] - sep = l[i] - i += 1 - ymd.append(int(l[i])) - i += 1 - if i < len_l and l[i] == sep: - # Jan-01-99 - i += 1 - ymd.append(int(l[i])) - i += 1 - elif (i+3 < len_l and l[i] == l[i+2] == ' ' - and info.pertain(l[i+1])): - # Jan of 01 - # In this case, 01 is clearly year - try: - value = int(l[i+3]) - except ValueError: - # Wrong guess - pass - else: - # Convert it here to become unambiguous - ymd.append(info.convertyear(value)) - i += 4 - continue - - # Check am/pm - value = info.ampm(l[i]) - if value is not None: - if value == 1 and res.hour < 12: - res.hour += 12 - elif value == 0 and res.hour == 12: - res.hour = 0 - i += 1 - continue - - # Check for a timezone name - if (res.hour is not None and len(l[i]) <= 5 and - res.tzname is None and res.tzoffset is None and - not [x for x in l[i] if x not in string.ascii_uppercase]): - res.tzname = l[i] - res.tzoffset = info.tzoffset(res.tzname) - i += 1 - - # Check for something like GMT+3, or BRST+3. Notice - # that it doesn't mean "I am 3 hours after GMT", but - # "my time +3 is GMT". If found, we reverse the - # logic so that timezone parsing code will get it - # right. - if i < len_l and l[i] in ('+', '-'): - l[i] = ('+', '-')[l[i] == '+'] - res.tzoffset = None - if info.utczone(res.tzname): - # With something like GMT+3, the timezone - # is *not* GMT. - res.tzname = None - - continue - - # Check for a numbered timezone - if res.hour is not None and l[i] in ('+', '-'): - signal = (-1,1)[l[i] == '+'] - i += 1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - res.tzoffset = int(l[i][:2])*3600+int(l[i][2:])*60 - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - res.tzoffset = int(l[i])*3600+int(l[i+2])*60 - i += 2 - elif len_li <= 2: - # -[0]3 - res.tzoffset = int(l[i][:2])*3600 - else: - return None - i += 1 - res.tzoffset *= signal - - # Look for a timezone name between parenthesis - if (i+3 < len_l and - info.jump(l[i]) and l[i+1] == '(' and l[i+3] == ')' and - 3 <= len(l[i+2]) <= 5 and - not [x for x in l[i+2] - if x not in string.ascii_uppercase]): - # -0300 (BRST) - res.tzname = l[i+2] - i += 4 - continue - - # Check jumps - if not (info.jump(l[i]) or fuzzy): - return None - - i += 1 - - # Process year/month/day - len_ymd = len(ymd) - if len_ymd > 3: - # More than three members!? - return None - elif len_ymd == 1 or (mstridx != -1 and len_ymd == 2): - # One member, or two members with a month string - if mstridx != -1: - res.month = ymd[mstridx] - del ymd[mstridx] - if len_ymd > 1 or mstridx == -1: - if ymd[0] > 31: - res.year = ymd[0] - else: - res.day = ymd[0] - elif len_ymd == 2: - # Two members with numbers - if ymd[0] > 31: - # 99-01 - res.year, res.month = ymd - elif ymd[1] > 31: - # 01-99 - res.month, res.year = ymd - elif dayfirst and ymd[1] <= 12: - # 13-01 - res.day, res.month = ymd - else: - # 01-13 - res.month, res.day = ymd - if len_ymd == 3: - # Three members - if mstridx == 0: - res.month, res.day, res.year = ymd - elif mstridx == 1: - if ymd[0] > 31 or (yearfirst and ymd[2] <= 31): - # 99-Jan-01 - res.year, res.month, res.day = ymd - else: - # 01-Jan-01 - # Give precendence to day-first, since - # two-digit years is usually hand-written. - res.day, res.month, res.year = ymd - elif mstridx == 2: - # WTF!? - if ymd[1] > 31: - # 01-99-Jan - res.day, res.year, res.month = ymd - else: - # 99-01-Jan - res.year, res.day, res.month = ymd - else: - if ymd[0] > 31 or \ - (yearfirst and ymd[1] <= 12 and ymd[2] <= 31): - # 99-01-01 - res.year, res.month, res.day = ymd - elif ymd[0] > 12 or (dayfirst and ymd[1] <= 12): - # 13-01-01 - res.day, res.month, res.year = ymd - else: - # 01-13-01 - res.month, res.day, res.year = ymd - - except (IndexError, ValueError, AssertionError): - return None - - if not info.validate(res): - return None - return res - -DEFAULTPARSER = parser() -def parse(timestr, parserinfo=None, **kwargs): - if parserinfo: - return parser(parserinfo).parse(timestr, **kwargs) - else: - return DEFAULTPARSER.parse(timestr, **kwargs) - - -class _tzparser(object): - - class _result(_resultbase): - - __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset", - "start", "end"] - - class _attr(_resultbase): - __slots__ = ["month", "week", "weekday", - "yday", "jyday", "day", "time"] - - def __repr__(self): - return self._repr("") - - def __init__(self): - _resultbase.__init__(self) - self.start = self._attr() - self.end = self._attr() - - def parse(self, tzstr): - res = self._result() - l = _timelex.split(tzstr) - try: - - len_l = len(l) - - i = 0 - while i < len_l: - # BRST+3[BRDT[+2]] - j = i - while j < len_l and not [x for x in l[j] - if x in "0123456789:,-+"]: - j += 1 - if j != i: - if not res.stdabbr: - offattr = "stdoffset" - res.stdabbr = "".join(l[i:j]) - else: - offattr = "dstoffset" - res.dstabbr = "".join(l[i:j]) - i = j - if (i < len_l and - (l[i] in ('+', '-') or l[i][0] in "0123456789")): - if l[i] in ('+', '-'): - # Yes, that's right. See the TZ variable - # documentation. - signal = (1,-1)[l[i] == '+'] - i += 1 - else: - signal = -1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - setattr(res, offattr, - (int(l[i][:2])*3600+int(l[i][2:])*60)*signal) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - setattr(res, offattr, - (int(l[i])*3600+int(l[i+2])*60)*signal) - i += 2 - elif len_li <= 2: - # -[0]3 - setattr(res, offattr, - int(l[i][:2])*3600*signal) - else: - return None - i += 1 - if res.dstabbr: - break - else: - break - - if i < len_l: - for j in range(i, len_l): - if l[j] == ';': l[j] = ',' - - assert l[i] == ',' - - i += 1 - - if i >= len_l: - pass - elif (8 <= l.count(',') <= 9 and - not [y for x in l[i:] if x != ',' - for y in x if y not in "0123456789"]): - # GMT0BST,3,0,30,3600,10,0,26,7200[,3600] - for x in (res.start, res.end): - x.month = int(l[i]) - i += 2 - if l[i] == '-': - value = int(l[i+1])*-1 - i += 1 - else: - value = int(l[i]) - i += 2 - if value: - x.week = value - x.weekday = (int(l[i])-1)%7 - else: - x.day = int(l[i]) - i += 2 - x.time = int(l[i]) - i += 2 - if i < len_l: - if l[i] in ('-','+'): - signal = (-1,1)[l[i] == "+"] - i += 1 - else: - signal = 1 - res.dstoffset = (res.stdoffset+int(l[i]))*signal - elif (l.count(',') == 2 and l[i:].count('/') <= 2 and - not [y for x in l[i:] if x not in (',','/','J','M', - '.','-',':') - for y in x if y not in "0123456789"]): - for x in (res.start, res.end): - if l[i] == 'J': - # non-leap year day (1 based) - i += 1 - x.jyday = int(l[i]) - elif l[i] == 'M': - # month[-.]week[-.]weekday - i += 1 - x.month = int(l[i]) - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.week = int(l[i]) - if x.week == 5: - x.week = -1 - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.weekday = (int(l[i])-1)%7 - else: - # year day (zero based) - x.yday = int(l[i])+1 - - i += 1 - - if i < len_l and l[i] == '/': - i += 1 - # start time - len_li = len(l[i]) - if len_li == 4: - # -0300 - x.time = (int(l[i][:2])*3600+int(l[i][2:])*60) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - x.time = int(l[i])*3600+int(l[i+2])*60 - i += 2 - if i+1 < len_l and l[i+1] == ':': - i += 2 - x.time += int(l[i]) - elif len_li <= 2: - # -[0]3 - x.time = (int(l[i][:2])*3600) - else: - return None - i += 1 - - assert i == len_l or l[i] == ',' - - i += 1 - - assert i >= len_l - - except (IndexError, ValueError, AssertionError): - return None - - return res - - -DEFAULTTZPARSER = _tzparser() -def _parsetz(tzstr): - return DEFAULTTZPARSER.parse(tzstr) - - -def _parsems(value): - """Parse a I[.F] seconds value into (seconds, microseconds).""" - if "." not in value: - return int(value), 0 - else: - i, f = value.split(".") - return int(i), int(f.ljust(6, "0")[:6]) - - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/relativedelta.py b/lib/dateutil_py2/relativedelta.py deleted file mode 100644 index 0c72a8180fb7..000000000000 --- a/lib/dateutil_py2/relativedelta.py +++ /dev/null @@ -1,432 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime -import calendar - -__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class relativedelta: - """ -The relativedelta type is based on the specification of the excelent -work done by M.-A. Lemburg in his mx.DateTime extension. However, -notice that this type does *NOT* implement the same algorithm as -his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. - -There's two different ways to build a relativedelta instance. The -first one is passing it two date/datetime classes: - - relativedelta(datetime1, datetime2) - -And the other way is to use the following keyword arguments: - - year, month, day, hour, minute, second, microsecond: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds: - Relative information, may be negative. - - weekday: - One of the weekday instances (MO, TU, etc). These instances may - receive a parameter N, specifying the Nth weekday, which could - be positive or negative (like MO(+1) or MO(-2). Not specifying - it is the same as specifying +1. You can also use an integer, - where 0=MO. - - leapdays: - Will add given days to the date found, if year is a leap - year, and the date found is post 28 of february. - - yearday, nlyearday: - Set the yearday or the non-leap year day (jump leap days). - These are converted to day/month/leapdays information. - -Here is the behavior of operations with relativedelta: - -1) Calculate the absolute year, using the 'year' argument, or the - original datetime year, if the argument is not present. - -2) Add the relative 'years' argument to the absolute year. - -3) Do steps 1 and 2 for month/months. - -4) Calculate the absolute day, using the 'day' argument, or the - original datetime day, if the argument is not present. Then, - subtract from the day until it fits in the year and month - found after their operations. - -5) Add the relative 'days' argument to the absolute day. Notice - that the 'weeks' argument is multiplied by 7 and added to - 'days'. - -6) Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, - microsecond/microseconds. - -7) If the 'weekday' argument is present, calculate the weekday, - with the given (wday, nth) tuple. wday is the index of the - weekday (0-6, 0=Mon), and nth is the number of weeks to add - forward or backward, depending on its signal. Notice that if - the calculated date is already Monday, for example, using - (0, 1) or (0, -1) won't change the day. - """ - - def __init__(self, dt1=None, dt2=None, - years=0, months=0, days=0, leapdays=0, weeks=0, - hours=0, minutes=0, seconds=0, microseconds=0, - year=None, month=None, day=None, weekday=None, - yearday=None, nlyearday=None, - hour=None, minute=None, second=None, microsecond=None): - if dt1 and dt2: - if not isinstance(dt1, datetime.date) or \ - not isinstance(dt2, datetime.date): - raise TypeError, "relativedelta only diffs datetime/date" - if type(dt1) is not type(dt2): - if not isinstance(dt1, datetime.datetime): - dt1 = datetime.datetime.fromordinal(dt1.toordinal()) - elif not isinstance(dt2, datetime.datetime): - dt2 = datetime.datetime.fromordinal(dt2.toordinal()) - self.years = 0 - self.months = 0 - self.days = 0 - self.leapdays = 0 - self.hours = 0 - self.minutes = 0 - self.seconds = 0 - self.microseconds = 0 - self.year = None - self.month = None - self.day = None - self.weekday = None - self.hour = None - self.minute = None - self.second = None - self.microsecond = None - self._has_time = 0 - - months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month) - self._set_months(months) - dtm = self.__radd__(dt2) - if dt1 < dt2: - while dt1 > dtm: - months += 1 - self._set_months(months) - dtm = self.__radd__(dt2) - else: - while dt1 < dtm: - months -= 1 - self._set_months(months) - dtm = self.__radd__(dt2) - delta = dt1 - dtm - self.seconds = delta.seconds+delta.days*86400 - self.microseconds = delta.microseconds - else: - self.years = years - self.months = months - self.days = days+weeks*7 - self.leapdays = leapdays - self.hours = hours - self.minutes = minutes - self.seconds = seconds - self.microseconds = microseconds - self.year = year - self.month = month - self.day = day - self.hour = hour - self.minute = minute - self.second = second - self.microsecond = microsecond - - if type(weekday) is int: - self.weekday = weekdays[weekday] - else: - self.weekday = weekday - - yday = 0 - if nlyearday: - yday = nlyearday - elif yearday: - yday = yearday - if yearday > 59: - self.leapdays = -1 - if yday: - ydayidx = [31,59,90,120,151,181,212,243,273,304,334,366] - for idx, ydays in enumerate(ydayidx): - if yday <= ydays: - self.month = idx+1 - if idx == 0: - self.day = yday - else: - self.day = yday-ydayidx[idx-1] - break - else: - raise ValueError, "invalid year day (%d)" % yday - - self._fix() - - def _fix(self): - if abs(self.microseconds) > 999999: - s = self.microseconds//abs(self.microseconds) - div, mod = divmod(self.microseconds*s, 1000000) - self.microseconds = mod*s - self.seconds += div*s - if abs(self.seconds) > 59: - s = self.seconds//abs(self.seconds) - div, mod = divmod(self.seconds*s, 60) - self.seconds = mod*s - self.minutes += div*s - if abs(self.minutes) > 59: - s = self.minutes//abs(self.minutes) - div, mod = divmod(self.minutes*s, 60) - self.minutes = mod*s - self.hours += div*s - if abs(self.hours) > 23: - s = self.hours//abs(self.hours) - div, mod = divmod(self.hours*s, 24) - self.hours = mod*s - self.days += div*s - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years += div*s - if (self.hours or self.minutes or self.seconds or self.microseconds or - self.hour is not None or self.minute is not None or - self.second is not None or self.microsecond is not None): - self._has_time = 1 - else: - self._has_time = 0 - - def _set_months(self, months): - self.months = months - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years = div*s - else: - self.years = 0 - - def __radd__(self, other): - if not isinstance(other, datetime.date): - raise TypeError, "unsupported type for add operation" - elif self._has_time and not isinstance(other, datetime.datetime): - other = datetime.datetime.fromordinal(other.toordinal()) - year = (self.year or other.year)+self.years - month = self.month or other.month - if self.months: - assert 1 <= abs(self.months) <= 12 - month += self.months - if month > 12: - year += 1 - month -= 12 - elif month < 1: - year -= 1 - month += 12 - day = min(calendar.monthrange(year, month)[1], - self.day or other.day) - repl = {"year": year, "month": month, "day": day} - for attr in ["hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - repl[attr] = value - days = self.days - if self.leapdays and month > 2 and calendar.isleap(year): - days += self.leapdays - ret = (other.replace(**repl) - + datetime.timedelta(days=days, - hours=self.hours, - minutes=self.minutes, - seconds=self.seconds, - microseconds=self.microseconds)) - if self.weekday: - weekday, nth = self.weekday.weekday, self.weekday.n or 1 - jumpdays = (abs(nth)-1)*7 - if nth > 0: - jumpdays += (7-ret.weekday()+weekday)%7 - else: - jumpdays += (ret.weekday()-weekday)%7 - jumpdays *= -1 - ret += datetime.timedelta(days=jumpdays) - return ret - - def __rsub__(self, other): - return self.__neg__().__radd__(other) - - def __add__(self, other): - if not isinstance(other, relativedelta): - raise TypeError, "unsupported type for add operation" - return relativedelta(years=other.years+self.years, - months=other.months+self.months, - days=other.days+self.days, - hours=other.hours+self.hours, - minutes=other.minutes+self.minutes, - seconds=other.seconds+self.seconds, - microseconds=other.microseconds+self.microseconds, - leapdays=other.leapdays or self.leapdays, - year=other.year or self.year, - month=other.month or self.month, - day=other.day or self.day, - weekday=other.weekday or self.weekday, - hour=other.hour or self.hour, - minute=other.minute or self.minute, - second=other.second or self.second, - microsecond=other.second or self.microsecond) - - def __sub__(self, other): - if not isinstance(other, relativedelta): - raise TypeError, "unsupported type for sub operation" - return relativedelta(years=other.years-self.years, - months=other.months-self.months, - days=other.days-self.days, - hours=other.hours-self.hours, - minutes=other.minutes-self.minutes, - seconds=other.seconds-self.seconds, - microseconds=other.microseconds-self.microseconds, - leapdays=other.leapdays or self.leapdays, - year=other.year or self.year, - month=other.month or self.month, - day=other.day or self.day, - weekday=other.weekday or self.weekday, - hour=other.hour or self.hour, - minute=other.minute or self.minute, - second=other.second or self.second, - microsecond=other.second or self.microsecond) - - def __neg__(self): - return relativedelta(years=-self.years, - months=-self.months, - days=-self.days, - hours=-self.hours, - minutes=-self.minutes, - seconds=-self.seconds, - microseconds=-self.microseconds, - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - def __nonzero__(self): - return not (not self.years and - not self.months and - not self.days and - not self.hours and - not self.minutes and - not self.seconds and - not self.microseconds and - not self.leapdays and - self.year is None and - self.month is None and - self.day is None and - self.weekday is None and - self.hour is None and - self.minute is None and - self.second is None and - self.microsecond is None) - - def __mul__(self, other): - f = float(other) - return relativedelta(years=self.years*f, - months=self.months*f, - days=self.days*f, - hours=self.hours*f, - minutes=self.minutes*f, - seconds=self.seconds*f, - microseconds=self.microseconds*f, - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - def __eq__(self, other): - if not isinstance(other, relativedelta): - return False - if self.weekday or other.weekday: - if not self.weekday or not other.weekday: - return False - if self.weekday.weekday != other.weekday.weekday: - return False - n1, n2 = self.weekday.n, other.weekday.n - if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): - return False - return (self.years == other.years and - self.months == other.months and - self.days == other.days and - self.hours == other.hours and - self.minutes == other.minutes and - self.seconds == other.seconds and - self.leapdays == other.leapdays and - self.year == other.year and - self.month == other.month and - self.day == other.day and - self.hour == other.hour and - self.minute == other.minute and - self.second == other.second and - self.microsecond == other.microsecond) - - def __ne__(self, other): - return not self.__eq__(other) - - def __div__(self, other): - return self.__mul__(1/float(other)) - - def __repr__(self): - l = [] - for attr in ["years", "months", "days", "leapdays", - "hours", "minutes", "seconds", "microseconds"]: - value = getattr(self, attr) - if value: - l.append("%s=%+d" % (attr, value)) - for attr in ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, `value`)) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/rrule.py b/lib/dateutil_py2/rrule.py deleted file mode 100644 index 6bd83cad3722..000000000000 --- a/lib/dateutil_py2/rrule.py +++ /dev/null @@ -1,1097 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import itertools -import datetime -import calendar -import thread -import sys - -__all__ = ["rrule", "rruleset", "rrulestr", - "YEARLY", "MONTHLY", "WEEKLY", "DAILY", - "HOURLY", "MINUTELY", "SECONDLY", - "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -# Every mask is 7 days longer to handle cross-year weekly periods. -M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+ - [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7) -M365MASK = list(M366MASK) -M29, M30, M31 = range(1,30), range(1,31), range(1,32) -MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -MDAY365MASK = list(MDAY366MASK) -M29, M30, M31 = range(-29,0), range(-30,0), range(-31,0) -NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -NMDAY365MASK = list(NMDAY366MASK) -M366RANGE = (0,31,60,91,121,152,182,213,244,274,305,335,366) -M365RANGE = (0,31,59,90,120,151,181,212,243,273,304,334,365) -WDAYMASK = [0,1,2,3,4,5,6]*55 -del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31] -MDAY365MASK = tuple(MDAY365MASK) -M365MASK = tuple(M365MASK) - -(YEARLY, - MONTHLY, - WEEKLY, - DAILY, - HOURLY, - MINUTELY, - SECONDLY) = range(7) - -# Imported on demand. -easter = None -parser = None - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - if n == 0: - raise ValueError, "Can't create weekday with n == 0" - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class rrulebase: - def __init__(self, cache=False): - if cache: - self._cache = [] - self._cache_lock = thread.allocate_lock() - self._cache_gen = self._iter() - self._cache_complete = False - else: - self._cache = None - self._cache_complete = False - self._len = None - - def __iter__(self): - if self._cache_complete: - return iter(self._cache) - elif self._cache is None: - return self._iter() - else: - return self._iter_cached() - - def _iter_cached(self): - i = 0 - gen = self._cache_gen - cache = self._cache - acquire = self._cache_lock.acquire - release = self._cache_lock.release - while gen: - if i == len(cache): - acquire() - if self._cache_complete: - break - try: - for j in range(10): - cache.append(gen.next()) - except StopIteration: - self._cache_gen = gen = None - self._cache_complete = True - break - release() - yield cache[i] - i += 1 - while i < self._len: - yield cache[i] - i += 1 - - def __getitem__(self, item): - if self._cache_complete: - return self._cache[item] - elif isinstance(item, slice): - if item.step and item.step < 0: - return list(iter(self))[item] - else: - return list(itertools.islice(self, - item.start or 0, - item.stop or sys.maxint, - item.step or 1)) - elif item >= 0: - gen = iter(self) - try: - for i in range(item+1): - res = gen.next() - except StopIteration: - raise IndexError - return res - else: - return list(iter(self))[item] - - def __contains__(self, item): - if self._cache_complete: - return item in self._cache - else: - for i in self: - if i == item: - return True - elif i > item: - return False - return False - - # __len__() introduces a large performance penality. - def count(self): - if self._len is None: - for x in self: pass - return self._len - - def before(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - last = None - if inc: - for i in gen: - if i > dt: - break - last = i - else: - for i in gen: - if i >= dt: - break - last = i - return last - - def after(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - if inc: - for i in gen: - if i >= dt: - return i - else: - for i in gen: - if i > dt: - return i - return None - - def between(self, after, before, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - started = False - l = [] - if inc: - for i in gen: - if i > before: - break - elif not started: - if i >= after: - started = True - l.append(i) - else: - l.append(i) - else: - for i in gen: - if i >= before: - break - elif not started: - if i > after: - started = True - l.append(i) - else: - l.append(i) - return l - -class rrule(rrulebase): - def __init__(self, freq, dtstart=None, - interval=1, wkst=None, count=None, until=None, bysetpos=None, - bymonth=None, bymonthday=None, byyearday=None, byeaster=None, - byweekno=None, byweekday=None, - byhour=None, byminute=None, bysecond=None, - cache=False): - rrulebase.__init__(self, cache) - global easter - if not dtstart: - dtstart = datetime.datetime.now().replace(microsecond=0) - elif not isinstance(dtstart, datetime.datetime): - dtstart = datetime.datetime.fromordinal(dtstart.toordinal()) - else: - dtstart = dtstart.replace(microsecond=0) - self._dtstart = dtstart - self._tzinfo = dtstart.tzinfo - self._freq = freq - self._interval = interval - self._count = count - if until and not isinstance(until, datetime.datetime): - until = datetime.datetime.fromordinal(until.toordinal()) - self._until = until - if wkst is None: - self._wkst = calendar.firstweekday() - elif type(wkst) is int: - self._wkst = wkst - else: - self._wkst = wkst.weekday - if bysetpos is None: - self._bysetpos = None - elif type(bysetpos) is int: - if bysetpos == 0 or not (-366 <= bysetpos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - self._bysetpos = (bysetpos,) - else: - self._bysetpos = tuple(bysetpos) - for pos in self._bysetpos: - if pos == 0 or not (-366 <= pos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - if not (byweekno or byyearday or bymonthday or - byweekday is not None or byeaster is not None): - if freq == YEARLY: - if not bymonth: - bymonth = dtstart.month - bymonthday = dtstart.day - elif freq == MONTHLY: - bymonthday = dtstart.day - elif freq == WEEKLY: - byweekday = dtstart.weekday() - # bymonth - if not bymonth: - self._bymonth = None - elif type(bymonth) is int: - self._bymonth = (bymonth,) - else: - self._bymonth = tuple(bymonth) - # byyearday - if not byyearday: - self._byyearday = None - elif type(byyearday) is int: - self._byyearday = (byyearday,) - else: - self._byyearday = tuple(byyearday) - # byeaster - if byeaster is not None: - if not easter: - from dateutil import easter - if type(byeaster) is int: - self._byeaster = (byeaster,) - else: - self._byeaster = tuple(byeaster) - else: - self._byeaster = None - # bymonthay - if not bymonthday: - self._bymonthday = () - self._bynmonthday = () - elif type(bymonthday) is int: - if bymonthday < 0: - self._bynmonthday = (bymonthday,) - self._bymonthday = () - else: - self._bymonthday = (bymonthday,) - self._bynmonthday = () - else: - self._bymonthday = tuple([x for x in bymonthday if x > 0]) - self._bynmonthday = tuple([x for x in bymonthday if x < 0]) - # byweekno - if byweekno is None: - self._byweekno = None - elif type(byweekno) is int: - self._byweekno = (byweekno,) - else: - self._byweekno = tuple(byweekno) - # byweekday / bynweekday - if byweekday is None: - self._byweekday = None - self._bynweekday = None - elif type(byweekday) is int: - self._byweekday = (byweekday,) - self._bynweekday = None - elif hasattr(byweekday, "n"): - if not byweekday.n or freq > MONTHLY: - self._byweekday = (byweekday.weekday,) - self._bynweekday = None - else: - self._bynweekday = ((byweekday.weekday, byweekday.n),) - self._byweekday = None - else: - self._byweekday = [] - self._bynweekday = [] - for wday in byweekday: - if type(wday) is int: - self._byweekday.append(wday) - elif not wday.n or freq > MONTHLY: - self._byweekday.append(wday.weekday) - else: - self._bynweekday.append((wday.weekday, wday.n)) - self._byweekday = tuple(self._byweekday) - self._bynweekday = tuple(self._bynweekday) - if not self._byweekday: - self._byweekday = None - elif not self._bynweekday: - self._bynweekday = None - # byhour - if byhour is None: - if freq < HOURLY: - self._byhour = (dtstart.hour,) - else: - self._byhour = None - elif type(byhour) is int: - self._byhour = (byhour,) - else: - self._byhour = tuple(byhour) - # byminute - if byminute is None: - if freq < MINUTELY: - self._byminute = (dtstart.minute,) - else: - self._byminute = None - elif type(byminute) is int: - self._byminute = (byminute,) - else: - self._byminute = tuple(byminute) - # bysecond - if bysecond is None: - if freq < SECONDLY: - self._bysecond = (dtstart.second,) - else: - self._bysecond = None - elif type(bysecond) is int: - self._bysecond = (bysecond,) - else: - self._bysecond = tuple(bysecond) - - if self._freq >= HOURLY: - self._timeset = None - else: - self._timeset = [] - for hour in self._byhour: - for minute in self._byminute: - for second in self._bysecond: - self._timeset.append( - datetime.time(hour, minute, second, - tzinfo=self._tzinfo)) - self._timeset.sort() - self._timeset = tuple(self._timeset) - - def _iter(self): - year, month, day, hour, minute, second, weekday, yearday, _ = \ - self._dtstart.timetuple() - - # Some local variables to speed things up a bit - freq = self._freq - interval = self._interval - wkst = self._wkst - until = self._until - bymonth = self._bymonth - byweekno = self._byweekno - byyearday = self._byyearday - byweekday = self._byweekday - byeaster = self._byeaster - bymonthday = self._bymonthday - bynmonthday = self._bynmonthday - bysetpos = self._bysetpos - byhour = self._byhour - byminute = self._byminute - bysecond = self._bysecond - - ii = _iterinfo(self) - ii.rebuild(year, month) - - getdayset = {YEARLY:ii.ydayset, - MONTHLY:ii.mdayset, - WEEKLY:ii.wdayset, - DAILY:ii.ddayset, - HOURLY:ii.ddayset, - MINUTELY:ii.ddayset, - SECONDLY:ii.ddayset}[freq] - - if freq < HOURLY: - timeset = self._timeset - else: - gettimeset = {HOURLY:ii.htimeset, - MINUTELY:ii.mtimeset, - SECONDLY:ii.stimeset}[freq] - if ((freq >= HOURLY and - self._byhour and hour not in self._byhour) or - (freq >= MINUTELY and - self._byminute and minute not in self._byminute) or - (freq >= SECONDLY and - self._bysecond and second not in self._bysecond)): - timeset = () - else: - timeset = gettimeset(hour, minute, second) - - total = 0 - count = self._count - while True: - # Get dayset with the right frequency - dayset, start, end = getdayset(year, month, day) - - # Do the "hard" work ;-) - filtered = False - for i in dayset[start:end]: - if ((bymonth and ii.mmask[i] not in bymonth) or - (byweekno and not ii.wnomask[i]) or - (byweekday and ii.wdaymask[i] not in byweekday) or - (ii.nwdaymask and not ii.nwdaymask[i]) or - (byeaster and not ii.eastermask[i]) or - ((bymonthday or bynmonthday) and - ii.mdaymask[i] not in bymonthday and - ii.nmdaymask[i] not in bynmonthday) or - (byyearday and - ((i < ii.yearlen and i+1 not in byyearday - and -ii.yearlen+i not in byyearday) or - (i >= ii.yearlen and i+1-ii.yearlen not in byyearday - and -ii.nextyearlen+i-ii.yearlen - not in byyearday)))): - dayset[i] = None - filtered = True - - # Output results - if bysetpos and timeset: - poslist = [] - for pos in bysetpos: - if pos < 0: - daypos, timepos = divmod(pos, len(timeset)) - else: - daypos, timepos = divmod(pos-1, len(timeset)) - try: - i = [x for x in dayset[start:end] - if x is not None][daypos] - time = timeset[timepos] - except IndexError: - pass - else: - date = datetime.date.fromordinal(ii.yearordinal+i) - res = datetime.datetime.combine(date, time) - if res not in poslist: - poslist.append(res) - poslist.sort() - for res in poslist: - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - else: - for i in dayset[start:end]: - if i is not None: - date = datetime.date.fromordinal(ii.yearordinal+i) - for time in timeset: - res = datetime.datetime.combine(date, time) - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - - # Handle frequency and interval - fixday = False - if freq == YEARLY: - year += interval - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == MONTHLY: - month += interval - if month > 12: - div, mod = divmod(month, 12) - month = mod - year += div - if month == 0: - month = 12 - year -= 1 - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == WEEKLY: - if wkst > weekday: - day += -(weekday+1+(6-wkst))+self._interval*7 - else: - day += -(weekday-wkst)+self._interval*7 - weekday = wkst - fixday = True - elif freq == DAILY: - day += interval - fixday = True - elif freq == HOURLY: - if filtered: - # Jump to one iteration before next day - hour += ((23-hour)//interval)*interval - while True: - hour += interval - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if not byhour or hour in byhour: - break - timeset = gettimeset(hour, minute, second) - elif freq == MINUTELY: - if filtered: - # Jump to one iteration before next day - minute += ((1439-(hour*60+minute))//interval)*interval - while True: - minute += interval - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - filtered = False - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute)): - break - timeset = gettimeset(hour, minute, second) - elif freq == SECONDLY: - if filtered: - # Jump to one iteration before next day - second += (((86399-(hour*3600+minute*60+second)) - //interval)*interval) - while True: - second += self._interval - div, mod = divmod(second, 60) - if div: - second = mod - minute += div - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute) and - (not bysecond or second in bysecond)): - break - timeset = gettimeset(hour, minute, second) - - if fixday and day > 28: - daysinmonth = calendar.monthrange(year, month)[1] - if day > daysinmonth: - while day > daysinmonth: - day -= daysinmonth - month += 1 - if month == 13: - month = 1 - year += 1 - if year > datetime.MAXYEAR: - self._len = total - return - daysinmonth = calendar.monthrange(year, month)[1] - ii.rebuild(year, month) - -class _iterinfo(object): - __slots__ = ["rrule", "lastyear", "lastmonth", - "yearlen", "nextyearlen", "yearordinal", "yearweekday", - "mmask", "mrange", "mdaymask", "nmdaymask", - "wdaymask", "wnomask", "nwdaymask", "eastermask"] - - def __init__(self, rrule): - for attr in self.__slots__: - setattr(self, attr, None) - self.rrule = rrule - - def rebuild(self, year, month): - # Every mask is 7 days longer to handle cross-year weekly periods. - rr = self.rrule - if year != self.lastyear: - self.yearlen = 365+calendar.isleap(year) - self.nextyearlen = 365+calendar.isleap(year+1) - firstyday = datetime.date(year, 1, 1) - self.yearordinal = firstyday.toordinal() - self.yearweekday = firstyday.weekday() - - wday = datetime.date(year, 1, 1).weekday() - if self.yearlen == 365: - self.mmask = M365MASK - self.mdaymask = MDAY365MASK - self.nmdaymask = NMDAY365MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M365RANGE - else: - self.mmask = M366MASK - self.mdaymask = MDAY366MASK - self.nmdaymask = NMDAY366MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M366RANGE - - if not rr._byweekno: - self.wnomask = None - else: - self.wnomask = [0]*(self.yearlen+7) - #no1wkst = firstwkst = self.wdaymask.index(rr._wkst) - no1wkst = firstwkst = (7-self.yearweekday+rr._wkst)%7 - if no1wkst >= 4: - no1wkst = 0 - # Number of days in the year, plus the days we got - # from last year. - wyearlen = self.yearlen+(self.yearweekday-rr._wkst)%7 - else: - # Number of days in the year, minus the days we - # left in last year. - wyearlen = self.yearlen-no1wkst - div, mod = divmod(wyearlen, 7) - numweeks = div+mod//4 - for n in rr._byweekno: - if n < 0: - n += numweeks+1 - if not (0 < n <= numweeks): - continue - if n > 1: - i = no1wkst+(n-1)*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - else: - i = no1wkst - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if 1 in rr._byweekno: - # Check week number 1 of next year as well - # TODO: Check -numweeks for next year. - i = no1wkst+numweeks*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - if i < self.yearlen: - # If week starts in next year, we - # don't care about it. - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if no1wkst: - # Check last week number of last year as - # well. If no1wkst is 0, either the year - # started on week start, or week number 1 - # got days from last year, so there are no - # days from last year's last week number in - # this year. - if -1 not in rr._byweekno: - lyearweekday = datetime.date(year-1,1,1).weekday() - lno1wkst = (7-lyearweekday+rr._wkst)%7 - lyearlen = 365+calendar.isleap(year-1) - if lno1wkst >= 4: - lno1wkst = 0 - lnumweeks = 52+(lyearlen+ - (lyearweekday-rr._wkst)%7)%7//4 - else: - lnumweeks = 52+(self.yearlen-no1wkst)%7//4 - else: - lnumweeks = -1 - if lnumweeks in rr._byweekno: - for i in range(no1wkst): - self.wnomask[i] = 1 - - if (rr._bynweekday and - (month != self.lastmonth or year != self.lastyear)): - ranges = [] - if rr._freq == YEARLY: - if rr._bymonth: - for month in rr._bymonth: - ranges.append(self.mrange[month-1:month+1]) - else: - ranges = [(0, self.yearlen)] - elif rr._freq == MONTHLY: - ranges = [self.mrange[month-1:month+1]] - if ranges: - # Weekly frequency won't get here, so we may not - # care about cross-year weekly periods. - self.nwdaymask = [0]*self.yearlen - for first, last in ranges: - last -= 1 - for wday, n in rr._bynweekday: - if n < 0: - i = last+(n+1)*7 - i -= (self.wdaymask[i]-wday)%7 - else: - i = first+(n-1)*7 - i += (7-self.wdaymask[i]+wday)%7 - if first <= i <= last: - self.nwdaymask[i] = 1 - - if rr._byeaster: - self.eastermask = [0]*(self.yearlen+7) - eyday = easter.easter(year).toordinal()-self.yearordinal - for offset in rr._byeaster: - self.eastermask[eyday+offset] = 1 - - self.lastyear = year - self.lastmonth = month - - def ydayset(self, year, month, day): - return range(self.yearlen), 0, self.yearlen - - def mdayset(self, year, month, day): - set = [None]*self.yearlen - start, end = self.mrange[month-1:month+1] - for i in range(start, end): - set[i] = i - return set, start, end - - def wdayset(self, year, month, day): - # We need to handle cross-year weeks here. - set = [None]*(self.yearlen+7) - i = datetime.date(year, month, day).toordinal()-self.yearordinal - start = i - for j in range(7): - set[i] = i - i += 1 - #if (not (0 <= i < self.yearlen) or - # self.wdaymask[i] == self.rrule._wkst): - # This will cross the year boundary, if necessary. - if self.wdaymask[i] == self.rrule._wkst: - break - return set, start, i - - def ddayset(self, year, month, day): - set = [None]*self.yearlen - i = datetime.date(year, month, day).toordinal()-self.yearordinal - set[i] = i - return set, i, i+1 - - def htimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for minute in rr._byminute: - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, - tzinfo=rr._tzinfo)) - set.sort() - return set - - def mtimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo)) - set.sort() - return set - - def stimeset(self, hour, minute, second): - return (datetime.time(hour, minute, second, - tzinfo=self.rrule._tzinfo),) - - -class rruleset(rrulebase): - - class _genitem: - def __init__(self, genlist, gen): - try: - self.dt = gen() - genlist.append(self) - except StopIteration: - pass - self.genlist = genlist - self.gen = gen - - def next(self): - try: - self.dt = self.gen() - except StopIteration: - self.genlist.remove(self) - - def __cmp__(self, other): - return cmp(self.dt, other.dt) - - def __init__(self, cache=False): - rrulebase.__init__(self, cache) - self._rrule = [] - self._rdate = [] - self._exrule = [] - self._exdate = [] - - def rrule(self, rrule): - self._rrule.append(rrule) - - def rdate(self, rdate): - self._rdate.append(rdate) - - def exrule(self, exrule): - self._exrule.append(exrule) - - def exdate(self, exdate): - self._exdate.append(exdate) - - def _iter(self): - rlist = [] - self._rdate.sort() - self._genitem(rlist, iter(self._rdate).next) - for gen in [iter(x).next for x in self._rrule]: - self._genitem(rlist, gen) - rlist.sort() - exlist = [] - self._exdate.sort() - self._genitem(exlist, iter(self._exdate).next) - for gen in [iter(x).next for x in self._exrule]: - self._genitem(exlist, gen) - exlist.sort() - lastdt = None - total = 0 - while rlist: - ritem = rlist[0] - if not lastdt or lastdt != ritem.dt: - while exlist and exlist[0] < ritem: - exlist[0].next() - exlist.sort() - if not exlist or ritem != exlist[0]: - total += 1 - yield ritem.dt - lastdt = ritem.dt - ritem.next() - rlist.sort() - self._len = total - -class _rrulestr: - - _freq_map = {"YEARLY": YEARLY, - "MONTHLY": MONTHLY, - "WEEKLY": WEEKLY, - "DAILY": DAILY, - "HOURLY": HOURLY, - "MINUTELY": MINUTELY, - "SECONDLY": SECONDLY} - - _weekday_map = {"MO":0,"TU":1,"WE":2,"TH":3,"FR":4,"SA":5,"SU":6} - - def _handle_int(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = int(value) - - def _handle_int_list(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = [int(x) for x in value.split(',')] - - _handle_INTERVAL = _handle_int - _handle_COUNT = _handle_int - _handle_BYSETPOS = _handle_int_list - _handle_BYMONTH = _handle_int_list - _handle_BYMONTHDAY = _handle_int_list - _handle_BYYEARDAY = _handle_int_list - _handle_BYEASTER = _handle_int_list - _handle_BYWEEKNO = _handle_int_list - _handle_BYHOUR = _handle_int_list - _handle_BYMINUTE = _handle_int_list - _handle_BYSECOND = _handle_int_list - - def _handle_FREQ(self, rrkwargs, name, value, **kwargs): - rrkwargs["freq"] = self._freq_map[value] - - def _handle_UNTIL(self, rrkwargs, name, value, **kwargs): - global parser - if not parser: - from dateutil import parser - try: - rrkwargs["until"] = parser.parse(value, - ignoretz=kwargs.get("ignoretz"), - tzinfos=kwargs.get("tzinfos")) - except ValueError: - raise ValueError, "invalid until date" - - def _handle_WKST(self, rrkwargs, name, value, **kwargs): - rrkwargs["wkst"] = self._weekday_map[value] - - def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwarsg): - l = [] - for wday in value.split(','): - for i in range(len(wday)): - if wday[i] not in '+-0123456789': - break - n = wday[:i] or None - w = wday[i:] - if n: n = int(n) - l.append(weekdays[self._weekday_map[w]](n)) - rrkwargs["byweekday"] = l - - _handle_BYDAY = _handle_BYWEEKDAY - - def _parse_rfc_rrule(self, line, - dtstart=None, - cache=False, - ignoretz=False, - tzinfos=None): - if line.find(':') != -1: - name, value = line.split(':') - if name != "RRULE": - raise ValueError, "unknown parameter name" - else: - value = line - rrkwargs = {} - for pair in value.split(';'): - name, value = pair.split('=') - name = name.upper() - value = value.upper() - try: - getattr(self, "_handle_"+name)(rrkwargs, name, value, - ignoretz=ignoretz, - tzinfos=tzinfos) - except AttributeError: - raise ValueError, "unknown parameter '%s'" % name - except (KeyError, ValueError): - raise ValueError, "invalid '%s': %s" % (name, value) - return rrule(dtstart=dtstart, cache=cache, **rrkwargs) - - def _parse_rfc(self, s, - dtstart=None, - cache=False, - unfold=False, - forceset=False, - compatible=False, - ignoretz=False, - tzinfos=None): - global parser - if compatible: - forceset = True - unfold = True - s = s.upper() - if not s.strip(): - raise ValueError, "empty string" - if unfold: - lines = s.splitlines() - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - else: - lines = s.split() - if (not forceset and len(lines) == 1 and - (s.find(':') == -1 or s.startswith('RRULE:'))): - return self._parse_rfc_rrule(lines[0], cache=cache, - dtstart=dtstart, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - rrulevals = [] - rdatevals = [] - exrulevals = [] - exdatevals = [] - for line in lines: - if not line: - continue - if line.find(':') == -1: - name = "RRULE" - value = line - else: - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError, "empty property name" - name = parms[0] - parms = parms[1:] - if name == "RRULE": - for parm in parms: - raise ValueError, "unsupported RRULE parm: "+parm - rrulevals.append(value) - elif name == "RDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError, "unsupported RDATE parm: "+parm - rdatevals.append(value) - elif name == "EXRULE": - for parm in parms: - raise ValueError, "unsupported EXRULE parm: "+parm - exrulevals.append(value) - elif name == "EXDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError, "unsupported RDATE parm: "+parm - exdatevals.append(value) - elif name == "DTSTART": - for parm in parms: - raise ValueError, "unsupported DTSTART parm: "+parm - if not parser: - from dateutil import parser - dtstart = parser.parse(value, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - raise ValueError, "unsupported property: "+name - if (forceset or len(rrulevals) > 1 or - rdatevals or exrulevals or exdatevals): - if not parser and (rdatevals or exdatevals): - from dateutil import parser - set = rruleset(cache=cache) - for value in rrulevals: - set.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in rdatevals: - for datestr in value.split(','): - set.rdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exrulevals: - set.exrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exdatevals: - for datestr in value.split(','): - set.exdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - if compatible and dtstart: - set.rdate(dtstart) - return set - else: - return self._parse_rfc_rrule(rrulevals[0], - dtstart=dtstart, - cache=cache, - ignoretz=ignoretz, - tzinfos=tzinfos) - - def __call__(self, s, **kwargs): - return self._parse_rfc(s, **kwargs) - -rrulestr = _rrulestr() - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/tz.py b/lib/dateutil_py2/tz.py deleted file mode 100644 index 0e28d6b33209..000000000000 --- a/lib/dateutil_py2/tz.py +++ /dev/null @@ -1,951 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime -import struct -import time -import sys -import os - -relativedelta = None -parser = None -rrule = None - -__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange", - "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"] - -try: - from dateutil.tzwin import tzwin, tzwinlocal -except (ImportError, OSError): - tzwin, tzwinlocal = None, None - -ZERO = datetime.timedelta(0) -EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal() - -class tzutc(datetime.tzinfo): - - def utcoffset(self, dt): - return ZERO - - def dst(self, dt): - return ZERO - - def tzname(self, dt): - return "UTC" - - def __eq__(self, other): - return (isinstance(other, tzutc) or - (isinstance(other, tzoffset) and other._offset == ZERO)) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzoffset(datetime.tzinfo): - - def __init__(self, name, offset): - self._name = name - self._offset = datetime.timedelta(seconds=offset) - - def utcoffset(self, dt): - return self._offset - - def dst(self, dt): - return ZERO - - def tzname(self, dt): - return self._name - - def __eq__(self, other): - return (isinstance(other, tzoffset) and - self._offset == other._offset) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(%s, %s)" % (self.__class__.__name__, - `self._name`, - self._offset.days*86400+self._offset.seconds) - - __reduce__ = object.__reduce__ - -class tzlocal(datetime.tzinfo): - - _std_offset = datetime.timedelta(seconds=-time.timezone) - if time.daylight: - _dst_offset = datetime.timedelta(seconds=-time.altzone) - else: - _dst_offset = _std_offset - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - def tzname(self, dt): - return time.tzname[self._isdst(dt)] - - def _isdst(self, dt): - # We can't use mktime here. It is unstable when deciding if - # the hour near to a change is DST or not. - # - # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, - # dt.minute, dt.second, dt.weekday(), 0, -1)) - # return time.localtime(timestamp).tm_isdst - # - # The code above yields the following result: - # - #>>> import tz, datetime - #>>> t = tz.tzlocal() - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - # - # Here is a more stable implementation: - # - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - return time.localtime(timestamp+time.timezone).tm_isdst - - def __eq__(self, other): - if not isinstance(other, tzlocal): - return False - return (self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset) - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class _ttinfo(object): - __slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"] - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def __repr__(self): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, `value`)) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - - def __eq__(self, other): - if not isinstance(other, _ttinfo): - return False - return (self.offset == other.offset and - self.delta == other.delta and - self.isdst == other.isdst and - self.abbr == other.abbr and - self.isstd == other.isstd and - self.isgmt == other.isgmt) - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - state = {} - for name in self.__slots__: - state[name] = getattr(self, name, None) - return state - - def __setstate__(self, state): - for name in self.__slots__: - if name in state: - setattr(self, name, state[name]) - -class tzfile(datetime.tzinfo): - - # http://www.twinsun.com/tz/tz-link.htm - # ftp://elsie.nci.nih.gov/pub/tz*.tar.gz - - def __init__(self, fileobj): - if isinstance(fileobj, basestring): - self._filename = fileobj - fileobj = open(fileobj) - elif hasattr(fileobj, "name"): - self._filename = fileobj.name - else: - self._filename = `fileobj` - - # From tzfile(5): - # - # The time zone information files used by tzset(3) - # begin with the magic characters "TZif" to identify - # them as time zone information files, followed by - # sixteen bytes reserved for future use, followed by - # six four-byte values of type long, written in a - # ``standard'' byte order (the high-order byte - # of the value is written first). - - if fileobj.read(4) != "TZif": - raise ValueError, "magic not found" - - fileobj.read(16) - - ( - # The number of UTC/local indicators stored in the file. - ttisgmtcnt, - - # The number of standard/wall indicators stored in the file. - ttisstdcnt, - - # The number of leap seconds for which data is - # stored in the file. - leapcnt, - - # The number of "transition times" for which data - # is stored in the file. - timecnt, - - # The number of "local time types" for which data - # is stored in the file (must not be zero). - typecnt, - - # The number of characters of "time zone - # abbreviation strings" stored in the file. - charcnt, - - ) = struct.unpack(">6l", fileobj.read(24)) - - # The above header is followed by tzh_timecnt four-byte - # values of type long, sorted in ascending order. - # These values are written in ``standard'' byte order. - # Each is used as a transition time (as returned by - # time(2)) at which the rules for computing local time - # change. - - if timecnt: - self._trans_list = struct.unpack(">%dl" % timecnt, - fileobj.read(timecnt*4)) - else: - self._trans_list = [] - - # Next come tzh_timecnt one-byte values of type unsigned - # char; each one tells which of the different types of - # ``local time'' types described in the file is associated - # with the same-indexed transition time. These values - # serve as indices into an array of ttinfo structures that - # appears next in the file. - - if timecnt: - self._trans_idx = struct.unpack(">%dB" % timecnt, - fileobj.read(timecnt)) - else: - self._trans_idx = [] - - # Each ttinfo structure is written as a four-byte value - # for tt_gmtoff of type long, in a standard byte - # order, followed by a one-byte value for tt_isdst - # and a one-byte value for tt_abbrind. In each - # structure, tt_gmtoff gives the number of - # seconds to be added to UTC, tt_isdst tells whether - # tm_isdst should be set by localtime(3), and - # tt_abbrind serves as an index into the array of - # time zone abbreviation characters that follow the - # ttinfo structure(s) in the file. - - ttinfo = [] - - for i in range(typecnt): - ttinfo.append(struct.unpack(">lbb", fileobj.read(6))) - - abbr = fileobj.read(charcnt) - - # Then there are tzh_leapcnt pairs of four-byte - # values, written in standard byte order; the - # first value of each pair gives the time (as - # returned by time(2)) at which a leap second - # occurs; the second gives the total number of - # leap seconds to be applied after the given time. - # The pairs of values are sorted in ascending order - # by time. - - # Not used, for now - if leapcnt: - leap = struct.unpack(">%dl" % (leapcnt*2), - fileobj.read(leapcnt*8)) - - # Then there are tzh_ttisstdcnt standard/wall - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as standard - # time or wall clock time, and are used when - # a time zone file is used in handling POSIX-style - # time zone environment variables. - - if ttisstdcnt: - isstd = struct.unpack(">%db" % ttisstdcnt, - fileobj.read(ttisstdcnt)) - - # Finally, there are tzh_ttisgmtcnt UTC/local - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as UTC or - # local time, and are used when a time zone file - # is used in handling POSIX-style time zone envi- - # ronment variables. - - if ttisgmtcnt: - isgmt = struct.unpack(">%db" % ttisgmtcnt, - fileobj.read(ttisgmtcnt)) - - # ** Everything has been read ** - - # Build ttinfo list - self._ttinfo_list = [] - for i in range(typecnt): - gmtoff, isdst, abbrind = ttinfo[i] - # Round to full-minutes if that's not the case. Python's - # datetime doesn't accept sub-minute timezones. Check - # http://python.org/sf/1447945 for some information. - gmtoff = (gmtoff+30)//60*60 - tti = _ttinfo() - tti.offset = gmtoff - tti.delta = datetime.timedelta(seconds=gmtoff) - tti.isdst = isdst - tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)] - tti.isstd = (ttisstdcnt > i and isstd[i] != 0) - tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0) - self._ttinfo_list.append(tti) - - # Replace ttinfo indexes for ttinfo objects. - trans_idx = [] - for idx in self._trans_idx: - trans_idx.append(self._ttinfo_list[idx]) - self._trans_idx = tuple(trans_idx) - - # Set standard, dst, and before ttinfos. before will be - # used when a given time is before any transitions, - # and will be set to the first non-dst ttinfo, or to - # the first dst, if all of them are dst. - self._ttinfo_std = None - self._ttinfo_dst = None - self._ttinfo_before = None - if self._ttinfo_list: - if not self._trans_list: - self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0] - else: - for i in range(timecnt-1,-1,-1): - tti = self._trans_idx[i] - if not self._ttinfo_std and not tti.isdst: - self._ttinfo_std = tti - elif not self._ttinfo_dst and tti.isdst: - self._ttinfo_dst = tti - if self._ttinfo_std and self._ttinfo_dst: - break - else: - if self._ttinfo_dst and not self._ttinfo_std: - self._ttinfo_std = self._ttinfo_dst - - for tti in self._ttinfo_list: - if not tti.isdst: - self._ttinfo_before = tti - break - else: - self._ttinfo_before = self._ttinfo_list[0] - - # Now fix transition times to become relative to wall time. - # - # I'm not sure about this. In my tests, the tz source file - # is setup to wall time, and in the binary file isstd and - # isgmt are off, so it should be in wall time. OTOH, it's - # always in gmt time. Let me know if you have comments - # about this. - laststdoffset = 0 - self._trans_list = list(self._trans_list) - for i in range(len(self._trans_list)): - tti = self._trans_idx[i] - if not tti.isdst: - # This is std time. - self._trans_list[i] += tti.offset - laststdoffset = tti.offset - else: - # This is dst time. Convert to std. - self._trans_list[i] += laststdoffset - self._trans_list = tuple(self._trans_list) - - def _find_ttinfo(self, dt, laststd=0): - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - idx = 0 - for trans in self._trans_list: - if timestamp < trans: - break - idx += 1 - else: - return self._ttinfo_std - if idx == 0: - return self._ttinfo_before - if laststd: - while idx > 0: - tti = self._trans_idx[idx-1] - if not tti.isdst: - return tti - idx -= 1 - else: - return self._ttinfo_std - else: - return self._trans_idx[idx-1] - - def utcoffset(self, dt): - if not self._ttinfo_std: - return ZERO - return self._find_ttinfo(dt).delta - - def dst(self, dt): - if not self._ttinfo_dst: - return ZERO - tti = self._find_ttinfo(dt) - if not tti.isdst: - return ZERO - - # The documentation says that utcoffset()-dst() must - # be constant for every dt. - return tti.delta-self._find_ttinfo(dt, laststd=1).delta - - # An alternative for that would be: - # - # return self._ttinfo_dst.offset-self._ttinfo_std.offset - # - # However, this class stores historical changes in the - # dst offset, so I belive that this wouldn't be the right - # way to implement this. - - def tzname(self, dt): - if not self._ttinfo_std: - return None - return self._find_ttinfo(dt).abbr - - def __eq__(self, other): - if not isinstance(other, tzfile): - return False - return (self._trans_list == other._trans_list and - self._trans_idx == other._trans_idx and - self._ttinfo_list == other._ttinfo_list) - - def __ne__(self, other): - return not self.__eq__(other) - - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, `self._filename`) - - def __reduce__(self): - if not os.path.isfile(self._filename): - raise ValueError, "Unpickable %s class" % self.__class__.__name__ - return (self.__class__, (self._filename,)) - -class tzrange(datetime.tzinfo): - - def __init__(self, stdabbr, stdoffset=None, - dstabbr=None, dstoffset=None, - start=None, end=None): - global relativedelta - if not relativedelta: - from dateutil import relativedelta - self._std_abbr = stdabbr - self._dst_abbr = dstabbr - if stdoffset is not None: - self._std_offset = datetime.timedelta(seconds=stdoffset) - else: - self._std_offset = ZERO - if dstoffset is not None: - self._dst_offset = datetime.timedelta(seconds=dstoffset) - elif dstabbr and stdoffset is not None: - self._dst_offset = self._std_offset+datetime.timedelta(hours=+1) - else: - self._dst_offset = ZERO - if dstabbr and start is None: - self._start_delta = relativedelta.relativedelta( - hours=+2, month=4, day=1, weekday=relativedelta.SU(+1)) - else: - self._start_delta = start - if dstabbr and end is None: - self._end_delta = relativedelta.relativedelta( - hours=+1, month=10, day=31, weekday=relativedelta.SU(-1)) - else: - self._end_delta = end - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - def tzname(self, dt): - if self._isdst(dt): - return self._dst_abbr - else: - return self._std_abbr - - def _isdst(self, dt): - if not self._start_delta: - return False - year = datetime.datetime(dt.year,1,1) - start = year+self._start_delta - end = year+self._end_delta - dt = dt.replace(tzinfo=None) - if start < end: - return dt >= start and dt < end - else: - return dt >= start or dt < end - - def __eq__(self, other): - if not isinstance(other, tzrange): - return False - return (self._std_abbr == other._std_abbr and - self._dst_abbr == other._dst_abbr and - self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset and - self._start_delta == other._start_delta and - self._end_delta == other._end_delta) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(...)" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzstr(tzrange): - - def __init__(self, s): - global parser - if not parser: - from dateutil import parser - self._s = s - - res = parser._parsetz(s) - if res is None: - raise ValueError, "unknown string format" - - # Here we break the compatibility with the TZ variable handling. - # GMT-3 actually *means* the timezone -3. - if res.stdabbr in ("GMT", "UTC"): - res.stdoffset *= -1 - - # We must initialize it first, since _delta() needs - # _std_offset and _dst_offset set. Use False in start/end - # to avoid building it two times. - tzrange.__init__(self, res.stdabbr, res.stdoffset, - res.dstabbr, res.dstoffset, - start=False, end=False) - - if not res.dstabbr: - self._start_delta = None - self._end_delta = None - else: - self._start_delta = self._delta(res.start) - if self._start_delta: - self._end_delta = self._delta(res.end, isend=1) - - def _delta(self, x, isend=0): - kwargs = {} - if x.month is not None: - kwargs["month"] = x.month - if x.weekday is not None: - kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week) - if x.week > 0: - kwargs["day"] = 1 - else: - kwargs["day"] = 31 - elif x.day: - kwargs["day"] = x.day - elif x.yday is not None: - kwargs["yearday"] = x.yday - elif x.jyday is not None: - kwargs["nlyearday"] = x.jyday - if not kwargs: - # Default is to start on first sunday of april, and end - # on last sunday of october. - if not isend: - kwargs["month"] = 4 - kwargs["day"] = 1 - kwargs["weekday"] = relativedelta.SU(+1) - else: - kwargs["month"] = 10 - kwargs["day"] = 31 - kwargs["weekday"] = relativedelta.SU(-1) - if x.time is not None: - kwargs["seconds"] = x.time - else: - # Default is 2AM. - kwargs["seconds"] = 7200 - if isend: - # Convert to standard time, to follow the documented way - # of working with the extra hour. See the documentation - # of the tzinfo class. - delta = self._dst_offset-self._std_offset - kwargs["seconds"] -= delta.seconds+delta.days*86400 - return relativedelta.relativedelta(**kwargs) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, `self._s`) - -class _tzicalvtzcomp: - def __init__(self, tzoffsetfrom, tzoffsetto, isdst, - tzname=None, rrule=None): - self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) - self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto) - self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom - self.isdst = isdst - self.tzname = tzname - self.rrule = rrule - -class _tzicalvtz(datetime.tzinfo): - def __init__(self, tzid, comps=[]): - self._tzid = tzid - self._comps = comps - self._cachedate = [] - self._cachecomp = [] - - def _find_comp(self, dt): - if len(self._comps) == 1: - return self._comps[0] - dt = dt.replace(tzinfo=None) - try: - return self._cachecomp[self._cachedate.index(dt)] - except ValueError: - pass - lastcomp = None - lastcompdt = None - for comp in self._comps: - if not comp.isdst: - # Handle the extra hour in DST -> STD - compdt = comp.rrule.before(dt-comp.tzoffsetdiff, inc=True) - else: - compdt = comp.rrule.before(dt, inc=True) - if compdt and (not lastcompdt or lastcompdt < compdt): - lastcompdt = compdt - lastcomp = comp - if not lastcomp: - # RFC says nothing about what to do when a given - # time is before the first onset date. We'll look for the - # first standard component, or the first component, if - # none is found. - for comp in self._comps: - if not comp.isdst: - lastcomp = comp - break - else: - lastcomp = comp[0] - self._cachedate.insert(0, dt) - self._cachecomp.insert(0, lastcomp) - if len(self._cachedate) > 10: - self._cachedate.pop() - self._cachecomp.pop() - return lastcomp - - def utcoffset(self, dt): - return self._find_comp(dt).tzoffsetto - - def dst(self, dt): - comp = self._find_comp(dt) - if comp.isdst: - return comp.tzoffsetdiff - else: - return ZERO - - def tzname(self, dt): - return self._find_comp(dt).tzname - - def __repr__(self): - return "" % `self._tzid` - - __reduce__ = object.__reduce__ - -class tzical: - def __init__(self, fileobj): - global rrule - if not rrule: - from dateutil import rrule - - if isinstance(fileobj, basestring): - self._s = fileobj - fileobj = open(fileobj) - elif hasattr(fileobj, "name"): - self._s = fileobj.name - else: - self._s = `fileobj` - - self._vtz = {} - - self._parse_rfc(fileobj.read()) - - def keys(self): - return self._vtz.keys() - - def get(self, tzid=None): - if tzid is None: - keys = self._vtz.keys() - if len(keys) == 0: - raise ValueError, "no timezones defined" - elif len(keys) > 1: - raise ValueError, "more than one timezone available" - tzid = keys[0] - return self._vtz.get(tzid) - - def _parse_offset(self, s): - s = s.strip() - if not s: - raise ValueError, "empty offset" - if s[0] in ('+', '-'): - signal = (-1,+1)[s[0]=='+'] - s = s[1:] - else: - signal = +1 - if len(s) == 4: - return (int(s[:2])*3600+int(s[2:])*60)*signal - elif len(s) == 6: - return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal - else: - raise ValueError, "invalid offset: "+s - - def _parse_rfc(self, s): - lines = s.splitlines() - if not lines: - raise ValueError, "empty string" - - # Unfold - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - - tzid = None - comps = [] - invtz = False - comptype = None - for line in lines: - if not line: - continue - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError, "empty property name" - name = parms[0].upper() - parms = parms[1:] - if invtz: - if name == "BEGIN": - if value in ("STANDARD", "DAYLIGHT"): - # Process component - pass - else: - raise ValueError, "unknown component: "+value - comptype = value - founddtstart = False - tzoffsetfrom = None - tzoffsetto = None - rrulelines = [] - tzname = None - elif name == "END": - if value == "VTIMEZONE": - if comptype: - raise ValueError, \ - "component not closed: "+comptype - if not tzid: - raise ValueError, \ - "mandatory TZID not found" - if not comps: - raise ValueError, \ - "at least one component is needed" - # Process vtimezone - self._vtz[tzid] = _tzicalvtz(tzid, comps) - invtz = False - elif value == comptype: - if not founddtstart: - raise ValueError, \ - "mandatory DTSTART not found" - if tzoffsetfrom is None: - raise ValueError, \ - "mandatory TZOFFSETFROM not found" - if tzoffsetto is None: - raise ValueError, \ - "mandatory TZOFFSETFROM not found" - # Process component - rr = None - if rrulelines: - rr = rrule.rrulestr("\n".join(rrulelines), - compatible=True, - ignoretz=True, - cache=True) - comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto, - (comptype == "DAYLIGHT"), - tzname, rr) - comps.append(comp) - comptype = None - else: - raise ValueError, \ - "invalid component end: "+value - elif comptype: - if name == "DTSTART": - rrulelines.append(line) - founddtstart = True - elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"): - rrulelines.append(line) - elif name == "TZOFFSETFROM": - if parms: - raise ValueError, \ - "unsupported %s parm: %s "%(name, parms[0]) - tzoffsetfrom = self._parse_offset(value) - elif name == "TZOFFSETTO": - if parms: - raise ValueError, \ - "unsupported TZOFFSETTO parm: "+parms[0] - tzoffsetto = self._parse_offset(value) - elif name == "TZNAME": - if parms: - raise ValueError, \ - "unsupported TZNAME parm: "+parms[0] - tzname = value - elif name == "COMMENT": - pass - else: - raise ValueError, "unsupported property: "+name - else: - if name == "TZID": - if parms: - raise ValueError, \ - "unsupported TZID parm: "+parms[0] - tzid = value - elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): - pass - else: - raise ValueError, "unsupported property: "+name - elif name == "BEGIN" and value == "VTIMEZONE": - tzid = None - comps = [] - invtz = True - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, `self._s`) - -if sys.platform != "win32": - TZFILES = ["/etc/localtime", "localtime"] - TZPATHS = ["/usr/share/zoneinfo", "/usr/lib/zoneinfo", "/etc/zoneinfo"] -else: - TZFILES = [] - TZPATHS = [] - -def gettz(name=None): - tz = None - if not name: - try: - name = os.environ["TZ"] - except KeyError: - pass - if name is None or name == ":": - for filepath in TZFILES: - if not os.path.isabs(filepath): - filename = filepath - for path in TZPATHS: - filepath = os.path.join(path, filename) - if os.path.isfile(filepath): - break - else: - continue - if os.path.isfile(filepath): - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = tzlocal() - else: - if name.startswith(":"): - name = name[:-1] - if os.path.isabs(name): - if os.path.isfile(name): - tz = tzfile(name) - else: - tz = None - else: - for path in TZPATHS: - filepath = os.path.join(path, name) - if not os.path.isfile(filepath): - filepath = filepath.replace(' ','_') - if not os.path.isfile(filepath): - continue - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = None - if tzwin: - try: - tz = tzwin(name) - except OSError: - pass - if not tz: - from dateutil.zoneinfo import gettz - tz = gettz(name) - if not tz: - for c in name: - # name must have at least one offset to be a tzstr - if c in "0123456789": - try: - tz = tzstr(name) - except ValueError: - pass - break - else: - if name in ("GMT", "UTC"): - tz = tzutc() - elif name in time.tzname: - tz = tzlocal() - return tz - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/tzwin.py b/lib/dateutil_py2/tzwin.py deleted file mode 100644 index 073e0ff68e3f..000000000000 --- a/lib/dateutil_py2/tzwin.py +++ /dev/null @@ -1,180 +0,0 @@ -# This code was originally contributed by Jeffrey Harris. -import datetime -import struct -import _winreg - -__author__ = "Jeffrey Harris & Gustavo Niemeyer " - -__all__ = ["tzwin", "tzwinlocal"] - -ONEWEEK = datetime.timedelta(7) - -TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" -TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" -TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" - -def _settzkeyname(): - global TZKEYNAME - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - try: - _winreg.OpenKey(handle, TZKEYNAMENT).Close() - TZKEYNAME = TZKEYNAMENT - except WindowsError: - TZKEYNAME = TZKEYNAME9X - handle.Close() - -_settzkeyname() - -class tzwinbase(datetime.tzinfo): - """tzinfo class based on win32's timezones available in the registry.""" - - def utcoffset(self, dt): - if self._isdst(dt): - return datetime.timedelta(minutes=self._dstoffset) - else: - return datetime.timedelta(minutes=self._stdoffset) - - def dst(self, dt): - if self._isdst(dt): - minutes = self._dstoffset - self._stdoffset - return datetime.timedelta(minutes=minutes) - else: - return datetime.timedelta(0) - - def tzname(self, dt): - if self._isdst(dt): - return self._dstname - else: - return self._stdname - - def list(): - """Return a list of all time zones known to the system.""" - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - tzkey = _winreg.OpenKey(handle, TZKEYNAME) - result = [_winreg.EnumKey(tzkey, i) - for i in range(_winreg.QueryInfoKey(tzkey)[0])] - tzkey.Close() - handle.Close() - return result - list = staticmethod(list) - - def display(self): - return self._display - - def _isdst(self, dt): - dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek, - self._dsthour, self._dstminute, - self._dstweeknumber) - dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek, - self._stdhour, self._stdminute, - self._stdweeknumber) - if dston < dstoff: - return dston <= dt.replace(tzinfo=None) < dstoff - else: - return not dstoff <= dt.replace(tzinfo=None) < dston - - -class tzwin(tzwinbase): - - def __init__(self, name): - self._name = name - - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - tzkey = _winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name)) - keydict = valuestodict(tzkey) - tzkey.Close() - handle.Close() - - self._stdname = keydict["Std"].encode("iso-8859-1") - self._dstname = keydict["Dlt"].encode("iso-8859-1") - - self._display = keydict["Display"] - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=3l16h", keydict["TZI"]) - self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 - self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1 - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[4:9] - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[12:17] - - def __repr__(self): - return "tzwin(%s)" % repr(self._name) - - def __reduce__(self): - return (self.__class__, (self._name,)) - - -class tzwinlocal(tzwinbase): - - def __init__(self): - - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - - tzlocalkey = _winreg.OpenKey(handle, TZLOCALKEYNAME) - keydict = valuestodict(tzlocalkey) - tzlocalkey.Close() - - self._stdname = keydict["StandardName"].encode("iso-8859-1") - self._dstname = keydict["DaylightName"].encode("iso-8859-1") - - try: - tzkey = _winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname)) - _keydict = valuestodict(tzkey) - self._display = _keydict["Display"] - tzkey.Close() - except OSError: - self._display = None - - handle.Close() - - self._stdoffset = -keydict["Bias"]-keydict["StandardBias"] - self._dstoffset = self._stdoffset-keydict["DaylightBias"] - - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=8h", keydict["StandardStart"]) - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[1:6] - - tup = struct.unpack("=8h", keydict["DaylightStart"]) - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[1:6] - - def __reduce__(self): - return (self.__class__, ()) - -def picknthweekday(year, month, dayofweek, hour, minute, whichweek): - """dayofweek == 0 means Sunday, whichweek 5 means last instance""" - first = datetime.datetime(year, month, 1, hour, minute) - weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1)) - for n in xrange(whichweek): - dt = weekdayone+(whichweek-n)*ONEWEEK - if dt.month == month: - return dt - -def valuestodict(key): - """Convert a registry key's values to a dictionary.""" - dict = {} - size = _winreg.QueryInfoKey(key)[1] - for i in range(size): - data = _winreg.EnumValue(key, i) - dict[data[0]] = data[1] - return dict diff --git a/lib/dateutil_py2/zoneinfo/__init__.py b/lib/dateutil_py2/zoneinfo/__init__.py deleted file mode 100644 index 9bed6264c8b9..000000000000 --- a/lib/dateutil_py2/zoneinfo/__init__.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Copyright (c) 2003-2005 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -from dateutil.tz import tzfile -from tarfile import TarFile -import os - -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -__all__ = ["setcachesize", "gettz", "rebuild"] - -CACHE = [] -CACHESIZE = 10 - -class tzfile(tzfile): - def __reduce__(self): - return (gettz, (self._filename,)) - -def getzoneinfofile(): - filenames = os.listdir(os.path.join(os.path.dirname(__file__))) - filenames.sort() - filenames.reverse() - for entry in filenames: - if entry.startswith("zoneinfo") and ".tar." in entry: - return os.path.join(os.path.dirname(__file__), entry) - return None - -ZONEINFOFILE = getzoneinfofile() - -del getzoneinfofile - -def setcachesize(size): - global CACHESIZE, CACHE - CACHESIZE = size - del CACHE[size:] - -def gettz(name): - tzinfo = None - if ZONEINFOFILE: - for cachedname, tzinfo in CACHE: - if cachedname == name: - break - else: - tf = TarFile.open(ZONEINFOFILE) - try: - zonefile = tf.extractfile(name) - except KeyError: - tzinfo = None - else: - tzinfo = tzfile(zonefile) - tf.close() - CACHE.insert(0, (name, tzinfo)) - del CACHE[CACHESIZE:] - return tzinfo - -def rebuild(filename, tag=None, format="gz"): - import tempfile, shutil - tmpdir = tempfile.mkdtemp() - zonedir = os.path.join(tmpdir, "zoneinfo") - moduledir = os.path.dirname(__file__) - if tag: tag = "-"+tag - targetname = "zoneinfo%s.tar.%s" % (tag, format) - try: - tf = TarFile.open(filename) - for name in tf.getnames(): - if not (name.endswith(".sh") or - name.endswith(".tab") or - name == "leapseconds"): - tf.extract(name, tmpdir) - filepath = os.path.join(tmpdir, name) - os.system("zic -d %s %s" % (zonedir, filepath)) - tf.close() - target = os.path.join(moduledir, targetname) - for entry in os.listdir(moduledir): - if entry.startswith("zoneinfo") and ".tar." in entry: - os.unlink(os.path.join(moduledir, entry)) - tf = TarFile.open(target, "w:%s" % format) - for entry in os.listdir(zonedir): - entrypath = os.path.join(zonedir, entry) - tf.add(entrypath, entry) - tf.close() - finally: - shutil.rmtree(tmpdir) diff --git a/lib/dateutil_py2/zoneinfo/zoneinfo-2010g.tar.gz b/lib/dateutil_py2/zoneinfo/zoneinfo-2010g.tar.gz deleted file mode 100644 index 8bd4f96402be..000000000000 Binary files a/lib/dateutil_py2/zoneinfo/zoneinfo-2010g.tar.gz and /dev/null differ diff --git a/lib/dateutil_py3/LICENSE b/lib/dateutil_py3/LICENSE deleted file mode 100644 index 5834335bd9da..000000000000 --- a/lib/dateutil_py3/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -dateutil - Extensions to the standard Python datetime module. - -Copyright (c) 2003-2011 - Gustavo Niemeyer -Copyright (c) 2012 - Tomi Pieviläinen - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/dateutil_py3/NEWS b/lib/dateutil_py3/NEWS deleted file mode 100644 index 3a0a8ed12aae..000000000000 --- a/lib/dateutil_py3/NEWS +++ /dev/null @@ -1,164 +0,0 @@ -Version 2.1 ------------ - -- New maintainer - -- Dateutil now works on Python 2.6, 2.7 and 3.2 from same codebase (with six) - -- #704047: Ismael Carnales' patch for a new time format - -- Small bug fixes, thanks for reporters! - - -Version 2.0 ------------ - -- Ported to Python 3, by Brian Jones. If you need dateutil for Python 2.X, - please continue using the 1.X series. - -- There's no such thing as a "PSF License". This source code is now - made available under the Simplified BSD license. See LICENSE for - details. - -Version 1.5 ------------ - -- As reported by Mathieu Bridon, rrules were matching the bysecond rules - incorrectly against byminute in some circumstances when the SECONDLY - frequency was in use, due to a copy & paste bug. The problem has been - unittested and corrected. - -- Adam Ryan reported a problem in the relativedelta implementation which - affected the yearday parameter in the month of January specifically. - This has been unittested and fixed. - -- Updated timezone information. - - -Version 1.4.1 -------------- - -- Updated timezone information. - - -Version 1.4 ------------ - -- Fixed another parser precision problem on conversion of decimal seconds - to microseconds, as reported by Erik Brown. Now these issues are gone - for real since it's not using floating point arithmetic anymore. - -- Fixed case where tzrange.utcoffset and tzrange.dst() might fail due - to a date being used where a datetime was expected (reported and fixed - by Lennart Regebro). - -- Prevent tzstr from introducing daylight timings in strings that didn't - specify them (reported by Lennart Regebro). - -- Calls like gettz("GMT+3") and gettz("UTC-2") will now return the - expected values, instead of the TZ variable behavior. - -- Fixed DST signal handling in zoneinfo files. Reported by - Nicholas F. Fabry and John-Mark Gurney. - - -Version 1.3 ------------ - -- Fixed precision problem on conversion of decimal seconds to - microseconds, as reported by Skip Montanaro. - -- Fixed bug in constructor of parser, and converted parser classes to - new-style classes. Original report and patch by Michael Elsdörfer. - -- Initialize tzid and comps in tz.py, to prevent the code from ever - raising a NameError (even with broken files). Johan Dahlin suggested - the fix after a pyflakes run. - -- Version is now published in dateutil.__version__, as requested - by Darren Dale. - -- All code is compatible with new-style division. - - -Version 1.2 ------------ - -- Now tzfile will round timezones to full-minutes if necessary, - since Python's datetime doesn't support sub-minute offsets. - Thanks to Ilpo Nyyssönen for reporting the issue. - -- Removed bare string exceptions, as reported and fixed by - Wilfredo Sánchez Vega. - -- Fix bug in leap count parsing (reported and fixed by Eugene Oden). - - -Version 1.1 ------------ - -- Fixed rrule byyearday handling. Abramo Bagnara pointed out that - RFC2445 allows negative numbers. - -- Fixed --prefix handling in setup.py (by Sidnei da Silva). - -- Now tz.gettz() returns a tzlocal instance when not given any - arguments and no other timezone information is found. - -- Updating timezone information to version 2005q. - - -Version 1.0 ------------ - -- Fixed parsing of XXhXXm formatted time after day/month/year - has been parsed. - -- Added patch by Jeffrey Harris optimizing rrule.__contains__. - - -Version 0.9 ------------ - -- Fixed pickling of timezone types, as reported by - Andreas Köhler. - -- Implemented internal timezone information with binary - timezone files [1]. datautil.tz.gettz() function will now - try to use the system timezone files, and fallback to - the internal versions. It's also possible to ask for - the internal versions directly by using - dateutil.zoneinfo.gettz(). - -- New tzwin timezone type, allowing access to Windows - internal timezones (contributed by Jeffrey Harris). - -- Fixed parsing of unicode date strings. - -- Accept parserinfo instances as the parser constructor - parameter, besides parserinfo (sub)classes. - -- Changed weekday to spell the not-set n value as None - instead of 0. - -- Fixed other reported bugs. - -[1] http://www.twinsun.com/tz/tz-link.htm - - -Version 0.5 ------------ - -- Removed FREQ_ prefix from rrule frequency constants - WARNING: this breaks compatibility with previous versions. - -- Fixed rrule.between() for cases where "after" is achieved - before even starting, as reported by Andreas Köhler. - -- Fixed two digit zero-year parsing (such as 31-Dec-00), as - reported by Jim Abramson, and included test case for this. - -- Sort exdate and rdate before iterating over them, so that - it's not necessary to sort them before adding to the rruleset, - as reported by Nicholas Piper. - diff --git a/lib/dateutil_py3/README b/lib/dateutil_py3/README deleted file mode 100644 index 9453699e7d54..000000000000 --- a/lib/dateutil_py3/README +++ /dev/null @@ -1,1970 +0,0 @@ -## This file is in the moin format. The latest version is found -## at https://moin.conectiva.com.br/DateUtil - -== Contents == -[[TableOfContents]] - -== Description == -The '''dateutil''' module provides powerful extensions to -the standard '''datetime''' module, available in Python. - -== Features == - - * Computing of relative deltas (next month, next year, - next monday, last week of month, etc); - - * Computing of relative deltas between two given - date and/or datetime objects; - - * Computing of dates based on very flexible recurrence rules, - using a superset of the - [ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] - specification. Parsing of RFC strings is supported as well. - - * Generic parsing of dates in almost any string format; - - * Timezone (tzinfo) implementations for tzfile(5) format - files (/etc/localtime, /usr/share/zoneinfo, etc), TZ - environment string (in all known formats), iCalendar - format files, given ranges (with help from relative deltas), - local machine timezone, fixed offset timezone, UTC timezone, - and Windows registry-based time zones. - - * Internal up-to-date world timezone information based on - Olson's database. - - * Computing of Easter Sunday dates for any given year, - using Western, Orthodox or Julian algorithms; - - * More than 400 test cases. - -== Quick example == -Here's a snapshot, just to give an idea about the power of the -package. For more examples, look at the documentation below. - -Suppose you want to know how much time is left, in -years/months/days/etc, before the next easter happening on a -year with a Friday 13th in August, and you want to get today's -date out of the "date" unix system command. Here is the code: -{{{ -from dateutil.relativedelta import * -from dateutil.easter import * -from dateutil.rrule import * -from dateutil.parser import * -from datetime import * -import commands -import os -now = parse(commands.getoutput("date")) -today = now.date() -year = rrule(YEARLY,bymonth=8,bymonthday=13,byweekday=FR)[0].year -rdelta = relativedelta(easter(year), today) -print "Today is:", today -print "Year with next Aug 13th on a Friday is:", year -print "How far is the Easter of that year:", rdelta -print "And the Easter of that year is:", today+rdelta -}}} - -And here's the output: -{{{ -Today is: 2003-10-11 -Year with next Aug 13th on a Friday is: 2004 -How far is the Easter of that year: relativedelta(months=+6) -And the Easter of that year is: 2004-04-11 -}}} - -{i} Being exactly 6 months ahead was '''really''' a coincidence :) - -== Download == -The following files are available. - * attachment:python-dateutil-1.0.tar.bz2 - * attachment:python-dateutil-1.0-1.noarch.rpm - -== Author == -The dateutil module was written by GustavoNiemeyer . - -== Documentation == -The following modules are available. - -=== relativedelta === -This module offers the '''relativedelta''' type, which is based -on the specification of the excelent work done by M.-A. Lemburg in his -[http://www.egenix.com/files/python/mxDateTime.html mxDateTime] -extension. However, notice that this type '''does not''' implement the -same algorithm as his work. Do not expect it to behave like -{{{mxDateTime}}}'s counterpart. - -==== relativedelta type ==== - -There's two different ways to build a relativedelta instance. The -first one is passing it two {{{date}}}/{{{datetime}}} instances: -{{{ -relativedelta(datetime1, datetime2) -}}} - -This will build the relative difference between {{{datetime1}}} and -{{{datetime2}}}, so that the following constraint is always true: -{{{ -datetime2+relativedelta(datetime1, datetime2) == datetime1 -}}} - -Notice that instead of {{{datetime}}} instances, you may use -{{{date}}} instances, or a mix of both. - -And the other way is to use any of the following keyword arguments: - - year, month, day, hour, minute, second, microsecond:: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds:: - Relative information, may be negative. - - weekday:: - One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These - instances may receive a parameter {{{n}}}, specifying the {{{n}}}th - weekday, which could be positive or negative (like {{{MO(+2)}}} or - {{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}. - You can also use an integer, where {{{0=MO}}}. Notice that, - for example, if the calculated date is already Monday, using - {{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context), - won't change the day. - - leapdays:: - Will add given days to the date found, but only if the computed - year is a leap year and the computed date is post 28 of february. - - yearday, nlyearday:: - Set the yearday or the non-leap year day (jump leap days). - These are converted to {{{day}}}/{{{month}}}/{{{leapdays}}} - information. - -==== Behavior of operations ==== -If you're curious about exactly how the relative delta will act -on operations, here is a description of its behavior. - - 1. Calculate the absolute year, using the {{{year}}} argument, or the - original datetime year, if the argument is not present. - 1. Add the relative {{{years}}} argument to the absolute year. - 1. Do steps 1 and 2 for {{{month}}}/{{{months}}}. - 1. Calculate the absolute day, using the {{{day}}} argument, or the - original datetime day, if the argument is not present. Then, subtract - from the day until it fits in the year and month found after their - operations. - 1. Add the relative {{{days}}} argument to the absolute day. Notice - that the {{{weeks}}} argument is multiplied by 7 and added to {{{days}}}. - 1. If {{{leapdays}}} is present, the computed year is a leap year, and - the computed month is after february, remove one day from the found date. - 1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}}, - {{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}. - 1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th - occurrence of the given weekday. - -==== Examples ==== - -Let's begin our trip. -{{{ ->>> from datetime import *; from dateutil.relativedelta import * ->>> import calendar -}}} - -Store some values. -{{{ ->>> NOW = datetime.now() ->>> TODAY = date.today() ->>> NOW -datetime.datetime(2003, 9, 17, 20, 54, 47, 282310) ->>> TODAY -datetime.date(2003, 9, 17) -}}} - -Next month. -{{{ ->>> NOW+relativedelta(months=+1) -datetime.datetime(2003, 10, 17, 20, 54, 47, 282310) -}}} - -Next month, plus one week. -{{{ ->>> NOW+relativedelta(months=+1, weeks=+1) -datetime.datetime(2003, 10, 24, 20, 54, 47, 282310) -}}} - -Next month, plus one week, at 10am. -{{{ ->>> TODAY+relativedelta(months=+1, weeks=+1, hour=10) -datetime.datetime(2003, 10, 24, 10, 0) -}}} - -Let's try the other way around. Notice that the -hour setting we get in the relativedelta is relative, -since it's a difference, and the weeks parameter -has gone. -{{{ ->>> relativedelta(datetime(2003, 10, 24, 10, 0), TODAY) -relativedelta(months=+1, days=+7, hours=+10) -}}} - -One month before one year. -{{{ ->>> NOW+relativedelta(years=+1, months=-1) -datetime.datetime(2004, 8, 17, 20, 54, 47, 282310) -}}} - -How does it handle months with different numbers of days? -Notice that adding one month will never cross the month -boundary. -{{{ ->>> date(2003,1,27)+relativedelta(months=+1) -datetime.date(2003, 2, 27) ->>> date(2003,1,31)+relativedelta(months=+1) -datetime.date(2003, 2, 28) ->>> date(2003,1,31)+relativedelta(months=+2) -datetime.date(2003, 3, 31) -}}} - -The logic for years is the same, even on leap years. -{{{ ->>> date(2000,2,28)+relativedelta(years=+1) -datetime.date(2001, 2, 28) ->>> date(2000,2,29)+relativedelta(years=+1) -datetime.date(2001, 2, 28) - ->>> date(1999,2,28)+relativedelta(years=+1) -datetime.date(2000, 2, 28) ->>> date(1999,3,1)+relativedelta(years=+1) -datetime.date(2000, 3, 1) - ->>> date(2001,2,28)+relativedelta(years=-1) -datetime.date(2000, 2, 28) ->>> date(2001,3,1)+relativedelta(years=-1) -datetime.date(2000, 3, 1) -}}} - -Next friday. -{{{ ->>> TODAY+relativedelta(weekday=FR) -datetime.date(2003, 9, 19) - ->>> TODAY+relativedelta(weekday=calendar.FRIDAY) -datetime.date(2003, 9, 19) -}}} - -Last friday in this month. -{{{ ->>> TODAY+relativedelta(day=31, weekday=FR(-1)) -datetime.date(2003, 9, 26) -}}} - -Next wednesday (it's today!). -{{{ ->>> TODAY+relativedelta(weekday=WE(+1)) -datetime.date(2003, 9, 17) -}}} - -Next wednesday, but not today. -{{{ ->>> TODAY+relativedelta(days=+1, weekday=WE(+1)) -datetime.date(2003, 9, 24) -}}} - -Following -[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation] -find the first day of the 15th week of 1997. -{{{ ->>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14) -datetime.datetime(1997, 4, 7, 0, 0) -}}} - -How long ago has the millennium changed? -{{{ ->>> relativedelta(NOW, date(2001,1,1)) -relativedelta(years=+2, months=+8, days=+16, - hours=+20, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -How old is John? -{{{ ->>> johnbirthday = datetime(1978, 4, 5, 12, 0) ->>> relativedelta(NOW, johnbirthday) -relativedelta(years=+25, months=+5, days=+12, - hours=+8, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -It works with dates too. -{{{ ->>> relativedelta(TODAY, johnbirthday) -relativedelta(years=+25, months=+5, days=+11, hours=+12) -}}} - -Obtain today's date using the yearday: -{{{ ->>> date(2003, 1, 1)+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -We can use today's date, since yearday should be absolute -in the given year: -{{{ ->>> TODAY+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -Last year it should be in the same day: -{{{ ->>> date(2002, 1, 1)+relativedelta(yearday=260) -datetime.date(2002, 9, 17) -}}} - -But not in a leap year: -{{{ ->>> date(2000, 1, 1)+relativedelta(yearday=260) -datetime.date(2000, 9, 16) -}}} - -We can use the non-leap year day to ignore this: -{{{ ->>> date(2000, 1, 1)+relativedelta(nlyearday=260) -datetime.date(2000, 9, 17) -}}} - -=== rrule === -The rrule module offers a small, complete, and very fast, implementation -of the recurrence rules documented in the -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar RFC], including -support for caching of results. - -==== rrule type ==== -That's the base of the rrule operation. It accepts all the keywords -defined in the RFC as its constructor parameters (except {{{byday}}}, -which was renamed to {{{byweekday}}}) and more. The constructor -prototype is: -{{{ -rrule(freq) -}}} - -Where {{{freq}}} must be one of {{{YEARLY}}}, {{{MONTHLY}}}, -{{{WEEKLY}}}, {{{DAILY}}}, {{{HOURLY}}}, {{{MINUTELY}}}, -or {{{SECONDLY}}}. - -Additionally, it supports the following keyword arguments: - - cache:: - If given, it must be a boolean value specifying to enable - or disable caching of results. If you will use the same - {{{rrule}}} instance multiple times, enabling caching will - improve the performance considerably. - - dtstart:: - The recurrence start. Besides being the base for the - recurrence, missing parameters in the final recurrence - instances will also be extracted from this date. If not - given, {{{datetime.now()}}} will be used instead. - - interval:: - The interval between each {{{freq}}} iteration. For example, - when using {{{YEARLY}}}, an interval of {{{2}}} means - once every two years, but with {{{HOURLY}}}, it means - once every two hours. The default interval is {{{1}}}. - - wkst:: - The week start day. Must be one of the {{{MO}}}, {{{TU}}}, - {{{WE}}} constants, or an integer, specifying the first day - of the week. This will affect recurrences based on weekly - periods. The default week start is got from - {{{calendar.firstweekday()}}}, and may be modified by - {{{calendar.setfirstweekday()}}}. - - count:: - How many occurrences will be generated. - - until:: - If given, this must be a {{{datetime}}} instance, that will - specify the limit of the recurrence. If a recurrence instance - happens to be the same as the {{{datetime}}} instance given - in the {{{until}}} keyword, this will be the last occurrence. - - bysetpos:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each given integer will - specify an occurrence number, corresponding to the nth - occurrence of the rule inside the frequency period. For - example, a {{{bysetpos}}} of {{{-1}}} if combined with a - {{{MONTHLY}}} frequency, and a {{{byweekday}}} of - {{{(MO, TU, WE, TH, FR)}}}, will result in the last work - day of every month. - - bymonth:: - If given, it must be either an integer, or a sequence of - integers, meaning the months to apply the recurrence to. - - bymonthday:: - If given, it must be either an integer, or a sequence of - integers, meaning the month days to apply the recurrence to. - - byyearday:: - If given, it must be either an integer, or a sequence of - integers, meaning the year days to apply the recurrence to. - - byweekno:: - If given, it must be either an integer, or a sequence of - integers, meaning the week numbers to apply the recurrence - to. Week numbers have the meaning described in ISO8601, - that is, the first week of the year is that containing at - least four days of the new year. - - byweekday:: - If given, it must be either an integer ({{{0 == MO}}}), a - sequence of integers, one of the weekday constants - ({{{MO}}}, {{{TU}}}, etc), or a sequence of these constants. - When given, these variables will define the weekdays where - the recurrence will be applied. It's also possible to use - an argument {{{n}}} for the weekday instances, which will - mean the {{{n}}}''th'' occurrence of this weekday in the - period. For example, with {{{MONTHLY}}}, or with - {{{YEARLY}}} and {{{BYMONTH}}}, using {{{FR(+1)}}} - in {{{byweekday}}} will specify the first friday of the - month where the recurrence happens. Notice that in the RFC - documentation, this is specified as {{{BYDAY}}}, but was - renamed to avoid the ambiguity of that keyword. - - byhour:: - If given, it must be either an integer, or a sequence of - integers, meaning the hours to apply the recurrence to. - - byminute:: - If given, it must be either an integer, or a sequence of - integers, meaning the minutes to apply the recurrence to. - - bysecond:: - If given, it must be either an integer, or a sequence of - integers, meaning the seconds to apply the recurrence to. - - byeaster:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each integer will define - an offset from the Easter Sunday. Passing the offset - {{{0}}} to {{{byeaster}}} will yield the Easter Sunday - itself. This is an extension to the RFC specification. - -==== rrule methods ==== -The following methods are available in {{{rrule}}} instances: - - rrule.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.between(after, before, inc=False):: - Returns all the occurrences of the rrule between {{{after}}} - and {{{before}}}. The {{{inc}}} keyword defines what happens - if {{{after}}} and/or {{{before}}} are themselves occurrences. - With {{{inc == True}}}, they will be included in the list, - if they are found in the recurrence set. - - rrule.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rrule}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -rr = rrule(...) -if datetime(...) in rr: - ... -print rr[0] -print rr[-1] -print rr[1:2] -print rr[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== Notes ==== - - * The rrule type has no {{{byday}}} keyword. The equivalent keyword - has been replaced by the {{{byweekday}}} keyword, to remove the - ambiguity present in the original keyword. - - * Unlike documented in the RFC, the starting datetime ({{{dtstart}}}) - is not the first recurrence instance, unless it does fit in the - specified rules. In a python module context, this behavior makes more - sense than otherwise. Notice that you can easily get the original - behavior by using a rruleset and adding the {{{dtstart}}} as an - {{{rdate}}} recurrence. - - * Unlike documented in the RFC, every keyword is valid on every - frequency (the RFC documents that {{{byweekno}}} is only valid - on yearly frequencies, for example). - - * In addition to the documented keywords, a {{{byeaster}}} keyword - was introduced, making it easy to compute recurrent events relative - to the Easter Sunday. - -==== rrule examples ==== -These examples were converted from the RFC. - -Prepare the environment. -{{{ ->>> from dateutil.rrule import * ->>> from dateutil.parser import * ->>> from datetime import * - ->>> import pprint ->>> import sys ->>> sys.displayhook = pprint.pprint -}}} - -Daily, for 10 occurrences. -{{{ ->>> list(rrule(DAILY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0)] -}}} - -Daily until December 24, 1997 -{{{ ->>> list(rrule(DAILY, - dtstart=parse("19970902T090000"), - until=parse("19971224T000000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - (...) - datetime.datetime(1997, 12, 21, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1997, 12, 23, 9, 0)] -}}} - -Every other day, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=2, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0)] -}}} - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=10, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Everyday in January, for 3 years. -{{{ ->>> list(rrule(YEARLY, bymonth=1, byweekday=range(7), - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -[datetime.datetime(1998, 1, 1, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - (...) - datetime.datetime(1998, 1, 30, 9, 0), - datetime.datetime(1998, 1, 31, 9, 0), - datetime.datetime(1999, 1, 1, 9, 0), - datetime.datetime(1999, 1, 2, 9, 0), - (...) - datetime.datetime(1999, 1, 30, 9, 0), - datetime.datetime(1999, 1, 31, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0), - (...) - datetime.datetime(2000, 1, 29, 9, 0), - datetime.datetime(2000, 1, 31, 9, 0)] -}}} - -Same thing, in another way. -{{{ ->>> list(rrule(DAILY, bymonth=1, - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -(...) -}}} - -Weekly for 10 occurrences. -{{{ ->>> list(rrule(WEEKLY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 21, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Every other week, 6 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 11, 9, 0)] -}}} - -Weekly on Tuesday and Thursday for 5 weeks. -{{{ ->>> list(rrule(WEEKLY, count=10, wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 25, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0)] -}}} - -Every other week on Tuesday and Thursday, for 8 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=8, - wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 16, 9, 0)] -}}} - -Monthly on the 1st Friday for ten occurrences. -{{{ ->>> list(rrule(MONTHLY, count=10, byweekday=FR(1), - dtstart=parse("19970905T090000"))) -[datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 10, 3, 9, 0), - datetime.datetime(1997, 11, 7, 9, 0), - datetime.datetime(1997, 12, 5, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - datetime.datetime(1998, 2, 6, 9, 0), - datetime.datetime(1998, 3, 6, 9, 0), - datetime.datetime(1998, 4, 3, 9, 0), - datetime.datetime(1998, 5, 1, 9, 0), - datetime.datetime(1998, 6, 5, 9, 0)] -}}} - -Every other month on the 1st and last Sunday of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=10, - byweekday=(SU(1), SU(-1)), - dtstart=parse("19970907T090000"))) -[datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0), - datetime.datetime(1998, 1, 4, 9, 0), - datetime.datetime(1998, 1, 25, 9, 0), - datetime.datetime(1998, 3, 1, 9, 0), - datetime.datetime(1998, 3, 29, 9, 0), - datetime.datetime(1998, 5, 3, 9, 0), - datetime.datetime(1998, 5, 31, 9, 0)] -}}} - -Monthly on the second to last Monday of the month for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, byweekday=MO(-2), - dtstart=parse("19970922T090000"))) -[datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 20, 9, 0), - datetime.datetime(1997, 11, 17, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1998, 1, 19, 9, 0), - datetime.datetime(1998, 2, 16, 9, 0)] -}}} - -Monthly on the third to the last day of the month, for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, bymonthday=-3, - dtstart=parse("19970928T090000"))) -[datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 10, 29, 9, 0), - datetime.datetime(1997, 11, 28, 9, 0), - datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1998, 1, 29, 9, 0), - datetime.datetime(1998, 2, 26, 9, 0)] -}}} - -Monthly on the 2nd and 15th of the month for 5 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(2,15), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 15, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0)] -}}} - -Monthly on the first and last day of the month for 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(-1,1,), - dtstart=parse("1997090 -2T090000"))) -[datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 1, 9, 0), - datetime.datetime(1997, 10, 31, 9, 0), - datetime.datetime(1997, 11, 1, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0)] -}}} - -Every 18 months on the 10th thru 15th of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=18, count=10, - bymonthday=range(10,16), - dtstart=parse("19970910T090000"))) -[datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 13, 9, 0), - datetime.datetime(1997, 9, 14, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1999, 3, 10, 9, 0), - datetime.datetime(1999, 3, 11, 9, 0), - datetime.datetime(1999, 3, 12, 9, 0), - datetime.datetime(1999, 3, 13, 9, 0)] -}}} - -Every Tuesday, every other month, 6 occurences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=6, byweekday=TU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Yearly in June and July for 10 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, bymonth=(6,7), - dtstart=parse("19970610T0900 -00"))) -[datetime.datetime(1997, 6, 10, 9, 0), - datetime.datetime(1997, 7, 10, 9, 0), - datetime.datetime(1998, 6, 10, 9, 0), - datetime.datetime(1998, 7, 10, 9, 0)] -}}} - -Every 3rd year on the 1st, 100th and 200th day for 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, interval=3, byyearday=(1,100,200), - dtstart=parse("19970101T090000"))) -[datetime.datetime(1997, 1, 1, 9, 0), - datetime.datetime(1997, 4, 10, 9, 0), - datetime.datetime(1997, 7, 19, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0)] -}}} - -Every 20th Monday of the year, 3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekday=MO(20), - dtstart=parse("19970519T090000"))) -[datetime.datetime(1997, 5, 19, 9, 0), - datetime.datetime(1998, 5, 18, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -Monday of week number 20 (where the default start of the week is Monday), -3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekno=20, byweekday=MO, - dtstart=parse("19970512T090000"))) -[datetime.datetime(1997, 5, 12, 9, 0), - datetime.datetime(1998, 5, 11, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -The week number 1 may be in the last year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=1, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1999, 1, 4, 9, 0), - datetime.datetime(2000, 1, 3, 9, 0)] -}}} - -And the week numbers greater than 51 may be in the next year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=52, byweekday=SU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 28, 9, 0), - datetime.datetime(1998, 12, 27, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0)] -}}} - -Only some years have week number 53: -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=53, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 12, 28, 9, 0), - datetime.datetime(2004, 12, 27, 9, 0), - datetime.datetime(2009, 12, 28, 9, 0)] -}}} - -Every Friday the 13th, 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, byweekday=FR, bymonthday=13, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 2, 13, 9, 0), - datetime.datetime(1998, 3, 13, 9, 0), - datetime.datetime(1998, 11, 13, 9, 0), - datetime.datetime(1999, 8, 13, 9, 0)] -}}} - -Every four years, the first Tuesday after a Monday in November, -3 occurrences (U.S. Presidential Election day): -{{{ ->>> list(rrule(YEARLY, interval=4, count=3, bymonth=11, - byweekday=TU, bymonthday=(2,3,4,5,6,7,8), - dtstart=parse("19961105T090000"))) -[datetime.datetime(1996, 11, 5, 9, 0), - datetime.datetime(2000, 11, 7, 9, 0), - datetime.datetime(2004, 11, 2, 9, 0)] -}}} - -The 3rd instance into the month of one of Tuesday, Wednesday or -Thursday, for the next 3 months: -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(TU,WE,TH), - bysetpos=3, dtstart=parse("19970904T090000"))) -[datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 11, 6, 9, 0)] -}}} - -The 2nd to last weekday of the month, 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(MO,TU,WE,TH,FR), - bysetpos=-2, dtstart=parse("19970929T090000"))) -[datetime.datetime(1997, 9, 29, 9, 0), - datetime.datetime(1997, 10, 30, 9, 0), - datetime.datetime(1997, 11, 27, 9, 0)] -}}} - -Every 3 hours from 9:00 AM to 5:00 PM on a specific day. -{{{ ->>> list(rrule(HOURLY, interval=3, - dtstart=parse("19970902T090000"), - until=parse("19970902T170000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 15, 0)] -}}} - -Every 15 minutes for 6 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=15, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 15), - datetime.datetime(1997, 9, 2, 9, 30), - datetime.datetime(1997, 9, 2, 9, 45), - datetime.datetime(1997, 9, 2, 10, 0), - datetime.datetime(1997, 9, 2, 10, 15)] -}}} - -Every hour and a half for 4 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=90, count=4, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 10, 30), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 13, 30)] -}}} - -Every 20 minutes from 9:00 AM to 4:40 PM for two days. -{{{ ->>> list(rrule(MINUTELY, interval=20, count=48, - byhour=range(9,17), byminute=(0,20,40), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 20), - (...) - datetime.datetime(1997, 9, 2, 16, 20), - datetime.datetime(1997, 9, 2, 16, 40), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 3, 9, 20), - (...) - datetime.datetime(1997, 9, 3, 16, 20), - datetime.datetime(1997, 9, 3, 16, 40)] -}}} - -An example where the days generated makes a difference because of {{{wkst}}}. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=MO, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 10, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 24, 9, 0)] - ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=SU, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 17, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 31, 9, 0)] -}}} - -==== rruleset type ==== -The {{{rruleset}}} type allows more complex recurrence setups, mixing -multiple rules, dates, exclusion rules, and exclusion dates. -The type constructor takes the following keyword arguments: - - cache:: - If True, caching of results will be enabled, improving performance - of multiple queries considerably. - -==== rruleset methods ==== -The following methods are available: - - rruleset.rrule(rrule):: - Include the given {{{rrule}}} instance in the recurrence set - generation. - - rruleset.rdate(dt):: - Include the given {{{datetime}}} instance in the recurrence - set generation. - - rruleset.exrule(rrule):: - Include the given {{{rrule}}} instance in the recurrence set - exclusion list. Dates which are part of the given recurrence - rules will not be generated, even if some inclusive {{{rrule}}} - or {{{rdate}}} matches them. - - rruleset.exdate(dt):: - Include the given {{{datetime}}} instance in the recurrence set - exclusion list. Dates included that way will not be generated, - even if some inclusive {{{rrule}}} or {{{rdate}}} matches them. - - rruleset.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.between(after, before, inc=False):: - Returns all the occurrences of the rrule between {{{after}}} - and {{{before}}}. The {{{inc}}} keyword defines what happens - if {{{after}}} and/or {{{before}}} are themselves occurrences. - With {{{inc == True}}}, they will be included in the list, - if they are found in the recurrence set. - - rruleset.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rruleset}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -set = rruleset(...) -if datetime(...) in set: - ... -print set[0] -print set[-1] -print set[1:2] -print set[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== rruleset examples ==== -Daily, for 7 days, jumping Saturday and Sunday occurrences. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(DAILY, count=7, - dtstart=parse("19970902T090000"))) ->>> set.exrule(rrule(YEARLY, byweekday=(SA,SU), - dtstart=parse("19970902T090000"))) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0)] -}}} - -Weekly, for 4 weeks, plus one time on day 7, and not on day 16. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(WEEKLY, count=4, - dtstart=parse("19970902T090000"))) ->>> set.rdate(datetime.datetime(1997, 9, 7, 9, 0)) ->>> set.exdate(datetime.datetime(1997, 9, 16, 9, 0)) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0)] -}}} - -==== rrulestr() function ==== -The {{{rrulestr()}}} function is a parser for ''RFC-like'' syntaxes. -The function prototype is: -{{{ -rrulestr(str) -}}} - -The string passed as parameter may be a multiple line string, a -single line string, or just the {{{RRULE}}} property value. - -Additionally, it accepts the following keyword arguments: - - cache:: - If {{{True}}}, the {{{rruleset}}} or {{{rrule}}} created instance - will cache its results. Default is not to cache. - - dtstart:: - If given, it must be a {{{datetime}}} instance that will be used - when no {{{DTSTART}}} property is found in the parsed string. If - it is not given, and the property is not found, {{{datetime.now()}}} - will be used instead. - - unfold:: - If set to {{{True}}}, lines will be unfolded following the RFC - specification. It defaults to {{{False}}}, meaning that spaces - before every line will be stripped. - - forceset:: - If set to {{{True}}} a {{{rruleset}}} instance will be returned, - even if only a single rule is found. The default is to return an - {{{rrule}}} if possible, and an {{{rruleset}}} if necessary. - - compatible:: - If set to {{{True}}}, the parser will operate in RFC-compatible - mode. Right now it means that {{{unfold}}} will be turned on, - and if a {{{DTSTART}}} is found, it will be considered the first - recurrence instance, as documented in the RFC. - - ignoretz:: - If set to {{{True}}}, the date parser will ignore timezone - information available in the {{{DTSTART}}} property, or the - {{{UNTIL}}} attribute. - - tzinfos:: - If set, it will be passed to the datetime string parser to - resolve unknown timezone settings. For more information about - what could be used here, check the parser documentation. - -==== rrulestr() examples ==== - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """)) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Same thing, but passing only the {{{RRULE}}} value. -{{{ ->>> list(rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Notice that when using a single rule, it returns an -{{{rrule}}} instance, unless {{{forceset}}} was used. -{{{ ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5") - - ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """) - - ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", forceset=True) - -}}} - -But when an {{{rruleset}}} is needed, it is automatically used. -{{{ ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... RRULE:FREQ=DAILY;INTERVAL=5;COUNT=3 -... """) - -}}} - -=== parser === -This module offers a generic date/time string parser which is -able to parse most known formats to represent a date and/or -time. - -==== parse() function ==== -That's probably the only function you'll need from this module. -It offers you an interface to access the parser functionality and -extract a {{{datetime}}} type out of a string. - -The prototype of this function is: -{{{ -parse(timestr) -}}} - -Additionally, the following keyword arguments are available: - - default:: - If given, this must be a {{{datetime}}} instance. Any fields - missing in the parsed date will be copied from this instance. - The default value is the current date, at 00:00:00am. - - ignoretz:: - If this is true, even if a timezone is found in the string, - the parser will not use it. - - tzinfos:: - Using this keyword argument you may provide custom timezones - to the parser. If given, it must be either a dictionary with - the timezone abbreviation as key, or a function accepting a - timezone abbreviation and offset as argument. The dictionary - values and the function return must be a timezone offset - in seconds, a tzinfo subclass, or a string defining the - timezone (in the TZ environment variable format). - - dayfirst:: - This option allow one to change the precedence in which - days are parsed in date strings. The default is given in the - parserinfo instance (the default parserinfo has it set to - False). If {{{dayfirst}}} is False, the {{{MM-DD-YYYY}}} - format will have precedence over {{{DD-MM-YYYY}}} in an - ambiguous date. - - yearfirst:: - This option allow one to change the precedence in which - years are parsed in date strings. The default is given in - the parserinfo instance (the default parserinfo has it set - to False). If {{{yearfirst}}} is false, the {{{MM-DD-YY}}} - format will have precedence over {{{YY-MM-DD}}} in an - ambiguous date. - - fuzzy:: - If {{{fuzzy}}} is set to True, unknown tokens in the string - will be ignored. - - parserinfo:: - This parameter allows one to change how the string is parsed, - by using a different parserinfo class instance. Using it you - may, for example, intenationalize the parser strings, or make - it ignore additional words. - -==== Format precedence ==== -Whenever an ambiguous date is found, the {{{dayfirst}}} and -{{{yearfirst}}} parameters will control how the information -is processed. Here is the precedence in each case: - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{False}}}, -(default, if no parameter is given): - - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{False}}}: - - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - -==== Converting two digit years ==== -When a two digit year is found, it is processed considering -the current year, so that the computed year is never more -than 49 years after the current year, nor 50 years before the -current year. In other words, if we are in year 2003, and the -year 30 is found, it will be considered as 2030, but if the -year 60 is found, it will be considered 1960. - -==== Examples ==== -The following code will prepare the environment: -{{{ ->>> from dateutil.parser import * ->>> from dateutil.tz import * ->>> from datetime import * ->>> TZOFFSETS = {"BRST": -10800} ->>> BRSTTZ = tzoffset(-10800, "BRST") ->>> DEFAULT = datetime(2003, 9, 25) -}}} - -Some simple examples based on the {{{date}}} command, using the -{{{TZOFFSET}}} dictionary to provide the BRST timezone offset. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) - ->>> parse("2003 10:36:28 BRST 25 Sep Thu", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) -}}} - -Notice that since BRST is my local timezone, parsing it without -further timezone settings will yield a {{{tzlocal}}} timezone. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzlocal()) -}}} - -We can also ask to ignore the timezone explicitly: -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", ignoretz=True) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -That's the same as processing a string without timezone: -{{{ ->>> parse("Thu Sep 25 10:36:28 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Without the year, but passing our {{{DEFAULT}}} datetime to return -the same year, no mattering what year we currently are in: -{{{ ->>> parse("Thu Sep 25 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Strip it further: -{{{ ->>> parse("Thu Sep 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) - ->>> parse("10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) ->>> -}}} - -Strip in a different way: -{{{ ->>> parse("Thu Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Another format, based on {{{date -R}}} (RFC822): -{{{ ->>> parse("Thu, 25 Sep 2003 10:49:41 -0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -ISO format: -{{{ ->>> parse("2003-09-25T10:49:41.5-03:00") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzoffset(None, -10800)) -}}} - -Some variations: -{{{ ->>> parse("2003-09-25T10:49:41") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("2003-09-25T10:49") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("2003-09-25T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -ISO format, without separators: -{{{ ->>> parse("20030925T104941.5-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("20030925T1049") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("20030925T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("20030925") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Everything together. -{{{ ->>> parse("199709020900") -datetime.datetime(1997, 9, 2, 9, 0) ->>> parse("19970902090059") -datetime.datetime(1997, 9, 2, 9, 0, 59) -}}} - -Different date orderings: -{{{ ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003-Sep-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-Sep-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("09-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-09-2003") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Check some ambiguous dates: -{{{ ->>> parse("10-09-2003") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-2003", dayfirst=True) -datetime.datetime(2003, 9, 10, 0, 0) - ->>> parse("10-09-03") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-03", yearfirst=True) -datetime.datetime(2010, 9, 3, 0, 0) -}}} - -Other date separators are allowed: -{{{ ->>> parse("2003.Sep.25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003/09/25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Even with spaces: -{{{ ->>> parse("2003 Sep 25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003 09 25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Hours with letters work: -{{{ ->>> parse("10h36m28.5s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28, 500000) - ->>> parse("01s02h03m", default=DEFAULT) -datetime.datetime(2003, 9, 25, 2, 3, 1) - ->>> parse("01h02m03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 1, 2) - ->>> parse("01h02", default=DEFAULT) -datetime.datetime(2003, 9, 2, 1, 0) - ->>> parse("01h02s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 1, 0, 2) -}}} - -With AM/PM: -{{{ ->>> parse("10h am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("10pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 22, 0) - ->>> parse("12:00am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("12pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 12, 0) -}}} - -Some special treating for ''pertain'' relations: -{{{ ->>> parse("Sep 03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 0, 0) - ->>> parse("Sep of 03", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Fuzzy parsing: -{{{ ->>> s = "Today is 25 of September of 2003, exactly " \ -... "at 10:49:41 with timezone -03:00." ->>> parse(s, fuzzy=True) -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -Other random formats: -{{{ ->>> parse("Wed, July 10, '96") -datetime.datetime(1996, 7, 10, 0, 0) - ->>> parse("1996.07.10 AD at 15:08:56 PDT", ignoretz=True) -datetime.datetime(1996, 7, 10, 15, 8, 56) - ->>> parse("Tuesday, April 12, 1952 AD 3:30:42pm PST", ignoretz=True) -datetime.datetime(1952, 4, 12, 15, 30, 42) - ->>> parse("November 5, 1994, 8:15:30 am EST", ignoretz=True) -datetime.datetime(1994, 11, 5, 8, 15, 30) - ->>> parse("3rd of May 2001") -datetime.datetime(2001, 5, 3, 0, 0) - ->>> parse("5:50 A.M. on June 13, 1990") -datetime.datetime(1990, 6, 13, 5, 50) -}}} - -=== easter === -This module offers a generic easter computing method for -any given year, using Western, Orthodox or Julian algorithms. - -==== easter() function ==== -This method was ported from the work done by -[http://users.chariot.net.au/~gmarts/eastalg.htm GM Arts], -on top of the algorithm by -[http://www.tondering.dk/claus/calendar.html Claus Tondering], -which was based in part on the algorithm of Ouding (1940), -as quoted in "Explanatory Supplement to the Astronomical -Almanac", P. Kenneth Seidelmann, editor. - -This algorithm implements three different easter -calculation methods: - - 1. Original calculation in Julian calendar, valid in - dates after 326 AD - 1. Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 1. Revised method, in Gregorian calendar, valid in - years 1583 to 4099 as well - -These methods are represented by the constants: -{{{ -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 -}}} - -The default method is method 3. - -=== tz === -This module offers timezone implementations subclassing -the abstract {{{datetime.tzinfo}}} type. There are -classes to handle [http://www.twinsun.com/tz/tz-link.htm tzfile] -format files (usually are in /etc/localtime, -/usr/share/zoneinfo, etc), TZ environment string (in all -known formats), given ranges (with help from relative -deltas), local machine timezone, fixed offset timezone, -and UTC timezone. - -==== tzutc type ==== -This type implements a basic UTC timezone. The constructor of this -type accepts no parameters. - -==== tzutc examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now() -datetime.datetime(2003, 9, 27, 9, 40, 1, 521290) - ->>> datetime.now(tzutc()) -datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc()) - ->>> datetime.now(tzutc()).tzname() -'UTC' -}}} - -==== tzoffset type ==== -This type implements a fixed offset timezone, with no -support to daylight saving times. Here is the prototype of the -type constructor: -{{{ -tzoffset(name, offset) -}}} - -The {{{name}}} parameter may be optionally set to {{{None}}}, and -{{{offset}}} must be given in seconds. - -==== tzoffset examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzoffset("BRST", -10800)) -datetime.datetime(2003, 9, 27, 9, 52, 43, 624904, - tzinfo=tzinfo=tzoffset('BRST', -10800)) - ->>> datetime.now(tzoffset("BRST", -10800)).tzname() -'BRST' - ->>> datetime.now(tzoffset("BRST", -10800)).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 12, 53, 11, 446419, - tzinfo=tzutc()) -}}} - -==== tzlocal type ==== -This type implements timezone settings as known by the -operating system. The constructor of this type accepts no -parameters. - -==== tzlocal examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzlocal()) -datetime.datetime(2003, 9, 27, 10, 1, 43, 673605, - tzinfo=tzlocal()) - ->>> datetime.now(tzlocal()).tzname() -'BRST' - ->>> datetime.now(tzlocal()).astimezone(tzoffset(None, 0)) -datetime.datetime(2003, 9, 27, 13, 3, 0, 11493, - tzinfo=tzoffset(None, 0)) -}}} - -==== tzstr type ==== -This type implements timezone settings extracted from a -string in known TZ environment variable formats. Here is the prototype -of the constructor: -{{{ -tzstr(str) -}}} - -==== tzstr examples ==== -Here are examples of the recognized formats: - - * {{{EST5EDT}}} - * {{{EST5EDT,4,0,6,7200,10,0,26,7200,3600}}} - * {{{EST5EDT,4,1,0,7200,10,-1,0,7200,3600}}} - * {{{EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00}}} - * {{{EST5EDT4,95/02:00:00,298/02:00}}} - * {{{EST5EDT4,J96/02:00:00,J299/02:00}}} - -Notice that if daylight information is not present, but a -daylight abbreviation was provided, {{{tzstr}}} will follow the -convention of using the first sunday of April to start daylight -saving, and the last sunday of October to end it. If start or -end time is not present, 2AM will be used, and if the daylight -offset is not present, the standard offset plus one hour will -be used. This convention is the same as used in the GNU libc. - -This also means that some of the above examples are exactly -equivalent, and all of these examples are equivalent -in the year of 2003. - -Here is the example mentioned in the -[http://www.python.org/doc/current/lib/module-time.html time module documentation]. -{{{ ->>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'16:08:12 05/08/03 AEST' -}}} - -And here is an example showing the same information using {{{tzstr}}}, -without touching system settings. -{{{ ->>> tz1 = tzstr('EST+05EDT,M4.1.0,M10.5.0') ->>> tz2 = tzstr('AEST-10AEDT-11,M10.5.0,M3.5.0') ->>> dt = datetime(2003, 5, 8, 2, 7, 36, tzinfo=tz1) ->>> dt.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> dt.astimezone(tz2).strftime('%X %x %Z') -'16:07:36 05/08/03 AEST' -}}} - -Are these really equivalent? -{{{ ->>> tzstr('EST5EDT') == tzstr('EST5EDT,4,1,0,7200,10,-1,0,7200,3600') -True -}}} - -Check the daylight limit. -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzrange type ==== -This type offers the same functionality as the {{{tzstr}}} type, but -instead of timezone strings, information is passed using -{{{relativedelta}}}s which are applied to a datetime set to the first -day of the year. Here is the prototype of this type's constructor: -{{{ -tzrange(stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, - start=None, end=None): -}}} - -Offsets must be given in seconds. Information not provided will be -set to the defaults, as explained in the {{{tzstr}}} section above. - -==== tzrange examples ==== -{{{ ->>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT") -True - ->>> from dateutil.relativedelta import * ->>> range1 = tzrange("EST", -18000, "EDT") ->>> range2 = tzrange("EST", -18000, "EDT", -14400, -... relativedelta(hours=+2, month=4, day=1, - weekday=SU(+1)), -... relativedelta(hours=+1, month=10, day=31, - weekday=SU(-1))) ->>> tzstr('EST5EDT') == range1 == range2 -True -}}} - -Notice a minor detail in the last example: while the DST should end -at 2AM, the delta will catch 1AM. That's because the daylight saving -time should end at 2AM standard time (the difference between STD and -DST is 1h in the given example) instead of the DST time. That's how -the {{{tzinfo}}} subtypes should deal with the extra hour that happens -when going back to the standard time. Check -[http://www.python.org/doc/current/lib/datetime-tzinfo.html tzinfo documentation] -for more information. - -==== tzfile type ==== -This type allows one to use tzfile(5) format timezone files to extract -current and historical zone information. Here is the type constructor -prototype: -{{{ -tzfile(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzfile examples ==== -{{{ ->>> tz = tzfile("/etc/localtime") ->>> datetime.now(tz) -datetime.datetime(2003, 9, 27, 12, 3, 48, 392138, - tzinfo=tzfile('/etc/localtime')) - ->>> datetime.now(tz).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 15, 3, 53, 70863, - tzinfo=tzutc()) - ->>> datetime.now(tz).tzname() -'BRST' ->>> datetime(2003, 1, 1, tzinfo=tz).tzname() -'BRDT' -}}} - -Check the daylight limit. -{{{ ->>> tz = tzfile('/usr/share/zoneinfo/EST5EDT') ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzical type ==== -This type is able to parse -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] -style {{{VTIMEZONE}}} sessions into a Python timezone object. -The constuctor prototype is: -{{{ -tzical(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzical methods ==== - - tzical.get(tzid=None):: - Since a single iCalendar file may contain more than one timezone, - you must ask for the timezone you want with this method. If there's - more than one timezone in the parsed file, you'll need to pass the - {{{tzid}}} parameter. Otherwise, leaving it empty will yield the only - available timezone. - -==== tzical examples ==== -Here is a sample file extracted from the RFC. This file defines -the {{{EST5EDT}}} timezone, and will be used in the following example. -{{{ -BEGIN:VTIMEZONE -TZID:US-Eastern -LAST-MODIFIED:19870101T000000Z -TZURL:http://zones.stds_r_us.net/tz/US-Eastern -BEGIN:STANDARD -DTSTART:19671029T020000 -RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 -TZOFFSETFROM:-0400 -TZOFFSETTO:-0500 -TZNAME:EST -END:STANDARD -BEGIN:DAYLIGHT -DTSTART:19870405T020000 -RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 -TZOFFSETFROM:-0500 -TZOFFSETTO:-0400 -TZNAME:EDT -END:DAYLIGHT -END:VTIMEZONE -}}} - -And here is an example exploring a {{{tzical}}} type: -{{{ ->>> from dateutil.tz import *; from datetime import * - ->>> tz = tzical('EST5EDT.ics') ->>> tz.keys() -['US-Eastern'] - ->>> est = tz.get('US-Eastern') ->>> est - - ->>> datetime.now(est) -datetime.datetime(2003, 10, 6, 19, 44, 18, 667987, - tzinfo=) - ->>> est == tz.get() -True -}}} - -Let's check the daylight ranges, as usual: -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=est).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=est).tzname() -'EDT' - ->>> datetime(2003, 10, 26, 0, 59, tzinfo=est).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=est).tzname() -'EST' -}}} - -==== tzwin type ==== -This type offers access to internal registry-based Windows timezones. -The constuctor prototype is: -{{{ -tzwin(name) -}}} - -Where {{{name}}} is the timezone name. There's a static {{{tzwin.list()}}} -method to check the available names, - -==== tzwin methods ==== - - tzwin.display():: - This method returns the timezone extended name. - - tzwin.list():: - This static method lists all available timezone names. - -==== tzwin examples ==== -{{{ ->>> tz = tzwin("E. South America Standard Time") -}}} - -==== tzwinlocal type ==== -This type offers access to internal registry-based Windows timezones. -The constructor accepts no parameters, so the prototype is: -{{{ -tzwinlocal() -}}} - -==== tzwinlocal methods ==== - - tzwinlocal.display():: - This method returns the timezone extended name, and returns - {{{None}}} if one is not available. - -==== tzwinlocal examples ==== -{{{ ->>> tz = tzwinlocal() -}}} - -==== gettz() function ==== -This function is a helper that will try its best to get the right -timezone for your environment, or for the given string. The prototype -is as follows: -{{{ -gettz(name=None) -}}} - -If given, the parameter may be a filename, a path relative to the base -of the timezone information path (the base could be -{{{/usr/share/zoneinfo}}}, for example), a string timezone -specification, or a timezone abbreviation. If {{{name}}} is not given, -and the {{{TZ}}} environment variable is set, it's used instead. If the -parameter is not given, and {{{TZ}}} is not set, the default tzfile -paths will be tried. Then, if no timezone information is found, -an internal compiled database of timezones is used. When running -on Windows, the internal registry-based Windows timezones are also -considered. - -Example: -{{{ ->>> from dateutil.tz import * ->>> gettz() -tzfile('/etc/localtime') - ->>> gettz("America/Sao Paulo") -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> gettz("EST5EDT") -tzfile('/usr/share/zoneinfo/EST5EDT') - ->>> gettz("EST5") -tzstr('EST5') - ->>> gettz('BRST') -tzlocal() - ->>> os.environ["TZ"] = "America/Sao Paulo" ->>> gettz() -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> os.environ["TZ"] = "BRST" ->>> gettz() -tzlocal() - ->>> gettz("Unavailable") ->>> -}}} - -=== zoneinfo === -This module provides direct access to the internal compiled -database of timezones. The timezone data and the compiling tools -are obtained from the following project: - - http://www.twinsun.com/tz/tz-link.htm - -==== gettz() function ==== -This function will try to retrieve the given timezone information -from the internal compiled database, and will cache its results. - -Example: -{{{ ->>> from dateutil import zoneinfo ->>> zoneinfo.gettz("Brazil/East") -tzfile('Brazil/East') -}}} - -## vim:ft=moin diff --git a/lib/dateutil_py3/__init__.py b/lib/dateutil_py3/__init__.py deleted file mode 100644 index a23cea5218cc..000000000000 --- a/lib/dateutil_py3/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__author__ = "Tomi Pieviläinen " -__license__ = "Simplified BSD" -__version__ = "2.1-mpl" diff --git a/lib/dateutil_py3/easter.py b/lib/dateutil_py3/easter.py deleted file mode 100644 index d8a38844f9e3..000000000000 --- a/lib/dateutil_py3/easter.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -import datetime - -__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] - -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 - -def easter(year, method=EASTER_WESTERN): - """ - This method was ported from the work done by GM Arts, - on top of the algorithm by Claus Tondering, which was - based in part on the algorithm of Ouding (1940), as - quoted in "Explanatory Supplement to the Astronomical - Almanac", P. Kenneth Seidelmann, editor. - - This algorithm implements three different easter - calculation methods: - - 1 - Original calculation in Julian calendar, valid in - dates after 326 AD - 2 - Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 3 - Revised method, in Gregorian calendar, valid in - years 1583 to 4099 as well - - These methods are represented by the constants: - - EASTER_JULIAN = 1 - EASTER_ORTHODOX = 2 - EASTER_WESTERN = 3 - - The default method is method 3. - - More about the algorithm may be found at: - - http://users.chariot.net.au/~gmarts/eastalg.htm - - and - - http://www.tondering.dk/claus/calendar.html - - """ - - if not (1 <= method <= 3): - raise ValueError("invalid method") - - # g - Golden year - 1 - # c - Century - # h - (23 - Epact) mod 30 - # i - Number of days from March 21 to Paschal Full Moon - # j - Weekday for PFM (0=Sunday, etc) - # p - Number of days from March 21 to Sunday on or before PFM - # (-6 to 28 methods 1 & 3, to 56 for method 2) - # e - Extra days to add for method 2 (converting Julian - # date to Gregorian date) - - y = year - g = y % 19 - e = 0 - if method < 3: - # Old method - i = (19*g+15)%30 - j = (y+y//4+i)%7 - if method == 2: - # Extra dates to convert Julian to Gregorian date - e = 10 - if y > 1600: - e = e+y//100-16-(y//100-16)//4 - else: - # New method - c = y//100 - h = (c-c//4-(8*c+13)//25+19*g+15)%30 - i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11)) - j = (y+y//4+i+2-c+c//4)%7 - - # p can be from -6 to 56 corresponding to dates 22 March to 23 May - # (later dates apply to method 2, although 23 May never actually occurs) - p = i-j+e - d = 1+(p+27+(p+6)//40)%31 - m = 3+(p+26)//30 - return datetime.date(int(y), int(m), int(d)) - diff --git a/lib/dateutil_py3/parser.py b/lib/dateutil_py3/parser.py deleted file mode 100644 index a2604a35ba06..000000000000 --- a/lib/dateutil_py3/parser.py +++ /dev/null @@ -1,909 +0,0 @@ -# -*- coding:iso-8859-1 -*- -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -from __future__ import unicode_literals -__license__ = "Simplified BSD" - - -import datetime -import string -import time -import sys -import os -import collections - -try: - from io import StringIO -except ImportError: - from io import StringIO - -from six import text_type, binary_type, integer_types - -from . import relativedelta -from . import tz - - -__all__ = ["parse", "parserinfo"] - - -# Some pointers: -# -# http://www.cl.cam.ac.uk/~mgk25/iso-time.html -# http://www.iso.ch/iso/en/prods-services/popstds/datesandtime.html -# http://www.w3.org/TR/NOTE-datetime -# http://ringmaster.arc.nasa.gov/tools/time_formats.html -# http://search.cpan.org/author/MUIR/Time-modules-2003.0211/lib/Time/ParseDate.pm -# http://stein.cshl.org/jade/distrib/docs/java.text.SimpleDateFormat.html - - -class _timelex(object): - - def __init__(self, instream): - if isinstance(instream, text_type): - instream = StringIO(instream) - self.instream = instream - self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' - 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' - 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ') - self.numchars = '0123456789' - self.whitespace = ' \t\r\n' - self.charstack = [] - self.tokenstack = [] - self.eof = False - - def get_token(self): - if self.tokenstack: - return self.tokenstack.pop(0) - seenletters = False - token = None - state = None - wordchars = self.wordchars - numchars = self.numchars - whitespace = self.whitespace - while not self.eof: - if self.charstack: - nextchar = self.charstack.pop(0) - else: - nextchar = self.instream.read(1) - while nextchar == '\x00': - nextchar = self.instream.read(1) - if not nextchar: - self.eof = True - break - elif not state: - token = nextchar - if nextchar in wordchars: - state = 'a' - elif nextchar in numchars: - state = '0' - elif nextchar in whitespace: - token = ' ' - break # emit token - else: - break # emit token - elif state == 'a': - seenletters = True - if nextchar in wordchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0': - if nextchar in numchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == 'a.': - seenletters = True - if nextchar == '.' or nextchar in wordchars: - token += nextchar - elif nextchar in numchars and token[-1] == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0.': - if nextchar == '.' or nextchar in numchars: - token += nextchar - elif nextchar in wordchars and token[-1] == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - if (state in ('a.', '0.') and - (seenletters or token.count('.') > 1 or token[-1] == '.')): - l = token.split('.') - token = l[0] - for tok in l[1:]: - self.tokenstack.append('.') - if tok: - self.tokenstack.append(tok) - return token - - def __iter__(self): - return self - - def __next__(self): - token = self.get_token() - if token is None: - raise StopIteration - return token - - def next(self): - return self.__next__() # Python 2.x support - - def split(cls, s): - return list(cls(s)) - split = classmethod(split) - - -class _resultbase(object): - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def _repr(self, classname): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, repr(value))) - return "%s(%s)" % (classname, ", ".join(l)) - - def __repr__(self): - return self._repr(self.__class__.__name__) - - -class parserinfo(object): - - # m from a.m/p.m, t from ISO T separator - JUMP = [" ", ".", ",", ";", "-", "/", "'", - "at", "on", "and", "ad", "m", "t", "of", - "st", "nd", "rd", "th"] - - WEEKDAYS = [("Mon", "Monday"), - ("Tue", "Tuesday"), - ("Wed", "Wednesday"), - ("Thu", "Thursday"), - ("Fri", "Friday"), - ("Sat", "Saturday"), - ("Sun", "Sunday")] - MONTHS = [("Jan", "January"), - ("Feb", "February"), - ("Mar", "March"), - ("Apr", "April"), - ("May", "May"), - ("Jun", "June"), - ("Jul", "July"), - ("Aug", "August"), - ("Sep", "Sept", "September"), - ("Oct", "October"), - ("Nov", "November"), - ("Dec", "December")] - HMS = [("h", "hour", "hours"), - ("m", "minute", "minutes"), - ("s", "second", "seconds")] - AMPM = [("am", "a"), - ("pm", "p")] - UTCZONE = ["UTC", "GMT", "Z"] - PERTAIN = ["of"] - TZOFFSET = {} - - def __init__(self, dayfirst=False, yearfirst=False): - self._jump = self._convert(self.JUMP) - self._weekdays = self._convert(self.WEEKDAYS) - self._months = self._convert(self.MONTHS) - self._hms = self._convert(self.HMS) - self._ampm = self._convert(self.AMPM) - self._utczone = self._convert(self.UTCZONE) - self._pertain = self._convert(self.PERTAIN) - - self.dayfirst = dayfirst - self.yearfirst = yearfirst - - self._year = time.localtime().tm_year - self._century = self._year//100*100 - - def _convert(self, lst): - dct = {} - for i in range(len(lst)): - v = lst[i] - if isinstance(v, tuple): - for v in v: - dct[v.lower()] = i - else: - dct[v.lower()] = i - return dct - - def jump(self, name): - return name.lower() in self._jump - - def weekday(self, name): - if len(name) >= 3: - try: - return self._weekdays[name.lower()] - except KeyError: - pass - return None - - def month(self, name): - if len(name) >= 3: - try: - return self._months[name.lower()]+1 - except KeyError: - pass - return None - - def hms(self, name): - try: - return self._hms[name.lower()] - except KeyError: - return None - - def ampm(self, name): - try: - return self._ampm[name.lower()] - except KeyError: - return None - - def pertain(self, name): - return name.lower() in self._pertain - - def utczone(self, name): - return name.lower() in self._utczone - - def tzoffset(self, name): - if name in self._utczone: - return 0 - return self.TZOFFSET.get(name) - - def convertyear(self, year): - if year < 100: - year += self._century - if abs(year-self._year) >= 50: - if year < self._year: - year += 100 - else: - year -= 100 - return year - - def validate(self, res): - # move to info - if res.year is not None: - res.year = self.convertyear(res.year) - if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z': - res.tzname = "UTC" - res.tzoffset = 0 - elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): - res.tzoffset = 0 - return True - - -class parser(object): - - def __init__(self, info=None): - self.info = info or parserinfo() - - def parse(self, timestr, default=None, - ignoretz=False, tzinfos=None, - **kwargs): - if not default: - default = datetime.datetime.now().replace(hour=0, minute=0, - second=0, microsecond=0) - res = self._parse(timestr, **kwargs) - if res is None: - raise ValueError("unknown string format") - repl = {} - for attr in ["year", "month", "day", "hour", - "minute", "second", "microsecond"]: - value = getattr(res, attr) - if value is not None: - repl[attr] = value - ret = default.replace(**repl) - if res.weekday is not None and not res.day: - ret = ret+relativedelta.relativedelta(weekday=res.weekday) - if not ignoretz: - if isinstance(tzinfos, collections.Callable) or tzinfos and res.tzname in tzinfos: - if isinstance(tzinfos, collections.Callable): - tzdata = tzinfos(res.tzname, res.tzoffset) - else: - tzdata = tzinfos.get(res.tzname) - if isinstance(tzdata, datetime.tzinfo): - tzinfo = tzdata - elif isinstance(tzdata, text_type): - tzinfo = tz.tzstr(tzdata) - elif isinstance(tzdata, integer_types): - tzinfo = tz.tzoffset(res.tzname, tzdata) - else: - raise ValueError("offset must be tzinfo subclass, " \ - "tz string, or int offset") - ret = ret.replace(tzinfo=tzinfo) - elif res.tzname and res.tzname in time.tzname: - ret = ret.replace(tzinfo=tz.tzlocal()) - elif res.tzoffset == 0: - ret = ret.replace(tzinfo=tz.tzutc()) - elif res.tzoffset: - ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) - return ret - - class _result(_resultbase): - __slots__ = ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond", - "tzname", "tzoffset"] - - def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False): - info = self.info - if dayfirst is None: - dayfirst = info.dayfirst - if yearfirst is None: - yearfirst = info.yearfirst - res = self._result() - l = _timelex.split(timestr) - try: - - # year/month/day list - ymd = [] - - # Index of the month string in ymd - mstridx = -1 - - len_l = len(l) - i = 0 - while i < len_l: - - # Check if it's a number - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - value = None - - if value is not None: - # Token is a number - len_li = len(l[i]) - i += 1 - if (len(ymd) == 3 and len_li in (2, 4) - and (i >= len_l or (l[i] != ':' and - info.hms(l[i]) is None))): - # 19990101T23[59] - s = l[i-1] - res.hour = int(s[:2]) - if len_li == 4: - res.minute = int(s[2:]) - elif len_li == 6 or (len_li > 6 and l[i-1].find('.') == 6): - # YYMMDD or HHMMSS[.ss] - s = l[i-1] - if not ymd and l[i-1].find('.') == -1: - ymd.append(info.convertyear(int(s[:2]))) - ymd.append(int(s[2:4])) - ymd.append(int(s[4:])) - else: - # 19990101T235959[.59] - res.hour = int(s[:2]) - res.minute = int(s[2:4]) - res.second, res.microsecond = _parsems(s[4:]) - elif len_li == 8: - # YYYYMMDD - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:])) - elif len_li in (12, 14): - # YYYYMMDDhhmm[ss] - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:8])) - res.hour = int(s[8:10]) - res.minute = int(s[10:12]) - if len_li == 14: - res.second = int(s[12:]) - elif ((i < len_l and info.hms(l[i]) is not None) or - (i+1 < len_l and l[i] == ' ' and - info.hms(l[i+1]) is not None)): - # HH[ ]h or MM[ ]m or SS[.ss][ ]s - if l[i] == ' ': - i += 1 - idx = info.hms(l[i]) - while True: - if idx == 0: - res.hour = int(value) - if value%1: - res.minute = int(60*(value%1)) - elif idx == 1: - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - elif idx == 2: - res.second, res.microsecond = \ - _parsems(value_repr) - i += 1 - if i >= len_l or idx == 2: - break - # 12h00 - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - break - else: - i += 1 - idx += 1 - if i < len_l: - newidx = info.hms(l[i]) - if newidx is not None: - idx = newidx - elif i == len_l and l[i-2] == ' ' and info.hms(l[i-3]) is not None: - # X h MM or X m SS - idx = info.hms(l[i-3]) + 1 - if idx == 1: - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - elif idx == 2: - res.second, res.microsecond = \ - _parsems(value_repr) - i += 1 - elif i+1 < len_l and l[i] == ':': - # HH:MM[:SS[.ss]] - res.hour = int(value) - i += 1 - value = float(l[i]) - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - i += 1 - if i < len_l and l[i] == ':': - res.second, res.microsecond = _parsems(l[i+1]) - i += 2 - elif i < len_l and l[i] in ('-', '/', '.'): - sep = l[i] - ymd.append(int(value)) - i += 1 - if i < len_l and not info.jump(l[i]): - try: - # 01-01[-01] - ymd.append(int(l[i])) - except ValueError: - # 01-Jan[-01] - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - else: - return None - i += 1 - if i < len_l and l[i] == sep: - # We have three members - i += 1 - value = info.month(l[i]) - if value is not None: - ymd.append(value) - mstridx = len(ymd)-1 - assert mstridx == -1 - else: - ymd.append(int(l[i])) - i += 1 - elif i >= len_l or info.jump(l[i]): - if i+1 < len_l and info.ampm(l[i+1]) is not None: - # 12 am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i+1]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i+1]) == 0: - res.hour = 0 - i += 1 - else: - # Year, month or day - ymd.append(int(value)) - i += 1 - elif info.ampm(l[i]) is not None: - # 12am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i]) == 0: - res.hour = 0 - i += 1 - elif not fuzzy: - return None - else: - i += 1 - continue - - # Check weekday - value = info.weekday(l[i]) - if value is not None: - res.weekday = value - i += 1 - continue - - # Check month name - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - i += 1 - if i < len_l: - if l[i] in ('-', '/'): - # Jan-01[-99] - sep = l[i] - i += 1 - ymd.append(int(l[i])) - i += 1 - if i < len_l and l[i] == sep: - # Jan-01-99 - i += 1 - ymd.append(int(l[i])) - i += 1 - elif (i+3 < len_l and l[i] == l[i+2] == ' ' - and info.pertain(l[i+1])): - # Jan of 01 - # In this case, 01 is clearly year - try: - value = int(l[i+3]) - except ValueError: - # Wrong guess - pass - else: - # Convert it here to become unambiguous - ymd.append(info.convertyear(value)) - i += 4 - continue - - # Check am/pm - value = info.ampm(l[i]) - if value is not None: - if value == 1 and res.hour < 12: - res.hour += 12 - elif value == 0 and res.hour == 12: - res.hour = 0 - i += 1 - continue - - # Check for a timezone name - if (res.hour is not None and len(l[i]) <= 5 and - res.tzname is None and res.tzoffset is None and - not [x for x in l[i] if x not in string.ascii_uppercase]): - res.tzname = l[i] - res.tzoffset = info.tzoffset(res.tzname) - i += 1 - - # Check for something like GMT+3, or BRST+3. Notice - # that it doesn't mean "I am 3 hours after GMT", but - # "my time +3 is GMT". If found, we reverse the - # logic so that timezone parsing code will get it - # right. - if i < len_l and l[i] in ('+', '-'): - l[i] = ('+', '-')[l[i] == '+'] - res.tzoffset = None - if info.utczone(res.tzname): - # With something like GMT+3, the timezone - # is *not* GMT. - res.tzname = None - - continue - - # Check for a numbered timezone - if res.hour is not None and l[i] in ('+', '-'): - signal = (-1, 1)[l[i] == '+'] - i += 1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - res.tzoffset = int(l[i][:2])*3600+int(l[i][2:])*60 - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - res.tzoffset = int(l[i])*3600+int(l[i+2])*60 - i += 2 - elif len_li <= 2: - # -[0]3 - res.tzoffset = int(l[i][:2])*3600 - else: - return None - i += 1 - res.tzoffset *= signal - - # Look for a timezone name between parenthesis - if (i+3 < len_l and - info.jump(l[i]) and l[i+1] == '(' and l[i+3] == ')' and - 3 <= len(l[i+2]) <= 5 and - not [x for x in l[i+2] - if x not in string.ascii_uppercase]): - # -0300 (BRST) - res.tzname = l[i+2] - i += 4 - continue - - # Check jumps - if not (info.jump(l[i]) or fuzzy): - return None - - i += 1 - - # Process year/month/day - len_ymd = len(ymd) - if len_ymd > 3: - # More than three members!? - return None - elif len_ymd == 1 or (mstridx != -1 and len_ymd == 2): - # One member, or two members with a month string - if mstridx != -1: - res.month = ymd[mstridx] - del ymd[mstridx] - if len_ymd > 1 or mstridx == -1: - if ymd[0] > 31: - res.year = ymd[0] - else: - res.day = ymd[0] - elif len_ymd == 2: - # Two members with numbers - if ymd[0] > 31: - # 99-01 - res.year, res.month = ymd - elif ymd[1] > 31: - # 01-99 - res.month, res.year = ymd - elif dayfirst and ymd[1] <= 12: - # 13-01 - res.day, res.month = ymd - else: - # 01-13 - res.month, res.day = ymd - if len_ymd == 3: - # Three members - if mstridx == 0: - res.month, res.day, res.year = ymd - elif mstridx == 1: - if ymd[0] > 31 or (yearfirst and ymd[2] <= 31): - # 99-Jan-01 - res.year, res.month, res.day = ymd - else: - # 01-Jan-01 - # Give precendence to day-first, since - # two-digit years is usually hand-written. - res.day, res.month, res.year = ymd - elif mstridx == 2: - # WTF!? - if ymd[1] > 31: - # 01-99-Jan - res.day, res.year, res.month = ymd - else: - # 99-01-Jan - res.year, res.day, res.month = ymd - else: - if ymd[0] > 31 or \ - (yearfirst and ymd[1] <= 12 and ymd[2] <= 31): - # 99-01-01 - res.year, res.month, res.day = ymd - elif ymd[0] > 12 or (dayfirst and ymd[1] <= 12): - # 13-01-01 - res.day, res.month, res.year = ymd - else: - # 01-13-01 - res.month, res.day, res.year = ymd - - except (IndexError, ValueError, AssertionError): - return None - - if not info.validate(res): - return None - return res - -DEFAULTPARSER = parser() -def parse(timestr, parserinfo=None, **kwargs): - # Python 2.x support: datetimes return their string presentation as - # bytes in 2.x and unicode in 3.x, so it's reasonable to expect that - # the parser will get both kinds. Internally we use unicode only. - if isinstance(timestr, binary_type): - timestr = timestr.decode() - if parserinfo: - return parser(parserinfo).parse(timestr, **kwargs) - else: - return DEFAULTPARSER.parse(timestr, **kwargs) - - -class _tzparser(object): - - class _result(_resultbase): - - __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset", - "start", "end"] - - class _attr(_resultbase): - __slots__ = ["month", "week", "weekday", - "yday", "jyday", "day", "time"] - - def __repr__(self): - return self._repr("") - - def __init__(self): - _resultbase.__init__(self) - self.start = self._attr() - self.end = self._attr() - - def parse(self, tzstr): - res = self._result() - l = _timelex.split(tzstr) - try: - - len_l = len(l) - - i = 0 - while i < len_l: - # BRST+3[BRDT[+2]] - j = i - while j < len_l and not [x for x in l[j] - if x in "0123456789:,-+"]: - j += 1 - if j != i: - if not res.stdabbr: - offattr = "stdoffset" - res.stdabbr = "".join(l[i:j]) - else: - offattr = "dstoffset" - res.dstabbr = "".join(l[i:j]) - i = j - if (i < len_l and - (l[i] in ('+', '-') or l[i][0] in "0123456789")): - if l[i] in ('+', '-'): - # Yes, that's right. See the TZ variable - # documentation. - signal = (1, -1)[l[i] == '+'] - i += 1 - else: - signal = -1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - setattr(res, offattr, - (int(l[i][:2])*3600+int(l[i][2:])*60)*signal) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - setattr(res, offattr, - (int(l[i])*3600+int(l[i+2])*60)*signal) - i += 2 - elif len_li <= 2: - # -[0]3 - setattr(res, offattr, - int(l[i][:2])*3600*signal) - else: - return None - i += 1 - if res.dstabbr: - break - else: - break - - if i < len_l: - for j in range(i, len_l): - if l[j] == ';': l[j] = ',' - - assert l[i] == ',' - - i += 1 - - if i >= len_l: - pass - elif (8 <= l.count(',') <= 9 and - not [y for x in l[i:] if x != ',' - for y in x if y not in "0123456789"]): - # GMT0BST,3,0,30,3600,10,0,26,7200[,3600] - for x in (res.start, res.end): - x.month = int(l[i]) - i += 2 - if l[i] == '-': - value = int(l[i+1])*-1 - i += 1 - else: - value = int(l[i]) - i += 2 - if value: - x.week = value - x.weekday = (int(l[i])-1)%7 - else: - x.day = int(l[i]) - i += 2 - x.time = int(l[i]) - i += 2 - if i < len_l: - if l[i] in ('-', '+'): - signal = (-1, 1)[l[i] == "+"] - i += 1 - else: - signal = 1 - res.dstoffset = (res.stdoffset+int(l[i]))*signal - elif (l.count(',') == 2 and l[i:].count('/') <= 2 and - not [y for x in l[i:] if x not in (',', '/', 'J', 'M', - '.', '-', ':') - for y in x if y not in "0123456789"]): - for x in (res.start, res.end): - if l[i] == 'J': - # non-leap year day (1 based) - i += 1 - x.jyday = int(l[i]) - elif l[i] == 'M': - # month[-.]week[-.]weekday - i += 1 - x.month = int(l[i]) - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.week = int(l[i]) - if x.week == 5: - x.week = -1 - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.weekday = (int(l[i])-1)%7 - else: - # year day (zero based) - x.yday = int(l[i])+1 - - i += 1 - - if i < len_l and l[i] == '/': - i += 1 - # start time - len_li = len(l[i]) - if len_li == 4: - # -0300 - x.time = (int(l[i][:2])*3600+int(l[i][2:])*60) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - x.time = int(l[i])*3600+int(l[i+2])*60 - i += 2 - if i+1 < len_l and l[i+1] == ':': - i += 2 - x.time += int(l[i]) - elif len_li <= 2: - # -[0]3 - x.time = (int(l[i][:2])*3600) - else: - return None - i += 1 - - assert i == len_l or l[i] == ',' - - i += 1 - - assert i >= len_l - - except (IndexError, ValueError, AssertionError): - return None - - return res - - -DEFAULTTZPARSER = _tzparser() -def _parsetz(tzstr): - return DEFAULTTZPARSER.parse(tzstr) - - -def _parsems(value): - """Parse a I[.F] seconds value into (seconds, microseconds).""" - if "." not in value: - return int(value), 0 - else: - i, f = value.split(".") - return int(i), int(f.ljust(6, "0")[:6]) - - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/relativedelta.py b/lib/dateutil_py3/relativedelta.py deleted file mode 100644 index 4393bcbcde22..000000000000 --- a/lib/dateutil_py3/relativedelta.py +++ /dev/null @@ -1,436 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -import datetime -import calendar - -from six import integer_types - -__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class relativedelta(object): - """ -The relativedelta type is based on the specification of the excelent -work done by M.-A. Lemburg in his mx.DateTime extension. However, -notice that this type does *NOT* implement the same algorithm as -his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. - -There's two different ways to build a relativedelta instance. The -first one is passing it two date/datetime classes: - - relativedelta(datetime1, datetime2) - -And the other way is to use the following keyword arguments: - - year, month, day, hour, minute, second, microsecond: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds: - Relative information, may be negative. - - weekday: - One of the weekday instances (MO, TU, etc). These instances may - receive a parameter N, specifying the Nth weekday, which could - be positive or negative (like MO(+1) or MO(-2). Not specifying - it is the same as specifying +1. You can also use an integer, - where 0=MO. - - leapdays: - Will add given days to the date found, if year is a leap - year, and the date found is post 28 of february. - - yearday, nlyearday: - Set the yearday or the non-leap year day (jump leap days). - These are converted to day/month/leapdays information. - -Here is the behavior of operations with relativedelta: - -1) Calculate the absolute year, using the 'year' argument, or the - original datetime year, if the argument is not present. - -2) Add the relative 'years' argument to the absolute year. - -3) Do steps 1 and 2 for month/months. - -4) Calculate the absolute day, using the 'day' argument, or the - original datetime day, if the argument is not present. Then, - subtract from the day until it fits in the year and month - found after their operations. - -5) Add the relative 'days' argument to the absolute day. Notice - that the 'weeks' argument is multiplied by 7 and added to - 'days'. - -6) Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, - microsecond/microseconds. - -7) If the 'weekday' argument is present, calculate the weekday, - with the given (wday, nth) tuple. wday is the index of the - weekday (0-6, 0=Mon), and nth is the number of weeks to add - forward or backward, depending on its signal. Notice that if - the calculated date is already Monday, for example, using - (0, 1) or (0, -1) won't change the day. - """ - - def __init__(self, dt1=None, dt2=None, - years=0, months=0, days=0, leapdays=0, weeks=0, - hours=0, minutes=0, seconds=0, microseconds=0, - year=None, month=None, day=None, weekday=None, - yearday=None, nlyearday=None, - hour=None, minute=None, second=None, microsecond=None): - if dt1 and dt2: - if (not isinstance(dt1, datetime.date)) or (not isinstance(dt2, datetime.date)): - raise TypeError("relativedelta only diffs datetime/date") - if not type(dt1) == type(dt2): #isinstance(dt1, type(dt2)): - if not isinstance(dt1, datetime.datetime): - dt1 = datetime.datetime.fromordinal(dt1.toordinal()) - elif not isinstance(dt2, datetime.datetime): - dt2 = datetime.datetime.fromordinal(dt2.toordinal()) - self.years = 0 - self.months = 0 - self.days = 0 - self.leapdays = 0 - self.hours = 0 - self.minutes = 0 - self.seconds = 0 - self.microseconds = 0 - self.year = None - self.month = None - self.day = None - self.weekday = None - self.hour = None - self.minute = None - self.second = None - self.microsecond = None - self._has_time = 0 - - months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month) - self._set_months(months) - dtm = self.__radd__(dt2) - if dt1 < dt2: - while dt1 > dtm: - months += 1 - self._set_months(months) - dtm = self.__radd__(dt2) - else: - while dt1 < dtm: - months -= 1 - self._set_months(months) - dtm = self.__radd__(dt2) - delta = dt1 - dtm - self.seconds = delta.seconds+delta.days*86400 - self.microseconds = delta.microseconds - else: - self.years = years - self.months = months - self.days = days+weeks*7 - self.leapdays = leapdays - self.hours = hours - self.minutes = minutes - self.seconds = seconds - self.microseconds = microseconds - self.year = year - self.month = month - self.day = day - self.hour = hour - self.minute = minute - self.second = second - self.microsecond = microsecond - - if isinstance(weekday, integer_types): - self.weekday = weekdays[weekday] - else: - self.weekday = weekday - - yday = 0 - if nlyearday: - yday = nlyearday - elif yearday: - yday = yearday - if yearday > 59: - self.leapdays = -1 - if yday: - ydayidx = [31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 366] - for idx, ydays in enumerate(ydayidx): - if yday <= ydays: - self.month = idx+1 - if idx == 0: - self.day = yday - else: - self.day = yday-ydayidx[idx-1] - break - else: - raise ValueError("invalid year day (%d)" % yday) - - self._fix() - - def _fix(self): - if abs(self.microseconds) > 999999: - s = self.microseconds//abs(self.microseconds) - div, mod = divmod(self.microseconds*s, 1000000) - self.microseconds = mod*s - self.seconds += div*s - if abs(self.seconds) > 59: - s = self.seconds//abs(self.seconds) - div, mod = divmod(self.seconds*s, 60) - self.seconds = mod*s - self.minutes += div*s - if abs(self.minutes) > 59: - s = self.minutes//abs(self.minutes) - div, mod = divmod(self.minutes*s, 60) - self.minutes = mod*s - self.hours += div*s - if abs(self.hours) > 23: - s = self.hours//abs(self.hours) - div, mod = divmod(self.hours*s, 24) - self.hours = mod*s - self.days += div*s - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years += div*s - if (self.hours or self.minutes or self.seconds or self.microseconds or - self.hour is not None or self.minute is not None or - self.second is not None or self.microsecond is not None): - self._has_time = 1 - else: - self._has_time = 0 - - def _set_months(self, months): - self.months = months - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years = div*s - else: - self.years = 0 - - def __add__(self, other): - if isinstance(other, relativedelta): - return relativedelta(years=other.years+self.years, - months=other.months+self.months, - days=other.days+self.days, - hours=other.hours+self.hours, - minutes=other.minutes+self.minutes, - seconds=other.seconds+self.seconds, - microseconds=other.microseconds+self.microseconds, - leapdays=other.leapdays or self.leapdays, - year=other.year or self.year, - month=other.month or self.month, - day=other.day or self.day, - weekday=other.weekday or self.weekday, - hour=other.hour or self.hour, - minute=other.minute or self.minute, - second=other.second or self.second, - microsecond=other.microsecond or self.microsecond) - if not isinstance(other, datetime.date): - raise TypeError("unsupported type for add operation") - elif self._has_time and not isinstance(other, datetime.datetime): - other = datetime.datetime.fromordinal(other.toordinal()) - year = (self.year or other.year)+self.years - month = self.month or other.month - if self.months: - assert 1 <= abs(self.months) <= 12 - month += self.months - if month > 12: - year += 1 - month -= 12 - elif month < 1: - year -= 1 - month += 12 - day = min(calendar.monthrange(year, month)[1], - self.day or other.day) - repl = {"year": year, "month": month, "day": day} - for attr in ["hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - repl[attr] = value - days = self.days - if self.leapdays and month > 2 and calendar.isleap(year): - days += self.leapdays - ret = (other.replace(**repl) - + datetime.timedelta(days=days, - hours=self.hours, - minutes=self.minutes, - seconds=self.seconds, - microseconds=self.microseconds)) - if self.weekday: - weekday, nth = self.weekday.weekday, self.weekday.n or 1 - jumpdays = (abs(nth)-1)*7 - if nth > 0: - jumpdays += (7-ret.weekday()+weekday)%7 - else: - jumpdays += (ret.weekday()-weekday)%7 - jumpdays *= -1 - ret += datetime.timedelta(days=jumpdays) - return ret - - def __radd__(self, other): - return self.__add__(other) - - def __rsub__(self, other): - return self.__neg__().__radd__(other) - - def __sub__(self, other): - if not isinstance(other, relativedelta): - raise TypeError("unsupported type for sub operation") - return relativedelta(years=self.years-other.years, - months=self.months-other.months, - days=self.days-other.days, - hours=self.hours-other.hours, - minutes=self.minutes-other.minutes, - seconds=self.seconds-other.seconds, - microseconds=self.microseconds-other.microseconds, - leapdays=self.leapdays or other.leapdays, - year=self.year or other.year, - month=self.month or other.month, - day=self.day or other.day, - weekday=self.weekday or other.weekday, - hour=self.hour or other.hour, - minute=self.minute or other.minute, - second=self.second or other.second, - microsecond=self.microsecond or other.microsecond) - - def __neg__(self): - return relativedelta(years=-self.years, - months=-self.months, - days=-self.days, - hours=-self.hours, - minutes=-self.minutes, - seconds=-self.seconds, - microseconds=-self.microseconds, - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - def __bool__(self): - return not (not self.years and - not self.months and - not self.days and - not self.hours and - not self.minutes and - not self.seconds and - not self.microseconds and - not self.leapdays and - self.year is None and - self.month is None and - self.day is None and - self.weekday is None and - self.hour is None and - self.minute is None and - self.second is None and - self.microsecond is None) - - def __mul__(self, other): - f = float(other) - return relativedelta(years=int(self.years*f), - months=int(self.months*f), - days=int(self.days*f), - hours=int(self.hours*f), - minutes=int(self.minutes*f), - seconds=int(self.seconds*f), - microseconds=int(self.microseconds*f), - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - __rmul__ = __mul__ - - def __eq__(self, other): - if not isinstance(other, relativedelta): - return False - if self.weekday or other.weekday: - if not self.weekday or not other.weekday: - return False - if self.weekday.weekday != other.weekday.weekday: - return False - n1, n2 = self.weekday.n, other.weekday.n - if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): - return False - return (self.years == other.years and - self.months == other.months and - self.days == other.days and - self.hours == other.hours and - self.minutes == other.minutes and - self.seconds == other.seconds and - self.leapdays == other.leapdays and - self.year == other.year and - self.month == other.month and - self.day == other.day and - self.hour == other.hour and - self.minute == other.minute and - self.second == other.second and - self.microsecond == other.microsecond) - - def __ne__(self, other): - return not self.__eq__(other) - - def __div__(self, other): - return self.__mul__(1/float(other)) - - __truediv__ = __div__ - - def __repr__(self): - l = [] - for attr in ["years", "months", "days", "leapdays", - "hours", "minutes", "seconds", "microseconds"]: - value = getattr(self, attr) - if value: - l.append("%s=%+d" % (attr, value)) - for attr in ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, repr(value))) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/rrule.py b/lib/dateutil_py3/rrule.py deleted file mode 100644 index ad4d3ba70c4e..000000000000 --- a/lib/dateutil_py3/rrule.py +++ /dev/null @@ -1,1112 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -import itertools -import datetime -import calendar -try: - import _thread -except ImportError: - import thread as _thread -import sys - -from six import advance_iterator, integer_types - -__all__ = ["rrule", "rruleset", "rrulestr", - "YEARLY", "MONTHLY", "WEEKLY", "DAILY", - "HOURLY", "MINUTELY", "SECONDLY", - "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -# Every mask is 7 days longer to handle cross-year weekly periods. -M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+ - [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7) -M365MASK = list(M366MASK) -M29, M30, M31 = list(range(1, 30)), list(range(1, 31)), list(range(1, 32)) -MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -MDAY365MASK = list(MDAY366MASK) -M29, M30, M31 = list(range(-29, 0)), list(range(-30, 0)), list(range(-31, 0)) -NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -NMDAY365MASK = list(NMDAY366MASK) -M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366) -M365RANGE = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365) -WDAYMASK = [0, 1, 2, 3, 4, 5, 6]*55 -del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31] -MDAY365MASK = tuple(MDAY365MASK) -M365MASK = tuple(M365MASK) - -(YEARLY, - MONTHLY, - WEEKLY, - DAILY, - HOURLY, - MINUTELY, - SECONDLY) = list(range(7)) - -# Imported on demand. -easter = None -parser = None - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - if n == 0: - raise ValueError("Can't create weekday with n == 0") - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class rrulebase(object): - def __init__(self, cache=False): - if cache: - self._cache = [] - self._cache_lock = _thread.allocate_lock() - self._cache_gen = self._iter() - self._cache_complete = False - else: - self._cache = None - self._cache_complete = False - self._len = None - - def __iter__(self): - if self._cache_complete: - return iter(self._cache) - elif self._cache is None: - return self._iter() - else: - return self._iter_cached() - - def _iter_cached(self): - i = 0 - gen = self._cache_gen - cache = self._cache - acquire = self._cache_lock.acquire - release = self._cache_lock.release - while gen: - if i == len(cache): - acquire() - if self._cache_complete: - break - try: - for j in range(10): - cache.append(advance_iterator(gen)) - except StopIteration: - self._cache_gen = gen = None - self._cache_complete = True - break - release() - yield cache[i] - i += 1 - while i < self._len: - yield cache[i] - i += 1 - - def __getitem__(self, item): - if self._cache_complete: - return self._cache[item] - elif isinstance(item, slice): - if item.step and item.step < 0: - return list(iter(self))[item] - else: - return list(itertools.islice(self, - item.start or 0, - item.stop or sys.maxsize, - item.step or 1)) - elif item >= 0: - gen = iter(self) - try: - for i in range(item+1): - res = advance_iterator(gen) - except StopIteration: - raise IndexError - return res - else: - return list(iter(self))[item] - - def __contains__(self, item): - if self._cache_complete: - return item in self._cache - else: - for i in self: - if i == item: - return True - elif i > item: - return False - return False - - # __len__() introduces a large performance penality. - def count(self): - if self._len is None: - for x in self: pass - return self._len - - def before(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - last = None - if inc: - for i in gen: - if i > dt: - break - last = i - else: - for i in gen: - if i >= dt: - break - last = i - return last - - def after(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - if inc: - for i in gen: - if i >= dt: - return i - else: - for i in gen: - if i > dt: - return i - return None - - def between(self, after, before, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - started = False - l = [] - if inc: - for i in gen: - if i > before: - break - elif not started: - if i >= after: - started = True - l.append(i) - else: - l.append(i) - else: - for i in gen: - if i >= before: - break - elif not started: - if i > after: - started = True - l.append(i) - else: - l.append(i) - return l - -class rrule(rrulebase): - def __init__(self, freq, dtstart=None, - interval=1, wkst=None, count=None, until=None, bysetpos=None, - bymonth=None, bymonthday=None, byyearday=None, byeaster=None, - byweekno=None, byweekday=None, - byhour=None, byminute=None, bysecond=None, - cache=False): - super(rrule, self).__init__(cache) - global easter - if not dtstart: - dtstart = datetime.datetime.now().replace(microsecond=0) - elif not isinstance(dtstart, datetime.datetime): - dtstart = datetime.datetime.fromordinal(dtstart.toordinal()) - else: - dtstart = dtstart.replace(microsecond=0) - self._dtstart = dtstart - self._tzinfo = dtstart.tzinfo - self._freq = freq - self._interval = interval - self._count = count - if until and not isinstance(until, datetime.datetime): - until = datetime.datetime.fromordinal(until.toordinal()) - self._until = until - if wkst is None: - self._wkst = calendar.firstweekday() - elif isinstance(wkst, integer_types): - self._wkst = wkst - else: - self._wkst = wkst.weekday - if bysetpos is None: - self._bysetpos = None - elif isinstance(bysetpos, integer_types): - if bysetpos == 0 or not (-366 <= bysetpos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - self._bysetpos = (bysetpos,) - else: - self._bysetpos = tuple(bysetpos) - for pos in self._bysetpos: - if pos == 0 or not (-366 <= pos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - if not (byweekno or byyearday or bymonthday or - byweekday is not None or byeaster is not None): - if freq == YEARLY: - if not bymonth: - bymonth = dtstart.month - bymonthday = dtstart.day - elif freq == MONTHLY: - bymonthday = dtstart.day - elif freq == WEEKLY: - byweekday = dtstart.weekday() - # bymonth - if not bymonth: - self._bymonth = None - elif isinstance(bymonth, integer_types): - self._bymonth = (bymonth,) - else: - self._bymonth = tuple(bymonth) - # byyearday - if not byyearday: - self._byyearday = None - elif isinstance(byyearday, integer_types): - self._byyearday = (byyearday,) - else: - self._byyearday = tuple(byyearday) - # byeaster - if byeaster is not None: - if not easter: - from dateutil import easter - if isinstance(byeaster, integer_types): - self._byeaster = (byeaster,) - else: - self._byeaster = tuple(byeaster) - else: - self._byeaster = None - # bymonthay - if not bymonthday: - self._bymonthday = () - self._bynmonthday = () - elif isinstance(bymonthday, integer_types): - if bymonthday < 0: - self._bynmonthday = (bymonthday,) - self._bymonthday = () - else: - self._bymonthday = (bymonthday,) - self._bynmonthday = () - else: - self._bymonthday = tuple([x for x in bymonthday if x > 0]) - self._bynmonthday = tuple([x for x in bymonthday if x < 0]) - # byweekno - if byweekno is None: - self._byweekno = None - elif isinstance(byweekno, integer_types): - self._byweekno = (byweekno,) - else: - self._byweekno = tuple(byweekno) - # byweekday / bynweekday - if byweekday is None: - self._byweekday = None - self._bynweekday = None - elif isinstance(byweekday, integer_types): - self._byweekday = (byweekday,) - self._bynweekday = None - elif hasattr(byweekday, "n"): - if not byweekday.n or freq > MONTHLY: - self._byweekday = (byweekday.weekday,) - self._bynweekday = None - else: - self._bynweekday = ((byweekday.weekday, byweekday.n),) - self._byweekday = None - else: - self._byweekday = [] - self._bynweekday = [] - for wday in byweekday: - if isinstance(wday, integer_types): - self._byweekday.append(wday) - elif not wday.n or freq > MONTHLY: - self._byweekday.append(wday.weekday) - else: - self._bynweekday.append((wday.weekday, wday.n)) - self._byweekday = tuple(self._byweekday) - self._bynweekday = tuple(self._bynweekday) - if not self._byweekday: - self._byweekday = None - elif not self._bynweekday: - self._bynweekday = None - # byhour - if byhour is None: - if freq < HOURLY: - self._byhour = (dtstart.hour,) - else: - self._byhour = None - elif isinstance(byhour, integer_types): - self._byhour = (byhour,) - else: - self._byhour = tuple(byhour) - # byminute - if byminute is None: - if freq < MINUTELY: - self._byminute = (dtstart.minute,) - else: - self._byminute = None - elif isinstance(byminute, integer_types): - self._byminute = (byminute,) - else: - self._byminute = tuple(byminute) - # bysecond - if bysecond is None: - if freq < SECONDLY: - self._bysecond = (dtstart.second,) - else: - self._bysecond = None - elif isinstance(bysecond, integer_types): - self._bysecond = (bysecond,) - else: - self._bysecond = tuple(bysecond) - - if self._freq >= HOURLY: - self._timeset = None - else: - self._timeset = [] - for hour in self._byhour: - for minute in self._byminute: - for second in self._bysecond: - self._timeset.append( - datetime.time(hour, minute, second, - tzinfo=self._tzinfo)) - self._timeset.sort() - self._timeset = tuple(self._timeset) - - def _iter(self): - year, month, day, hour, minute, second, weekday, yearday, _ = \ - self._dtstart.timetuple() - - # Some local variables to speed things up a bit - freq = self._freq - interval = self._interval - wkst = self._wkst - until = self._until - bymonth = self._bymonth - byweekno = self._byweekno - byyearday = self._byyearday - byweekday = self._byweekday - byeaster = self._byeaster - bymonthday = self._bymonthday - bynmonthday = self._bynmonthday - bysetpos = self._bysetpos - byhour = self._byhour - byminute = self._byminute - bysecond = self._bysecond - - ii = _iterinfo(self) - ii.rebuild(year, month) - - getdayset = {YEARLY:ii.ydayset, - MONTHLY:ii.mdayset, - WEEKLY:ii.wdayset, - DAILY:ii.ddayset, - HOURLY:ii.ddayset, - MINUTELY:ii.ddayset, - SECONDLY:ii.ddayset}[freq] - - if freq < HOURLY: - timeset = self._timeset - else: - gettimeset = {HOURLY:ii.htimeset, - MINUTELY:ii.mtimeset, - SECONDLY:ii.stimeset}[freq] - if ((freq >= HOURLY and - self._byhour and hour not in self._byhour) or - (freq >= MINUTELY and - self._byminute and minute not in self._byminute) or - (freq >= SECONDLY and - self._bysecond and second not in self._bysecond)): - timeset = () - else: - timeset = gettimeset(hour, minute, second) - - total = 0 - count = self._count - while True: - # Get dayset with the right frequency - dayset, start, end = getdayset(year, month, day) - - # Do the "hard" work ;-) - filtered = False - for i in dayset[start:end]: - if ((bymonth and ii.mmask[i] not in bymonth) or - (byweekno and not ii.wnomask[i]) or - (byweekday and ii.wdaymask[i] not in byweekday) or - (ii.nwdaymask and not ii.nwdaymask[i]) or - (byeaster and not ii.eastermask[i]) or - ((bymonthday or bynmonthday) and - ii.mdaymask[i] not in bymonthday and - ii.nmdaymask[i] not in bynmonthday) or - (byyearday and - ((i < ii.yearlen and i+1 not in byyearday - and -ii.yearlen+i not in byyearday) or - (i >= ii.yearlen and i+1-ii.yearlen not in byyearday - and -ii.nextyearlen+i-ii.yearlen - not in byyearday)))): - dayset[i] = None - filtered = True - - # Output results - if bysetpos and timeset: - poslist = [] - for pos in bysetpos: - if pos < 0: - daypos, timepos = divmod(pos, len(timeset)) - else: - daypos, timepos = divmod(pos-1, len(timeset)) - try: - i = [x for x in dayset[start:end] - if x is not None][daypos] - time = timeset[timepos] - except IndexError: - pass - else: - date = datetime.date.fromordinal(ii.yearordinal+i) - res = datetime.datetime.combine(date, time) - if res not in poslist: - poslist.append(res) - poslist.sort() - for res in poslist: - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - else: - for i in dayset[start:end]: - if i is not None: - date = datetime.date.fromordinal(ii.yearordinal+i) - for time in timeset: - res = datetime.datetime.combine(date, time) - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - - # Handle frequency and interval - fixday = False - if freq == YEARLY: - year += interval - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == MONTHLY: - month += interval - if month > 12: - div, mod = divmod(month, 12) - month = mod - year += div - if month == 0: - month = 12 - year -= 1 - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == WEEKLY: - if wkst > weekday: - day += -(weekday+1+(6-wkst))+self._interval*7 - else: - day += -(weekday-wkst)+self._interval*7 - weekday = wkst - fixday = True - elif freq == DAILY: - day += interval - fixday = True - elif freq == HOURLY: - if filtered: - # Jump to one iteration before next day - hour += ((23-hour)//interval)*interval - while True: - hour += interval - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if not byhour or hour in byhour: - break - timeset = gettimeset(hour, minute, second) - elif freq == MINUTELY: - if filtered: - # Jump to one iteration before next day - minute += ((1439-(hour*60+minute))//interval)*interval - while True: - minute += interval - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - filtered = False - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute)): - break - timeset = gettimeset(hour, minute, second) - elif freq == SECONDLY: - if filtered: - # Jump to one iteration before next day - second += (((86399-(hour*3600+minute*60+second)) - //interval)*interval) - while True: - second += self._interval - div, mod = divmod(second, 60) - if div: - second = mod - minute += div - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute) and - (not bysecond or second in bysecond)): - break - timeset = gettimeset(hour, minute, second) - - if fixday and day > 28: - daysinmonth = calendar.monthrange(year, month)[1] - if day > daysinmonth: - while day > daysinmonth: - day -= daysinmonth - month += 1 - if month == 13: - month = 1 - year += 1 - if year > datetime.MAXYEAR: - self._len = total - return - daysinmonth = calendar.monthrange(year, month)[1] - ii.rebuild(year, month) - -class _iterinfo(object): - __slots__ = ["rrule", "lastyear", "lastmonth", - "yearlen", "nextyearlen", "yearordinal", "yearweekday", - "mmask", "mrange", "mdaymask", "nmdaymask", - "wdaymask", "wnomask", "nwdaymask", "eastermask"] - - def __init__(self, rrule): - for attr in self.__slots__: - setattr(self, attr, None) - self.rrule = rrule - - def rebuild(self, year, month): - # Every mask is 7 days longer to handle cross-year weekly periods. - rr = self.rrule - if year != self.lastyear: - self.yearlen = 365+calendar.isleap(year) - self.nextyearlen = 365+calendar.isleap(year+1) - firstyday = datetime.date(year, 1, 1) - self.yearordinal = firstyday.toordinal() - self.yearweekday = firstyday.weekday() - - wday = datetime.date(year, 1, 1).weekday() - if self.yearlen == 365: - self.mmask = M365MASK - self.mdaymask = MDAY365MASK - self.nmdaymask = NMDAY365MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M365RANGE - else: - self.mmask = M366MASK - self.mdaymask = MDAY366MASK - self.nmdaymask = NMDAY366MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M366RANGE - - if not rr._byweekno: - self.wnomask = None - else: - self.wnomask = [0]*(self.yearlen+7) - #no1wkst = firstwkst = self.wdaymask.index(rr._wkst) - no1wkst = firstwkst = (7-self.yearweekday+rr._wkst)%7 - if no1wkst >= 4: - no1wkst = 0 - # Number of days in the year, plus the days we got - # from last year. - wyearlen = self.yearlen+(self.yearweekday-rr._wkst)%7 - else: - # Number of days in the year, minus the days we - # left in last year. - wyearlen = self.yearlen-no1wkst - div, mod = divmod(wyearlen, 7) - numweeks = div+mod//4 - for n in rr._byweekno: - if n < 0: - n += numweeks+1 - if not (0 < n <= numweeks): - continue - if n > 1: - i = no1wkst+(n-1)*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - else: - i = no1wkst - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if 1 in rr._byweekno: - # Check week number 1 of next year as well - # TODO: Check -numweeks for next year. - i = no1wkst+numweeks*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - if i < self.yearlen: - # If week starts in next year, we - # don't care about it. - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if no1wkst: - # Check last week number of last year as - # well. If no1wkst is 0, either the year - # started on week start, or week number 1 - # got days from last year, so there are no - # days from last year's last week number in - # this year. - if -1 not in rr._byweekno: - lyearweekday = datetime.date(year-1, 1, 1).weekday() - lno1wkst = (7-lyearweekday+rr._wkst)%7 - lyearlen = 365+calendar.isleap(year-1) - if lno1wkst >= 4: - lno1wkst = 0 - lnumweeks = 52+(lyearlen+ - (lyearweekday-rr._wkst)%7)%7//4 - else: - lnumweeks = 52+(self.yearlen-no1wkst)%7//4 - else: - lnumweeks = -1 - if lnumweeks in rr._byweekno: - for i in range(no1wkst): - self.wnomask[i] = 1 - - if (rr._bynweekday and - (month != self.lastmonth or year != self.lastyear)): - ranges = [] - if rr._freq == YEARLY: - if rr._bymonth: - for month in rr._bymonth: - ranges.append(self.mrange[month-1:month+1]) - else: - ranges = [(0, self.yearlen)] - elif rr._freq == MONTHLY: - ranges = [self.mrange[month-1:month+1]] - if ranges: - # Weekly frequency won't get here, so we may not - # care about cross-year weekly periods. - self.nwdaymask = [0]*self.yearlen - for first, last in ranges: - last -= 1 - for wday, n in rr._bynweekday: - if n < 0: - i = last+(n+1)*7 - i -= (self.wdaymask[i]-wday)%7 - else: - i = first+(n-1)*7 - i += (7-self.wdaymask[i]+wday)%7 - if first <= i <= last: - self.nwdaymask[i] = 1 - - if rr._byeaster: - self.eastermask = [0]*(self.yearlen+7) - eyday = easter.easter(year).toordinal()-self.yearordinal - for offset in rr._byeaster: - self.eastermask[eyday+offset] = 1 - - self.lastyear = year - self.lastmonth = month - - def ydayset(self, year, month, day): - return list(range(self.yearlen)), 0, self.yearlen - - def mdayset(self, year, month, day): - set = [None]*self.yearlen - start, end = self.mrange[month-1:month+1] - for i in range(start, end): - set[i] = i - return set, start, end - - def wdayset(self, year, month, day): - # We need to handle cross-year weeks here. - set = [None]*(self.yearlen+7) - i = datetime.date(year, month, day).toordinal()-self.yearordinal - start = i - for j in range(7): - set[i] = i - i += 1 - #if (not (0 <= i < self.yearlen) or - # self.wdaymask[i] == self.rrule._wkst): - # This will cross the year boundary, if necessary. - if self.wdaymask[i] == self.rrule._wkst: - break - return set, start, i - - def ddayset(self, year, month, day): - set = [None]*self.yearlen - i = datetime.date(year, month, day).toordinal()-self.yearordinal - set[i] = i - return set, i, i+1 - - def htimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for minute in rr._byminute: - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, - tzinfo=rr._tzinfo)) - set.sort() - return set - - def mtimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo)) - set.sort() - return set - - def stimeset(self, hour, minute, second): - return (datetime.time(hour, minute, second, - tzinfo=self.rrule._tzinfo),) - - -class rruleset(rrulebase): - - class _genitem(object): - def __init__(self, genlist, gen): - try: - self.dt = advance_iterator(gen) - genlist.append(self) - except StopIteration: - pass - self.genlist = genlist - self.gen = gen - - def __next__(self): - try: - self.dt = advance_iterator(self.gen) - except StopIteration: - self.genlist.remove(self) - - next = __next__ - - def __lt__(self, other): - return self.dt < other.dt - - def __gt__(self, other): - return self.dt > other.dt - - def __eq__(self, other): - return self.dt == other.dt - - def __ne__(self, other): - return self.dt != other.dt - - def __init__(self, cache=False): - super(rruleset, self).__init__(cache) - self._rrule = [] - self._rdate = [] - self._exrule = [] - self._exdate = [] - - def rrule(self, rrule): - self._rrule.append(rrule) - - def rdate(self, rdate): - self._rdate.append(rdate) - - def exrule(self, exrule): - self._exrule.append(exrule) - - def exdate(self, exdate): - self._exdate.append(exdate) - - def _iter(self): - rlist = [] - self._rdate.sort() - self._genitem(rlist, iter(self._rdate)) - for gen in [iter(x) for x in self._rrule]: - self._genitem(rlist, gen) - rlist.sort() - exlist = [] - self._exdate.sort() - self._genitem(exlist, iter(self._exdate)) - for gen in [iter(x) for x in self._exrule]: - self._genitem(exlist, gen) - exlist.sort() - lastdt = None - total = 0 - while rlist: - ritem = rlist[0] - if not lastdt or lastdt != ritem.dt: - while exlist and exlist[0] < ritem: - advance_iterator(exlist[0]) - exlist.sort() - if not exlist or ritem != exlist[0]: - total += 1 - yield ritem.dt - lastdt = ritem.dt - advance_iterator(ritem) - rlist.sort() - self._len = total - -class _rrulestr(object): - - _freq_map = {"YEARLY": YEARLY, - "MONTHLY": MONTHLY, - "WEEKLY": WEEKLY, - "DAILY": DAILY, - "HOURLY": HOURLY, - "MINUTELY": MINUTELY, - "SECONDLY": SECONDLY} - - _weekday_map = {"MO":0,"TU":1,"WE":2,"TH":3,"FR":4,"SA":5,"SU":6} - - def _handle_int(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = int(value) - - def _handle_int_list(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = [int(x) for x in value.split(',')] - - _handle_INTERVAL = _handle_int - _handle_COUNT = _handle_int - _handle_BYSETPOS = _handle_int_list - _handle_BYMONTH = _handle_int_list - _handle_BYMONTHDAY = _handle_int_list - _handle_BYYEARDAY = _handle_int_list - _handle_BYEASTER = _handle_int_list - _handle_BYWEEKNO = _handle_int_list - _handle_BYHOUR = _handle_int_list - _handle_BYMINUTE = _handle_int_list - _handle_BYSECOND = _handle_int_list - - def _handle_FREQ(self, rrkwargs, name, value, **kwargs): - rrkwargs["freq"] = self._freq_map[value] - - def _handle_UNTIL(self, rrkwargs, name, value, **kwargs): - global parser - if not parser: - from dateutil import parser - try: - rrkwargs["until"] = parser.parse(value, - ignoretz=kwargs.get("ignoretz"), - tzinfos=kwargs.get("tzinfos")) - except ValueError: - raise ValueError("invalid until date") - - def _handle_WKST(self, rrkwargs, name, value, **kwargs): - rrkwargs["wkst"] = self._weekday_map[value] - - def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwarsg): - l = [] - for wday in value.split(','): - for i in range(len(wday)): - if wday[i] not in '+-0123456789': - break - n = wday[:i] or None - w = wday[i:] - if n: n = int(n) - l.append(weekdays[self._weekday_map[w]](n)) - rrkwargs["byweekday"] = l - - _handle_BYDAY = _handle_BYWEEKDAY - - def _parse_rfc_rrule(self, line, - dtstart=None, - cache=False, - ignoretz=False, - tzinfos=None): - if line.find(':') != -1: - name, value = line.split(':') - if name != "RRULE": - raise ValueError("unknown parameter name") - else: - value = line - rrkwargs = {} - for pair in value.split(';'): - name, value = pair.split('=') - name = name.upper() - value = value.upper() - try: - getattr(self, "_handle_"+name)(rrkwargs, name, value, - ignoretz=ignoretz, - tzinfos=tzinfos) - except AttributeError: - raise ValueError("unknown parameter '%s'" % name) - except (KeyError, ValueError): - raise ValueError("invalid '%s': %s" % (name, value)) - return rrule(dtstart=dtstart, cache=cache, **rrkwargs) - - def _parse_rfc(self, s, - dtstart=None, - cache=False, - unfold=False, - forceset=False, - compatible=False, - ignoretz=False, - tzinfos=None): - global parser - if compatible: - forceset = True - unfold = True - s = s.upper() - if not s.strip(): - raise ValueError("empty string") - if unfold: - lines = s.splitlines() - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - else: - lines = s.split() - if (not forceset and len(lines) == 1 and - (s.find(':') == -1 or s.startswith('RRULE:'))): - return self._parse_rfc_rrule(lines[0], cache=cache, - dtstart=dtstart, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - rrulevals = [] - rdatevals = [] - exrulevals = [] - exdatevals = [] - for line in lines: - if not line: - continue - if line.find(':') == -1: - name = "RRULE" - value = line - else: - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError("empty property name") - name = parms[0] - parms = parms[1:] - if name == "RRULE": - for parm in parms: - raise ValueError("unsupported RRULE parm: "+parm) - rrulevals.append(value) - elif name == "RDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError("unsupported RDATE parm: "+parm) - rdatevals.append(value) - elif name == "EXRULE": - for parm in parms: - raise ValueError("unsupported EXRULE parm: "+parm) - exrulevals.append(value) - elif name == "EXDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError("unsupported RDATE parm: "+parm) - exdatevals.append(value) - elif name == "DTSTART": - for parm in parms: - raise ValueError("unsupported DTSTART parm: "+parm) - if not parser: - from dateutil import parser - dtstart = parser.parse(value, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - raise ValueError("unsupported property: "+name) - if (forceset or len(rrulevals) > 1 or - rdatevals or exrulevals or exdatevals): - if not parser and (rdatevals or exdatevals): - from dateutil import parser - set = rruleset(cache=cache) - for value in rrulevals: - set.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in rdatevals: - for datestr in value.split(','): - set.rdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exrulevals: - set.exrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exdatevals: - for datestr in value.split(','): - set.exdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - if compatible and dtstart: - set.rdate(dtstart) - return set - else: - return self._parse_rfc_rrule(rrulevals[0], - dtstart=dtstart, - cache=cache, - ignoretz=ignoretz, - tzinfos=tzinfos) - - def __call__(self, s, **kwargs): - return self._parse_rfc(s, **kwargs) - -rrulestr = _rrulestr() - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/tz.py b/lib/dateutil_py3/tz.py deleted file mode 100644 index e849fc24b5e2..000000000000 --- a/lib/dateutil_py3/tz.py +++ /dev/null @@ -1,960 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -from six import string_types, PY3 - -import datetime -import struct -import time -import sys -import os - -relativedelta = None -parser = None -rrule = None - -__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange", - "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"] - -try: - from dateutil.tzwin import tzwin, tzwinlocal -except (ImportError, OSError): - tzwin, tzwinlocal = None, None - -def tzname_in_python2(myfunc): - """Change unicode output into bytestrings in Python 2 - - tzname() API changed in Python 3. It used to return bytes, but was changed - to unicode strings - """ - def inner_func(*args, **kwargs): - if PY3: - return myfunc(*args, **kwargs) - else: - return myfunc(*args, **kwargs).encode() - return inner_func - -ZERO = datetime.timedelta(0) -EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal() - -class tzutc(datetime.tzinfo): - - def utcoffset(self, dt): - return ZERO - - def dst(self, dt): - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return "UTC" - - def __eq__(self, other): - return (isinstance(other, tzutc) or - (isinstance(other, tzoffset) and other._offset == ZERO)) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzoffset(datetime.tzinfo): - - def __init__(self, name, offset): - self._name = name - self._offset = datetime.timedelta(seconds=offset) - - def utcoffset(self, dt): - return self._offset - - def dst(self, dt): - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return self._name - - def __eq__(self, other): - return (isinstance(other, tzoffset) and - self._offset == other._offset) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(%s, %s)" % (self.__class__.__name__, - repr(self._name), - self._offset.days*86400+self._offset.seconds) - - __reduce__ = object.__reduce__ - -class tzlocal(datetime.tzinfo): - - _std_offset = datetime.timedelta(seconds=-time.timezone) - if time.daylight: - _dst_offset = datetime.timedelta(seconds=-time.altzone) - else: - _dst_offset = _std_offset - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return time.tzname[self._isdst(dt)] - - def _isdst(self, dt): - # We can't use mktime here. It is unstable when deciding if - # the hour near to a change is DST or not. - # - # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, - # dt.minute, dt.second, dt.weekday(), 0, -1)) - # return time.localtime(timestamp).tm_isdst - # - # The code above yields the following result: - # - #>>> import tz, datetime - #>>> t = tz.tzlocal() - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - # - # Here is a more stable implementation: - # - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - return time.localtime(timestamp+time.timezone).tm_isdst - - def __eq__(self, other): - if not isinstance(other, tzlocal): - return False - return (self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset) - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class _ttinfo(object): - __slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"] - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def __repr__(self): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, repr(value))) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - - def __eq__(self, other): - if not isinstance(other, _ttinfo): - return False - return (self.offset == other.offset and - self.delta == other.delta and - self.isdst == other.isdst and - self.abbr == other.abbr and - self.isstd == other.isstd and - self.isgmt == other.isgmt) - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - state = {} - for name in self.__slots__: - state[name] = getattr(self, name, None) - return state - - def __setstate__(self, state): - for name in self.__slots__: - if name in state: - setattr(self, name, state[name]) - -class tzfile(datetime.tzinfo): - - # http://www.twinsun.com/tz/tz-link.htm - # ftp://ftp.iana.org/tz/tz*.tar.gz - - def __init__(self, fileobj): - if isinstance(fileobj, string_types): - self._filename = fileobj - fileobj = open(fileobj, 'rb') - elif hasattr(fileobj, "name"): - self._filename = fileobj.name - else: - self._filename = repr(fileobj) - - # From tzfile(5): - # - # The time zone information files used by tzset(3) - # begin with the magic characters "TZif" to identify - # them as time zone information files, followed by - # sixteen bytes reserved for future use, followed by - # six four-byte values of type long, written in a - # ``standard'' byte order (the high-order byte - # of the value is written first). - - if fileobj.read(4).decode() != "TZif": - raise ValueError("magic not found") - - fileobj.read(16) - - ( - # The number of UTC/local indicators stored in the file. - ttisgmtcnt, - - # The number of standard/wall indicators stored in the file. - ttisstdcnt, - - # The number of leap seconds for which data is - # stored in the file. - leapcnt, - - # The number of "transition times" for which data - # is stored in the file. - timecnt, - - # The number of "local time types" for which data - # is stored in the file (must not be zero). - typecnt, - - # The number of characters of "time zone - # abbreviation strings" stored in the file. - charcnt, - - ) = struct.unpack(">6l", fileobj.read(24)) - - # The above header is followed by tzh_timecnt four-byte - # values of type long, sorted in ascending order. - # These values are written in ``standard'' byte order. - # Each is used as a transition time (as returned by - # time(2)) at which the rules for computing local time - # change. - - if timecnt: - self._trans_list = struct.unpack(">%dl" % timecnt, - fileobj.read(timecnt*4)) - else: - self._trans_list = [] - - # Next come tzh_timecnt one-byte values of type unsigned - # char; each one tells which of the different types of - # ``local time'' types described in the file is associated - # with the same-indexed transition time. These values - # serve as indices into an array of ttinfo structures that - # appears next in the file. - - if timecnt: - self._trans_idx = struct.unpack(">%dB" % timecnt, - fileobj.read(timecnt)) - else: - self._trans_idx = [] - - # Each ttinfo structure is written as a four-byte value - # for tt_gmtoff of type long, in a standard byte - # order, followed by a one-byte value for tt_isdst - # and a one-byte value for tt_abbrind. In each - # structure, tt_gmtoff gives the number of - # seconds to be added to UTC, tt_isdst tells whether - # tm_isdst should be set by localtime(3), and - # tt_abbrind serves as an index into the array of - # time zone abbreviation characters that follow the - # ttinfo structure(s) in the file. - - ttinfo = [] - - for i in range(typecnt): - ttinfo.append(struct.unpack(">lbb", fileobj.read(6))) - - abbr = fileobj.read(charcnt).decode() - - # Then there are tzh_leapcnt pairs of four-byte - # values, written in standard byte order; the - # first value of each pair gives the time (as - # returned by time(2)) at which a leap second - # occurs; the second gives the total number of - # leap seconds to be applied after the given time. - # The pairs of values are sorted in ascending order - # by time. - - # Not used, for now - if leapcnt: - leap = struct.unpack(">%dl" % (leapcnt*2), - fileobj.read(leapcnt*8)) - - # Then there are tzh_ttisstdcnt standard/wall - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as standard - # time or wall clock time, and are used when - # a time zone file is used in handling POSIX-style - # time zone environment variables. - - if ttisstdcnt: - isstd = struct.unpack(">%db" % ttisstdcnt, - fileobj.read(ttisstdcnt)) - - # Finally, there are tzh_ttisgmtcnt UTC/local - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as UTC or - # local time, and are used when a time zone file - # is used in handling POSIX-style time zone envi- - # ronment variables. - - if ttisgmtcnt: - isgmt = struct.unpack(">%db" % ttisgmtcnt, - fileobj.read(ttisgmtcnt)) - - # ** Everything has been read ** - - # Build ttinfo list - self._ttinfo_list = [] - for i in range(typecnt): - gmtoff, isdst, abbrind = ttinfo[i] - # Round to full-minutes if that's not the case. Python's - # datetime doesn't accept sub-minute timezones. Check - # http://python.org/sf/1447945 for some information. - gmtoff = (gmtoff+30)//60*60 - tti = _ttinfo() - tti.offset = gmtoff - tti.delta = datetime.timedelta(seconds=gmtoff) - tti.isdst = isdst - tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)] - tti.isstd = (ttisstdcnt > i and isstd[i] != 0) - tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0) - self._ttinfo_list.append(tti) - - # Replace ttinfo indexes for ttinfo objects. - trans_idx = [] - for idx in self._trans_idx: - trans_idx.append(self._ttinfo_list[idx]) - self._trans_idx = tuple(trans_idx) - - # Set standard, dst, and before ttinfos. before will be - # used when a given time is before any transitions, - # and will be set to the first non-dst ttinfo, or to - # the first dst, if all of them are dst. - self._ttinfo_std = None - self._ttinfo_dst = None - self._ttinfo_before = None - if self._ttinfo_list: - if not self._trans_list: - self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0] - else: - for i in range(timecnt-1, -1, -1): - tti = self._trans_idx[i] - if not self._ttinfo_std and not tti.isdst: - self._ttinfo_std = tti - elif not self._ttinfo_dst and tti.isdst: - self._ttinfo_dst = tti - if self._ttinfo_std and self._ttinfo_dst: - break - else: - if self._ttinfo_dst and not self._ttinfo_std: - self._ttinfo_std = self._ttinfo_dst - - for tti in self._ttinfo_list: - if not tti.isdst: - self._ttinfo_before = tti - break - else: - self._ttinfo_before = self._ttinfo_list[0] - - # Now fix transition times to become relative to wall time. - # - # I'm not sure about this. In my tests, the tz source file - # is setup to wall time, and in the binary file isstd and - # isgmt are off, so it should be in wall time. OTOH, it's - # always in gmt time. Let me know if you have comments - # about this. - laststdoffset = 0 - self._trans_list = list(self._trans_list) - for i in range(len(self._trans_list)): - tti = self._trans_idx[i] - if not tti.isdst: - # This is std time. - self._trans_list[i] += tti.offset - laststdoffset = tti.offset - else: - # This is dst time. Convert to std. - self._trans_list[i] += laststdoffset - self._trans_list = tuple(self._trans_list) - - def _find_ttinfo(self, dt, laststd=0): - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - idx = 0 - for trans in self._trans_list: - if timestamp < trans: - break - idx += 1 - else: - return self._ttinfo_std - if idx == 0: - return self._ttinfo_before - if laststd: - while idx > 0: - tti = self._trans_idx[idx-1] - if not tti.isdst: - return tti - idx -= 1 - else: - return self._ttinfo_std - else: - return self._trans_idx[idx-1] - - def utcoffset(self, dt): - if not self._ttinfo_std: - return ZERO - return self._find_ttinfo(dt).delta - - def dst(self, dt): - if not self._ttinfo_dst: - return ZERO - tti = self._find_ttinfo(dt) - if not tti.isdst: - return ZERO - - # The documentation says that utcoffset()-dst() must - # be constant for every dt. - return tti.delta-self._find_ttinfo(dt, laststd=1).delta - - # An alternative for that would be: - # - # return self._ttinfo_dst.offset-self._ttinfo_std.offset - # - # However, this class stores historical changes in the - # dst offset, so I belive that this wouldn't be the right - # way to implement this. - - @tzname_in_python2 - def tzname(self, dt): - if not self._ttinfo_std: - return None - return self._find_ttinfo(dt).abbr - - def __eq__(self, other): - if not isinstance(other, tzfile): - return False - return (self._trans_list == other._trans_list and - self._trans_idx == other._trans_idx and - self._ttinfo_list == other._ttinfo_list) - - def __ne__(self, other): - return not self.__eq__(other) - - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self._filename)) - - def __reduce__(self): - if not os.path.isfile(self._filename): - raise ValueError("Unpickable %s class" % self.__class__.__name__) - return (self.__class__, (self._filename,)) - -class tzrange(datetime.tzinfo): - - def __init__(self, stdabbr, stdoffset=None, - dstabbr=None, dstoffset=None, - start=None, end=None): - global relativedelta - if not relativedelta: - from dateutil import relativedelta - self._std_abbr = stdabbr - self._dst_abbr = dstabbr - if stdoffset is not None: - self._std_offset = datetime.timedelta(seconds=stdoffset) - else: - self._std_offset = ZERO - if dstoffset is not None: - self._dst_offset = datetime.timedelta(seconds=dstoffset) - elif dstabbr and stdoffset is not None: - self._dst_offset = self._std_offset+datetime.timedelta(hours=+1) - else: - self._dst_offset = ZERO - if dstabbr and start is None: - self._start_delta = relativedelta.relativedelta( - hours=+2, month=4, day=1, weekday=relativedelta.SU(+1)) - else: - self._start_delta = start - if dstabbr and end is None: - self._end_delta = relativedelta.relativedelta( - hours=+1, month=10, day=31, weekday=relativedelta.SU(-1)) - else: - self._end_delta = end - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - if self._isdst(dt): - return self._dst_abbr - else: - return self._std_abbr - - def _isdst(self, dt): - if not self._start_delta: - return False - year = datetime.datetime(dt.year, 1, 1) - start = year+self._start_delta - end = year+self._end_delta - dt = dt.replace(tzinfo=None) - if start < end: - return dt >= start and dt < end - else: - return dt >= start or dt < end - - def __eq__(self, other): - if not isinstance(other, tzrange): - return False - return (self._std_abbr == other._std_abbr and - self._dst_abbr == other._dst_abbr and - self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset and - self._start_delta == other._start_delta and - self._end_delta == other._end_delta) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(...)" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzstr(tzrange): - - def __init__(self, s): - global parser - if not parser: - from dateutil import parser - self._s = s - - res = parser._parsetz(s) - if res is None: - raise ValueError("unknown string format") - - # Here we break the compatibility with the TZ variable handling. - # GMT-3 actually *means* the timezone -3. - if res.stdabbr in ("GMT", "UTC"): - res.stdoffset *= -1 - - # We must initialize it first, since _delta() needs - # _std_offset and _dst_offset set. Use False in start/end - # to avoid building it two times. - tzrange.__init__(self, res.stdabbr, res.stdoffset, - res.dstabbr, res.dstoffset, - start=False, end=False) - - if not res.dstabbr: - self._start_delta = None - self._end_delta = None - else: - self._start_delta = self._delta(res.start) - if self._start_delta: - self._end_delta = self._delta(res.end, isend=1) - - def _delta(self, x, isend=0): - kwargs = {} - if x.month is not None: - kwargs["month"] = x.month - if x.weekday is not None: - kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week) - if x.week > 0: - kwargs["day"] = 1 - else: - kwargs["day"] = 31 - elif x.day: - kwargs["day"] = x.day - elif x.yday is not None: - kwargs["yearday"] = x.yday - elif x.jyday is not None: - kwargs["nlyearday"] = x.jyday - if not kwargs: - # Default is to start on first sunday of april, and end - # on last sunday of october. - if not isend: - kwargs["month"] = 4 - kwargs["day"] = 1 - kwargs["weekday"] = relativedelta.SU(+1) - else: - kwargs["month"] = 10 - kwargs["day"] = 31 - kwargs["weekday"] = relativedelta.SU(-1) - if x.time is not None: - kwargs["seconds"] = x.time - else: - # Default is 2AM. - kwargs["seconds"] = 7200 - if isend: - # Convert to standard time, to follow the documented way - # of working with the extra hour. See the documentation - # of the tzinfo class. - delta = self._dst_offset-self._std_offset - kwargs["seconds"] -= delta.seconds+delta.days*86400 - return relativedelta.relativedelta(**kwargs) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self._s)) - -class _tzicalvtzcomp(object): - def __init__(self, tzoffsetfrom, tzoffsetto, isdst, - tzname=None, rrule=None): - self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) - self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto) - self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom - self.isdst = isdst - self.tzname = tzname - self.rrule = rrule - -class _tzicalvtz(datetime.tzinfo): - def __init__(self, tzid, comps=[]): - self._tzid = tzid - self._comps = comps - self._cachedate = [] - self._cachecomp = [] - - def _find_comp(self, dt): - if len(self._comps) == 1: - return self._comps[0] - dt = dt.replace(tzinfo=None) - try: - return self._cachecomp[self._cachedate.index(dt)] - except ValueError: - pass - lastcomp = None - lastcompdt = None - for comp in self._comps: - if not comp.isdst: - # Handle the extra hour in DST -> STD - compdt = comp.rrule.before(dt-comp.tzoffsetdiff, inc=True) - else: - compdt = comp.rrule.before(dt, inc=True) - if compdt and (not lastcompdt or lastcompdt < compdt): - lastcompdt = compdt - lastcomp = comp - if not lastcomp: - # RFC says nothing about what to do when a given - # time is before the first onset date. We'll look for the - # first standard component, or the first component, if - # none is found. - for comp in self._comps: - if not comp.isdst: - lastcomp = comp - break - else: - lastcomp = comp[0] - self._cachedate.insert(0, dt) - self._cachecomp.insert(0, lastcomp) - if len(self._cachedate) > 10: - self._cachedate.pop() - self._cachecomp.pop() - return lastcomp - - def utcoffset(self, dt): - return self._find_comp(dt).tzoffsetto - - def dst(self, dt): - comp = self._find_comp(dt) - if comp.isdst: - return comp.tzoffsetdiff - else: - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return self._find_comp(dt).tzname - - def __repr__(self): - return "" % repr(self._tzid) - - __reduce__ = object.__reduce__ - -class tzical(object): - def __init__(self, fileobj): - global rrule - if not rrule: - from dateutil import rrule - - if isinstance(fileobj, string_types): - self._s = fileobj - fileobj = open(fileobj, 'r') # ical should be encoded in UTF-8 with CRLF - elif hasattr(fileobj, "name"): - self._s = fileobj.name - else: - self._s = repr(fileobj) - - self._vtz = {} - - self._parse_rfc(fileobj.read()) - - def keys(self): - return list(self._vtz.keys()) - - def get(self, tzid=None): - if tzid is None: - keys = list(self._vtz.keys()) - if len(keys) == 0: - raise ValueError("no timezones defined") - elif len(keys) > 1: - raise ValueError("more than one timezone available") - tzid = keys[0] - return self._vtz.get(tzid) - - def _parse_offset(self, s): - s = s.strip() - if not s: - raise ValueError("empty offset") - if s[0] in ('+', '-'): - signal = (-1, +1)[s[0]=='+'] - s = s[1:] - else: - signal = +1 - if len(s) == 4: - return (int(s[:2])*3600+int(s[2:])*60)*signal - elif len(s) == 6: - return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal - else: - raise ValueError("invalid offset: "+s) - - def _parse_rfc(self, s): - lines = s.splitlines() - if not lines: - raise ValueError("empty string") - - # Unfold - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - - tzid = None - comps = [] - invtz = False - comptype = None - for line in lines: - if not line: - continue - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError("empty property name") - name = parms[0].upper() - parms = parms[1:] - if invtz: - if name == "BEGIN": - if value in ("STANDARD", "DAYLIGHT"): - # Process component - pass - else: - raise ValueError("unknown component: "+value) - comptype = value - founddtstart = False - tzoffsetfrom = None - tzoffsetto = None - rrulelines = [] - tzname = None - elif name == "END": - if value == "VTIMEZONE": - if comptype: - raise ValueError("component not closed: "+comptype) - if not tzid: - raise ValueError("mandatory TZID not found") - if not comps: - raise ValueError("at least one component is needed") - # Process vtimezone - self._vtz[tzid] = _tzicalvtz(tzid, comps) - invtz = False - elif value == comptype: - if not founddtstart: - raise ValueError("mandatory DTSTART not found") - if tzoffsetfrom is None: - raise ValueError("mandatory TZOFFSETFROM not found") - if tzoffsetto is None: - raise ValueError("mandatory TZOFFSETFROM not found") - # Process component - rr = None - if rrulelines: - rr = rrule.rrulestr("\n".join(rrulelines), - compatible=True, - ignoretz=True, - cache=True) - comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto, - (comptype == "DAYLIGHT"), - tzname, rr) - comps.append(comp) - comptype = None - else: - raise ValueError("invalid component end: "+value) - elif comptype: - if name == "DTSTART": - rrulelines.append(line) - founddtstart = True - elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"): - rrulelines.append(line) - elif name == "TZOFFSETFROM": - if parms: - raise ValueError("unsupported %s parm: %s "%(name, parms[0])) - tzoffsetfrom = self._parse_offset(value) - elif name == "TZOFFSETTO": - if parms: - raise ValueError("unsupported TZOFFSETTO parm: "+parms[0]) - tzoffsetto = self._parse_offset(value) - elif name == "TZNAME": - if parms: - raise ValueError("unsupported TZNAME parm: "+parms[0]) - tzname = value - elif name == "COMMENT": - pass - else: - raise ValueError("unsupported property: "+name) - else: - if name == "TZID": - if parms: - raise ValueError("unsupported TZID parm: "+parms[0]) - tzid = value - elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): - pass - else: - raise ValueError("unsupported property: "+name) - elif name == "BEGIN" and value == "VTIMEZONE": - tzid = None - comps = [] - invtz = True - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self._s)) - -if sys.platform != "win32": - TZFILES = ["/etc/localtime", "localtime"] - TZPATHS = ["/usr/share/zoneinfo", "/usr/lib/zoneinfo", "/etc/zoneinfo"] -else: - TZFILES = [] - TZPATHS = [] - -def gettz(name=None): - tz = None - if not name: - try: - name = os.environ["TZ"] - except KeyError: - pass - if name is None or name == ":": - for filepath in TZFILES: - if not os.path.isabs(filepath): - filename = filepath - for path in TZPATHS: - filepath = os.path.join(path, filename) - if os.path.isfile(filepath): - break - else: - continue - if os.path.isfile(filepath): - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = tzlocal() - else: - if name.startswith(":"): - name = name[:-1] - if os.path.isabs(name): - if os.path.isfile(name): - tz = tzfile(name) - else: - tz = None - else: - for path in TZPATHS: - filepath = os.path.join(path, name) - if not os.path.isfile(filepath): - filepath = filepath.replace(' ', '_') - if not os.path.isfile(filepath): - continue - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = None - if tzwin: - try: - tz = tzwin(name) - except OSError: - pass - if not tz: - from dateutil.zoneinfo import gettz - tz = gettz(name) - if not tz: - for c in name: - # name must have at least one offset to be a tzstr - if c in "0123456789": - try: - tz = tzstr(name) - except ValueError: - pass - break - else: - if name in ("GMT", "UTC"): - tz = tzutc() - elif name in time.tzname: - tz = tzlocal() - return tz - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/tzwin.py b/lib/dateutil_py3/tzwin.py deleted file mode 100644 index 041c6cc3d645..000000000000 --- a/lib/dateutil_py3/tzwin.py +++ /dev/null @@ -1,179 +0,0 @@ -# This code was originally contributed by Jeffrey Harris. -import datetime -import struct -import winreg - - -__all__ = ["tzwin", "tzwinlocal"] - -ONEWEEK = datetime.timedelta(7) - -TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" -TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" -TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" - -def _settzkeyname(): - global TZKEYNAME - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - try: - winreg.OpenKey(handle, TZKEYNAMENT).Close() - TZKEYNAME = TZKEYNAMENT - except WindowsError: - TZKEYNAME = TZKEYNAME9X - handle.Close() - -_settzkeyname() - -class tzwinbase(datetime.tzinfo): - """tzinfo class based on win32's timezones available in the registry.""" - - def utcoffset(self, dt): - if self._isdst(dt): - return datetime.timedelta(minutes=self._dstoffset) - else: - return datetime.timedelta(minutes=self._stdoffset) - - def dst(self, dt): - if self._isdst(dt): - minutes = self._dstoffset - self._stdoffset - return datetime.timedelta(minutes=minutes) - else: - return datetime.timedelta(0) - - def tzname(self, dt): - if self._isdst(dt): - return self._dstname - else: - return self._stdname - - def list(): - """Return a list of all time zones known to the system.""" - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - tzkey = winreg.OpenKey(handle, TZKEYNAME) - result = [winreg.EnumKey(tzkey, i) - for i in range(winreg.QueryInfoKey(tzkey)[0])] - tzkey.Close() - handle.Close() - return result - list = staticmethod(list) - - def display(self): - return self._display - - def _isdst(self, dt): - dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek, - self._dsthour, self._dstminute, - self._dstweeknumber) - dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek, - self._stdhour, self._stdminute, - self._stdweeknumber) - if dston < dstoff: - return dston <= dt.replace(tzinfo=None) < dstoff - else: - return not dstoff <= dt.replace(tzinfo=None) < dston - - -class tzwin(tzwinbase): - - def __init__(self, name): - self._name = name - - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - tzkey = winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name)) - keydict = valuestodict(tzkey) - tzkey.Close() - handle.Close() - - self._stdname = keydict["Std"].encode("iso-8859-1") - self._dstname = keydict["Dlt"].encode("iso-8859-1") - - self._display = keydict["Display"] - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=3l16h", keydict["TZI"]) - self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 - self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1 - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[4:9] - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[12:17] - - def __repr__(self): - return "tzwin(%s)" % repr(self._name) - - def __reduce__(self): - return (self.__class__, (self._name,)) - - -class tzwinlocal(tzwinbase): - - def __init__(self): - - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - - tzlocalkey = winreg.OpenKey(handle, TZLOCALKEYNAME) - keydict = valuestodict(tzlocalkey) - tzlocalkey.Close() - - self._stdname = keydict["StandardName"].encode("iso-8859-1") - self._dstname = keydict["DaylightName"].encode("iso-8859-1") - - try: - tzkey = winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname)) - _keydict = valuestodict(tzkey) - self._display = _keydict["Display"] - tzkey.Close() - except OSError: - self._display = None - - handle.Close() - - self._stdoffset = -keydict["Bias"]-keydict["StandardBias"] - self._dstoffset = self._stdoffset-keydict["DaylightBias"] - - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=8h", keydict["StandardStart"]) - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[1:6] - - tup = struct.unpack("=8h", keydict["DaylightStart"]) - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[1:6] - - def __reduce__(self): - return (self.__class__, ()) - -def picknthweekday(year, month, dayofweek, hour, minute, whichweek): - """dayofweek == 0 means Sunday, whichweek 5 means last instance""" - first = datetime.datetime(year, month, 1, hour, minute) - weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1)) - for n in range(whichweek): - dt = weekdayone+(whichweek-n)*ONEWEEK - if dt.month == month: - return dt - -def valuestodict(key): - """Convert a registry key's values to a dictionary.""" - dict = {} - size = winreg.QueryInfoKey(key)[1] - for i in range(size): - data = winreg.EnumValue(key, i) - dict[data[0]] = data[1] - return dict diff --git a/lib/dateutil_py3/zoneinfo/__init__.py b/lib/dateutil_py3/zoneinfo/__init__.py deleted file mode 100644 index a1b34874baa3..000000000000 --- a/lib/dateutil_py3/zoneinfo/__init__.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Copyright (c) 2003-2005 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -from dateutil.tz import tzfile -from tarfile import TarFile -import os - -__author__ = "Tomi Pieviläinen " -__license__ = "Simplified BSD" - -__all__ = ["setcachesize", "gettz", "rebuild"] - -CACHE = [] -CACHESIZE = 10 - -class tzfile(tzfile): - def __reduce__(self): - return (gettz, (self._filename,)) - -def getzoneinfofile(): - filenames = sorted(os.listdir(os.path.join(os.path.dirname(__file__)))) - filenames.reverse() - for entry in filenames: - if entry.startswith("zoneinfo") and ".tar." in entry: - return os.path.join(os.path.dirname(__file__), entry) - return None - -ZONEINFOFILE = getzoneinfofile() - -del getzoneinfofile - -def setcachesize(size): - global CACHESIZE, CACHE - CACHESIZE = size - del CACHE[size:] - -def gettz(name): - tzinfo = None - if ZONEINFOFILE: - for cachedname, tzinfo in CACHE: - if cachedname == name: - break - else: - tf = TarFile.open(ZONEINFOFILE) - try: - zonefile = tf.extractfile(name) - except KeyError: - tzinfo = None - else: - tzinfo = tzfile(zonefile) - tf.close() - CACHE.insert(0, (name, tzinfo)) - del CACHE[CACHESIZE:] - return tzinfo - -def rebuild(filename, tag=None, format="gz"): - import tempfile, shutil - tmpdir = tempfile.mkdtemp() - zonedir = os.path.join(tmpdir, "zoneinfo") - moduledir = os.path.dirname(__file__) - if tag: tag = "-"+tag - targetname = "zoneinfo%s.tar.%s" % (tag, format) - try: - tf = TarFile.open(filename) - # The "backwards" zone file contains links to other files, so must be - # processed as last - for name in sorted(tf.getnames(), - key=lambda k: k != "backward" and k or "z"): - if not (name.endswith(".sh") or - name.endswith(".tab") or - name == "leapseconds"): - tf.extract(name, tmpdir) - filepath = os.path.join(tmpdir, name) - os.system("zic -d %s %s" % (zonedir, filepath)) - tf.close() - target = os.path.join(moduledir, targetname) - for entry in os.listdir(moduledir): - if entry.startswith("zoneinfo") and ".tar." in entry: - os.unlink(os.path.join(moduledir, entry)) - tf = TarFile.open(target, "w:%s" % format) - for entry in os.listdir(zonedir): - entrypath = os.path.join(zonedir, entry) - tf.add(entrypath, entry) - tf.close() - finally: - shutil.rmtree(tmpdir) diff --git a/lib/dateutil_py3/zoneinfo/zoneinfo--latest.tar.gz b/lib/dateutil_py3/zoneinfo/zoneinfo--latest.tar.gz deleted file mode 100644 index 12eadffb098a..000000000000 Binary files a/lib/dateutil_py3/zoneinfo/zoneinfo--latest.tar.gz and /dev/null differ diff --git a/lib/dateutil_py3/zoneinfo/zoneinfo-2011d.tar.gz b/lib/dateutil_py3/zoneinfo/zoneinfo-2011d.tar.gz deleted file mode 100644 index a8c96074d8a2..000000000000 Binary files a/lib/dateutil_py3/zoneinfo/zoneinfo-2011d.tar.gz and /dev/null differ diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 6d523877f65f..c4611514c848 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -2,7 +2,7 @@ This is an object-oriented plotting library. A procedural interface is provided by the companion pyplot module, -which may be imported directly, e.g:: +which may be imported directly, e.g.:: from matplotlib.pyplot import * @@ -99,13 +99,36 @@ """ from __future__ import print_function -__version__ = '1.2.1' +import sys + +__version__ = '1.3.x' __version__numpy__ = '1.4' # minimum required numpy version -import os, re, shutil, subprocess, sys, warnings +try: + import dateutil +except ImportError: + raise ImportError("matplotlib requires dateutil") + +try: + import pyparsing +except ImportError: + raise ImportError("matplotlib requires pyparsing") +else: + _required = [1, 5, 6] + if [int(x) for x in pyparsing.__version__.split('.')] < _required: + raise ImportError( + "matplotlib requires pyparsing >= {0}".format( + '.'.join(str(x) for x in _required))) + +import os, re, shutil, warnings import distutils.sysconfig import distutils.version +# cbook must import matplotlib only within function +# definitions, so it is safe to import from it here. +from matplotlib.cbook import is_string_like +from matplotlib.compat import subprocess + try: reload except NameError: @@ -123,32 +146,6 @@ sys.argv = ['modpython'] -class MatplotlibDeprecationWarning(UserWarning): - """ - A class for issuing deprecation warnings for Matplotlib users. - - In light of the fact that Python builtin DeprecationWarnings are ignored - by default as of Python 2.7 (see link below), this class was put in to - allow for the signaling of deprecation, but via UserWarnings which are not - ignored by default. - - http://docs.python.org/dev/whatsnew/2.7.html#the-future-for-python-2-x - """ - pass - -""" -Manage user customizations through a rc file. - -The default file location is given in the following order - - - environment variable MATPLOTLIBRC - - - HOME/.matplotlib/matplotlibrc if HOME is defined - - - PATH/matplotlibrc where PATH is the return value of - get_data_path() -""" - import sys, os, tempfile if sys.version_info[0] >= 3: @@ -192,28 +189,34 @@ def byte2str(b): return b __version__numpy__, numpy.__version__)) del version -def is_string_like(obj): - if hasattr(obj, 'shape'): return 0 - try: obj + '' - except (TypeError, ValueError): return 0 - return 1 - def _is_writable_dir(p): """ p is a string pointing to a putative writable dir -- return True p is such a string, else False """ - try: p + '' # test is string like - except TypeError: return False + try: + p + '' # test is string like + except TypeError: + return False + + # Test whether the operating system thinks it's a writable directory. + # Note that this check is necessary on Google App Engine, because the + # subsequent check will succeed even though p may not be writable. + if not os.access(p, os.W_OK) or not os.path.isdir(p): + return False + + # Also test that it is actually possible to write to a file here. try: t = tempfile.TemporaryFile(dir=p) try: t.write(ascii('1')) finally: t.close() - except OSError: return False - else: return True + except OSError: + return False + + return True class Verbose: """ @@ -466,38 +469,42 @@ def checkdep_usetex(s): def _get_home(): """Find user's home directory if possible. - Otherwise raise error. + Otherwise, returns None. - :see: http://mail.python.org/pipermail/python-list/2005-February/263921.html + :see: http://mail.python.org/pipermail/python-list/2005-February/325395.html """ - path='' try: - path=os.path.expanduser("~") - except: + path = os.path.expanduser("~") + except ImportError: + # This happens on Google App Engine (pwd module is not present). pass - if not os.path.isdir(path): - for evar in ('HOME', 'USERPROFILE', 'TMP'): - try: - path = os.environ[evar] - if os.path.isdir(path): - break - except: pass - if path: - return path else: - raise RuntimeError('please define environment variable $HOME') + if os.path.isdir(path): + return path + for evar in ('HOME', 'USERPROFILE', 'TMP'): + path = os.environ.get(evar) + if path is not None and os.path.isdir(path): + return path + return None def _create_tmp_config_dir(): """ If the config directory can not be created, create a temporary directory. + + Returns None if a writable temporary directory could not be created. """ import getpass import tempfile - tempdir = os.path.join( - tempfile.gettempdir(), 'matplotlib-%s' % getpass.getuser()) + try: + tempdir = tempfile.gettempdir() + except NotImplementedError: + # Some restricted platforms (such as Google App Engine) do not provide + # gettempdir. + return None + tempdir = os.path.join(tempdir, 'matplotlib-%s' % getpass.getuser()) os.environ['MPLCONFIGDIR'] = tempdir return tempdir @@ -505,42 +512,92 @@ def _create_tmp_config_dir(): get_home = verbose.wrap('$HOME=%s', _get_home, always=False) -def _get_configdir(): +def _get_xdg_config_dir(): """ - Return the string representing the configuration directory. + Returns the XDG configuration directory, according to the `XDG + base directory spec + `_. + """ + return os.environ.get('XDG_CONFIG_HOME', os.path.join(get_home(), '.config')) - Default is HOME/.matplotlib. You can override this with the - MPLCONFIGDIR environment variable. If the default is not - writable, and MPLCONFIGDIR is not set, then - tempfile.gettempdir() is used to provide a directory in - which a matplotlib subdirectory is created as the configuration - directory. + +def _get_xdg_cache_dir(): + """ + Returns the XDG cache directory, according to the `XDG + base directory spec + `_. """ + return os.environ.get('XDG_CACHE_HOME', os.path.join(get_home(), '.cache')) + + +def _get_config_or_cache_dir(xdg_base): + from matplotlib.cbook import mkdirs configdir = os.environ.get('MPLCONFIGDIR') if configdir is not None: if not os.path.exists(configdir): - os.makedirs(configdir) + from matplotlib.cbook import mkdirs + mkdirs(configdir) + if not _is_writable_dir(configdir): return _create_tmp_config_dir() return configdir h = get_home() - p = os.path.join(get_home(), '.matplotlib') + p = os.path.join(h, '.matplotlib') + if (sys.platform.startswith('linux') and + not os.path.exists(p)): + p = os.path.join(xdg_base, 'matplotlib') if os.path.exists(p): if not _is_writable_dir(p): return _create_tmp_config_dir() else: - if not _is_writable_dir(h): + try: + mkdirs(p) + except OSError: return _create_tmp_config_dir() - from matplotlib.cbook import mkdirs - mkdirs(p) return p + + +def _get_configdir(): + """ + Return the string representing the configuration directory. + + The directory is chosen as follows: + + 1. If the MPLCONFIGDIR environment variable is supplied, choose that. + + 2a. On Linux, if `$HOME/.matplotlib` exists, choose that, but warn that + that is the old location. Barring that, follow the XDG specification + and look first in `$XDG_CONFIG_HOME`, if defined, or `$HOME/.config`. + + 2b. On other platforms, choose `$HOME/.matplotlib`. + + 3. If the chosen directory exists and is writable, use that as the + configuration directory. + 4. If possible, create a temporary directory, and use it as the + configuration directory. + 5. A writable directory could not be found or created; return None. + """ + return _get_config_or_cache_dir(_get_xdg_config_dir()) + get_configdir = verbose.wrap('CONFIGDIR=%s', _get_configdir, always=False) +def _get_cachedir(): + """ + Return the location of the cache directory. + + The procedure used to find the directory is the same as for + _get_config_dir, except using `$XDG_CONFIG_HOME`/`~/.cache` instead. + """ + return _get_config_or_cache_dir(_get_xdg_cache_dir()) + +get_cachedir = verbose.wrap('CACHEDIR=%s', _get_cachedir, always=False) + + def _get_data_path(): 'get the path to matplotlib data' @@ -599,9 +656,9 @@ def get_example_data(fname): def get_py2exe_datafiles(): datapath = get_data_path() - head, tail = os.path.split(datapath) + _, tail = os.path.split(datapath) d = {} - for root, dirs, files in os.walk(datapath): + for root, _, files in os.walk(datapath): # Need to explicitly remove cocoa_agg files or py2exe complains # NOTE I dont know why, but do as previous version if 'Matplotlib.nib' in files: @@ -615,40 +672,36 @@ def get_py2exe_datafiles(): def matplotlib_fname(): """ - Return the path to the rc file + Get the location of the config file. - Search order: + The file location is determined in the following order - * current working dir - * environ var MATPLOTLIBRC - * HOME/.matplotlib/matplotlibrc - * MATPLOTLIBDATA/matplotlibrc + - `$PWD/matplotlibrc` + - environment variable `MATPLOTLIBRC` - """ + - `$MPLCONFIGDIR/matplotlib` - oldname = os.path.join( os.getcwd(), '.matplotlibrc') - if os.path.exists(oldname): - print("""\ -WARNING: Old rc filename ".matplotlibrc" found in working dir - and and renamed to new default rc file name "matplotlibrc" - (no leading"dot"). """, file=sys.stderr) - shutil.move('.matplotlibrc', 'matplotlibrc') + - On Linux, - home = get_home() - oldname = os.path.join( home, '.matplotlibrc') - if os.path.exists(oldname): - configdir = get_configdir() - newname = os.path.join(configdir, 'matplotlibrc') - print("""\ -WARNING: Old rc filename "%s" found and renamed to - new default rc file name "%s"."""%(oldname, newname), file=sys.stderr) + - `$HOME/.matplotlib/matplotlibrc`, if it exists - shutil.move(oldname, newname) + - or `$XDG_CONFIG_HOME/matplotlib/matplotlibrc` (if + $XDG_CONFIG_HOME is defined) + - or `$HOME/.config/matplotlib/matplotlibrc` (if + $XDG_CONFIG_HOME is not defined) - fname = os.path.join( os.getcwd(), 'matplotlibrc') - if os.path.exists(fname): return fname + - On other platforms, + + - `$HOME/.matplotlib/matplotlibrc` if `$HOME` is defined. + + - Lastly, it looks in `$MATPLOTLIBDATA/matplotlibrc` for a + system-defined copy. + """ + fname = os.path.join(os.getcwd(), 'matplotlibrc') + if os.path.exists(fname): + return fname if 'MATPLOTLIBRC' in os.environ: path = os.environ['MATPLOTLIBRC'] @@ -657,14 +710,28 @@ def matplotlib_fname(): if os.path.exists(fname): return fname - fname = os.path.join(get_configdir(), 'matplotlibrc') - if os.path.exists(fname): return fname - - - path = get_data_path() # guaranteed to exist or raise + configdir = _get_configdir() + if configdir is not None: + fname = os.path.join(configdir, 'matplotlibrc') + if os.path.exists(fname): + if (sys.platform.startswith('linux') and + fname == os.path.join( + get_home(), '.matplotlib', 'matplotlibrc')): + warnings.warn( + "Found matplotlib configuration in ~/.matplotlib. " + "To conform with the XDG base directory standard, " + "this configuration location has been deprecated " + "on Linux, and the new location is now %r. Please " + "move your configuration there to ensure that " + "matplotlib will continue to find it in the future." % + _get_xdg_config_dir()) + return fname + + path = get_data_path() # guaranteed to exist or raise fname = os.path.join(path, 'matplotlibrc') if not os.path.exists(fname): warnings.warn('Could not find matplotlibrc; using defaults') + return fname @@ -680,11 +747,6 @@ def matplotlib_fname(): } _deprecated_ignore_map = { - 'legend.pad' : 'legend.borderpad', - 'legend.labelsep' : 'legend.labelspacing', - 'legend.handlelen' : 'legend.handlelength', - 'legend.handletextsep' : 'legend.handletextpad', - 'legend.axespad' : 'legend.borderaxespad', } @@ -697,8 +759,8 @@ class RcParams(dict): :mod:`matplotlib.rcsetup` """ - validate = dict([ (key, converter) for key, (default, converter) in \ - defaultParams.iteritems() ]) + validate = dict((key, converter) for key, (default, converter) in \ + defaultParams.iteritems()) msg_depr = "%s is deprecated and replaced with %s; please use the latter." msg_depr_ignore = "%s is deprecated and ignored. Use %s" @@ -729,6 +791,19 @@ def __getitem__(self, key): key = alt return dict.__getitem__(self, key) + def __repr__(self): + import pprint + class_name = self.__class__.__name__ + indent = len(class_name) + 1 + repr_split = pprint.pformat(dict(self), indent=1, + width=80 - indent).split('\n') + repr_indented = ('\n' + ' ' * indent).join(repr_split) + return '{0}({1})'.format(class_name, repr_indented) + + def __str__(self): + return '\n'.join('{0}: {1}'.format(k, v) + for k, v in sorted(self.items())) + def keys(self): """ Return sorted list of keys. @@ -741,16 +816,35 @@ def values(self): """ Return values in order of sorted keys. """ - return [self[k] for k in self.iterkeys()] + return [self[k] for k in self.keys()] -def rc_params(fail_on_error=False): - 'Return the default params updated from the values in the rc file' + def find_all(self, pattern): + """ + Return the subset of this RcParams dictionary whose keys match, + using :func:`re.search`, the given ``pattern``. + + .. note:: + Changes to the returned dictionary are *not* propagated to + the parent RcParams dictionary. + + """ + import re + pattern_re = re.compile(pattern) + return RcParams((key, value) + for key, value in self.items() + if pattern_re.search(key)) + + +def rc_params(fail_on_error=False): + """Return a :class:`matplotlib.RcParams` instance from the + default matplotlib rc file. + """ fname = matplotlib_fname() if not os.path.exists(fname): # this should never happen, default in mpl-data should always be found message = 'could not find rc file; returning defaults' - ret = RcParams([ (key, default) for key, (default, converter) in \ + ret = RcParams([(key, default) for key, (default, _) in \ defaultParams.iteritems() ]) warnings.warn(message) return ret @@ -759,29 +853,31 @@ def rc_params(fail_on_error=False): def rc_params_from_file(fname, fail_on_error=False): - """Load and return params from fname.""" - + """Return a :class:`matplotlib.RcParams` instance from the + contents of the given filename. + """ cnt = 0 rc_temp = {} with open(fname) as fd: for line in fd: cnt += 1 - strippedline = line.split('#',1)[0].strip() + strippedline = line.split('#', 1)[0].strip() if not strippedline: continue - tup = strippedline.split(':',1) - if len(tup) !=2: - warnings.warn('Illegal line #%d\n\t%s\n\tin file "%s"'%\ + tup = strippedline.split(':', 1) + if len(tup) != 2: + warnings.warn('Illegal line #%d\n\t%s\n\tin file "%s"' % \ (cnt, line, fname)) continue key, val = tup key = key.strip() val = val.strip() if key in rc_temp: - warnings.warn('Duplicate key in file "%s", line #%d'%(fname,cnt)) + warnings.warn('Duplicate key in file "%s", line #%d' % \ + (fname, cnt)) rc_temp[key] = (val, line, cnt) - ret = RcParams([ (key, default) for key, (default, converter) in \ - defaultParams.iteritems() ]) + ret = RcParams([(key, default) for key, (default, _) in \ + defaultParams.iteritems()]) for key in ('verbose.level', 'verbose.fileo'): if key in rc_temp: @@ -865,10 +961,10 @@ def rc_params_from_file(fname, fail_on_error=False): def rc(group, **kwargs): """ - Set the current rc params. Group is the grouping for the rc, eg. + Set the current rc params. Group is the grouping for the rc, e.g., for ``lines.linewidth`` the group is ``lines``, for ``axes.facecolor``, the group is ``axes``, and so on. Group may - also be a list or tuple of group names, eg. (*xtick*, *ytick*). + also be a list or tuple of group names, e.g., (*xtick*, *ytick*). *kwargs* is a dictionary attribute name/value pairs, eg:: rc('lines', linewidth=2, color='r') @@ -899,7 +995,7 @@ def rc(group, **kwargs): Note you can use python's kwargs dictionary facility to store - dictionaries of default parameters. Eg, you can customize the + dictionaries of default parameters. e.g., you can customize the font rc as follows:: font = {'family' : 'monospace', @@ -957,11 +1053,11 @@ class rc_context(object): This allows one to do:: - >>> with mpl.rc_context(fname='screen.rc'): - >>> plt.plot(x, a) - >>> with mpl.rc_context(fname='print.rc'): - >>> plt.plot(x, b) - >>> plt.plot(x, c) + with mpl.rc_context(fname='screen.rc'): + plt.plot(x, a) + with mpl.rc_context(fname='print.rc'): + plt.plot(x, b) + plt.plot(x, c) The 'a' vs 'x' and 'c' vs 'x' plots would have settings from 'screen.rc', while the 'b' vs 'x' plot would have settings from @@ -969,8 +1065,8 @@ class rc_context(object): A dictionary can also be passed to the context manager:: - >>> with mpl.rc_context(rc={'text.usetex': True}, fname='screen.rc'): - >>> plt.plot(x, a) + with mpl.rc_context(rc={'text.usetex': True}, fname='screen.rc'): + plt.plot(x, a) The 'rc' dictionary takes precedence over the settings loaded from 'fname'. Passing a dictionary only is also valid. @@ -979,12 +1075,15 @@ class rc_context(object): def __init__(self, rc=None, fname=None): self.rcdict = rc self.fname = fname - def __enter__(self): self._rcparams = rcParams.copy() if self.fname: rc_file(self.fname) if self.rcdict: rcParams.update(self.rcdict) + + def __enter__(self): + return self + def __exit__(self, type, value, tb): rcParams.update(self._rcparams) @@ -1020,16 +1119,25 @@ def use(arg, warn=True, force=False): is issued if you try and call this after pylab or pyplot have been loaded. In certain black magic use cases, e.g. :func:`pyplot.switch_backend`, we are doing the reloading necessary to - make the backend switch work (in some cases, e.g. pure image + make the backend switch work (in some cases, e.g., pure image backends) so one can set warn=False to suppress the warnings. To find out which backend is currently set, see :func:`matplotlib.get_backend`. """ + # Lets determine the proper backend name first + if arg.startswith('module://'): + name = arg + else: + # Lowercase only non-module backend names (modules are case-sensitive) + arg = arg.lower() + name = validate_backend(arg) + # Check if we've already set up a backend if 'matplotlib.backends' in sys.modules: - if warn: + # Warn only if called with a different name + if (rcParams['backend'] != name) and warn: warnings.warn(_use_error_msg) # Unless we've been told to force it, just return @@ -1039,14 +1147,7 @@ def use(arg, warn=True, force=False): else: need_reload = False - # Set-up the proper backend name - if arg.startswith('module://'): - name = arg - else: - # Lowercase only non-module backend names (modules are case-sensitive) - arg = arg.lower() - name = validate_backend(arg) - + # Store the backend name rcParams['backend'] = name # If needed we reload here because a lot of setup code is triggered on @@ -1055,7 +1156,7 @@ def use(arg, warn=True, force=False): reload(sys.modules['matplotlib.backends']) def get_backend(): - "Returns the current backend." + """Return the name of the current backend.""" return rcParams['backend'] def interactive(b): @@ -1094,35 +1195,46 @@ def tk_window_focus(): default_test_modules = [ 'matplotlib.tests.test_agg', + 'matplotlib.tests.test_arrow_patches', 'matplotlib.tests.test_artist', 'matplotlib.tests.test_axes', - 'matplotlib.tests.test_backend_svg', + 'matplotlib.tests.test_backend_pdf', 'matplotlib.tests.test_backend_pgf', + 'matplotlib.tests.test_backend_qt4', + 'matplotlib.tests.test_backend_svg', 'matplotlib.tests.test_basic', + 'matplotlib.tests.test_bbox_tight', 'matplotlib.tests.test_cbook', + 'matplotlib.tests.test_coding_standards', + 'matplotlib.tests.test_collections', 'matplotlib.tests.test_colorbar', 'matplotlib.tests.test_colors', + 'matplotlib.tests.test_compare_images', + 'matplotlib.tests.test_contour', 'matplotlib.tests.test_dates', 'matplotlib.tests.test_delaunay', 'matplotlib.tests.test_figure', 'matplotlib.tests.test_image', 'matplotlib.tests.test_legend', + 'matplotlib.tests.test_lines', 'matplotlib.tests.test_mathtext', 'matplotlib.tests.test_mlab', 'matplotlib.tests.test_patches', + 'matplotlib.tests.test_path', + 'matplotlib.tests.test_patheffects', 'matplotlib.tests.test_pickle', + 'matplotlib.tests.test_png', 'matplotlib.tests.test_rcparams', 'matplotlib.tests.test_scale', 'matplotlib.tests.test_simplification', 'matplotlib.tests.test_spines', + 'matplotlib.tests.test_streamplot', 'matplotlib.tests.test_subplots', 'matplotlib.tests.test_text', 'matplotlib.tests.test_ticker', 'matplotlib.tests.test_tightlayout', - 'matplotlib.tests.test_triangulation', 'matplotlib.tests.test_transforms', - 'matplotlib.tests.test_arrow_patches', - 'matplotlib.tests.test_backend_qt4', + 'matplotlib.tests.test_triangulation', ] diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index e5addf15b895..94fd34fa59f1 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -2,33 +2,44 @@ Nothing here but dictionaries for generating LinearSegmentedColormaps, and a dictionary of these dictionaries. +Documentation for each is in pyplot.colormaps() """ from __future__ import print_function, division import numpy as np _binary_data = { - 'red' : ((0., 1., 1.), (1., 0., 0.)), + 'red': ((0., 1., 1.), (1., 0., 0.)), 'green': ((0., 1., 1.), (1., 0., 0.)), - 'blue' : ((0., 1., 1.), (1., 0., 0.)) + 'blue': ((0., 1., 1.), (1., 0., 0.)) } -_autumn_data = {'red': ((0., 1.0, 1.0),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(1.0, 1.0, 1.0)), - 'blue': ((0., 0., 0.),(1.0, 0., 0.))} - -_bone_data = {'red': ((0., 0., 0.),(0.746032, 0.652778, 0.652778),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(0.365079, 0.319444, 0.319444), - (0.746032, 0.777778, 0.777778),(1.0, 1.0, 1.0)), - 'blue': ((0., 0., 0.),(0.365079, 0.444444, 0.444444),(1.0, 1.0, 1.0))} +_autumn_data = {'red': ((0., 1.0, 1.0), (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)), + 'blue': ((0., 0., 0.), (1.0, 0., 0.))} + +_bone_data = {'red': ((0., 0., 0.), + (0.746032, 0.652778, 0.652778), + (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), + (0.365079, 0.319444, 0.319444), + (0.746032, 0.777778, 0.777778), + (1.0, 1.0, 1.0)), + 'blue': ((0., 0., 0.), + (0.365079, 0.444444, 0.444444), + (1.0, 1.0, 1.0))} _cool_data = {'red': ((0., 0., 0.), (1.0, 1.0, 1.0)), 'green': ((0., 1., 1.), (1.0, 0., 0.)), 'blue': ((0., 1., 1.), (1.0, 1., 1.))} -_copper_data = {'red': ((0., 0., 0.),(0.809524, 1.000000, 1.000000),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(1.0, 0.7812, 0.7812)), - 'blue': ((0., 0., 0.),(1.0, 0.4975, 0.4975))} +_copper_data = {'red': ((0., 0., 0.), + (0.809524, 1.000000, 1.000000), + (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), + (1.0, 0.7812, 0.7812)), + 'blue': ((0., 0., 0.), + (1.0, 0.4975, 0.4975))} _flag_data = { 'red': lambda x: 0.75 * np.sin((x * 31.5 + 0.25) * np.pi) + 0.5, @@ -42,6 +53,7 @@ 'blue': lambda x: -1.1 * np.sin((x * 20.9) * np.pi), } + def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0): """Return custom data dictionary of (r,g,b) conversion functions, which can be used with :func:`register_cmap`, for the cubehelix color scheme. @@ -82,9 +94,10 @@ def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0): """ def get_color_function(p0, p1): + def color(x): # Apply gamma factor to emphasise low or high intensity values - xg = x**gamma + xg = x ** gamma # Calculate amplitude and angle of deviation from the black # to white diagonal in the plane of constant @@ -113,15 +126,15 @@ def color(x): 1: lambda x: 0.5, 2: lambda x: 1, 3: lambda x: x, - 4: lambda x: x**2, - 5: lambda x: x**3, - 6: lambda x: x**4, + 4: lambda x: x ** 2, + 5: lambda x: x ** 3, + 6: lambda x: x ** 4, 7: lambda x: np.sqrt(x), 8: lambda x: np.sqrt(np.sqrt(x)), 9: lambda x: np.sin(x * np.pi / 2), 10: lambda x: np.cos(x * np.pi / 2), 11: lambda x: np.abs(x - 0.5), - 12: lambda x: (2 * x - 1)**2, + 12: lambda x: (2 * x - 1) ** 2, 13: lambda x: np.sin(x * np.pi), 14: lambda x: np.abs(np.cos(x * np.pi)), 15: lambda x: np.sin(x * 2 * np.pi), @@ -137,8 +150,8 @@ def color(x): 25: lambda x: np.abs(3 * x - 2), 26: lambda x: (3 * x - 1) / 2, 27: lambda x: (3 * x - 2) / 2, - 28: lambda x: np.abs((3 * x - 1) / 2), - 29: lambda x: np.abs((3 * x - 2) / 2), + 28: lambda x: np.abs((3 * x - 1) / 2), + 29: lambda x: np.abs((3 * x - 2) / 2), 30: lambda x: x / 0.32 - 0.78125, 31: lambda x: 2 * x - 0.84, 32: lambda x: gfunc32(x), @@ -148,6 +161,7 @@ def color(x): 36: lambda x: 2 * x - 1. } + def gfunc32(x): ret = np.zeros(len(x)) m = (x < 0.25) @@ -201,180 +215,289 @@ def gfunc32(x): (0.75, (0.5, 0.36, 0.33)), (1.00, (1.0, 1.0, 1.0))) -_gray_data = {'red': ((0., 0, 0), (1., 1, 1)), - 'green': ((0., 0, 0), (1., 1, 1)), - 'blue': ((0., 0, 0), (1., 1, 1))} - -_hot_data = {'red': ((0., 0.0416, 0.0416),(0.365079, 1.000000, 1.000000),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(0.365079, 0.000000, 0.000000), - (0.746032, 1.000000, 1.000000),(1.0, 1.0, 1.0)), - 'blue': ((0., 0., 0.),(0.746032, 0.000000, 0.000000),(1.0, 1.0, 1.0))} - -_hsv_data = {'red': ((0., 1., 1.),(0.158730, 1.000000, 1.000000), - (0.174603, 0.968750, 0.968750),(0.333333, 0.031250, 0.031250), - (0.349206, 0.000000, 0.000000),(0.666667, 0.000000, 0.000000), - (0.682540, 0.031250, 0.031250),(0.841270, 0.968750, 0.968750), - (0.857143, 1.000000, 1.000000),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(0.158730, 0.937500, 0.937500), - (0.174603, 1.000000, 1.000000),(0.507937, 1.000000, 1.000000), - (0.666667, 0.062500, 0.062500),(0.682540, 0.000000, 0.000000), +_gray_data = {'red': ((0., 0, 0), (1., 1, 1)), + 'green': ((0., 0, 0), (1., 1, 1)), + 'blue': ((0., 0, 0), (1., 1, 1))} + +_hot_data = {'red': ((0., 0.0416, 0.0416), + (0.365079, 1.000000, 1.000000), + (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), + (0.365079, 0.000000, 0.000000), + (0.746032, 1.000000, 1.000000), + (1.0, 1.0, 1.0)), + 'blue': ((0., 0., 0.), + (0.746032, 0.000000, 0.000000), + (1.0, 1.0, 1.0))} + +_hsv_data = {'red': ((0., 1., 1.), + (0.158730, 1.000000, 1.000000), + (0.174603, 0.968750, 0.968750), + (0.333333, 0.031250, 0.031250), + (0.349206, 0.000000, 0.000000), + (0.666667, 0.000000, 0.000000), + (0.682540, 0.031250, 0.031250), + (0.841270, 0.968750, 0.968750), + (0.857143, 1.000000, 1.000000), + (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), + (0.158730, 0.937500, 0.937500), + (0.174603, 1.000000, 1.000000), + (0.507937, 1.000000, 1.000000), + (0.666667, 0.062500, 0.062500), + (0.682540, 0.000000, 0.000000), (1.0, 0., 0.)), - 'blue': ((0., 0., 0.),(0.333333, 0.000000, 0.000000), - (0.349206, 0.062500, 0.062500),(0.507937, 1.000000, 1.000000), - (0.841270, 1.000000, 1.000000),(0.857143, 0.937500, 0.937500), + 'blue': ((0., 0., 0.), + (0.333333, 0.000000, 0.000000), + (0.349206, 0.062500, 0.062500), + (0.507937, 1.000000, 1.000000), + (0.841270, 1.000000, 1.000000), + (0.857143, 0.937500, 0.937500), (1.0, 0.09375, 0.09375))} -_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89,1, 1), +_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), - 'green': ((0., 0, 0), (0.125,0, 0), (0.375,1, 1), (0.64,1, 1), - (0.91,0,0), (1, 0, 0)), - 'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65,0, 0), - (1, 0, 0))} - -_pink_data = {'red': ((0., 0.1178, 0.1178),(0.015873, 0.195857, 0.195857), - (0.031746, 0.250661, 0.250661),(0.047619, 0.295468, 0.295468), - (0.063492, 0.334324, 0.334324),(0.079365, 0.369112, 0.369112), - (0.095238, 0.400892, 0.400892),(0.111111, 0.430331, 0.430331), - (0.126984, 0.457882, 0.457882),(0.142857, 0.483867, 0.483867), - (0.158730, 0.508525, 0.508525),(0.174603, 0.532042, 0.532042), - (0.190476, 0.554563, 0.554563),(0.206349, 0.576204, 0.576204), - (0.222222, 0.597061, 0.597061),(0.238095, 0.617213, 0.617213), - (0.253968, 0.636729, 0.636729),(0.269841, 0.655663, 0.655663), - (0.285714, 0.674066, 0.674066),(0.301587, 0.691980, 0.691980), - (0.317460, 0.709441, 0.709441),(0.333333, 0.726483, 0.726483), - (0.349206, 0.743134, 0.743134),(0.365079, 0.759421, 0.759421), - (0.380952, 0.766356, 0.766356),(0.396825, 0.773229, 0.773229), - (0.412698, 0.780042, 0.780042),(0.428571, 0.786796, 0.786796), - (0.444444, 0.793492, 0.793492),(0.460317, 0.800132, 0.800132), - (0.476190, 0.806718, 0.806718),(0.492063, 0.813250, 0.813250), - (0.507937, 0.819730, 0.819730),(0.523810, 0.826160, 0.826160), - (0.539683, 0.832539, 0.832539),(0.555556, 0.838870, 0.838870), - (0.571429, 0.845154, 0.845154),(0.587302, 0.851392, 0.851392), - (0.603175, 0.857584, 0.857584),(0.619048, 0.863731, 0.863731), - (0.634921, 0.869835, 0.869835),(0.650794, 0.875897, 0.875897), - (0.666667, 0.881917, 0.881917),(0.682540, 0.887896, 0.887896), - (0.698413, 0.893835, 0.893835),(0.714286, 0.899735, 0.899735), - (0.730159, 0.905597, 0.905597),(0.746032, 0.911421, 0.911421), - (0.761905, 0.917208, 0.917208),(0.777778, 0.922958, 0.922958), - (0.793651, 0.928673, 0.928673),(0.809524, 0.934353, 0.934353), - (0.825397, 0.939999, 0.939999),(0.841270, 0.945611, 0.945611), - (0.857143, 0.951190, 0.951190),(0.873016, 0.956736, 0.956736), - (0.888889, 0.962250, 0.962250),(0.904762, 0.967733, 0.967733), - (0.920635, 0.973185, 0.973185),(0.936508, 0.978607, 0.978607), - (0.952381, 0.983999, 0.983999),(0.968254, 0.989361, 0.989361), - (0.984127, 0.994695, 0.994695),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(0.015873, 0.102869, 0.102869), - (0.031746, 0.145479, 0.145479),(0.047619, 0.178174, 0.178174), - (0.063492, 0.205738, 0.205738),(0.079365, 0.230022, 0.230022), - (0.095238, 0.251976, 0.251976),(0.111111, 0.272166, 0.272166), - (0.126984, 0.290957, 0.290957),(0.142857, 0.308607, 0.308607), - (0.158730, 0.325300, 0.325300),(0.174603, 0.341178, 0.341178), - (0.190476, 0.356348, 0.356348),(0.206349, 0.370899, 0.370899), - (0.222222, 0.384900, 0.384900),(0.238095, 0.398410, 0.398410), - (0.253968, 0.411476, 0.411476),(0.269841, 0.424139, 0.424139), - (0.285714, 0.436436, 0.436436),(0.301587, 0.448395, 0.448395), - (0.317460, 0.460044, 0.460044),(0.333333, 0.471405, 0.471405), - (0.349206, 0.482498, 0.482498),(0.365079, 0.493342, 0.493342), - (0.380952, 0.517549, 0.517549),(0.396825, 0.540674, 0.540674), - (0.412698, 0.562849, 0.562849),(0.428571, 0.584183, 0.584183), - (0.444444, 0.604765, 0.604765),(0.460317, 0.624669, 0.624669), - (0.476190, 0.643958, 0.643958),(0.492063, 0.662687, 0.662687), - (0.507937, 0.680900, 0.680900),(0.523810, 0.698638, 0.698638), - (0.539683, 0.715937, 0.715937),(0.555556, 0.732828, 0.732828), - (0.571429, 0.749338, 0.749338),(0.587302, 0.765493, 0.765493), - (0.603175, 0.781313, 0.781313),(0.619048, 0.796819, 0.796819), - (0.634921, 0.812029, 0.812029),(0.650794, 0.826960, 0.826960), - (0.666667, 0.841625, 0.841625),(0.682540, 0.856040, 0.856040), - (0.698413, 0.870216, 0.870216),(0.714286, 0.884164, 0.884164), - (0.730159, 0.897896, 0.897896),(0.746032, 0.911421, 0.911421), - (0.761905, 0.917208, 0.917208),(0.777778, 0.922958, 0.922958), - (0.793651, 0.928673, 0.928673),(0.809524, 0.934353, 0.934353), - (0.825397, 0.939999, 0.939999),(0.841270, 0.945611, 0.945611), - (0.857143, 0.951190, 0.951190),(0.873016, 0.956736, 0.956736), - (0.888889, 0.962250, 0.962250),(0.904762, 0.967733, 0.967733), - (0.920635, 0.973185, 0.973185),(0.936508, 0.978607, 0.978607), - (0.952381, 0.983999, 0.983999),(0.968254, 0.989361, 0.989361), - (0.984127, 0.994695, 0.994695),(1.0, 1.0, 1.0)), - 'blue': ((0., 0., 0.),(0.015873, 0.102869, 0.102869), - (0.031746, 0.145479, 0.145479),(0.047619, 0.178174, 0.178174), - (0.063492, 0.205738, 0.205738),(0.079365, 0.230022, 0.230022), - (0.095238, 0.251976, 0.251976),(0.111111, 0.272166, 0.272166), - (0.126984, 0.290957, 0.290957),(0.142857, 0.308607, 0.308607), - (0.158730, 0.325300, 0.325300),(0.174603, 0.341178, 0.341178), - (0.190476, 0.356348, 0.356348),(0.206349, 0.370899, 0.370899), - (0.222222, 0.384900, 0.384900),(0.238095, 0.398410, 0.398410), - (0.253968, 0.411476, 0.411476),(0.269841, 0.424139, 0.424139), - (0.285714, 0.436436, 0.436436),(0.301587, 0.448395, 0.448395), - (0.317460, 0.460044, 0.460044),(0.333333, 0.471405, 0.471405), - (0.349206, 0.482498, 0.482498),(0.365079, 0.493342, 0.493342), - (0.380952, 0.503953, 0.503953),(0.396825, 0.514344, 0.514344), - (0.412698, 0.524531, 0.524531),(0.428571, 0.534522, 0.534522), - (0.444444, 0.544331, 0.544331),(0.460317, 0.553966, 0.553966), - (0.476190, 0.563436, 0.563436),(0.492063, 0.572750, 0.572750), - (0.507937, 0.581914, 0.581914),(0.523810, 0.590937, 0.590937), - (0.539683, 0.599824, 0.599824),(0.555556, 0.608581, 0.608581), - (0.571429, 0.617213, 0.617213),(0.587302, 0.625727, 0.625727), - (0.603175, 0.634126, 0.634126),(0.619048, 0.642416, 0.642416), - (0.634921, 0.650600, 0.650600),(0.650794, 0.658682, 0.658682), - (0.666667, 0.666667, 0.666667),(0.682540, 0.674556, 0.674556), - (0.698413, 0.682355, 0.682355),(0.714286, 0.690066, 0.690066), - (0.730159, 0.697691, 0.697691),(0.746032, 0.705234, 0.705234), - (0.761905, 0.727166, 0.727166),(0.777778, 0.748455, 0.748455), - (0.793651, 0.769156, 0.769156),(0.809524, 0.789314, 0.789314), - (0.825397, 0.808969, 0.808969),(0.841270, 0.828159, 0.828159), - (0.857143, 0.846913, 0.846913),(0.873016, 0.865261, 0.865261), - (0.888889, 0.883229, 0.883229),(0.904762, 0.900837, 0.900837), - (0.920635, 0.918109, 0.918109),(0.936508, 0.935061, 0.935061), - (0.952381, 0.951711, 0.951711),(0.968254, 0.968075, 0.968075), - (0.984127, 0.984167, 0.984167),(1.0, 1.0, 1.0))} - -_spring_data = {'red': ((0., 1., 1.),(1.0, 1.0, 1.0)), - 'green': ((0., 0., 0.),(1.0, 1.0, 1.0)), - 'blue': ((0., 1., 1.),(1.0, 0.0, 0.0))} - - -_summer_data = {'red': ((0., 0., 0.),(1.0, 1.0, 1.0)), - 'green': ((0., 0.5, 0.5),(1.0, 1.0, 1.0)), - 'blue': ((0., 0.4, 0.4),(1.0, 0.4, 0.4))} - - -_winter_data = {'red': ((0., 0., 0.),(1.0, 0.0, 0.0)), - 'green': ((0., 0., 0.),(1.0, 1.0, 1.0)), - 'blue': ((0., 1., 1.),(1.0, 0.5, 0.5))} - -_spectral_data = {'red': [(0.0, 0.0, 0.0), (0.05, 0.4667, 0.4667), - (0.10, 0.5333, 0.5333), (0.15, 0.0, 0.0), - (0.20, 0.0, 0.0), (0.25, 0.0, 0.0), - (0.30, 0.0, 0.0), (0.35, 0.0, 0.0), - (0.40, 0.0, 0.0), (0.45, 0.0, 0.0), - (0.50, 0.0, 0.0), (0.55, 0.0, 0.0), - (0.60, 0.0, 0.0), (0.65, 0.7333, 0.7333), - (0.70, 0.9333, 0.9333), (0.75, 1.0, 1.0), - (0.80, 1.0, 1.0), (0.85, 1.0, 1.0), - (0.90, 0.8667, 0.8667), (0.95, 0.80, 0.80), - (1.0, 0.80, 0.80)], - 'green': [(0.0, 0.0, 0.0), (0.05, 0.0, 0.0), - (0.10, 0.0, 0.0), (0.15, 0.0, 0.0), - (0.20, 0.0, 0.0), (0.25, 0.4667, 0.4667), - (0.30, 0.6000, 0.6000), (0.35, 0.6667, 0.6667), - (0.40, 0.6667, 0.6667), (0.45, 0.6000, 0.6000), - (0.50, 0.7333, 0.7333), (0.55, 0.8667, 0.8667), - (0.60, 1.0, 1.0), (0.65, 1.0, 1.0), - (0.70, 0.9333, 0.9333), (0.75, 0.8000, 0.8000), - (0.80, 0.6000, 0.6000), (0.85, 0.0, 0.0), - (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), - (1.0, 0.80, 0.80)], - 'blue': [(0.0, 0.0, 0.0), (0.05, 0.5333, 0.5333), - (0.10, 0.6000, 0.6000), (0.15, 0.6667, 0.6667), - (0.20, 0.8667, 0.8667), (0.25, 0.8667, 0.8667), - (0.30, 0.8667, 0.8667), (0.35, 0.6667, 0.6667), - (0.40, 0.5333, 0.5333), (0.45, 0.0, 0.0), - (0.5, 0.0, 0.0), (0.55, 0.0, 0.0), - (0.60, 0.0, 0.0), (0.65, 0.0, 0.0), - (0.70, 0.0, 0.0), (0.75, 0.0, 0.0), - (0.80, 0.0, 0.0), (0.85, 0.0, 0.0), - (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), - (1.0, 0.80, 0.80)]} + 'green': ((0., 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), + (0.91, 0, 0), (1, 0, 0)), + 'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), + (0.65, 0, 0), (1, 0, 0))} + +_pink_data = {'red': ((0., 0.1178, 0.1178), (0.015873, 0.195857, 0.195857), + (0.031746, 0.250661, 0.250661), + (0.047619, 0.295468, 0.295468), + (0.063492, 0.334324, 0.334324), + (0.079365, 0.369112, 0.369112), + (0.095238, 0.400892, 0.400892), + (0.111111, 0.430331, 0.430331), + (0.126984, 0.457882, 0.457882), + (0.142857, 0.483867, 0.483867), + (0.158730, 0.508525, 0.508525), + (0.174603, 0.532042, 0.532042), + (0.190476, 0.554563, 0.554563), + (0.206349, 0.576204, 0.576204), + (0.222222, 0.597061, 0.597061), + (0.238095, 0.617213, 0.617213), + (0.253968, 0.636729, 0.636729), + (0.269841, 0.655663, 0.655663), + (0.285714, 0.674066, 0.674066), + (0.301587, 0.691980, 0.691980), + (0.317460, 0.709441, 0.709441), + (0.333333, 0.726483, 0.726483), + (0.349206, 0.743134, 0.743134), + (0.365079, 0.759421, 0.759421), + (0.380952, 0.766356, 0.766356), + (0.396825, 0.773229, 0.773229), + (0.412698, 0.780042, 0.780042), + (0.428571, 0.786796, 0.786796), + (0.444444, 0.793492, 0.793492), + (0.460317, 0.800132, 0.800132), + (0.476190, 0.806718, 0.806718), + (0.492063, 0.813250, 0.813250), + (0.507937, 0.819730, 0.819730), + (0.523810, 0.826160, 0.826160), + (0.539683, 0.832539, 0.832539), + (0.555556, 0.838870, 0.838870), + (0.571429, 0.845154, 0.845154), + (0.587302, 0.851392, 0.851392), + (0.603175, 0.857584, 0.857584), + (0.619048, 0.863731, 0.863731), + (0.634921, 0.869835, 0.869835), + (0.650794, 0.875897, 0.875897), + (0.666667, 0.881917, 0.881917), + (0.682540, 0.887896, 0.887896), + (0.698413, 0.893835, 0.893835), + (0.714286, 0.899735, 0.899735), + (0.730159, 0.905597, 0.905597), + (0.746032, 0.911421, 0.911421), + (0.761905, 0.917208, 0.917208), + (0.777778, 0.922958, 0.922958), + (0.793651, 0.928673, 0.928673), + (0.809524, 0.934353, 0.934353), + (0.825397, 0.939999, 0.939999), + (0.841270, 0.945611, 0.945611), + (0.857143, 0.951190, 0.951190), + (0.873016, 0.956736, 0.956736), + (0.888889, 0.962250, 0.962250), + (0.904762, 0.967733, 0.967733), + (0.920635, 0.973185, 0.973185), + (0.936508, 0.978607, 0.978607), + (0.952381, 0.983999, 0.983999), + (0.968254, 0.989361, 0.989361), + (0.984127, 0.994695, 0.994695), (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), (0.015873, 0.102869, 0.102869), + (0.031746, 0.145479, 0.145479), + (0.047619, 0.178174, 0.178174), + (0.063492, 0.205738, 0.205738), + (0.079365, 0.230022, 0.230022), + (0.095238, 0.251976, 0.251976), + (0.111111, 0.272166, 0.272166), + (0.126984, 0.290957, 0.290957), + (0.142857, 0.308607, 0.308607), + (0.158730, 0.325300, 0.325300), + (0.174603, 0.341178, 0.341178), + (0.190476, 0.356348, 0.356348), + (0.206349, 0.370899, 0.370899), + (0.222222, 0.384900, 0.384900), + (0.238095, 0.398410, 0.398410), + (0.253968, 0.411476, 0.411476), + (0.269841, 0.424139, 0.424139), + (0.285714, 0.436436, 0.436436), + (0.301587, 0.448395, 0.448395), + (0.317460, 0.460044, 0.460044), + (0.333333, 0.471405, 0.471405), + (0.349206, 0.482498, 0.482498), + (0.365079, 0.493342, 0.493342), + (0.380952, 0.517549, 0.517549), + (0.396825, 0.540674, 0.540674), + (0.412698, 0.562849, 0.562849), + (0.428571, 0.584183, 0.584183), + (0.444444, 0.604765, 0.604765), + (0.460317, 0.624669, 0.624669), + (0.476190, 0.643958, 0.643958), + (0.492063, 0.662687, 0.662687), + (0.507937, 0.680900, 0.680900), + (0.523810, 0.698638, 0.698638), + (0.539683, 0.715937, 0.715937), + (0.555556, 0.732828, 0.732828), + (0.571429, 0.749338, 0.749338), + (0.587302, 0.765493, 0.765493), + (0.603175, 0.781313, 0.781313), + (0.619048, 0.796819, 0.796819), + (0.634921, 0.812029, 0.812029), + (0.650794, 0.826960, 0.826960), + (0.666667, 0.841625, 0.841625), + (0.682540, 0.856040, 0.856040), + (0.698413, 0.870216, 0.870216), + (0.714286, 0.884164, 0.884164), + (0.730159, 0.897896, 0.897896), + (0.746032, 0.911421, 0.911421), + (0.761905, 0.917208, 0.917208), + (0.777778, 0.922958, 0.922958), + (0.793651, 0.928673, 0.928673), + (0.809524, 0.934353, 0.934353), + (0.825397, 0.939999, 0.939999), + (0.841270, 0.945611, 0.945611), + (0.857143, 0.951190, 0.951190), + (0.873016, 0.956736, 0.956736), + (0.888889, 0.962250, 0.962250), + (0.904762, 0.967733, 0.967733), + (0.920635, 0.973185, 0.973185), + (0.936508, 0.978607, 0.978607), + (0.952381, 0.983999, 0.983999), + (0.968254, 0.989361, 0.989361), + (0.984127, 0.994695, 0.994695), (1.0, 1.0, 1.0)), + 'blue': ((0., 0., 0.), (0.015873, 0.102869, 0.102869), + (0.031746, 0.145479, 0.145479), + (0.047619, 0.178174, 0.178174), + (0.063492, 0.205738, 0.205738), + (0.079365, 0.230022, 0.230022), + (0.095238, 0.251976, 0.251976), + (0.111111, 0.272166, 0.272166), + (0.126984, 0.290957, 0.290957), + (0.142857, 0.308607, 0.308607), + (0.158730, 0.325300, 0.325300), + (0.174603, 0.341178, 0.341178), + (0.190476, 0.356348, 0.356348), + (0.206349, 0.370899, 0.370899), + (0.222222, 0.384900, 0.384900), + (0.238095, 0.398410, 0.398410), + (0.253968, 0.411476, 0.411476), + (0.269841, 0.424139, 0.424139), + (0.285714, 0.436436, 0.436436), + (0.301587, 0.448395, 0.448395), + (0.317460, 0.460044, 0.460044), + (0.333333, 0.471405, 0.471405), + (0.349206, 0.482498, 0.482498), + (0.365079, 0.493342, 0.493342), + (0.380952, 0.503953, 0.503953), + (0.396825, 0.514344, 0.514344), + (0.412698, 0.524531, 0.524531), + (0.428571, 0.534522, 0.534522), + (0.444444, 0.544331, 0.544331), + (0.460317, 0.553966, 0.553966), + (0.476190, 0.563436, 0.563436), + (0.492063, 0.572750, 0.572750), + (0.507937, 0.581914, 0.581914), + (0.523810, 0.590937, 0.590937), + (0.539683, 0.599824, 0.599824), + (0.555556, 0.608581, 0.608581), + (0.571429, 0.617213, 0.617213), + (0.587302, 0.625727, 0.625727), + (0.603175, 0.634126, 0.634126), + (0.619048, 0.642416, 0.642416), + (0.634921, 0.650600, 0.650600), + (0.650794, 0.658682, 0.658682), + (0.666667, 0.666667, 0.666667), + (0.682540, 0.674556, 0.674556), + (0.698413, 0.682355, 0.682355), + (0.714286, 0.690066, 0.690066), + (0.730159, 0.697691, 0.697691), + (0.746032, 0.705234, 0.705234), + (0.761905, 0.727166, 0.727166), + (0.777778, 0.748455, 0.748455), + (0.793651, 0.769156, 0.769156), + (0.809524, 0.789314, 0.789314), + (0.825397, 0.808969, 0.808969), + (0.841270, 0.828159, 0.828159), + (0.857143, 0.846913, 0.846913), + (0.873016, 0.865261, 0.865261), + (0.888889, 0.883229, 0.883229), + (0.904762, 0.900837, 0.900837), + (0.920635, 0.918109, 0.918109), + (0.936508, 0.935061, 0.935061), + (0.952381, 0.951711, 0.951711), + (0.968254, 0.968075, 0.968075), + (0.984127, 0.984167, 0.984167), (1.0, 1.0, 1.0))} + +_spring_data = {'red': ((0., 1., 1.), (1.0, 1.0, 1.0)), + 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)), + 'blue': ((0., 1., 1.), (1.0, 0.0, 0.0))} + + +_summer_data = {'red': ((0., 0., 0.), (1.0, 1.0, 1.0)), + 'green': ((0., 0.5, 0.5), (1.0, 1.0, 1.0)), + 'blue': ((0., 0.4, 0.4), (1.0, 0.4, 0.4))} + + +_winter_data = {'red': ((0., 0., 0.), (1.0, 0.0, 0.0)), + 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)), + 'blue': ((0., 1., 1.), (1.0, 0.5, 0.5))} + +_nipy_spectral_data = { + 'red': [(0.0, 0.0, 0.0), (0.05, 0.4667, 0.4667), + (0.10, 0.5333, 0.5333), (0.15, 0.0, 0.0), + (0.20, 0.0, 0.0), (0.25, 0.0, 0.0), + (0.30, 0.0, 0.0), (0.35, 0.0, 0.0), + (0.40, 0.0, 0.0), (0.45, 0.0, 0.0), + (0.50, 0.0, 0.0), (0.55, 0.0, 0.0), + (0.60, 0.0, 0.0), (0.65, 0.7333, 0.7333), + (0.70, 0.9333, 0.9333), (0.75, 1.0, 1.0), + (0.80, 1.0, 1.0), (0.85, 1.0, 1.0), + (0.90, 0.8667, 0.8667), (0.95, 0.80, 0.80), + (1.0, 0.80, 0.80)], + 'green': [(0.0, 0.0, 0.0), (0.05, 0.0, 0.0), + (0.10, 0.0, 0.0), (0.15, 0.0, 0.0), + (0.20, 0.0, 0.0), (0.25, 0.4667, 0.4667), + (0.30, 0.6000, 0.6000), (0.35, 0.6667, 0.6667), + (0.40, 0.6667, 0.6667), (0.45, 0.6000, 0.6000), + (0.50, 0.7333, 0.7333), (0.55, 0.8667, 0.8667), + (0.60, 1.0, 1.0), (0.65, 1.0, 1.0), + (0.70, 0.9333, 0.9333), (0.75, 0.8000, 0.8000), + (0.80, 0.6000, 0.6000), (0.85, 0.0, 0.0), + (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), + (1.0, 0.80, 0.80)], + 'blue': [(0.0, 0.0, 0.0), (0.05, 0.5333, 0.5333), + (0.10, 0.6000, 0.6000), (0.15, 0.6667, 0.6667), + (0.20, 0.8667, 0.8667), (0.25, 0.8667, 0.8667), + (0.30, 0.8667, 0.8667), (0.35, 0.6667, 0.6667), + (0.40, 0.5333, 0.5333), (0.45, 0.0, 0.0), + (0.5, 0.0, 0.0), (0.55, 0.0, 0.0), + (0.60, 0.0, 0.0), (0.65, 0.0, 0.0), + (0.70, 0.0, 0.0), (0.75, 0.0, 0.0), + (0.80, 0.0, 0.0), (0.85, 0.0, 0.0), + (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), + (1.0, 0.80, 0.80)], +} # 34 colormaps based on color specifications and designs @@ -1610,7 +1733,7 @@ def gfunc32(x): _gist_stern_data = { 'red': ( (0.000, 0.000, 0.000), (0.0547, 1.000, 1.000), - (0.250, 0.027, 0.250), #(0.2500, 0.250, 0.250), + (0.250, 0.027, 0.250), # (0.2500, 0.250, 0.250), (1.000, 1.000, 1.000)), 'green': ((0, 0, 0), (1, 1, 1)), 'blue': ( @@ -1733,35 +1856,36 @@ def gfunc32(x): } # Implementation of Carey Rappaport's CMRmap. -# See `A Color Map for Effective Black-and-White Rendering of Color-Scale Images' by Carey Rappaport +# See `A Color Map for Effective Black-and-White Rendering of Color-Scale +# Images' by Carey Rappaport # http://www.mathworks.com/matlabcentral/fileexchange/2662-cmrmap-m -_CMRmap_data = {'red' : ( (0.000, 0.00, 0.00), - (0.125, 0.15, 0.15), - (0.250, 0.30, 0.30), - (0.375, 0.60, 0.60), - (0.500, 1.00, 1.00), - (0.625, 0.90, 0.90), - (0.750, 0.90, 0.90), - (0.875, 0.90, 0.90), - (1.000, 1.00, 1.00) ), - 'green' : ( (0.000, 0.00, 0.00), - (0.125, 0.15, 0.15), - (0.250, 0.15, 0.15), - (0.375, 0.20, 0.20), - (0.500, 0.25, 0.25), - (0.625, 0.50, 0.50), - (0.750, 0.75, 0.75), - (0.875, 0.90, 0.90), - (1.000, 1.00, 1.00) ), - 'blue': ( (0.000, 0.00, 0.00), - (0.125, 0.50, 0.50), - (0.250, 0.75, 0.75), - (0.375, 0.50, 0.50), - (0.500, 0.15, 0.15), - (0.625, 0.00, 0.00), - (0.750, 0.10, 0.10), - (0.875, 0.50, 0.50), - (1.000, 1.00, 1.00) )} +_CMRmap_data = {'red': ((0.000, 0.00, 0.00), + (0.125, 0.15, 0.15), + (0.250, 0.30, 0.30), + (0.375, 0.60, 0.60), + (0.500, 1.00, 1.00), + (0.625, 0.90, 0.90), + (0.750, 0.90, 0.90), + (0.875, 0.90, 0.90), + (1.000, 1.00, 1.00)), + 'green': ((0.000, 0.00, 0.00), + (0.125, 0.15, 0.15), + (0.250, 0.15, 0.15), + (0.375, 0.20, 0.20), + (0.500, 0.25, 0.25), + (0.625, 0.50, 0.50), + (0.750, 0.75, 0.75), + (0.875, 0.90, 0.90), + (1.000, 1.00, 1.00)), + 'blue': ((0.000, 0.00, 0.00), + (0.125, 0.50, 0.50), + (0.250, 0.75, 0.75), + (0.375, 0.50, 0.50), + (0.500, 0.15, 0.15), + (0.625, 0.00, 0.00), + (0.750, 0.10, 0.10), + (0.875, 0.50, 0.50), + (1.000, 1.00, 1.00))} datad = { 'afmhot': _afmhot_data, @@ -1777,10 +1901,10 @@ def gfunc32(x): 'flag': _flag_data, 'gnuplot': _gnuplot_data, 'gnuplot2': _gnuplot2_data, - 'gray' : _gray_data, + 'gray': _gray_data, 'hot': _hot_data, 'hsv': _hsv_data, - 'jet' : _jet_data, + 'jet': _jet_data, 'ocean': _ocean_data, 'pink': _pink_data, 'prism': _prism_data, @@ -1790,50 +1914,51 @@ def gfunc32(x): 'summer': _summer_data, 'terrain': _terrain_data, 'winter': _winter_data, - 'spectral': _spectral_data + 'nipy_spectral': _nipy_spectral_data, + 'spectral': _nipy_spectral_data, # alias for backward compatibility } -datad['Accent']=_Accent_data -datad['Blues']=_Blues_data -datad['BrBG']=_BrBG_data -datad['BuGn']=_BuGn_data -datad['BuPu']=_BuPu_data -datad['Dark2']=_Dark2_data -datad['GnBu']=_GnBu_data -datad['Greens']=_Greens_data -datad['Greys']=_Greys_data -datad['Oranges']=_Oranges_data -datad['OrRd']=_OrRd_data -datad['Paired']=_Paired_data -datad['Pastel1']=_Pastel1_data -datad['Pastel2']=_Pastel2_data -datad['PiYG']=_PiYG_data -datad['PRGn']=_PRGn_data -datad['PuBu']=_PuBu_data -datad['PuBuGn']=_PuBuGn_data -datad['PuOr']=_PuOr_data -datad['PuRd']=_PuRd_data -datad['Purples']=_Purples_data -datad['RdBu']=_RdBu_data -datad['RdGy']=_RdGy_data -datad['RdPu']=_RdPu_data -datad['RdYlBu']=_RdYlBu_data -datad['RdYlGn']=_RdYlGn_data -datad['Reds']=_Reds_data -datad['Set1']=_Set1_data -datad['Set2']=_Set2_data -datad['Set3']=_Set3_data -datad['Spectral']=_Spectral_data -datad['YlGn']=_YlGn_data -datad['YlGnBu']=_YlGnBu_data -datad['YlOrBr']=_YlOrBr_data -datad['YlOrRd']=_YlOrRd_data -datad['gist_earth']=_gist_earth_data -datad['gist_gray']=_gist_gray_data -datad['gist_heat']=_gist_heat_data -datad['gist_ncar']=_gist_ncar_data -datad['gist_rainbow']=_gist_rainbow_data -datad['gist_stern']=_gist_stern_data -datad['gist_yarg']=_gist_yarg_data -datad['coolwarm']=_coolwarm_data +datad['Accent'] = _Accent_data +datad['Blues'] = _Blues_data +datad['BrBG'] = _BrBG_data +datad['BuGn'] = _BuGn_data +datad['BuPu'] = _BuPu_data +datad['Dark2'] = _Dark2_data +datad['GnBu'] = _GnBu_data +datad['Greens'] = _Greens_data +datad['Greys'] = _Greys_data +datad['Oranges'] = _Oranges_data +datad['OrRd'] = _OrRd_data +datad['Paired'] = _Paired_data +datad['Pastel1'] = _Pastel1_data +datad['Pastel2'] = _Pastel2_data +datad['PiYG'] = _PiYG_data +datad['PRGn'] = _PRGn_data +datad['PuBu'] = _PuBu_data +datad['PuBuGn'] = _PuBuGn_data +datad['PuOr'] = _PuOr_data +datad['PuRd'] = _PuRd_data +datad['Purples'] = _Purples_data +datad['RdBu'] = _RdBu_data +datad['RdGy'] = _RdGy_data +datad['RdPu'] = _RdPu_data +datad['RdYlBu'] = _RdYlBu_data +datad['RdYlGn'] = _RdYlGn_data +datad['Reds'] = _Reds_data +datad['Set1'] = _Set1_data +datad['Set2'] = _Set2_data +datad['Set3'] = _Set3_data +datad['Spectral'] = _Spectral_data +datad['YlGn'] = _YlGn_data +datad['YlGnBu'] = _YlGnBu_data +datad['YlOrBr'] = _YlOrBr_data +datad['YlOrRd'] = _YlOrRd_data +datad['gist_earth'] = _gist_earth_data +datad['gist_gray'] = _gist_gray_data +datad['gist_heat'] = _gist_heat_data +datad['gist_ncar'] = _gist_ncar_data +datad['gist_rainbow'] = _gist_rainbow_data +datad['gist_stern'] = _gist_stern_data +datad['gist_yarg'] = _gist_yarg_data +datad['coolwarm'] = _coolwarm_data diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index afef43f917f1..0141e207f629 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -6,7 +6,6 @@ import sys, gc import atexit -import traceback def error_msg(msg): diff --git a/lib/matplotlib/afm.py b/lib/matplotlib/afm.py index 3cff52b77079..ba14a6f7a042 100644 --- a/lib/matplotlib/afm.py +++ b/lib/matplotlib/afm.py @@ -103,7 +103,7 @@ def _parse_header(fh): """ Reads the font metrics header (up to the char metrics) and returns a dictionary mapping *key* to *val*. *val* will be converted to the - appropriate python type as necessary; eg: + appropriate python type as necessary; e.g.: * 'False'->False * '0'->0 @@ -496,18 +496,18 @@ def get_kern_dist_from_name(self, name1, name2): return 0 def get_fontname(self): - "Return the font name, eg, 'Times-Roman'" + "Return the font name, e.g., 'Times-Roman'" return self._header[b'FontName'] def get_fullname(self): - "Return the font full name, eg, 'Times-Roman'" + "Return the font full name, e.g., 'Times-Roman'" name = self._header.get(b'FullName') if name is None: # use FontName as a substitute name = self._header[b'FontName'] return name def get_familyname(self): - "Return the font family name, eg, 'Times'" + "Return the font family name, e.g., 'Times'" name = self._header.get(b'FamilyName') if name is not None: return name @@ -518,7 +518,7 @@ def get_familyname(self): return re.sub(extras, '', name) def get_weight(self): - "Return the font weight, eg, 'Bold' or 'Roman'" + "Return the font weight, e.g., 'Bold' or 'Roman'" return self._header[b'Weight'] def get_angle(self): diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index e2a2e24e2728..1d935f423920 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -20,18 +20,18 @@ import sys import itertools import contextlib -import subprocess from matplotlib.cbook import iterable, is_string_like +from matplotlib.compat import subprocess from matplotlib import verbose from matplotlib import rcParams # Other potential writing methods: -# * ImageMagick convert: convert -set delay 3 -colorspace GRAY -colors 16 -# -dispose 1 -loop 0 -scale 50% *.png Output.gif # * http://pymedia.org/ # * libmng (produces swf) python wrappers: https://github.com/libming/libming # * Wrap x264 API: -# http://stackoverflow.com/questions/2940671/how-to-encode-series-of-images-into-h264-using-x264-api-c-c + +# (http://stackoverflow.com/questions/2940671/ +# how-to-encode-series-of-images-into-h264-using-x264-api-c-c ) # A registry for available MovieWriter classes @@ -55,6 +55,9 @@ def list(self): ''' Get a list of available MovieWriters.''' return self.avail.keys() + def is_available(self, name): + return name in self.avail + def __getitem__(self, name): if not self.avail: raise RuntimeError("No MovieWriters available!") @@ -82,7 +85,7 @@ class MovieWriter(object): The format used in writing frame data, defaults to 'rgba' ''' def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None, - metadata=None): + metadata=None): ''' Construct a new MovieWriter object. @@ -186,9 +189,11 @@ def finish(self): 'Finish any processing for writing the movie.' self.cleanup() - def grab_frame(self): + def grab_frame(self, **savefig_kwargs): ''' Grab the image information from the figure and save as a movie frame. + All keyword arguments in savefig_kwargs are passed on to the 'savefig' + command that saves the figure. ''' verbose.report('MovieWriter.grab_frame: Grabbing frame.', level='debug') @@ -196,11 +201,12 @@ def grab_frame(self): # Tell the figure to save its data to the sink, using the # frame format and dpi. self.fig.savefig(self._frame_sink(), format=self.frame_format, - dpi=self.dpi) + dpi=self.dpi, **savefig_kwargs) except RuntimeError: out, err = self._proc.communicate() - verbose.report('MovieWriter -- Error running proc:\n%s\n%s' % (out, - err), level='helpful') + verbose.report('MovieWriter -- Error ' + 'running proc:\n%s\n%s' % (out, + err), level='helpful') raise def _frame_sink(self): @@ -214,10 +220,10 @@ def _args(self): def cleanup(self): 'Clean-up and collect the process used to write the movie file.' out, err = self._proc.communicate() - verbose.report('MovieWriter -- Command stdout:\n%s' % out, - level='debug') - verbose.report('MovieWriter -- Command stderr:\n%s' % err, - level='debug') + verbose.report('MovieWriter -- ' + 'Command stdout:\n%s' % out, level='debug') + verbose.report('MovieWriter -- ' + 'Command stderr:\n%s' % err, level='debug') @classmethod def bin_path(cls): @@ -235,8 +241,10 @@ def isAvailable(cls): running the commandline tool. ''' try: - subprocess.Popen(cls.bin_path(), shell=False, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.Popen(cls.bin_path(), + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) return True except OSError: return False @@ -304,7 +312,7 @@ def _frame_sink(self): self._temp_names.append(fname) verbose.report( 'FileMovieWriter.frame_sink: saving frame %d to fname=%s' % - (self._frame_counter, fname), + (self._frame_counter, fname), level='debug') self._frame_counter += 1 # Ensures each created name is 'unique' @@ -322,8 +330,8 @@ def finish(self): # the process here, rather than having an open pipe. if self._proc.returncode: raise RuntimeError('Error creating movie, return code: ' - + str(self._proc.returncode) - + ' Try running with --verbose-debug') + + str(self._proc.returncode) + + ' Try running with --verbose-debug') def cleanup(self): MovieWriter.cleanup(self) @@ -390,6 +398,25 @@ def _args(self): self._base_temp_name()] + self.output_args +# Base class of avconv information. AVConv has identical arguments to +# FFMpeg +class AVConvBase(FFMpegBase): + exec_key = 'animation.avconv_path' + args_key = 'animation.avconv_args' + + +# Combine AVConv options with pipe-based writing +@writers.register('avconv') +class AVConvWriter(AVConvBase, FFMpegWriter): + pass + + +# Combine AVConv options with file-based writing +@writers.register('avconv_file') +class AVConvFileWriter(AVConvBase, FFMpegFileWriter): + pass + + # Base class of mencoder information. Contains configuration key information # as well as arguments for controlling *output* class MencoderBase: @@ -399,7 +426,7 @@ class MencoderBase: # Mencoder only allows certain keys, other ones cause the program # to fail. allowed_metadata = ['name', 'artist', 'genre', 'subject', 'copyright', - 'srcform', 'comment'] + 'srcform', 'comment'] # Mencoder mandates using name, but 'title' works better with ffmpeg. # If we find it, just put it's value into name @@ -418,8 +445,8 @@ def output_args(self): args.extend(self.extra_args) if self.metadata: args.extend(['-info', ':'.join('%s=%s' % (k, v) - for k, v in self.metadata.items() - if k in self.allowed_metadata)]) + for k, v in self.metadata.items() + if k in self.allowed_metadata)]) return args @@ -430,9 +457,9 @@ def _args(self): # Returns the command line parameters for subprocess to use # mencoder to create a movie return [self.bin_path(), '-', '-demuxer', 'rawvideo', '-rawvideo', - ('w=%i:h=%i:' % self.frame_size + - 'fps=%i:format=%s' % (self.fps, - self.frame_format))] + self.output_args + ('w=%i:h=%i:' % self.frame_size + + 'fps=%i:format=%s' % (self.fps, + self.frame_format))] + self.output_args # Combine Mencoder options with temp file-based writing @@ -444,10 +471,45 @@ def _args(self): # Returns the command line parameters for subprocess to use # mencoder to create a movie return [self.bin_path(), - 'mf://%s*.%s' % (self.temp_prefix, self.frame_format), - '-frames', str(self._frame_counter), '-mf', - 'type=%s:fps=%d' % (self.frame_format, - self.fps)] + self.output_args + 'mf://%s*.%s' % (self.temp_prefix, self.frame_format), + '-frames', str(self._frame_counter), '-mf', + 'type=%s:fps=%d' % (self.frame_format, + self.fps)] + self.output_args + + +# Base class for animated GIFs with convert utility +class ImageMagickBase: + exec_key = 'animation.convert_path' + args_key = 'animation.convert_args' + + @property + def delay(self): + return 100. / self.fps + + @property + def output_args(self): + return [self.outfile] + + +@writers.register('imagemagick') +class ImageMagickWriter(MovieWriter, ImageMagickBase): + def _args(self): + return ([self.bin_path(), + '-size', '%ix%i' % self.frame_size, '-depth', '8', + '-delay', str(self.delay), '-loop', '0', + '%s:-' % self.frame_format] + + self.output_args) + + +@writers.register('imagemagick_file') +class ImageMagickFileWriter(FileMovieWriter, ImageMagickBase): + supported_formats = ['png', 'jpeg', 'ppm', 'tiff', 'sgi', 'bmp', + 'pbm', 'raw', 'rgba'] + + def _args(self): + return ([self.bin_path(), '-delay', str(self.delay), '-loop', '0', + '%s*.%s' % (self.temp_prefix, self.frame_format)] + + self.output_args) class Animation(object): @@ -467,7 +529,10 @@ class Animation(object): ''' def __init__(self, fig, event_source=None, blit=False): self._fig = fig - self._blit = blit + # Disables blitting for backends that don't support it. This + # allows users to request it if available, but still have a + # fallback that works if it is not. + self._blit = blit and fig.canvas.supports_blit # These are the basics of the animation. The frame sequence represents # information for each frame of the animation and depends on how the @@ -487,7 +552,7 @@ def __init__(self, fig, event_source=None, blit=False): # fire events and try to draw to a deleted figure. self._close_id = self._fig.canvas.mpl_connect('close_event', self._stop) - if blit: + if self._blit: self._setup_blit() def _start(self, *args): @@ -512,11 +577,12 @@ def _stop(self, *args): self.event_source = None def save(self, filename, writer=None, fps=None, dpi=None, codec=None, - bitrate=None, extra_args=None, metadata=None, extra_anim=None): + bitrate=None, extra_args=None, metadata=None, extra_anim=None, + savefig_kwargs=None): ''' Saves a movie file by drawing every frame. - *filename* is the output filename, eg :file:`mymovie.mp4` + *filename* is the output filename, e.g., :file:`mymovie.mp4` *writer* is either an instance of :class:`MovieWriter` or a string key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. @@ -553,7 +619,37 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, `matplotlib.Figure` instance. Also, animation frames will just be simply combined, so there should be a 1:1 correspondence between the frames from the different animations. + + *savefig_kwargs* is a dictionary containing keyword arguments to be + passed on to the 'savefig' command which is called repeatedly to save + the individual frames. This can be used to set tight bounding boxes, + for example. ''' + if savefig_kwargs is None: + savefig_kwargs = {} + + # FIXME: Using 'bbox_inches' doesn't currently work with + # writers that pipe the data to the command because this + # requires a fixed frame size (see Ryan May's reply in this + # thread: [1]). Thus we drop the 'bbox_inches' argument if it + # exists in savefig_kwargs. + # + # [1] (http://matplotlib.1069221.n5.nabble.com/ + # Animation-class-let-save-accept-kwargs-which- + # are-passed-on-to-savefig-td39627.html) + # + if 'bbox_inches' in savefig_kwargs: + if not (writer in ['ffmpeg_file', 'mencoder_file'] or + isinstance(writer, + (FFMpegFileWriter, MencoderFileWriter))): + print("Warning: discarding the 'bbox_inches' argument in " + "'savefig_kwargs' as it is only currently supported " + "with the writers 'ffmpeg_file' and 'mencoder_file' " + "(writer used: " + "'{}').".format(writer if isinstance(writer, str) + else writer.__class__.__name__)) + savefig_kwargs.pop('bbox_inches') + # Need to disconnect the first draw callback, since we'll be doing # draws. Otherwise, we'll end up starting the animation. if self._first_draw_id is not None: @@ -592,11 +688,18 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, if is_string_like(writer): if writer in writers.avail: writer = writers[writer](fps, codec, bitrate, - extra_args=extra_args, metadata=metadata) + extra_args=extra_args, + metadata=metadata) else: import warnings warnings.warn("MovieWriter %s unavailable" % writer) - writer = writers.list()[0] + + try: + writer = writers.list()[0] + except IndexError: + raise ValueError("Cannot save animation: no writers are " + "available. Please install mencoder or " + "ffmpeg to save animations.") verbose.report('Animation.save using %s' % type(writer), level='helpful') @@ -612,12 +715,12 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, for anim, d in zip(all_anim, data): #TODO: Need to see if turning off blit is really necessary anim._draw_next_frame(d, blit=False) - writer.grab_frame() + writer.grab_frame(**savefig_kwargs) # Reconnect signal for first draw if necessary if reconnect_first_draw: self._first_draw_id = self._fig.canvas.mpl_connect('draw_event', - self._start) + self._start) def _step(self, *args): ''' @@ -665,7 +768,7 @@ def _pre_draw(self, framedata, blit): def _draw_frame(self, framedata): # Performs actual drawing of the frame. raise NotImplementedError('Needs to be implemented by subclasses to' - ' actually make an animation.') + ' actually make an animation.') def _post_draw(self, framedata, blit): # After the frame is rendered, this handles the actual flushing of @@ -708,7 +811,7 @@ def _setup_blit(self): self._blit_cache = dict() self._drawn_artists = [] self._resize_id = self._fig.canvas.mpl_connect('resize_event', - self._handle_resize) + self._handle_resize) self._post_draw(None, self._blit) def _handle_resize(self, *args): @@ -730,7 +833,7 @@ def _end_redraw(self, evt): 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) + self._handle_resize) class TimedAnimation(Animation): @@ -745,7 +848,7 @@ class TimedAnimation(Animation): the animation. ''' def __init__(self, fig, interval=200, repeat_delay=None, repeat=True, - event_source=None, *args, **kwargs): + event_source=None, *args, **kwargs): # Store the timing information self._interval = interval self._repeat_delay = repeat_delay @@ -861,10 +964,13 @@ class FuncAnimation(TimedAnimation): *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. + used. This function will be called once before the first frame. + + If blit=True, *func* and *init_func* should return an iterable of + drawables to clear. ''' def __init__(self, fig, func, frames=None, init_func=None, fargs=None, - save_count=None, **kwargs): + save_count=None, **kwargs): if fargs: self._args = fargs else: diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 33fd46b8bab6..d349d616e859 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -101,6 +101,8 @@ def __init__(self): self._url = None self._gid = None self._snap = None + self._sketch = rcParams['path.sketch'] + self._path_effects = rcParams['path.effects'] def __getstate__(self): d = self.__dict__.copy() @@ -180,6 +182,15 @@ def get_axes(self): """ return self.axes + def get_window_extent(self, renderer): + """ + Get the axes bounding box in display space. + Subclasses should override for inclusion in the bounding box + "tight" calculation. Default is to return an empty bounding + box at 0, 0. + """ + return Bbox([[0, 0], [0, 0]]) + def add_callback(self, func): """ Adds a callback function that will be called whenever one of @@ -336,7 +347,7 @@ def pick(self, mouseevent): ax = getattr(a, 'axes', None) if mouseevent.inaxes is None or mouseevent.inaxes == ax: # we need to check if mouseevent.inaxes is None - # because some objects associated with an axes (eg a + # because some objects associated with an axes (e.g., a # tick label) can be outside the bounding box of the # axes and inaxes will be None a.pick(mouseevent) @@ -358,7 +369,7 @@ def set_picker(self, picker): off an event if it's data is within epsilon of the mouse event. For some artists like lines and patch collections, the artist may provide additional data to the pick event - that is generated, e.g. the indices of the data within + that is generated, e.g., the indices of the data within epsilon of the pick event * A function: if picker is callable, it is a user supplied @@ -447,6 +458,63 @@ def set_snap(self, snap): """ self._snap = snap + def get_sketch_params(self): + """ + Returns the sketch parameters for the artist. + + Returns + ------- + sketch_params : tuple or `None` + + A 3-tuple with the following elements: + + * `scale`: The amplitude of the wiggle perpendicular to the + source line. + + * `length`: The length of the wiggle along the line. + + * `randomness`: The scale factor by which the length is + shrunken or expanded. + + May return `None` if no sketch parameters were set. + """ + return self._sketch + + def set_sketch_params(self, scale=None, length=None, randomness=None): + """ + Sets the the sketch parameters. + + Parameters + ---------- + + scale : float, optional + The amplitude of the wiggle perpendicular to the source + line, in pixels. If scale is `None`, or not provided, no + sketch filter will be provided. + + length : float, optional + The length of the wiggle along the line, in pixels + (default 128.0) + + randomness : float, optional + The scale factor by which the length is shrunken or + expanded (default 16.0) + """ + if scale is None: + self._sketch = None + else: + self._sketch = (scale, length or 128.0, randomness or 16.0) + + def set_path_effects(self, path_effects): + """ + set path_effects, which should be a list of instances of + matplotlib.patheffect._Base class or its derivatives. + """ + self._path_effects = path_effects + + def get_path_effects(self): + return self._path_effects + def get_figure(self): """ Return the :class:`~matplotlib.figure.Figure` instance the @@ -663,7 +731,7 @@ def update(self, props): store = self.eventson self.eventson = False changed = False - + for k, v in props.iteritems(): func = getattr(self, 'set_' + k, None) if func is None or not callable(func): @@ -719,6 +787,8 @@ def update_from(self, other): self._clippath = other._clippath self._lod = other._lod self._label = other._label + self._sketch = other._sketch + self._path_effects = other._path_effects self.pchanged() def properties(self): @@ -743,10 +813,7 @@ def findobj(self, match=None, include_self=True): """ Find artist objects. - pyplot signature: - findobj(o=gcf(), match=None, include_self=True) - - Recursively find all :class:matplotlib.artist.Artist instances + Recursively find all :class:`~matplotlib.artist.Artist` instances contained in self. *match* can be @@ -756,14 +823,12 @@ def findobj(self, match=None, include_self=True): - function with signature ``boolean = match(artist)`` used to filter matches - - class instance: eg Line2D. Only return artists of class type. + - class instance: e.g., Line2D. Only return artists of class type. If *include_self* is True (default), include self in the list to be checked for a match. - .. plot:: mpl_examples/pylab_examples/findobj_demo.py """ - if match is None: # always return True def matchfunc(x): return True @@ -819,7 +884,7 @@ def get_aliases(self): Get a dict mapping *fullname* -> *alias* for each *alias* in the :class:`~matplotlib.artist.ArtistInspector`. - Eg., for lines:: + e.g., for lines:: {'markerfacecolor': 'mfc', 'linewidth' : 'lw', @@ -849,7 +914,7 @@ def get_valid_values(self, attr): This is done by querying the docstring of the function *set_attr* for a line that begins with ACCEPTS: - Eg., for a line linestyle, return + e.g., for a line linestyle, return "[ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'steps'`` | ``'None'`` ]" """ @@ -896,7 +961,7 @@ def _get_setters_and_targets(self): def get_setters(self): """ - Get the attribute strings with setters for object. Eg., for a line, + Get the attribute strings with setters for object. e.g., for a line, return ``['markerfacecolor', 'linewidth', ....]``. """ @@ -917,7 +982,7 @@ def aliased_name(self, s): return 'PROPNAME or alias' if *s* has an alias, else return PROPNAME. - E.g. for the line markerfacecolor property, which has an + e.g., for the line markerfacecolor property, which has an alias, return 'markerfacecolor or mfc' and for the transform property, which does not, return 'transform' """ @@ -934,7 +999,7 @@ def aliased_name_rest(self, s, target): return 'PROPNAME or alias' if *s* has an alias, else return PROPNAME formatted for ReST - E.g. for the line markerfacecolor property, which has an + e.g., for the line markerfacecolor property, which has an alias, return 'markerfacecolor or mfc' and for the transform property, which does not, return 'transform' """ @@ -1083,7 +1148,7 @@ def findobj(self, match=None): - function with signature ``boolean = match(artist)`` - - class instance: eg :class:`~matplotlib.lines.Line2D` + - class instance: e.g., :class:`~matplotlib.lines.Line2D` used to filter matches. """ @@ -1125,7 +1190,7 @@ def getp(obj, property=None): getp(obj) # get all the object properties getp(obj, 'linestyle') # get the linestyle property - *obj* is a :class:`Artist` instance, eg + *obj* is a :class:`Artist` instance, e.g., :class:`~matplotllib.lines.Line2D` or an instance of a :class:`~matplotlib.axes.Axes` or :class:`matplotlib.text.Text`. If the *property* is 'somename', this function returns @@ -1183,7 +1248,7 @@ def setp(obj, *args, **kwargs): :func:`setp` operates on a single instance or a list of instances. If you are in query mode introspecting the possible values, only the first instance in the sequence is used. When actually setting - values, all the instances will be set. E.g., suppose you have a + values, all the instances will be set. e.g., suppose you have a list of two lines, the following will make both lines thicker and red:: @@ -1197,7 +1262,7 @@ def setp(obj, *args, **kwargs): with python kwargs. For example, the following are equivalent:: >>> setp(lines, 'linewidth', 2, 'color', r') # MATLAB style - + ... >>> setp(lines, linewidth=2, color='r') # python style """ diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index cd46fdcbfb30..1980e5e9e20c 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -1,5 +1,6 @@ from __future__ import division, print_function -import math, sys, warnings, datetime +import math +import warnings from operator import itemgetter import itertools @@ -16,7 +17,7 @@ import matplotlib.collections as mcoll import matplotlib.colors as mcolors import matplotlib.contour as mcontour -import matplotlib.dates as _ # <-registers a date unit converter +import matplotlib.dates as _ # <-registers a date unit converter from matplotlib import docstring import matplotlib.font_manager as font_manager import matplotlib.image as mimage @@ -36,13 +37,13 @@ import matplotlib.ticker as mticker import matplotlib.transforms as mtransforms import matplotlib.tri as mtri -from matplotlib import MatplotlibDeprecationWarning as mplDeprecation from matplotlib.container import BarContainer, ErrorbarContainer, StemContainer iterable = cbook.iterable is_string_like = cbook.is_string_like is_sequence_of_strings = cbook.is_sequence_of_strings + def _string_to_bool(s): if not is_string_like(s): return s @@ -52,6 +53,7 @@ def _string_to_bool(s): return False raise ValueError("string argument must be either 'on' or 'off'") + def _process_plot_format(fmt): """ Process a MATLAB style color/line style format string. Return a @@ -81,26 +83,26 @@ def _process_plot_format(fmt): try: fmtint = str(int(fmt)) except ValueError: - return linestyle, marker, color # Yes + return linestyle, marker, color # Yes else: if fmt != fmtint: # user definitely doesn't want tri_down marker - return linestyle, marker, color # Yes + return linestyle, marker, color # Yes else: # ignore converted color color = None except ValueError: - pass # No, not just a color. + pass # No, not just a color. # handle the multi char special cases and strip them from the # string - if fmt.find('--')>=0: + if fmt.find('--') >= 0: linestyle = '--' fmt = fmt.replace('--', '') - if fmt.find('-.')>=0: + if fmt.find('-.') >= 0: linestyle = '-.' fmt = fmt.replace('-.', '') - if fmt.find(' ')>=0: + if fmt.find(' ') >= 0: linestyle = 'None' fmt = fmt.replace(' ', '') @@ -135,24 +137,6 @@ def _process_plot_format(fmt): return linestyle, marker, color -def set_default_color_cycle(clist): - """ - Change the default cycle of colors that will be used by the plot - command. This must be called before creating the - :class:`Axes` to which it will apply; it will - apply to all future axes. - - *clist* is a sequence of mpl color specifiers. - - See also: :meth:`~matplotlib.axes.Axes.set_color_cycle`. - - .. Note:: Deprecated 2010/01/03. - Set rcParams['axes.color_cycle'] directly. - - """ - rcParams['axes.color_cycle'] = clist - warnings.warn("Set rcParams['axes.color_cycle'] directly", mplDeprecation) - class _process_plot_var_args(object): """ @@ -187,36 +171,41 @@ def set_color_cycle(self, clist=None): 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) + 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) + 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: + yunits = kwargs.pop('runits', yunits) + + if xunits != self.axes.xaxis.units: self.axes.xaxis.set_units(xunits) - if yunits!=self.axes.yaxis.units: + + if yunits != self.axes.yaxis.units: self.axes.yaxis.set_units(yunits) - ret = self._grab_next_args(*args, **kwargs) + ret = self._grab_next_args(*args, **kwargs) return ret def set_lineprops(self, line, **kwargs): assert self.command == 'plot', 'set_lineprops only works with "plot"' for key, val in kwargs.items(): - funcName = "set_%s"%key - if not hasattr(line,funcName): - raise TypeError('There is no line property "%s"'%key) - func = getattr(line,funcName) + funcName = "set_%s" % key + if not hasattr(line, funcName): + raise TypeError('There is no line property "%s"' % key) + func = getattr(line, funcName) func(val) def set_patchprops(self, fill_poly, **kwargs): assert self.command == 'fill', 'set_patchprops only works with "fill"' for key, val in kwargs.items(): - funcName = "set_%s"%key - if not hasattr(fill_poly,funcName): - raise TypeError('There is no patch property "%s"'%key) - func = getattr(fill_poly,funcName) + funcName = "set_%s" % key + if not hasattr(fill_poly, funcName): + raise TypeError('There is no patch property "%s"' % key) + func = getattr(fill_poly, funcName) func(val) def _xy_from_xy(self, x, y): @@ -224,7 +213,7 @@ def _xy_from_xy(self, x, y): bx = self.axes.xaxis.update_units(x) by = self.axes.yaxis.update_units(y) - if self.command!='plot': + if self.command != 'plot': # the Line2D class can handle unitized data, with # support for post hoc unit changes etc. Other mpl # artists, eg Polygon which _process_plot_var_args @@ -242,7 +231,7 @@ def _xy_from_xy(self, x, y): if by: y = self.axes.convert_yunits(y) - x = np.atleast_1d(x) #like asanyarray, but converts scalar to array + x = np.atleast_1d(x) # like asanyarray, but converts scalar to array y = np.atleast_1d(y) if x.shape[0] != y.shape[0]: raise ValueError("x and y must have same first dimension") @@ -250,21 +239,21 @@ def _xy_from_xy(self, x, y): raise ValueError("x and y can be no greater than 2-D") if x.ndim == 1: - x = x[:,np.newaxis] + x = x[:, np.newaxis] if y.ndim == 1: - y = y[:,np.newaxis] + y = y[:, np.newaxis] return x, y def _makeline(self, x, y, kw, kwargs): - kw = kw.copy() # Don't modify the original kw. + kw = kw.copy() # Don't modify the original kw. if not 'color' in kw and not 'color' in kwargs.keys(): kw['color'] = self.color_cycle.next() # (can't use setdefault because it always evaluates # its second argument) seg = mlines.Line2D(x, y, - axes=self.axes, - **kw - ) + axes=self.axes, + **kw + ) self.set_lineprops(seg, **kwargs) return seg @@ -273,16 +262,14 @@ def _makefill(self, x, y, kw, kwargs): facecolor = kw['color'] except KeyError: facecolor = self.color_cycle.next() - seg = mpatches.Polygon(np.hstack( - (x[:,np.newaxis],y[:,np.newaxis])), - facecolor = facecolor, - fill=True, - closed=kw['closed'] - ) + seg = mpatches.Polygon(np.hstack((x[:, np.newaxis], + y[:, np.newaxis])), + facecolor=facecolor, + fill=True, + closed=kw['closed']) self.set_patchprops(seg, **kwargs) return seg - def _plot_args(self, tup, kwargs): ret = [] if len(tup) > 1 and is_string_like(tup[-1]): @@ -315,7 +302,7 @@ def _plot_args(self, tup, kwargs): ncx, ncy = x.shape[1], y.shape[1] for j in xrange(max(ncx, ncy)): - seg = func(x[:,j%ncx], y[:,j%ncy], kw, kwargs) + seg = func(x[:, j % ncx], y[:, j % ncy], kw, kwargs) ret.append(seg) return ret @@ -324,7 +311,7 @@ def _grab_next_args(self, *args, **kwargs): remaining = args while 1: - if len(remaining)==0: + if len(remaining) == 0: return if len(remaining) <= 3: for seg in self._plot_args(remaining, kwargs): @@ -338,7 +325,7 @@ def _grab_next_args(self, *args, **kwargs): for seg in self._plot_args(remaining[:isplit], kwargs): yield seg - remaining=remaining[isplit:] + remaining = remaining[isplit:] class Axes(martist.Artist): @@ -364,10 +351,10 @@ def __str__(self): return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds) def __init__(self, fig, rect, - axisbg = None, # defaults to rc axes.facecolor - frameon = True, - sharex=None, # use Axes instance's xaxis info - sharey=None, # use Axes instance's yaxis info + axisbg=None, # defaults to rc axes.facecolor + frameon=True, + sharex=None, # use Axes instance's xaxis info + sharey=None, # use Axes instance's yaxis info label='', xscale=None, yscale=None, @@ -423,7 +410,8 @@ def __init__(self, fig, rect, *yticklabels* sequence of strings *yticks* sequence of floats ================ ========================================= - """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} + """ % {'scale': ' | '.join( + [repr(x) for x in mscale.get_scale_names()])} martist.Artist.__init__(self) if isinstance(rect, mtransforms.Bbox): self._position = rect @@ -460,7 +448,8 @@ def __init__(self, fig, rect, # this call may differ for non-sep axes, eg polar self._init_axis() - if axisbg is None: axisbg = rcParams['axes.facecolor'] + if axisbg is None: + axisbg = rcParams['axes.facecolor'] self._axisbg = axisbg self._frameon = frameon self._axisbelow = rcParams['axes.axisbelow'] @@ -468,26 +457,25 @@ def __init__(self, fig, rect, self._rasterization_zorder = None self._hold = rcParams['axes.hold'] - self._connected = {} # a dict from events to (id, func) + self._connected = {} # a dict from events to (id, func) self.cla() # funcs used to format x and y - fall back on major formatters self.fmt_xdata = None self.fmt_ydata = None - - self.set_cursor_props((1,'k')) # set the cursor properties for axes + self.set_cursor_props((1, 'k')) # set the cursor properties for axes self._cachedRenderer = None self.set_navigate(True) self.set_navigate_mode(None) - if xscale: self.set_xscale(xscale) if yscale: self.set_yscale(yscale) - if len(kwargs): martist.setp(self, **kwargs) + if len(kwargs): + martist.setp(self, **kwargs) if self.xaxis is not None: self._xcid = self.xaxis.callbacks.connect('units finalize', @@ -531,9 +519,10 @@ def set_figure(self, fig): """ martist.Artist.set_figure(self, fig) - self.bbox = mtransforms.TransformedBbox(self._position, fig.transFigure) - #these will be updated later as data is added - self.dataLim = mtransforms.Bbox.unit() + self.bbox = mtransforms.TransformedBbox(self._position, + fig.transFigure) + # these will be updated later as data is added + self.dataLim = mtransforms.Bbox.null() self.viewLim = mtransforms.Bbox.unit() self.transScale = mtransforms.TransformWrapper( mtransforms.IdentityTransform()) @@ -561,7 +550,7 @@ def _set_lim_and_transforms(self): # Transforms the x and y axis separately by a scale factor. # It is assumed that this part will have non-linear components - # (e.g. for a log scale). + # (e.g., for a log scale). self.transScale = mtransforms.TransformWrapper( mtransforms.IdentityTransform()) @@ -576,11 +565,11 @@ def _set_lim_and_transforms(self): self.transData = self.transScale + (self.transLimits + self.transAxes) self._xaxis_transform = mtransforms.blended_transform_factory( - self.transData, self.transAxes) + self.transData, self.transAxes) self._yaxis_transform = mtransforms.blended_transform_factory( - self.transAxes, self.transData) + self.transAxes, self.transData) - def get_xaxis_transform(self,which='grid'): + def get_xaxis_transform(self, which='grid'): """ Get the transformation used for drawing x-axis labels, ticks and gridlines. The x-direction is in data coordinates and the @@ -594,12 +583,12 @@ def get_xaxis_transform(self,which='grid'): place axis elements in different locations. """ - if which=='grid': + if which == 'grid': return self._xaxis_transform - elif which=='tick1': + elif which == 'tick1': # for cartesian projection, this is bottom spine return self.spines['bottom'].get_spine_transform() - elif which=='tick2': + elif which == 'tick2': # for cartesian projection, this is top spine return self.spines['top'].get_spine_transform() else: @@ -657,7 +646,7 @@ def get_xaxis_text2_transform(self, pad_points): self.figure.dpi_scale_trans), "bottom", "center") - def get_yaxis_transform(self,which='grid'): + def get_yaxis_transform(self, which='grid'): """ Get the transformation used for drawing y-axis labels, ticks and gridlines. The x-direction is in axis coordinates and the @@ -671,12 +660,12 @@ def get_yaxis_transform(self,which='grid'): place axis elements in different locations. """ - if which=='grid': + if which == 'grid': return self._yaxis_transform - elif which=='tick1': + elif which == 'tick1': # for cartesian projection, this is bottom spine return self.spines['left'].get_spine_transform() - elif which=='tick2': + elif which == 'tick2': # for cartesian projection, this is top spine return self.spines['right'].get_spine_transform() else: @@ -705,7 +694,7 @@ def get_yaxis_text1_transform(self, pad_points): """ return (self.get_yaxis_transform(which='tick1') + mtransforms.ScaledTranslation(-1 * pad_points / 72.0, 0, - self.figure.dpi_scale_trans), + self.figure.dpi_scale_trans), "center", "right") def get_yaxis_text2_transform(self, pad_points): @@ -731,7 +720,7 @@ def get_yaxis_text2_transform(self, pad_points): """ return (self.get_yaxis_transform(which='tick2') + mtransforms.ScaledTranslation(pad_points / 72.0, 0, - self.figure.dpi_scale_trans), + self.figure.dpi_scale_trans), "center", "left") def _update_transScale(self): @@ -752,7 +741,6 @@ def get_position(self, original=False): else: return self._position.frozen() - def set_position(self, pos, which='both'): """ Set the axes position with:: @@ -795,7 +783,7 @@ def set_axes_locator(self, locator): """ set axes_locator - ACCEPT : a callable object which takes an axes instance and renderer and + ACCEPT: a callable object which takes an axes instance and renderer and returns a bbox. """ self._axes_locator = locator @@ -845,18 +833,17 @@ def _gen_axes_spines(self, locations=None, offset=0.0, units='inches'): """ return { - 'left':mspines.Spine.linear_spine(self,'left'), - 'right':mspines.Spine.linear_spine(self,'right'), - 'bottom':mspines.Spine.linear_spine(self,'bottom'), - 'top':mspines.Spine.linear_spine(self,'top'), - } + 'left': mspines.Spine.linear_spine(self, 'left'), + 'right': mspines.Spine.linear_spine(self, 'right'), + 'bottom': mspines.Spine.linear_spine(self, 'bottom'), + 'top': mspines.Spine.linear_spine(self, 'top'), } def cla(self): """Clear the current axes.""" # Note: this is called by Axes.__init__() self.xaxis.cla() self.yaxis.cla() - for name,spine in self.spines.iteritems(): + for name, spine in self.spines.iteritems(): spine.cla() self.ignore_existing_data_limits = True @@ -877,7 +864,7 @@ def cla(self): minl = self._sharex.xaxis.get_minor_locator() # This overwrites the current formatter/locator - self.xaxis.set_scale(self._sharex.xaxis.get_scale()) + self.xaxis._set_scale(self._sharex.xaxis.get_scale()) # Reset the formatter/locator self.xaxis.set_major_formatter(majf) @@ -885,7 +872,7 @@ def cla(self): self.xaxis.set_major_locator(majl) self.xaxis.set_minor_locator(minl) else: - self.xaxis.set_scale('linear') + self.xaxis._set_scale('linear') if self._sharey is not None: self.yaxis.major = self._sharey.yaxis.major @@ -900,7 +887,7 @@ def cla(self): minl = self._sharey.yaxis.get_minor_locator() # This overwrites the current formatter/locator - self.yaxis.set_scale(self._sharey.yaxis.get_scale()) + self.yaxis._set_scale(self._sharey.yaxis.get_scale()) # Reset the formatter/locator self.yaxis.set_major_formatter(majf) @@ -908,14 +895,14 @@ def cla(self): self.yaxis.set_major_locator(majl) self.yaxis.set_minor_locator(minl) else: - self.yaxis.set_scale('linear') + self.yaxis._set_scale('linear') self._autoscaleXon = True self._autoscaleYon = True - self._xmargin = 0 - self._ymargin = 0 + self._xmargin = rcParams['axes.xmargin'] + self._ymargin = rcParams['axes.ymargin'] self._tight = False - self._update_transScale() # needed? + self._update_transScale() # needed? self._get_lines = _process_plot_var_args(self) self._get_patches_for_fill = _process_plot_var_args(self, 'fill') @@ -927,27 +914,38 @@ def cla(self): self.tables = [] self.artists = [] self.images = [] - self._current_image = None # strictly for pyplot via _sci, _gci + self._current_image = None # strictly for pyplot via _sci, _gci self.legend_ = None self.collections = [] # collection.Collection instances - self.containers = [] # + self.containers = [] self.grid(self._gridOn) props = font_manager.FontProperties(size=rcParams['axes.titlesize']) - self.titleOffsetTrans = mtransforms.ScaledTranslation( 0.0, 5.0 / 72.0, self.figure.dpi_scale_trans) - self.title = mtext.Text( + self.title = mtext.Text( x=0.5, y=1.0, text='', fontproperties=props, verticalalignment='baseline', horizontalalignment='center', ) - self.title.set_transform(self.transAxes + self.titleOffsetTrans) - self.title.set_clip_box(None) + self._left_title = mtext.Text( + x=0.0, y=1.0, text='', + fontproperties=props, + verticalalignment='baseline', + horizontalalignment='left', ) + self._right_title = mtext.Text( + x=1.0, y=1.0, text='', + fontproperties=props, + verticalalignment='baseline', + horizontalalignment='right', + ) - self._set_artist_props(self.title) + for _title in (self.title, self._left_title, self._right_title): + _title.set_transform(self.transAxes + self.titleOffsetTrans) + _title.set_clip_box(None) + self._set_artist_props(_title) # the patch draws the background of the axes. we want this to # be below the other artists; the axesPatch name is @@ -968,10 +966,6 @@ def cla(self): self._shared_x_axes.clean() self._shared_y_axes.clean() - def get_frame(self): - raise AttributeError('Axes.frame was removed in favor of Axes.spines') - frame = property(get_frame) - def clear(self): """clear the axes""" self.cla() @@ -985,7 +979,6 @@ def set_color_cycle(self, clist): self._get_lines.set_color_cycle(clist) self._get_patches_for_fill.set_color_cycle(clist) - def ishold(self): """return the HOLD status of the axes""" return self._hold @@ -1010,7 +1003,6 @@ def hold(self, b=None): # turn hold off hold(False) - When hold is *True*, subsequent plot commands will be added to the current axes. When hold is *False*, the current axes and figure will be cleared on the next plot command @@ -1065,13 +1057,18 @@ def set_aspect(self, aspect, adjustable=None, anchor=None): etc. ===== ===================== + .. deprecated:: 1.2 + the option 'normal' for aspect is deprecated. Use 'auto' instead. """ - if aspect in ('normal', 'auto'): + if aspect == 'normal': + cbook.warn_deprecated( + '1.2', name='normal', alternative='auto', obj_type='aspect') self._aspect = 'auto' - elif aspect == 'equal': - self._aspect = 'equal' + + elif aspect in ('equal', 'auto'): + self._aspect = aspect else: - self._aspect = float(aspect) # raise ValueError if necessary + self._aspect = float(aspect) # raise ValueError if necessary if adjustable is not None: self.set_adjustable(adjustable) @@ -1120,7 +1117,7 @@ def set_anchor(self, anchor): self._anchor = anchor else: raise ValueError('argument must be among %s' % - ', '.join(mtransforms.Bbox.coefs.keys())) + ', '.join(mtransforms.Bbox.coefs.keys())) def get_data_ratio(self): """ @@ -1129,28 +1126,26 @@ def get_data_ratio(self): This method is intended to be overridden by new projection types. """ - xmin,xmax = self.get_xbound() - ymin,ymax = self.get_ybound() - - xsize = max(math.fabs(xmax-xmin), 1e-30) - ysize = max(math.fabs(ymax-ymin), 1e-30) + xmin, xmax = self.get_xbound() + ymin, ymax = self.get_ybound() - return ysize/xsize + xsize = max(math.fabs(xmax - xmin), 1e-30) + ysize = max(math.fabs(ymax - ymin), 1e-30) + return ysize / xsize def get_data_ratio_log(self): """ Returns the aspect ratio of the raw data in log scale. Will be used when both axis scales are in log. """ - xmin,xmax = self.get_xbound() - ymin,ymax = self.get_ybound() - - xsize = max(math.fabs(math.log10(xmax)-math.log10(xmin)), 1e-30) - ysize = max(math.fabs(math.log10(ymax)-math.log10(ymin)), 1e-30) + xmin, xmax = self.get_xbound() + ymin, ymax = self.get_ybound() - return ysize/xsize + xsize = max(math.fabs(math.log10(xmax) - math.log10(xmin)), 1e-30) + ysize = max(math.fabs(math.log10(ymax) - math.log10(ymin)), 1e-30) + return ysize / xsize def apply_aspect(self, position=None): """ @@ -1160,7 +1155,6 @@ def apply_aspect(self, position=None): if position is None: position = self.get_position(original=True) - aspect = self.get_aspect() if self.name != 'polar': @@ -1169,20 +1163,20 @@ def apply_aspect(self, position=None): aspect_scale_mode = "linear" elif xscale == "log" and yscale == "log": aspect_scale_mode = "log" - elif (xscale == "linear" and yscale == "log") or \ - (xscale == "log" and yscale == "linear"): + elif ((xscale == "linear" and yscale == "log") or + (xscale == "log" and yscale == "linear")): if aspect is not "auto": warnings.warn( - 'aspect is not supported for Axes with xscale=%s, yscale=%s' \ - % (xscale, yscale)) + 'aspect is not supported for Axes with xscale=%s, ' + 'yscale=%s' % (xscale, yscale)) aspect = "auto" - else: # some custom projections have their own scales. + else: # some custom projections have their own scales. pass else: aspect_scale_mode = "linear" if aspect == 'auto': - self.set_position( position , which='active') + self.set_position(position, which='active') return if aspect == 'equal': @@ -1198,8 +1192,8 @@ def apply_aspect(self, position=None): warnings.warn( 'shared axes: "adjustable" is being changed to "datalim"') - figW,figH = self.get_figure().get_size_inches() - fig_aspect = figH/figW + figW, figH = self.get_figure().get_size_inches() + fig_aspect = figH / figW if self._adjustable in ['box', 'box-forced']: if aspect_scale_mode == "log": box_aspect = A * self.get_data_ratio_log() @@ -1214,23 +1208,21 @@ def apply_aspect(self, position=None): # by prior use of 'box' self.set_position(position, which='active') - - xmin,xmax = self.get_xbound() - ymin,ymax = self.get_ybound() + xmin, xmax = self.get_xbound() + ymin, ymax = self.get_ybound() if aspect_scale_mode == "log": xmin, xmax = math.log10(xmin), math.log10(xmax) ymin, ymax = math.log10(ymin), math.log10(ymax) - xsize = max(math.fabs(xmax-xmin), 1e-30) - ysize = max(math.fabs(ymax-ymin), 1e-30) - + xsize = max(math.fabs(xmax - xmin), 1e-30) + ysize = max(math.fabs(ymax - ymin), 1e-30) - l,b,w,h = position.bounds - box_aspect = fig_aspect * (h/w) + l, b, w, h = position.bounds + box_aspect = fig_aspect * (h / w) data_ratio = box_aspect / A - y_expander = (data_ratio*xsize/ysize - 1.0) + y_expander = (data_ratio * xsize / ysize - 1.0) #print 'y_expander', y_expander # If y_expander > 0, the dy/dx viewLim ratio needs to increase if abs(y_expander) < 0.005: @@ -1254,7 +1246,8 @@ def apply_aspect(self, position=None): Xsize = ysize / data_ratio Xmarg = Xsize - xr Ymarg = Ysize - yr - xm = 0 # Setting these targets to, e.g., 0.05*xr does not seem to help. + xm = 0 # Setting these targets to, e.g., 0.05*xr does not seem to + # help. ym = 0 #print 'xmin, xmax, ymin, ymax', xmin, xmax, ymin, ymax #print 'xsize, Xsize, ysize, Ysize', xsize, Xsize, ysize, Ysize @@ -1277,23 +1270,23 @@ def apply_aspect(self, position=None): else: adjy = y_expander > 0 #print 'y_expander, adjy', y_expander, adjy - adjust_y = changey or adjy #(Ymarg > xmarg) + adjust_y = changey or adjy # (Ymarg > xmarg) if adjust_y: - yc = 0.5*(ymin+ymax) - y0 = yc - Ysize/2.0 - y1 = yc + Ysize/2.0 + yc = 0.5 * (ymin + ymax) + y0 = yc - Ysize / 2.0 + y1 = yc + Ysize / 2.0 if aspect_scale_mode == "log": - self.set_ybound((10.**y0, 10.**y1)) + self.set_ybound((10. ** y0, 10. ** y1)) else: self.set_ybound((y0, y1)) #print 'New y0, y1:', y0, y1 #print 'New ysize, ysize/xsize', y1-y0, (y1-y0)/xsize else: - xc = 0.5*(xmin+xmax) - x0 = xc - Xsize/2.0 - x1 = xc + Xsize/2.0 + xc = 0.5 * (xmin + xmax) + x0 = xc - Xsize / 2.0 + x1 = xc + Xsize / 2.0 if aspect_scale_mode == "log": - self.set_xbound((10.**x0, 10.**x1)) + self.set_xbound((10. ** x0, 10. ** x1)) else: self.set_xbound((x0, x1)) #print 'New x0, x1:', x0, x1 @@ -1313,21 +1306,23 @@ def axis(self, *v, **kwargs): ymin, ymax = self.get_ylim() return xmin, xmax, ymin, ymax - if len(v)==1 and is_string_like(v[0]): + if len(v) == 1 and is_string_like(v[0]): s = v[0].lower() - if s=='on': self.set_axis_on() - elif s=='off': self.set_axis_off() + if s == 'on': + self.set_axis_on() + elif s == 'off': + self.set_axis_off() elif s in ('equal', 'tight', 'scaled', 'normal', 'auto', 'image'): self.set_autoscale_on(True) self.set_aspect('auto') self.autoscale_view(tight=False) # self.apply_aspect() - if s=='equal': + if s == 'equal': self.set_aspect('equal', adjustable='datalim') elif s == 'scaled': self.set_aspect('equal', adjustable='box', anchor='C') - self.set_autoscale_on(False) # Req. by Mark Bakker - elif s=='tight': + self.set_autoscale_on(False) # Req. by Mark Bakker + elif s == 'tight': self.autoscale_view(tight=True) self.set_autoscale_on(False) elif s == 'image': @@ -1348,16 +1343,16 @@ def axis(self, *v, **kwargs): except IndexError: xmin = kwargs.get('xmin', None) xmax = kwargs.get('xmax', None) - auto = False # turn off autoscaling, unless... + auto = False # turn off autoscaling, unless... if xmin is None and xmax is None: - auto = None # leave autoscaling state alone + auto = None # leave autoscaling state alone xmin, xmax = self.set_xlim(xmin, xmax, emit=emit, auto=auto) ymin = kwargs.get('ymin', None) ymax = kwargs.get('ymax', None) - auto = False # turn off autoscaling, unless... + auto = False # turn off autoscaling, unless... if ymin is None and ymax is None: - auto = None # leave autoscaling state alone + auto = None # leave autoscaling state alone ymin, ymax = self.set_ylim(ymin, ymax, emit=emit, auto=auto) return xmin, xmax, ymin, ymax @@ -1370,21 +1365,10 @@ def axis(self, *v, **kwargs): return v - def get_child_artists(self): + def get_legend(self): """ - Return a list of artists the axes contains. - - .. deprecated:: 0.98 + Return the legend.Legend instance, or None if no legend is defined """ - raise mplDeprecation('Use get_children instead') - - def get_frame(self): - """Return the axes Rectangle frame""" - warnings.warn('use ax.patch instead', mplDeprecation) - return self.patch - - def get_legend(self): - """Return the legend.Legend instance, or None if no legend is defined""" return self.legend_ def get_images(self): @@ -1401,13 +1385,13 @@ def get_xaxis(self): def get_xgridlines(self): """Get the x grid lines as a list of Line2D instances""" - return cbook.silent_list('Line2D xgridline', self.xaxis.get_gridlines()) - + return cbook.silent_list('Line2D xgridline', + self.xaxis.get_gridlines()) def get_xticklines(self): """Get the xtick lines as a list of Line2D instances""" - return cbook.silent_list('Text xtickline', self.xaxis.get_ticklines()) - + return cbook.silent_list('Text xtickline', + self.xaxis.get_ticklines()) def get_yaxis(self): """Return the YAxis instance""" @@ -1415,11 +1399,13 @@ def get_yaxis(self): def get_ygridlines(self): """Get the y grid lines as a list of Line2D instances""" - return cbook.silent_list('Line2D ygridline', self.yaxis.get_gridlines()) + return cbook.silent_list('Line2D ygridline', + self.yaxis.get_gridlines()) def get_yticklines(self): """Get the ytick lines as a list of Line2D instances""" - return cbook.silent_list('Line2D ytickline', self.yaxis.get_ticklines()) + return cbook.silent_list('Line2D ytickline', + self.yaxis.get_ticklines()) #### Adding and tracking artists @@ -1434,7 +1420,8 @@ def _sci(self, im): "ContourSet must be in current Axes") elif im not in self.images and im not in self.collections: raise ValueError( - "Argument must be an image, collection, or ContourSet in this Axes") + "Argument must be an image, collection, or ContourSet in " + "this Axes") self._current_image = im def _gci(self): @@ -1456,7 +1443,7 @@ def has_data(self): len(self.collections) + len(self.images) + len(self.lines) + - len(self.patches))>0 + len(self.patches)) > 0 def add_artist(self, a): """ @@ -1480,15 +1467,18 @@ def add_collection(self, collection, autolim=True): """ label = collection.get_label() if not label: - collection.set_label('_collection%d'%len(self.collections)) + collection.set_label('_collection%d' % len(self.collections)) self.collections.append(collection) self._set_artist_props(collection) if collection.get_clip_path() is None: collection.set_clip_path(self.patch) - if autolim: - if collection._paths and len(collection._paths): - self.update_datalim(collection.get_datalim(self.transData)) + + if (autolim and + collection._paths is not None and + len(collection._paths) and + len(collection._offsets)): + self.update_datalim(collection.get_datalim(self.transData)) collection._remove_method = lambda h: self.collections.remove(h) return collection @@ -1512,7 +1502,9 @@ def add_line(self, line): return line def _update_line_limits(self, line): - """Figures out the data limit of the given line, updating self.dataLim.""" + """ + Figures out the data limit of the given line, updating self.dataLim. + """ path = line.get_path() if path.vertices.size == 0: return @@ -1596,7 +1588,6 @@ def _update_patch_limits(self, patch): self.update_datalim(xys, updatex=updatex, updatey=updatey) - def add_table(self, tab): """ Add a :class:`~matplotlib.tables.Table` instance to the @@ -1619,12 +1610,11 @@ def add_container(self, container): """ label = container.get_label() if not label: - container.set_label('_container%d'%len(self.containers)) + container.set_label('_container%d' % len(self.containers)) self.containers.append(container) container.set_remove_method(lambda h: self.containers.remove(h)) return container - def relim(self): """ Recompute the data limits based on current artists. @@ -1635,21 +1625,27 @@ def relim(self): # Collections are deliberately not supported (yet); see # the TODO note in artists.py. self.dataLim.ignore(True) + self.dataLim.set_points(mtransforms.Bbox.null().get_points()) self.ignore_existing_data_limits = True + for line in self.lines: self._update_line_limits(line) for p in self.patches: self._update_patch_limits(p) + def update_datalim(self, xys, updatex=True, updatey=True): - """Update the data lim bbox with seq of xy tups or equiv. 2-D array""" + """ + Update the data lim bbox with seq of xy tups or equiv. 2-D array + """ # if no data is set currently, the bbox will ignore its # limits and set the bound to be the bounds of the xydata. # Otherwise, it will compute the bounds of it's current data # and the data in xydata - if iterable(xys) and not len(xys): return + if iterable(xys) and not len(xys): + return if not ma.isMaskedArray(xys): xys = np.asarray(xys) self.dataLim.update_from_data_xy(xys, self.ignore_existing_data_limits, @@ -1657,12 +1653,15 @@ def update_datalim(self, xys, updatex=True, updatey=True): self.ignore_existing_data_limits = False def update_datalim_numerix(self, x, y): - """Update the data lim bbox with seq of xy tups""" + """ + Update the data lim bbox with seq of xy tups + """ # if no data is set currently, the bbox will ignore it's # limits and set the bound to be the bounds of the xydata. # Otherwise, it will compute the bounds of it's current data # and the data in xydata - if iterable(x) and not len(x): return + if iterable(x) and not len(x): + return self.dataLim.update_from_data(x, y, self.ignore_existing_data_limits) self.ignore_existing_data_limits = False @@ -1676,7 +1675,8 @@ def update_datalim_bounds(self, bounds): def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): """Look for unit *kwargs* and update the axis instances as necessary""" - if self.xaxis is None or self.yaxis is None: return + if self.xaxis is None or self.yaxis is None: + return #print 'processing', self.get_geometry() if xdata is not None: @@ -1693,10 +1693,10 @@ 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) + xunits = kwargs.pop('xunits', self.xaxis.units) if self.name == 'polar': - xunits = kwargs.pop( 'thetaunits', xunits ) - if xunits!=self.xaxis.units: + xunits = kwargs.pop('thetaunits', xunits) + if xunits != self.xaxis.units: #print '\tkw setting xunits', xunits self.xaxis.set_units(xunits) # If the units being set imply a different converter, @@ -1706,8 +1706,8 @@ def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): yunits = kwargs.pop('yunits', self.yaxis.units) if self.name == 'polar': - yunits = kwargs.pop( 'runits', yunits ) - if yunits!=self.yaxis.units: + yunits = kwargs.pop('runits', yunits) + if yunits != self.yaxis.units: #print '\tkw setting yunits', yunits self.yaxis.set_units(yunits) # If the units being set imply a different converter, @@ -1791,7 +1791,6 @@ def set_ymargin(self, m): raise ValueError("margin must be in range 0 to 1") self._ymargin = m - def margins(self, *args, **kw): """ Set or retrieve autoscaling margins. @@ -1849,7 +1848,6 @@ def margins(self, *args, **kw): self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley) - def set_rasterization_zorder(self, z): """ Set zorder value below which artists will be rasterized. Set @@ -1905,7 +1903,6 @@ def autoscale(self, enable=True, axis='both', tight=None): scaley = self._autoscaleYon self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley) - def autoscale_view(self, tight=None, scalex=True, scaley=True): """ Autoscale the view limits using the data limits. You can @@ -1913,17 +1910,16 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True): setting *scaley* to *False*. The autoscaling preserves any axis direction reversal that has already been done. - The data limits are not updated automatically when artist - data are changed after the artist has been added to an - Axes instance. In that case, use - :meth:`matplotlib.axes.Axes.relim` - prior to calling autoscale_view. + The data limits are not updated automatically when artist data are + changed after the artist has been added to an Axes instance. In that + case, use :meth:`matplotlib.axes.Axes.relim` prior to calling + autoscale_view. """ if tight is None: # if image data only just use the datalim - _tight = self._tight or (len(self.images)>0 and - len(self.lines)==0 and - len(self.patches)==0) + _tight = self._tight or (len(self.images) > 0 and + len(self.lines) == 0 and + len(self.patches) == 0) else: _tight = self._tight = bool(tight) @@ -1934,7 +1930,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True): x0, x1 = bb.intervalx xlocator = self.xaxis.get_major_locator() try: - # e.g. DateLocator has its own nonsingular() + # e.g., DateLocator has its own nonsingular() x0, x1 = xlocator.nonsingular(x0, x1) except AttributeError: # Default nonsingular for, e.g., MaxNLocator @@ -1977,7 +1973,8 @@ def draw(self, renderer=None, inframe=False): if renderer is None: raise RuntimeError('No renderer defined') - if not self.get_visible(): return + if not self.get_visible(): + return renderer.open_group('axes') locator = self.get_axes_locator() @@ -1987,7 +1984,6 @@ def draw(self, renderer=None, inframe=False): else: self.apply_aspect() - artists = [] artists.extend(self.collections) @@ -2003,7 +1999,10 @@ def draw(self, renderer=None, inframe=False): self.xaxis.set_zorder(2.5) self.yaxis.set_zorder(2.5) artists.extend([self.xaxis, self.yaxis]) - if not inframe: artists.append(self.title) + if not inframe: + artists.append(self.title) + artists.append(self._left_title) + artists.append(self._right_title) artists.extend(self.tables) if self.legend_ is not None: artists.append(self.legend_) @@ -2022,13 +2021,12 @@ def draw(self, renderer=None, inframe=False): # add images to dsu if the backend support compositing. # otherwise, does the manaul compositing without adding images to dsu. - if len(self.images)<=1 or renderer.option_image_nocomposite(): + if len(self.images) <= 1 or renderer.option_image_nocomposite(): dsu.extend([(im.zorder, im) for im in self.images]) _do_composite = False else: _do_composite = True - dsu.sort(key=itemgetter(0)) # rasterize artists with negative zorder @@ -2051,17 +2049,16 @@ def draw(self, renderer=None, inframe=False): # make a composite image blending alpha # list of (mimage.Image, ox, oy) - zorder_images = [(im.zorder, im) for im in self.images \ + zorder_images = [(im.zorder, im) for im in self.images if im.get_visible()] zorder_images.sort(key=lambda x: x[0]) mag = renderer.get_image_magnification() - ims = [(im.make_image(mag),0,0) for z,im in zorder_images] - + ims = [(im.make_image(mag), 0, 0, im.get_alpha()) for z, im in zorder_images] l, b, r, t = self.bbox.extents - width = mag*((round(r) + 0.5) - (round(l) - 0.5)) - height = mag*((round(t) + 0.5) - (round(b) - 0.5)) + width = mag * ((round(r) + 0.5) - (round(l) - 0.5)) + height = mag * ((round(t) + 0.5) - (round(b) - 0.5)) im = mimage.from_images(height, width, ims) @@ -2112,17 +2109,6 @@ def redraw_in_frame(self): def get_renderer_cache(self): return self._cachedRenderer - def __draw_animate(self): - # ignore for now; broken - if self._lastRenderer is None: - raise RuntimeError('You must first call ax.draw()') - dsu = [(a.zorder, a) for a in self.animated.keys()] - dsu.sort(key=lambda x: x[0]) - renderer = self._lastRenderer - renderer.blit() - for tmp, a in dsu: - a.draw(renderer) - #### Axes rectangle characteristics def get_frame_on(self): @@ -2147,7 +2133,8 @@ def get_axisbelow(self): def set_axisbelow(self, b): """ - Set whether the axis ticks and gridlines are above or below most artists + Set whether the axis ticks and gridlines are above or below most + artists ACCEPTS: [ *True* | *False* ] """ @@ -2189,9 +2176,9 @@ def grid(self, b=None, which='major', axis='both', **kwargs): b = _string_to_bool(b) if axis == 'x' or axis == 'both': - self.xaxis.grid(b, which=which, **kwargs) + self.xaxis.grid(b, which=which, **kwargs) if axis == 'y' or axis == 'both': - self.yaxis.grid(b, which=which, **kwargs) + self.yaxis.grid(b, which=which, **kwargs) def ticklabel_format(self, **kwargs): """ @@ -2240,7 +2227,7 @@ def ticklabel_format(self, **kwargs): if scilimits is not None: try: m, n = scilimits - m+n+1 # check that both are numbers + m + n + 1 # check that both are numbers except (ValueError, TypeError): raise ValueError("scilimits must be a sequence of 2 integers") if style[:3] == 'sci': @@ -2353,7 +2340,7 @@ def tick_params(self, axis='both', **kwargs): Distance in points between tick and label. *labelsize* - Tick label font size in points or as a string (e.g. 'large'). + Tick label font size in points or as a string (e.g., 'large'). *labelcolor* Tick label color; mpl color spec. @@ -2451,12 +2438,14 @@ def set_xbound(self, lower=None, upper=None): It will not change the _autoscaleXon attribute. """ if upper is None and iterable(lower): - lower,upper = lower + lower, upper = lower - old_lower,old_upper = self.get_xbound() + old_lower, old_upper = self.get_xbound() - if lower is None: lower = old_lower - if upper is None: upper = old_upper + if lower is None: + lower = old_lower + if upper is None: + upper = old_upper if self.xaxis_inverted(): if lower < upper: @@ -2527,7 +2516,7 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, **kw): raise ValueError("unrecognized kwargs: %s" % kw.keys()) if right is None and iterable(left): - left,right = left + left, right = left self._process_unit_info(xdata=(left, right)) if left is not None: @@ -2536,10 +2525,12 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, **kw): right = self.convert_xunits(right) old_left, old_right = self.get_xlim() - if left is None: left = old_left - if right is None: right = old_right + if left is None: + left = old_left + if right is None: + right = old_right - if left==right: + if left == right: warnings.warn(('Attempting to set identical left==right results\n' + 'in singular transformations; automatically expanding.\n' + 'left=%s, right=%s') % (left, right)) @@ -2582,7 +2573,7 @@ def set_xscale(self, value, **kwargs): Different kwargs are accepted, depending on the scale: %(scale_docs)s """ - self.xaxis.set_scale(value, **kwargs) + self.xaxis._set_scale(value, **kwargs) self.autoscale_view(scaley=False) self._update_transScale() @@ -2642,7 +2633,9 @@ def set_xticklabels(self, labels, fontdict=None, minor=False, **kwargs): minor=minor, **kwargs) def invert_yaxis(self): - "Invert the y-axis." + """ + Invert the y-axis. + """ bottom, top = self.get_ylim() self.set_ylim(top, bottom, auto=None) @@ -2652,7 +2645,10 @@ def yaxis_inverted(self): return top < bottom def get_ybound(self): - "Return y-axis numerical bounds in the form of lowerBound < upperBound" + """ + Return y-axis numerical bounds in the form of + ``lowerBound < upperBound`` + """ bottom, top = self.get_ylim() if bottom < top: return bottom, top @@ -2666,12 +2662,14 @@ def set_ybound(self, lower=None, upper=None): It will not change the _autoscaleYon attribute. """ if upper is None and iterable(lower): - lower,upper = lower + lower, upper = lower - old_lower,old_upper = self.get_ybound() + old_lower, old_upper = self.get_ybound() - if lower is None: lower = old_lower - if upper is None: upper = old_upper + if lower is None: + lower = old_lower + if upper is None: + upper = old_upper if self.yaxis_inverted(): if lower < upper: @@ -2742,7 +2740,7 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, **kw): raise ValueError("unrecognized kwargs: %s" % kw.keys()) if top is None and iterable(bottom): - bottom,top = bottom + bottom, top = bottom if bottom is not None: bottom = self.convert_yunits(bottom) @@ -2751,10 +2749,12 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, **kw): old_bottom, old_top = self.get_ylim() - if bottom is None: bottom = old_bottom - if top is None: top = old_top + if bottom is None: + bottom = old_bottom + if top is None: + top = old_top - if bottom==top: + if bottom == top: warnings.warn(('Attempting to set identical bottom==top results\n' + 'in singular transformations; automatically expanding.\n' + 'bottom=%s, top=%s') % (bottom, top)) @@ -2798,7 +2798,7 @@ def set_yscale(self, value, **kwargs): Different kwargs are accepted, depending on the scale: %(scale_docs)s """ - self.yaxis.set_scale(value, **kwargs) + self.yaxis._set_scale(value, **kwargs) self.autoscale_view(scalex=False) self._update_transScale() @@ -2888,7 +2888,8 @@ def format_xdata(self, x): self.fmt_xdata if it is callable, else will fall back on the xaxis major formatter """ - try: return self.fmt_xdata(x) + try: + return self.fmt_xdata(x) except TypeError: func = self.xaxis.get_major_formatter().format_data_short val = func(x) @@ -2900,10 +2901,11 @@ def format_ydata(self, y): :attr:`fmt_ydata` attribute if it is callable, else will fall back on the yaxis major formatter """ - try: return self.fmt_ydata(y) + try: + return self.fmt_ydata(y) except TypeError: func = self.yaxis.get_major_formatter().format_data_short - val = func(y) + val = func(y) return val def format_coord(self, x, y): @@ -2916,7 +2918,7 @@ def format_coord(self, x, y): ys = '???' else: ys = self.format_ydata(y) - return 'x=%s y=%s'%(xs,ys) + return 'x=%s y=%s' % (xs, ys) #### Interactive manipulation @@ -2926,7 +2928,7 @@ def can_zoom(self): """ return True - def can_pan(self) : + def can_pan(self): """ Return *True* if this axes supports any pan/zoom button functionality. """ @@ -2979,12 +2981,12 @@ def start_pan(self, x, y, button): """ self._pan_start = cbook.Bunch( - lim = self.viewLim.frozen(), - trans = self.transData.frozen(), - trans_inverse = self.transData.inverted().frozen(), - bbox = self.bbox.frozen(), - x = x, - y = y + lim=self.viewLim.frozen(), + trans=self.transData.frozen(), + trans_inverse=self.transData.inverted().frozen(), + bbox=self.bbox.frozen(), + x=x, + y=y ) def end_pan(self): @@ -3019,25 +3021,25 @@ def drag_pan(self, button, key, x, y): """ def format_deltas(key, dx, dy): - if key=='control': - if(abs(dx)>abs(dy)): + if key == 'control': + if abs(dx) > abs(dy): dy = dx else: dx = dy - elif key=='x': + elif key == 'x': dy = 0 - elif key=='y': + elif key == 'y': dx = 0 - elif key=='shift': - if 2*abs(dx) < abs(dy): - dx=0 - elif 2*abs(dy) < abs(dx): - dy=0 - elif(abs(dx)>abs(dy)): - dy=dy/abs(dy)*abs(dx) + elif key == 'shift': + if 2 * abs(dx) < abs(dy): + dx = 0 + elif 2 * abs(dy) < abs(dx): + dy = 0 + elif abs(dx) > abs(dy): + dy = dy / abs(dy) * abs(dx) else: - dx=dx/abs(dx)*abs(dy) - return (dx,dy) + dx = dx / abs(dx) * abs(dy) + return (dx, dy) p = self._pan_start dx = x - p.x @@ -3090,39 +3092,15 @@ def set_cursor_props(self, *args): ACCEPTS: a (*float*, *color*) tuple """ - if len(args)==1: + if len(args) == 1: lw, c = args[0] - elif len(args)==2: + elif len(args) == 2: lw, c = args else: raise ValueError('args must be a (linewidth, color) tuple') - c =mcolors.colorConverter.to_rgba(c) + c = mcolors.colorConverter.to_rgba(c) self._cursorProps = lw, c - def connect(self, s, func): - """ - Register observers to be notified when certain events occur. Register - with callback functions with the following signatures. The function - has the following signature:: - - func(ax) # where ax is the instance making the callback. - - The following events can be connected to: - - 'xlim_changed','ylim_changed' - - The connection id is is returned - you can use this with - disconnect to disconnect from the axes event - - """ - raise mplDeprecation('use the callbacks CallbackRegistry instance ' - 'instead') - - def disconnect(self, cid): - """disconnect from the Axes event.""" - raise mplDeprecation('use the callbacks CallbackRegistry instance ' - 'instead') - def get_children(self): """return a list of child artists""" children = [] @@ -3138,17 +3116,20 @@ def get_children(self): children.append(self.legend_) children.extend(self.collections) children.append(self.title) + children.append(self._left_title) + children.append(self._right_title) children.append(self.patch) children.extend(self.spines.itervalues()) return children - def contains(self,mouseevent): + def contains(self, mouseevent): """ Test whether the mouse event occured in the axes. Returns *True* / *False*, {} """ - if callable(self._contains): return self._contains(self,mouseevent) + if callable(self._contains): + return self._contains(self, mouseevent) return self.patch.contains(mouseevent) @@ -3170,116 +3151,89 @@ def pick(self, *args): each child artist will fire a pick event if mouseevent is over the artist and the artist has picker set """ - if len(args) > 1: - raise mplDeprecation('New pick API implemented -- ' - 'see API_CHANGES in the src distribution') martist.Artist.pick(self, args[0]) - def __pick(self, x, y, trans=None, among=None): - """ - Return the artist under point that is closest to the *x*, *y*. - If *trans* is *None*, *x*, and *y* are in window coords, - (0,0 = lower left). Otherwise, *trans* is a - :class:`~matplotlib.transforms.Transform` that specifies the - coordinate system of *x*, *y*. + ### Labelling - The selection of artists from amongst which the pick function - finds an artist can be narrowed using the optional keyword - argument *among*. If provided, this should be either a sequence - of permitted artists or a function taking an artist as its - argument and returning a true value if and only if that artist - can be selected. + def get_title(self, loc="center"): + """Get an axes title. - Note this algorithm calculates distance to the vertices of the - polygon, so if you want to pick a patch, click on the edge! - """ - # MGDTODO: Needs updating - if trans is not None: - xywin = trans.transform_point((x,y)) - else: - xywin = x,y - - def dist_points(p1, p2): - 'return the distance between two points' - x1, y1 = p1 - x2, y2 = p2 - return math.sqrt((x1-x2)**2+(y1-y2)**2) - - def dist_x_y(p1, x, y): - '*x* and *y* are arrays; return the distance to the closest point' - x1, y1 = p1 - return min(np.sqrt((x-x1)**2+(y-y1)**2)) - - def dist(a): - if isinstance(a, Text): - bbox = a.get_window_extent() - l,b,w,h = bbox.bounds - verts = (l,b), (l,b+h), (l+w,b+h), (l+w, b) - xt, yt = zip(*verts) - elif isinstance(a, Patch): - path = a.get_path() - tverts = a.get_transform().transform_path(path) - xt, yt = zip(*tverts) - elif isinstance(a, mlines.Line2D): - xdata = a.get_xdata(orig=False) - ydata = a.get_ydata(orig=False) - xt, yt = a.get_transform().numerix_x_y(xdata, ydata) - - return dist_x_y(xywin, np.asarray(xt), np.asarray(yt)) - - artists = self.lines + self.patches + self.texts - if callable(among): - artists = filter(test, artists) - elif iterable(among): - amongd = dict([(k,1) for k in among]) - artists = [a for a in artists if a in amongd] - elif among is None: - pass - else: - raise ValueError('among must be callable or iterable') - if not len(artists): return None - ds = [ (dist(a),a) for a in artists] - ds.sort() - return ds[0][1] + Get one of the three available axes titles. The available titles + are positioned above the axes in the center, flush with the left + edge, and flush with the right edge. - #### Labelling + Parameters + ---------- + loc : {'center', 'left', 'right'}, str, optional + Which title to get, defaults to 'center' + + Returns + ------- + title: str + The title text string. - def get_title(self): - """ - Get the title text string. """ - return self.title.get_text() + try: + title = {'left': self._left_title, + 'center': self.title, + 'right': self._right_title}[loc.lower()] + except KeyError: + raise ValueError("'%s' is not a valid location" % loc) + return title.get_text() @docstring.dedent_interpd - def set_title(self, label, fontdict=None, **kwargs): + def set_title(self, label, fontdict=None, loc="center", **kwargs): """ - Call signature:: + Set a title for the axes. - set_title(label, fontdict=None, **kwargs): + Set one of the three available axes titles. The available titles + are positioned above the axes in the center, flush with the left + edge, and flush with the right edge. - Set the title for the axes. + Parameters + ---------- + label : str + Text to use for the title - kwargs are Text properties: - %(Text)s + fontdict : dict + A dictionary controlling the appearance of the title text, + the default `fontdict` is:: - ACCEPTS: str + {'fontsize': rcParams['axes.titlesize'], + 'verticalalignment': 'baseline', + 'horizontalalignment': loc} - .. seealso:: + loc : {'center', 'left', 'right'}, str, optional + Which title to set, defaults to 'center' - :meth:`text` - for information on how override and the optional args work + Returns + ------- + text : :class:`~matplotlib.text.Text` + The matplotlib text instance representing the title + + Other parameters + ---------------- + Other keyword arguments are text properties, see + :class:`~matplotlib.text.Text` for a list of valid text + properties. """ + try: + title = {'left': self._left_title, + 'center': self.title, + 'right': self._right_title}[loc.lower()] + except KeyError: + raise ValueError("'%s' is not a valid location" % loc) default = { - 'fontsize':rcParams['axes.titlesize'], - 'verticalalignment' : 'baseline', - 'horizontalalignment' : 'center' + 'fontsize': rcParams['axes.titlesize'], + 'verticalalignment': 'baseline', + 'horizontalalignment': loc.lower() } - - self.title.set_text(label) - self.title.update(default) - if fontdict is not None: self.title.update(fontdict) - self.title.update(kwargs) - return self.title + title.set_text(label) + title.update(default) + if fontdict is not None: + title.update(fontdict) + title.update(kwargs) + return title def get_xlabel(self): """ @@ -3291,25 +3245,26 @@ def get_xlabel(self): @docstring.dedent_interpd def set_xlabel(self, xlabel, fontdict=None, labelpad=None, **kwargs): """ - Call signature:: - - set_xlabel(xlabel, fontdict=None, labelpad=None, **kwargs) - Set the label for the xaxis. - *labelpad* is the spacing in points between the label and the x-axis - - Valid kwargs are :class:`~matplotlib.text.Text` properties: - %(Text)s + Parameters + ---------- + xlabel : string + x label - ACCEPTS: str + labelpad : scalar, optional, default: None + spacing in points between the label and the x-axis - .. seealso:: + Other parameters + ---------------- + kwargs : `~matplotlib.text.Text` properties - :meth:`text` - for information on how override and the optional args work + See also + -------- + text : for information on how override and the optional args work """ - if labelpad is not None: self.xaxis.labelpad = labelpad + if labelpad is not None: + self.xaxis.labelpad = labelpad return self.xaxis.set_label_text(xlabel, fontdict, **kwargs) def get_ylabel(self): @@ -3322,25 +3277,27 @@ def get_ylabel(self): @docstring.dedent_interpd def set_ylabel(self, ylabel, fontdict=None, labelpad=None, **kwargs): """ - Call signature:: - - set_ylabel(ylabel, fontdict=None, labelpad=None, **kwargs) - Set the label for the yaxis - *labelpad* is the spacing in points between the label and the y-axis + Parameters + ---------- + ylabel : string + y label - Valid kwargs are :class:`~matplotlib.text.Text` properties: - %(Text)s + labelpad : scalar, optional, default: None + spacing in points between the label and the x-axis - ACCEPTS: str + Other parameters + ---------------- + kwargs : `~matplotlib.text.Text` properties - .. seealso:: + See also + -------- + text : for information on how override and the optional args work - :meth:`text` - for information on how override and the optional args work """ - if labelpad is not None: self.yaxis.labelpad = labelpad + if labelpad is not None: + self.yaxis.labelpad = labelpad return self.yaxis.set_label_text(ylabel, fontdict, **kwargs) @docstring.dedent_interpd @@ -3349,55 +3306,58 @@ def text(self, x, y, s, fontdict=None, """ Add text to the axes. - Call signature:: - - text(x, y, s, fontdict=None, **kwargs) - Add text in string *s* to axis at location *x*, *y*, data coordinates. - Keyword arguments: + Parameters + ---------- + s : string + text + + x, y : scalars + data coordinates + + fontdict : dictionary, optional, default: None + A dictionary to override the default text properties. If fontdict + is None, the defaults are determined by your rc parameters. - *fontdict*: - A dictionary to override the default text properties. - If *fontdict* is *None*, the defaults are determined by your rc - parameters. + withdash : boolean, optional, default: False + Creates a `~matplotlib.text.TextWithDash` instance instead of a + `~matplotlib.text.Text` instance. - *withdash*: [ *False* | *True* ] - Creates a :class:`~matplotlib.text.TextWithDash` instance - instead of a :class:`~matplotlib.text.Text` instance. + Other parameters + ---------------- + kwargs : `~matplotlib.text.Text` properties. + Other miscellaneous text parameters. + Examples + -------- Individual keyword arguments can be used to override any given parameter:: - text(x, y, s, fontsize=12) + >>> text(x, y, s, fontsize=12) The default transform specifies that text is in data coords, alternatively, you can specify text in axis coords (0,0 is lower-left and 1,1 is upper-right). The example below places text in the center of the axes:: - text(0.5, 0.5,'matplotlib', - horizontalalignment='center', - verticalalignment='center', - transform = ax.transAxes) + >>> text(0.5, 0.5,'matplotlib', horizontalalignment='center', + >>> verticalalignment='center', + >>> transform = ax.transAxes) - You can put a rectangular box around the text instance (eg. to - set a background color) by using the keyword *bbox*. *bbox* is - a dictionary of :class:`matplotlib.patches.Rectangle` - properties. For example:: + You can put a rectangular box around the text instance (e.g., to + set a background color) by using the keyword *bbox*. *bbox* is + a dictionary of `~matplotlib.patches.Rectangle` + properties. For example:: - text(x, y, s, bbox=dict(facecolor='red', alpha=0.5)) - - Valid kwargs are :class:`~matplotlib.text.Text` properties: - - %(Text)s + >>> text(x, y, s, bbox=dict(facecolor='red', alpha=0.5)) """ default = { - 'verticalalignment' : 'baseline', - 'horizontalalignment' : 'left', - 'transform' : self.transData, - 'clip_on' : False + 'verticalalignment': 'baseline', + 'horizontalalignment': 'left', + 'transform': self.transData, + 'clip_on': False } # At some point if we feel confident that TextWithDash @@ -3408,16 +3368,15 @@ def text(self, x, y, s, fontdict=None, # a dash to TextWithDash and dashlength. if withdash: t = mtext.TextWithDash( - x=x, y=y, text=s, - ) + x=x, y=y, text=s) else: t = mtext.Text( - x=x, y=y, text=s, - ) + x=x, y=y, text=s) self._set_artist_props(t) t.update(default) - if fontdict is not None: t.update(fontdict) + if fontdict is not None: + t.update(fontdict) t.update(kwargs) self.texts.append(t) t._remove_method = lambda h: self.texts.remove(h) @@ -3445,7 +3404,8 @@ def annotate(self, *args, **kwargs): a = mtext.Annotation(*args, **kwargs) a.set_transform(mtransforms.IdentityTransform()) self._set_artist_props(a) - if kwargs.has_key('clip_on'): a.set_clip_path(self.patch) + if kwargs.has_key('clip_on'): + a.set_clip_path(self.patch) self.texts.append(a) a._remove_method = lambda h: self.texts.remove(h) return a @@ -3464,14 +3424,14 @@ def axhline(self, y=0, xmin=0, xmax=1, **kwargs): Draw a horizontal line at *y* from *xmin* to *xmax*. With the default values of *xmin* = 0 and *xmax* = 1, this line will always span the horizontal extent of the axes, regardless of - the xlim settings, even if you change them, eg. with the + the xlim settings, even if you change them, e.g., with the :meth:`set_xlim` command. That is, the horizontal extent is in axes coords: 0=left, 0.5=middle, 1.0=right but the *y* location is in data coordinates. Return value is the :class:`~matplotlib.lines.Line2D` instance. kwargs are the same as kwargs to plot, and can be - used to control the line properties. Eg., + used to control the line properties. e.g., * draw a thick red hline at *y* = 0 that spans the xrange:: @@ -3505,13 +3465,13 @@ def axhline(self, y=0, xmin=0, xmax=1, **kwargs): # We need to strip away the units for comparison with # non-unitized bounds - self._process_unit_info( ydata=y, kwargs=kwargs ) - yy = self.convert_yunits( y ) - scaley = (yyymax) + self._process_unit_info(ydata=y, kwargs=kwargs) + yy = self.convert_yunits(y) + scaley = (yy < ymin) or (yy > ymax) trans = mtransforms.blended_transform_factory( self.transAxes, self.transData) - l = mlines.Line2D([xmin,xmax], [y,y], transform=trans, **kwargs) + l = mlines.Line2D([xmin, xmax], [y, y], transform=trans, **kwargs) self.add_line(l) self.autoscale_view(scalex=False, scaley=scaley) return l @@ -3528,14 +3488,14 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs): Draw a vertical line at *x* from *ymin* to *ymax*. With the default values of *ymin* = 0 and *ymax* = 1, this line will always span the vertical extent of the axes, regardless of the - ylim settings, even if you change them, eg. with the + ylim settings, even if you change them, e.g., with the :meth:`set_ylim` command. That is, the vertical extent is in axes coords: 0=bottom, 0.5=middle, 1.0=top but the *x* location is in data coordinates. Return value is the :class:`~matplotlib.lines.Line2D` instance. kwargs are the same as kwargs to plot, and can be - used to control the line properties. Eg., + used to control the line properties. e.g., * draw a thick red vline at *x* = 0 that spans the yrange:: @@ -3569,13 +3529,13 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs): # We need to strip away the units for comparison with # non-unitized bounds - self._process_unit_info( xdata=x, kwargs=kwargs ) - xx = self.convert_xunits( x ) - scalex = (xxxmax) + self._process_unit_info(xdata=x, kwargs=kwargs) + xx = self.convert_xunits(x) + scalex = (xx < xmin) or (xx > xmax) trans = mtransforms.blended_transform_factory( self.transData, self.transAxes) - l = mlines.Line2D([x,x], [ymin,ymax] , transform=trans, **kwargs) + l = mlines.Line2D([x, x], [ymin, ymax], transform=trans, **kwargs) self.add_line(l) self.autoscale_view(scalex=scalex, scaley=False) return l @@ -3595,7 +3555,7 @@ def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs): Draw a horizontal span (rectangle) from *ymin* to *ymax*. With the default values of *xmin* = 0 and *xmax* = 1, this always spans the xrange, regardless of the xlim settings, even - if you change them, eg. with the :meth:`set_xlim` command. + if you change them, e.g., with the :meth:`set_xlim` command. That is, the horizontal extent is in axes coords: 0=left, 0.5=middle, 1.0=right but the *y* location is in data coordinates. @@ -3623,11 +3583,11 @@ def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs): self.transAxes, self.transData) # process the unit information - self._process_unit_info( [xmin, xmax], [ymin, ymax], kwargs=kwargs ) + self._process_unit_info([xmin, xmax], [ymin, ymax], kwargs=kwargs) # first we need to strip away the units - xmin, xmax = self.convert_xunits( [xmin, xmax] ) - ymin, ymax = self.convert_yunits( [ymin, ymax] ) + xmin, xmax = self.convert_xunits([xmin, xmax]) + ymin, ymax = self.convert_yunits([ymin, ymax]) verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin) p = mpatches.Polygon(verts, **kwargs) @@ -3651,7 +3611,7 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs): Draw a vertical span (rectangle) from *xmin* to *xmax*. With the default values of *ymin* = 0 and *ymax* = 1, this always spans the yrange, regardless of the ylim settings, even if you - change them, eg. with the :meth:`set_ylim` command. That is, + change them, e.g., with the :meth:`set_ylim` command. That is, the vertical extent is in axes coords: 0=bottom, 0.5=middle, 1.0=top but the *y* location is in data coordinates. @@ -3679,11 +3639,11 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs): self.transData, self.transAxes) # process the unit information - self._process_unit_info( [xmin, xmax], [ymin, ymax], kwargs=kwargs ) + self._process_unit_info([xmin, xmax], [ymin, ymax], kwargs=kwargs) # first we need to strip away the units - xmin, xmax = self.convert_xunits( [xmin, xmax] ) - ymin, ymax = self.convert_yunits( [ymin, ymax] ) + xmin, xmax = self.convert_xunits([xmin, xmax]) + ymin, ymax = self.convert_yunits([ymin, ymax]) verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)] p = mpatches.Polygon(verts, **kwargs) @@ -3692,77 +3652,77 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs): self.autoscale_view(scaley=False) return p - @docstring.dedent def hlines(self, y, xmin, xmax, colors='k', linestyles='solid', label='', **kwargs): """ Plot horizontal lines. - call signature:: + Plot horizontal lines at each `y` from `xmin` to `xmax`. - hlines(y, xmin, xmax, colors='k', linestyles='solid', **kwargs) + Parameters + ---------- + y : scalar or 1D array_like + y-indexes where to plot the lines. - Plot horizontal lines at each *y* from *xmin* to *xmax*. + xmin, xmax : scalar or 1D array_like + Respective beginning and end of each line. If scalars are + provided, all lines will have same length. - Returns the :class:`~matplotlib.collections.LineCollection` - that was added. + colors : array_like of colors, optional, default: 'k' - Required arguments: + linestyles : ['solid' | 'dashed' | 'dashdot' | 'dotted'], optional - *y*: - a 1-D numpy array or iterable. + label : string, optional, default: '' - *xmin* and *xmax*: - can be scalars or ``len(x)`` numpy arrays. If they are - scalars, then the respective values are constant, else the - widths of the lines are determined by *xmin* and *xmax*. + Returns + ------- + lines : `~matplotlib.collections.LineCollection` - Optional keyword arguments: - - *colors*: - a line collections color argument, either a single color - or a ``len(y)`` list of colors + Other parameters + ---------------- + kwargs : `~matplotlib.collections.LineCollection` properties. - *linestyles*: - [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] + See also + -------- + vlines : vertical lines - **Example:** + Examples + -------- + .. plot:: mpl_examples/pylab_examples/vline_hline_demo.py - .. plot:: mpl_examples/pylab_examples/hline_demo.py """ - if kwargs.get('fmt') is not None: - raise mplDeprecation('hlines now uses a ' - 'collections.LineCollection and not a ' - 'list of Line2D to draw; see API_CHANGES') # We do the conversion first since not all unitized data is uniform # process the unit information - self._process_unit_info( [xmin, xmax], y, kwargs=kwargs ) - y = self.convert_yunits( y ) + self._process_unit_info([xmin, xmax], y, kwargs=kwargs) + y = self.convert_yunits(y) xmin = self.convert_xunits(xmin) xmax = self.convert_xunits(xmax) - if not iterable(y): y = [y] - if not iterable(xmin): xmin = [xmin] - if not iterable(xmax): xmax = [xmax] + if not iterable(y): + y = [y] + if not iterable(xmin): + xmin = [xmin] + if not iterable(xmax): + xmax = [xmax] y = np.asarray(y) xmin = np.asarray(xmin) xmax = np.asarray(xmax) - if len(xmin)==1: - xmin = np.resize( xmin, y.shape ) - if len(xmax)==1: - xmax = np.resize( xmax, y.shape ) + if len(xmin) == 1: + xmin = np.resize(xmin, y.shape) + if len(xmax) == 1: + xmax = np.resize(xmax, y.shape) - if len(xmin)!=len(y): + if len(xmin) != len(y): raise ValueError('xmin and y are unequal sized sequences') - if len(xmax)!=len(y): + if len(xmax) != len(y): raise ValueError('xmax and y are unequal sized sequences') - verts = [ ((thisxmin, thisy), (thisxmax, thisy)) - for thisxmin, thisxmax, thisy in zip(xmin, xmax, y)] + verts = [((thisxmin, thisy), (thisxmax, thisy)) + for thisxmin, thisxmax, thisy in zip(xmin, xmax, y)] coll = mcoll.LineCollection(verts, colors=colors, linestyles=linestyles, label=label) self.add_collection(coll) @@ -3779,7 +3739,6 @@ def hlines(self, y, xmin, xmax, colors='k', linestyles='solid', self.update_datalim(corners) self.autoscale_view() - return coll @docstring.dedent_interpd @@ -3788,62 +3747,72 @@ def vlines(self, x, ymin, ymax, colors='k', linestyles='solid', """ Plot vertical lines. - Call signature:: + Plot vertical lines at each `x` from `ymin` to `ymax`. - vlines(x, ymin, ymax, color='k', linestyles='solid') + Parameters + ---------- + x : scalar or 1D array_like + x-indexes where to plot the lines. - Plot vertical lines at each *x* from *ymin* to *ymax*. *ymin* - or *ymax* can be scalars or len(*x*) numpy arrays. If they are - scalars, then the respective values are constant, else the - heights of the lines are determined by *ymin* and *ymax*. + xmin, xmax : scalar or 1D array_like + Respective beginning and end of each line. If scalars are + provided, all lines will have same length. - *colors* : - A line collection's color args, either a single color - or a ``len(x)`` list of colors + colors : array_like of colors, optional, default: 'k' - *linestyles* : [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] + linestyles : ['solid' | 'dashed' | 'dashdot' | 'dotted'], optional - Returns the :class:`matplotlib.collections.LineCollection` - that was added. + label : string, optional, default: '' - kwargs are :class:`~matplotlib.collections.LineCollection` properties: + Returns + ------- + lines : `~matplotlib.collections.LineCollection` - %(LineCollection)s - """ + Other parameters + ---------------- + kwargs : `~matplotlib.collections.LineCollection` properties. - if kwargs.get('fmt') is not None: - raise mplDeprecation('vlines now uses a ' - 'collections.LineCollection and not a ' - 'list of Line2D to draw; see API_CHANGES') + See also + -------- + hlines : horizontal lines + + Examples + --------- + .. plot:: mpl_examples/pylab_examples/vline_hline_demo.py + + """ self._process_unit_info(xdata=x, ydata=[ymin, ymax], kwargs=kwargs) # We do the conversion first since not all unitized data is uniform - x = self.convert_xunits( x ) - ymin = self.convert_yunits( ymin ) - ymax = self.convert_yunits( ymax ) + x = self.convert_xunits(x) + ymin = self.convert_yunits(ymin) + ymax = self.convert_yunits(ymax) - if not iterable(x): x = [x] - if not iterable(ymin): ymin = [ymin] - if not iterable(ymax): ymax = [ymax] + if not iterable(x): + x = [x] + if not iterable(ymin): + ymin = [ymin] + if not iterable(ymax): + ymax = [ymax] x = np.asarray(x) ymin = np.asarray(ymin) ymax = np.asarray(ymax) - if len(ymin)==1: - ymin = np.resize( ymin, x.shape ) - if len(ymax)==1: - ymax = np.resize( ymax, x.shape ) + if len(ymin) == 1: + ymin = np.resize(ymin, x.shape) + if len(ymax) == 1: + ymax = np.resize(ymax, x.shape) - if len(ymin)!=len(x): + if len(ymin) != len(x): raise ValueError('ymin and x are unequal sized sequences') - if len(ymax)!=len(x): + if len(ymax) != len(x): raise ValueError('ymax and x are unequal sized sequences') Y = np.array([ymin, ymax]).T - verts = [ ((thisx, thisymin), (thisx, thisymax)) - for thisx, (thisymin, thisymax) in zip(x,Y)] + verts = [((thisx, thisymin), (thisx, thisymax)) + for thisx, (thisymin, thisymax) in zip(x, Y)] #print 'creating line collection' coll = mcoll.LineCollection(verts, colors=colors, linestyles=linestyles, label=label) @@ -3851,11 +3820,11 @@ def vlines(self, x, ymin, ymax, colors='k', linestyles='solid', coll.update(kwargs) if len(x) > 0: - minx = min( x ) - maxx = max( x ) + minx = min(x) + maxx = max(x) - miny = min( min(ymin), min(ymax) ) - maxy = max( max(ymin), max(ymax) ) + miny = min(min(ymin), min(ymax)) + maxy = max(max(ymin), max(ymax)) corners = (minx, miny), (maxx, maxy) self.update_datalim(corners) @@ -3863,6 +3832,175 @@ def vlines(self, x, ymin, ymax, colors='k', linestyles='solid', return coll + @docstring.dedent_interpd + def eventplot(self, positions, orientation='horizontal', lineoffsets=1, + linelengths=1, linewidths=None, colors=None, + linestyles='solid', **kwargs): + """ + Plot identical parallel lines at specific positions. + + Call signature:: + + eventplot(positions, orientation='horizontal', lineoffsets=0, + linelengths=1, linewidths=None, color =None, + linestyles='solid' + + Plot parallel lines at the given positions. positions should be a 1D + or 2D array-like object, with each row corresponding to a row or column + of lines. + + This type of plot is commonly used in neuroscience for representing + neural events, where it is commonly called a spike raster, dot raster, + or raster plot. + + However, it is useful in any situation where you wish to show the + timing or position of multiple sets of discrete events, such as the + arrival times of people to a business on each day of the month or the + date of hurricanes each year of the last century. + + *orientation* : [ 'horizonal' | 'vertical' ] + 'horizonal' : the lines will be vertical and arranged in rows + "vertical' : lines will be horizontal and arranged in columns + + *lineoffsets* : + A float or array-like containing floats. + + *linelengths* : + A float or array-like containing floats. + + *linewidths* : + A float or array-like containing floats. + + *colors* + must be a sequence of RGBA tuples (eg arbitrary color + strings, etc, not allowed) or a list of such sequences + + *linestyles* : + [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] or an array of these + values + + For linelengths, linewidths, colors, and linestyles, if only a single + value is given, that value is applied to all lines. If an array-like + is given, it must have the same length as positions, and each value + will be applied to the corresponding row or column in positions. + + Returns a list of :class:`matplotlib.collections.EventCollection` + objects that were added. + + kwargs are :class:`~matplotlib.collections.LineCollection` properties: + + %(LineCollection)s + + **Example:** + + .. plot:: mpl_examples/pylab_examples/eventplot_demo.py + """ + self._process_unit_info(xdata=positions, + ydata=[lineoffsets, linelengths], + kwargs=kwargs) + + # We do the conversion first since not all unitized data is uniform + positions = self.convert_xunits(positions) + lineoffsets = self.convert_yunits(lineoffsets) + linelengths = self.convert_yunits(linelengths) + + if not iterable(positions): + positions = [positions] + elif any(iterable(position) for position in positions): + positions = [np.asanyarray(position) for position in positions] + else: + positions = [np.asanyarray(positions)] + + if len(positions) == 0: + return [] + + if not iterable(lineoffsets): + lineoffsets = [lineoffsets] + if not iterable(linelengths): + linelengths = [linelengths] + if not iterable(linewidths): + linewidths = [linewidths] + if not iterable(colors): + colors = [colors] + if hasattr(linestyles, 'lower') or not iterable(linestyles): + linestyles = [linestyles] + + lineoffsets = np.asarray(lineoffsets) + linelengths = np.asarray(linelengths) + linewidths = np.asarray(linewidths) + + if len(lineoffsets) == 0: + lineoffsets = [None] + if len(linelengths) == 0: + linelengths = [None] + if len(linewidths) == 0: + lineoffsets = [None] + if len(linewidths) == 0: + lineoffsets = [None] + if len(colors) == 0: + colors = [None] + + if len(lineoffsets) == 1 and len(positions) != 1: + lineoffsets = np.tile(lineoffsets, len(positions)) + lineoffsets[0] = 0 + lineoffsets = np.cumsum(lineoffsets) + if len(linelengths) == 1: + linelengths = np.tile(linelengths, len(positions)) + if len(linewidths) == 1: + linewidths = np.tile(linewidths, len(positions)) + if len(colors) == 1: + colors = np.asanyarray(colors) + colors = np.tile(colors, [len(positions), 1]) + if len(linestyles) == 1: + linestyles = [linestyles] * len(positions) + + if len(lineoffsets) != len(positions): + raise ValueError('lineoffsets and positions are unequal sized ' + 'sequences') + if len(linelengths) != len(positions): + raise ValueError('linelengths and positions are unequal sized ' + 'sequences') + if len(linewidths) != len(positions): + raise ValueError('linewidths and positions are unequal sized ' + 'sequences') + if len(colors) != len(positions): + raise ValueError('colors and positions are unequal sized ' + 'sequences') + if len(linestyles) != len(positions): + raise ValueError('linestyles and positions are unequal sized ' + 'sequences') + + colls = [] + for position, lineoffset, linelength, linewidth, color, linestyle in \ + itertools.izip(positions, lineoffsets, linelengths, linewidths, + colors, linestyles): + coll = mcoll.EventCollection(position, + orientation=orientation, + lineoffset=lineoffset, + linelength=linelength, + linewidth=linewidth, + color=color, + linestyle=linestyle) + self.add_collection(coll) + coll.update(kwargs) + colls.append(coll) + + if len(positions) > 0: + minpos = min(position.min() for position in positions) + maxpos = max(position.max() for position in positions) + + minline = (lineoffsets - linelengths).min() + maxline = (lineoffsets + linelengths).max() + + if colls[0].is_horizontal(): + corners = (minpos, minline), (maxpos, maxline) + else: + corners = (minline, minpos), (maxline, maxpos) + self.update_datalim(corners) + self.autoscale_view() + + return colls + #### Basic plotting @docstring.dedent_interpd def plot(self, *args, **kwargs): @@ -3873,10 +4011,10 @@ def plot(self, *args, **kwargs): optional format string. For example, each of the following is legal:: - plot(x, y) # plot x and y using default line style and color - plot(x, y, 'bo') # plot x and y using blue circle markers - plot(y) # plot y using x as index array 0..N-1 - plot(y, 'r+') # ditto, but with red plusses + plot(x, y) # plot x and y using default line style and color + plot(x, y, 'bo') # plot x and y using blue circle markers + plot(y) # plot y using x as index array 0..N-1 + plot(y, 'r+') # ditto, but with red plusses If *x* and/or *y* is 2-dimensional, then the corresponding columns will be plotted. @@ -3989,10 +4127,11 @@ def plot(self, *args, **kwargs): whether the *x* and *y* axes are autoscaled; the default is *True*. """ - scalex = kwargs.pop( 'scalex', True) - scaley = kwargs.pop( 'scaley', True) + scalex = kwargs.pop('scalex', True) + scaley = kwargs.pop('scaley', True) - if not self._hold: self.cla() + if not self._hold: + self.cla() lines = [] for line in self._get_lines(*args, **kwargs): @@ -4010,7 +4149,8 @@ def plot_date(self, x, y, fmt='bo', tz=None, xdate=True, ydate=False, Call signature:: - plot_date(x, y, fmt='bo', tz=None, xdate=True, ydate=False, **kwargs) + plot_date(x, y, fmt='bo', tz=None, xdate=True, + ydate=False, **kwargs) Similar to the :func:`~matplotlib.pyplot.plot` command, except the *x* or *y* (or both) data is considered to be dates, and the @@ -4060,7 +4200,8 @@ def plot_date(self, x, y, fmt='bo', tz=None, xdate=True, ydate=False, floating point dates. """ - if not self._hold: self.cla() + if not self._hold: + self.cla() ret = self.plot(x, y, fmt, **kwargs) @@ -4073,7 +4214,6 @@ def plot_date(self, x, y, fmt='bo', tz=None, xdate=True, ydate=False, return ret - @docstring.dedent_interpd def loglog(self, *args, **kwargs): """ @@ -4113,7 +4253,8 @@ def loglog(self, *args, **kwargs): .. plot:: mpl_examples/pylab_examples/log_demo.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() dx = {'basex': kwargs.pop('basex', 10), 'subsx': kwargs.pop('subsx', None), @@ -4127,10 +4268,10 @@ def loglog(self, *args, **kwargs): self.set_xscale('log', **dx) self.set_yscale('log', **dy) - b = self._hold - self._hold = True # we've already processed the hold + b = self._hold + self._hold = True # we've already processed the hold l = self.plot(*args, **kwargs) - self._hold = b # restore the hold + self._hold = b # restore the hold return l @@ -4172,17 +4313,18 @@ def semilogx(self, *args, **kwargs): :meth:`loglog` For example code and figure """ - if not self._hold: self.cla() - d = {'basex': kwargs.pop( 'basex', 10), - 'subsx': kwargs.pop( 'subsx', None), + if not self._hold: + self.cla() + d = {'basex': kwargs.pop('basex', 10), + 'subsx': kwargs.pop('subsx', None), 'nonposx': kwargs.pop('nonposx', 'mask'), } self.set_xscale('log', **d) - b = self._hold - self._hold = True # we've already processed the hold + b = self._hold + self._hold = True # we've already processed the hold l = self.plot(*args, **kwargs) - self._hold = b # restore the hold + self._hold = b # restore the hold return l @docstring.dedent_interpd @@ -4223,16 +4365,17 @@ def semilogy(self, *args, **kwargs): :meth:`loglog` For example code and figure """ - if not self._hold: self.cla() + if not self._hold: + self.cla() d = {'basey': kwargs.pop('basey', 10), 'subsy': kwargs.pop('subsy', None), 'nonposy': kwargs.pop('nonposy', 'mask'), } self.set_yscale('log', **d) - b = self._hold - self._hold = True # we've already processed the hold + b = self._hold + self._hold = True # we've already processed the hold l = self.plot(*args, **kwargs) - self._hold = b # restore the hold + self._hold = b # restore the hold return l @@ -4356,7 +4499,7 @@ def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none, """ Nx = len(x) - if Nx!=len(y): + if Nx != len(y): raise ValueError('x and y must be equal length') x = detrend(np.asarray(x)) @@ -4364,17 +4507,18 @@ def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none, c = np.correlate(x, y, mode=2) - if normed: c/= np.sqrt(np.dot(x,x) * np.dot(y,y)) + if normed: + c /= np.sqrt(np.dot(x, x) * np.dot(y, y)) - if maxlags is None: maxlags = Nx - 1 + if maxlags is None: + maxlags = Nx - 1 if maxlags >= Nx or maxlags < 1: raise ValueError('maglags must be None or strictly ' - 'positive < %d'%Nx) - - lags = np.arange(-maxlags,maxlags+1) - c = c[Nx-1-maxlags:Nx+maxlags] + 'positive < %d' % Nx) + lags = np.arange(-maxlags, maxlags + 1) + c = c[Nx - 1 - maxlags:Nx + maxlags] if usevlines: a = self.vlines(lags, [0], c, **kwargs) @@ -4387,7 +4531,6 @@ def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none, b = None return lags, c, a, b - def _get_legend_handles(self, legend_handler_map=None): "return artists that will be used as handles for legend" handles_original = self.lines + self.patches + \ @@ -4402,14 +4545,13 @@ def _get_legend_handles(self, legend_handler_map=None): handles = [] for h in handles_original: - if h.get_label() == "_nolegend_": #.startswith('_'): + if h.get_label() == "_nolegend_": # .startswith('_'): continue if mlegend.Legend.get_legend_handler(handler_map, h): handles.append(h) return handles - def get_legend_handles_labels(self, legend_handler_map=None): """ Return handles and labels for legend @@ -4425,14 +4567,12 @@ def get_legend_handles_labels(self, legend_handler_map=None): labels = [] for handle in self._get_legend_handles(legend_handler_map): label = handle.get_label() - #if (label is not None and label != '' and not label.startswith('_')): if label and not label.startswith('_'): handles.append(handle) labels.append(label) return handles, labels - def legend(self, *args, **kwargs): """ Place a legend on the current axes. @@ -4476,7 +4616,7 @@ def legend(self, *args, **kwargs): or:: - legend( (line1, line2, line3), ('label1', 'label2', 'label3'), loc=2) + legend((line1, line2, line3), ('label1', 'label2', 'label3'), loc=2) The location codes are @@ -4500,7 +4640,7 @@ def legend(self, *args, **kwargs): Users can specify any arbitrary location for the legend using the *bbox_to_anchor* keyword argument. bbox_to_anchor can be an instance of BboxBase(or its derivatives) or a tuple of 2 or 4 floats. - For example, + For example:: loc = 'upper right', bbox_to_anchor = (0.5, 0.5) @@ -4513,7 +4653,6 @@ def legend(self, *args, **kwargs): The loc itslef can be a 2-tuple giving x,y of the lower-left corner of the legend in axes coords (*bbox_to_anchor* is ignored). - Keyword arguments: *prop*: [ *None* | FontProperties | dict ] @@ -4521,7 +4660,8 @@ def legend(self, *args, **kwargs): instance. If *prop* is a dictionary, a new instance will be created with *prop*. If *None*, use rc settings. - *fontsize*: [ size in points | 'xx-small' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' | 'xx-large' ] + *fontsize*: [size in points | 'xx-small' | 'x-small' | 'small' | + 'medium' | 'large' | 'x-large' | 'xx-large'] Set the font size. May be either a size string, relative to the default font size, or an absolute font size in points. This argument is only used if prop is not specified. @@ -4551,6 +4691,9 @@ def legend(self, *args, **kwargs): If *True*, draw a shadow behind legend. If *None*, use rc settings. + *framealpha*: [*None* | float] + If not None, alpha channel for legend frame. Default *None*. + *ncol* : integer number of columns. default is 1 @@ -4558,7 +4701,7 @@ def legend(self, *args, **kwargs): if mode is "expand", the legend will be horizontally expanded to fill the axes area (or *bbox_to_anchor*) - *bbox_to_anchor* : an instance of BboxBase or a tuple of 2 or 4 floats + *bbox_to_anchor*: an instance of BboxBase or a tuple of 2 or 4 floats the bbox that the legend will be anchored. *bbox_transform* : [ an instance of Transform | *None* ] @@ -4569,24 +4712,25 @@ def legend(self, *args, **kwargs): Padding and spacing between various elements use following keywords parameters. These values are measure in font-size - units. E.g., a fontsize of 10 points and a handlelength=5 + units. e.g., a fontsize of 10 points and a handlelength=5 implies a handlelength of 50 points. Values from rcParams will be used if None. - ================ ================================================================== + ================ ==================================================== Keyword Description - ================ ================================================================== + ================ ==================================================== borderpad the fractional whitespace inside the legend border labelspacing the vertical space between the legend entries handlelength the length of the legend handles handletextpad the pad between the legend handle and text borderaxespad the pad between the axes and legend border columnspacing the spacing between columns - ================ ================================================================== + ================ ==================================================== - .. Note:: Not all kinds of artist are supported by the legend command. - See LINK (FIXME) for details. + .. note:: + Not all kinds of artist are supported by the legend command. + See :ref:`plotting-guide-legend` for details. **Example:** @@ -4597,20 +4741,20 @@ def legend(self, *args, **kwargs): """ - if len(args)==0: + if len(args) == 0: handles, labels = self.get_legend_handles_labels() if len(handles) == 0: warnings.warn("No labeled objects found. " "Use label='...' kwarg on individual plots.") return None - elif len(args)==1: + elif len(args) == 1: # LABELS labels = args[0] handles = [h for h, label in zip(self._get_legend_handles(), labels)] - elif len(args)==2: + elif len(args) == 2: if is_string_like(args[1]) or isinstance(args[1], int): # LABELS, LOC labels, loc = args @@ -4621,18 +4765,16 @@ def legend(self, *args, **kwargs): # LINES, LABELS handles, labels = args - elif len(args)==3: + elif len(args) == 3: # LINES, LABELS, LOC handles, labels, loc = args kwargs['loc'] = loc else: raise TypeError('Invalid arguments to legend') - # Why do we need to call "flatten" here? -JJL # handles = cbook.flatten(handles) - self.legend_ = mlegend.Legend(self, handles, labels, **kwargs) return self.legend_ @@ -4667,82 +4809,83 @@ def step(self, x, y, *args, **kwargs): if where not in ('pre', 'post', 'mid'): raise ValueError("'where' argument to step must be " "'pre', 'post' or 'mid'") - kwargs['linestyle'] = 'steps-' + where + usr_linestyle = kwargs.pop('linestyle', '') + kwargs['linestyle'] = 'steps-' + where + usr_linestyle return self.plot(x, y, *args, **kwargs) - @docstring.dedent_interpd def bar(self, left, height, width=0.8, bottom=None, **kwargs): """ Make a bar plot. - Call signature:: - - bar(left, height, width=0.8, bottom=0, **kwargs) - Make a bar plot with rectangles bounded by: - *left*, *left* + *width*, *bottom*, *bottom* + *height* + `left`, `left` + `width`, `bottom`, `bottom` + `height` (left, right, bottom and top edges) - *left*, *height*, *width*, and *bottom* can be either scalars - or sequences + Parameters + ---------- + left : sequence of scalars + the x coordinates of the left sides of the bars - Return value is a list of - :class:`matplotlib.patches.Rectangle` instances. + height : sequence of scalars + the heights of the bars - Required arguments: + width : scalar or array-like, optional, default: 0.8 + the width(s) of the bars - ======== =============================================== - Argument Description - ======== =============================================== - *left* the x coordinates of the left sides of the bars - *height* the heights of the bars - ======== =============================================== + bottom : scalar or array-like, optional, default: None + the y coordinate(s) of the bars - Optional keyword arguments: + color : scalar or array-like, optional + the colors of the bars - =============== ========================================== - Keyword Description - =============== ========================================== - *width* the widths of the bars - *bottom* the y coordinates of the bottom edges of - the bars - *color* the colors of the bars - *edgecolor* the colors of the bar edges - *linewidth* width of bar edges; None means use default - linewidth; 0 means don't draw edges. - *xerr* if not None, will be used to generate - errorbars on the bar chart - *yerr* if not None, will be used to generate - errorbars on the bar chart - *ecolor* specifies the color of any errorbar - *capsize* (default 3) determines the length in - points of the error bar caps - *error_kw* dictionary of kwargs to be passed to - errorbar method. *ecolor* and *capsize* - may be specified here rather than as - independent kwargs. - *align* 'edge' (default) | 'center' - *orientation* 'vertical' | 'horizontal' - *log* [False|True] False (default) leaves the - orientation axis as-is; True sets it to - log scale - =============== ========================================== + edgecolor : scalar or array-like, optional + the colors of the bar edges - For vertical bars, *align* = 'edge' aligns bars by their left - edges in left, while *align* = 'center' interprets these - values as the *x* coordinates of the bar centers. For - horizontal bars, *align* = 'edge' aligns bars by their bottom - edges in bottom, while *align* = 'center' interprets these - values as the *y* coordinates of the bar centers. + linewidth : scalar or array-like, optional, default: None + width of bar edge(s). If None, use default + linewidth; If 0, don't draw edges. - The optional arguments *color*, *edgecolor*, *linewidth*, - *xerr*, and *yerr* can be either scalars or sequences of + xerr : scalar or array-like, optional, default: None + if not None, will be used to generate errorbar(s) on the bar chart + + yerr :scalar or array-like, optional, default: None + if not None, will be used to generate errorbar(s) on the bar chart + + ecolor : scalar or array-like, optional, default: None + specifies the color of errorbar(s) + + capsize : integer, optional, default: 3 + determines the length in points of the error bar caps + + error_kw : + dictionary of kwargs to be passed to errorbar method. *ecolor* and + *capsize* may be specified here rather than as independent kwargs. + + align : ['edge' | 'center'], optional, default: 'edge' + If `edge`, aligns bars by their left edges (for vertical bars) and + by their bottom edges (for horizontal bars). If `center`, interpret + the `left` argument as the coordinates of the centers of the bars. + + orientation : 'vertical' | 'horizontal', optional, default: 'vertical' + The orientation of the bars. + + log : boolean, optional, default: False + If true, sets the axis to be log scale + + Returns + ------- + :class:`matplotlib.patches.Rectangle` instances. + + Notes + ----- + The optional arguments `color`, `edgecolor`, `linewidth`, + `xerr`, and `yerr` can be either scalars or sequences of length equal to the number of bars. This enables you to use bar as the basis for stacked bar charts, or candlestick plots. - Detail: *xerr* and *yerr* are passed directly to + Detail: `xerr` and `yerr` are passed directly to :meth:`errorbar`, so they can also have shape 2xN for independent specification of lower and upper errors. @@ -4754,7 +4897,8 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): .. plot:: mpl_examples/pylab_examples/bar_stacked.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() color = kwargs.pop('color', None) edgecolor = kwargs.pop('edgecolor', None) linewidth = kwargs.pop('linewidth', None) @@ -4774,6 +4918,7 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): orientation = kwargs.pop('orientation', 'vertical') log = kwargs.pop('log', False) label = kwargs.pop('label', '') + def make_iterable(x): if not iterable(x): return [x] @@ -4831,8 +4976,8 @@ def make_iterable(x): color = [None] * nbars else: color = list(mcolors.colorConverter.to_rgba_array(color)) - if len(color) == 0: # until to_rgba_array is changed - color = [[0,0,0,0]] + if len(color) == 0: # until to_rgba_array is changed + color = [[0, 0, 0, 0]] if len(color) < nbars: color *= nbars @@ -4841,53 +4986,58 @@ def make_iterable(x): else: edgecolor = list(mcolors.colorConverter.to_rgba_array(edgecolor)) if len(edgecolor) == 0: # until to_rgba_array is changed - edgecolor = [[0,0,0,0]] + edgecolor = [[0, 0, 0, 0]] if len(edgecolor) < nbars: edgecolor *= nbars # FIXME: convert the following to proper input validation # raising ValueError; don't use assert for this. - assert len(left)==nbars, "incompatible sizes: argument 'left' must be length %d or scalar" % nbars - assert len(height)==nbars, ("incompatible sizes: argument 'height' must be length %d or scalar" % - nbars) - assert len(width)==nbars, ("incompatible sizes: argument 'width' must be length %d or scalar" % - nbars) - assert len(bottom)==nbars, ("incompatible sizes: argument 'bottom' must be length %d or scalar" % - nbars) + assert len(left) == nbars, ("incompatible sizes: argument 'left' must " + "be length %d or scalar" % nbars) + assert len(height) == nbars, ("incompatible sizes: argument 'height' " + "must be length %d or scalar" % + nbars) + assert len(width) == nbars, ("incompatible sizes: argument 'width' " + "must be length %d or scalar" % + nbars) + assert len(bottom) == nbars, ("incompatible sizes: argument 'bottom' " + "must be length %d or scalar" % + nbars) patches = [] # lets do some conversions now since some types cannot be # subtracted uniformly if self.xaxis is not None: - left = self.convert_xunits( left ) - width = self.convert_xunits( width ) + left = self.convert_xunits(left) + width = self.convert_xunits(width) if xerr is not None: - xerr = self.convert_xunits( xerr ) + xerr = self.convert_xunits(xerr) if self.yaxis is not None: - bottom = self.convert_yunits( bottom ) - height = self.convert_yunits( height ) + bottom = self.convert_yunits(bottom) + height = self.convert_yunits(height) if yerr is not None: - yerr = self.convert_yunits( yerr ) + yerr = self.convert_yunits(yerr) if align == 'edge': pass elif align == 'center': if orientation == 'vertical': - left = [left[i] - width[i]/2. for i in xrange(len(left))] + left = [left[i] - width[i] / 2. for i in xrange(len(left))] elif orientation == 'horizontal': - bottom = [bottom[i] - height[i]/2. for i in xrange(len(bottom))] + bottom = [bottom[i] - height[i] / 2. + for i in xrange(len(bottom))] else: raise ValueError('invalid alignment: %s' % align) args = zip(left, bottom, width, height, color, edgecolor, linewidth) for l, b, w, h, c, e, lw in args: - if h<0: + if h < 0: b += h h = abs(h) - if w<0: + if w < 0: l += w w = abs(w) r = mpatches.Rectangle( @@ -4904,18 +5054,18 @@ def make_iterable(x): patches.append(r) holdstate = self._hold - self.hold(True) # ensure hold is on before plotting errorbars + self.hold(True) # ensure hold is on before plotting errorbars if xerr is not None or yerr is not None: if orientation == 'vertical': # using list comps rather than arrays to preserve unit info - x = [l+0.5*w for l, w in zip(left, width)] - y = [b+h for b,h in zip(bottom, height)] + x = [l + 0.5 * w for l, w in zip(left, width)] + y = [b + h for b, h in zip(bottom, height)] elif orientation == 'horizontal': # using list comps rather than arrays to preserve unit info - x = [l+w for l,w in zip(left, width)] - y = [b+0.5*h for b,h in zip(bottom, height)] + x = [l + w for l, w in zip(left, width)] + y = [b + 0.5 * h for b, h in zip(bottom, height)] if "label" not in error_kw: error_kw["label"] = '_nolegend_' @@ -4926,14 +5076,14 @@ def make_iterable(x): else: errorbar = None - self.hold(holdstate) # restore previous hold state + self.hold(holdstate) # restore previous hold state if adjust_xlim: xmin, xmax = self.dataLim.intervalx xmin = np.amin([w for w in width if w > 0]) if xerr is not None: xmin = xmin - np.amax(xerr) - xmin = max(xmin*0.9, 1e-100) + xmin = max(xmin * 0.9, 1e-100) self.dataLim.intervalx = (xmin, xmax) if adjust_ylim: @@ -4941,7 +5091,7 @@ def make_iterable(x): ymin = np.amin([h for h in height if h > 0]) if yerr is not None: ymin = ymin - np.amax(yerr) - ymin = max(ymin*0.9, 1e-100) + ymin = max(ymin * 0.9, 1e-100) self.dataLim.intervaly = (ymin, ymax) self.autoscale_view() @@ -5019,8 +5169,8 @@ def barh(self, bottom, width, height=0.8, left=None, **kwargs): %(Rectangle)s """ - patches = self.bar(left=left, height=height, width=width, bottom=bottom, - orientation='horizontal', **kwargs) + patches = self.bar(left=left, height=height, width=width, + bottom=bottom, orientation='horizontal', **kwargs) return patches @docstring.dedent_interpd @@ -5068,13 +5218,13 @@ def broken_barh(self, xranges, yrange, **kwargs): return col - def stem(self, x, y, linefmt='b-', markerfmt='bo', basefmt='r-', - bottom=None, label=None): + def stem(self, *args, **kwargs): """ Create a stem plot. - Call signature:: + Call signatures:: + stem(y, linefmt='b-', markerfmt='bo', basefmt='r-') stem(x, y, linefmt='b-', markerfmt='bo', basefmt='r-') A stem plot plots vertical lines (using *linefmt*) at each *x* @@ -5082,11 +5232,14 @@ def stem(self, x, y, linefmt='b-', markerfmt='bo', basefmt='r-', using *markerfmt*. A horizontal line at 0 is is plotted using *basefmt*. + If no *x* values are provided, the default is (0, 1, ..., len(y) - 1) + Return value is a tuple (*markerline*, *stemlines*, *baseline*). .. seealso:: - This `document `_ + This + `document `_ for details. @@ -5094,10 +5247,42 @@ def stem(self, x, y, linefmt='b-', markerfmt='bo', basefmt='r-', .. plot:: mpl_examples/pylab_examples/stem_plot.py """ - remember_hold=self._hold - if not self._hold: self.cla() + remember_hold = self._hold + if not self._hold: + self.cla() self.hold(True) + # Assume there's at least one data array + y = np.asarray(args[0], dtype=np.float) + args = args[1:] + + # Try a second one + try: + second = np.asarray(args[0], dtype=np.float) + x, y = y, second + args = args[1:] + except (IndexError, ValueError): + # The second array doesn't make sense, or it doesn't exist + second = np.arange(len(y)) + x = second + + # Popping some defaults + try: + linefmt = kwargs.pop('linefmt', args[0]) + except IndexError: + linefmt = kwargs.pop('linefmt', 'b-') + try: + markerfmt = kwargs.pop('markerfmt', args[1]) + except IndexError: + markerfmt = kwargs.pop('markerfmt', 'bo') + try: + basefmt = kwargs.pop('basefmt', args[2]) + except IndexError: + basefmt = kwargs.pop('basefmt', 'r-') + + bottom = kwargs.pop('bottom', None) + label = kwargs.pop('label', None) + markerline, = self.plot(x, y, markerfmt, label="_nolegend_") if bottom is None: @@ -5105,11 +5290,11 @@ def stem(self, x, y, linefmt='b-', markerfmt='bo', basefmt='r-', stemlines = [] for thisx, thisy in zip(x, y): - l, = self.plot([thisx,thisx], [bottom, thisy], linefmt, + l, = self.plot([thisx, thisx], [bottom, thisy], linefmt, label="_nolegend_") stemlines.append(l) - baseline, = self.plot([np.amin(x), np.amax(x)], [bottom,bottom], + baseline, = self.plot([np.amin(x), np.amax(x)], [bottom, bottom], basefmt, label="_nolegend_") self.hold(remember_hold) @@ -5120,7 +5305,6 @@ def stem(self, x, y, linefmt='b-', markerfmt='bo', basefmt='r-', return stem_container - def pie(self, x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, radius=None): @@ -5154,9 +5338,9 @@ def pie(self, x, explode=None, labels=None, colors=None, A sequence of strings providing the labels for each wedge *autopct*: [ *None* | format string | format function ] - If not *None*, is a string or function used to label the - wedges with their numeric value. The label will be placed inside - the wedge. If it is a format string, the label will be ``fmt%pct``. + If not *None*, is a string or function used to label the wedges + with their numeric value. The label will be placed inside the + wedge. If it is a format string, the label will be ``fmt%pct``. If it is a function, it will be called. *pctdistance*: scalar @@ -5178,11 +5362,15 @@ def pie(self, x, explode=None, labels=None, colors=None, The radius of the pie, if *radius* is *None* it will be set to 1. The pie chart will probably look best if the figure and axes are - square. Eg.:: + square, or the Axes aspect is equal. e.g.:: figure(figsize=(8,8)) ax = axes([0.1, 0.1, 0.8, 0.8]) + or:: + + axes(aspect=1) + Return value: If *autopct* is *None*, return the tuple (*patches*, *texts*): @@ -5203,16 +5391,19 @@ def pie(self, x, explode=None, labels=None, colors=None, x = np.asarray(x).astype(np.float32) sx = float(x.sum()) - if sx>1: x = np.divide(x,sx) - - if labels is None: labels = ['']*len(x) - if explode is None: explode = [0]*len(x) - assert(len(x)==len(labels)) - assert(len(x)==len(explode)) - if colors is None: colors = ('b', 'g', 'r', 'c', 'm', 'y', 'k', 'w') - + if sx > 1: + x = np.divide(x, sx) + + if labels is None: + labels = [''] * len(x) + if explode is None: + explode = [0] * len(x) + assert(len(x) == len(labels)) + assert(len(x) == len(explode)) + if colors is None: + colors = ('b', 'g', 'r', 'c', 'm', 'y', 'k', 'w') - center = 0,0 + center = 0, 0 if radius is None: radius = 1 @@ -5227,15 +5418,15 @@ def pie(self, x, explode=None, labels=None, colors=None, autotexts = [] i = 0 - for frac, label, expl in cbook.safezip(x,labels, explode): + for frac, label, expl in cbook.safezip(x, labels, explode): x, y = center theta2 = theta1 + frac - thetam = 2*math.pi*0.5*(theta1+theta2) - x += expl*math.cos(thetam) - y += expl*math.sin(thetam) + thetam = 2 * math.pi * 0.5 * (theta1 + theta2) + x += expl * math.cos(thetam) + y += expl * math.sin(thetam) - w = mpatches.Wedge((x,y), radius, 360.*theta1, 360.*theta2, - facecolor=colors[i%len(colors)]) + w = mpatches.Wedge((x, y), radius, 360. * theta1, 360. * theta2, + facecolor=colors[i % len(colors)]) slices.append(w) self.add_patch(w) w.set_label(label) @@ -5247,13 +5438,12 @@ def pie(self, x, explode=None, labels=None, colors=None, shad = mpatches.Shadow(w, -0.02, -0.02, #props={'facecolor':w.get_facecolor()} ) - shad.set_zorder(0.9*w.get_zorder()) + shad.set_zorder(0.9 * w.get_zorder()) shad.set_label('_nolegend_') self.add_patch(shad) - - xt = x + labeldistance*radius*math.cos(thetam) - yt = y + labeldistance*radius*math.sin(thetam) + xt = x + labeldistance * radius * math.cos(thetam) + yt = y + labeldistance * radius * math.sin(thetam) label_alignment = xt > 0 and 'left' or 'right' t = self.text(xt, yt, label, @@ -5264,12 +5454,12 @@ def pie(self, x, explode=None, labels=None, colors=None, texts.append(t) if autopct is not None: - xt = x + pctdistance*radius*math.cos(thetam) - yt = y + pctdistance*radius*math.sin(thetam) + xt = x + pctdistance * radius * math.cos(thetam) + yt = y + pctdistance * radius * math.sin(thetam) if is_string_like(autopct): - s = autopct%(100.*frac) + s = autopct % (100. * frac) elif callable(autopct): - s = autopct(100.*frac) + s = autopct(100. * frac) else: raise TypeError( 'autopct must be callable or a format string') @@ -5279,7 +5469,6 @@ def pie(self, x, explode=None, labels=None, colors=None, verticalalignment='center') autotexts.append(t) - theta1 = theta2 i += 1 @@ -5361,9 +5550,9 @@ def errorbar(self, x, y, yerr=None, xerr=None, type as *xerr* and *yerr*. *errorevery*: positive integer - subsamples the errorbars. Eg if everyerror=5, errorbars for every - 5-th datapoint will be plotted. The data plot itself still shows - all data points. + subsamples the errorbars. e.g., if everyerror=5, errorbars for + every 5-th datapoint will be plotted. The data plot itself still + shows all data points. All other keyword arguments are passed on to the plot command for the markers. For example, this code makes big red squares with @@ -5394,15 +5583,17 @@ def errorbar(self, x, y, yerr=None, xerr=None, **Example:** - .. plot:: mpl_examples/pylab_examples/errorbar_demo.py + .. plot:: mpl_examples/statistics/errorbar_demo.py """ if errorevery < 1: - raise ValueError('errorevery has to be a strictly positive integer') + raise ValueError( + 'errorevery has to be a strictly positive integer') self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs) - if not self._hold: self.cla() + if not self._hold: + self.cla() holdstate = self._hold self._hold = True @@ -5418,28 +5609,28 @@ def errorbar(self, x, y, yerr=None, xerr=None, if xerr is not None: if not iterable(xerr): - xerr = [xerr]*len(x) + xerr = [xerr] * len(x) if yerr is not None: if not iterable(yerr): - yerr = [yerr]*len(y) + yerr = [yerr] * len(y) l0 = None if barsabove and fmt is not None: - l0, = self.plot(x,y,fmt,label="_nolegend_", **kwargs) + l0, = self.plot(x, y, fmt, label="_nolegend_", **kwargs) barcols = [] caplines = [] - lines_kw = {'label':'_nolegend_'} + lines_kw = {'label': '_nolegend_'} if elinewidth: lines_kw['linewidth'] = elinewidth else: if 'linewidth' in kwargs: - lines_kw['linewidth']=kwargs['linewidth'] + lines_kw['linewidth'] = kwargs['linewidth'] if 'lw' in kwargs: - lines_kw['lw']=kwargs['lw'] + lines_kw['lw'] = kwargs['lw'] if 'transform' in kwargs: lines_kw['transform'] = kwargs['transform'] if 'alpha' in kwargs: @@ -5449,17 +5640,24 @@ def errorbar(self, x, y, yerr=None, xerr=None, # arrays fine here, they are booleans and hence not units if not iterable(lolims): - lolims = np.asarray([lolims]*len(x), bool) - else: lolims = np.asarray(lolims, bool) + lolims = np.asarray([lolims] * len(x), bool) + else: + lolims = np.asarray(lolims, bool) - if not iterable(uplims): uplims = np.array([uplims]*len(x), bool) - else: uplims = np.asarray(uplims, bool) + if not iterable(uplims): + uplims = np.array([uplims] * len(x), bool) + else: + uplims = np.asarray(uplims, bool) - if not iterable(xlolims): xlolims = np.array([xlolims]*len(x), bool) - else: xlolims = np.asarray(xlolims, bool) + if not iterable(xlolims): + xlolims = np.array([xlolims] * len(x), bool) + else: + xlolims = np.asarray(xlolims, bool) - if not iterable(xuplims): xuplims = np.array([xuplims]*len(x), bool) - else: xuplims = np.asarray(xuplims, bool) + if not iterable(xuplims): + xuplims = np.array([xuplims] * len(x), bool) + else: + xuplims = np.asarray(xuplims, bool) everymask = np.arange(len(x)) % errorevery == 0 @@ -5468,17 +5666,16 @@ def xywhere(xs, ys, mask): return xs[mask], ys[mask] where mask is True but xs and ys are not arrays """ - assert len(xs)==len(ys) - assert len(xs)==len(mask) + assert len(xs) == len(ys) + assert len(xs) == len(mask) xs = [thisx for thisx, b in zip(xs, mask) if b] ys = [thisy for thisy, b in zip(ys, mask) if b] return xs, ys - if capsize > 0: plot_kw = { - 'ms':2*capsize, - 'label':'_nolegend_'} + 'ms': 2 * capsize, + 'label': '_nolegend_'} if capthick is not None: # 'mew' has higher priority, I believe, # if both 'mew' and 'markeredgewidth' exists. @@ -5489,9 +5686,9 @@ def xywhere(xs, ys, mask): # For backwards-compat, allow explicit setting of # 'mew' or 'markeredgewidth' to over-ride capthick. if 'markeredgewidth' in kwargs: - plot_kw['markeredgewidth']=kwargs['markeredgewidth'] + plot_kw['markeredgewidth'] = kwargs['markeredgewidth'] if 'mew' in kwargs: - plot_kw['mew']=kwargs['mew'] + plot_kw['mew'] = kwargs['mew'] if 'transform' in kwargs: plot_kw['transform'] = kwargs['transform'] if 'alpha' in kwargs: @@ -5499,25 +5696,24 @@ def xywhere(xs, ys, mask): if 'zorder' in kwargs: plot_kw['zorder'] = kwargs['zorder'] - if xerr is not None: - if (iterable(xerr) and len(xerr)==2 and + if (iterable(xerr) and len(xerr) == 2 and iterable(xerr[0]) and iterable(xerr[1])): # using list comps rather than arrays to preserve units - left = [thisx-thiserr for (thisx, thiserr) - in cbook.safezip(x,xerr[0])] - right = [thisx+thiserr for (thisx, thiserr) - in cbook.safezip(x,xerr[1])] + left = [thisx - thiserr for (thisx, thiserr) + in cbook.safezip(x, xerr[0])] + right = [thisx + thiserr for (thisx, thiserr) + in cbook.safezip(x, xerr[1])] else: # using list comps rather than arrays to preserve units - left = [thisx-thiserr for (thisx, thiserr) - in cbook.safezip(x,xerr)] - right = [thisx+thiserr for (thisx, thiserr) - in cbook.safezip(x,xerr)] + left = [thisx - thiserr for (thisx, thiserr) + in cbook.safezip(x, xerr)] + right = [thisx + thiserr for (thisx, thiserr) + in cbook.safezip(x, xerr)] yo, _ = xywhere(y, right, everymask) - lo, ro= xywhere(left, right, everymask) - barcols.append( self.hlines(yo, lo, ro, **lines_kw ) ) + lo, ro = xywhere(left, right, everymask) + barcols.append(self.hlines(yo, lo, ro, **lines_kw)) if capsize > 0: if xlolims.any(): # can't use numpy logical indexing since left and @@ -5526,75 +5722,75 @@ def xywhere(xs, ys, mask): caplines.extend( self.plot(leftlo, ylo, ls='None', - marker=mlines.CARETLEFT, **plot_kw) ) + marker=mlines.CARETLEFT, **plot_kw)) xlolims = ~xlolims leftlo, ylo = xywhere(left, y, xlolims & everymask) - caplines.extend( self.plot(leftlo, ylo, 'k|', **plot_kw) ) + caplines.extend(self.plot(leftlo, ylo, 'k|', **plot_kw)) else: leftlo, ylo = xywhere(left, y, everymask) - caplines.extend( self.plot(leftlo, ylo, 'k|', **plot_kw) ) + caplines.extend(self.plot(leftlo, ylo, 'k|', **plot_kw)) if xuplims.any(): rightup, yup = xywhere(right, y, xuplims & everymask) caplines.extend( self.plot(rightup, yup, ls='None', - marker=mlines.CARETRIGHT, **plot_kw) ) + marker=mlines.CARETRIGHT, **plot_kw)) xuplims = ~xuplims rightup, yup = xywhere(right, y, xuplims & everymask) - caplines.extend( self.plot(rightup, yup, 'k|', **plot_kw) ) + caplines.extend(self.plot(rightup, yup, 'k|', **plot_kw)) else: rightup, yup = xywhere(right, y, everymask) - caplines.extend( self.plot(rightup, yup, 'k|', **plot_kw) ) + caplines.extend(self.plot(rightup, yup, 'k|', **plot_kw)) if yerr is not None: - if (iterable(yerr) and len(yerr)==2 and + if (iterable(yerr) and len(yerr) == 2 and iterable(yerr[0]) and iterable(yerr[1])): # using list comps rather than arrays to preserve units - lower = [thisy-thiserr for (thisy, thiserr) - in cbook.safezip(y,yerr[0])] - upper = [thisy+thiserr for (thisy, thiserr) - in cbook.safezip(y,yerr[1])] + lower = [thisy - thiserr for (thisy, thiserr) + in cbook.safezip(y, yerr[0])] + upper = [thisy + thiserr for (thisy, thiserr) + in cbook.safezip(y, yerr[1])] else: # using list comps rather than arrays to preserve units - lower = [thisy-thiserr for (thisy, thiserr) - in cbook.safezip(y,yerr)] - upper = [thisy+thiserr for (thisy, thiserr) - in cbook.safezip(y,yerr)] + lower = [thisy - thiserr for (thisy, thiserr) + in cbook.safezip(y, yerr)] + upper = [thisy + thiserr for (thisy, thiserr) + in cbook.safezip(y, yerr)] xo, _ = xywhere(x, lower, everymask) - lo, uo= xywhere(lower, upper, everymask) - barcols.append( self.vlines(xo, lo, uo, **lines_kw) ) + lo, uo = xywhere(lower, upper, everymask) + barcols.append(self.vlines(xo, lo, uo, **lines_kw)) if capsize > 0: if lolims.any(): xlo, lowerlo = xywhere(x, lower, lolims & everymask) caplines.extend( self.plot(xlo, lowerlo, ls='None', - marker=mlines.CARETDOWN, **plot_kw) ) + marker=mlines.CARETDOWN, **plot_kw)) lolims = ~lolims xlo, lowerlo = xywhere(x, lower, lolims & everymask) - caplines.extend( self.plot(xlo, lowerlo, 'k_', **plot_kw) ) + caplines.extend(self.plot(xlo, lowerlo, 'k_', **plot_kw)) else: xlo, lowerlo = xywhere(x, lower, everymask) - caplines.extend( self.plot(xlo, lowerlo, 'k_', **plot_kw) ) + caplines.extend(self.plot(xlo, lowerlo, 'k_', **plot_kw)) if uplims.any(): xup, upperup = xywhere(x, upper, uplims & everymask) caplines.extend( self.plot(xup, upperup, ls='None', - marker=mlines.CARETUP, **plot_kw) ) + marker=mlines.CARETUP, **plot_kw)) uplims = ~uplims xup, upperup = xywhere(x, upper, uplims & everymask) - caplines.extend( self.plot(xup, upperup, 'k_', **plot_kw) ) + caplines.extend(self.plot(xup, upperup, 'k_', **plot_kw)) else: xup, upperup = xywhere(x, upper, everymask) - caplines.extend( self.plot(xup, upperup, 'k_', **plot_kw) ) + caplines.extend(self.plot(xup, upperup, 'k_', **plot_kw)) if not barsabove and fmt is not None: - l0, = self.plot(x,y,fmt,**kwargs) + l0, = self.plot(x, y, fmt, **kwargs) if ecolor is None: if l0 is None: @@ -5610,13 +5806,14 @@ def xywhere(xs, ys, mask): self.autoscale_view() self._hold = holdstate - errorbar_container = ErrorbarContainer((l0, tuple(caplines), tuple(barcols)), + errorbar_container = ErrorbarContainer((l0, tuple(caplines), + tuple(barcols)), has_xerr=(xerr is not None), has_yerr=(yerr is not None), label=label) self.containers.append(errorbar_container) - return errorbar_container # (l0, caplines, barcols) + return errorbar_container # (l0, caplines, barcols) def boxplot(self, x, notch=False, sym='b+', vert=True, whis=1.5, positions=None, widths=None, patch_artist=False, @@ -5679,9 +5876,9 @@ def boxplot(self, x, notch=False, sym='b+', vert=True, whis=1.5, Array or sequence whose first dimension (or length) is compatible with *x* and whose second dimension is 2. When the current element of *conf_intervals* is not None, the notch locations computed by - matplotlib are overridden (assuming notch is True). When an element of - *conf_intervals* is None, boxplot compute notches the method - specified by the other kwargs (e.g. *bootstrap*). + matplotlib are overridden (assuming notch is True). When an + element of *conf_intervals* is None, boxplot compute notches the + method specified by the other kwargs (e.g., *bootstrap*). *positions* : [ default 1,2,...,n ] Sets the horizontal positions of the boxes. The ticks and limits @@ -5717,10 +5914,10 @@ def boxplot(self, x, notch=False, sym='b+', vert=True, whis=1.5, def bootstrapMedian(data, N=5000): # determine 95% confidence intervals of the median M = len(data) - percentile = [2.5,97.5] + percentile = [2.5, 97.5] estimate = np.zeros(N) for n in range(N): - bsIndex = np.random.random_integers(0,M-1,M) + bsIndex = np.random.random_integers(0, M - 1, M) bsData = data[bsIndex] estimate[n] = mlab.prctile(bsData, 50) CI = mlab.prctile(estimate, percentile) @@ -5741,11 +5938,12 @@ def computeConfInterval(data, med, iq, bootstrap): # and Larsen, W.A. (1978) "Variations of # Boxplots", The American Statistician, 32:12-16. N = len(data) - notch_min = med - 1.57*iq/np.sqrt(N) - notch_max = med + 1.57*iq/np.sqrt(N) + notch_min = med - 1.57 * iq / np.sqrt(N) + notch_max = med + 1.57 * iq / np.sqrt(N) return notch_min, notch_max - if not self._hold: self.cla() + if not self._hold: + self.cla() holdStatus = self._hold whiskers, caps, boxes, medians, fliers = [], [], [], [], [] @@ -5755,7 +5953,7 @@ def computeConfInterval(data, med, iq, bootstrap): if hasattr(x[0], 'shape'): x = list(x) else: - x = [x,] + x = [x, ] elif len(x.shape) == 2: nr, nc = x.shape if nr == 1: @@ -5763,7 +5961,7 @@ def computeConfInterval(data, med, iq, bootstrap): elif nc == 1: x = [x.ravel()] else: - x = [x[:,i] for i in xrange(nc)] + x = [x[:, i] for i in xrange(nc)] else: raise ValueError("input x can have no more than 2 dimensions") if not hasattr(x[0], '__len__'): @@ -5801,13 +5999,12 @@ def computeConfInterval(data, med, iq, bootstrap): if ci is not None and len(ci) != 2: raise ValueError(msg3) - # get some plot info if positions is None: positions = range(1, col + 1) if widths is None: distance = max(positions) - min(positions) - widths = min(0.15*max(distance,1.0), 0.5) + widths = min(0.15 * max(distance, 1.0), 0.5) if isinstance(widths, float) or isinstance(widths, int): widths = np.ones((col,), float) * widths @@ -5816,12 +6013,12 @@ def computeConfInterval(data, med, iq, bootstrap): for i, pos in enumerate(positions): d = np.ravel(x[i]) row = len(d) - if row==0: + if row == 0: # no data, skip this position continue # get median and quartiles - q1, med, q3 = mlab.prctile(d,[25,50,75]) + q1, med, q3 = mlab.prctile(d, [25, 50, 75]) # replace with input medians if available if usermedians is not None: @@ -5830,27 +6027,29 @@ def computeConfInterval(data, med, iq, bootstrap): # get high extreme iq = q3 - q1 - hi_val = q3 + whis*iq - wisk_hi = np.compress( d <= hi_val , d ) - if len(wisk_hi) == 0: + hi_val = q3 + whis * iq + wisk_hi = np.compress(d <= hi_val, d) + if len(wisk_hi) == 0 or np.max(wisk_hi) < q3: wisk_hi = q3 else: wisk_hi = max(wisk_hi) + # get low extreme - lo_val = q1 - whis*iq - wisk_lo = np.compress( d >= lo_val, d ) - if len(wisk_lo) == 0: + lo_val = q1 - whis * iq + wisk_lo = np.compress(d >= lo_val, d) + if len(wisk_lo) == 0 or np.min(wisk_lo) > q1: wisk_lo = q1 else: wisk_lo = min(wisk_lo) + # get fliers - if we are showing them flier_hi = [] flier_lo = [] flier_hi_x = [] flier_lo_x = [] if len(sym) != 0: - flier_hi = np.compress( d > wisk_hi, d ) - flier_lo = np.compress( d < wisk_lo, d ) + flier_hi = np.compress(d > wisk_hi, d) + flier_lo = np.compress(d < wisk_lo, d) flier_hi_x = np.ones(flier_hi.shape[0]) * pos flier_lo_x = np.ones(flier_lo.shape[0]) * pos @@ -5870,7 +6069,8 @@ def computeConfInterval(data, med, iq, bootstrap): # calculate 'notch' plot if notch: # conf. intervals from user, if available - if conf_intervals is not None and conf_intervals[i] is not None: + if (conf_intervals is not None and + conf_intervals[i] is not None): notch_max = np.max(conf_intervals[i]) notch_min = np.min(conf_intervals[i]) else: @@ -5880,7 +6080,7 @@ def computeConfInterval(data, med, iq, bootstrap): # make our notched box vectors box_x = [box_x_min, box_x_max, box_x_max, cap_x_max, box_x_max, box_x_max, box_x_min, box_x_min, cap_x_min, box_x_min, - box_x_min ] + box_x_min] box_y = [q1, q1, notch_min, med, notch_max, q3, q3, notch_max, med, notch_min, q1] # make our median line vectors @@ -5889,45 +6089,49 @@ def computeConfInterval(data, med, iq, bootstrap): # calculate 'regular' plot else: # make our box vectors - box_x = [box_x_min, box_x_max, box_x_max, box_x_min, box_x_min ] - box_y = [q1, q1, q3, q3, q1 ] + box_x = [box_x_min, box_x_max, box_x_max, box_x_min, box_x_min] + box_y = [q1, q1, q3, q3, q1] # make our median line vectors med_x = [box_x_min, box_x_max] - def to_vc(xs,ys): + def to_vc(xs, ys): # convert arguments to verts and codes verts = [] #codes = [] - for xi,yi in zip(xs,ys): - verts.append( (xi,yi) ) - verts.append( (0,0) ) # ignored + for xi, yi in zip(xs, ys): + verts.append((xi, yi)) + verts.append((0, 0)) # ignored codes = [mpath.Path.MOVETO] + \ - [mpath.Path.LINETO]*(len(verts)-2) + \ + [mpath.Path.LINETO] * (len(verts) - 2) + \ [mpath.Path.CLOSEPOLY] - return verts,codes + return verts, codes - def patch_list(xs,ys): - verts,codes = to_vc(xs,ys) - path = mpath.Path( verts, codes ) + def patch_list(xs, ys): + verts, codes = to_vc(xs, ys) + path = mpath.Path(verts, codes) patch = mpatches.PathPatch(path) self.add_artist(patch) return [patch] # vertical or horizontal plot? if vert: + def doplot(*args): return self.plot(*args) - def dopatch(xs,ys): - return patch_list(xs,ys) + + def dopatch(xs, ys): + return patch_list(xs, ys) else: + def doplot(*args): shuffled = [] for i in xrange(0, len(args), 3): - shuffled.extend([args[i+1], args[i], args[i+2]]) + shuffled.extend([args[i + 1], args[i], args[i + 2]]) return self.plot(*shuffled) - def dopatch(xs,ys): - xs,ys = ys,xs # flip X, Y - return patch_list(xs,ys) + + def dopatch(xs, ys): + xs, ys = ys, xs # flip X, Y + return patch_list(xs, ys) if patch_artist: median_color = 'k' @@ -5943,7 +6147,7 @@ def dopatch(xs,ys): else: boxes.extend(doplot(box_x, box_y, 'b-')) - medians.extend(doplot(med_x, med_y, median_color+'-')) + medians.extend(doplot(med_x, med_y, median_color + '-')) fliers.extend(doplot(flier_hi_x, flier_hi, sym, flier_lo_x, flier_lo, sym)) @@ -5953,7 +6157,7 @@ def dopatch(xs,ys): else: setticks, setlim = self.set_yticks, self.set_ylim - newlimits = min(positions)-0.5, max(positions)+0.5 + newlimits = min(positions) - 0.5, max(positions) + 0.5 setlim(newlimits) setticks(positions) @@ -5965,96 +6169,80 @@ def dopatch(xs,ys): @docstring.dedent_interpd def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, - vmin=None, vmax=None, alpha=None, linewidths=None, - faceted=True, verts=None, - **kwargs): - """ - Make a scatter plot. - - Call signatures:: - - scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None, - vmin=None, vmax=None, alpha=None, linewidths=None, - verts=None, **kwargs) - - Make a scatter plot of *x* versus *y*, where *x*, *y* are - converted to 1-D sequences which must be of the same length, *N*. - - Keyword arguments: - - *s*: - size in points^2. It is a scalar or an array of the same - length as *x* and *y*. + vmin=None, vmax=None, alpha=None, linewidths=None, + verts=None, **kwargs): + """ + Make a scatter plot of x vs y, where x and y are sequence like objects + of the same lengths. + + Parameters + ---------- + x, y : array_like, shape (n, ) + Input data + + s : scalar or array_like, shape (n, ), optional, default: 20 + size in points^2. + + c : color or sequence of color, optional, default : 'b' + `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. + + marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o' + See `~matplotlib.markers` for more information on the different + styles of markers scatter supports. + + cmap : `~matplotlib.colors.Colormap`, optional, default: None + A `~matplotlib.colors.Colormap` instance or registered name. + `cmap` is only used if `c` is an array of floats. If None, + defaults to rc `image.cmap`. + + norm : `~matplotlib.colors.Normalize`, optional, default: None + A `~matplotlib.colors.Normalize` instance is used to scale + luminance data to 0, 1. `norm` is only used if `c` is an array of + floats. If `None`, use the default :func:`normalize`. + + vmin, vmax : scalar, optional, default: None + `vmin` and `vmax` are used in conjunction with `norm` to normalize + luminance data. If either are `None`, the min and max of the + color array is used. Note if you pass a `norm` instance, your + settings for `vmin` and `vmax` will be ignored. + + alpha : scalar, optional, default: None + The alpha blending value, between 0 (transparent) and 1 (opaque) - *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. + linewidths : scalar or array_like, optional, default: None + If None, defaults to (lines.linewidth,). Note that this is a + tuple, and if you set the linewidths argument you must set it as a + sequence of floats, as required by + `~matplotlib.collections.RegularPolyCollection`. - *marker*: - can be one of: + Returns + ------- + paths : `~matplotlib.collections.PathCollection` - %(MarkerTable)s + Other parameters + ---------------- + kwargs : `~matplotlib.collections.Collection` properties - Any or all of *x*, *y*, *s*, and *c* may be masked arrays, in + Notes + ------ + Any or all of `x`, `y`, `s`, and `c` may be masked arrays, in which case all masks will be combined and only unmasked points will be plotted. - Other keyword arguments: the color mapping and normalization - arguments will be used only if *c* is an array of floats. - - *cmap*: [ *None* | Colormap ] - A :class:`matplotlib.colors.Colormap` instance or registered - name. If *None*, defaults to rc ``image.cmap``. *cmap* is - only used if *c* is an array of floats. - - *norm*: [ *None* | Normalize ] - A :class:`matplotlib.colors.Normalize` instance is used to - scale luminance data to 0, 1. If *None*, use the default - :func:`normalize`. *norm* is only used if *c* is an array - of floats. - - *vmin*/*vmax*: - *vmin* and *vmax* are used in conjunction with norm to - normalize luminance data. If either are *None*, the min and - max of the color array *C* is used. Note if you pass a - *norm* instance, your settings for *vmin* and *vmax* will - be ignored. - - *alpha*: ``0 <= scalar <= 1`` or *None* - The alpha value for the patches - - *linewidths*: [ *None* | scalar | sequence ] - If *None*, defaults to (lines.linewidth,). Note that this - is a tuple, and if you set the linewidths argument you - must set it as a sequence of floats, as required by - :class:`~matplotlib.collections.RegularPolyCollection`. - - Optional kwargs control the - :class:`~matplotlib.collections.Collection` properties; in - particular: - - *edgecolors*: - The string 'none' to plot faces with no outlines - - *facecolors*: - The string 'none' to plot unfilled outlines - - Here are the standard descriptions of all the - :class:`~matplotlib.collections.Collection` kwargs: - - %(Collection)s + Examples + -------- + .. plot:: mpl_examples/shapes_and_collections/scatter_demo.py - A :class:`~matplotlib.collections.Collection` instance is - returned. """ - if not self._hold: self.cla() + if not self._hold: + self.cla() self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs) x = self.convert_xunits(x) @@ -6089,17 +6277,15 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, else: colors = mcolors.colorConverter.to_rgba_array(c, alpha) - - if faceted: - edgecolors = None - else: - edgecolors = 'none' - warnings.warn( - '''replace "faceted=False" with "edgecolors='none'"''', - mplDeprecation) # 2008/04/18 - - sym = None - symstyle = 0 + faceted = kwargs.pop('faceted', None) + edgecolors = kwargs.get('edgecolors', None) + if faceted is not None: + cbook.warn_deprecated( + '1.2', 'faceted', alternative='edgecolor', obj_type='option') + if faceted: + edgecolors = None + else: + edgecolors = 'none' # to be API compatible if marker is None and not (verts is None): @@ -6114,18 +6300,19 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, collection = mcoll.PathCollection( (path,), scales, - facecolors = colors, - edgecolors = edgecolors, - linewidths = linewidths, - offsets = zip(x,y), - transOffset = kwargs.pop('transform', self.transData), + facecolors=colors, + edgecolors=edgecolors, + linewidths=linewidths, + offsets=zip(x, y), + transOffset=kwargs.pop('transform', self.transData), ) collection.set_transform(mtransforms.IdentityTransform()) collection.set_alpha(alpha) collection.update(kwargs) if colors is None: - if norm is not None: assert(isinstance(norm, mcolors.Normalize)) + if norm is not None: + assert(isinstance(norm, mcolors.Normalize)) collection.set_array(np.asarray(c)) collection.set_cmap(cmap) collection.set_norm(norm) @@ -6140,10 +6327,10 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, # to data coords to get the exact bounding box for efficiency # reasons. It can be done right if this is deemed important. # Also, only bother with this padding if there is anything to draw. - if self._xmargin < 0.05 and x.size > 0 : + if self._xmargin < 0.05 and x.size > 0: self.set_xmargin(0.05) - if self._ymargin < 0.05 and x.size > 0 : + if self._ymargin < 0.05 and x.size > 0: self.set_ymargin(0.05) self.add_collection(collection) @@ -6152,12 +6339,12 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, return collection @docstring.dedent_interpd - def hexbin(self, x, y, C = None, gridsize = 100, bins = None, - xscale = 'linear', yscale = 'linear', extent = None, - cmap=None, norm=None, vmin=None, vmax=None, - alpha=None, linewidths=None, edgecolors='none', - reduce_C_function = np.mean, mincnt=None, marginals=False, - **kwargs): + def hexbin(self, x, y, C=None, gridsize=100, bins=None, + xscale='linear', yscale='linear', extent=None, + cmap=None, norm=None, vmin=None, vmax=None, + alpha=None, linewidths=None, edgecolors='none', + reduce_C_function=np.mean, mincnt=None, marginals=False, + **kwargs): """ Make a hexagonal binning plot. @@ -6286,29 +6473,28 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, """ - if not self._hold: self.cla() + if not self._hold: + self.cla() self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs) - x, y, C = cbook.delete_masked_points(x, y, C) - # Set the size of the hexagon grid if iterable(gridsize): nx, ny = gridsize else: nx = gridsize - ny = int(nx/math.sqrt(3)) + ny = int(nx / math.sqrt(3)) # Count the number of data in each hexagon x = np.array(x, float) y = np.array(y, float) - if xscale=='log': + if xscale == 'log': if np.any(x <= 0.0): raise ValueError("x contains non-positive values, so can not" " be log-scaled") x = np.log10(x) - if yscale=='log': + if yscale == 'log': if np.any(y <= 0.0): raise ValueError("y contains non-positive values, so can not" " be log-scaled") @@ -6325,15 +6511,15 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, padding = 1.e-9 * (xmax - xmin) xmin -= padding xmax += padding - sx = (xmax-xmin) / nx - sy = (ymax-ymin) / ny + sx = (xmax - xmin) / nx + sy = (ymax - ymin) / ny if marginals: xorig = x.copy() yorig = y.copy() - x = (x-xmin)/sx - y = (y-ymin)/sy + x = (x - xmin) / sx + y = (y - ymin) / sy ix1 = np.round(x).astype(int) iy1 = np.round(y).astype(int) ix2 = np.floor(x).astype(int) @@ -6343,41 +6529,41 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, ny1 = ny + 1 nx2 = nx ny2 = ny - n = nx1*ny1+nx2*ny2 + n = nx1 * ny1 + nx2 * ny2 - d1 = (x-ix1)**2 + 3.0 * (y-iy1)**2 - d2 = (x-ix2-0.5)**2 + 3.0 * (y-iy2-0.5)**2 - bdist = (d1= 0) and (ix1[i] < nx1) and (iy1[i] >= 0) and (iy1[i] < ny1)): - lattice1[ix1[i], iy1[i]]+=1 + lattice1[ix1[i], iy1[i]] += 1 else: if ((ix2[i] >= 0) and (ix2[i] < nx2) and (iy2[i] >= 0) and (iy2[i] < ny2)): - lattice2[ix2[i], iy2[i]]+=1 + lattice2[ix2[i], iy2[i]] += 1 # threshold if mincnt is not None: for i in xrange(nx1): for j in xrange(ny1): - if lattice1[i,j]= 0) and (ix1[i] < nx1) and (iy1[i] >= 0) and (iy1[i] < ny1)): - lattice1[ix1[i], iy1[i]].append( C[i] ) + lattice1[ix1[i], iy1[i]].append(C[i]) else: if ((ix2[i] >= 0) and (ix2[i] < nx2) and (iy2[i] >= 0) and (iy2[i] < ny2)): - lattice2[ix2[i], iy2[i]].append( C[i] ) - + lattice2[ix2[i], iy2[i]].append(C[i]) for i in xrange(nx1): for j in xrange(ny1): - vals = lattice1[i,j] - if len(vals)>mincnt: - lattice1[i,j] = reduce_C_function( vals ) + vals = lattice1[i, j] + if len(vals) > mincnt: + lattice1[i, j] = reduce_C_function(vals) else: - lattice1[i,j] = np.nan + lattice1[i, j] = np.nan for i in xrange(nx2): for j in xrange(ny2): - vals = lattice2[i,j] - if len(vals)>mincnt: - lattice2[i,j] = reduce_C_function( vals ) + vals = lattice2[i, j] + if len(vals) > mincnt: + lattice2[i, j] = reduce_C_function(vals) else: - lattice2[i,j] = np.nan + lattice2[i, j] = np.nan - accum = np.hstack(( - lattice1.astype(float).ravel(), lattice2.astype(float).ravel())) + accum = np.hstack((lattice1.astype(float).ravel(), + lattice2.astype(float).ravel())) good_idxs = ~np.isnan(accum) offsets = np.zeros((n, 2), float) - offsets[:nx1*ny1,0] = np.repeat(np.arange(nx1), ny1) - offsets[:nx1*ny1,1] = np.tile(np.arange(ny1), nx1) - offsets[nx1*ny1:,0] = np.repeat(np.arange(nx2) + 0.5, ny2) - offsets[nx1*ny1:,1] = np.tile(np.arange(ny2), nx2) + 0.5 - offsets[:,0] *= sx - offsets[:,1] *= sy - offsets[:,0] += xmin - offsets[:,1] += ymin + offsets[:nx1 * ny1, 0] = np.repeat(np.arange(nx1), ny1) + offsets[:nx1 * ny1, 1] = np.tile(np.arange(ny1), nx1) + offsets[nx1 * ny1:, 0] = np.repeat(np.arange(nx2) + 0.5, ny2) + offsets[nx1 * ny1:, 1] = np.tile(np.arange(ny2), nx2) + 0.5 + offsets[:, 0] *= sx + offsets[:, 1] *= sy + offsets[:, 0] += xmin + offsets[:, 1] += ymin # remove accumulation bins with no data - offsets = offsets[good_idxs,:] + offsets = offsets[good_idxs, :] accum = accum[good_idxs] polygon = np.zeros((6, 2), float) - polygon[:,0] = sx * np.array([ 0.5, 0.5, 0.0, -0.5, -0.5, 0.0]) - polygon[:,1] = sy * np.array([-0.5, 0.5, 1.0, 0.5, -0.5, -1.0]) / 3.0 + polygon[:, 0] = sx * np.array([0.5, 0.5, 0.0, -0.5, -0.5, 0.0]) + polygon[:, 1] = sy * np.array([-0.5, 0.5, 1.0, 0.5, -0.5, -1.0]) / 3.0 - if edgecolors=='none': + if edgecolors == 'none': edgecolors = 'face' if xscale == 'log' or yscale == 'log': @@ -6472,7 +6657,7 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, ) if isinstance(norm, mcolors.LogNorm): - if (accum==0).any(): + if (accum == 0).any(): # make sure we have not zeros accum += 1 @@ -6483,17 +6668,18 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, norm.autoscale(accum) # Transform accum if needed - if bins=='log': - accum = np.log10(accum+1) - elif bins!=None: + if bins == 'log': + accum = np.log10(accum + 1) + elif bins != None: if not iterable(bins): minimum, maximum = min(accum), max(accum) - bins-=1 # one less edge than bins - bins = minimum + (maximum-minimum)*np.arange(bins)/bins + bins -= 1 # one less edge than bins + bins = minimum + (maximum - minimum) * np.arange(bins) / bins bins = np.sort(bins) accum = bins.searchsorted(accum) - if norm is not None: assert(isinstance(norm, mcolors.Normalize)) + if norm is not None: + assert(isinstance(norm, mcolors.Normalize)) collection.set_array(accum) collection.set_cmap(cmap) collection.set_norm(norm) @@ -6506,7 +6692,7 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, collection.autoscale_None() corners = ((xmin, ymin), (xmax, ymax)) - self.update_datalim( corners) + self.update_datalim(corners) self.autoscale_view(tight=True) # add the collection last @@ -6514,15 +6700,14 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None, if not marginals: return collection - if C is None: C = np.ones(len(x)) def coarse_bin(x, y, coarse): - ind = coarse.searchsorted(x).clip(0, len(coarse)-1) + ind = coarse.searchsorted(x).clip(0, len(coarse) - 1) mus = np.zeros(len(coarse)) for i in range(len(coarse)): - mu = reduce_C_function(y[ind==i]) + mu = reduce_C_function(y[ind == i]) mus[i] = mu return mus @@ -6531,23 +6716,26 @@ def coarse_bin(x, y, coarse): xcoarse = coarse_bin(xorig, C, coarse) valid = ~np.isnan(xcoarse) verts, values = [], [] - for i,val in enumerate(xcoarse): + for i, val in enumerate(xcoarse): thismin = coarse[i] - if i 0-1 - - *norm* is only used for an MxN float array. - - *vmin*/*vmax*: [ *None* | scalar ] - Used to scale a luminance image to 0-1. If either is - *None*, the min and max of the luminance values will be - used. Note if *norm* is not *None*, the settings for - *vmin* and *vmax* will be ignored. - - *alpha*: scalar + Parameters + ----------- + X : array_like, shape (n, m) or (n, m, 3) or (n, m, 4) + Display the image in `X` to current axes. `X` may be a float + array, a uint8 array or a PIL image. If `X` is an array, it + can have the following shapes: + + - MxN -- luminance (grayscale, float array only) + - MxNx3 -- RGB (float or uint8 array) + - MxNx4 -- RGBA (float or uint8 array) + + The value for each component of MxNx3 and MxNx4 float arrays + should be in the range 0.0 to 1.0; MxN float arrays may be + normalised. + + cmap : `~matplotlib.colors.Colormap`, optional, default: None + If None, default to rc `image.cmap` value. `cmap` is ignored when + `X` has RGB(A) information + + aspect : ['auto' | 'equal' | scalar], optional, default: None + If 'auto', changes the image aspect ratio to match that of the + axes. + + If 'equal', and `extent` is None, changes the axes aspect ratio to + match that of the image. If `extent` is not `None`, the axes + aspect ratio is changed to match that of the extent. + + If None, default to rc ``image.aspect`` value. + + interpolation : string, optional, default: None + Acceptable values are 'none', 'nearest', 'bilinear', 'bicubic', + 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', + 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', + 'lanczos' + + If `interpolation` is None, default to rc `image.interpolation`. + See also the `filternorm` and `filterrad` parameters. + If `interpolation` is 'none', then no interpolation is performed + on the Agg, ps and pdf backends. Other backends will fall back to + 'nearest'. + + norm : `~matplotlib.colors.Normalize`, optional, default: None + A `~matplotlib.colors.Normalize` instance is used to scale + luminance data to 0, 1. If `None`, use the default + func:`normalize`. `norm` is only used if `X` is an array of + floats. + + vmin, vmax : scalar, optional, default: None + `vmin` and `vmax` are used in conjunction with norm to normalize + luminance data. Note if you pass a `norm` instance, your + settings for `vmin` and `vmax` will be ignored. + + alpha : scalar, optional, default: None The alpha blending value, between 0 (transparent) and 1 (opaque) - or *None* - *origin*: [ *None* | 'upper' | 'lower' ] + origin : ['upper' | 'lower'], optional, default: None Place the [0,0] index of the array in the upper left or lower left - corner of the axes. If *None*, default to rc ``image.origin``. + corner of the axes. If None, default to rc `image.origin`. - *extent*: [ *None* | scalars (left, right, bottom, top) ] + extent : scalars (left, right, bottom, top), optional, default: None Data limits for the axes. The default assigns zero-based row, - column indices to the *x*, *y* centers of the pixels. + column indices to the `x`, `y` centers of the pixels. - *shape*: [ *None* | scalars (columns, rows) ] + shape : scalars (columns, rows), optional, default: None For raw buffer images - *filternorm*: + filternorm : scalar, optional, default: 1 A parameter for the antigrain image resize filter. From the - antigrain documentation, if *filternorm* = 1, the filter normalizes - integer values and corrects the rounding errors. It doesn't do - anything with the source floating point values, it corrects only - integers according to the rule of 1.0 which means that any sum of - pixel weights must be equal to 1.0. So, the filter function must - produce a graph of the proper shape. + antigrain documentation, if `filternorm` = 1, the filter + normalizes integer values and corrects the rounding errors. It + doesn't do anything with the source floating point values, it + corrects only integers according to the rule of 1.0 which means + that any sum of pixel weights must be equal to 1.0. So, the + filter function must produce a graph of the proper shape. - *filterrad*: - The filter radius for filters that have a radius - parameter, i.e. when interpolation is one of: 'sinc', - 'lanczos' or 'blackman' + filterrad : scalar, optional, default: 4.0 + The filter radius for filters that have a radius parameter, i.e. + when interpolation is one of: 'sinc', 'lanczos' or 'blackman' - Additional kwargs are :class:`~matplotlib.artist.Artist` properties. + Returns + -------- + image : `~matplotlib.image.AxesImage` - %(Artist)s + Other parameters + ---------------- + kwargs : `~matplotlib.artist.Artist` properties. - **Example:** + See also + -------- + matshow : Plot a matrix or an array as an image. + + Examples + -------- .. plot:: mpl_examples/pylab_examples/image_demo.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() - if norm is not None: assert(isinstance(norm, mcolors.Normalize)) - if aspect is None: aspect = rcParams['image.aspect'] + if norm is not None: + assert(isinstance(norm, mcolors.Normalize)) + if aspect is None: + aspect = rcParams['image.aspect'] self.set_aspect(aspect) im = mimage.AxesImage(self, cmap, norm, interpolation, origin, extent, filternorm=filternorm, @@ -7127,14 +7319,35 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, return im + @staticmethod + def _pcolorargs(funcname, *args, **kw): + # This takes one kwarg, allmatch. + # If allmatch is True, then the incoming X, Y, C must + # have matching dimensions, taking into account that + # X and Y can be 1-D rather than 2-D. This perfect + # match is required for Gouroud shading. For flat + # shading, X and Y specify boundaries, so we need + # one more boundary than color in each direction. + # For convenience, and consistent with Matlab, we + # discard the last row and/or column of C if necessary + # to meet this condition. This is done if allmatch + # is False. + + allmatch = kw.pop("allmatch", False) - def _pcolorargs(self, funcname, *args): - if len(args)==1: + if len(args) == 1: C = args[0] numRows, numCols = C.shape - X, Y = np.meshgrid(np.arange(numCols+1), np.arange(numRows+1) ) - elif len(args)==3: + if allmatch: + X, Y = np.meshgrid(np.arange(numCols), np.arange(numRows)) + else: + X, Y = np.meshgrid(np.arange(numCols + 1), + np.arange(numRows + 1)) + return X, Y, C + + if len(args) == 3: X, Y, C = args + numRows, numCols = C.shape else: raise TypeError( 'Illegal arguments to %s; see help(%s)' % (funcname, funcname)) @@ -7142,7 +7355,7 @@ def _pcolorargs(self, funcname, *args): Nx = X.shape[-1] Ny = Y.shape[0] if len(X.shape) != 2 or X.shape[0] == 1: - x = X.reshape(1,Nx) + x = X.reshape(1, Nx) X = x.repeat(Ny, axis=0) if len(Y.shape) != 2 or Y.shape[1] == 1: y = Y.reshape(Ny, 1) @@ -7151,6 +7364,17 @@ def _pcolorargs(self, funcname, *args): raise TypeError( 'Incompatible X, Y inputs to %s; see help(%s)' % ( funcname, funcname)) + if allmatch: + if not (Nx == numCols and Ny == numRows): + raise TypeError('Dimensions of C %s are incompatible with' + ' X (%d) and/or Y (%d); see help(%s)' % ( + C.shape, Nx, Ny, funcname)) + else: + if not (numCols in (Nx, Nx-1) and numRows in (Ny, Ny-1)): + raise TypeError('Dimensions of C %s are incompatible with' + ' X (%d) and/or Y (%d); see help(%s)' % ( + C.shape, Nx, Ny, funcname)) + C = C[:Ny-1, :Nx-1] return X, Y, C @docstring.dedent_interpd @@ -7158,9 +7382,11 @@ def pcolor(self, *args, **kwargs): """ Create a pseudocolor plot of a 2-D array. - Note: pcolor can be very slow for large arrays; consider - using the similar but much faster - :func:`~matplotlib.pyplot.pcolormesh` instead. + .. note:: + + pcolor can be very slow for large arrays; consider + using the similar but much faster + :func:`~matplotlib.pyplot.pcolormesh` instead. Call signatures:: @@ -7249,7 +7475,7 @@ def pcolor(self, *args, **kwargs): x = np.arange(5) y = np.arange(3) - X, Y = meshgrid(x,y) + X, Y = np.meshgrid(x, y) is equivalent to:: @@ -7263,9 +7489,9 @@ def pcolor(self, *args, **kwargs): so if you have:: - C = rand( len(x), len(y)) + C = rand(len(x), len(y)) - then you need:: + then you need to transpose C:: pcolor(X, Y, C.T) @@ -7283,14 +7509,16 @@ def pcolor(self, *args, **kwargs): %(PolyCollection)s - 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*. - Stroking the edges may be preferred if *alpha* is 1, but - will cause artifacts otherwise. + .. 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*. + Stroking the edges may be preferred if *alpha* is 1, but + will cause artifacts otherwise. .. seealso:: @@ -7299,50 +7527,55 @@ def pcolor(self, *args, **kwargs): pcolor and pcolormesh. """ - if not self._hold: self.cla() + if not self._hold: + self.cla() alpha = kwargs.pop('alpha', None) norm = kwargs.pop('norm', None) cmap = kwargs.pop('cmap', None) vmin = kwargs.pop('vmin', None) vmax = kwargs.pop('vmax', None) + if 'shading' in kwargs: + cbook.warn_deprecated( + '1.2', 'shading', alternative='edgecolors', obj_type='option') shading = kwargs.pop('shading', 'flat') - X, Y, C = self._pcolorargs('pcolor', *args) + X, Y, C = self._pcolorargs('pcolor', *args, allmatch=False) Ny, Nx = X.shape # convert to MA, if necessary. C = ma.asarray(C) X = ma.asarray(X) Y = ma.asarray(Y) - mask = ma.getmaskarray(X)+ma.getmaskarray(Y) - xymask = mask[0:-1,0:-1]+mask[1:,1:]+mask[0:-1,1:]+mask[1:,0:-1] + mask = ma.getmaskarray(X) + ma.getmaskarray(Y) + xymask = (mask[0:-1, 0:-1] + mask[1:, 1:] + + mask[0:-1, 1:] + mask[1:, 0:-1]) # don't plot if C or any of the surrounding vertices are masked. - mask = ma.getmaskarray(C)[0:Ny-1,0:Nx-1]+xymask + mask = ma.getmaskarray(C) + xymask newaxis = np.newaxis compress = np.compress - ravelmask = (mask==0).ravel() - X1 = compress(ravelmask, ma.filled(X[0:-1,0:-1]).ravel()) - Y1 = compress(ravelmask, ma.filled(Y[0:-1,0:-1]).ravel()) - X2 = compress(ravelmask, ma.filled(X[1:,0:-1]).ravel()) - Y2 = compress(ravelmask, ma.filled(Y[1:,0:-1]).ravel()) - X3 = compress(ravelmask, ma.filled(X[1:,1:]).ravel()) - Y3 = compress(ravelmask, ma.filled(Y[1:,1:]).ravel()) - X4 = compress(ravelmask, ma.filled(X[0:-1,1:]).ravel()) - Y4 = compress(ravelmask, ma.filled(Y[0:-1,1:]).ravel()) + ravelmask = (mask == 0).ravel() + X1 = compress(ravelmask, ma.filled(X[0:-1, 0:-1]).ravel()) + Y1 = compress(ravelmask, ma.filled(Y[0:-1, 0:-1]).ravel()) + X2 = compress(ravelmask, ma.filled(X[1:, 0:-1]).ravel()) + Y2 = compress(ravelmask, ma.filled(Y[1:, 0:-1]).ravel()) + X3 = compress(ravelmask, ma.filled(X[1:, 1:]).ravel()) + Y3 = compress(ravelmask, ma.filled(Y[1:, 1:]).ravel()) + X4 = compress(ravelmask, ma.filled(X[0:-1, 1:]).ravel()) + Y4 = compress(ravelmask, ma.filled(Y[0:-1, 1:]).ravel()) npoly = len(X1) - xy = np.concatenate((X1[:,newaxis], Y1[:,newaxis], - X2[:,newaxis], Y2[:,newaxis], - X3[:,newaxis], Y3[:,newaxis], - X4[:,newaxis], Y4[:,newaxis], - X1[:,newaxis], Y1[:,newaxis]), + xy = np.concatenate((X1[:, newaxis], Y1[:, newaxis], + X2[:, newaxis], Y2[:, newaxis], + X3[:, newaxis], Y3[:, newaxis], + X4[:, newaxis], Y4[:, newaxis], + X1[:, newaxis], Y1[:, newaxis]), axis=1) verts = xy.reshape((npoly, 5, 2)) - C = compress(ravelmask, ma.filled(C[0:Ny-1,0:Nx-1]).ravel()) + C = compress(ravelmask, ma.filled(C[0:Ny - 1, 0:Nx - 1]).ravel()) linewidths = (0.25,) if 'linewidth' in kwargs: @@ -7353,6 +7586,7 @@ def pcolor(self, *args, **kwargs): edgecolors = 'k', else: edgecolors = 'none' + if 'edgecolor' in kwargs: kwargs['edgecolors'] = kwargs.pop('edgecolor') ec = kwargs.setdefault('edgecolors', edgecolors) @@ -7367,12 +7601,12 @@ def pcolor(self, *args, **kwargs): ec.lower() == "none"): kwargs['antialiaseds'] = False - collection = mcoll.PolyCollection(verts, **kwargs) collection.set_alpha(alpha) collection.set_array(C) - if norm is not None: assert(isinstance(norm, mcolors.Normalize)) + if norm is not None: + assert(isinstance(norm, mcolors.Normalize)) collection.set_cmap(cmap) collection.set_norm(norm) collection.set_clim(vmin, vmax) @@ -7401,7 +7635,7 @@ def pcolor(self, *args, **kwargs): maxy = np.amax(y) corners = (minx, miny), (maxx, maxy) - self.update_datalim( corners) + self.update_datalim(corners) self.autoscale_view() self.add_collection(collection) return collection @@ -7456,7 +7690,8 @@ def pcolormesh(self, *args, **kwargs): 'gouraud', each quad will be Gouraud shaded. When gouraud shading, edgecolors is ignored. - *edgecolors*: [ *None* | ``'None'`` | ``'face'`` | color | color sequence] + *edgecolors*: [*None* | ``'None'`` | ``'face'`` | color | + color sequence] If *None*, the rc setting is used by default. If ``'None'``, edges will not be visible. @@ -7482,7 +7717,8 @@ def pcolormesh(self, *args, **kwargs): For an explanation of the grid orientation and the expansion of 1-D *X* and/or *Y* to 2-D arrays. """ - if not self._hold: self.cla() + if not self._hold: + self.cla() alpha = kwargs.pop('alpha', None) norm = kwargs.pop('norm', None) @@ -7493,15 +7729,13 @@ def pcolormesh(self, *args, **kwargs): antialiased = kwargs.pop('antialiased', False) kwargs.setdefault('edgecolors', 'None') - X, Y, C = self._pcolorargs('pcolormesh', *args) + allmatch = (shading == 'gouraud') + + X, Y, C = self._pcolorargs('pcolormesh', *args, allmatch=allmatch) Ny, Nx = X.shape # convert to one dimensional arrays - if shading != 'gouraud': - C = ma.ravel(C[0:Ny-1, 0:Nx-1]) # data point in each cell is value at - # lower left corner - else: - C = C.ravel() + C = C.ravel() X = X.ravel() Y = Y.ravel() @@ -7514,7 +7748,8 @@ def pcolormesh(self, *args, **kwargs): antialiased=antialiased, shading=shading, **kwargs) collection.set_alpha(alpha) collection.set_array(C) - if norm is not None: assert(isinstance(norm, mcolors.Normalize)) + if norm is not None: + assert(isinstance(norm, mcolors.Normalize)) collection.set_cmap(cmap) collection.set_norm(norm) collection.set_clim(vmin, vmax) @@ -7541,7 +7776,7 @@ def pcolormesh(self, *args, **kwargs): maxy = np.amax(Y) corners = (minx, miny), (maxx, maxy) - self.update_datalim( corners) + self.update_datalim(corners) self.autoscale_view() self.add_collection(collection) return collection @@ -7630,14 +7865,16 @@ def pcolorfast(self, *args, **kwargs): """ - if not self._hold: self.cla() + if not self._hold: + self.cla() alpha = kwargs.pop('alpha', None) norm = kwargs.pop('norm', None) cmap = kwargs.pop('cmap', None) vmin = kwargs.pop('vmin', None) vmax = kwargs.pop('vmax', None) - if norm is not None: assert(isinstance(norm, mcolors.Normalize)) + if norm is not None: + assert(isinstance(norm, mcolors.Normalize)) C = args[-1] nr, nc = C.shape @@ -7655,8 +7892,8 @@ def pcolorfast(self, *args, **kwargs): else: dx = np.diff(x) dy = np.diff(y) - if (np.ptp(dx) < 0.01*np.abs(dx.mean()) and - np.ptp(dy) < 0.01*np.abs(dy.mean())): + if (np.ptp(dx) < 0.01 * np.abs(dx.mean()) and + np.ptp(dy) < 0.01 * np.abs(dy.mean())): style = "image" else: style = "pcolorimage" @@ -7671,12 +7908,12 @@ def pcolorfast(self, *args, **kwargs): # convert to one dimensional arrays # This should also be moved to the QuadMesh class - C = ma.ravel(C) # data point in each cell is value - # at lower left corner + C = ma.ravel(C) # data point in each cell is value + # at lower left corner X = x.ravel() Y = y.ravel() - Nx = nc+1 - Ny = nr+1 + Nx = nc + 1 + Ny = nr + 1 # The following needs to be cleaned up; the renderer # requires separate contiguous arrays for X and Y, @@ -7731,13 +7968,15 @@ def pcolorfast(self, *args, **kwargs): return ret def contour(self, *args, **kwargs): - if not self._hold: self.cla() + if not self._hold: + self.cla() kwargs['filled'] = False return mcontour.QuadContourSet(self, *args, **kwargs) contour.__doc__ = mcontour.QuadContourSet.contour_doc def contourf(self, *args, **kwargs): - if not self._hold: self.cla() + if not self._hold: + self.cla() kwargs['filled'] = True return mcontour.QuadContourSet(self, *args, **kwargs) contourf.__doc__ = mcontour.QuadContourSet.contour_doc @@ -7780,7 +8019,6 @@ def _make_twin_axes(self, *kl, **kwargs): ax2 = self.figure.add_axes(self.get_position(True), *kl, **kwargs) return ax2 - def twinx(self): """ Call signature:: @@ -7847,14 +8085,6 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, """ Plot a histogram. - Call signature:: - - 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, stacked=False, - **kwargs) - Compute and draw the histogram of *x*. The return value is a tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*, [*patches0*, *patches1*,...]) if the input contains multiple @@ -7867,133 +8097,128 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, Masked arrays are not supported at present. - Keyword arguments: + Parameters + ---------- + x : array_like, shape (n, ) + Input values. + + bins : integer or array_like, optional, default: 10 + If an integer is given, `bins + 1` bin edges are returned, + consistently with :func:`numpy.histogram` for numpy version >= + 1.3. - *bins*: - Either an integer number of bins or a sequence giving the - bins. If *bins* is an integer, *bins* + 1 bin edges - will be returned, consistent with :func:`numpy.histogram` - for numpy version >= 1.3, and with the *new* = True argument - in earlier versions. - Unequally spaced bins are supported if *bins* is a sequence. + Unequally spaced bins are supported if `bins` is a sequence. - *range*: + range : tuple, optional, default: None The lower and upper range of the bins. Lower and upper outliers - are ignored. If not provided, *range* is (x.min(), x.max()). - Range has no effect if *bins* is a sequence. + are ignored. If not provided, `range` is (x.min(), x.max()). Range + has no effect if `bins` is a sequence. - If *bins* is a sequence or *range* is specified, autoscaling + If `bins` is a sequence or `range` is specified, autoscaling is based on the specified bin range instead of the range of x. - *normed*: - If *True*, the first element of the return tuple will + normed : boolean, optional, default: False + If `True`, the first element of the return tuple will be the counts normalized to form a probability density, i.e., - ``n/(len(x)*dbin)``. In a probability density, the integral of - the histogram should be 1; you can verify that with a - trapezoidal integration of the probability density function:: - - pdf, bins, patches = ax.hist(...) - print np.sum(pdf * np.diff(bins)) - - .. note:: - - Until numpy release 1.5, the underlying numpy - histogram function was incorrect with *normed*=*True* - if bin sizes were unequal. MPL inherited that - error. It is now corrected within MPL when using - earlier numpy versions - - *weights*: - An array of weights, of the same shape as *x*. Each value in - *x* only contributes its associated weight towards the bin - count (instead of 1). If *normed* is True, the weights are - normalized, so that the integral of the density over the range - remains 1. - - *cumulative*: - If *True*, then a histogram is computed where each bin - gives the counts in that bin plus all bins for smaller values. - The last bin gives the total number of datapoints. If *normed* - is also *True* then the histogram is normalized such that the - last bin equals 1. If *cumulative* evaluates to less than 0 - (e.g. -1), the direction of accumulation is reversed. In this - case, if *normed* is also *True*, then the histogram is normalized - such that the first bin equals 1. - - *histtype*: [ 'bar' | 'barstacked' | 'step' | 'stepfilled' ] + ``n/(len(x)`dbin)``, ie the integral of the histogram will sum to + 1. If *stacked* is also *True*, the sum of the histograms is + normalized to 1. + + weights : array_like, shape (n, ), optional, default: None + An array of weights, of the same shape as `x`. Each value in `x` + only contributes its associated weight towards the bin count + (instead of 1). If `normed` is True, the weights are normalized, + so that the integral of the density over the range remains 1. + + cumulative : boolean, optional, default : True + If `True`, then a histogram is computed where each bin gives the + counts in that bin plus all bins for smaller values. The last bin + gives the total number of datapoints. If `normed` is also `True` + then the histogram is normalized such that the last bin equals 1. + If `cumulative` evaluates to less than 0 (e.g., -1), the direction + of accumulation is reversed. In this case, if `normed` is also + `True`, then the histogram is normalized such that the first bin + equals 1. + + histtype : ['bar' | 'barstacked' | 'step' | 'stepfilled'], optional The type of histogram to draw. - - 'bar' is a traditional bar-type histogram. If multiple data - are given the bars are aranged side by side. + - 'bar' is a traditional bar-type histogram. If multiple data + are given the bars are aranged side by side. - - 'barstacked' is a bar-type histogram where multiple - data are stacked on top of each other. + - 'barstacked' is a bar-type histogram where multiple + data are stacked on top of each other. - - 'step' generates a lineplot that is by default - unfilled. + - 'step' generates a lineplot that is by default + unfilled. - - 'stepfilled' generates a lineplot that is by default - filled. + - 'stepfilled' generates a lineplot that is by default + filled. - *align*: ['left' | 'mid' | 'right' ] + align : ['left' | 'mid' | 'right'], optional, default: 'mid' Controls how the histogram is plotted. - - 'left': bars are centered on the left bin edges. + - 'left': bars are centered on the left bin edges. - - 'mid': bars are centered between the bin edges. + - 'mid': bars are centered between the bin edges. - - 'right': bars are centered on the right bin edges. + - 'right': bars are centered on the right bin edges. - *orientation*: [ 'horizontal' | 'vertical' ] - If 'horizontal', :func:`~matplotlib.pyplot.barh` will be - used for bar-type histograms and the *bottom* kwarg will be - the left edges. + orientation : ['horizontal' | 'vertical'], optional + If 'horizontal', `~matplotlib.pyplot.barh` will be used for + bar-type histograms and the *bottom* kwarg will be the left edges. - *rwidth*: - The relative width of the bars as a fraction of the bin - width. If *None*, automatically compute the width. Ignored - if *histtype* = 'step' or 'stepfilled'. + rwidth : scalar, optional, default: None + The relative width of the bars as a fraction of the bin width. If + `None`, automatically compute the width. Ignored if `histtype` = + 'step' or 'stepfilled'. - *log*: - If *True*, the histogram axis will be set to a log scale. - If *log* is *True* and *x* is a 1D array, empty bins will - be filtered out and only the non-empty (*n*, *bins*, - *patches*) will be returned. + log : boolean, optional, default : False + If `True`, the histogram axis will be set to a log scale. If `log` + is `True` and `x` is a 1D array, empty bins will be filtered out + and only the non-empty (`n`, `bins`, `patches`) will be returned. - *color*: - Color spec or sequence of color specs, one per - dataset. Default (*None*) uses the standard line - color sequence. + color : color or array_like of colors, optional, default: None + Color spec or sequence of color specs, one per dataset. Default + (`None`) uses the standard line color sequence. - *label*: - String, or sequence of strings to match multiple - datasets. Bar charts yield multiple patches per - dataset, but only the first gets the label, so - that the legend command will work as expected:: + label : string, optional, default: '' + String, or sequence of strings to match multiple datasets. Bar + charts yield multiple patches per dataset, but only the first gets + the label, so that the legend command will work as expected. - ax.hist(10+2*np.random.randn(1000), label='men') - ax.hist(12+3*np.random.randn(1000), label='women', alpha=0.5) - ax.legend() + stacked : boolean, optional, default : False + If `True`, multiple data are stacked on top of each other If + `False` multiple data are aranged side by side if histtype is + 'bar' or on top of each other if histtype is 'step' - *stacked*: - If *True*, multiple data are stacked on top of each other - If *False* multiple data are aranged side by side if - histtype is 'bar' or on top of each other if histtype is 'step' + Returns + ------- + tuple : (n, bins, patches) or ([n0, n1, ...], bins, [patches0, patches1,...]) - . + Other Parameters + ---------------- + kwargs : `~matplotlib.patches.Patch` properties - kwargs are used to update the properties of the - :class:`~matplotlib.patches.Patch` instances returned by *hist*: + See also + -------- + hist2d : 2D histograms - %(Patch)s + Notes + ----- + Until numpy release 1.5, the underlying numpy histogram function was + incorrect with `normed`=`True` if bin sizes were unequal. MPL + inherited that error. It is now corrected within MPL when using + earlier numpy versions. - **Example:** - - .. plot:: mpl_examples/pylab_examples/histogram_demo.py + Examples + -------- + .. plot:: mpl_examples/statistics/histogram_demo_features.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() # xrange becomes range after 2to3 bin_range = range @@ -8010,18 +8235,12 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, if align not in ['left', 'mid', 'right']: raise ValueError("align kwarg %s is not recognized" % align) - if orientation not in [ 'horizontal', 'vertical']: + if orientation not in ['horizontal', 'vertical']: raise ValueError( "orientation kwarg %s is not recognized" % orientation) - - if kwargs.get('width') is not None: - raise mplDeprecation( - 'hist now uses the rwidth to give relative width ' - 'and not absolute width') - if histtype == 'barstacked' and not stacked: - stacked=True + stacked = True # Massage 'x' for processing. # NOTE: Be sure any changes here is also done below to 'weights' @@ -8029,23 +8248,24 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, # TODO: support masked arrays; x = np.asarray(x) if x.ndim == 2: - x = x.T # 2-D input with columns as datasets; switch to rows + x = x.T # 2-D input with columns as datasets; switch to rows elif x.ndim == 1: x = x.reshape(1, x.shape[0]) # new view, single row else: raise ValueError("x must be 1D or 2D") if x.shape[1] < x.shape[0]: - warnings.warn('2D hist input should be nsamples x nvariables;\n ' + warnings.warn( + '2D hist input should be nsamples x nvariables;\n ' 'this looks transposed (shape is %d x %d)' % x.shape[::-1]) else: # multiple hist with data of different length x = [np.asarray(xi) for xi in x] - nx = len(x) # number of datasets + nx = len(x) # number of datasets if color is None: color = [self._get_lines.color_cycle.next() - for i in xrange(nx)] + for i in xrange(nx)] else: color = mcolors.colorConverter.to_rgba_array(color) if len(color) != nx: @@ -8053,7 +8273,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, # We need to do to 'weights' what was done to 'x' if weights is not None: - if isinstance(weights, np.ndarray) or not iterable(weights[0]) : + if isinstance(weights, np.ndarray) or not iterable(weights[0]): w = np.array(weights) if w.ndim == 2: w = w.T @@ -8073,21 +8293,12 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, else: w = [None]*nx - - # Save autoscale state for later restoration; turn autoscaling - # off so we can do it all a single time at the end, instead - # of having it done by bar or fill and then having to be redone. - _saved_autoscalex = self.get_autoscalex_on() - _saved_autoscaley = self.get_autoscaley_on() - self.set_autoscalex_on(False) - self.set_autoscaley_on(False) - # Save the datalimits for the same reason: _saved_bounds = self.dataLim.bounds # Check whether bins or range are given explicitly. In that # case use those values for autoscaling. - binsgiven = (cbook.iterable(bins) or bin_range != None) + binsgiven = (cbook.iterable(bins) or bin_range is not None) # If bins are not specified either explicitly or via range, # we need to figure out the range required for all datasets, @@ -8104,8 +8315,6 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, # We will handle the normed kwarg within mpl until we # get to the point of requiring numpy >= 1.5. hist_kwargs = dict(range=bin_range) - if np.__version__ < "1.3": # version 1.1 and 1.2 - hist_kwargs['new'] = True n = [] mlast = bottom @@ -8113,9 +8322,10 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, # this will automatically overwrite bins, # so that each histogram uses the same bins m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs) + m = m.astype(float) # causes problems later if it's an int if mlast is None: mlast = np.zeros(len(bins)-1, m.dtype) - if normed: + if normed and not stacked: db = np.diff(bins) m = (m.astype(float) / db) / m.sum() if stacked: @@ -8123,12 +8333,14 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, mlast[:] = m n.append(m) - - + if stacked and normed: + db = np.diff(bins) + for m in n: + m[:] = (m.astype(float) / db) / n[-1].sum() if cumulative: slc = slice(None) if cbook.is_numlike(cumulative) and cumulative < 0: - slc = slice(None,None,-1) + slc = slice(None, None, -1) if normed: n = [(m * np.diff(bins))[slc].cumsum()[slc] for m in n] @@ -8138,16 +8350,24 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, patches = [] if histtype.startswith('bar'): + # Save autoscale state for later restoration; turn autoscaling + # off so we can do it all a single time at the end, instead + # of having it done by bar or fill and then having to be redone. + _saved_autoscalex = self.get_autoscalex_on() + _saved_autoscaley = self.get_autoscaley_on() + self.set_autoscalex_on(False) + self.set_autoscaley_on(False) + totwidth = np.diff(bins) if rwidth is not None: dr = min(1.0, max(0.0, rwidth)) - elif len(n)>1: + elif len(n) > 1: dr = 0.8 else: dr = 1.0 - if histtype=='bar' and not stacked: + if histtype == 'bar' and not stacked: width = dr*totwidth/nx dw = width @@ -8156,7 +8376,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, else: boffset = 0.0 stacked = False - elif histtype=='barstacked' or stacked: + elif histtype == 'barstacked' or stacked: width = dr*totwidth boffset, dw = 0.0, 0.0 @@ -8177,7 +8397,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, bottom = np.zeros(len(m), np.float) if stacked: height = m - bottom - else : + else: height = m patch = _barfunc(bins[:-1]+boffset, height, width, align='center', log=log, @@ -8187,20 +8407,24 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, bottom[:] = m boffset += dw + self.set_autoscalex_on(_saved_autoscalex) + self.set_autoscaley_on(_saved_autoscaley) + self.autoscale_view() + elif histtype.startswith('step'): # these define the perimeter of the polygon - x = np.zeros( 4*len(bins)-3, np.float ) - y = np.zeros( 4*len(bins)-3, np.float ) + x = np.zeros(4 * len(bins) - 3, np.float) + y = np.zeros(4 * len(bins) - 3, np.float) x[0:2*len(bins)-1:2], x[1:2*len(bins)-1:2] = bins, bins[:-1] x[2*len(bins)-1:] = x[1:2*len(bins)-1][::-1] if log: if orientation == 'horizontal': - self.set_xscale('log', nonposx = 'clip') + self.set_xscale('log', nonposx='clip') logbase = self.xaxis._scale.base else: # orientation == 'vertical' - self.set_yscale('log', nonposy = 'clip') + self.set_yscale('log', nonposy='clip') logbase = self.yaxis._scale.base # Setting a minimum of 0 results in problems for log plots @@ -8208,10 +8432,11 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, # For normed data, set to log base * minimum data value # (gives 1 full tick-label unit for the lowest filled bin) ndata = np.array(n) - minimum = (np.min(ndata[ndata>0])) / logbase + minimum = (np.min(ndata[ndata > 0])) / logbase else: - # For non-normed data, set the min to log base, again so that - # there is 1 full tick-label unit for the lowest bin + # For non-normed data, set the min to log base, + # again so that there is 1 full tick-label unit + # for the lowest bin minimum = 1.0 / logbase y[0], y[-1] = minimum, minimum @@ -8236,9 +8461,9 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, # set the top of this polygon y[1:2*len(bins)-1:2], y[2:2*len(bins):2] = m, m if log: - y[ycmax]=None + if cmin is not None: + h[h < cmin] = None + if cmax is not None: + h[h > cmax] = None - pc = self.pcolorfast(xedges,yedges,h.T,**kwargs) - self.set_xlim(xedges[0],xedges[-1]) - self.set_ylim(yedges[0],yedges[-1]) + pc = self.pcolorfast(xedges, yedges, h.T, **kwargs) + self.set_xlim(xedges[0], xedges[-1]) + self.set_ylim(yedges[0], yedges[-1]) - return h,xedges,yedges,pc + return h, xedges, yedges, pc @docstring.dedent_interpd def psd(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, @@ -8454,9 +8684,10 @@ def psd(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, .. plot:: mpl_examples/pylab_examples/psd_demo.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() pxx, freqs = mlab.psd(x, NFFT, Fs, detrend, window, noverlap, pad_to, - sides, scale_by_freq) + sides, scale_by_freq) pxx.shape = len(freqs), freqs += Fc @@ -8465,17 +8696,18 @@ def psd(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, else: psd_units = 'dB' - self.plot(freqs, 10*np.log10(pxx), **kwargs) + self.plot(freqs, 10 * np.log10(pxx), **kwargs) self.set_xlabel('Frequency') self.set_ylabel('Power Spectral Density (%s)' % psd_units) self.grid(True) vmin, vmax = self.viewLim.intervaly - intv = vmax-vmin + intv = vmax - vmin logi = int(np.log10(intv)) - if logi==0: logi=.1 - step = 10*logi + if logi == 0: + logi = .1 + step = 10 * logi #print vmin, vmax, step, intv, math.floor(vmin), math.ceil(vmax)+1 - ticks = np.arange(math.floor(vmin), math.ceil(vmax)+1, step) + ticks = np.arange(math.floor(vmin), math.ceil(vmax) + 1, step) self.set_yticks(ticks) return pxx, freqs @@ -8534,23 +8766,24 @@ def csd(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, :meth:`psd` For a description of the optional parameters. """ - if not self._hold: self.cla() + if not self._hold: + self.cla() pxy, freqs = mlab.csd(x, y, NFFT, Fs, detrend, window, noverlap, pad_to, sides, scale_by_freq) pxy.shape = len(freqs), # pxy is complex freqs += Fc - self.plot(freqs, 10*np.log10(np.absolute(pxy)), **kwargs) + self.plot(freqs, 10 * np.log10(np.absolute(pxy)), **kwargs) self.set_xlabel('Frequency') self.set_ylabel('Cross Spectrum Magnitude (dB)') self.grid(True) vmin, vmax = self.viewLim.intervaly - intv = vmax-vmin - step = 10*int(np.log10(intv)) + intv = vmax - vmin + step = 10 * int(np.log10(intv)) - ticks = np.arange(math.floor(vmin), math.ceil(vmax)+1, step) + ticks = np.arange(math.floor(vmin), math.ceil(vmax) + 1, step) self.set_yticks(ticks) return pxy, freqs @@ -8606,7 +8839,8 @@ def cohere(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, .. plot:: mpl_examples/pylab_examples/cohere_demo.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() cxy, freqs = mlab.cohere(x, y, NFFT, Fs, detrend, window, noverlap, scale_by_freq) freqs += Fc @@ -8633,11 +8867,12 @@ def specgram(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, cmap=None, xextent=None, pad_to=None, sides='default', scale_by_freq=None, **kwargs) - Compute a spectrogram of data in *x*. Data are split into + Compute and plot a spectrogram of data in *x*. Data are split into *NFFT* length segments and the PSD of each section is computed. The windowing function *window* is applied to each segment, and the amount of overlap of each segment is - specified with *noverlap*. + specified with *noverlap*. The spectrogram is plotted in decibels + as a colormap (using imshow). %(PSD)s @@ -8672,16 +8907,22 @@ def specgram(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, - *Pxx* is an array of shape `(len(times), len(freqs))` of power - *im* is a :class:`~matplotlib.image.AxesImage` instance - Note: If *x* is real (i.e. non-complex), only the positive - spectrum is shown. If *x* is complex, both positive and - negative parts of the spectrum are shown. This can be - overridden using the *sides* keyword argument. + .. note:: + + If *x* is real (i.e. non-complex), only the positive + spectrum is shown. If *x* is complex, both positive and + negative parts of the spectrum are shown. This can be + overridden using the *sides* keyword argument. + + Also note that while the plot is in dB, the *Pxx* array returned is + linear in power. **Example:** .. plot:: mpl_examples/pylab_examples/specgram_demo.py """ - if not self._hold: self.cla() + if not self._hold: + self.cla() Pxx, freqs, bins = mlab.specgram(x, NFFT, Fs, detrend, window, noverlap, pad_to, sides, scale_by_freq) @@ -8689,7 +8930,8 @@ def specgram(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, Z = 10. * np.log10(Pxx) Z = np.flipud(Z) - if xextent is None: xextent = 0, np.amax(bins) + if xextent is None: + xextent = 0, np.amax(bins) xmin, xmax = xextent freqs += Fc extent = xmin, xmax, freqs[0], freqs[-1] @@ -8699,7 +8941,7 @@ def specgram(self, x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, return Pxx, freqs, bins, im def spy(self, Z, precision=0, marker=None, markersize=None, - aspect='equal', **kwargs): + aspect='equal', **kwargs): """ Plot the sparsity pattern on a 2-D array. @@ -8749,7 +8991,7 @@ def spy(self, Z, precision=0, marker=None, markersize=None, :func:`~matplotlib.pyplot.imshow` For image options. - For controlling colors, e.g. cyan background and red marks, + For controlling colors, e.g., cyan background and red marks, use:: cmap = mcolors.ListedColormap(['c','r']) @@ -8772,21 +9014,17 @@ def spy(self, Z, precision=0, marker=None, markersize=None, :func:`~matplotlib.pyplot.plot` For plotting options """ - if precision is None: - precision = 0 - warnings.warn("Use precision=0 instead of None", mplDeprecation) - # 2008/10/03 if marker is None and markersize is None and hasattr(Z, 'tocoo'): marker = 's' if marker is None and markersize is None: Z = np.asarray(Z) - mask = np.absolute(Z)>precision + mask = np.absolute(Z) > precision if 'cmap' not in kwargs: kwargs['cmap'] = mcolors.ListedColormap(['w', 'k'], name='binary') nr, nc = Z.shape - extent = [-0.5, nc-0.5, nr-0.5, -0.5] + extent = [-0.5, nc - 0.5, nr - 0.5, -0.5] ret = self.imshow(mask, interpolation='nearest', aspect=aspect, extent=extent, origin='upper', **kwargs) else: @@ -8801,16 +9039,18 @@ def spy(self, Z, precision=0, marker=None, markersize=None, x = c.col[nonzero] else: Z = np.asarray(Z) - nonzero = np.absolute(Z)>precision + nonzero = np.absolute(Z) > precision y, x = np.nonzero(nonzero) - if marker is None: marker = 's' - if markersize is None: markersize = 10 + if marker is None: + marker = 's' + if markersize is None: + markersize = 10 marks = mlines.Line2D(x, y, linestyle='None', marker=marker, markersize=markersize, **kwargs) self.add_line(marks) nr, nc = Z.shape - self.set_xlim(xmin=-0.5, xmax=nc-0.5) - self.set_ylim(ymin=nr-0.5, ymax=-0.5) + self.set_xlim(xmin=-0.5, xmax=nc - 0.5) + self.set_ylim(ymin=nr - 0.5, ymax=-0.5) self.set_aspect(aspect) ret = marks self.title.set_y(1.05) @@ -8828,20 +9068,32 @@ def matshow(self, Z, **kwargs): """ Plot a matrix or array as an image. - The matrix will be shown the way it would be printed, - with the first row at the top. Row and column numbering - is zero-based. + The matrix will be shown the way it would be printed, with the first + row at the top. Row and column numbering is zero-based. - Argument: - *Z* anything that can be interpreted as a 2-D array + Parameters + ---------- + Z : array_like shape (n, m) + The matrix to be displayed. - kwargs all are passed to :meth:`~matplotlib.axes.Axes.imshow`. - :meth:`matshow` sets defaults for *origin*, - *interpolation*, and *aspect*; if you want row zero to - be at the bottom instead of the top, you can set the *origin* - kwarg to "lower". + Returns + ------- + image : `~matplotlib.image.AxesImage` + + Other parameters + ---------------- + kwargs : `~matplotlib.axes.Axes.imshow` arguments + Sets `origin` to 'upper', 'interpolation' to 'nearest' and + 'aspect' to equal. + + See also + -------- + imshow : plot an image + + Examples + -------- + .. plot:: mpl_examples/pylab_examples/matshow.py - Returns: an :class:`matplotlib.image.AxesImage` instance. """ Z = np.asanyarray(Z) nr, nc = Z.shape @@ -8862,11 +9114,8 @@ def matshow(self, Z, **kwargs): return im def get_default_bbox_extra_artists(self): - bbox_extra_artists = [t for t in self.texts if t.get_visible()] - if self.legend_: - bbox_extra_artists.append(self.legend_) - return bbox_extra_artists - + return [artist for artist in self.get_children() + if artist.get_visible()] def get_tightbbox(self, renderer, call_axes_locator=True): """ @@ -8880,7 +9129,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True): compared to the axes bbox. """ - artists = [] bb = [] if not self.get_visible(): @@ -8897,14 +9145,21 @@ def get_tightbbox(self, renderer, call_axes_locator=True): if self.title.get_visible(): bb.append(self.title.get_window_extent(renderer)) + if self._left_title.get_visible(): + bb.append(self._left_title.get_window_extent(renderer)) + if self._right_title.get_visible(): + bb.append(self._right_title.get_window_extent(renderer)) bb_xaxis = self.xaxis.get_tightbbox(renderer) - if bb_xaxis: bb.append(bb_xaxis) + if bb_xaxis: + bb.append(bb_xaxis) bb_yaxis = self.yaxis.get_tightbbox(renderer) - if bb_yaxis: bb.append(bb_yaxis) + if bb_yaxis: + bb.append(bb_yaxis) - _bbox = mtransforms.Bbox.union([b for b in bb if b.width!=0 or b.height!=0]) + _bbox = mtransforms.Bbox.union( + [b for b in bb if b.width != 0 or b.height != 0]) return _bbox @@ -8941,6 +9196,7 @@ def triplot(self, *args, **kwargs): from matplotlib.gridspec import GridSpec, SubplotSpec + class SubplotBase: """ Base class for subplots, which are :class:`Axes` instances with @@ -8974,18 +9230,19 @@ def __init__(self, fig, *args, **kwargs): rows, cols, num = map(int, s) except ValueError: raise ValueError( - 'Single argument to subplot must be a 3-digit integer') - self._subplotspec = GridSpec(rows, cols)[num-1] + 'Single argument to subplot must be a 3-digit ' + 'integer') + self._subplotspec = GridSpec(rows, cols)[num - 1] # num - 1 for converting from MATLAB to python indexing - elif len(args)==3: + elif len(args) == 3: rows, cols, num = args rows = int(rows) cols = int(cols) if isinstance(num, tuple) and len(num) == 2: num = [int(n) for n in num] - self._subplotspec = GridSpec(rows, cols)[num[0]-1:num[1]] + self._subplotspec = GridSpec(rows, cols)[num[0] - 1:num[1]] else: - self._subplotspec = GridSpec(rows, cols)[int(num)-1] + self._subplotspec = GridSpec(rows, cols)[int(num) - 1] # num - 1 for converting from MATLAB to python indexing else: raise ValueError('Illegal argument(s) to subplot: %s' % (args,)) @@ -9008,12 +9265,12 @@ def __reduce__(self): def get_geometry(self): """get the subplot geometry, eg 2,2,3""" rows, cols, num1, num2 = self.get_subplotspec().get_geometry() - return rows, cols, num1+1 # for compatibility + return rows, cols, num1 + 1 # for compatibility # COVERAGE NOTE: Never used internally or from examples def change_geometry(self, numrows, numcols, num): - """change subplot geometry, eg. from 1,1,1 to 2,2,3""" - self._subplotspec = GridSpec(numrows, numcols)[num-1] + """change subplot geometry, e.g., from 1,1,1 to 2,2,3""" + self._subplotspec = GridSpec(numrows, numcols)[num - 1] self.update_params() self.set_position(self.figbox) @@ -9032,19 +9289,17 @@ def update_params(self): self.get_subplotspec().get_position(self.figure, return_all=True) - def is_first_col(self): - return self.colNum==0 + return self.colNum == 0 def is_first_row(self): - return self.rowNum==0 + return self.rowNum == 0 def is_last_row(self): - return self.rowNum==self.numRows-1 - + return self.rowNum == self.numRows - 1 def is_last_col(self): - return self.colNum==self.numCols-1 + return self.colNum == self.numCols - 1 # COVERAGE NOTE: Never used internally or from examples def label_outer(self): @@ -9061,7 +9316,6 @@ def label_outer(self): for label in self.get_yticklabels(): label.set_visible(firstcol) - def _make_twin_axes(self, *kl, **kwargs): """ make a twinx axes of self. This is used for twinx and twiny. @@ -9076,8 +9330,9 @@ def _make_twin_axes(self, *kl, **kwargs): self.figure.add_subplot(ax2) return ax2 - _subplot_classes = {} + + def subplot_class_factory(axes_class=None): # This makes a new class that inherits from SubplotBase and the # given axes_class (which is assumed to be a subclass of Axes). diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index f0aa06f740ba..954e401395ab 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -16,6 +16,7 @@ import matplotlib.transforms as mtransforms import matplotlib.units as munits import numpy as np +import warnings GRIDLINE_INTERPOLATION_STEPS = 180 @@ -651,7 +652,7 @@ def __init__(self, axes, pickradius=15): self._minor_tick_kw = dict() self.cla() - self.set_scale('linear') + self._set_scale('linear') def set_label_coords(self, x, y, transform=None): """ @@ -681,7 +682,14 @@ def get_transform(self): def get_scale(self): return self._scale.name + @cbook.deprecated('1.3') def set_scale(self, value, **kwargs): + """ + This should be a private function (moved to _set_scale) + """ + self._set_scale(value, **kwargs) + + def _set_scale(self, value, **kwargs): self._scale = mscale.scale_factory(value, self, **kwargs) self._scale.set_default_locators_and_formatters(self) @@ -974,11 +982,40 @@ def _update_ticks(self, renderer): tick_tups = [ti for ti in tick_tups if (ti[1] >= ilow) and (ti[1] <= ihigh)] + # so that we don't lose ticks on the end, expand out the interval ever so slightly. The + # "ever so slightly" is defined to be the width of a half of a pixel. We don't want to draw + # a tick that even one pixel outside of the defined axis interval. + if interval[0] <= interval[1]: + interval_expanded = interval + else: + interval_expanded = interval[1], interval[0] + + if hasattr(self, '_get_pixel_distance_along_axis'): + # normally, one does not want to catch all exceptions that + # could possibly happen, but it is not clear exactly what + # exceptions might arise from a user's projection (their + # rendition of the Axis object). So, we catch all, with + # the idea that one would rather potentially lose a tick + # from one side of the axis or another, rather than see a + # stack trace. + try: + ds1 = self._get_pixel_distance_along_axis(interval_expanded[0], -0.5) + except: + warnings.warn("Unable to find pixel distance along axis for interval padding; assuming no interval padding needed.") + ds1 = 0.0 + try: + ds2 = self._get_pixel_distance_along_axis(interval_expanded[1], +0.5) + except: + warnings.warn("Unable to find pixel distance along axis for interval padding; assuming no interval padding needed.") + ds2 = 0.0 + interval_expanded = (interval_expanded[0] - ds1, + interval_expanded[1] + ds2) + ticks_to_draw = [] for tick, loc, label in tick_tups: if tick is None: continue - if not mtransforms.interval_contains(interval, loc): + if not mtransforms.interval_contains(interval_expanded, loc): continue tick.update_position(loc) tick.set_label1(label) @@ -1601,6 +1638,35 @@ def _get_offset_text(self): self.offset_text_position = 'bottom' return offsetText + def _get_pixel_distance_along_axis(self, where, perturb): + """ + Returns the amount, in data coordinates, that a single pixel corresponds to in the + locality given by "where", which is also given in data coordinates, and is an x coordinate. + "perturb" is the amount to perturb the pixel. Usually +0.5 or -0.5. + + Implementing this routine for an axis is optional; if present, it will ensure that no + ticks are lost due to round-off at the extreme ends of an axis. + """ + + # Note that this routine does not work for a polar axis, because of the 1e-10 below. To + # do things correctly, we need to use rmax instead of 1e-10 for a polar axis. But + # since we do not have that kind of information at this point, we just don't try to + # pad anything for the theta axis of a polar plot. + if self.axes.name == 'polar': + return 0.0 + + # + # first figure out the pixel location of the "where" point. We use 1e-10 for the + # y point, so that we remain compatible with log axes. + # + trans = self.axes.transData # transformation from data coords to display coords + transinv = trans.inverted() # transformation from display coords to data coords + pix = trans.transform_point((where, 1e-10)) + ptp = transinv.transform_point((pix[0] + perturb, pix[1])) # perturb the pixel. + dx = abs(ptp[0] - where) + + return dx + def get_label_position(self): """ Return the label position (top or bottom) @@ -1849,9 +1915,10 @@ def _get_label(self): size=rcParams['axes.labelsize'], weight=rcParams['axes.labelweight']), color=rcParams['axes.labelcolor'], - verticalalignment='center', - horizontalalignment='right', + verticalalignment='bottom', + horizontalalignment='center', rotation='vertical', + rotation_mode='anchor', ) label.set_transform(mtransforms.blended_transform_factory( mtransforms.IdentityTransform(), self.axes.transAxes)) @@ -1875,6 +1942,27 @@ def _get_offset_text(self): self.offset_text_position = 'left' return offsetText + def _get_pixel_distance_along_axis(self, where, perturb): + """ + Returns the amount, in data coordinates, that a single pixel corresponds to in the + locality given by "where", which is also given in data coordinates, and is an y coordinate. + "perturb" is the amount to perturb the pixel. Usually +0.5 or -0.5. + + Implementing this routine for an axis is optional; if present, it will ensure that no + ticks are lost due to round-off at the extreme ends of an axis. + """ + + # + # first figure out the pixel location of the "where" point. We use 1e-10 for the + # x point, so that we remain compatible with log axes. + # + trans = self.axes.transData # transformation from data coords to display coords + transinv = trans.inverted() # transformation from display coords to data coords + pix = trans.transform_point((1e-10, where)) + ptp = transinv.transform_point((pix[0], pix[1] + perturb)) # perturb the pixel. + dy = abs(ptp[1] - where) + return dy + def get_label_position(self): """ Return the label position (left or right) @@ -1888,10 +1976,12 @@ def set_label_position(self, position): ACCEPTS: [ 'left' | 'right' ] """ assert position == 'left' or position == 'right' - if position == 'right': - self.label.set_horizontalalignment('left') + self.label.set_rotation_mode('anchor') + self.label.set_horizontalalignment('center') + if position == 'left': + self.label.set_verticalalignment('bottom') else: - self.label.set_horizontalalignment('right') + self.label.set_verticalalignment('top') self.label_position = position def _update_label_position(self, bboxes, bboxes2): diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 8abff141cc3a..b8c6dc8f97cb 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -28,7 +28,10 @@ """ from __future__ import division, print_function -import os, warnings, time, io +import os +import warnings +import time +import io import numpy as np import matplotlib.cbook as cbook @@ -38,15 +41,15 @@ #import matplotlib.path as path from matplotlib import rcParams from matplotlib import is_interactive +from matplotlib import get_backend from matplotlib._pylab_helpers import Gcf from matplotlib.transforms import Bbox, TransformedBbox, Affine2D -import cStringIO import matplotlib.tight_bbox as tight_bbox import matplotlib.textpath as textpath from matplotlib.path import Path -from matplotlib import MatplotlibDeprecationWarning as mplDeprecation +from matplotlib.cbook import mplDeprecation try: from PIL import Image @@ -56,6 +59,7 @@ _backend_d = {} + def register_backend(format, backend_class): _backend_d[format] = backend_class @@ -97,6 +101,10 @@ def __call__(self, block=None): # IPython versions >= 0.10 tack the _needmain # attribute onto pyplot.show, and always set # it to False, when in --pylab mode. + ipython_pylab = ipython_pylab and get_backend() != 'WebAgg' + # TODO: The above is a hack to get the WebAgg backend + # working with `ipython --pylab` until proper integration + # is implemented. except AttributeError: ipython_pylab = False @@ -105,14 +113,13 @@ def __call__(self, block=None): if ipython_pylab: return - if not is_interactive(): + if not is_interactive() or get_backend() == 'WebAgg': self.mainloop() def mainloop(self): pass - class RendererBase: """An abstract base class to handle drawing/rendering operations. @@ -157,7 +164,8 @@ def draw_path(self, gc, path, transform, rgbFace=None): """ raise NotImplementedError - def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): + def draw_markers(self, gc, marker_path, marker_trans, path, + trans, rgbFace=None): """ Draws a marker at each of the vertices in path. This includes all vertices, including control points on curves. To avoid @@ -180,9 +188,10 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None) """ for vertices, codes in path.iter_segments(trans, simplify=False): if len(vertices): - x,y = vertices[-2:] + x, y = vertices[-2:] self.draw_path(gc, marker_path, - marker_trans + transforms.Affine2D().translate(x, y), + marker_trans + + transforms.Affine2D().translate(x, y), rgbFace) def draw_path_collection(self, gc, master_transform, paths, all_transforms, @@ -212,15 +221,16 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, """ path_ids = [] for path, transform in self._iter_collection_raw_paths( - master_transform, paths, all_transforms): + master_transform, paths, all_transforms): path_ids.append((path, transform)) for xo, yo, path_id, gc0, rgbFace in self._iter_collection( gc, master_transform, all_transforms, path_ids, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, - antialiaseds, urls, offset_position): + antialiaseds, urls, offset_position): path, transform = path_id - transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo) + transform = transforms.Affine2D( + transform.get_matrix()).translate(xo, yo) self.draw_path(gc0, path, transform, rgbFace) def draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, @@ -290,9 +300,9 @@ def _iter_collection_raw_paths(self, master_transform, paths, The backend should take each yielded path and transform and create an object that can be referenced (reused) later. """ - Npaths = len(paths) + Npaths = len(paths) Ntransforms = len(all_transforms) - N = max(Npaths, Ntransforms) + N = max(Npaths, Ntransforms) if Npaths == 0: return @@ -334,15 +344,15 @@ def _iter_collection(self, gc, master_transform, all_transforms, use for filling the path. """ Ntransforms = len(all_transforms) - Npaths = len(path_ids) - Noffsets = len(offsets) - N = max(Npaths, Noffsets) + Npaths = len(path_ids) + Noffsets = len(offsets) + N = max(Npaths, Noffsets) Nfacecolors = len(facecolors) Nedgecolors = len(edgecolors) Nlinewidths = len(linewidths) Nlinestyles = len(linestyles) - Naa = len(antialiaseds) - Nurls = len(urls) + Naa = len(antialiaseds) + Nurls = len(urls) if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: return @@ -352,8 +362,6 @@ def _iter_collection(self, gc, master_transform, all_transforms, gc0 = self.new_gc() gc0.copy_properties(gc) - original_alpha = gc.get_alpha() - if Nfacecolors == 0: rgbFace = None @@ -367,7 +375,8 @@ def _iter_collection(self, gc, master_transform, all_transforms, xo, yo = toffsets[i % Noffsets] if offset_position == 'data': if Ntransforms: - transform = all_transforms[i % Ntransforms] + master_transform + transform = (all_transforms[i % Ntransforms] + + master_transform) else: transform = master_transform xo, yo = transform.transform_point((xo, yo)) @@ -376,7 +385,6 @@ def _iter_collection(self, gc, master_transform, all_transforms, yo = -(yp - yo) if not (np.isfinite(xo) and np.isfinite(yo)): continue - gc0.set_alpha(original_alpha) if Nfacecolors: rgbFace = facecolors[i % Nfacecolors] if Nedgecolors: @@ -389,16 +397,12 @@ def _iter_collection(self, gc, master_transform, all_transforms, if fg[3] == 0.0: gc0.set_linewidth(0) else: - gc0.set_alpha(gc0.get_alpha() * fg[3]) - gc0.set_foreground(fg[:3]) + gc0.set_foreground(fg) else: gc0.set_foreground(fg) if rgbFace is not None and len(rgbFace) == 4: if rgbFace[3] == 0: rgbFace = None - else: - gc0.set_alpha(gc0.get_alpha() * rgbFace[3]) - rgbFace = rgbFace[:3] gc0.set_antialiased(antialiaseds[i % Naa]) if Nurls: gc0.set_url(urls[i % Nurls]) @@ -448,12 +452,12 @@ def option_scale_image(self): """ return False - def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): + def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): """ """ self._draw_text_as_path(gc, x, y, s, prop, angle, ismath="TeX") - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): """ Draw the text instance @@ -464,10 +468,10 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False): the x location of the text in display coords *y* - the y location of the text in display coords + the y location of the text baseline in display coords *s* - a :class:`matplotlib.text.Text` instance + the text string *prop* a :class:`matplotlib.font_manager.FontProperties` instance @@ -475,6 +479,9 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False): *angle* the rotation angle in degrees + *mtext* + a :class:`matplotlib.text.Text` instance + **backend implementers note** When you are trying to determine if you have gotten your bounding box @@ -483,7 +490,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False): if 0: bbox_artist(self, renderer) - to if 1, and then the actual bounding box will be blotted along with + to if 1, and then the actual bounding box will be plotted along with your text. """ @@ -510,24 +517,25 @@ def _get_text_path_transform(self, x, y, s, prop, angle, ismath): fontsize = self.points_to_pixels(prop.get_size_in_points()) if ismath == "TeX": - verts, codes = text2path.get_text_path(prop, s, ismath=False, usetex=True) + verts, codes = text2path.get_text_path(prop, s, ismath=False, + usetex=True) else: - verts, codes = text2path.get_text_path(prop, s, ismath=ismath, usetex=False) + verts, codes = text2path.get_text_path(prop, s, ismath=ismath, + usetex=False) path = Path(verts, codes) - angle = angle/180.*3.141592 + angle = angle / 180. * 3.141592 if self.flipy(): - transform = Affine2D().scale(fontsize/text2path.FONT_SCALE, - fontsize/text2path.FONT_SCALE).\ - rotate(angle).translate(x, self.height-y) + transform = Affine2D().scale(fontsize / text2path.FONT_SCALE, + fontsize / text2path.FONT_SCALE) + transform = transform.rotate(angle).translate(x, self.height - y) else: - transform = Affine2D().scale(fontsize/text2path.FONT_SCALE, - fontsize/text2path.FONT_SCALE).\ - rotate(angle).translate(x, y) + transform = Affine2D().scale(fontsize / text2path.FONT_SCALE, + fontsize / text2path.FONT_SCALE) + transform = transform.rotate(angle).translate(x, y) return path, transform - def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): """ draw the text by converting them to paths using textpath module. @@ -545,20 +553,20 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): If True, use mathtext parser. If "TeX", use *usetex* mode. """ - path, transform = self._get_text_path_transform(x, y, s, prop, angle, ismath) - color = gc.get_rgb()[:3] + path, transform = self._get_text_path_transform( + x, y, s, prop, angle, ismath) + color = gc.get_rgb() gc.set_linewidth(0.0) self.draw_path(gc, path, transform, rgbFace=color) - def get_text_width_height_descent(self, s, prop, ismath): """ get the width and height, and the offset from the bottom to the baseline (descent), in display coords of the string s with :class:`~matplotlib.font_manager.FontProperties` prop """ - if ismath=='TeX': + if ismath == 'TeX': # todo: handle props size = prop.get_size_in_points() texmanager = self._text2path.get_texmanager() @@ -568,17 +576,16 @@ def get_text_width_height_descent(self, s, prop, ismath): return w, h, d dpi = self.points_to_pixels(72) - fontscale = self._text2path.FONT_SCALE if ismath: - width, height, descent, glyphs, rects = \ - self._text2path.mathtext_parser.parse(s, dpi, prop) - return width, height, descent + dims = self._text2path.mathtext_parser.parse(s, dpi, prop) + return dims[0:3] # return width, height, descent flags = self._text2path._get_hinting_flag() font = self._text2path._get_font(prop) size = prop.get_size_in_points() font.set_size(size, dpi) - font.set_text(s, 0.0, flags=flags) # the width and height of unrotated string + # the width and height of unrotated string + font.set_text(s, 0.0, flags=flags) w, h = font.get_width_height() d = font.get_descent() w /= 64.0 # convert from subpixels @@ -586,7 +593,6 @@ def get_text_width_height_descent(self, s, prop, ismath): d /= 64.0 return w, h, d - def flipy(self): """ Return true if y small numbers are top for renderer Is used @@ -608,7 +614,6 @@ def get_texmanager(self): self._texmanager = TexManager() return self._texmanager - def new_gc(self): """ Return an instance of a :class:`GraphicsContextBase` @@ -673,15 +678,15 @@ class GraphicsContextBase: # a mapping from dash styles to suggested offset, dash pairs dashd = { - 'solid' : (None, None), - 'dashed' : (0, (6.0, 6.0)), - 'dashdot' : (0, (3.0, 5.0, 1.0, 5.0)), - 'dotted' : (0, (1.0, 3.0)), - } + 'solid': (None, None), + 'dashed': (0, (6.0, 6.0)), + 'dashdot': (0, (3.0, 5.0, 1.0, 5.0)), + 'dotted': (0, (1.0, 3.0)), + } def __init__(self): self._alpha = 1.0 - self._forced_alpha = False # if True, _alpha overrides A from RGBA + self._forced_alpha = False # if True, _alpha overrides A from RGBA self._antialiased = 1 # use 0,1 not True, False for extension code self._capstyle = 'butt' self._cliprect = None @@ -690,15 +695,18 @@ def __init__(self): self._joinstyle = 'round' self._linestyle = 'solid' self._linewidth = 1 - self._rgb = (0.0, 0.0, 0.0) + self._rgb = (0.0, 0.0, 0.0, 1.0) + self._orig_color = (0.0, 0.0, 0.0, 1.0) self._hatch = None self._url = None self._gid = None self._snap = None + self._sketch = None def copy_properties(self, gc): 'Copy properties from gc to self' self._alpha = gc._alpha + self._forced_alpha = gc._forced_alpha self._antialiased = gc._antialiased self._capstyle = gc._capstyle self._cliprect = gc._cliprect @@ -708,10 +716,12 @@ def copy_properties(self, gc): self._linestyle = gc._linestyle self._linewidth = gc._linewidth self._rgb = gc._rgb + self._orig_color = gc._orig_color self._hatch = gc._hatch self._url = gc._url self._gid = gc._gid self._snap = gc._snap + self._sketch = gc._sketch def restore(self): """ @@ -739,7 +749,8 @@ def get_capstyle(self): def get_clip_rectangle(self): """ - Return the clip rectangle as a :class:`~matplotlib.transforms.Bbox` instance + Return the clip rectangle as a :class:`~matplotlib.transforms.Bbox` + instance """ return self._cliprect @@ -768,6 +779,13 @@ def get_dashes(self): """ return self._dashes + def get_forced_alpha(self): + """ + Return whether the value given by get_alpha() should be used to + override any other alpha-channel values. + """ + return self._forced_alpha + def get_joinstyle(self): """ Return the line join style as one of ('miter', 'round', 'bevel') @@ -820,14 +838,19 @@ def get_snap(self): def set_alpha(self, alpha): """ - Set the alpha value used for blending - not supported on - all backends + Set the alpha value used for blending - not supported on all backends. + If ``alpha=None`` (the default), the alpha components of the + foreground and fill colors will be used to set their respective + transparencies (where applicable); otherwise, ``alpha`` will override + them. """ if alpha is not None: self._alpha = alpha self._forced_alpha = True else: + self._alpha = 1.0 self._forced_alpha = False + self.set_foreground(self._orig_color) def set_antialiased(self, b): """ @@ -835,8 +858,10 @@ def set_antialiased(self, b): """ # use 0, 1 to make life easier on extension code trying to read the gc - if b: self._antialiased = 1 - else: self._antialiased = 0 + if b: + self._antialiased = 1 + else: + self._antialiased = 0 def set_capstyle(self, cs): """ @@ -869,39 +894,38 @@ def set_dashes(self, dash_offset, dash_list): is the offset (usually 0). *dash_list* - specifies the on-off sequence as points. ``(None, None)`` specifies a solid line + specifies the on-off sequence as points. + ``(None, None)`` specifies a solid line """ if dash_list is not None: - dash_list = np.asarray(dash_list) - if np.any(dash_list <= 0.0): + dl = np.asarray(dash_list) + if np.any(dl <= 0.0): raise ValueError("All values in the dash list must be positive") self._dashes = dash_offset, dash_list - def set_foreground(self, fg, isRGB=False): + def set_foreground(self, fg, isRGBA=False): """ Set the foreground color. fg can be a MATLAB format string, a html hex color string, an rgb or rgba unit tuple, or a float between 0 and 1. In the latter case, grayscale is used. - If you know fg is rgb or rgba, set ``isRGB=True`` for - efficiency. + If you know fg is rgba, set ``isRGBA=True`` for efficiency. """ - if isRGB: + self._orig_color = fg + if self._forced_alpha: + self._rgb = colors.colorConverter.to_rgba(fg, self._alpha) + elif isRGBA: self._rgb = fg else: self._rgb = colors.colorConverter.to_rgba(fg) - if len(self._rgb) == 4 and not self._forced_alpha: - self.set_alpha(self._rgb[3]) - # Use set_alpha method here so that subclasses will - # be calling their own version, which may set their - # own attributes. def set_graylevel(self, frac): """ Set the foreground color to be a gray level with *frac* """ - self._rgb = (frac, frac, frac) + self._orig_color = frac + self._rgb = (frac, frac, frac, self._alpha) def set_joinstyle(self, js): """ @@ -930,7 +954,7 @@ def set_linestyle(self, style): 'dotted' : (0, (1.0, 3.0)), """ - if style in self.dashd.keys(): + if style in self.dashd: offset, dashes = self.dashd[style] elif isinstance(style, tuple): offset, dashes = style @@ -985,6 +1009,53 @@ def get_hatch_path(self, density=6.0): return None return Path.hatch(self._hatch, density) + def get_sketch_params(self): + """ + Returns the sketch parameters for the artist. + + Returns + ------- + sketch_params : tuple or `None` + + A 3-tuple with the following elements: + + * `scale`: The amplitude of the wiggle perpendicular to the + source line. + + * `length`: The length of the wiggle along the line. + + * `randomness`: The scale factor by which the length is + shrunken or expanded. + + May return `None` if no sketch parameters were set. + """ + return self._sketch + + def set_sketch_params(self, scale=None, length=None, randomness=None): + """ + Sets the the sketch parameters. + + Parameters + ---------- + + scale : float, optional + The amplitude of the wiggle perpendicular to the source + line, in pixels. If scale is `None`, or not provided, no + sketch filter will be provided. + + length : float, optional + The length of the wiggle along the line, in pixels + (default 128.0) + + randomness : float, optional + The scale factor by which the length is shrunken or + expanded (default 16.0) + """ + if scale is None: + self._sketch = None + else: + self._sketch = (scale, length or 128.0, randomness or 16.0) + class TimerBase(object): ''' @@ -1036,7 +1107,7 @@ def __init__(self, interval=None, callbacks=None): if callbacks is None: self.callbacks = [] else: - self.callbacks = callbacks[:] # Create a copy + self.callbacks = callbacks[:] # Create a copy if interval is None: self._interval = 1000 @@ -1125,13 +1196,15 @@ def _timer_set_single_shot(self): def _on_timer(self): ''' Runs all function that have been registered as callbacks. Functions - can return False if they should not be called any more. If there + can return False (or 0) if they should not be called any more. If there are no callbacks, the timer is automatically stopped. ''' - for func,args,kwargs in self.callbacks: + for func, args, kwargs in self.callbacks: ret = func(*args, **kwargs) + # docstring above explains why we use `if ret == False` here, + # instead of `if not ret`. if ret == False: - self.callbacks.remove((func,args,kwargs)) + self.callbacks.remove((func, args, kwargs)) if len(self.callbacks) == 0: self.stop() @@ -1154,11 +1227,12 @@ class Event: """ - def __init__(self, name, canvas,guiEvent=None): + def __init__(self, name, canvas, guiEvent=None): self.name = name self.canvas = canvas self.guiEvent = guiEvent + class IdleEvent(Event): """ An event triggered by the GUI backend when it is idle -- useful @@ -1166,11 +1240,13 @@ class IdleEvent(Event): """ pass + class DrawEvent(Event): """ An event triggered by a draw operation on the canvas - In addition to the :class:`Event` attributes, the following event attributes are defined: + In addition to the :class:`Event` attributes, the following event + attributes are defined: *renderer* the :class:`RendererBase` instance for the draw event @@ -1180,11 +1256,13 @@ def __init__(self, name, canvas, renderer): Event.__init__(self, name, canvas) self.renderer = renderer + class ResizeEvent(Event): """ An event triggered by a canvas resize - In addition to the :class:`Event` attributes, the following event attributes are defined: + In addition to the :class:`Event` attributes, the following event + attributes are defined: *width* width of the canvas in pixels @@ -1197,11 +1275,13 @@ def __init__(self, name, canvas): Event.__init__(self, name, canvas) self.width, self.height = canvas.get_width_height() + class CloseEvent(Event): """ An event triggered by a figure being closed - In addition to the :class:`Event` attributes, the following event attributes are defined: + In addition to the :class:`Event` attributes, the following event + attributes are defined: """ def __init__(self, name, canvas, guiEvent=None): Event.__init__(self, name, canvas, guiEvent) @@ -1233,25 +1313,23 @@ class LocationEvent(Event): y coord of mouse in data coords """ - x = None # x position - pixels from left of canvas - y = None # y position - pixels from right of canvas - inaxes = None # the Axes instance if mouse us over axes - xdata = None # x coord of mouse in data coords - ydata = None # y coord of mouse in data coords + x = None # x position - pixels from left of canvas + y = None # y position - pixels from right of canvas + inaxes = None # the Axes instance if mouse us over axes + xdata = None # x coord of mouse in data coords + ydata = None # y coord of mouse in data coords # the last event that was triggered before this one lastevent = None - def __init__(self, name, canvas, x, y,guiEvent=None): + def __init__(self, name, canvas, x, y, guiEvent=None): """ *x*, *y* in figure coords, 0,0 = bottom, left """ - Event.__init__(self, name, canvas,guiEvent=guiEvent) + Event.__init__(self, name, canvas, guiEvent=guiEvent) self.x = x self.y = y - - if x is None or y is None: # cannot check if event was in axes if no x,y info self.inaxes = None @@ -1260,28 +1338,30 @@ def __init__(self, name, canvas, x, y,guiEvent=None): # Find all axes containing the mouse if self.canvas.mouse_grabber is None: - axes_list = [a for a in self.canvas.figure.get_axes() if a.in_axes(self)] + axes_list = [a for a in self.canvas.figure.get_axes() + if a.in_axes(self)] else: axes_list = [self.canvas.mouse_grabber] - if len(axes_list) == 0: # None found + if len(axes_list) == 0: # None found self.inaxes = None self._update_enter_leave() return - elif (len(axes_list) > 1): # Overlap, get the highest zorder + elif (len(axes_list) > 1): # Overlap, get the highest zorder axes_list.sort(key=lambda x: x.zorder) - self.inaxes = axes_list[-1] # Use the highest zorder - else: # Just found one hit + self.inaxes = axes_list[-1] # Use the highest zorder + else: # Just found one hit self.inaxes = axes_list[0] try: - xdata, ydata = self.inaxes.transData.inverted().transform_point((x, y)) + trans = self.inaxes.transData.inverted() + xdata, ydata = trans.transform_point((x, y)) except ValueError: - self.xdata = None - self.ydata = None + self.xdata = None + self.ydata = None else: - self.xdata = xdata - self.ydata = ydata + self.xdata = xdata + self.ydata = ydata self._update_enter_leave() @@ -1289,7 +1369,7 @@ def _update_enter_leave(self): 'process the figure/axes enter leave events' if LocationEvent.lastevent is not None: last = LocationEvent.lastevent - if last.inaxes!=self.inaxes: + if last.inaxes != self.inaxes: # process axes enter/leave events try: if last.inaxes is not None: @@ -1314,8 +1394,10 @@ def _update_enter_leave(self): class MouseEvent(LocationEvent): """ - A mouse event ('button_press_event', 'button_release_event', 'scroll_event', - 'motion_notify_event'). + A mouse event ('button_press_event', + 'button_release_event', + 'scroll_event', + 'motion_notify_event'). In addition to the :class:`Event` and :class:`LocationEvent` attributes, the following attributes are defined: @@ -1340,14 +1422,14 @@ def on_press(event): cid = fig.canvas.mpl_connect('button_press_event', on_press) """ - x = None # x position - pixels from left of canvas - y = None # y position - pixels from right of canvas - button = None # button pressed None, 1, 2, 3 - dblclick = None # whether or not the event is the result of a double click - inaxes = None # the Axes instance if mouse us over axes - xdata = None # x coord of mouse in data coords - ydata = None # y coord of mouse in data coords - step = None # scroll steps for scroll events + x = None # x position - pixels from left of canvas + y = None # y position - pixels from right of canvas + button = None # button pressed None, 1, 2, 3 + dblclick = None # whether or not the event is the result of a double click + inaxes = None # the Axes instance if mouse us over axes + xdata = None # x coord of mouse in data coords + ydata = None # y coord of mouse in data coords + step = None # scroll steps for scroll events def __init__(self, name, canvas, x, y, button=None, key=None, step=0, dblclick=False, guiEvent=None): @@ -1364,7 +1446,8 @@ def __init__(self, name, canvas, x, y, button=None, key=None, def __str__(self): return ("MPL MouseEvent: xy=(%d,%d) xydata=(%s,%s) button=%d " + "dblclick=%s inaxes=%s") % (self.x, self.y, self.xdata, - self.ydata, self.button, self.dblclick, self.inaxes) + self.ydata, self.button, + self.dblclick, self.inaxes) class PickEvent(Event): @@ -1400,7 +1483,8 @@ def on_pick(event): cid = fig.canvas.mpl_connect('pick_event', on_pick) """ - def __init__(self, name, canvas, mouseevent, artist, guiEvent=None, **kwargs): + def __init__(self, name, canvas, mouseevent, artist, + guiEvent=None, **kwargs): Event.__init__(self, name, canvas, guiEvent) self.mouseevent = mouseevent self.artist = artist @@ -1421,7 +1505,7 @@ class KeyEvent(LocationEvent): the key(s) pressed. Could be **None**, a single case sensitive ascii character ("g", "G", "#", etc.), a special key ("control", "shift", "f1", "up", etc.) or a - combination of the above (e.g. "ctrl+alt+g", "ctrl+alt+G"). + combination of the above (e.g., "ctrl+alt+g", "ctrl+alt+G"). .. note:: @@ -1470,7 +1554,9 @@ class FigureCanvasBase(object): 'axes_enter_event', 'axes_leave_event', 'close_event' - ] + ] + + supports_blit = True def __init__(self, figure): figure.set_canvas(self) @@ -1478,17 +1564,17 @@ def __init__(self, figure): # a dictionary from event name to a dictionary that maps cid->func self.callbacks = cbook.CallbackRegistry() self.widgetlock = widgets.LockDraw() - self._button = None # the button pressed - self._key = None # the key pressed + self._button = None # the button pressed + self._key = None # the key pressed self._lastx, self._lasty = None, None - self.button_pick_id = self.mpl_connect('button_press_event',self.pick) - self.scroll_pick_id = self.mpl_connect('scroll_event',self.pick) - self.mouse_grabber = None # the axes currently grabbing mouse + self.button_pick_id = self.mpl_connect('button_press_event', self.pick) + self.scroll_pick_id = self.mpl_connect('scroll_event', self.pick) + self.mouse_grabber = None # the axes currently grabbing mouse self.toolbar = None # NavigationToolbar2 will set me self._is_saving = False if False: ## highlight the artists that are hit - self.mpl_connect('motion_notify_event',self.onHilite) + self.mpl_connect('motion_notify_event', self.onHilite) ## delete the artists that are clicked on #self.mpl_disconnect(self.button_pick_id) #self.mpl_connect('button_press_event',self.onRemove) @@ -1511,19 +1597,19 @@ def onRemove(self, ev): def sort_artists(artists): # This depends on stable sort and artists returned # from get_children in z order. - L = [ (h.zorder, h) for h in artists ] + L = [(h.zorder, h) for h in artists] L.sort() - return [ h for zorder, h in L ] + return [h for zorder, h in L] # Find the top artist under the cursor under = sort_artists(self.figure.hitlist(ev)) h = None - if under: h = under[-1] + if under: + h = under[-1] # Try deleting that artist, or its parent if you # can't delete the artist while h: - print("Removing",h) if h.remove(): self.draw_idle() break @@ -1542,7 +1628,8 @@ def onHilite(self, ev): canvas.mpl_connect('motion_notify_event',canvas.onHilite) """ - if not hasattr(self,'_active'): self._active = dict() + if not hasattr(self, '_active'): + self._active = dict() under = self.figure.hitlist(ev) enter = [a for a in under if a not in self._active] @@ -1552,9 +1639,9 @@ def onHilite(self, ev): #print "leaving:",[str(a) for a in leave] # On leave restore the captured colour for a in leave: - if hasattr(a,'get_color'): + if hasattr(a, 'get_color'): a.set_color(self._active[a]) - elif hasattr(a,'get_edgecolor'): + elif hasattr(a, 'get_edgecolor'): a.set_edgecolor(self._active[a][0]) a.set_facecolor(self._active[a][1]) del self._active[a] @@ -1563,18 +1650,20 @@ def onHilite(self, ev): # be done first in case the parent recolouring affects # the child. for a in enter: - if hasattr(a,'get_color'): + if hasattr(a, 'get_color'): self._active[a] = a.get_color() - elif hasattr(a,'get_edgecolor'): - self._active[a] = (a.get_edgecolor(),a.get_facecolor()) - else: self._active[a] = None + elif hasattr(a, 'get_edgecolor'): + self._active[a] = (a.get_edgecolor(), a.get_facecolor()) + else: + self._active[a] = None for a in enter: - if hasattr(a,'get_color'): + if hasattr(a, 'get_color'): a.set_color('red') - elif hasattr(a,'get_edgecolor'): + elif hasattr(a, 'get_edgecolor'): a.set_edgecolor('red') a.set_facecolor('lightblue') - else: self._active[a] = None + else: + self._active[a] = None self.draw_idle() def pick(self, mouseevent): @@ -1637,7 +1726,8 @@ def key_press_event(self, key, guiEvent=None): """ self._key = key s = 'key_press_event' - event = KeyEvent(s, self, key, self._lastx, self._lasty, guiEvent=guiEvent) + event = KeyEvent( + s, self, key, self._lastx, self._lasty, guiEvent=guiEvent) self.callbacks.process(s, event) def key_release_event(self, key, guiEvent=None): @@ -1646,7 +1736,8 @@ def key_release_event(self, key, guiEvent=None): 'key_release_event' with a :class:`KeyEvent` """ s = 'key_release_event' - event = KeyEvent(s, self, key, self._lastx, self._lasty, guiEvent=guiEvent) + event = KeyEvent( + s, self, key, self._lastx, self._lasty, guiEvent=guiEvent) self.callbacks.process(s, event) self._key = None @@ -1677,7 +1768,6 @@ def scroll_event(self, x, y, step, guiEvent=None): step=step, guiEvent=guiEvent) self.callbacks.process(s, mouseevent) - def button_press_event(self, x, y, button, dblclick=False, guiEvent=None): """ Backend derived classes should call this function on any mouse @@ -1797,7 +1887,8 @@ def release_mouse(self, ax): """ Release the mouse grab held by the axes, ax. Usually called by the widgets. - It is ok to call this even if you ax doesn't have the mouse grab currently. + It is ok to call this even if you ax doesn't have the mouse + grab currently. """ if self.mouse_grabber is ax: self.mouse_grabber = None @@ -1829,17 +1920,15 @@ def get_width_height(self): return int(self.figure.bbox.width), int(self.figure.bbox.height) filetypes = { - 'emf': 'Enhanced Metafile', 'eps': 'Encapsulated Postscript', 'pdf': 'Portable Document Format', 'pgf': 'LaTeX PGF Figure', 'png': 'Portable Network Graphics', - 'ps' : 'Postscript', + 'ps': 'Postscript', 'raw': 'Raw RGBA bitmap', 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', - 'svgz': 'Scalable Vector Graphics' - } + 'svgz': 'Scalable Vector Graphics'} # All of these print_* functions do a lazy import because # a) otherwise we'd have cyclical imports, since all of these @@ -1852,62 +1941,60 @@ def get_width_height(self): # >>> import matplotlib.tests.test_spines # >>> list(matplotlib.tests.test_spines.test_spines_axes_positions())[0][0]() - def print_emf(self, *args, **kwargs): - from backends.backend_emf import FigureCanvasEMF # lazy import - emf = self.switch_backends(FigureCanvasEMF) - return emf.print_emf(*args, **kwargs) - def print_eps(self, *args, **kwargs): - from backends.backend_ps import FigureCanvasPS # lazy import + from backends.backend_ps import FigureCanvasPS # lazy import ps = self.switch_backends(FigureCanvasPS) return ps.print_eps(*args, **kwargs) def print_pdf(self, *args, **kwargs): - from backends.backend_pdf import FigureCanvasPdf # lazy import + from backends.backend_pdf import FigureCanvasPdf # lazy import pdf = self.switch_backends(FigureCanvasPdf) return pdf.print_pdf(*args, **kwargs) def print_pgf(self, *args, **kwargs): - from backends.backend_pgf import FigureCanvasPgf # lazy import + from backends.backend_pgf import FigureCanvasPgf # lazy import pgf = self.switch_backends(FigureCanvasPgf) return pgf.print_pgf(*args, **kwargs) def print_png(self, *args, **kwargs): - from backends.backend_agg import FigureCanvasAgg # lazy import + from backends.backend_agg import FigureCanvasAgg # lazy import agg = self.switch_backends(FigureCanvasAgg) return agg.print_png(*args, **kwargs) def print_ps(self, *args, **kwargs): - from backends.backend_ps import FigureCanvasPS # lazy import + from backends.backend_ps import FigureCanvasPS # lazy import ps = self.switch_backends(FigureCanvasPS) return ps.print_ps(*args, **kwargs) def print_raw(self, *args, **kwargs): - from backends.backend_agg import FigureCanvasAgg # lazy import + from backends.backend_agg import FigureCanvasAgg # lazy import agg = self.switch_backends(FigureCanvasAgg) return agg.print_raw(*args, **kwargs) - print_bmp = print_rgb = print_raw + print_bmp = print_rgba = print_raw def print_svg(self, *args, **kwargs): - from backends.backend_svg import FigureCanvasSVG # lazy import + from backends.backend_svg import FigureCanvasSVG # lazy import svg = self.switch_backends(FigureCanvasSVG) return svg.print_svg(*args, **kwargs) def print_svgz(self, *args, **kwargs): - from backends.backend_svg import FigureCanvasSVG # lazy import + from backends.backend_svg import FigureCanvasSVG # lazy import svg = self.switch_backends(FigureCanvasSVG) return svg.print_svgz(*args, **kwargs) if _has_pil: - filetypes['jpg'] = filetypes['jpeg'] = 'Joint Photographic Experts Group' + filetypes['jpg'] = 'Joint Photographic Experts Group' + filetypes['jpeg'] = filetypes['jpg'] + 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. + 95 (best). The default is 95, if not given in the + matplotlibrc file in the savefig.jpeg_quality parameter. + 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 @@ -1916,22 +2003,29 @@ def print_jpg(self, filename_or_obj, *args, **kwargs): *progressive*: If present, indicates that this image should be stored as a progressive JPEG file. """ - from backends.backend_agg import FigureCanvasAgg # lazy import + from backends.backend_agg import FigureCanvasAgg # lazy import agg = self.switch_backends(FigureCanvasAgg) buf, size = agg.print_to_buffer() - if kwargs.pop("dryrun", False): return + if kwargs.pop("dryrun", False): + return image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) options = cbook.restrict_dict(kwargs, ['quality', 'optimize', 'progressive']) + + if 'quality' not in options: + options['quality'] = rcParams['savefig.jpeg_quality'] + return image.save(filename_or_obj, format='jpeg', **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 + from backends.backend_agg import FigureCanvasAgg # lazy import agg = self.switch_backends(FigureCanvasAgg) buf, size = agg.print_to_buffer() - if kwargs.pop("dryrun", False): return + if kwargs.pop("dryrun", False): + return image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) dpi = (self.figure.dpi, self.figure.dpi) return image.save(filename_or_obj, format='tiff', @@ -2037,7 +2131,6 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w', if dpi is None: dpi = rcParams['savefig.dpi'] - origDPI = self.figure.dpi origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() @@ -2050,7 +2143,6 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w', if bbox_inches is None: bbox_inches = rcParams['savefig.bbox'] - if bbox_inches: # call adjust_bbox to save only the given area if bbox_inches == "tight": @@ -2076,20 +2168,31 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w', renderer = self.figure._cachedRenderer bbox_inches = self.figure.get_tightbbox(renderer) - bbox_extra_artists = kwargs.pop("bbox_extra_artists", None) - if bbox_extra_artists is None: - bbox_extra_artists = self.figure.get_default_bbox_extra_artists() - - bb = [a.get_window_extent(renderer) for a in bbox_extra_artists] + bbox_artists = kwargs.pop("bbox_extra_artists", None) + if bbox_artists is None: + bbox_artists = self.figure.get_default_bbox_extra_artists() + + bbox_filtered = [] + for a in bbox_artists: + bbox = a.get_window_extent(renderer) + if a.get_clip_on(): + clip_box = a.get_clip_box() + if clip_box is not None: + bbox = Bbox.intersection(bbox, clip_box) + clip_path = a.get_clip_path() + if clip_path is not None and bbox is not None: + clip_path = clip_path.get_fully_transformed_path() + bbox = Bbox.intersection(bbox, + clip_path.get_extents()) + if bbox is not None and (bbox.width != 0 or + bbox.height != 0): + bbox_filtered.append(bbox) - bbox_filtered = [b for b in bb if b.width!=0 or b.height!=0] if bbox_filtered: _bbox = Bbox.union(bbox_filtered) - - bbox_inches1 = TransformedBbox(_bbox, - Affine2D().scale(1./self.figure.dpi)) - - bbox_inches = Bbox.union([bbox_inches, bbox_inches1]) + trans = Affine2D().scale(1.0 / self.figure.dpi) + bbox_extra = TransformedBbox(_bbox, trans) + bbox_inches = Bbox.union([bbox_inches, bbox_extra]) pad = kwargs.pop("pad_inches", None) if pad is None: @@ -2234,9 +2337,10 @@ def mpl_disconnect(self, cid): 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. + 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: @@ -2255,7 +2359,7 @@ def flush_events(self): """ raise NotImplementedError - def start_event_loop(self,timeout): + def start_event_loop(self, timeout): """ Start an event loop. This is used to start a blocking event loop so that interactive functions, such as ginput and @@ -2277,7 +2381,7 @@ def stop_event_loop(self): """ raise NotImplementedError - def start_event_loop_default(self,timeout=0): + def start_event_loop_default(self, timeout=0): """ Start an event loop. This is used to start a blocking event loop so that interactive functions, such as ginput and @@ -2302,11 +2406,12 @@ def start_event_loop_default(self,timeout=0): str += " to this GUI is implemented" warnings.warn(str, mplDeprecation) - if timeout <= 0: timeout = np.inf + if timeout <= 0: + timeout = np.inf timestep = 0.01 counter = 0 self._looping = True - while self._looping and counter*timestep < timeout: + while self._looping and counter * timestep < timeout: self.flush_events() time.sleep(timestep) counter += 1 @@ -2415,25 +2520,27 @@ def key_press_handler(event, canvas, toolbar=None): ax.set_xscale('log') ax.figure.canvas.draw() - elif (event.key.isdigit() and event.key!='0') or event.key in all: + elif (event.key.isdigit() and event.key != '0') or event.key in all: # keys in list 'all' enables all axes (default key 'a'), # otherwise if key is a number only enable this particular axes # if it was the axes, where the event was raised if not (event.key in all): - n = int(event.key)-1 + n = int(event.key) - 1 for i, a in enumerate(canvas.figure.get_axes()): # consider axes, in which the event was raised # FIXME: Why only this axes? if event.x is not None and event.y is not None \ - and a.in_axes(event): + and a.in_axes(event): if event.key in all: a.set_navigate(True) else: - a.set_navigate(i==n) + a.set_navigate(i == n) + class NonGuiException(Exception): pass + class FigureManagerBase: """ Helper class for pyplot mode, wraps everything up into a neat bundle @@ -2454,7 +2561,8 @@ def __init__(self, canvas, num): self.key_press_handler_id = self.canvas.mpl_connect('key_press_event', self.key_press) """ - The returned id from connecting the default key handler via :meth:`FigureCanvasBase.mpl_connnect`. + The returned id from connecting the default key handler via + :meth:`FigureCanvasBase.mpl_connnect`. To disable default key press handling:: @@ -2577,7 +2685,7 @@ class NavigationToolbar2(object): (None, None, None, None), ('Subplots', 'Configure subplots', 'subplots', 'configure_subplots'), ('Save', 'Save the figure', 'filesave', 'save_figure'), - ) + ) def __init__(self, canvas): self.canvas = canvas @@ -2585,18 +2693,21 @@ def __init__(self, canvas): # a dict from axes index to a list of view limits self._views = cbook.Stack() self._positions = cbook.Stack() # stack of subplot positions - self._xypress = None # the location and axis info at the time of the press + self._xypress = None # the location and axis info at the time + # of the press self._idPress = None self._idRelease = None self._active = None self._lastCursor = None self._init_toolbar() - self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.mouse_move) + self._idDrag = self.canvas.mpl_connect( + 'motion_notify_event', self.mouse_move) self._ids_zoom = [] self._zoom_mode = None - self._button_pressed = None # determined by the button pressed at start + self._button_pressed = None # determined by the button pressed + # at start self.mode = '' # a mode string for the status bar self.set_history_buttons() @@ -2661,11 +2772,11 @@ def mouse_move(self, event): self.set_cursor(cursors.POINTER) self._lastCursor = cursors.POINTER else: - if self._active=='ZOOM': + if self._active == 'ZOOM': if self._lastCursor != cursors.SELECT_REGION: self.set_cursor(cursors.SELECT_REGION) self._lastCursor = cursors.SELECT_REGION - elif (self._active=='PAN' and + elif (self._active == 'PAN' and self._lastCursor != cursors.MOVE): self.set_cursor(cursors.MOVE) @@ -2682,9 +2793,10 @@ def mouse_move(self, event): self.set_message('%s, %s' % (self.mode, s)) else: self.set_message(s) - else: self.set_message(self.mode) + else: + self.set_message(self.mode) - def pan(self,*args): + def pan(self, *args): """Activate the pan/zoom tool. pan with left button, zoom with right""" # set the pointer icon and button press funcs to the # appropriate callbacks @@ -2724,51 +2836,53 @@ def press_pan(self, event): """the press mouse button in pan/zoom mode callback""" if event.button == 1: - self._button_pressed=1 - elif event.button == 3: - self._button_pressed=3 + self._button_pressed = 1 + elif event.button == 3: + self._button_pressed = 3 else: - self._button_pressed=None + self._button_pressed = None return x, y = event.x, event.y # push the current view to define home if stack is empty - if self._views.empty(): self.push_current() + if self._views.empty(): + self.push_current() - self._xypress=[] + self._xypress = [] for i, a in enumerate(self.canvas.figure.get_axes()): if (x is not None and y is not None and a.in_axes(event) and - a.get_navigate() and a.can_pan()) : + a.get_navigate() and a.can_pan()): a.start_pan(x, y, event.button) self._xypress.append((a, i)) self.canvas.mpl_disconnect(self._idDrag) - self._idDrag=self.canvas.mpl_connect('motion_notify_event', - self.drag_pan) + self._idDrag = self.canvas.mpl_connect('motion_notify_event', + self.drag_pan) self.press(event) def press_zoom(self, event): """the press mouse button in zoom to rect mode callback""" if event.button == 1: - self._button_pressed=1 - elif event.button == 3: - self._button_pressed=3 + self._button_pressed = 1 + elif event.button == 3: + self._button_pressed = 3 else: - self._button_pressed=None + self._button_pressed = None return x, y = event.x, event.y # push the current view to define home if stack is empty - if self._views.empty(): self.push_current() + if self._views.empty(): + self.push_current() - self._xypress=[] + self._xypress = [] for i, a in enumerate(self.canvas.figure.get_axes()): if (x is not None and y is not None and a.in_axes(event) and - a.get_navigate() and a.can_zoom()) : - self._xypress.append(( x, y, a, i, a.viewLim.frozen(), - a.transData.frozen() )) + a.get_navigate() and a.can_zoom()): + self._xypress.append((x, y, a, i, a.viewLim.frozen(), + a.transData.frozen())) id1 = self.canvas.mpl_connect('motion_notify_event', self.drag_zoom) id2 = self.canvas.mpl_connect('key_press_event', @@ -2791,15 +2905,16 @@ def _switch_off_zoom_mode(self, event): def push_current(self): """push the current view limits and position onto the stack""" - lims = []; pos = [] + lims = [] + pos = [] for a in self.canvas.figure.get_axes(): xmin, xmax = a.get_xlim() ymin, ymax = a.get_ylim() - lims.append( (xmin, xmax, ymin, ymax) ) + lims.append((xmin, xmax, ymin, ymax)) # Store both the original and modified positions - pos.append( ( - a.get_position(True).frozen(), - a.get_position().frozen() ) ) + pos.append(( + a.get_position(True).frozen(), + a.get_position().frozen())) self._views.push(lims) self._positions.push(pos) self.set_history_buttons() @@ -2814,12 +2929,14 @@ def release_pan(self, event): if self._button_pressed is None: return self.canvas.mpl_disconnect(self._idDrag) - self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.mouse_move) + self._idDrag = self.canvas.mpl_connect( + 'motion_notify_event', self.mouse_move) for a, ind in self._xypress: a.end_pan() - if not self._xypress: return + if not self._xypress: + return self._xypress = [] - self._button_pressed=None + self._button_pressed = None self.push_current() self.release(event) self.draw() @@ -2860,7 +2977,8 @@ def release_zoom(self, event): self.canvas.mpl_disconnect(zoom_id) self._ids_zoom = [] - if not self._xypress: return + if not self._xypress: + return last_a = [] @@ -2868,7 +2986,7 @@ def release_zoom(self, event): x, y = event.x, event.y lastx, lasty, a, ind, lim, trans = cur_xypress # ignore singular clicks - 5 pixels is a threshold - if abs(x-lastx)<5 or abs(y-lasty)<5: + if abs(x - lastx) < 5 or abs(y - lasty) < 5: self._xypress = None self.release(event) self.draw() @@ -2878,46 +2996,64 @@ def release_zoom(self, event): # zoom to rect inverse = a.transData.inverted() - lastx, lasty = inverse.transform_point( (lastx, lasty) ) - x, y = inverse.transform_point( (x, y) ) - Xmin,Xmax=a.get_xlim() - Ymin,Ymax=a.get_ylim() + lastx, lasty = inverse.transform_point((lastx, lasty)) + x, y = inverse.transform_point((x, y)) + Xmin, Xmax = a.get_xlim() + Ymin, Ymax = a.get_ylim() # detect twinx,y axes and avoid double zooming twinx, twiny = False, False if last_a: for la in last_a: - if a.get_shared_x_axes().joined(a,la): twinx=True - if a.get_shared_y_axes().joined(a,la): twiny=True + if a.get_shared_x_axes().joined(a, la): + twinx = True + if a.get_shared_y_axes().joined(a, la): + twiny = True last_a.append(a) if twinx: x0, x1 = Xmin, Xmax else: if Xmin < Xmax: - if x Xmax: x1=Xmax + if x < lastx: + x0, x1 = x, lastx + else: + x0, x1 = lastx, x + if x0 < Xmin: + x0 = Xmin + if x1 > Xmax: + x1 = Xmax else: - if x>lastx: x0, x1 = x, lastx - else: x0, x1 = lastx, x - if x0 > Xmin: x0=Xmin - if x1 < Xmax: x1=Xmax + if x > lastx: + x0, x1 = x, lastx + else: + x0, x1 = lastx, x + if x0 > Xmin: + x0 = Xmin + if x1 < Xmax: + x1 = Xmax if twiny: y0, y1 = Ymin, Ymax else: if Ymin < Ymax: - if y Ymax: y1=Ymax + if y < lasty: + y0, y1 = y, lasty + else: + y0, y1 = lasty, y + if y0 < Ymin: + y0 = Ymin + if y1 > Ymax: + y1 = Ymax else: - if y>lasty: y0, y1 = y, lasty - else: y0, y1 = lasty, y - if y0 > Ymin: y0=Ymin - if y1 < Ymax: y1=Ymax + if y > lasty: + y0, y1 = y, lasty + else: + y0, y1 = lasty, y + if y0 > Ymin: + y0 = Ymin + if y1 < Ymax: + y1 = Ymax if self._button_pressed == 1: if self._zoom_mode == "x": @@ -2928,22 +3064,22 @@ def release_zoom(self, event): a.set_xlim((x0, x1)) a.set_ylim((y0, y1)) elif self._button_pressed == 3: - if a.get_xscale()=='log': - alpha=np.log(Xmax/Xmin)/np.log(x1/x0) - rx1=pow(Xmin/x0,alpha)*Xmin - rx2=pow(Xmax/x0,alpha)*Xmin + if a.get_xscale() == 'log': + alpha = np.log(Xmax / Xmin) / np.log(x1 / x0) + rx1 = pow(Xmin / x0, alpha) * Xmin + rx2 = pow(Xmax / x0, alpha) * Xmin else: - alpha=(Xmax-Xmin)/(x1-x0) - rx1=alpha*(Xmin-x0)+Xmin - rx2=alpha*(Xmax-x0)+Xmin - if a.get_yscale()=='log': - alpha=np.log(Ymax/Ymin)/np.log(y1/y0) - ry1=pow(Ymin/y0,alpha)*Ymin - ry2=pow(Ymax/y0,alpha)*Ymin + alpha = (Xmax - Xmin) / (x1 - x0) + rx1 = alpha * (Xmin - x0) + Xmin + rx2 = alpha * (Xmax - x0) + Xmin + if a.get_yscale() == 'log': + alpha = np.log(Ymax / Ymin) / np.log(y1 / y0) + ry1 = pow(Ymin / y0, alpha) * Ymin + ry2 = pow(Ymax / y0, alpha) * Ymin else: - alpha=(Ymax-Ymin)/(y1-y0) - ry1=alpha*(Ymin-y0)+Ymin - ry2=alpha*(Ymax-y0)+Ymin + alpha = (Ymax - Ymin) / (y1 - y0) + ry1 = alpha * (Ymin - y0) + Ymin + ry2 = alpha * (Ymax - y0) + Ymin if self._zoom_mode == "x": a.set_xlim((rx1, rx2)) @@ -2985,16 +3121,18 @@ def _update_view(self): """ lims = self._views() - if lims is None: return + if lims is None: + return pos = self._positions() - if pos is None: return + if pos is None: + return for i, a in enumerate(self.canvas.figure.get_axes()): xmin, xmax, ymin, ymax = lims[i] a.set_xlim((xmin, xmax)) a.set_ylim((ymin, ymax)) # Restore both the original and modified positions - a.set_position( pos[i][0], 'original' ) - a.set_position( pos[i][1], 'active' ) + a.set_position(pos[i][0], 'original') + a.set_position(pos[i][1], 'active') self.draw() @@ -3023,16 +3161,18 @@ def zoom(self, *args): self._active = 'ZOOM' if self._idPress is not None: - self._idPress=self.canvas.mpl_disconnect(self._idPress) + self._idPress = self.canvas.mpl_disconnect(self._idPress) self.mode = '' if self._idRelease is not None: - self._idRelease=self.canvas.mpl_disconnect(self._idRelease) + self._idRelease = self.canvas.mpl_disconnect(self._idRelease) self.mode = '' - if self._active: - self._idPress = self.canvas.mpl_connect('button_press_event', self.press_zoom) - self._idRelease = self.canvas.mpl_connect('button_release_event', self.release_zoom) + if self._active: + self._idPress = self.canvas.mpl_connect('button_press_event', + self.press_zoom) + self._idRelease = self.canvas.mpl_connect('button_release_event', + self.release_zoom) self.mode = 'zoom rect' self.canvas.widgetlock(self) else: diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index f9a53729ee5d..418fc5bb73ab 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -16,9 +16,8 @@ TODO: - * allow save to file handle - * integrate screen dpi w/ ppi and text + """ from __future__ import division import threading @@ -154,11 +153,13 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) - x = np.round(x + ox) - y = np.round(y - oy) + xd = descent * np.sin(np.deg2rad(angle)) + yd = descent * np.cos(np.deg2rad(angle)) + x = np.round(x + ox - xd) + y = np.round(y - oy + yd) self._renderer.draw_text_image(font_image, x, y + 1, angle, gc) - def draw_text(self, gc, x, y, s, prop, angle, ismath): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): """ Render the text """ @@ -177,10 +178,14 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath): # space) in the following call to draw_text_image). font.set_text(s, 0, flags=flags) font.draw_glyphs_to_bitmap(antialiased=rcParams['text.antialiased']) + d = font.get_descent() / 64.0 + # The descent needs to be adjusted for the angle + xd = -d * np.sin(np.deg2rad(angle)) + yd = d * np.cos(np.deg2rad(angle)) #print x, y, int(x), int(y), s self._renderer.draw_text_image( - font.get_image(), np.round(x), np.round(y) + 1, angle, gc) + font.get_image(), np.round(x - xd), np.round(y + yd) + 1, angle, gc) def get_text_width_height_descent(self, s, prop, ismath): """ @@ -216,7 +221,7 @@ def get_text_width_height_descent(self, s, prop, ismath): return w, h, d - def draw_tex(self, gc, x, y, s, prop, angle): + def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): # todo, handle props, angle, origins size = prop.get_size_in_points() @@ -227,6 +232,12 @@ def draw_tex(self, gc, x, y, s, prop, angle): Z = texmanager.get_grey(s, size, self.dpi) Z = np.array(Z * 255.0, np.uint8) + w, h, d = self.get_text_width_height_descent(s, prop, ismath) + xd = d * np.sin(np.deg2rad(angle)) + yd = d * np.cos(np.deg2rad(angle)) + x = np.round(x - xd) + y = np.round(y + yd) + self._renderer.draw_text_image(Z, x, y, angle, gc) def get_canvas_width_height(self): @@ -432,7 +443,7 @@ def draw(self): """ if __debug__: verbose.report('FigureCanvasAgg.draw', 'debug-annoying') - self.renderer = self.get_renderer() + self.renderer = self.get_renderer(cleared=True) # acquire a lock on the shared font cache RendererAgg.lock.acquire() @@ -443,7 +454,7 @@ def draw(self): - def get_renderer(self): + def get_renderer(self, cleared=False): l, b, w, h = self.figure.bbox.bounds key = w, h, self.figure.dpi try: self._lastKey, self.renderer @@ -453,6 +464,8 @@ def get_renderer(self): if need_new_renderer: self.renderer = RendererAgg(w, h, self.figure.dpi) self._lastKey = key + elif cleared: + self.renderer.clear() return self.renderer def tostring_rgb(self): diff --git a/lib/matplotlib/backends/backend_cairo.py b/lib/matplotlib/backends/backend_cairo.py index 966e618fa408..f8328b5c7e77 100644 --- a/lib/matplotlib/backends/backend_cairo.py +++ b/lib/matplotlib/backends/backend_cairo.py @@ -110,13 +110,13 @@ def set_width_height(self, width, height): # font transform? - def _fill_and_stroke (self, ctx, fill_c, alpha): + def _fill_and_stroke (self, ctx, fill_c, alpha, alpha_overrides): if fill_c is not None: ctx.save() - if len(fill_c) == 3: + if len(fill_c) == 3 or alpha_overrides: ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], alpha) else: - ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], alpha*fill_c[3]) + ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], fill_c[3]) ctx.fill_preserve() ctx.restore() ctx.stroke() @@ -150,34 +150,28 @@ def draw_path(self, gc, path, transform, rgbFace=None): ctx.new_path() self.convert_path(ctx, path, transform) - self._fill_and_stroke(ctx, rgbFace, gc.get_alpha()) + self._fill_and_stroke(ctx, rgbFace, gc.get_alpha(), gc.get_forced_alpha()) def draw_image(self, gc, x, y, im): # bbox - not currently used if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) - clippath, clippath_trans = gc.get_clip_path() - im.flipud_out() rows, cols, buf = im.color_conv (BYTE_FORMAT) surface = cairo.ImageSurface.create_for_data ( buf, cairo.FORMAT_ARGB32, cols, rows, cols*4) - # function does not pass a 'gc' so use renderer.ctx - ctx = self.gc.ctx - ctx.save() - if clippath is not None: - ctx.new_path() - RendererCairo.convert_path(ctx, clippath, clippath_trans) - ctx.clip() + ctx = gc.ctx y = self.height - y - rows + + ctx.save() ctx.set_source_surface (surface, x, y) ctx.paint() ctx.restore() im.flipud_out() - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # Note: x,y are device/display coords, not user-coords, unlike other # draw_* methods if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) @@ -192,17 +186,17 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False): ctx.select_font_face (prop.get_name(), self.fontangles [prop.get_style()], self.fontweights[prop.get_weight()]) - + size = prop.get_size_in_points() * self.dpi / 72.0 - + ctx.save() if angle: ctx.rotate (-angle * np.pi / 180) ctx.set_font_size (size) if sys.version_info[0] < 3: - ctx.show_text (s.encode("utf-8")) + ctx.show_text(s.encode("utf-8")) else: - ctx.show_text (s) + ctx.show_text(s) ctx.restore() def _draw_mathtext(self, gc, x, y, s, prop, angle): @@ -220,16 +214,19 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle): for font, fontsize, s, ox, oy in glyphs: ctx.new_path() ctx.move_to(ox, oy) - + fontProp = ttfFontProperty(font) ctx.save() ctx.select_font_face (fontProp.name, self.fontangles [fontProp.style], self.fontweights[fontProp.weight]) - + size = fontsize * self.dpi / 72.0 ctx.set_font_size(size) - ctx.show_text(s.encode("utf-8")) + if sys.version_info[0] < 3: + ctx.show_text(s.encode("utf-8")) + else: + ctx.show_text(s) ctx.restore() for ox, oy, w, h in rects: @@ -322,7 +319,10 @@ def set_alpha(self, alpha): GraphicsContextBase.set_alpha(self, alpha) _alpha = self.get_alpha() rgb = self._rgb - self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], _alpha) + if self.get_forced_alpha(): + self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], _alpha) + else: + self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], rgb[3]) #def set_antialiased(self, b): @@ -365,8 +365,8 @@ def set_dashes(self, offset, dashes): self.renderer.points_to_pixels (np.asarray(dashes)), offset) - def set_foreground(self, fg, isRGB=None): - GraphicsContextBase.set_foreground(self, fg, isRGB) + def set_foreground(self, fg, isRGBA=None): + GraphicsContextBase.set_foreground(self, fg, isRGBA) if len(self._rgb) == 3: self.ctx.set_source_rgb(*self._rgb) else: diff --git a/lib/matplotlib/backends/backend_cocoaagg.py b/lib/matplotlib/backends/backend_cocoaagg.py index 5c9c04938874..945f57ef7cc5 100644 --- a/lib/matplotlib/backends/backend_cocoaagg.py +++ b/lib/matplotlib/backends/backend_cocoaagg.py @@ -25,6 +25,12 @@ from AppKit import * from PyObjCTools import NibClassBuilder, AppHelper +from matplotlib import cbook +cbook.warn_deprecated( + '1.3', + message="The CocoaAgg backend is not a fully-functioning backend. " + "It may be removed in matplotlib 1.4.") + import matplotlib from matplotlib.figure import Figure from matplotlib.backend_bases import FigureManagerBase, FigureCanvasBase @@ -292,4 +298,3 @@ def WMEnable(name='Python'): print('SetFrontProcess', (err, psn), file=sys.stderr) return False return True - diff --git a/lib/matplotlib/backends/backend_emf.py b/lib/matplotlib/backends/backend_emf.py deleted file mode 100644 index 50da4fea706f..000000000000 --- a/lib/matplotlib/backends/backend_emf.py +++ /dev/null @@ -1,746 +0,0 @@ -""" -Enhanced Metafile backend. See http://pyemf.sourceforge.net for the EMF -driver library. -""" - -from __future__ import division, print_function - -try: - import pyemf -except ImportError: - raise ImportError('You must first install pyemf from http://pyemf.sf.net') - -import os,sys,math,re - -from matplotlib import verbose, __version__, rcParams - -from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ - FigureManagerBase, FigureCanvasBase -from matplotlib.figure import Figure -from matplotlib.transforms import Bbox - -from matplotlib.font_manager import findfont, FontProperties -from matplotlib.ft2font import FT2Font, KERNING_UNFITTED, KERNING_DEFAULT, KERNING_UNSCALED - -from matplotlib.path import Path -from matplotlib.transforms import Affine2D -from matplotlib.mlab import quad2cubic - -# Font handling stuff snarfed from backend_ps, but only using TTF fonts -_fontd = {} - -# Debug print stuff -debugHandle = False -debugPrint = False -debugText = False - -# Hashable font properties class. In EMF, angle of rotation is a part -# of the font properties, so a handle to a new font must be obtained -# if the rotation changes. -class EMFFontProperties(FontProperties): - def __init__(self,other,angle): - FontProperties.__init__(self,other.get_family(), - other.get_style(), - other.get_variant(), - other.get_weight(), - other.get_stretch(), - other.get_size()) - self._angle=angle - - def __hash__(self): - return hash( (FontProperties.__hash__(self), self._angle)) - - def __str__(self): - return str( (FontProperties.__str__(self), self._angle)) - - def set_angle(self,angle): - self._angle=angle - - def get_angle(self): - return self._angle - -# Hashable pen (line style) properties. -class EMFPen: - def __init__(self,emf,gc): - self.emf=emf - self.gc=gc - - r,g,b=gc.get_rgb()[:3] - self.r=int(r*255) - self.g=int(g*255) - self.b=int(b*255) - self.width=int(gc.get_linewidth()) - - self.style=0 - self.set_linestyle() - if debugHandle: print("EMFPen: style=%d width=%d rgb=(%d,%d,%d)" % (self.style,self.width,self.r,self.g,self.b)) - - def __hash__(self): - return hash((self.style,self.width,self.r,self.g,self.b)) - - def set_linestyle(self): - # Hack. Negative width lines will not get drawn. - if self.width<0: - self.style=pyemf.PS_NULL - else: - styles={'solid':pyemf.PS_SOLID, 'dashed':pyemf.PS_DASH, - 'dashdot':pyemf.PS_DASHDOT, 'dotted':pyemf.PS_DOT} - #style=styles.get(self.gc.get_linestyle('solid')) - style=self.gc.get_linestyle('solid') - if debugHandle: print("EMFPen: style=%s" % style) - if style in styles: - self.style=styles[style] - else: - self.style=pyemf.PS_SOLID - - def get_handle(self): - handle=self.emf.CreatePen(self.style,self.width,(self.r,self.g,self.b)) - return handle - -# Hashable brush (fill style) properties. -class EMFBrush: - def __init__(self,emf,rgb): - self.emf=emf - r,g,b=rgb[:3] - self.r=int(r*255) - self.g=int(g*255) - self.b=int(b*255) - if debugHandle: print("EMFBrush: rgb=(%d,%d,%d)" % (self.r,self.g,self.b)) - - def __hash__(self): - return hash((self.r,self.g,self.b)) - - def get_handle(self): - handle=self.emf.CreateSolidBrush((self.r,self.g,self.b)) - return handle - - - - -class RendererEMF(RendererBase): - """ - The renderer handles drawing/rendering operations through a - pyemf.EMF instance. - """ - - fontweights = { - 100 : pyemf.FW_NORMAL, - 200 : pyemf.FW_NORMAL, - 300 : pyemf.FW_NORMAL, - 400 : pyemf.FW_NORMAL, - 500 : pyemf.FW_NORMAL, - 600 : pyemf.FW_BOLD, - 700 : pyemf.FW_BOLD, - 800 : pyemf.FW_BOLD, - 900 : pyemf.FW_BOLD, - 'ultralight' : pyemf.FW_ULTRALIGHT, - 'light' : pyemf.FW_LIGHT, - 'normal' : pyemf.FW_NORMAL, - 'medium' : pyemf.FW_MEDIUM, - 'semibold' : pyemf.FW_SEMIBOLD, - 'bold' : pyemf.FW_BOLD, - 'heavy' : pyemf.FW_HEAVY, - 'ultrabold' : pyemf.FW_ULTRABOLD, - 'black' : pyemf.FW_BLACK, - } - - def __init__(self, outfile, width, height, dpi): - "Initialize the renderer with a gd image instance" - self.outfile = outfile - - # a map from get_color args to colors - self._cached = {} - - # dict of hashed properties to already created font handles - self._fontHandle = {} - - self.lastHandle = {'font':-1, 'pen':-1, 'brush':-1} - - self.emf=pyemf.EMF(width,height,dpi,'in') - - self.width=int(width*dpi) - self.height=int(height*dpi) - self.dpi = dpi - self.pointstodpi = dpi/72.0 - self.hackPointsForMathExponent = 2.0 - - # set background transparent for text - self.emf.SetBkMode(pyemf.TRANSPARENT) - # set baseline for text to be bottom left corner - self.emf.SetTextAlign( pyemf.TA_BOTTOM|pyemf.TA_LEFT) - - self._lastClipRect = None - - if debugPrint: print("RendererEMF: (%f,%f) %s dpi=%f" % (self.width,self.height,outfile,dpi)) - - - - def save(self): - self.emf.save(self.outfile) - - def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): - """ - Draw an arc using GraphicsContext instance gcEdge, centered at x,y, - with width and height and angles from 0.0 to 360.0 - 0 degrees is at 3-o'clock - positive angles are anti-clockwise - - If the color rgbFace is not None, fill the arc with it. - """ - if debugPrint: print("draw_arc: (%f,%f) angles=(%f,%f) w,h=(%f,%f)" % (x,y,angle1,angle2,width,height)) - pen=self.select_pen(gcEdge) - brush=self.select_brush(rgbFace) - - # This algorithm doesn't work very well on small circles - # because of rounding error. This shows up most obviously on - # legends where the circles are small anyway, and it is - # compounded by the fact that it puts several circles right - # next to each other so the differences are obvious. - hw=width/2 - hh=height/2 - x1=int(x-width/2) - y1=int(y-height/2) - if brush: - self.emf.Pie(int(x-hw),int(self.height-(y-hh)),int(x+hw),int(self.height-(y+hh)),int(x+math.cos(angle1*math.pi/180.0)*hw),int(self.height-(y+math.sin(angle1*math.pi/180.0)*hh)),int(x+math.cos(angle2*math.pi/180.0)*hw),int(self.height-(y+math.sin(angle2*math.pi/180.0)*hh))) - else: - self.emf.Arc(int(x-hw),int(self.height-(y-hh)),int(x+hw),int(self.height-(y+hh)),int(x+math.cos(angle1*math.pi/180.0)*hw),int(self.height-(y+math.sin(angle1*math.pi/180.0)*hh)),int(x+math.cos(angle2*math.pi/180.0)*hw),int(self.height-(y+math.sin(angle2*math.pi/180.0)*hh))) - - - def handle_clip_rectangle(self, gc): - new_bounds = gc.get_clip_rectangle() - if new_bounds is not None: - new_bounds = new_bounds.bounds - if self._lastClipRect != new_bounds: - self._lastClipRect = new_bounds - if new_bounds is None: - # use the maximum rectangle to disable clipping - x, y, width, height = (0, 0, self.width, self.height) - else: - x, y, width, height = new_bounds - self.emf.BeginPath() - self.emf.MoveTo(int(x), int(self.height - y)) - self.emf.LineTo(int(x) + int(width), int(self.height - y)) - self.emf.LineTo(int(x) + int(width), int(self.height - y) - int(height)) - self.emf.LineTo(int(x), int(self.height - y) - int(height)) - self.emf.CloseFigure() - self.emf.EndPath() - self.emf.SelectClipPath() - - - def convert_path(self, tpath): - self.emf.BeginPath() - last_points = None - for points, code in tpath.iter_segments(): - if code == Path.MOVETO: - self.emf.MoveTo(*points) - elif code == Path.CLOSEPOLY: - self.emf.CloseFigure() - elif code == Path.LINETO: - self.emf.LineTo(*points) - elif code == Path.CURVE3: - points = quad2cubic(*(list(last_points[-2:]) + list(points))) - self.emf.PolyBezierTo(zip(points[2::2], points[3::2])) - elif code == Path.CURVE4: - self.emf.PolyBezierTo(zip(points[::2], points[1::2])) - last_points = points - self.emf.EndPath() - - - def draw_path(self, gc, path, transform, rgbFace=None): - """ - Draws a :class:`~matplotlib.path.Path` instance using the - given affine transform. - """ - self.handle_clip_rectangle(gc) - gc._rgb = gc._rgb[:3] - self.select_pen(gc) - self.select_brush(rgbFace) - transform = transform + Affine2D().scale(1.0, -1.0).translate(0.0, self.height) - tpath = transform.transform_path(path) - self.convert_path(tpath) - if rgbFace is None: - self.emf.StrokePath() - else: - self.emf.StrokeAndFillPath() - - - def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): - """ - Draw the Image instance into the current axes; x is the - distance in pixels from the left hand side of the canvas. y is - the distance from the origin. That is, if origin is upper, y - is the distance from top. If origin is lower, y is the - distance from bottom - - bbox is a matplotlib.transforms.BBox instance for clipping, or - None - """ - - # pyemf2 currently doesn't support bitmaps. - - pass - - - def draw_line(self, gc, x1, y1, x2, y2): - """ - Draw a single line from x1,y1 to x2,y2 - """ - if debugPrint: print("draw_line: (%f,%f) - (%f,%f)" % (x1,y1,x2,y2)) - - if self.select_pen(gc): - self.emf.Polyline([(long(x1),long(self.height-y1)),(long(x2),long(self.height-y2))]) - else: - if debugPrint: print("draw_line: optimizing away (%f,%f) - (%f,%f)" % (x1,y1,x2,y2)) - - def draw_lines(self, gc, x, y): - """ - x and y are equal length arrays, draw lines connecting each - point in x, y - """ - if debugPrint: print("draw_lines: %d points" % len(str(x))) - - # optimize away anything that won't actually be drawn. Edge - # style must not be PS_NULL for it to appear on screen. - if self.select_pen(gc): - points = [(long(x[i]), long(self.height-y[i])) for i in range(len(x))] - self.emf.Polyline(points) - - def draw_point(self, gc, x, y): - """ - Draw a single point at x,y - Where 'point' is a device-unit point (or pixel), not a matplotlib point - """ - if debugPrint: print("draw_point: (%f,%f)" % (x,y)) - - # don't cache this pen - pen=EMFPen(self.emf,gc) - - self.emf.SetPixel(long(x),long(self.height-y),(pen.r,pen.g,pen.b)) - - def draw_polygon(self, gcEdge, rgbFace, points): - """ - Draw a polygon using the GraphicsContext instance gc. - points is a len vertices tuple, each element - giving the x,y coords a vertex - - If the color rgbFace is not None, fill the polygon with it - """ - if debugPrint: print("draw_polygon: %d points" % len(points)) - - # optimize away anything that won't actually draw. Either a - # face color or edge style must be defined - pen=self.select_pen(gcEdge) - brush=self.select_brush(rgbFace) - if pen or brush: - points = [(long(x), long(self.height-y)) for x,y in points] - self.emf.Polygon(points) - else: - points = [(long(x), long(self.height-y)) for x,y in points] - if debugPrint: print("draw_polygon: optimizing away polygon: %d points = %s" % (len(points),str(points))) - - def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): - """ - Draw a non-filled rectangle using the GraphicsContext instance gcEdge, - with lower left at x,y with width and height. - - If rgbFace is not None, fill the rectangle with it. - """ - if debugPrint: print("draw_rectangle: (%f,%f) w=%f,h=%f" % (x,y,width,height)) - - # optimize away anything that won't actually draw. Either a - # face color or edge style must be defined - pen=self.select_pen(gcEdge) - brush=self.select_brush(rgbFace) - if pen or brush: - self.emf.Rectangle(int(x),int(self.height-y),int(x)+int(width),int(self.height-y)-int(height)) - else: - if debugPrint: print("draw_rectangle: optimizing away (%f,%f) w=%f,h=%f" % (x,y,width,height)) - - - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): - """ - Draw the text.Text instance s at x,y (display coords) with font - properties instance prop at angle in degrees, using GraphicsContext gc - - **backend implementers note** - - When you are trying to determine if you have gotten your bounding box - right (which is what enables the text layout/alignment to work - properly), it helps to change the line in text.py - - if 0: bbox_artist(self, renderer) - - to if 1, and then the actual bounding box will be blotted along with - your text. - """ - if ismath: s = self.strip_math(s) - self.handle_clip_rectangle(gc) - self.emf.SetTextColor(gc.get_rgb()[:3]) - self.select_font(prop,angle) - if isinstance(s, unicode): - # unicode characters do not seem to work with pyemf - try: - s = s.replace(u'\u2212', '-').encode('iso-8859-1') - except UnicodeEncodeError: - pass - self.emf.TextOut(x,y,s) - - - def draw_plain_text(self, gc, x, y, s, prop, angle): - """ - Draw a text string verbatim; no conversion is done. - """ - if debugText: print("draw_plain_text: (%f,%f) %d degrees: '%s'" % (x,y,angle,s)) - if debugText: print(" properties:\n"+str(prop)) - self.select_font(prop,angle) - - # haxor follows! The subtleties of text placement in EMF - # still elude me a bit. It always seems to be too high on the - # page, about 10 pixels too high on a 300dpi resolution image. - # So, I'm adding this hack for the moment: - hackoffsetper300dpi=10 - xhack=math.sin(angle*math.pi/180.0)*hackoffsetper300dpi*self.dpi/300.0 - yhack=math.cos(angle*math.pi/180.0)*hackoffsetper300dpi*self.dpi/300.0 - - self.emf.TextOut(long(x+xhack),long(y+yhack),s) - - - def draw_math_text(self, gc, x, y, s, prop, angle): - """ - Draw a subset of TeX, currently handles exponents only. Since - pyemf doesn't have any raster functionality yet, the - texmanager.get_rgba won't help. - """ - if debugText: print("draw_math_text: (%f,%f) %d degrees: '%s'" % (x,y,angle,s)) - - s = s[1:-1] # strip the $ from front and back - match=re.match("10\^\{(.+)\}",s) - if match: - exp=match.group(1) - if debugText: print(" exponent=%s" % exp) - font = self._get_font_ttf(prop) - font.set_text("10", 0.0) - w, h = font.get_width_height() - w /= 64.0 # convert from subpixels - h /= 64.0 - self.draw_plain_text(gc,x,y,"10",prop,angle) - propexp=prop.copy() - propexp.set_size(prop.get_size_in_points()*.8) - self.draw_plain_text(gc,x+w+self.points_to_pixels(self.hackPointsForMathExponent),y-(h/2),exp,propexp,angle) - else: - # if it isn't an exponent, then render the raw TeX string. - self.draw_plain_text(gc,x,y,s,prop,angle) - - def get_math_text_width_height(self, s, prop): - """ - get the width and height in display coords of the string s - with FontPropertry prop, ripped right out of backend_ps. This - method must be kept in sync with draw_math_text. - """ - if debugText: print("get_math_text_width_height:") - s = s[1:-1] # strip the $ from front and back - match=re.match("10\^\{(.+)\}",s) - if match: - exp=match.group(1) - if debugText: print(" exponent=%s" % exp) - font = self._get_font_ttf(prop) - font.set_text("10", 0.0) - w1, h1 = font.get_width_height() - - propexp=prop.copy() - propexp.set_size(prop.get_size_in_points()*.8) - fontexp=self._get_font_ttf(propexp) - fontexp.set_text(exp, 0.0) - w2, h2 = fontexp.get_width_height() - w=w1+w2 - h=h1+(h2/2) - w /= 64.0 # convert from subpixels - h /= 64.0 - w+=self.points_to_pixels(self.hackPointsForMathExponent) - if debugText: print(" math string=%s w,h=(%f,%f)" % (s, w, h)) - else: - w,h=self.get_text_width_height(s,prop,False) - return w, h - - - def get_text_width_height_descent(self, s, prop, ismath): - """ - get the width and height in display coords of the string s - with FontPropertry prop - """ - if ismath: s = self.strip_math(s) - font = self._get_font_ttf(prop) - font.set_text(s, 0.0) - w, h = font.get_width_height() - w /= 64.0 # convert from subpixels - h /= 64.0 - d = font.get_descent() - d /= 64.0 - return w, h, d - - - def flipy(self): - """return true if y small numbers are top for renderer - Is used for drawing text (text.py) and images (image.py) only - """ - return True - - - def get_canvas_width_height(self): - """ - return the canvas width and height in display coords - """ - return self.width,self.height - - - def set_handle(self,type,handle): - """ - Update the EMF file with the current handle, but only if it - isn't the same as the last one. Don't want to flood the file - with duplicate info. - """ - if self.lastHandle[type] != handle: - self.emf.SelectObject(handle) - self.lastHandle[type]=handle - - - def get_font_handle(self, prop, angle): - """ - Look up the handle for the font based on the dict of - properties *and* the rotation angle, since in EMF the font - rotation is a part of the font definition. - """ - prop=EMFFontProperties(prop,angle) - size=int(prop.get_size_in_points()*self.pointstodpi) - face=prop.get_name() - key = hash(prop) - handle = self._fontHandle.get(key) - if handle is None: - handle=self.emf.CreateFont(-size, 0, int(angle)*10, int(angle)*10, - self.fontweights.get(prop.get_weight(), pyemf.FW_NORMAL), - int(prop.get_style() == 'italic'), - 0, 0, - pyemf.ANSI_CHARSET, pyemf.OUT_DEFAULT_PRECIS, - pyemf.CLIP_DEFAULT_PRECIS, pyemf.DEFAULT_QUALITY, - pyemf.DEFAULT_PITCH | pyemf.FF_DONTCARE, face); - if debugHandle: print("get_font_handle: creating handle=%d for face=%s size=%d" % (handle,face,size)) - self._fontHandle[key]=handle - if debugHandle: print(" found font handle %d for face=%s size=%d" % (handle,face,size)) - self.set_handle("font",handle) - return handle - - - def select_font(self,prop,angle): - handle=self.get_font_handle(prop,angle) - self.set_handle("font",handle) - - - def select_pen(self, gc): - """ - Select a pen that includes the color, line width and line - style. Return the pen if it will draw a line, or None if the - pen won't produce any output (i.e. the style is PS_NULL) - """ - pen=EMFPen(self.emf,gc) - key=hash(pen) - handle=self._fontHandle.get(key) - if handle is None: - handle=pen.get_handle() - self._fontHandle[key]=handle - if debugHandle: print(" found pen handle %d" % handle) - self.set_handle("pen",handle) - if pen.style != pyemf.PS_NULL: - return pen - else: - return None - - - def select_brush(self, rgb): - """ - Select a fill color, and return the brush if the color is - valid or None if this won't produce a fill operation. - """ - if rgb is not None: - brush=EMFBrush(self.emf,rgb) - key=hash(brush) - handle=self._fontHandle.get(key) - if handle is None: - handle=brush.get_handle() - self._fontHandle[key]=handle - if debugHandle: print(" found brush handle %d" % handle) - self.set_handle("brush",handle) - return brush - else: - return None - - - def _get_font_ttf(self, prop): - """ - get the true type font properties, used because EMFs on - windows will use true type fonts. - """ - key = hash(prop) - font = _fontd.get(key) - if font is None: - fname = findfont(prop) - if debugText: print("_get_font_ttf: name=%s" % fname) - font = FT2Font(str(fname)) - _fontd[key] = font - font.clear() - size = prop.get_size_in_points() - font.set_size(size, self.dpi) - - return font - - - def get_text_width_height(self, s, prop, ismath): - """ - get the width and height in display coords of the string s - with FontPropertry prop, ripped right out of backend_ps - """ - if debugText: print("get_text_width_height: ismath=%s properties: %s" % (str(ismath),str(prop))) - if ismath: - if debugText: print(" MATH TEXT! = %s" % str(ismath)) - w,h = self.get_math_text_width_height(s, prop) - return w,h - - font = self._get_font_ttf(prop) - font.set_text(s, 0.0) - w, h = font.get_width_height() - w /= 64.0 # convert from subpixels - h /= 64.0 - if debugText: print(" text string=%s w,h=(%f,%f)" % (s, w, h)) - return w, h - - - def new_gc(self): - return GraphicsContextEMF() - - def points_to_pixels(self, points): - # if backend doesn't have dpi, eg, postscript or svg - #return points - # elif backend assumes a value for pixels_per_inch - #return points/72.0 * self.dpi.get() * pixels_per_inch/72.0 - # else - return points/72.0 * self.dpi - - -class GraphicsContextEMF(GraphicsContextBase): - """ - The graphics context provides the color, line styles, etc... See the gtk - and postscript backends for examples of mapping the graphics context - attributes (cap styles, join styles, line widths, colors) to a particular - backend. In GTK this is done by wrapping a gtk.gdk.GC object and - forwarding the appropriate calls to it using a dictionary mapping styles - to gdk constants. In Postscript, all the work is done by the renderer, - mapping line styles to postscript calls. - - If it's more appropriate to do the mapping at the renderer level (as in - the postscript backend), you don't need to override any of the GC methods. - If it's more appropriate to wrap an instance (as in the GTK backend) and - do the mapping here, you'll need to override several of the setter - methods. - - The base GraphicsContext stores colors as a RGB tuple on the unit - interval, eg, (0.5, 0.0, 1.0). You may need to map this to colors - appropriate for your backend. - """ - pass - - - -######################################################################## -# -# The following functions and classes are for pylab and implement -# window/figure managers, etc... -# -######################################################################## - -def draw_if_interactive(): - """ - For image backends - is not required - For GUI backends - this should be overriden if drawing should be done in - interactive python mode - """ - pass - -def show(): - """ - For image backends - is not required - For GUI backends - show() is usually the last line of a pylab script and - tells the backend that it is time to draw. In interactive mode, this may - be a do nothing func. See the GTK backend for an example of how to handle - interactive versus batch mode - """ - for manager in Gcf.get_all_fig_managers(): - # do something to display the GUI - pass - - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - # if a main-level app must be created, this is the usual place to - # do it -- see backend_wx, backend_wxagg and backend_tkagg for - # examples. Not all GUIs require explicit instantiation of a - # main-level app (egg backend_gtk, backend_gtkagg) for pylab - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasEMF(figure) - manager = FigureManagerEMF(canvas, num) - return manager - - -class FigureCanvasEMF(FigureCanvasBase): - """ - The canvas the figure renders into. Calls the draw and print fig - methods, creates the renderers, etc... - - Public attribute - - figure - A Figure instance - """ - - def draw(self): - """ - Draw the figure using the renderer - """ - pass - - filetypes = {'emf': 'Enhanced Metafile'} - - def print_emf(self, filename, dpi=300, **kwargs): - width, height = self.figure.get_size_inches() - renderer = RendererEMF(filename,width,height,dpi) - self.figure.draw(renderer) - renderer.save() - - def get_default_filetype(self): - return 'emf' - -class FigureManagerEMF(FigureManagerBase): - """ - Wrap everything up into a window for the pylab interface - - For non interactive backends, the base class does all the work - """ - pass - -######################################################################## -# -# Now just provide the standard names that backend.__init__ is expecting -# -######################################################################## - - -FigureManager = FigureManagerEMF - diff --git a/lib/matplotlib/backends/backend_fltkagg.py b/lib/matplotlib/backends/backend_fltkagg.py deleted file mode 100644 index 52d4bd3b1efd..000000000000 --- a/lib/matplotlib/backends/backend_fltkagg.py +++ /dev/null @@ -1,645 +0,0 @@ -""" -A backend for FLTK - -Copyright: Gregory Lielens, Free Field Technologies SA and - John D. Hunter 2004 - -This code is released under the matplotlib license - -""" - -from __future__ import division, print_function - -import os, sys, math - -import fltk as Fltk -from backend_agg import FigureCanvasAgg - -import os.path - -import matplotlib - -from matplotlib import rcParams, verbose -from matplotlib.cbook import is_string_like -from matplotlib.backend_bases import \ - RendererBase, GraphicsContextBase, FigureManagerBase, FigureCanvasBase,\ - NavigationToolbar2, cursors -from matplotlib.backend_bases import ShowBase - - -from matplotlib.figure import Figure -from matplotlib._pylab_helpers import Gcf -import matplotlib.backends.windowing as windowing -from matplotlib.widgets import SubplotTool - -# the true dots per inch on the screen; should be display dependent -# see http://groups.google.com/groups?q=screen+dpi+x11&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=7077.26e81ad5%40swift.cs.tcd.ie&rnum=5 for some info about screen dpi -PIXELS_PER_INCH = 75 - -cursord= { - cursors.HAND: Fltk.FL_CURSOR_HAND, - cursors.POINTER: Fltk.FL_CURSOR_ARROW, - cursors.SELECT_REGION: Fltk.FL_CURSOR_CROSS, - cursors.MOVE: Fltk.FL_CURSOR_MOVE - } - -special_key={ - Fltk.FL_Shift_R:'shift', - Fltk.FL_Shift_L:'shift', - Fltk.FL_Control_R:'control', - Fltk.FL_Control_L:'control', - Fltk.FL_Control_R:'control', - Fltk.FL_Control_L:'control', - 65515:'win', - 65516:'win', - } - - -def error_msg_fltk(msg, parent=None): - Fltk.fl_message(msg) - - -def draw_if_interactive(): - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.draw() - -class Show(ShowBase): - def mainloop(self): - Fltk.Fl.run() - -show = Show() - - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - figure = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, figure) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - window = Fltk.Fl_Double_Window(10,10,30,30) - canvas = FigureCanvasFltkAgg(figure) - window.end() - #Fltk.Fl.visual(Fltk.FL_DOUBLE) - window.show() - window.make_current() - figManager = FigureManagerFltkAgg(canvas, num, window) - if matplotlib.is_interactive(): - figManager.show() - return figManager - - -class FltkCanvas(Fltk.Fl_Widget): - - def __init__(self,x,y,w,h,l,source): - Fltk.Fl_Widget.__init__(self, 0, 0, w, h, "canvas") - self._source=source - self._oldsize=(None,None) - self._draw_overlay = False - self._button = None - self._key = None - - - def draw(self): - newsize=(self.w(),self.h()) - if(self._oldsize !=newsize): - self._oldsize =newsize - self._source.resize(newsize) - self._source.draw() - t1,t2,w,h = self._source.figure.bbox.bounds - Fltk.fl_draw_image(self._source.buffer_rgba(),0,0,int(w),int(h),4,0) - self.redraw() - - def blit(self,bbox=None): - if bbox is None: - t1,t2,w,h = self._source.figure.bbox.bounds - else: - t1o,t2o,wo,ho = self._source.figure.bbox.bounds - t1,t2,w,h = bbox.bounds - x,y=int(t1),int(t2) - Fltk.fl_draw_image(self._source.buffer_rgba(),x,y,int(w),int(h),4,int(wo)*4) - #self.redraw() - - def handle(self, event): - x=Fltk.Fl.event_x() - y=Fltk.Fl.event_y() - yf=self._source.figure.bbox.height - y - if event == Fltk.FL_FOCUS or event == Fltk.FL_UNFOCUS: - return 1 - elif event == Fltk.FL_KEYDOWN: - ikey= Fltk.Fl.event_key() - if(ikey<=255): - self._key=chr(ikey) - else: - try: - self._key=special_key[ikey] - except: - self._key=None - - # TODO: Handle ctrl, alt, super modifiers. - FigureCanvasBase.key_press_event(self._source, self._key) - return 1 - elif event == Fltk.FL_KEYUP: - FigureCanvasBase.key_release_event(self._source, self._key) - self._key=None - elif event == Fltk.FL_PUSH: - self.window().make_current() - if Fltk.Fl.event_button1(): - self._button = 1 - elif Fltk.Fl.event_button2(): - self._button = 2 - elif Fltk.Fl.event_button3(): - self._button = 3 - else: - self._button = None - - if self._draw_overlay: - self._oldx=x - self._oldy=y - if Fltk.Fl.event_clicks(): # according to docs, event_clicks() returns nonzero if this is a double click. - FigureCanvasBase.button_press_event(self._source, x, yf, self._button, dblclick=True) - return 1 - else: - FigureCanvasBase.button_press_event(self._source, x, yf, self._button) - return 1 - elif event == Fltk.FL_ENTER: - self.take_focus() - return 1 - elif event == Fltk.FL_LEAVE: - return 1 - elif event == Fltk.FL_MOVE: - FigureCanvasBase.motion_notify_event(self._source, x, yf) - return 1 - elif event == Fltk.FL_DRAG: - self.window().make_current() - if self._draw_overlay: - self._dx=Fltk.Fl.event_x()-self._oldx - self._dy=Fltk.Fl.event_y()-self._oldy - Fltk.fl_overlay_rect(self._oldx,self._oldy,self._dx,self._dy) - FigureCanvasBase.motion_notify_event(self._source, x, yf) - return 1 - elif event == Fltk.FL_RELEASE: - self.window().make_current() - if self._draw_overlay: - Fltk.fl_overlay_clear() - FigureCanvasBase.button_release_event(self._source, x, yf, self._button) - self._button = None - return 1 - return 0 - -class FigureCanvasFltkAgg(FigureCanvasAgg): - def __init__(self, figure): - FigureCanvasAgg.__init__(self,figure) - t1,t2,w,h = self.figure.bbox.bounds - w, h = int(w), int(h) - self.canvas=FltkCanvas(0, 0, w, h, "canvas",self) - #self.draw() - - def resize(self,size): - w, h = size - # compute desired figure size in inches - dpival = self.figure.dpi - winch = w/dpival - hinch = h/dpival - self.figure.set_size_inches(winch,hinch) - - def draw(self): - FigureCanvasAgg.draw(self) - self.canvas.redraw() - - def blit(self,bbox): - self.canvas.blit(bbox) - - show = draw - - def widget(self): - return self.canvas - - def start_event_loop(self,timeout): - FigureCanvasBase.start_event_loop_default(self,timeout) - start_event_loop.__doc__=FigureCanvasBase.start_event_loop_default.__doc__ - - def stop_event_loop(self): - FigureCanvasBase.stop_event_loop_default(self) - stop_event_loop.__doc__=FigureCanvasBase.stop_event_loop_default.__doc__ - -def destroy_figure(ptr, figman): - figman.window.hide() - Fltk.Fl.wait(0) # This is needed to make the last figure vanish. - Gcf.destroy(figman._num) - -class FigureManagerFltkAgg(FigureManagerBase): - """ - Public attributes - - canvas : The FigureCanvas instance - num : The Figure number - toolbar : The fltk.Toolbar - window : The fltk.Window - """ - def __init__(self, canvas, num, window): - FigureManagerBase.__init__(self, canvas, num) - #Fltk container window - t1,t2,w,h = canvas.figure.bbox.bounds - w, h = int(w), int(h) - self.window = window - self.window.size(w,h+30) - self.window_title="Figure %d" % num - self.window.label(self.window_title) - self.window.size_range(350,200) - self.window.callback(destroy_figure,self) - self.canvas = canvas - self._num = num - if matplotlib.rcParams['toolbar']=='classic': - self.toolbar = NavigationToolbar( canvas, self ) - elif matplotlib.rcParams['toolbar']=='toolbar2': - self.toolbar = NavigationToolbar2FltkAgg( canvas, self ) - else: - self.toolbar = None - self.window.add_resizable(canvas.widget()) - if self.toolbar: - self.window.add(self.toolbar.widget()) - self.toolbar.update() - self.window.show() - - def notify_axes_change(fig): - 'this will be called whenever the current axes is changed' - if self.toolbar != None: self.toolbar.update() - self.canvas.figure.add_axobserver(notify_axes_change) - - def resize(self, event): - width, height = event.width, event.height - self.toolbar.configure(width=width) # , height=height) - - def show(self): - _focus = windowing.FocusManager() - self.canvas.draw() - self.window.redraw() - - def destroy(self): - self.window.hide() - Fltk.Fl.wait(0) # This is needed to make the last figure vanish. - Gcf.destroy(self._num) - - def set_window_title(self, title): - self.window_title=title - self.window.label(title) - -class AxisMenu: - def __init__(self, toolbar): - self.toolbar=toolbar - self._naxes = toolbar.naxes - self._mbutton = Fltk.Fl_Menu_Button(0,0,50,10,"Axes") - self._mbutton.add("Select All",0,select_all,self,0) - self._mbutton.add("Invert All",0,invert_all,self,Fltk.FL_MENU_DIVIDER) - self._axis_txt=[] - self._axis_var=[] - for i in range(self._naxes): - self._axis_txt.append("Axis %d" % (i+1)) - self._mbutton.add(self._axis_txt[i],0,set_active,self,Fltk.FL_MENU_TOGGLE) - for i in range(self._naxes): - self._axis_var.append(self._mbutton.find_item(self._axis_txt[i])) - self._axis_var[i].set() - def adjust(self, naxes): - if self._naxes < naxes: - for i in range(self._naxes, naxes): - self._axis_txt.append("Axis %d" % (i+1)) - self._mbutton.add(self._axis_txt[i],0,set_active,self,Fltk.FL_MENU_TOGGLE) - for i in range(self._naxes, naxes): - self._axis_var.append(self._mbutton.find_item(self._axis_txt[i])) - self._axis_var[i].set() - elif self._naxes > naxes: - for i in range(self._naxes-1, naxes-1, -1): - self._mbutton.remove(i+2) - if(naxes): - self._axis_var=self._axis_var[:naxes-1] - self._axis_txt=self._axis_txt[:naxes-1] - else: - self._axis_var=[] - self._axis_txt=[] - self._naxes = naxes - set_active(0,self) - - def widget(self): - return self._mbutton - - def get_indices(self): - a = [i for i in range(len(self._axis_var)) if self._axis_var[i].value()] - return a - -def set_active(ptr,amenu): - amenu.toolbar.set_active(amenu.get_indices()) - -def invert_all(ptr,amenu): - for a in amenu._axis_var: - if not a.value(): a.set() - set_active(ptr,amenu) - -def select_all(ptr,amenu): - for a in amenu._axis_var: - a.set() - set_active(ptr,amenu) - -class FLTKButton: - def __init__(self, text, file, command,argument,type="classic"): - file = os.path.join(rcParams['datapath'], 'images', file) - self.im = Fltk.Fl_PNM_Image(file) - size=26 - if type=="repeat": - self.b = Fltk.Fl_Repeat_Button(0,0,size,10) - self.b.box(Fltk.FL_THIN_UP_BOX) - elif type=="classic": - self.b = Fltk.Fl_Button(0,0,size,10) - self.b.box(Fltk.FL_THIN_UP_BOX) - elif type=="light": - self.b = Fltk.Fl_Light_Button(0,0,size+20,10) - self.b.box(Fltk.FL_THIN_UP_BOX) - elif type=="pushed": - self.b = Fltk.Fl_Button(0,0,size,10) - self.b.box(Fltk.FL_UP_BOX) - self.b.down_box(Fltk.FL_DOWN_BOX) - self.b.type(Fltk.FL_TOGGLE_BUTTON) - self.tooltiptext=text+" " - self.b.tooltip(self.tooltiptext) - self.b.callback(command,argument) - self.b.image(self.im) - self.b.deimage(self.im) - self.type=type - - def widget(self): - return self.b - -class NavigationToolbar: - """ - Public attriubutes - - canvas - the FigureCanvas (FigureCanvasFltkAgg = customised fltk.Widget) - - - """ - - def __init__(self, canvas, figman): - #xmin, xmax = canvas.figure.bbox.intervalx - #height, width = 50, xmax-xmin - self.canvas = canvas - self.figman = figman - - Fltk.Fl_File_Icon.load_system_icons() - self._fc = Fltk.Fl_File_Chooser( ".", "*", Fltk.Fl_File_Chooser.CREATE, "Save Figure" ) - self._fc.hide() - t1,t2,w,h = canvas.figure.bbox.bounds - w, h = int(w), int(h) - self._group = Fltk.Fl_Pack(0,h+2,1000,26) - self._group.type(Fltk.FL_HORIZONTAL) - self._axes=self.canvas.figure.axes - self.naxes = len(self._axes) - self.omenu = AxisMenu( toolbar=self) - - self.bLeft = FLTKButton( - text="Left", file="stock_left.ppm", - command=pan,argument=(self,1,'x'),type="repeat") - - self.bRight = FLTKButton( - text="Right", file="stock_right.ppm", - command=pan,argument=(self,-1,'x'),type="repeat") - - self.bZoomInX = FLTKButton( - text="ZoomInX",file="stock_zoom-in.ppm", - command=zoom,argument=(self,1,'x'),type="repeat") - - self.bZoomOutX = FLTKButton( - text="ZoomOutX", file="stock_zoom-out.ppm", - command=zoom, argument=(self,-1,'x'),type="repeat") - - self.bUp = FLTKButton( - text="Up", file="stock_up.ppm", - command=pan,argument=(self,1,'y'),type="repeat") - - self.bDown = FLTKButton( - text="Down", file="stock_down.ppm", - command=pan,argument=(self,-1,'y'),type="repeat") - - self.bZoomInY = FLTKButton( - text="ZoomInY", file="stock_zoom-in.ppm", - command=zoom,argument=(self,1,'y'),type="repeat") - - self.bZoomOutY = FLTKButton( - text="ZoomOutY",file="stock_zoom-out.ppm", - command=zoom, argument=(self,-1,'y'),type="repeat") - - self.bSave = FLTKButton( - text="Save", file="stock_save_as.ppm", - command=save_figure, argument=self) - - self._group.end() - - def widget(self): - return self._group - - def close(self): - Gcf.destroy(self.figman._num) - - def set_active(self, ind): - self._ind = ind - self._active = [ self._axes[i] for i in self._ind ] - - def update(self): - self._axes = self.canvas.figure.axes - naxes = len(self._axes) - self.omenu.adjust(naxes) - -def pan(ptr, arg): - base,direction,axe=arg - for a in base._active: - if(axe=='x'): - a.panx(direction) - else: - a.pany(direction) - base.figman.show() - -def zoom(ptr, arg): - base,direction,axe=arg - for a in base._active: - if(axe=='x'): - a.zoomx(direction) - else: - a.zoomy(direction) - base.figman.show() - - - -def save_figure(ptr,base): - filetypes = base.canvas.get_supported_filetypes() - default_filetype = base.canvas.get_default_filetype() - sorted_filetypes = filetypes.items() - sorted_filetypes.sort() - - selected_filter = 0 - filters = [] - for i, (ext, name) in enumerate(sorted_filetypes): - filter = '%s (*.%s)' % (name, ext) - filters.append(filter) - if ext == default_filetype: - selected_filter = i - filters = '\t'.join(filters) - - file_chooser=base._fc - file_chooser.filter(filters) - file_chooser.filter_value(selected_filter) - file_chooser.show() - while file_chooser.visible() : - Fltk.Fl.wait() - fname=None - if(file_chooser.count() and file_chooser.value(0) != None): - fname="" - (status,fname)=Fltk.fl_filename_absolute(fname, 1024, file_chooser.value(0)) - - if fname is None: # Cancel - return - #start from last directory - lastDir = os.path.dirname(fname) - file_chooser.directory(lastDir) - format = sorted_filetypes[file_chooser.filter_value()][0] - - try: - base.canvas.print_figure(fname, format=format) - except IOError as msg: - err = '\n'.join(map(str, msg)) - msg = 'Failed to save %s: Error msg was\n\n%s' % ( - fname, err) - error_msg_fltk(msg) - -class NavigationToolbar2FltkAgg(NavigationToolbar2): - """ - Public attriubutes - - canvas - the FigureCanvas - figman - the Figure manager - - """ - - def __init__(self, canvas, figman): - self.canvas = canvas - self.figman = figman - NavigationToolbar2.__init__(self, canvas) - self.pan_selected=False - self.zoom_selected=False - - def set_cursor(self, cursor): - Fltk.fl_cursor(cursord[cursor],Fltk.FL_BLACK,Fltk.FL_WHITE) - - def dynamic_update(self): - self.canvas.draw() - - def pan(self,*args): - self.pan_selected=not self.pan_selected - self.zoom_selected = False - self.canvas.canvas._draw_overlay= False - if self.pan_selected: - self.bPan.widget().value(1) - else: - self.bPan.widget().value(0) - if self.zoom_selected: - self.bZoom.widget().value(1) - else: - self.bZoom.widget().value(0) - NavigationToolbar2.pan(self,args) - - def zoom(self,*args): - self.zoom_selected=not self.zoom_selected - self.canvas.canvas._draw_overlay=self.zoom_selected - self.pan_selected = False - if self.pan_selected: - self.bPan.widget().value(1) - else: - self.bPan.widget().value(0) - if self.zoom_selected: - self.bZoom.widget().value(1) - else: - self.bZoom.widget().value(0) - NavigationToolbar2.zoom(self,args) - - def configure_subplots(self,*args): - window = Fltk.Fl_Double_Window(100,100,480,240) - toolfig = Figure(figsize=(6,3)) - canvas = FigureCanvasFltkAgg(toolfig) - window.end() - toolfig.subplots_adjust(top=0.9) - tool = SubplotTool(self.canvas.figure, toolfig) - window.show() - canvas.show() - - def _init_toolbar(self): - Fltk.Fl_File_Icon.load_system_icons() - self._fc = Fltk.Fl_File_Chooser( ".", "*", Fltk.Fl_File_Chooser.CREATE, "Save Figure" ) - self._fc.hide() - t1,t2,w,h = self.canvas.figure.bbox.bounds - w, h = int(w), int(h) - self._group = Fltk.Fl_Pack(0,h+2,1000,26) - self._group.type(Fltk.FL_HORIZONTAL) - self._axes=self.canvas.figure.axes - self.naxes = len(self._axes) - self.omenu = AxisMenu( toolbar=self) - - self.bHome = FLTKButton( - text="Home", file="home.ppm", - command=self.home,argument=self) - - self.bBack = FLTKButton( - text="Back", file="back.ppm", - command=self.back,argument=self) - - self.bForward = FLTKButton( - text="Forward", file="forward.ppm", - command=self.forward,argument=self) - - self.bPan = FLTKButton( - text="Pan/Zoom",file="move.ppm", - command=self.pan,argument=self,type="pushed") - - self.bZoom = FLTKButton( - text="Zoom to rectangle",file="zoom_to_rect.ppm", - command=self.zoom,argument=self,type="pushed") - - - self.bsubplot = FLTKButton( text="Configure Subplots", file="subplots.ppm", - command = self.configure_subplots,argument=self,type="pushed") - self.bSave = FLTKButton( - text="Save", file="filesave.ppm", - command=save_figure, argument=self) - - self._group.end() - self.message = Fltk.Fl_Output(0,0,w,8) - self._group.add_resizable(self.message) - self.update() - - def widget(self): - return self._group - - def close(self): - Gcf.destroy(self.figman._num) - - def set_active(self, ind): - self._ind = ind - self._active = [ self._axes[i] for i in self._ind ] - - def update(self): - self._axes = self.canvas.figure.axes - naxes = len(self._axes) - self.omenu.adjust(naxes) - NavigationToolbar2.update(self) - - def set_message(self, s): - self.message.value(s) - - - -FigureManager = FigureManagerFltkAgg diff --git a/lib/matplotlib/backends/backend_gdk.py b/lib/matplotlib/backends/backend_gdk.py index c0790c6591bb..49583dc8649e 100644 --- a/lib/matplotlib/backends/backend_gdk.py +++ b/lib/matplotlib/backends/backend_gdk.py @@ -19,6 +19,7 @@ def fn_name(): return sys._getframe(1).f_code.co_name import numpy as np import matplotlib +from matplotlib import rcParams from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ FigureManagerBase, FigureCanvasBase @@ -138,7 +139,7 @@ def draw_image(self, gc, x, y, im): im.flipud_out() - def draw_text(self, gc, x, y, s, prop, angle, ismath): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): x, y = int(x), int(y) if x < 0 or y < 0: # window has shrunk and text is off the edge @@ -392,8 +393,8 @@ def set_dashes(self, dash_offset, dash_list): self.gdkGC.line_style = gdk.LINE_ON_OFF_DASH - def set_foreground(self, fg, isRGB=False): - GraphicsContextBase.set_foreground(self, fg, isRGB) + def set_foreground(self, fg, isRGBA=False): + GraphicsContextBase.set_foreground(self, fg, isRGBA) self.gdkGC.foreground = self.rgb_to_gdk_color(self.get_rgb()) @@ -471,4 +472,13 @@ def _print_image(self, filename, format, *args, **kwargs): pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) - pixbuf.save(filename, format) + # set the default quality, if we are writing a JPEG. + # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save + options = cbook.restrict_dict(kwargs, ['quality']) + if format in ['jpg','jpeg']: + if 'quality' not in options: + options['quality'] = rcParams['savefig.jpeg_quality'] + options['quality'] = str(options['quality']) + + pixbuf.save(filename, format, options=options) + diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index 04b0a114e34f..9a9bb9f6ff3b 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -326,7 +326,7 @@ def leave_notify_event(self, widget, event): def enter_notify_event(self, widget, event): x, y, state = event.window.get_pointer() - FigureCanvasBase.enter_notify_event(self, event, xy=(x,y)) + FigureCanvasBase.enter_notify_event(self, event, xy=(x, y)) def _get_key(self, event): if event.keyval in self.keyvald: @@ -339,7 +339,7 @@ def _get_key(self, event): for key_mask, prefix in ( [gdk.MOD4_MASK, 'super'], [gdk.MOD1_MASK, 'alt'], - [gdk.CONTROL_MASK, 'ctrl'],): + [gdk.CONTROL_MASK, 'ctrl'], ): if event.state & key_mask: key = '{0}+{1}'.format(prefix, key) @@ -360,7 +360,6 @@ def configure_event(self, widget, event): return False # finish event propagation? - def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() @@ -453,7 +452,7 @@ def print_jpeg(self, filename, *args, **kwargs): def print_png(self, filename, *args, **kwargs): return self._print_image(filename, 'png') - def _print_image(self, filename, format): + def _print_image(self, filename, format, *args, **kwargs): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) @@ -470,9 +469,18 @@ def _print_image(self, filename, format): pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) + # set the default quality, if we are writing a JPEG. + # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save + options = cbook.restrict_dict(kwargs, ['quality']) + if format in ['jpg','jpeg']: + if 'quality' not in options: + options['quality'] = rcParams['savefig.jpeg_quality'] + + options['quality'] = str(options['quality']) + if is_string_like(filename): try: - pixbuf.save(filename, format) + pixbuf.save(filename, format, options=options) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) elif is_writable_file_like(filename): @@ -480,7 +488,7 @@ def _print_image(self, filename, format): def save_callback(buf, data=None): data.write(buf) try: - pixbuf.save_to_callback(save_callback, format, user_data=filename) + pixbuf.save_to_callback(save_callback, format, user_data=filename, options=options) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) else: @@ -733,6 +741,7 @@ def get_filechooser(self): fc = FileChooserDialog( title='Save the figure', parent=self.win, + path=os.path.expanduser(rcParams.get('savefig.directory', '')), filetypes=self.canvas.get_supported_filetypes(), default_filetype=self.canvas.get_default_filetype()) fc.set_current_name(self.canvas.get_default_filename()) @@ -743,6 +752,13 @@ def save_figure(self, *args): fname, format = chooser.get_filename_from_user() chooser.destroy() if fname: + startpath = os.path.expanduser(rcParams.get('savefig.directory', '')) + if startpath == '': + # explicitly missing key or empty str signals to use cwd + rcParams['savefig.directory'] = startpath + else: + # save dir for next time + rcParams['savefig.directory'] = os.path.dirname(unicode(fname)) try: self.canvas.print_figure(fname, format=format) except Exception as e: @@ -1013,8 +1029,8 @@ def save_figure(self, *args): class FileChooserDialog(gtk.FileChooserDialog): - """GTK+ 2.4 file selector which remembers the last file/directory - selected and presents the user with a menu of supported image formats + """GTK+ 2.4 file selector which presents the user with a menu + of supported image formats """ def __init__ (self, title = 'Save file', diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 53f8e270a9fb..9dc1da1bda04 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -3,10 +3,22 @@ import os, sys def fn_name(): return sys._getframe(1).f_code.co_name +try: + import gi +except ImportError: + raise ImportError("Gtk3 backend requires pygobject to be installed.") + +try: + gi.require_version("Gtk", "3.0") +except ValueError: + raise ImportError( + "Gtk3 backend requires the GObject introspection bindings for Gtk 3 " + "to be installed.") + try: from gi.repository import Gtk, Gdk, GObject except ImportError: - raise ImportError("GTK3 backend requires pygobject to be installed.") + raise ImportError("Gtk3 backend requires pygobject to be installed.") import matplotlib from matplotlib._pylab_helpers import Gcf @@ -537,6 +549,7 @@ def get_filechooser(self): fc = FileChooserDialog( title='Save the figure', parent=self.win, + path=os.path.expanduser(rcParams.get('savefig.directory', '')), filetypes=self.canvas.get_supported_filetypes(), default_filetype=self.canvas.get_default_filetype()) fc.set_current_name(self.canvas.get_default_filename()) @@ -547,6 +560,13 @@ def save_figure(self, *args): fname, format = chooser.get_filename_from_user() chooser.destroy() if fname: + startpath = os.path.expanduser(rcParams.get('savefig.directory', '')) + if startpath == '': + # explicitly missing key or empty str signals to use cwd + rcParams['savefig.directory'] = startpath + else: + # save dir for next time + rcParams['savefig.directory'] = os.path.dirname(unicode(fname)) try: self.canvas.print_figure(fname, format=format) except Exception as e: diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index 05191bf9e28c..50cfab4dc54e 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -50,13 +50,13 @@ def set_width_height (self, width, height): def draw_path(self, gc, path, transform, rgbFace=None): if rgbFace is not None: - rgbFace = tuple(rgbFace[:3]) + rgbFace = tuple(rgbFace) linewidth = gc.get_linewidth() gc.draw_path(path, transform, linewidth, rgbFace) def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): if rgbFace is not None: - rgbFace = tuple(rgbFace[:3]) + rgbFace = tuple(rgbFace) linewidth = gc.get_linewidth() gc.draw_markers(marker_path, marker_trans, path, trans, linewidth, rgbFace) @@ -107,11 +107,10 @@ def draw_gouraud_triangle(self, gc, points, colors, transform): def draw_image(self, gc, x, y, im): im.flipud_out() nrows, ncols, data = im.as_rgba_str() - gc.draw_image(x, y, nrows, ncols, data, gc.get_clip_rectangle(), - *gc.get_clip_path()) + gc.draw_image(x, y, nrows, ncols, data) im.flipud_out() - def draw_tex(self, gc, x, y, s, prop, angle): + def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): # todo, handle props, angle, origins size = prop.get_size_in_points() texmanager = self.get_texmanager() @@ -128,7 +127,7 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle): self.mathtext_parser.parse(s, self.dpi, prop) gc.draw_mathtext(x, y, angle, 255 - image.as_array()) - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): if ismath: self._draw_mathtext(gc, x, y, s, prop, angle) else: @@ -184,12 +183,14 @@ def __init__(self): def set_alpha(self, alpha): GraphicsContextBase.set_alpha(self, alpha) _alpha = self.get_alpha() - _macosx.GraphicsContext.set_alpha(self, _alpha) + _macosx.GraphicsContext.set_alpha(self, _alpha, self.get_forced_alpha()) + rgb = self.get_rgb() + _macosx.GraphicsContext.set_foreground(self, rgb) - def set_foreground(self, fg, isRGB=False): - GraphicsContextBase.set_foreground(self, fg, isRGB) + def set_foreground(self, fg, isRGBA=False): + GraphicsContextBase.set_foreground(self, fg, isRGBA) rgb = self.get_rgb() - _macosx.GraphicsContext.set_foreground(self, rgb[:3]) + _macosx.GraphicsContext.set_foreground(self, rgb) def set_graylevel(self, fg): GraphicsContextBase.set_graylevel(self, fg) @@ -232,13 +233,6 @@ def new_figure_manager(num, *args, **kwargs): """ Create a new figure manager instance """ - 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) figure = FigureClass(*args, **kwargs) return new_figure_manager_given_figure(num, figure) diff --git a/lib/matplotlib/backends/backend_mixed.py b/lib/matplotlib/backends/backend_mixed.py index 4b1a8b95b08a..511304855514 100644 --- a/lib/matplotlib/backends/backend_mixed.py +++ b/lib/matplotlib/backends/backend_mixed.py @@ -48,6 +48,7 @@ def __init__(self, figure, width, height, dpi, vector_renderer, # the figure dpi before and after the rasterization. Although # this looks ugly, I couldn't find a better solution. -JJL self.figure=figure + self._figdpi = figure.get_dpi() self._bbox_inches_restore = bbox_inches_restore @@ -121,16 +122,19 @@ def stop_rasterizing(self): image.is_grayscale = False image.flipud_out() gc = self._renderer.new_gc() + # TODO: If the mixedmode resolution differs from the figure's + # dpi, the image must be scaled (dpi->_figdpi). Not all + # backends support this. self._renderer.draw_image( gc, - float(l)/self.dpi*72., - (float(height) - b - h)/self.dpi*72., + float(l) / self.dpi * self._figdpi, + (float(height)-b-h) / self.dpi * self._figdpi, image) self._raster_renderer = None self._rasterizing = False - # restore the figure dpi. - self.figure.set_dpi(72) + # restore the figure dpi. + self.figure.set_dpi(self._figdpi) if self._bbox_inches_restore: # when tight bbox is used r = process_figure_for_rasterizing(self.figure, diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index ff36324c6444..d8f4887452e2 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -81,7 +81,7 @@ # stack. Thus the state must be pushed onto the stack before narrowing # the clip path. This is taken care of by GraphicsContextPdf. # -# 2. Sometimes it is necessary to refer to something (e.g. font, +# 2. Sometimes it is necessary to refer to something (e.g., font, # image, or extended graphics state, which contains the alpha value) # in the page stream by a name that needs to be defined outside the # stream. PdfFile provides the methods fontName, imageObject, and @@ -93,7 +93,7 @@ # * the alpha channel of images # * image compression could be improved (PDF supports png-like compression) # * encoding of fonts, including mathtext fonts and unicode support -# * TTF support has lots of small TODOs, e.g. how do you know if a font +# * TTF support has lots of small TODOs, e.g., how do you know if a font # is serif/sans-serif, or symbolic/non-symbolic? # * draw_markers, draw_line_collection, etc. @@ -436,7 +436,7 @@ def __init__(self, filename): revision = '' self.infoDict = { - 'Creator': 'matplotlib %s, http://matplotlib.sf.net' % __version__, + 'Creator': 'matplotlib %s, http://matplotlib.org' % __version__, 'Producer': 'matplotlib pdf backend%s' % revision, 'CreationDate': datetime.today() } @@ -1064,7 +1064,7 @@ def alphaState(self, alpha): self.nextAlphaState += 1 self.alphaStates[alpha] = \ (name, { 'Type': Name('ExtGState'), - 'CA': alpha, 'ca': alpha }) + 'CA': alpha[0], 'ca': alpha[1] }) return name def hatchPattern(self, hatch_style): @@ -1313,11 +1313,12 @@ def writePathCollectionTemplates(self): self.endStream() @staticmethod - def pathOperations(path, transform, clip=None, simplify=None): + def pathOperations(path, transform, clip=None, simplify=None, sketch=None): cmds = [] last_points = None for points, code in path.iter_segments(transform, clip=clip, - simplify=simplify): + simplify=simplify, + sketch=sketch): if code == Path.MOVETO: # This is allowed anywhere in the path cmds.extend(points) @@ -1340,14 +1341,15 @@ def pathOperations(path, transform, clip=None, simplify=None): last_points = points return cmds - def writePath(self, path, transform, clip=False): + def writePath(self, path, transform, clip=False, sketch=None): if clip: clip = (0.0, 0.0, self.width * 72, self.height * 72) simplify = path.should_simplify else: clip = None simplify = False - cmds = self.pathOperations(path, transform, clip, simplify=simplify) + cmds = self.pathOperations(path, transform, clip, simplify=simplify, + sketch=sketch) self.output(*cmds) def reserveObject(self, name=''): @@ -1443,11 +1445,21 @@ def check_gc(self, gc, fillcolor=None): orig_fill = gc._fillcolor gc._fillcolor = fillcolor + orig_alphas = gc._effective_alphas + + if gc._forced_alpha: + gc._effective_alphas = (gc._alpha, gc._alpha) + elif fillcolor is None or len(fillcolor) < 4: + gc._effective_alphas = (gc._rgb[3], 1.0) + else: + gc._effective_alphas = (gc._rgb[3], fillcolor[3]) + delta = self.gc.delta(gc) if delta: self.file.output(*delta) # Restore gc to avoid unwanted side effects gc._fillcolor = orig_fill + gc._effective_alphas = orig_alphas def tex_font_mapping(self, texfont): if self.tex_font_map is None: @@ -1516,7 +1528,8 @@ def draw_path(self, gc, path, transform, rgbFace=None): self.check_gc(gc, rgbFace) self.file.writePath( path, transform, - rgbFace is None and gc.get_hatch_path() is None) + rgbFace is None and gc.get_hatch_path() is None, + gc.get_sketch_params()) self.file.output(self.gc.paint()) def draw_path_collection(self, gc, master_transform, paths, all_transforms, @@ -1527,6 +1540,8 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, # stroke (and the amount of alpha for each) is the same for # all of them can_do_optimization = True + facecolors = np.asarray(facecolors) + edgecolors = np.asarray(edgecolors) if not len(facecolors): filled = False @@ -1622,15 +1637,15 @@ def draw_gouraud_triangles(self, gc, points, colors, trans): self.check_gc(gc) self.file.output(name, Op.shading) - def _setup_textpos(self, x, y, descent, angle, oldx=0, oldy=0, olddescent=0, oldangle=0): + def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0): if angle == oldangle == 0: - self.file.output(x - oldx, (y + descent) - (oldy + olddescent), Op.textpos) + self.file.output(x - oldx, y - oldy, Op.textpos) else: angle = angle / 180.0 * pi self.file.output( cos(angle), sin(angle), -sin(angle), cos(angle), x, y, Op.textmatrix) - self.file.output(0, descent, Op.textpos) + self.file.output(0, 0, Op.textpos) def draw_mathtext(self, gc, x, y, s, prop, angle): # TODO: fix positioning and encoding @@ -1660,7 +1675,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): fonttype = global_fonttype if fonttype == 42 or num <= 255: - self._setup_textpos(ox, oy, 0, 0, oldx, oldy) + self._setup_textpos(ox, oy, 0, oldx, oldy) oldx, oldy = ox, oy if (fontname, fontsize) != prev_font: self.file.output(self.file.fontName(fontname), fontsize, @@ -1697,7 +1712,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): # Pop off the global transformation self.file.output(Op.grestore) - def draw_tex(self, gc, x, y, s, prop, angle): + def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) @@ -1762,7 +1777,7 @@ def draw_tex(self, gc, x, y, s, prop, angle): self.file.output(elt[1], elt[2], Op.selectfont) elif elt[0] == 'text': curx, cury = mytrans.transform((elt[1], elt[2])) - self._setup_textpos(curx, cury, 0, angle, oldx, oldy) + self._setup_textpos(curx, cury, angle, oldx, oldy) oldx, oldy = curx, cury if len(elt[3]) == 1: self.file.output(elt[3][0], Op.show) @@ -1772,7 +1787,7 @@ def draw_tex(self, gc, x, y, s, prop, angle): assert False self.file.output(Op.end_text) - # Then output the boxes (e.g. variable-length lines of square + # Then output the boxes (e.g., variable-length lines of square # roots). boxgc = self.new_gc() boxgc.copy_properties(gc) @@ -1789,7 +1804,7 @@ def encode_string(self, s, fonttype): return s.encode('cp1252', 'replace') return s.encode('utf-16be', 'replace') - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # TODO: combine consecutive texts into one BT/ET delimited section # This function is rather complex, since there is no way to @@ -1811,13 +1826,11 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False): if rcParams['pdf.use14corefonts']: font = self._get_font_afm(prop) l, b, w, h = font.get_str_bbox(s) - descent = -b * fontsize / 1000 fonttype = 1 else: font = self._get_font_ttf(prop) self.track_characters(font, s) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) - descent = font.get_descent() / 64.0 fonttype = rcParams['pdf.fonttype'] @@ -1857,7 +1870,7 @@ def draw_text_simple(): self.file.fontName(prop), fontsize, Op.selectfont) - self._setup_textpos(x, y, descent, angle) + self._setup_textpos(x, y, angle) self.file.output(self.encode_string(s, fonttype), Op.show, Op.end_text) def draw_text_woven(chunks): @@ -1878,7 +1891,6 @@ def draw_text_woven(chunks): # output all the 2-byte characters. for mode in (1, 2): newx = oldx = 0 - olddescent = 0 # Output a 1-byte character chunk if mode == 1: self.file.output(Op.begin_text, @@ -1888,10 +1900,9 @@ def draw_text_woven(chunks): for chunk_type, chunk in chunks: if mode == 1 and chunk_type == 1: - self._setup_textpos(newx, 0, descent, 0, oldx, 0, olddescent, 0) + self._setup_textpos(newx, 0, 0, oldx, 0, 0) self.file.output(self.encode_string(chunk, fonttype), Op.show) oldx = newx - olddescent = descent lastgind = None for c in chunk: @@ -2008,6 +2019,7 @@ class GraphicsContextPdf(GraphicsContextBase): def __init__(self, file): GraphicsContextBase.__init__(self) self._fillcolor = (0.0, 0.0, 0.0) + self._effective_alphas = (1.0, 1.0) self.file = file self.parent = None @@ -2024,7 +2036,7 @@ def strokep(self): the path, in which case it would presumably be filled. """ # _linewidth > 0: in pdf a line of width 0 is drawn at minimum - # possible device width, but e.g. agg doesn't draw at all + # possible device width, but e.g., agg doesn't draw at all return (self._linewidth > 0 and self._alpha > 0 and (len(self._rgb) <= 3 or self._rgb[3] != 0.0)) @@ -2076,8 +2088,8 @@ def dash_cmd(self, dashes): offset = 0 return [list(dash), offset, Op.setdash] - def alpha_cmd(self, alpha): - name = self.file.alphaState(alpha) + def alpha_cmd(self, alpha, forced, effective_alphas): + name = self.file.alphaState(effective_alphas) return [name, Op.setgstate] def hatch_cmd(self, hatch): @@ -2142,7 +2154,7 @@ def clip_cmd(self, cliprect, clippath): commands = ( (('_cliprect', '_clippath'), clip_cmd), # must come first since may pop - (('_alpha',), alpha_cmd), + (('_alpha', '_forced_alpha', '_effective_alphas'), alpha_cmd), (('_capstyle',), capstyle_cmd), (('_fillcolor',), fillcolor_cmd), (('_joinstyle',), joinstyle_cmd), @@ -2187,6 +2199,7 @@ def copy_properties(self, other): """ GraphicsContextBase.copy_properties(self, other) self._fillcolor = other._fillcolor + self._effective_alphas = other._effective_alphas def finalize(self): """ diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 8a8dcb16c8c9..63c48082a85f 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -7,13 +7,13 @@ import shutil import tempfile import codecs -import subprocess import atexit import weakref import matplotlib as mpl from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase +from matplotlib.backends.backend_mixed import MixedModeRenderer from matplotlib.figure import Figure from matplotlib.text import Text from matplotlib.path import Path @@ -21,7 +21,8 @@ from matplotlib import font_manager from matplotlib.ft2font import FT2Font from matplotlib.cbook import is_string_like, is_writable_file_like -from matplotlib.cbook import check_output +from matplotlib.compat import subprocess +from matplotlib.compat.subprocess import check_output ############################################################################### @@ -421,7 +422,7 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None) bl, tr = marker_path.get_extents(marker_trans).get_points() coords = bl[0] * f, bl[1] * f, tr[0] * f, tr[1] * f writeln(self.fh, r"\pgfsys@defobject{currentmarker}{\pgfqpoint{%fin}{%fin}}{\pgfqpoint{%fin}{%fin}}{" % coords) - self._print_pgf_path(marker_path, marker_trans) + self._print_pgf_path(None, marker_path, marker_trans) self._pgf_path_draw(stroke=gc.get_linewidth() != 0.0, fill=rgbFace is not None) writeln(self.fh, r"}") @@ -441,7 +442,7 @@ def draw_path(self, gc, path, transform, rgbFace=None): # draw the path self._print_pgf_clip(gc) self._print_pgf_path_styles(gc, rgbFace) - self._print_pgf_path(path, transform) + self._print_pgf_path(gc, path, transform) self._pgf_path_draw(stroke=gc.get_linewidth() != 0.0, fill=rgbFace is not None) writeln(self.fh, r"\end{pgfscope}") @@ -452,7 +453,7 @@ def draw_path(self, gc, path, transform, rgbFace=None): # combine clip and path for clipping self._print_pgf_clip(gc) - self._print_pgf_path(path, transform) + self._print_pgf_path(gc, path, transform) writeln(self.fh, r"\pgfusepath{clip}") # build pattern definition @@ -461,7 +462,7 @@ def draw_path(self, gc, path, transform, rgbFace=None): writeln(self.fh, r"\pgfpathrectangle{\pgfqpoint{0in}{0in}}{\pgfqpoint{1in}{1in}}") writeln(self.fh, r"\pgfusepath{clip}") scale = mpl.transforms.Affine2D().scale(self.dpi) - self._print_pgf_path(gc.get_hatch_path(), scale) + self._print_pgf_path(None, gc.get_hatch_path(), scale) self._pgf_path_draw(stroke=True) writeln(self.fh, r"\end{pgfscope}") writeln(self.fh, r"}") @@ -495,7 +496,7 @@ def _print_pgf_clip(self, gc): # check for clip path clippath, clippath_trans = gc.get_clip_path() if clippath is not None: - self._print_pgf_path(clippath, clippath_trans) + self._print_pgf_path(gc, clippath, clippath_trans) writeln(self.fh, r"\pgfusepath{clip}") def _print_pgf_path_styles(self, gc, rgbFace): @@ -513,14 +514,18 @@ def _print_pgf_path_styles(self, gc, rgbFace): # filling has_fill = rgbFace is not None - path_is_transparent = gc.get_alpha() != 1.0 - fill_is_transparent = has_fill and (len(rgbFace) > 3) and (rgbFace[3] != 1.0) + + if gc.get_forced_alpha(): + fillopacity = strokeopacity = gc.get_alpha() + else: + strokeopacity = gc.get_rgb()[3] + fillopacity = rgbFace[3] if has_fill and len(rgbFace) > 3 else 1.0 + if has_fill: writeln(self.fh, r"\definecolor{currentfill}{rgb}{%f,%f,%f}" % tuple(rgbFace[:3])) writeln(self.fh, r"\pgfsetfillcolor{currentfill}") - if has_fill and (path_is_transparent or fill_is_transparent): - opacity = gc.get_alpha() * 1.0 if not fill_is_transparent else rgbFace[3] - writeln(self.fh, r"\pgfsetfillopacity{%f}" % opacity) + if has_fill and fillopacity != 1.0: + writeln(self.fh, r"\pgfsetfillopacity{%f}" % fillopacity) # linewidth and color lw = gc.get_linewidth() * mpl_pt_to_in * latex_in_to_pt @@ -528,25 +533,31 @@ def _print_pgf_path_styles(self, gc, rgbFace): writeln(self.fh, r"\pgfsetlinewidth{%fpt}" % lw) writeln(self.fh, r"\definecolor{currentstroke}{rgb}{%f,%f,%f}" % stroke_rgba[:3]) writeln(self.fh, r"\pgfsetstrokecolor{currentstroke}") - if gc.get_alpha() != 1.0: - writeln(self.fh, r"\pgfsetstrokeopacity{%f}" % gc.get_alpha()) + if strokeopacity != 1.0: + writeln(self.fh, r"\pgfsetstrokeopacity{%f}" % strokeopacity) # line style dash_offset, dash_list = gc.get_dashes() - ls = gc.get_linestyle(None) - if ls == "solid": + if dash_list is None: writeln(self.fh, r"\pgfsetdash{}{0pt}") - elif (ls == "dashed" or ls == "dashdot" or ls == "dotted"): + else: dash_str = r"\pgfsetdash{" for dash in dash_list: dash_str += r"{%fpt}" % dash dash_str += r"}{%fpt}" % dash_offset writeln(self.fh, dash_str) - def _print_pgf_path(self, path, transform): + def _print_pgf_path(self, gc, path, transform): f = 1. / self.dpi + # check for clip box + bbox = gc.get_clip_rectangle() if gc else None + if bbox: + p1, p2 = bbox.get_points() + clip = (p1[0], p1[1], p2[0], p2[1]) + else: + clip = None # build path - for points, code in path.iter_segments(transform): + for points, code in path.iter_segments(transform, clip=clip): if code == Path.MOVETO: x, y = tuple(points) writeln(self.fh, r"\pgfpathmoveto{\pgfqpoint{%fin}{%fin}}" % @@ -595,30 +606,53 @@ def draw_image(self, gc, x, y, im): writeln(self.fh, r"\pgftext[at=\pgfqpoint{%fin}{%fin},left,bottom]{\pgfimage[interpolate=true,width=%fin,height=%fin]{%s}}" % (x * f, y * f, w * f, h * f, fname_img)) writeln(self.fh, r"\end{pgfscope}") - def draw_tex(self, gc, x, y, s, prop, angle, ismath="TeX!"): - self.draw_text(gc, x, y, s, prop, angle, ismath) + def draw_tex(self, gc, x, y, s, prop, angle, ismath="TeX!", mtext=None): + self.draw_text(gc, x, y, s, prop, angle, ismath, mtext) - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): + # prepare string for tex s = common_texification(s) - - # apply font properties prop_cmds = _font_properties_str(prop) s = ur"{%s %s}" % (prop_cmds, s) - # draw text at given coordinates - x = x * 1. / self.dpi - y = y * 1. / self.dpi + writeln(self.fh, r"\begin{pgfscope}") + alpha = gc.get_alpha() if alpha != 1.0: writeln(self.fh, r"\pgfsetfillopacity{%f}" % alpha) writeln(self.fh, r"\pgfsetstrokeopacity{%f}" % alpha) - stroke_rgb = tuple(gc.get_rgb())[:3] - if stroke_rgb != (0, 0, 0): - writeln(self.fh, r"\definecolor{textcolor}{rgb}{%f,%f,%f}" % stroke_rgb) + rgb = tuple(gc.get_rgb())[:3] + if rgb != (0, 0, 0): + writeln(self.fh, r"\definecolor{textcolor}{rgb}{%f,%f,%f}" % rgb) writeln(self.fh, r"\pgfsetstrokecolor{textcolor}") writeln(self.fh, r"\pgfsetfillcolor{textcolor}") - writeln(self.fh, "\\pgftext[left,bottom,x=%fin,y=%fin,rotate=%f]{%s}\n" % (x, y, angle, s)) + + f = 1.0 / self.figure.dpi + text_args = [] + if angle == 0 or mtext.get_rotation_mode() == "anchor": + # if text anchoring can be supported, get the original coordinates + # and add alignment information + x, y = mtext.get_transform().transform_point(mtext.get_position()) + text_args.append("x=%fin" % (x * f)) + text_args.append("y=%fin" % (y * f)) + + halign = {"left": "left", "right": "right", "center": ""} + valign = {"top": "top", "bottom": "bottom", + "baseline": "base", "center": ""} + text_args.append(halign[mtext.get_ha()]) + text_args.append(valign[mtext.get_va()]) + else: + # if not, use the text layout provided by matplotlib + text_args.append("x=%fin" % (x * f)) + text_args.append("y=%fin" % (y * f)) + text_args.append("left") + text_args.append("base") + + if angle != 0: + text_args.append("rotate=%f" % angle) + + writeln(self.fh, r"\pgftext[%s]{%s}" % (",".join(text_args), s)) writeln(self.fh, r"\end{pgfscope}") def get_text_width_height_descent(self, s, prop, ismath): @@ -705,7 +739,7 @@ def __init__(self, *args): def get_default_filetype(self): return 'pdf' - def _print_pgf_to_fh(self, fh): + def _print_pgf_to_fh(self, fh, *args, **kwargs): header_text = r"""%% Creator: Matplotlib, PGF backend %% %% To include the figure in your LaTeX document, write @@ -734,6 +768,7 @@ def _print_pgf_to_fh(self, fh): # get figure size in inch w, h = self.figure.get_figwidth(), self.figure.get_figheight() + dpi = self.figure.get_dpi() # create pgfpicture environment and write the pgf code fh.write(header_text) @@ -744,7 +779,10 @@ def _print_pgf_to_fh(self, fh): writeln(fh, r"\begin{pgfpicture}") writeln(fh, r"\pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{%fin}{%fin}}" % (w, h)) writeln(fh, r"\pgfusepath{use as bounding box}") - renderer = RendererPgf(self.figure, fh) + _bbox_inches_restore = kwargs.pop("bbox_inches_restore", None) + renderer = MixedModeRenderer(self.figure, w, h, dpi, + RendererPgf(self.figure, fh), + bbox_inches_restore=_bbox_inches_restore) self.figure.draw(renderer) # end the pgfpicture environment @@ -763,14 +801,14 @@ def print_pgf(self, fname_or_fh, *args, **kwargs): # figure out where the pgf is to be written to if is_string_like(fname_or_fh): with codecs.open(fname_or_fh, "w", encoding="utf-8") as fh: - self._print_pgf_to_fh(fh) + self._print_pgf_to_fh(fh, *args, **kwargs) elif is_writable_file_like(fname_or_fh): raise ValueError("saving pgf to a stream is not supported, " + "consider using the pdf option of the pgf-backend") else: raise ValueError("filename must be a path") - def _print_pdf_to_fh(self, fh): + def _print_pdf_to_fh(self, fh, *args, **kwargs): w, h = self.figure.get_figwidth(), self.figure.get_figheight() try: @@ -781,7 +819,7 @@ def _print_pdf_to_fh(self, fh): fname_pdf = os.path.join(tmpdir, "figure.pdf") # print figure to pgf and compile it with latex - self.print_pgf(fname_pgf) + self.print_pgf(fname_pgf, *args, **kwargs) latex_preamble = get_preamble() latex_fontspec = get_fontspec() @@ -823,13 +861,13 @@ def print_pdf(self, fname_or_fh, *args, **kwargs): # figure out where the pdf is to be written to if is_string_like(fname_or_fh): with open(fname_or_fh, "wb") as fh: - self._print_pdf_to_fh(fh) + self._print_pdf_to_fh(fh, *args, **kwargs) elif is_writable_file_like(fname_or_fh): - self._print_pdf_to_fh(fname_or_fh) + self._print_pdf_to_fh(fname_or_fh, *args, **kwargs) else: raise ValueError("filename must be a path or a file-like object") - def _print_png_to_fh(self, fh): + def _print_png_to_fh(self, fh, *args, **kwargs): converter = make_pdf_to_png_converter() try: @@ -838,7 +876,7 @@ def _print_png_to_fh(self, fh): fname_pdf = os.path.join(tmpdir, "figure.pdf") fname_png = os.path.join(tmpdir, "figure.png") # create pdf and try to convert it to png - self.print_pdf(fname_pdf) + self.print_pdf(fname_pdf, *args, **kwargs) converter(fname_pdf, fname_png, dpi=self.figure.dpi) # copy file contents to target with open(fname_png, "rb") as fh_src: @@ -855,59 +893,12 @@ def print_png(self, fname_or_fh, *args, **kwargs): """ if is_string_like(fname_or_fh): with open(fname_or_fh, "wb") as fh: - self._print_png_to_fh(fh) + self._print_png_to_fh(fh, *args, **kwargs) elif is_writable_file_like(fname_or_fh): - self._print_png_to_fh(fname_or_fh) + self._print_png_to_fh(fname_or_fh, *args, **kwargs) else: raise ValueError("filename must be a path or a file-like object") - def _render_texts_pgf(self, fh): - # TODO: currently unused code path - - # alignment anchors - valign = {"top": "top", "bottom": "bottom", "baseline": "base", "center": ""} - halign = {"left": "left", "right": "right", "center": ""} - # alignment anchors for 90deg. rotated labels - rvalign = {"top": "left", "bottom": "right", "baseline": "right", "center": ""} - rhalign = {"left": "top", "right": "bottom", "center": ""} - - # TODO: matplotlib does not hide unused tick labels yet, workaround - for tick in self.figure.findobj(mpl.axis.Tick): - tick.label1.set_visible(tick.label1On) - tick.label2.set_visible(tick.label2On) - # TODO: strange, first legend label is always "None", workaround - for legend in self.figure.findobj(mpl.legend.Legend): - labels = legend.findobj(mpl.text.Text) - labels[0].set_visible(False) - # TODO: strange, legend child labels are duplicated, - # find a list of unique text objects as workaround - texts = self.figure.findobj(match=Text, include_self=False) - texts = list(set(texts)) - - # draw text elements - for text in texts: - s = text.get_text() - if not s or not text.get_visible(): - continue - - s = common_texification(s) - - fontsize = text.get_fontsize() - angle = text.get_rotation() - transform = text.get_transform() - x, y = transform.transform_point(text.get_position()) - x = x * 1.0 / self.figure.dpi - y = y * 1.0 / self.figure.dpi - # TODO: positioning behavior unknown for rotated elements - # right now only the alignment for 90deg rotations is correct - if angle == 90.: - align = rvalign[text.get_va()] + "," + rhalign[text.get_ha()] - else: - align = valign[text.get_va()] + "," + halign[text.get_ha()] - - s = ur"{\fontsize{%f}{%f}\selectfont %s}" % (fontsize, fontsize*1.2, s) - writeln(fh, ur"\pgftext[%s,x=%fin,y=%fin,rotate=%f]{%s}" % (align,x,y,angle,s)) - def get_renderer(self): return RendererPgf(self.figure, None) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 91168457aedb..7c83d7013019 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -87,7 +87,7 @@ def gs_version(self): except KeyError: pass - from subprocess import Popen, PIPE + from matplotlib.compat.subprocess import Popen, PIPE pipe = Popen(self.gs_exe + " --version", shell=True, stdout=PIPE).stdout if sys.version_info[0] >= 3: @@ -587,7 +587,7 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None) if rgbFace[0]==rgbFace[1] and rgbFace[0]==rgbFace[2]: ps_color = '%1.3f setgray' % rgbFace[0] else: - ps_color = '%1.3f %1.3f %1.3f setrgbcolor' % rgbFace + ps_color = '%1.3f %1.3f %1.3f setrgbcolor' % rgbFace[:3] # construct the generic marker command: ps_cmd = ['/o {', 'gsave', 'newpath', 'translate'] # dont want the translate to be global @@ -649,7 +649,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, self._path_collection_id += 1 - def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): + def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): """ draw a Text instance """ @@ -659,18 +659,18 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): color = '%1.3f,%1.3f,%1.3f'% gc.get_rgb()[:3] fontcmd = {'sans-serif' : r'{\sffamily %s}', 'monospace' : r'{\ttfamily %s}'}.get( - rcParams['font.family'], r'{\rmfamily %s}') + rcParams['font.family'][0], r'{\rmfamily %s}') s = fontcmd % s tex = r'\color[rgb]{%s} %s' % (color, s) corr = 0#w/2*(fontsize-10)/10 if rcParams['text.latex.preview']: # use baseline alignment! - pos = _nums_to_str(x-corr, y+bl) + pos = _nums_to_str(x-corr, y) self.psfrag.append(r'\psfrag{%s}[Bl][Bl][1][%f]{\fontsize{%f}{%f}%s}'%(thetext, angle, fontsize, fontsize*1.25, tex)) else: # stick to the bottom alignment, but this may give incorrect baseline some times. - pos = _nums_to_str(x-corr, y) + pos = _nums_to_str(x-corr, y-bl) self.psfrag.append(r'\psfrag{%s}[bl][bl][1][%f]{\fontsize{%f}{%f}%s}'%(thetext, angle, fontsize, fontsize*1.25, tex)) ps = """\ @@ -684,7 +684,7 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): self._pswriter.write(ps) self.textcnt += 1 - def draw_text(self, gc, x, y, s, prop, angle, ismath): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): """ draw a Text instance """ @@ -755,7 +755,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath): #print 'text', s lines = [] thisx = 0 - thisy = font.get_descent() / 64.0 + thisy = 0 for c in s: ccode = ord(c) gind = cmap.get(ccode) @@ -972,11 +972,6 @@ def print_ps(self, outfile, *args, **kwargs): def print_eps(self, outfile, *args, **kwargs): return self._print_ps(outfile, 'eps', *args, **kwargs) - - - - - def _print_ps(self, outfile, format, *args, **kwargs): papertype = kwargs.pop("papertype", rcParams['ps.papersize']) papertype = papertype.lower() @@ -1104,8 +1099,7 @@ def write(self, *kl, **kwargs): self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) - fd, tmpfile = mkstemp() - with io.open(fd, 'wb') as raw_fh: + def print_figure_impl(): if sys.version_info[0] >= 3: fh = io.TextIOWrapper(raw_fh, encoding="ascii") else: @@ -1180,20 +1174,39 @@ def write(self, *kl, **kwargs): if not isEPSF: print("%%EOF", file=fh) fh.flush() - if rcParams['ps.usedistiller'] == 'ghostscript': - gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) - elif rcParams['ps.usedistiller'] == 'xpdf': - xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) - - if passed_in_file_object: - with open(tmpfile, 'rb') as fh: - outfile.write(fh.read()) + if sys.version_info[0] >= 3: + fh.detach() + + if rcParams['ps.usedistiller']: + # We are going to use an external program to process the output. + # Write to a temporary file. + fd, tmpfile = mkstemp() + with io.open(fd, 'wb') as raw_fh: + print_figure_impl() else: - with open(outfile, 'w') as fh: - pass - mode = os.stat(outfile).st_mode - shutil.move(tmpfile, outfile) - os.chmod(outfile, mode) + # Write directly to outfile. + if passed_in_file_object: + raw_fh = outfile + print_figure_impl() + else: + with open(outfile, 'wb') as raw_fh: + print_figure_impl() + + if rcParams['ps.usedistiller']: + if rcParams['ps.usedistiller'] == 'ghostscript': + gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) + elif rcParams['ps.usedistiller'] == 'xpdf': + xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox) + + if passed_in_file_object: + with open(tmpfile, 'rb') as fh: + outfile.write(fh.read()) + else: + with open(outfile, 'w') as fh: + pass + mode = os.stat(outfile).st_mode + shutil.move(tmpfile, outfile) + os.chmod(outfile, mode) def _print_figure_tex(self, outfile, format, dpi, facecolor, edgecolor, orientation, isLandscape, papertype, diff --git a/lib/matplotlib/backends/backend_qt.py b/lib/matplotlib/backends/backend_qt.py deleted file mode 100644 index 9b009cf5ac8d..000000000000 --- a/lib/matplotlib/backends/backend_qt.py +++ /dev/null @@ -1,498 +0,0 @@ -from __future__ import division, print_function -import math -import os -import sys -import warnings - -from matplotlib import MatplotlibDeprecationWarning as mplDeprecation - -warnings.warn("QT3-based backends are deprecated and will be removed after" - " the v1.2.x release. Use the equivalent QT4 backend instead.", - mplDeprecation) - -import matplotlib -from matplotlib import verbose -from matplotlib.cbook import is_string_like, onetrue -from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ - FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors -from matplotlib.backend_bases import ShowBase - -from matplotlib._pylab_helpers import Gcf -from matplotlib.figure import Figure -from matplotlib.mathtext import MathTextParser -from matplotlib.widgets import SubplotTool - -try: - import qt -except ImportError: - raise ImportError("Qt backend requires pyqt to be installed." - " NOTE: QT3-based backends will not work in" - " Python 3.") - -backend_version = "0.9.1" -def fn_name(): return sys._getframe(1).f_code.co_name - -DEBUG = False - -cursord = { - cursors.MOVE : qt.Qt.PointingHandCursor, - cursors.HAND : qt.Qt.WaitCursor, - cursors.POINTER : qt.Qt.ArrowCursor, - cursors.SELECT_REGION : qt.Qt.CrossCursor, - } - -def draw_if_interactive(): - """ - Is called after every pylab drawing command - """ - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager != None: - figManager.canvas.draw() - -def _create_qApp(): - """ - Only one qApp can exist at a time, so check before creating one - """ - if qt.QApplication.startingUp(): - if DEBUG: print("Starting up QApplication") - global qApp - qApp = qt.QApplication( [" "] ) - qt.QObject.connect( qApp, qt.SIGNAL( "lastWindowClosed()" ), - qApp, qt.SLOT( "quit()" ) ) - #remember that matplotlib created the qApp - will be used by show() - _create_qApp.qAppCreatedHere = True - -_create_qApp.qAppCreatedHere = False - -class Show(ShowBase): - def mainloop(self): - if _create_qApp.qAppCreatedHere: - qt.qApp.exec_loop() - -show = Show() - - -def new_figure_manager( num, *args, **kwargs ): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasQT(figure) - manager = FigureManagerQT(canvas, num) - return manager - - -class FigureCanvasQT( qt.QWidget, FigureCanvasBase ): - keyvald = { qt.Qt.Key_Control : 'control', - qt.Qt.Key_Shift : 'shift', - qt.Qt.Key_Alt : 'alt', - } - # left 1, middle 2, right 3 - buttond = {1:1, 2:3, 4:2} - def __init__( self, figure ): - if DEBUG: print('FigureCanvasQt: ', figure) - _create_qApp() - - qt.QWidget.__init__( self, None, "QWidget figure" ) - FigureCanvasBase.__init__( self, figure ) - self.figure = figure - self.setMouseTracking( True ) - - w,h = self.get_width_height() - self.resize( w, h ) - - def enterEvent(self, event): - FigureCanvasBase.enter_notify_event(self, event) - - def leaveEvent(self, event): - FigureCanvasBase.leave_notify_event(self, event) - - def mousePressEvent( self, event ): - x = event.pos().x() - # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height - event.pos().y() - button = self.buttond[event.button()] - FigureCanvasBase.button_press_event( self, x, y, button ) - if DEBUG: print('button pressed:', event.button()) - - def mouseDoubleClickEvent( self, event ): - x = event.pos().x() - # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height - event.pos().y() - button = self.buttond[event.button()] - FigureCanvasBase.button_press_event( self, x, y, button, dblclick=True ) - if DEBUG: print('button doubleclicked:', event.button()) - - def mouseMoveEvent( self, event ): - x = event.x() - # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height - event.y() - FigureCanvasBase.motion_notify_event( self, x, y ) - if DEBUG: print('mouse move') - - def mouseReleaseEvent( self, event ): - x = event.x() - # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height - event.y() - button = self.buttond[event.button()] - FigureCanvasBase.button_release_event( self, x, y, button ) - if DEBUG: print('button released') - - def keyPressEvent( self, event ): - key = self._get_key( event ) - FigureCanvasBase.key_press_event( self, key ) - if DEBUG: print('key press', key) - - def keyReleaseEvent( self, event ): - key = self._get_key(event) - FigureCanvasBase.key_release_event( self, key ) - if DEBUG: print('key release', key) - - def resizeEvent( self, event ): - if DEBUG: print('resize (%d x %d)' % (event.size().width(), event.size().height())) - qt.QWidget.resizeEvent( self, event ) - w = event.size().width() - h = event.size().height() - if DEBUG: print("FigureCanvasQt.resizeEvent(", w, ",", h, ")") - dpival = self.figure.dpi - winch = w/dpival - hinch = h/dpival - self.figure.set_size_inches( winch, hinch ) - self.draw() - - def resize( self, w, h ): - # Pass through to Qt to resize the widget. - qt.QWidget.resize( self, w, h ) - - # Resize the figure by converting pixels to inches. - pixelPerInch = self.figure.dpi - wInch = w / pixelPerInch - hInch = h / pixelPerInch - self.figure.set_size_inches( wInch, hInch ) - - # Redraw everything. - self.draw() - - def sizeHint( self ): - w, h = self.get_width_height() - return qt.QSize( w, h ) - - def minumumSizeHint( self ): - return qt.QSize( 10, 10 ) - - def _get_key( self, event ): - if event.key() < 256: - key = event.text().latin1() - elif event.key() in self.keyvald: - key = self.keyvald[ event.key() ] - else: - key = None - - # TODO: Handle ctrl, alt, super modifiers. qt4 backend has implemented. - - return key - - def flush_events(self): - qt.qApp.processEvents() - - def start_event_loop(self,timeout): - FigureCanvasBase.start_event_loop_default(self,timeout) - start_event_loop.__doc__=FigureCanvasBase.start_event_loop_default.__doc__ - - def stop_event_loop(self): - FigureCanvasBase.stop_event_loop_default(self) - stop_event_loop.__doc__=FigureCanvasBase.stop_event_loop_default.__doc__ - -class FigureManagerQT( FigureManagerBase ): - """ - Public attributes - - canvas : The FigureCanvas instance - num : The Figure number - toolbar : The qt.QToolBar - window : The qt.QMainWindow - """ - - def __init__( self, canvas, num ): - if DEBUG: print('FigureManagerQT.%s' % fn_name()) - FigureManagerBase.__init__( self, canvas, num ) - self.canvas = canvas - self.window = qt.QMainWindow( None, None, qt.Qt.WDestructiveClose ) - self.window.closeEvent = self._widgetCloseEvent - - centralWidget = qt.QWidget( self.window ) - self.canvas.reparent( centralWidget, qt.QPoint( 0, 0 ) ) - - # Give the keyboard focus to the figure instead of the manager - self.canvas.setFocusPolicy( qt.QWidget.ClickFocus ) - self.canvas.setFocus() - self.set_window_title( "Figure %d" % num ) - - self.window._destroying = False - - self.toolbar = self._get_toolbar(self.canvas, centralWidget) - - # Use a vertical layout for the plot and the toolbar. Set the - # stretch to all be in the plot so the toolbar doesn't resize. - self.layout = qt.QVBoxLayout( centralWidget ) - self.layout.addWidget( self.canvas, 1 ) - - if self.toolbar: - self.layout.addWidget( self.toolbar, 0 ) - - self.window.setCentralWidget( centralWidget ) - - # Reset the window height so the canvas will be the right - # size. This ALMOST works right. The first issue is that the - # height w/ a toolbar seems to be off by just a little bit (so - # we add 4 pixels). The second is that the total width/height - # is slightly smaller that we actually want. It seems like - # the border of the window is being included in the size but - # AFAIK there is no way to get that size. - w = self.canvas.width() - h = self.canvas.height() - if self.toolbar: - h += self.toolbar.height() + 4 - self.window.resize( w, h ) - - if matplotlib.is_interactive(): - self.window.show() - - def notify_axes_change( fig ): - # This will be called whenever the current axes is changed - if self.toolbar != None: self.toolbar.update() - self.canvas.figure.add_axobserver( notify_axes_change ) - - def _widgetclosed( self ): - if self.window._destroying: return - self.window._destroying = True - Gcf.destroy(self.num) - - def _widgetCloseEvent( self, event ): - self._widgetclosed() - qt.QWidget.closeEvent( self.window, event ) - - def _get_toolbar(self, canvas, parent): - # must be inited after the window, drawingArea and figure - # attrs are set - if matplotlib.rcParams['toolbar'] == 'classic': - print("Classic toolbar is not yet supported") - elif matplotlib.rcParams['toolbar'] == 'toolbar2': - toolbar = NavigationToolbar2QT(canvas, parent) - else: - toolbar = None - return toolbar - - def resize(self, width, height): - 'set the canvas size in pixels' - self.window.resize(width, height) - - def show(self): - self.window.show() - - def destroy( self, *args ): - if self.window._destroying: return - self.window._destroying = True - if self.toolbar: self.toolbar.destroy() - if DEBUG: print("destroy figure manager") - self.window.close(True) - - def get_window_title(self): - return str(self.window.caption()) - - def set_window_title(self, title): - self.window.setCaption(title) - -class NavigationToolbar2QT( NavigationToolbar2, qt.QWidget ): - def __init__( self, canvas, parent ): - self.canvas = canvas - self.buttons = {} - - qt.QWidget.__init__( self, parent ) - - # Layout toolbar buttons horizontally. - self.layout = qt.QHBoxLayout( self ) - self.layout.setMargin( 2 ) - - NavigationToolbar2.__init__( self, canvas ) - - def _init_toolbar( self ): - basedir = os.path.join(matplotlib.rcParams[ 'datapath' ],'images') - - for text, tooltip_text, image_file, callback in self.toolitems: - if text == None: - self.layout.addSpacing( 8 ) - continue - - fname = os.path.join(basedir, image_file + '.ppm') - image = qt.QPixmap() - image.load( fname ) - - button = qt.QPushButton( qt.QIconSet( image ), "", self ) - qt.QToolTip.add( button, tooltip_text ) - - self.buttons[ text ] = button - - # The automatic layout doesn't look that good - it's too close - # to the images so add a margin around it. - margin = 4 - button.setFixedSize( image.width()+margin, image.height()+margin ) - - qt.QObject.connect( button, qt.SIGNAL( 'clicked()' ), - getattr( self, callback ) ) - self.layout.addWidget( button ) - - self.buttons[ 'Pan' ].setToggleButton( True ) - self.buttons[ 'Zoom' ].setToggleButton( True ) - - # Add the x,y location widget at the right side of the toolbar - # The stretch factor is 1 which means any resizing of the toolbar - # will resize this label instead of the buttons. - self.locLabel = qt.QLabel( "", self ) - self.locLabel.setAlignment( qt.Qt.AlignRight | qt.Qt.AlignVCenter ) - self.locLabel.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Ignored, - qt.QSizePolicy.Ignored)) - self.layout.addWidget( self.locLabel, 1 ) - - # reference holder for subplots_adjust window - self.adj_window = None - - - def destroy( self ): - for text, tooltip_text, image_file, callback in self.toolitems: - if text is not None: - qt.QObject.disconnect( self.buttons[ text ], - qt.SIGNAL( 'clicked()' ), - getattr( self, callback ) ) - - def pan( self, *args ): - self.buttons[ 'Zoom' ].setOn( False ) - NavigationToolbar2.pan( self, *args ) - - def zoom( self, *args ): - self.buttons[ 'Pan' ].setOn( False ) - NavigationToolbar2.zoom( self, *args ) - - def dynamic_update( self ): - self.canvas.draw() - - def set_message( self, s ): - self.locLabel.setText( s ) - - def set_cursor( self, cursor ): - if DEBUG: print('Set cursor' , cursor) - qt.QApplication.restoreOverrideCursor() - qt.QApplication.setOverrideCursor( qt.QCursor( cursord[cursor] ) ) - - def draw_rubberband( self, event, x0, y0, x1, y1 ): - height = self.canvas.figure.bbox.height - y1 = height - y1 - y0 = height - y0 - - w = abs(x1 - x0) - h = abs(y1 - y0) - - rect = [ int(val)for val in (min(x0,x1), min(y0, y1), w, h) ] - self.canvas.drawRectangle( rect ) - - def configure_subplots(self): - self.adj_window = qt.QMainWindow(None, None, qt.Qt.WDestructiveClose) - win = self.adj_window - win.setCaption("Subplot Configuration Tool") - - toolfig = Figure(figsize=(6,3)) - toolfig.subplots_adjust(top=0.9) - w = int (toolfig.bbox.width) - h = int (toolfig.bbox.height) - - canvas = self._get_canvas(toolfig) - tool = SubplotTool(self.canvas.figure, toolfig) - centralWidget = qt.QWidget(win) - canvas.reparent(centralWidget, qt.QPoint(0, 0)) - win.setCentralWidget(centralWidget) - - layout = qt.QVBoxLayout(centralWidget) - layout.addWidget(canvas, 1) - - win.resize(w, h) - canvas.setFocus() - win.show() - - def _get_canvas(self, fig): - return FigureCanvasQT(fig) - - def save_figure(self, *args): - filetypes = self.canvas.get_supported_filetypes_grouped() - sorted_filetypes = filetypes.items() - sorted_filetypes.sort() - default_filetype = self.canvas.get_default_filetype() - - start = self.canvas.get_default_filename() - filters = [] - selectedFilter = None - for name, exts in sorted_filetypes: - exts_list = " ".join(['*.%s' % ext for ext in exts]) - filter = '%s (%s)' % (name, exts_list) - if default_filetype in exts: - selectedFilter = filter - filters.append(filter) - filters = ';;'.join(filters) - - fname = qt.QFileDialog.getSaveFileName( - start, filters, self, "Save image", "Choose a filename to save to", - selectedFilter) - if fname: - try: - self.canvas.print_figure( unicode(fname) ) - except Exception as e: - qt.QMessageBox.critical( - self, "Error saving file", str(e), - qt.QMessageBox.Ok, qt.QMessageBox.NoButton) - - def set_history_buttons( self ): - canBackward = ( self._views._pos > 0 ) - canForward = ( self._views._pos < len( self._views._elements ) - 1 ) - self.buttons[ 'Back' ].setEnabled( canBackward ) - self.buttons[ 'Forward' ].setEnabled( canForward ) - -# set icon used when windows are minimized -try: - # TODO: This is badly broken - qt.window_set_default_icon_from_file ( - os.path.join( matplotlib.rcParams['datapath'], 'images', 'matplotlib.svg' ) ) -except: - verbose.report( 'Could not load matplotlib icon: %s' % sys.exc_info()[1] ) - - -def error_msg_qt( msg, parent=None ): - if not is_string_like( msg ): - msg = ','.join( map( str,msg ) ) - - qt.QMessageBox.warning( None, "Matplotlib", msg, qt.QMessageBox.Ok ) - -def exception_handler( type, value, tb ): - """Handle uncaught exceptions - It does not catch SystemExit - """ - msg = '' - # get the filename attribute if available (for IOError) - if hasattr(value, 'filename') and value.filename != None: - msg = value.filename + ': ' - if hasattr(value, 'strerror') and value.strerror != None: - msg += value.strerror - else: - msg += str(value) - - if len( msg ) : error_msg_qt( msg ) - - -FigureManager = FigureManagerQT diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 933016f80e03..53b7210489d2 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -1,6 +1,7 @@ from __future__ import division, print_function import math import os +import re import signal import sys @@ -53,6 +54,13 @@ def _create_qApp(): global qApp app = QtGui.QApplication.instance() if app is None: + + # check for DISPLAY env variable on X11 build of Qt + if hasattr(QtGui, "QX11Info"): + display = os.environ.get('DISPLAY') + if display is None or not re.search(':\d', display): + raise RuntimeError('Invalid DISPLAY variable') + qApp = QtGui.QApplication( [" "] ) QtCore.QObject.connect( qApp, QtCore.SIGNAL( "lastWindowClosed()" ), qApp, QtCore.SLOT( "quit()" ) ) @@ -608,7 +616,7 @@ def set_message( self, s ): def set_cursor( self, cursor ): if DEBUG: print('Set cursor' , cursor) - self.canvas.window().setCursor(cursord[cursor]) + self.canvas.setCursor(cursord[cursor]) def draw_rubberband( self, event, x0, y0, x1, y1 ): height = self.canvas.figure.bbox.height @@ -644,7 +652,9 @@ def save_figure(self, *args): sorted_filetypes.sort() default_filetype = self.canvas.get_default_filetype() - start = self.canvas.get_default_filename() + startpath = matplotlib.rcParams.get('savefig.directory', '') + startpath = os.path.expanduser(startpath) + start = os.path.join(startpath, self.canvas.get_default_filename()) filters = [] selectedFilter = None for name, exts in sorted_filetypes: @@ -657,6 +667,12 @@ def save_figure(self, *args): fname = _getSaveFileName(self, "Choose a filename to save to", start, filters, selectedFilter) if fname: + if startpath == '': + # explicitly missing key or empty str signals to use cwd + matplotlib.rcParams['savefig.directory'] = startpath + else: + # save dir for next time + matplotlib.rcParams['savefig.directory'] = os.path.dirname(unicode(fname)) try: self.canvas.print_figure( unicode(fname) ) except Exception as e: diff --git a/lib/matplotlib/backends/backend_qtagg.py b/lib/matplotlib/backends/backend_qtagg.py deleted file mode 100644 index 91a9cd47133e..000000000000 --- a/lib/matplotlib/backends/backend_qtagg.py +++ /dev/null @@ -1,158 +0,0 @@ -""" -Render to qt from agg -""" -from __future__ import division, print_function - -import os, sys -import matplotlib -from matplotlib import verbose -from matplotlib.figure import Figure - -from backend_agg import FigureCanvasAgg -from backend_qt import qt, FigureManagerQT, FigureCanvasQT,\ - show, draw_if_interactive, backend_version, \ - NavigationToolbar2QT - -DEBUG = False - - -def new_figure_manager( num, *args, **kwargs ): - """ - Create a new figure manager instance - """ - if DEBUG: print('backend_qtagg.new_figure_manager') - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass( *args, **kwargs ) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasQTAgg(figure) - return FigureManagerQTAgg(canvas, num) - - -class NavigationToolbar2QTAgg(NavigationToolbar2QT): - def _get_canvas(self, fig): - return FigureCanvasQTAgg(fig) - -class FigureManagerQTAgg(FigureManagerQT): - def _get_toolbar(self, canvas, parent): - # must be inited after the window, drawingArea and figure - # attrs are set - if matplotlib.rcParams['toolbar']=='classic': - print("Classic toolbar is not yet supported") - elif matplotlib.rcParams['toolbar']=='toolbar2': - toolbar = NavigationToolbar2QTAgg(canvas, parent) - else: - toolbar = None - return toolbar - -class FigureCanvasQTAgg( FigureCanvasAgg, FigureCanvasQT ): - """ - The canvas the figure renders into. Calls the draw and print fig - methods, creates the renderers, etc... - - Public attribute - - figure - A Figure instance - """ - - def __init__( self, figure ): - if DEBUG: print('FigureCanvasQtAgg: ', figure) - FigureCanvasQT.__init__( self, figure ) - FigureCanvasAgg.__init__( self, figure ) - self.drawRect = False - self.rect = [] - self.replot = True - self.pixmap = qt.QPixmap() - - def resizeEvent( self, e ): - FigureCanvasQT.resizeEvent( self, e ) - - def drawRectangle( self, rect ): - self.rect = rect - self.drawRect = True - # False in repaint does not clear the image before repainting - self.repaint( False ) - - def paintEvent( self, e ): - """ - Draw to the Agg backend and then copy the image to the qt.drawable. - In Qt, all drawing should be done inside of here when a widget is - shown onscreen. - """ - - FigureCanvasQT.paintEvent( self, e ) - if DEBUG: print('FigureCanvasQtAgg.paintEvent: ', self, \ - self.get_width_height()) - - p = qt.QPainter( self ) - - # only replot data when needed - if type(self.replot) is bool: # might be a bbox for blitting - if self.replot: - FigureCanvasAgg.draw( self ) - #stringBuffer = str( self.buffer_rgba(0,0) ) - - # matplotlib is in rgba byte order. - # qImage wants to put the bytes into argb format and - # is in a 4 byte unsigned int. little endian system is LSB first - # and expects the bytes in reverse order (bgra). - if ( qt.QImage.systemByteOrder() == qt.QImage.LittleEndian ): - stringBuffer = self.renderer._renderer.tostring_bgra() - else: - stringBuffer = self.renderer._renderer.tostring_argb() - - qImage = qt.QImage( stringBuffer, self.renderer.width, - self.renderer.height, 32, None, 0, - qt.QImage.IgnoreEndian ) - - self.pixmap.convertFromImage( qImage, qt.QPixmap.Color ) - - p.drawPixmap( qt.QPoint( 0, 0 ), self.pixmap ) - - # draw the zoom rectangle to the QPainter - if ( self.drawRect ): - p.setPen( qt.QPen( qt.Qt.black, 1, qt.Qt.DotLine ) ) - p.drawRect( self.rect[0], self.rect[1], self.rect[2], self.rect[3] ) - - # we are blitting here - else: - bbox = self.replot - l, b, r, t = bbox.extents - w = int(r) - int(l) - h = int(t) - int(b) - reg = self.copy_from_bbox(bbox) - stringBuffer = reg.to_string_argb() - qImage = qt.QImage(stringBuffer, w, h, 32, None, 0, qt.QImage.IgnoreEndian) - self.pixmap.convertFromImage(qImage, qt.QPixmap.Color) - p.drawPixmap(qt.QPoint(l, self.renderer.height-t), self.pixmap) - - p.end() - self.replot = False - self.drawRect = False - - def draw( self ): - """ - Draw the figure when xwindows is ready for the update - """ - - if DEBUG: print("FigureCanvasQtAgg.draw", self) - self.replot = True - FigureCanvasAgg.draw(self) - self.repaint(False) - - def blit(self, bbox=None): - """ - Blit the region in bbox - """ - - self.replot = bbox - self.repaint(False) - - 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 7dc7cd97a95e..cb535f8ea0a0 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -249,10 +249,11 @@ class RendererSVG(RendererBase): FONT_SCALE = 100.0 fontd = maxdict(50) - def __init__(self, width, height, svgwriter, basename=None): + def __init__(self, width, height, svgwriter, basename=None, image_dpi=72): self.width = width self.height = height self.writer = XMLWriter(svgwriter) + self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with self._groupd = {} if not rcParams['svg.image_inline']: @@ -294,7 +295,7 @@ def _write_default_style(self): writer = self.writer default_style = generate_css({ u'stroke-linejoin': u'round', - u'stroke-linecap': u'square'}) + u'stroke-linecap': u'butt'}) writer.start(u'defs') writer.start(u'style', type=u'text/css') writer.data(u'*{%s}\n' % default_style) @@ -391,15 +392,21 @@ def _get_style_dict(self, gc, rgbFace): """ attrib = {} + forced_alpha = gc.get_forced_alpha() + if gc.get_hatch() is not None: attrib[u'fill'] = u"url(#%s)" % self._get_hatch(gc, rgbFace) + if rgbFace is not None and len(rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha: + attrib[u'fill-opacity'] = str(rgbFace[3]) else: if rgbFace is None: attrib[u'fill'] = u'none' elif tuple(rgbFace[:3]) != (0, 0, 0): attrib[u'fill'] = rgb2hex(rgbFace) + if len(rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha: + attrib[u'fill-opacity'] = str(rgbFace[3]) - if gc.get_alpha() != 1.0: + if forced_alpha and gc.get_alpha() != 1.0: attrib[u'opacity'] = str(gc.get_alpha()) offset, seq = gc.get_dashes() @@ -409,12 +416,15 @@ def _get_style_dict(self, gc, rgbFace): linewidth = gc.get_linewidth() if linewidth: - attrib[u'stroke'] = rgb2hex(gc.get_rgb()) + rgb = gc.get_rgb() + attrib[u'stroke'] = rgb2hex(rgb) + if not forced_alpha and rgb[3] != 1.0: + attrib[u'stroke-opacity'] = str(rgb[3]) if linewidth != 1.0: attrib[u'stroke-width'] = str(linewidth) if gc.get_joinstyle() != 'round': attrib[u'stroke-linejoin'] = gc.get_joinstyle() - if gc.get_capstyle() != 'projecting': + if gc.get_capstyle() != 'butt': attrib[u'stroke-linecap'] = _capstyle_d[gc.get_capstyle()] return attrib @@ -738,6 +748,9 @@ def draw_gouraud_triangles(self, gc, triangles_array, colors_array, def option_scale_image(self): return True + def get_image_magnification(self): + return self.image_dpi / 72.0 + def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): attrib = {} clipid = self._get_clip(gc) @@ -760,6 +773,17 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): im.resize(numcols, numrows) h,w = im.get_size_out() + + if dx is None: + w = 72.0*w/self.image_dpi + else: + w = dx + + if dy is None: + h = 72.0*h/self.image_dpi + else: + h = dy + oid = getattr(im, '_gid', None) url = getattr(im, '_url', None) if url is not None: @@ -820,7 +844,7 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): def _adjust_char_id(self, char_id): return char_id.replace(u"%20", u"_") - def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): + def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None): """ draw the text by converting them to paths using textpath module. @@ -857,8 +881,6 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): _glyphs = text2path.get_glyphs_with_font( font, s, glyph_map=glyph_map, return_new_glyphs_only=True) glyph_info, glyph_map_new, rects = _glyphs - y -= ((font.get_descent() / 64.0) * - (prop.get_size_in_points() / text2path.FONT_SCALE)) if glyph_map_new: writer.start(u'defs') @@ -945,7 +967,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): writer.end('g') - def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): + def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None): writer = self.writer color = rgb2hex(gc.get_rgb()) @@ -958,7 +980,6 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): if not ismath: font = self._get_font(prop) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) - y -= font.get_descent() / 64.0 fontsize = prop.get_size_in_points() @@ -972,11 +993,39 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): style[u'font-style'] = prop.get_style().lower() attrib[u'style'] = generate_css(style) - attrib[u'transform'] = generate_transform([ - (u'translate', (x, y)), - (u'rotate', (-angle,))]) + if angle == 0 or mtext.get_rotation_mode() == "anchor": + # If text anchoring can be supported, get the original + # coordinates and add alignment information. + + # Get anchor coordinates. + transform = mtext.get_transform() + ax, ay = transform.transform_point(mtext.get_position()) + ay = self.height - ay + + # Don't do vertical anchor alignment. Most applications do not + # support 'alignment-baseline' yet. Apply the vertical layout + # to the anchor point manually for now. + angle_rad = angle * np.pi / 180. + dir_vert = np.array([np.sin(angle_rad), np.cos(angle_rad)]) + v_offset = np.dot(dir_vert, [(x - ax), (y - ay)]) + ax = ax + v_offset * dir_vert[0] + ay = ay + v_offset * dir_vert[1] + + ha_mpl_to_svg = {'left': 'start', 'right': 'end', + 'center': 'middle'} + style[u'text-anchor'] = ha_mpl_to_svg[mtext.get_ha()] + + attrib[u'x'] = str(ax) + attrib[u'y'] = str(ay) + attrib[u'style'] = generate_css(style) + attrib[u'transform'] = u"rotate(%f, %f, %f)" % (-angle, ax, ay) + writer.element(u'text', s, attrib=attrib) + else: + attrib[u'transform'] = generate_transform([ + (u'translate', (x, y)), + (u'rotate', (-angle,))]) - writer.element(u'text', s, attrib=attrib) + writer.element(u'text', s, attrib=attrib) if rcParams['svg.fonttype'] == 'svgfont': fontset = self._fonts.setdefault(font.fname, set()) @@ -1058,10 +1107,10 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): writer.end(u'g') - def draw_tex(self, gc, x, y, s, prop, angle): + def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): self._draw_text_as_path(gc, x, y, s, prop, angle, ismath="TeX") - def draw_text(self, gc, x, y, s, prop, angle, ismath): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): clipid = self._get_clip(gc) if clipid is not None: # Cannot apply clip-path directly to the text, because @@ -1070,9 +1119,9 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath): u'g', attrib={u'clip-path': u'url(#%s)' % clipid}) if rcParams['svg.fonttype'] == 'path': - self._draw_text_as_path(gc, x, y, s, prop, angle, ismath) + self._draw_text_as_path(gc, x, y, s, prop, angle, ismath, mtext) else: - self._draw_text_as_text(gc, x, y, s, prop, angle, ismath) + self._draw_text_as_text(gc, x, y, s, prop, angle, ismath, mtext) if clipid is not None: self.writer.end(u'g') @@ -1120,25 +1169,17 @@ def print_svgz(self, filename, *args, **kwargs): def _print_svg(self, filename, svgwriter, fh_to_close=None, **kwargs): try: + image_dpi = kwargs.pop("dpi", 72) self.figure.set_dpi(72.0) width, height = self.figure.get_size_inches() w, h = width*72, height*72 if rcParams['svg.image_noscale']: - renderer = RendererSVG(w, h, svgwriter, filename) + renderer = RendererSVG(w, h, svgwriter, filename, image_dpi) else: - # setting mixed renderer dpi other than 72 results in - # incorrect size of the rasterized image. It seems that the - # svg internally uses fixed dpi of 72 and seems to cause - # the problem. I hope someone who knows the svg backends - # take a look at this problem. Meanwhile, the dpi - # parameter is ignored and image_dpi is fixed at 72. - JJL - - #image_dpi = kwargs.pop("dpi", 72) - image_dpi = 72 _bbox_inches_restore = kwargs.pop("bbox_inches_restore", None) renderer = MixedModeRenderer(self.figure, - width, height, image_dpi, RendererSVG(w, h, svgwriter, filename), + width, height, image_dpi, RendererSVG(w, h, svgwriter, filename, image_dpi), bbox_inches_restore=_bbox_inches_restore) self.figure.draw(renderer) diff --git a/lib/matplotlib/backends/backend_template.py b/lib/matplotlib/backends/backend_template.py index ae7f01088e9c..32b3e1607680 100644 --- a/lib/matplotlib/backends/backend_template.py +++ b/lib/matplotlib/backends/backend_template.py @@ -104,7 +104,7 @@ def draw_path(self, gc, path, transform, rgbFace=None): def draw_image(self, gc, x, y, im): pass - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): pass def flipy(self): diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index fe0e145be3f1..40143ae1af86 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -307,7 +307,7 @@ def _update_pointer_position(self, guiEvent=None): # JDH: this method was written originally to get the pointer # location to the backend lastx and lasty attrs so that events - # like KeyEvent can be handled without mouse events. Eg, if + # like KeyEvent can be handled without mouse events. e.g., if # the cursor is already above the axes, then key presses like # 'g' should toggle the grid. In order for this to work in # backend_bases, the canvas needs to know _lastx and _lasty. @@ -895,17 +895,27 @@ def save_figure(self, *args): # work - JDH #defaultextension = self.canvas.get_default_filetype() defaultextension = '' + initialdir = rcParams.get('savefig.directory', '') + initialdir = os.path.expanduser(initialdir) + initialfile = self.canvas.get_default_filename() fname = asksaveasfilename( master=self.window, title='Save the figure', - filetypes = tk_filetypes, - defaultextension = defaultextension, - initialfile=self.canvas.get_default_filename(), + filetypes=tk_filetypes, + defaultextension=defaultextension, + initialdir=initialdir, + initialfile=initialfile, ) if fname == "" or fname == (): return else: + if initialdir == '': + # explicitly missing key or empty str signals to use cwd + rcParams['savefig.directory'] = initialdir + else: + # save dir for next time + rcParams['savefig.directory'] = os.path.dirname(unicode(fname)) try: # This method will handle the delegation to the correct type self.canvas.print_figure(fname) diff --git a/lib/matplotlib/backends/backend_webagg.py b/lib/matplotlib/backends/backend_webagg.py new file mode 100644 index 000000000000..3272140b4780 --- /dev/null +++ b/lib/matplotlib/backends/backend_webagg.py @@ -0,0 +1,615 @@ +""" +Displays Agg images in the browser, with interactivity +""" +from __future__ import division, print_function + +import datetime +import errno +import io +import json +import os +import random +import socket + +import numpy as np + +try: + import tornado +except ImportError: + raise RuntimeError("The WebAgg backend requires Tornado.") +import tornado.web +import tornado.ioloop +import tornado.websocket +import tornado.template + +import matplotlib +from matplotlib import rcParams +from matplotlib.figure import Figure +from matplotlib.backends import backend_agg +from matplotlib import backend_bases +from matplotlib._pylab_helpers import Gcf +from matplotlib import _png + + +def draw_if_interactive(): + """ + Is called after every pylab drawing command + """ + if matplotlib.is_interactive(): + figManager = Gcf.get_active() + if figManager is not None: + figManager.canvas.draw_idle() + + +class Show(backend_bases.ShowBase): + def mainloop(self): + WebAggApplication.initialize() + + url = "http://127.0.0.1:{port}{prefix}".format( + port=WebAggApplication.port, + prefix=WebAggApplication.url_prefix) + + if rcParams['webagg.open_in_browser']: + import webbrowser + webbrowser.open(url) + else: + print("To view figure, visit {0}".format(url)) + + WebAggApplication.start() + +show = Show() + + +def new_figure_manager(num, *args, **kwargs): + """ + Create a new figure manager instance + """ + FigureClass = kwargs.pop('FigureClass', Figure) + thisFig = FigureClass(*args, **kwargs) + return new_figure_manager_given_figure(num, thisFig) + + +def new_figure_manager_given_figure(num, figure): + """ + Create a new figure manager instance for the given figure. + """ + canvas = FigureCanvasWebAgg(figure) + manager = FigureManagerWebAgg(canvas, num) + return manager + + +class TimerTornado(backend_bases.TimerBase): + def _timer_start(self): + self._timer_stop() + if self._single: + ioloop = tornado.ioloop.IOLoop.instance() + self._timer = ioloop.add_timeout( + datetime.timedelta(milliseconds=self.interval), + self._on_timer) + else: + self._timer = tornado.ioloop.PeriodicCallback( + self._on_timer, + self.interval) + self._timer.start() + + def _timer_stop(self): + if self._timer is not None: + self._timer.stop() + self._timer = None + + def _timer_set_interval(self): + # Only stop and restart it if the timer has already been started + if self._timer is not None: + self._timer_stop() + self._timer_start() + + +class FigureCanvasWebAgg(backend_agg.FigureCanvasAgg): + supports_blit = False + + def __init__(self, *args, **kwargs): + backend_agg.FigureCanvasAgg.__init__(self, *args, **kwargs) + + # A buffer to hold the PNG data for the last frame. This is + # retained so it can be resent to each client without + # regenerating it. + self._png_buffer = io.BytesIO() + + # Set to True when the renderer contains data that is newer + # than the PNG buffer. + self._png_is_old = True + + # Set to True by the `refresh` message so that the next frame + # sent to the clients will be a full frame. + self._force_full = True + + # Set to True when a drawing is in progress to prevent redraw + # messages from piling up. + self._pending_draw = None + + def show(self): + # show the figure window + show() + + def draw(self): + # TODO: Do we just queue the drawing here? That's what Gtk does + renderer = self.get_renderer() + + self._png_is_old = True + + backend_agg.RendererAgg.lock.acquire() + try: + self.figure.draw(renderer) + finally: + backend_agg.RendererAgg.lock.release() + # Swap the frames + self.manager.refresh_all() + + def draw_idle(self): + if self._pending_draw is None: + ioloop = tornado.ioloop.IOLoop.instance() + self._pending_draw = ioloop.add_timeout( + datetime.timedelta(milliseconds=50), + self._draw_idle_callback) + + def _draw_idle_callback(self): + try: + self.draw() + finally: + self._pending_draw = None + + def get_diff_image(self): + if self._png_is_old: + # The buffer is created as type uint32 so that entire + # pixels can be compared in one numpy call, rather than + # needing to compare each plane separately. + buff = np.frombuffer( + self._renderer.buffer_rgba(), dtype=np.uint32) + buff.shape = ( + self._renderer.height, self._renderer.width) + + if not self._force_full: + last_buffer = np.frombuffer( + self._last_renderer.buffer_rgba(), dtype=np.uint32) + last_buffer.shape = ( + self._renderer.height, self._renderer.width) + + diff = buff != last_buffer + output = np.where(diff, buff, 0) + else: + output = buff + + # Clear out the PNG data buffer rather than recreating it + # each time. This reduces the number of memory + # (de)allocations. + self._png_buffer.truncate() + self._png_buffer.seek(0) + + # TODO: We should write a new version of write_png that + # handles the differencing inline + _png.write_png( + output.tostring(), + output.shape[1], output.shape[0], + self._png_buffer) + + # Swap the renderer frames + self._renderer, self._last_renderer = ( + self._last_renderer, self._renderer) + self._force_full = False + self._png_is_old = False + return self._png_buffer.getvalue() + + def get_renderer(self): + # Mirrors super.get_renderer, but caches the old one + # so that we can do things such as prodce a diff image + # in get_diff_image + _, _, w, h = self.figure.bbox.bounds + key = w, h, self.figure.dpi + try: + self._lastKey, self._renderer + except AttributeError: + need_new_renderer = True + else: + need_new_renderer = (self._lastKey != key) + + if need_new_renderer: + self._renderer = backend_agg.RendererAgg( + w, h, self.figure.dpi) + self._last_renderer = backend_agg.RendererAgg( + w, h, self.figure.dpi) + self._lastKey = key + + return self._renderer + + def handle_event(self, event): + e_type = event['type'] + if e_type in ('button_press', 'button_release', 'motion_notify'): + x = event['x'] + y = event['y'] + y = self.get_renderer().height - y + + # Javascript button numbers and matplotlib button numbers are + # off by 1 + button = event['button'] + 1 + + # The right mouse button pops up a context menu, which + # doesn't work very well, so use the middle mouse button + # instead. It doesn't seem that it's possible to disable + # the context menu in recent versions of Chrome. + if button == 2: + button = 3 + + if e_type == 'button_press': + self.button_press_event(x, y, button) + elif e_type == 'button_release': + self.button_release_event(x, y, button) + elif e_type == 'motion_notify': + self.motion_notify_event(x, y) + elif e_type in ('key_press', 'key_release'): + key = event['key'] + + if e_type == 'key_press': + self.key_press_event(key) + elif e_type == 'key_release': + self.key_release_event(key) + elif e_type == 'toolbar_button': + print('Toolbar button pressed: ', event['name']) + # TODO: Be more suspicious of the input + getattr(self.toolbar, event['name'])() + elif e_type == 'refresh': + self._force_full = True + self.draw_idle() + + def send_event(self, event_type, **kwargs): + self.manager.send_event(event_type, **kwargs) + + def new_timer(self, *args, **kwargs): + return TimerTornado(*args, **kwargs) + + def start_event_loop(self, timeout): + backend_bases.FigureCanvasBase.start_event_loop_default( + self, timeout) + start_event_loop.__doc__ = \ + backend_bases.FigureCanvasBase.start_event_loop_default.__doc__ + + def stop_event_loop(self): + backend_bases.FigureCanvasBase.stop_event_loop_default(self) + stop_event_loop.__doc__ = \ + backend_bases.FigureCanvasBase.stop_event_loop_default.__doc__ + + +class FigureManagerWebAgg(backend_bases.FigureManagerBase): + def __init__(self, canvas, num): + backend_bases.FigureManagerBase.__init__(self, canvas, num) + + self.web_sockets = set() + + self.toolbar = self._get_toolbar(canvas) + + def show(self): + pass + + def add_web_socket(self, web_socket): + self.web_sockets.add(web_socket) + + def remove_web_socket(self, web_socket): + self.web_sockets.remove(web_socket) + + def refresh_all(self): + for s in self.web_sockets: + s.send_image() + + def send_event(self, event_type, **kwargs): + for s in self.web_sockets: + s.send_event(event_type, **kwargs) + + def _get_toolbar(self, canvas): + toolbar = NavigationToolbar2WebAgg(canvas) + return toolbar + + def resize(self, w, h): + self.send_event('resize', size=(w, h)) + + +class NavigationToolbar2WebAgg(backend_bases.NavigationToolbar2): + _jquery_icon_classes = {'home': 'ui-icon ui-icon-home', + 'back': 'ui-icon ui-icon-circle-arrow-w', + 'forward': 'ui-icon ui-icon-circle-arrow-e', + 'zoom_to_rect': 'ui-icon ui-icon-search', + 'move': 'ui-icon ui-icon-arrow-4', + 'download': 'ui-icon ui-icon-disk', + None: None + } + + def _init_toolbar(self): + # Use the standard toolbar items + download button + toolitems = (backend_bases.NavigationToolbar2.toolitems + + (('Download', 'Download plot', 'download', 'download'),)) + + NavigationToolbar2WebAgg.toolitems = \ + tuple( + (text, tooltip_text, self._jquery_icon_classes[image_file], + name_of_method) + for text, tooltip_text, image_file, name_of_method + in toolitems if image_file in self._jquery_icon_classes) + + self.message = '' + self.cursor = 0 + + def _get_canvas(self, fig): + return FigureCanvasWebAgg(fig) + + def set_message(self, message): + if message != self.message: + self.canvas.send_event("message", message=message) + self.message = message + + def set_cursor(self, cursor): + if cursor != self.cursor: + self.canvas.send_event("cursor", cursor=cursor) + self.cursor = cursor + + def dynamic_update(self): + self.canvas.draw_idle() + + def draw_rubberband(self, event, x0, y0, x1, y1): + self.canvas.send_event( + "rubberband", x0=x0, y0=y0, x1=x1, y1=y1) + + def release_zoom(self, event): + super(NavigationToolbar2WebAgg, self).release_zoom(event) + self.canvas.send_event( + "rubberband", x0=-1, y0=-1, x1=-1, y1=-1) + + +class WebAggApplication(tornado.web.Application): + initialized = False + started = False + + _mpl_data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), + 'mpl-data') + _mpl_dirs = {'mpl-data': _mpl_data_path, + 'images': os.path.join(_mpl_data_path, 'images'), + 'web_backend': os.path.join(os.path.dirname(__file__), + 'web_backend')} + + class FavIcon(tornado.web.RequestHandler): + def get(self): + self.set_header('Content-Type', 'image/png') + with open(os.path.join(WebAggApplication._mpl_dirs['images'], + 'matplotlib.png')) as fd: + self.write(fd.read()) + + class SingleFigurePage(tornado.web.RequestHandler): + def __init__(self, application, request, **kwargs): + self.url_prefix = kwargs.pop('url_prefix', '') + return tornado.web.RequestHandler.__init__(self, application, + request, **kwargs) + + def get(self, fignum): + with open(os.path.join(WebAggApplication._mpl_dirs['web_backend'], + 'single_figure.html')) as fd: + tpl = fd.read() + + fignum = int(fignum) + manager = Gcf.get_fig_manager(fignum) + + ws_uri = 'ws://{req.host}{prefix}/'.format(req=self.request, + prefix=self.url_prefix) + t = tornado.template.Template(tpl) + self.write(t.generate( + prefix=self.url_prefix, + ws_uri=ws_uri, + fig_id=fignum, + toolitems=NavigationToolbar2WebAgg.toolitems, + canvas=manager.canvas)) + + class AllFiguresPage(tornado.web.RequestHandler): + def __init__(self, application, request, **kwargs): + self.url_prefix = kwargs.pop('url_prefix', '') + return tornado.web.RequestHandler.__init__(self, application, + request, **kwargs) + + def get(self): + with open(os.path.join(WebAggApplication._mpl_dirs['web_backend'], + 'all_figures.html')) as fd: + tpl = fd.read() + + ws_uri = 'ws://{req.host}{prefix}/'.format(req=self.request, + prefix=self.url_prefix) + t = tornado.template.Template(tpl) + + self.write(t.generate( + prefix=self.url_prefix, + ws_uri=ws_uri, + figures = sorted(list(Gcf.figs.items()), key=lambda item: item[0]), + toolitems=NavigationToolbar2WebAgg.toolitems)) + + + class MPLInterfaceJS(tornado.web.RequestHandler): + def get(self, fignum): + with open(os.path.join(WebAggApplication._mpl_dirs['web_backend'], + 'mpl_interface.js')) as fd: + tpl = fd.read() + + fignum = int(fignum) + manager = Gcf.get_fig_manager(fignum) + + t = tornado.template.Template(tpl) + self.write(t.generate( + toolitems=NavigationToolbar2WebAgg.toolitems, + canvas=manager.canvas)) + + class Download(tornado.web.RequestHandler): + def get(self, fignum, fmt): + self.fignum = int(fignum) + manager = Gcf.get_fig_manager(self.fignum) + + # TODO: Move this to a central location + mimetypes = { + 'ps': 'application/postscript', + 'eps': 'application/postscript', + 'pdf': 'application/pdf', + 'svg': 'image/svg+xml', + 'png': 'image/png', + 'jpeg': 'image/jpeg', + 'tif': 'image/tiff', + 'emf': 'application/emf' + } + + self.set_header('Content-Type', mimetypes.get(fmt, 'binary')) + + buff = io.BytesIO() + manager.canvas.print_figure(buff, format=fmt) + self.write(buff.getvalue()) + + class WebSocket(tornado.websocket.WebSocketHandler): + supports_binary = True + + def open(self, fignum): + self.fignum = int(fignum) + manager = Gcf.get_fig_manager(self.fignum) + manager.add_web_socket(self) + _, _, w, h = manager.canvas.figure.bbox.bounds + manager.resize(w, h) + self.on_message('{"type":"refresh"}') + + def on_close(self): + Gcf.get_fig_manager(self.fignum).remove_web_socket(self) + + def on_message(self, message): + message = json.loads(message) + # The 'supports_binary' message is on a client-by-client + # basis. The others affect the (shared) canvas as a + # whole. + if message['type'] == 'supports_binary': + self.supports_binary = message['value'] + else: + canvas = Gcf.get_fig_manager(self.fignum).canvas + canvas.handle_event(message) + + def send_event(self, event_type, **kwargs): + payload = {'type': event_type} + payload.update(kwargs) + self.write_message(json.dumps(payload)) + + def send_image(self): + canvas = Gcf.get_fig_manager(self.fignum).canvas + diff = canvas.get_diff_image() + if self.supports_binary: + self.write_message(diff, binary=True) + else: + data_uri = "data:image/png;base64,{0}".format( + diff.encode('base64').replace('\n', '')) + self.write_message(data_uri) + + def __init__(self, url_prefix=''): + if url_prefix: + assert url_prefix[0] == '/' and url_prefix[-1] != '/', \ + 'url_prefix must start with a "/" and not end with one.' + + super(WebAggApplication, self).__init__([ + # Static files for the CSS and JS + (url_prefix + r'/_static/(.*)', + tornado.web.StaticFileHandler, + {'path': self._mpl_dirs['web_backend']}), + + # Static images for toolbar buttons + (url_prefix + r'/_static/images/(.*)', + tornado.web.StaticFileHandler, + {'path': self._mpl_dirs['images']}), + + (url_prefix + r'/_static/jquery/css/themes/base/(.*)', + tornado.web.StaticFileHandler, + {'path': os.path.join(self._mpl_dirs['web_backend'], 'jquery', + 'css', 'themes', 'base')}), + + (url_prefix + r'/_static/jquery/css/themes/base/images/(.*)', + tornado.web.StaticFileHandler, + {'path': os.path.join(self._mpl_dirs['web_backend'], 'jquery', + 'css', 'themes', 'base', 'images')}), + + (url_prefix + r'/_static/jquery/js/(.*)', tornado.web.StaticFileHandler, + {'path': os.path.join(self._mpl_dirs['web_backend'], + 'jquery', 'js')}), + + (url_prefix + r'/_static/css/(.*)', tornado.web.StaticFileHandler, + {'path': os.path.join(self._mpl_dirs['web_backend'], 'css')}), + + # An MPL favicon + (url_prefix + r'/favicon.ico', self.FavIcon), + + # The page that contains all of the pieces + (url_prefix + r'/([0-9]+)', self.SingleFigurePage, + {'url_prefix': url_prefix}), + + (url_prefix + r'/([0-9]+)/mpl_interface.js', self.MPLInterfaceJS), + + # Sends images and events to the browser, and receives + # events from the browser + (url_prefix + r'/([0-9]+)/ws', self.WebSocket), + + # Handles the downloading (i.e., saving) of static images + (url_prefix + r'/([0-9]+)/download.([a-z]+)', self.Download), + + # The page that contains all of the figures + (url_prefix + r'/?', self.AllFiguresPage, + {'url_prefix': url_prefix}), + ]) + + @classmethod + def initialize(cls, url_prefix=''): + if cls.initialized: + return + + # Create the class instance + app = cls(url_prefix=url_prefix) + + cls.url_prefix = url_prefix + + # This port selection algorithm is borrowed, more or less + # verbatim, from IPython. + def random_ports(port, n): + """ + Generate a list of n random ports near the given port. + + The first 5 ports will be sequential, and the remaining n-5 will be + randomly selected in the range [port-2*n, port+2*n]. + """ + for i in range(min(5, n)): + yield port + i + for i in range(n - 5): + yield port + random.randint(-2 * n, 2 * n) + + success = None + cls.port = rcParams['webagg.port'] + for port in random_ports(cls.port, rcParams['webagg.port_retries']): + try: + app.listen(port) + except socket.error as e: + if e.errno != errno.EADDRINUSE: + raise + else: + cls.port = port + success = True + break + + if not success: + raise SystemExit( + "The webagg server could not be started because an available " + "port could not be found") + + cls.initialized = True + + @classmethod + def start(cls): + if cls.started: + return + + print("Press Ctrl+C to stop server") + try: + tornado.ioloop.IOLoop.instance().start() + except KeyboardInterrupt: + print("Server stopped") + + cls.started = True diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 76d2992ccc21..16c08d7c4dea 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -25,7 +25,7 @@ import numpy as np -from matplotlib import MatplotlibDeprecationWarning as mplDeprecation +from matplotlib.cbook import mplDeprecation # Debugging settings here... # Debug level set here. If the debug level is less than 5, information @@ -364,11 +364,7 @@ def draw_image(self, gc, x, y, im): gc.gfx_ctx.DrawBitmap(bitmap,int(l),int(self.height-b),int(w),int(-h)) gc.unselect() - def draw_text(self, gc, x, y, s, prop, angle, ismath): - """ - Render the matplotlib.text.Text instance - None) - """ + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): if ismath: s = self.strip_math(s) DEBUG_MSG("draw_text()", 1, self) gc.select() @@ -523,7 +519,7 @@ def unselect(self): self.dc.SelectObject(wx.NullBitmap) self.IsSelected = False - def set_foreground(self, fg, isRGB=None): + def set_foreground(self, fg, isRGBA=None): """ Set the foreground color. fg can be a matlab format string, a html hex color string, an rgb unit tuple, or a float between 0 @@ -536,7 +532,7 @@ def set_foreground(self, fg, isRGB=None): # Same goes for text foreground... DEBUG_MSG("set_foreground()", 1, self) self.select() - GraphicsContextBase.set_foreground(self, fg, isRGB) + GraphicsContextBase.set_foreground(self, fg, isRGBA) self._pen.SetColour(self.get_wxcolour(self.get_rgb())) self.gfx_ctx.SetPen(self._pen) @@ -789,190 +785,6 @@ def Copy_to_Clipboard(self, event=None): wx.TheClipboard.Close() wx.TheClipboard.Flush() - def Printer_Init(self): - """ - initialize printer settings using wx methods - - Deprecated. - """ - warnings.warn("Printer* methods will be removed", mplDeprecation) - self.printerData = wx.PrintData() - self.printerData.SetPaperId(wx.PAPER_LETTER) - self.printerData.SetPrintMode(wx.PRINT_MODE_PRINTER) - self.printerPageData= wx.PageSetupDialogData() - self.printerPageData.SetMarginBottomRight((25,25)) - self.printerPageData.SetMarginTopLeft((25,25)) - self.printerPageData.SetPrintData(self.printerData) - - self.printer_width = 5.5 - self.printer_margin= 0.5 - - def _get_printerData(self): - if self._printerData is None: - warnings.warn("Printer* methods will be removed", mplDeprecation) - self._printerData = wx.PrintData() - self._printerData.SetPaperId(wx.PAPER_LETTER) - self._printerData.SetPrintMode(wx.PRINT_MODE_PRINTER) - return self._printerData - printerData = property(_get_printerData) - - def _get_printerPageData(self): - if self._printerPageData is None: - warnings.warn("Printer* methods will be removed", mplDeprecation) - self._printerPageData= wx.PageSetupDialogData() - self._printerPageData.SetMarginBottomRight((25,25)) - self._printerPageData.SetMarginTopLeft((25,25)) - self._printerPageData.SetPrintData(self.printerData) - return self._printerPageData - printerPageData = property(_get_printerPageData) - - def Printer_Setup(self, event=None): - """ - set up figure for printing. The standard wx Printer - Setup Dialog seems to die easily. Therefore, this setup - simply asks for image width and margin for printing. - Deprecated. - """ - - dmsg = """Width of output figure in inches. -The current aspect ratio will be kept.""" - - warnings.warn("Printer* methods will be removed", mplDeprecation) - dlg = wx.Dialog(self, -1, 'Page Setup for Printing' , (-1,-1)) - df = dlg.GetFont() - df.SetWeight(wx.NORMAL) - df.SetPointSize(11) - dlg.SetFont(df) - - x_wid = wx.TextCtrl(dlg,-1,value="%.2f" % self.printer_width, size=(70,-1)) - x_mrg = wx.TextCtrl(dlg,-1,value="%.2f" % self.printer_margin,size=(70,-1)) - - sizerAll = wx.BoxSizer(wx.VERTICAL) - sizerAll.Add(wx.StaticText(dlg,-1,dmsg), - 0, wx.ALL | wx.EXPAND, 5) - - sizer = wx.FlexGridSizer(0,3) - sizerAll.Add(sizer, 0, wx.ALL | wx.EXPAND, 5) - - sizer.Add(wx.StaticText(dlg,-1,'Figure Width'), - 1, wx.ALIGN_LEFT|wx.ALL, 2) - sizer.Add(x_wid, - 1, wx.ALIGN_LEFT|wx.ALL, 2) - sizer.Add(wx.StaticText(dlg,-1,'in'), - 1, wx.ALIGN_LEFT|wx.ALL, 2) - - sizer.Add(wx.StaticText(dlg,-1,'Margin'), - 1, wx.ALIGN_LEFT|wx.ALL, 2) - sizer.Add(x_mrg, - 1, wx.ALIGN_LEFT|wx.ALL, 2) - sizer.Add(wx.StaticText(dlg,-1,'in'), - 1, wx.ALIGN_LEFT|wx.ALL, 2) - - btn = wx.Button(dlg,wx.ID_OK, " OK ") - btn.SetDefault() - sizer.Add(btn, 1, wx.ALIGN_LEFT, 5) - btn = wx.Button(dlg,wx.ID_CANCEL, " CANCEL ") - sizer.Add(btn, 1, wx.ALIGN_LEFT, 5) - - dlg.SetSizer(sizerAll) - dlg.SetAutoLayout(True) - sizerAll.Fit(dlg) - - if dlg.ShowModal() == wx.ID_OK: - try: - self.printer_width = float(x_wid.GetValue()) - self.printer_margin = float(x_mrg.GetValue()) - except: - pass - - if ((self.printer_width + self.printer_margin) > 7.5): - self.printerData.SetOrientation(wx.LANDSCAPE) - else: - self.printerData.SetOrientation(wx.PORTRAIT) - dlg.Destroy() - return - - def Printer_Setup2(self, event=None): - """ - set up figure for printing. Using the standard wx Printer - Setup Dialog. - - Deprecated. - """ - - warnings.warn("Printer* methods will be removed", mplDeprecation) - if hasattr(self, 'printerData'): - data = wx.PageSetupDialogData() - data.SetPrintData(self.printerData) - else: - data = wx.PageSetupDialogData() - data.SetMarginTopLeft( (15, 15) ) - data.SetMarginBottomRight( (15, 15) ) - - dlg = wx.PageSetupDialog(self, data) - - if dlg.ShowModal() == wx.ID_OK: - data = dlg.GetPageSetupData() - tl = data.GetMarginTopLeft() - br = data.GetMarginBottomRight() - self.printerData = wx.PrintData(data.GetPrintData()) - dlg.Destroy() - - def Printer_Preview(self, event=None): - """ - generate Print Preview with wx Print mechanism - - Deprecated. - """ - warnings.warn("Printer* methods will be removed", mplDeprecation) - po1 = PrintoutWx(self, width=self.printer_width, - margin=self.printer_margin) - po2 = PrintoutWx(self, width=self.printer_width, - margin=self.printer_margin) - self.preview = wx.PrintPreview(po1,po2,self.printerData) - if not self.preview.Ok(): print("error with preview") - - self.preview.SetZoom(50) - frameInst= self - while not isinstance(frameInst, wx.Frame): - frameInst= frameInst.GetParent() - frame = wx.PreviewFrame(self.preview, frameInst, "Preview") - frame.Initialize() - frame.SetPosition(self.GetPosition()) - frame.SetSize((850,650)) - frame.Centre(wx.BOTH) - frame.Show(True) - self.gui_repaint() - - def Printer_Print(self, event=None): - """ - Print figure using wx Print mechanism - - Deprecated. - """ - warnings.warn("Printer* methods will be removed", mplDeprecation) - pdd = wx.PrintDialogData() - # SetPrintData for 2.4 combatibility - pdd.SetPrintData(self.printerData) - pdd.SetToPage(1) - printer = wx.Printer(pdd) - printout = PrintoutWx(self, width=int(self.printer_width), - margin=int(self.printer_margin)) - print_ok = printer.Print(self, printout, True) - - if wx.VERSION_STRING >= '2.5': - if not print_ok and not printer.GetLastError() == wx.PRINTER_CANCELLED: - wx.MessageBox("""There was a problem printing. - Perhaps your current printer is not set correctly?""", - "Printing", wx.OK) - else: - if not print_ok: - wx.MessageBox("""There was a problem printing. - Perhaps your current printer is not set correctly?""", - "Printing", wx.OK) - printout.Destroy() - self.gui_repaint() - def draw_idle(self): """ Delay rendering until the GUI is idle. @@ -1171,14 +983,26 @@ def _print_image(self, filename, filetype, *args, **kwargs): self.figure.draw(renderer) + # image is the object that we call SaveFile on. + image = self.bitmap + # set the JPEG quality appropriately. Unfortunately, it is only possible + # to set the quality on a wx.Image object. So if we are saving a JPEG, + # convert the wx.Bitmap to a wx.Image, and set the quality. + if filetype == wx.BITMAP_TYPE_JPEG: + jpeg_quality = kwargs.get('quality',rcParams['savefig.jpeg_quality']) + image = self.bitmap.ConvertToImage() + image.SetOption(wx.IMAGE_OPTION_QUALITY,str(jpeg_quality)) + # Now that we have rendered into the bitmap, save it # to the appropriate file type and clean up if is_string_like(filename): - if not self.bitmap.SaveFile(filename, filetype): + if not image.SaveFile(filename, filetype): DEBUG_MSG('print_figure() file save error', 4, self) raise RuntimeError('Could not save figure to %s\n' % (filename)) elif is_writable_file_like(filename): - if not self.bitmap.ConvertToImage().SaveStream(filename, filetype): + if not isinstance(image,wx.Image): + image = image.ConvertToImage() + if not image.SaveStream(filename, filetype): DEBUG_MSG('print_figure() file save error', 4, self) raise RuntimeError('Could not save figure to %s\n' % (filename)) @@ -2070,7 +1894,7 @@ def zoomy(self, in_out): def update(self): """ - Update the toolbar menu - called when (e.g.) a new subplot + Update the toolbar menu - e.g., called when a new subplot or axes are added """ DEBUG_MSG("update()", 1, self) diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index 5672a29e9724..2a7424f8f7af 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -125,6 +125,19 @@ def text_to_qcolor(text): color.setNamedColor(text) return color +def is_matplotlib_color(value): + """ + Check if value is a color passed to us from matplotlib. + It could either be a valid color string or a 3-tuple of floats between 0. and 1. + """ + if text_to_qcolor(value).isValid(): + return True + if isinstance(value,tuple) and len(value)==3 and all(map(lambda v: isinstance(v,float),value)): + for c in value: + if c < 0. or c > 1.: + return False + return True + return False class ColorLayout(QHBoxLayout): """Color-specialized QLineEdit layout""" @@ -268,7 +281,7 @@ def setup(self): continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) - elif text_to_qcolor(value).isValid(): + elif is_matplotlib_color(value): field = ColorLayout(QColor(value), self) elif isinstance(value, (str, unicode)): field = QLineEdit(value, self) @@ -329,7 +342,7 @@ def get(self): continue elif tuple_to_qfont(value) is not None: value = field.get_font() - elif isinstance(value, (str, unicode)): + elif isinstance(value, (str, unicode)) or is_matplotlib_color(value): value = unicode(field.text()) elif isinstance(value, (list, tuple)): index = int(field.currentIndex()) @@ -508,7 +521,7 @@ def fedit(data, title="", comment="", icon=None, parent=None, apply=None): """ # Create a QApplication instance if no instance currently exists - # (e.g. if the module is used directly from the interpreter) + # (e.g., if the module is used directly from the interpreter) if QApplication.startingUp(): _app = QApplication([]) dialog = FormDialog(data, title, comment, icon, parent, apply) diff --git a/lib/matplotlib/backends/web_backend/all_figures.html b/lib/matplotlib/backends/web_backend/all_figures.html new file mode 100644 index 000000000000..a501d9379ce5 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/all_figures.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + MPL | WebAgg current figures + + + +
    + {% for (fig_id, fig_manager) in figures %} + {% set fig_label='Figure: {}'.format(fig_manager.canvas.figure.get_label()) %} + + {% if fig_label == 'Figure: ' %} + {% set fig_label="Figure {}".format(fig_id) %} + {% end %} + + + {% end %} + + + diff --git a/lib/matplotlib/backends/web_backend/css/boilerplate.css b/lib/matplotlib/backends/web_backend/css/boilerplate.css new file mode 100644 index 000000000000..2b1535f4495e --- /dev/null +++ b/lib/matplotlib/backends/web_backend/css/boilerplate.css @@ -0,0 +1,77 @@ +/** + * HTML5 ✰ Boilerplate + * + * style.css contains a reset, font normalization and some base styles. + * + * Credit is left where credit is due. + * Much inspiration was taken from these projects: + * - yui.yahooapis.com/2.8.1/build/base/base.css + * - camendesign.com/design/ + * - praegnanz.de/weblog/htmlcssjs-kickstart + */ + + +/** + * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline) + * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark + * html5doctor.com/html-5-reset-stylesheet/ + */ + +html, body, div, span, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, +small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, figcaption, figure, +footer, header, hgroup, menu, nav, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +sup { vertical-align: super; } +sub { vertical-align: sub; } + +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +blockquote, q { quotes: none; } + +blockquote:before, blockquote:after, +q:before, q:after { content: ""; content: none; } + +ins { background-color: #ff9; color: #000; text-decoration: none; } + +mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } + +del { text-decoration: line-through; } + +abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } + +table { border-collapse: collapse; border-spacing: 0; } + +hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } + +input, select { vertical-align: middle; } + + +/** + * Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/ + */ + +body { font:13px/1.231 sans-serif; *font-size:small; } /* Hack retained to preserve specificity */ +select, input, textarea, button { font:99% sans-serif; } + +/* Normalize monospace sizing: + en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */ +pre, code, kbd, samp { font-family: monospace, sans-serif; } + +em,i { font-style: italic; } +b,strong { font-weight: bold; } diff --git a/lib/matplotlib/backends/web_backend/css/fbm.css b/lib/matplotlib/backends/web_backend/css/fbm.css new file mode 100644 index 000000000000..0e21d19ae801 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/css/fbm.css @@ -0,0 +1,97 @@ + +/* Flexible box model classes */ +/* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */ + +.hbox { + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + + display: box; + box-orient: horizontal; + box-align: stretch; +} + +.hbox > * { + -webkit-box-flex: 0; + -moz-box-flex: 0; + box-flex: 0; +} + +.vbox { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + + display: box; + box-orient: vertical; + box-align: stretch; +} + +.vbox > * { + -webkit-box-flex: 0; + -moz-box-flex: 0; + box-flex: 0; +} + +.reverse { + -webkit-box-direction: reverse; + -moz-box-direction: reverse; + box-direction: reverse; +} + +.box-flex0 { + -webkit-box-flex: 0; + -moz-box-flex: 0; + box-flex: 0; +} + +.box-flex1, .box-flex { + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; +} + +.box-flex2 { + -webkit-box-flex: 2; + -moz-box-flex: 2; + box-flex: 2; +} + +.box-group1 { + -webkit-box-flex-group: 1; + -moz-box-flex-group: 1; + box-flex-group: 1; +} + +.box-group2 { + -webkit-box-flex-group: 2; + -moz-box-flex-group: 2; + box-flex-group: 2; +} + +.start { + -webkit-box-pack: start; + -moz-box-pack: start; + box-pack: start; +} + +.end { + -webkit-box-pack: end; + -moz-box-pack: end; + box-pack: end; +} + +.center { + -webkit-box-pack: center; + -moz-box-pack: center; + box-pack: center; +} diff --git a/lib/matplotlib/backends/web_backend/css/page.css b/lib/matplotlib/backends/web_backend/css/page.css new file mode 100644 index 000000000000..4ce53a6080e9 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/css/page.css @@ -0,0 +1,77 @@ +/** + * Primary styles + * + * Author: IPython Development Team + */ + + +body { + background-color: white; + /* This makes sure that the body covers the entire window and needs to + be in a different element than the display: box in wrapper below */ + position: absolute; + left: 0px; + right: 0px; + top: 0px; + bottom: 0px; + overflow: visible; +} + + +div#header { + /* Initially hidden to prevent FLOUC */ + display: none; + position: relative; + height: 40px; + padding: 5px; + margin: 0px; + width: 100%; +} + +span#ipython_notebook { + position: absolute; + padding: 2px 2px 2px 5px; +} + +span#ipython_notebook img { + font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif; + height: 24px; + text-decoration:none; + display: inline; + color: black; +} + +#site { + width: 100%; + display: none; +} + +/* We set the fonts by hand here to override the values in the theme */ +.ui-widget { + font-family: "Lucinda Grande", "Lucinda Sans Unicode", Helvetica, Arial, Verdana, sans-serif; +} + +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { + font-family: "Lucinda Grande", "Lucinda Sans Unicode", Helvetica, Arial, Verdana, sans-serif; +} + +/* Smaller buttons */ +.ui-button .ui-button-text { + padding: 0.2em 0.8em; + font-size: 77%; +} + +input.ui-button { + padding: 0.3em 0.9em; +} + +span#login_widget { + float: right; +} + +.border-box-sizing { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 000000000000..5b5dab2ab7b1 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_flat_75_ffffff_40x100.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 000000000000..ac8b229af950 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 000000000000..ad3d6346e00f Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 000000000000..42ccba269b6e Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 000000000000..5a46b47cb166 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 000000000000..86c2baa655ea Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 000000000000..4443fdc1a156 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 000000000000..7c9fa6c6edcf Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_222222_256x240.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_222222_256x240.png new file mode 100644 index 000000000000..ee039dc096a3 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_222222_256x240.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_2e83ff_256x240.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 000000000000..45e8928e5284 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_2e83ff_256x240.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_454545_256x240.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_454545_256x240.png new file mode 100644 index 000000000000..7ec70d11bfb2 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_454545_256x240.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_888888_256x240.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_888888_256x240.png new file mode 100644 index 000000000000..5ba708c39172 Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_888888_256x240.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_cd0a0a_256x240.png b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 000000000000..7930a558099b Binary files /dev/null and b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/images/ui-icons_cd0a0a_256x240.png differ diff --git a/lib/matplotlib/backends/web_backend/jquery/css/themes/base/jquery-ui.min.css b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/jquery-ui.min.css new file mode 100644 index 000000000000..82752b5522b9 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/jquery/css/themes/base/jquery-ui.min.css @@ -0,0 +1 @@ +.ui-helper-hidden{display:none;}.ui-helper-hidden-accessible{position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none;}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;}.ui-helper-clearfix:after{clear:both;}.ui-helper-clearfix{zoom:1;}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0);}.ui-state-disabled{cursor:default!important;}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%;}.ui-accordion{width:100%;}.ui-accordion .ui-accordion-header{cursor:pointer;position:relative;margin-top:1px;zoom:1;}.ui-accordion .ui-accordion-header-active{border-bottom:0!important;}.ui-accordion .ui-accordion-heading{display:block;font-size:1em;padding:.5em .5em .5em .7em;}.ui-accordion-icons .ui-accordion-heading{padding-left:2.2em;}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px;}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;margin-top:-2px;position:relative;top:1px;margin-bottom:2px;overflow:auto;display:none;zoom:1;}.ui-accordion .ui-accordion-content-active{display:block;}.ui-autocomplete{position:absolute;cursor:default;}* html .ui-autocomplete{width:1px;}.ui-button{display:inline-block;position:relative;padding:0;margin-right:.1em;text-decoration:none!important;cursor:pointer;text-align:center;zoom:1;overflow:hidden;*overflow:visible;}.ui-button-icon-only{width:2.2em;}button.ui-button-icon-only{width:2.4em;}.ui-button-icons-only{width:3.4em;}button.ui-button-icons-only{width:3.7em;}.ui-button .ui-button-text{display:block;line-height:1.4;}.ui-button-text-only .ui-button-text{padding:.4em 1em;}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px;}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em;}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em;}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em;}input.ui-button{padding:.4em 1em;}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px;}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px;}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em;}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em;}.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em;}.ui-buttonset{margin-right:7px;}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em;}button.ui-button::-moz-focus-inner{border:0;padding:0;}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none;}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0;}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em;}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px;}.ui-datepicker .ui-datepicker-prev{left:2px;}.ui-datepicker .ui-datepicker-next{right:2px;}.ui-datepicker .ui-datepicker-prev-hover{left:1px;}.ui-datepicker .ui-datepicker-next-hover{right:1px;}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px;}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center;}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0;}.ui-datepicker select.ui-datepicker-month-year{width:100%;}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%;}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em;}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0;}.ui-datepicker td{border:0;padding:1px;}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none;}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0;}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible;}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left;}.ui-datepicker.ui-datepicker-multi{width:auto;}.ui-datepicker-multi .ui-datepicker-group{float:left;}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em;}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%;}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%;}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%;}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0;}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0;}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left;}.ui-datepicker-row-break{clear:both;width:100%;font-size:0;}.ui-datepicker-rtl{direction:rtl;}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto;}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto;}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto;}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto;}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right;}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left;}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right;}.ui-datepicker-rtl .ui-datepicker-group{float:right;}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px;}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px;}.ui-datepicker-cover{display:none;display:block;position:absolute;z-index:-1;filter:mask();top:-4px;left:-4px;width:200px;height:200px;}.ui-dialog{position:absolute;padding:.2em;width:300px;overflow:hidden;}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative;}.ui-dialog .ui-dialog-title{float:left;margin:.1em 16px .1em 0;}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:19px;margin:-10px 0 0 0;padding:1px;height:18px;}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin:1px;}.ui-dialog .ui-dialog-titlebar-close:hover,.ui-dialog .ui-dialog-titlebar-close:focus{padding:0;}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto;zoom:1;}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em;}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right;}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer;}.ui-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px;}.ui-draggable .ui-dialog-titlebar{cursor:move;}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none;}.ui-menu .ui-menu{margin-top:-3px;position:absolute;}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;width:100%;}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;zoom:1;font-weight:normal;}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px;}.ui-menu .ui-state-disabled{font-weight:normal;padding:.0em .4em;margin:.4em 0 .2em;line-height:1.5;}.ui-menu-icons{position:relative;}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em;}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em;}.ui-menu .ui-menu-icon{position:static;float:right;}.ui-menubar{list-style:none;margin:0;padding-left:0;}.ui-menubar-item{float:left;}.ui-menubar .ui-button{float:left;font-weight:normal;border-top-width:0!important;border-bottom-width:0!important;margin:0;outline:none;}.ui-menubar .ui-menubar-link{border-right:1px dashed transparent;border-left:1px dashed transparent;}.ui-menubar .ui-menu{width:200px;position:absolute;z-index:9999;font-weight:normal;}.ui-progressbar{height:2em;text-align:left;overflow:hidden;}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%;}.ui-resizable{position:relative;}.ui-resizable-handle{position:absolute;font-size:.1px;z-index:99999;display:block;}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none;}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0;}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0;}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%;}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%;}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px;}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px;}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px;}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px;}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black;}.ui-slider{position:relative;text-align:left;}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0;}.ui-slider-horizontal{height:.8em;}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em;}.ui-slider-horizontal .ui-slider-range{top:0;height:100%;}.ui-slider-horizontal .ui-slider-range-min{left:0;}.ui-slider-horizontal .ui-slider-range-max{right:0;}.ui-slider-vertical{width:.8em;height:100px;}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em;}.ui-slider-vertical .ui-slider-range{left:0;width:100%;}.ui-slider-vertical .ui-slider-range-min{bottom:0;}.ui-slider-vertical .ui-slider-range-max{top:0;}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle;}.ui-spinner-input{border:none;background:none;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px;}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;z-index:100;text-align:center;vertical-align:middle;position:absolute;cursor:default;display:block;overflow:hidden;right:0;}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none;}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0;}.ui-spinner-up{top:0;}.ui-spinner-down{bottom:0;}span.ui-spinner{background:none;}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px;}.ui-tabs{position:relative;padding:.2em;zoom:1;}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0;}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom:0!important;padding:0;white-space:nowrap;}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none;}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px;}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text;}.ui-tabs .ui-tabs-nav li a,.ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer;}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none;}.ui-tooltip{padding:8px;position:absolute;z-index:9999;-o-box-shadow:0 0 5px #aaa;-moz-box-shadow:0 0 5px #aaa;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa;}* html .ui-tooltip{background-image:none;}body .ui-tooltip{border-width:2px;}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em;}.ui-widget .ui-widget{font-size:1em;}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em;}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222;}.ui-widget-content a{color:#222;}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold;}.ui-widget-header a{color:#222;}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555;}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none;}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121;}.ui-state-hover a,.ui-state-hover a:hover{color:#212121;text-decoration:none;}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121;}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none;}.ui-widget :active{outline:none;}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636;}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636;}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a;}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a;}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a;}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold;}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal;}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none;}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png);}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png);}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png);}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png);}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png);}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png);}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png);}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png);}.ui-icon-carat-1-n{background-position:0 0;}.ui-icon-carat-1-ne{background-position:-16px 0;}.ui-icon-carat-1-e{background-position:-32px 0;}.ui-icon-carat-1-se{background-position:-48px 0;}.ui-icon-carat-1-s{background-position:-64px 0;}.ui-icon-carat-1-sw{background-position:-80px 0;}.ui-icon-carat-1-w{background-position:-96px 0;}.ui-icon-carat-1-nw{background-position:-112px 0;}.ui-icon-carat-2-n-s{background-position:-128px 0;}.ui-icon-carat-2-e-w{background-position:-144px 0;}.ui-icon-triangle-1-n{background-position:0 -16px;}.ui-icon-triangle-1-ne{background-position:-16px -16px;}.ui-icon-triangle-1-e{background-position:-32px -16px;}.ui-icon-triangle-1-se{background-position:-48px -16px;}.ui-icon-triangle-1-s{background-position:-64px -16px;}.ui-icon-triangle-1-sw{background-position:-80px -16px;}.ui-icon-triangle-1-w{background-position:-96px -16px;}.ui-icon-triangle-1-nw{background-position:-112px -16px;}.ui-icon-triangle-2-n-s{background-position:-128px -16px;}.ui-icon-triangle-2-e-w{background-position:-144px -16px;}.ui-icon-arrow-1-n{background-position:0 -32px;}.ui-icon-arrow-1-ne{background-position:-16px -32px;}.ui-icon-arrow-1-e{background-position:-32px -32px;}.ui-icon-arrow-1-se{background-position:-48px -32px;}.ui-icon-arrow-1-s{background-position:-64px -32px;}.ui-icon-arrow-1-sw{background-position:-80px -32px;}.ui-icon-arrow-1-w{background-position:-96px -32px;}.ui-icon-arrow-1-nw{background-position:-112px -32px;}.ui-icon-arrow-2-n-s{background-position:-128px -32px;}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px;}.ui-icon-arrow-2-e-w{background-position:-160px -32px;}.ui-icon-arrow-2-se-nw{background-position:-176px -32px;}.ui-icon-arrowstop-1-n{background-position:-192px -32px;}.ui-icon-arrowstop-1-e{background-position:-208px -32px;}.ui-icon-arrowstop-1-s{background-position:-224px -32px;}.ui-icon-arrowstop-1-w{background-position:-240px -32px;}.ui-icon-arrowthick-1-n{background-position:0 -48px;}.ui-icon-arrowthick-1-ne{background-position:-16px -48px;}.ui-icon-arrowthick-1-e{background-position:-32px -48px;}.ui-icon-arrowthick-1-se{background-position:-48px -48px;}.ui-icon-arrowthick-1-s{background-position:-64px -48px;}.ui-icon-arrowthick-1-sw{background-position:-80px -48px;}.ui-icon-arrowthick-1-w{background-position:-96px -48px;}.ui-icon-arrowthick-1-nw{background-position:-112px -48px;}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px;}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px;}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px;}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px;}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px;}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px;}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px;}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px;}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px;}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px;}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px;}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px;}.ui-icon-arrowreturn-1-w{background-position:-64px -64px;}.ui-icon-arrowreturn-1-n{background-position:-80px -64px;}.ui-icon-arrowreturn-1-e{background-position:-96px -64px;}.ui-icon-arrowreturn-1-s{background-position:-112px -64px;}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px;}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px;}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px;}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px;}.ui-icon-arrow-4{background-position:0 -80px;}.ui-icon-arrow-4-diag{background-position:-16px -80px;}.ui-icon-extlink{background-position:-32px -80px;}.ui-icon-newwin{background-position:-48px -80px;}.ui-icon-refresh{background-position:-64px -80px;}.ui-icon-shuffle{background-position:-80px -80px;}.ui-icon-transfer-e-w{background-position:-96px -80px;}.ui-icon-transferthick-e-w{background-position:-112px -80px;}.ui-icon-folder-collapsed{background-position:0 -96px;}.ui-icon-folder-open{background-position:-16px -96px;}.ui-icon-document{background-position:-32px -96px;}.ui-icon-document-b{background-position:-48px -96px;}.ui-icon-note{background-position:-64px -96px;}.ui-icon-mail-closed{background-position:-80px -96px;}.ui-icon-mail-open{background-position:-96px -96px;}.ui-icon-suitcase{background-position:-112px -96px;}.ui-icon-comment{background-position:-128px -96px;}.ui-icon-person{background-position:-144px -96px;}.ui-icon-print{background-position:-160px -96px;}.ui-icon-trash{background-position:-176px -96px;}.ui-icon-locked{background-position:-192px -96px;}.ui-icon-unlocked{background-position:-208px -96px;}.ui-icon-bookmark{background-position:-224px -96px;}.ui-icon-tag{background-position:-240px -96px;}.ui-icon-home{background-position:0 -112px;}.ui-icon-flag{background-position:-16px -112px;}.ui-icon-calendar{background-position:-32px -112px;}.ui-icon-cart{background-position:-48px -112px;}.ui-icon-pencil{background-position:-64px -112px;}.ui-icon-clock{background-position:-80px -112px;}.ui-icon-disk{background-position:-96px -112px;}.ui-icon-calculator{background-position:-112px -112px;}.ui-icon-zoomin{background-position:-128px -112px;}.ui-icon-zoomout{background-position:-144px -112px;}.ui-icon-search{background-position:-160px -112px;}.ui-icon-wrench{background-position:-176px -112px;}.ui-icon-gear{background-position:-192px -112px;}.ui-icon-heart{background-position:-208px -112px;}.ui-icon-star{background-position:-224px -112px;}.ui-icon-link{background-position:-240px -112px;}.ui-icon-cancel{background-position:0 -128px;}.ui-icon-plus{background-position:-16px -128px;}.ui-icon-plusthick{background-position:-32px -128px;}.ui-icon-minus{background-position:-48px -128px;}.ui-icon-minusthick{background-position:-64px -128px;}.ui-icon-close{background-position:-80px -128px;}.ui-icon-closethick{background-position:-96px -128px;}.ui-icon-key{background-position:-112px -128px;}.ui-icon-lightbulb{background-position:-128px -128px;}.ui-icon-scissors{background-position:-144px -128px;}.ui-icon-clipboard{background-position:-160px -128px;}.ui-icon-copy{background-position:-176px -128px;}.ui-icon-contact{background-position:-192px -128px;}.ui-icon-image{background-position:-208px -128px;}.ui-icon-video{background-position:-224px -128px;}.ui-icon-script{background-position:-240px -128px;}.ui-icon-alert{background-position:0 -144px;}.ui-icon-info{background-position:-16px -144px;}.ui-icon-notice{background-position:-32px -144px;}.ui-icon-help{background-position:-48px -144px;}.ui-icon-check{background-position:-64px -144px;}.ui-icon-bullet{background-position:-80px -144px;}.ui-icon-radio-on{background-position:-96px -144px;}.ui-icon-radio-off{background-position:-112px -144px;}.ui-icon-pin-w{background-position:-128px -144px;}.ui-icon-pin-s{background-position:-144px -144px;}.ui-icon-play{background-position:0 -160px;}.ui-icon-pause{background-position:-16px -160px;}.ui-icon-seek-next{background-position:-32px -160px;}.ui-icon-seek-prev{background-position:-48px -160px;}.ui-icon-seek-end{background-position:-64px -160px;}.ui-icon-seek-start{background-position:-80px -160px;}.ui-icon-seek-first{background-position:-80px -160px;}.ui-icon-stop{background-position:-96px -160px;}.ui-icon-eject{background-position:-112px -160px;}.ui-icon-volume-off{background-position:-128px -160px;}.ui-icon-volume-on{background-position:-144px -160px;}.ui-icon-power{background-position:0 -176px;}.ui-icon-signal-diag{background-position:-16px -176px;}.ui-icon-signal{background-position:-32px -176px;}.ui-icon-battery-0{background-position:-48px -176px;}.ui-icon-battery-1{background-position:-64px -176px;}.ui-icon-battery-2{background-position:-80px -176px;}.ui-icon-battery-3{background-position:-96px -176px;}.ui-icon-circle-plus{background-position:0 -192px;}.ui-icon-circle-minus{background-position:-16px -192px;}.ui-icon-circle-close{background-position:-32px -192px;}.ui-icon-circle-triangle-e{background-position:-48px -192px;}.ui-icon-circle-triangle-s{background-position:-64px -192px;}.ui-icon-circle-triangle-w{background-position:-80px -192px;}.ui-icon-circle-triangle-n{background-position:-96px -192px;}.ui-icon-circle-arrow-e{background-position:-112px -192px;}.ui-icon-circle-arrow-s{background-position:-128px -192px;}.ui-icon-circle-arrow-w{background-position:-144px -192px;}.ui-icon-circle-arrow-n{background-position:-160px -192px;}.ui-icon-circle-zoomin{background-position:-176px -192px;}.ui-icon-circle-zoomout{background-position:-192px -192px;}.ui-icon-circle-check{background-position:-208px -192px;}.ui-icon-circlesmall-plus{background-position:0 -208px;}.ui-icon-circlesmall-minus{background-position:-16px -208px;}.ui-icon-circlesmall-close{background-position:-32px -208px;}.ui-icon-squaresmall-plus{background-position:-48px -208px;}.ui-icon-squaresmall-minus{background-position:-64px -208px;}.ui-icon-squaresmall-close{background-position:-80px -208px;}.ui-icon-grip-dotted-vertical{background-position:0 -224px;}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px;}.ui-icon-grip-solid-vertical{background-position:-32px -224px;}.ui-icon-grip-solid-horizontal{background-position:-48px -224px;}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px;}.ui-icon-grip-diagonal-se{background-position:-80px -224px;}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;-khtml-border-top-left-radius:4px;border-top-left-radius:4px;}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;-khtml-border-top-right-radius:4px;border-top-right-radius:4px;}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;-khtml-border-bottom-left-radius:4px;border-bottom-left-radius:4px;}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;-khtml-border-bottom-right-radius:4px;border-bottom-right-radius:4px;}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);-moz-border-radius:8px;-khtml-border-radius:8px;-webkit-border-radius:8px;border-radius:8px;} \ No newline at end of file diff --git a/lib/matplotlib/backends/web_backend/jquery/js/jquery-1.7.1.min.js b/lib/matplotlib/backends/web_backend/jquery/js/jquery-1.7.1.min.js new file mode 100644 index 000000000000..198b3ff07d80 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/jquery/js/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
    a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
    "+""+"
    ",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
    t
    ",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
    ",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/lib/matplotlib/backends/web_backend/jquery/js/jquery-ui.min.js b/lib/matplotlib/backends/web_backend/jquery/js/jquery-ui.min.js new file mode 100644 index 000000000000..1365ee1c4179 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/jquery/js/jquery-ui.min.js @@ -0,0 +1,16 @@ +/*! + * jQuery UI @VERSION + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */(function(a,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"@VERSION",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(c,d){function h(b,c,d,f){a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)});return c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){if(c===b)return g["inner"+d].call(this);return this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){if(typeof b!="number")return g["outer"+d].call(this,b);return this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!!d&&!!a.element[0].parentNode&&a.element[0].parentNode.nodeType!==11)for(var e=0;e0)return!0;b[d]=1,e=b[d]>0,b[d]=0;return e},isOverAxis:function(a,b,c){return a>b&&a",options:{disabled:!1,create:null},_createWidget:function(b,c){c=a(c||this.defaultElement||this)[0],this.element=a(c),this.options=a.widget.extend({},this.options,this._getCreateOptions(),b),this.bindings=a(),this.hoverable=a(),this.focusable=a(),c!==this&&(a.data(c,this.widgetName,this),this._bind({remove:"destroy"}),this.document=a(c.style?c.ownerDocument:c.document||c),this.window=a(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create"),this._init()},_getCreateOptions:a.noop,_create:a.noop,_init:a.noop,destroy:function(){this._destroy(),this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled"),this.bindings.unbind("."+this.widgetName),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:a.noop,widget:function(){return this.element},option:function(c,d){var e=c,f,g,h;if(arguments.length===0)return a.widget.extend({},this.options);if(typeof c=="string"){e={},f=c.split("."),c=f.shift();if(f.length){g=e[c]=a.widget.extend({},this.options[c]);for(h=0;h=9)&&!b.button)return this._mouseUp(b);if(this._mouseStarted){this._mouseDrag(b);return b.preventDefault()}this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b));return!this._mouseStarted},_mouseUp:function(b){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b));return!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})}(jQuery),function(a,b){a.widget("ui.draggable",a.ui.mouse,{version:"@VERSION",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!!this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy();return this}},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle"))return!1;this.handle=this._getHandle(b);if(!this.handle)return!1;a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")});return!0},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment();if(this._trigger("start",b)===!1){this._clear();return!1}this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.helper.addClass("ui-draggable-dragging"),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b);return!0},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1){this._mouseUp({});return!1}this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,b);return!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var d=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){d._trigger("stop",b)!==!1&&d._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b);return a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)});return c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute");return d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.lefth[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.toph[3]?j-this.offset.click.toph[2]?k-this.offset.click.left=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f=k&&g<=l||h>=k&&h<=l||gl)&&(e>=i&&e<=j||f>=i&&f<=j||ej);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();droppablesLoop:for(var g=0;g
    ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e');/sw|se|ne|nw/.test(f)&&h.css({zIndex:++c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){c.disabled||(a(this).removeClass("ui-resizable-autohide"),b._handles.show())},function(){c.disabled||b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement);return this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),a.browser.opera&&/relative/.test(f.css("position"))&&f.css({position:"relative",top:"auto",left:"auto"}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b);return!0},_mouseDrag:function(a){var b=this.helper,c=this.options,d={},e=this,f=this.originalMousePosition,g=this.axis,h=a.pageX-f.left||0,i=a.pageY-f.top||0,j=this._change[g];if(!j)return!1;var k=j.apply(this,[a,h,i]);this._updateVirtualBoundaries(a.shiftKey);if(this._aspectRatio||a.shiftKey)k=this._updateRatio(k,a);k=this._respectSize(k,a),this._propagate("resize",a),b.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(k),this._trigger("resize",a,this.ui());return!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove();return!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),ea.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null);return a},_proportionallyResize:function(){var b=this.options;if(!!this._proportionallyResizeElements.length){var c=this.helper||this.element;for(var d=0;d');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10),position:b.css("position")})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,e){a(b).each(function(){var b=a(this),f=a(this).data("resizable-alsoresize"),g={},i=e&&e.length?e:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(i,function(a,b){var c=(f[b]||0)+(h[b]||0);c&&c>=0&&(g[b]=c||null)}),a.browser.opera&&/relative/.test(b.css("position"))&&(d._revertToRelativePosition=!0,b.css({position:"absolute",top:"auto",left:"auto"})),b.css(g)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.css({position:b.data("resizable-alsoresize").position})})};d._revertToRelativePosition&&(d._revertToRelativePosition=!1,typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)),a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!!i){e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/e.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*e.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}}(jQuery),function(a,b){a.widget("ui.selectable",a.ui.mouse,{version:"@VERSION",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("
    ")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy();return this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(!this.options.disabled){var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element});return!1}})}},_mouseDrag:function(b){var c=this;this.dragged=!0;if(!this.options.disabled){var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!!i&&i.element!=c.element[0]){var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.righth||i.bottome&&i.rightf&&i.bottom *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget().toggleClass("ui-sortable-disabled",!!c)):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f){e=a(this);return!1}});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}this.currentItem=e,this._removeCurrentsFromItems();return!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b);return!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs;return!1},_mouseStop:function(b,c){if(!!b){a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1}},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers +[c].containerCache.over=0)}this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem));return this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"=");return d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")});return d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+jf&&b+ka[this.floating?"width":"height"]?l:f0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a),this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];e||(b.style.visibility="hidden");return b},update:function(a,b){if(!e||!!d.forcePlaceholderSize)b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!!c)if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.items[i][this.containers[d].floating?"left":"top"];Math.abs(j-h)this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.topthis.containment[3]?h-this.offset.click.topthis.containment[2]?i-this.offset.click.left=0;f--)a.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e={width:b.width(),height:b.height()},f=document.activeElement;b.wrap(d),(b[0]===f||a.contains(b[0],f))&&a(f).focus(),d=b.parent(),b.css("position")==="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),b.css(e);return d.css(c).show()},removeWrapper:function(b){var c=document.activeElement;b.parent().is(".ui-effects-wrapper")&&(b.parent().replaceWith(b),(b[0]===c||a.contains(b[0],c))&&a(c).focus());return b},setTransition:function(b,c,d,e){e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])});return e}}),a.fn.extend({effect:function(b,d,e,f){function m(b){function f(){a.isFunction(d)&&d.call(c[0]),a.isFunction(b)&&b()}var c=a(this),d=g.complete,e=g.mode;(c.is(":hidden")?e==="hide":e==="show")?f():j.call(c[0],g,f)}var g=l.apply(this,arguments),h=g.mode,i=g.queue,j=a.effects.effect[g.effect],k=!j&&c&&a.effects[g.effect];if(a.fx.off||!j&&!k)return h?this[h](g.duration,g.complete):this.each(function(){g.complete&&g.complete.call(this)});return j?i===!1?this.each(m):this.queue(i||"fx",m):k.call(this,{options:g,duration:g.duration,callback:g.complete,mode:g.mode})},_show:a.fn.show,show:function(a){if(m(a))return this._show.apply(this,arguments);var b=l.apply(this,arguments);b.mode="show";return this.effect.call(this,b)},_hide:a.fn.hide,hide:function(a){if(m(a))return this._hide.apply(this,arguments);var b=l.apply(this,arguments);b.mode="hide";return this.effect.call(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(m(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=l.apply(this,arguments);c.mode="toggle";return this.effect.call(this,c)},cssUnit:function(b){var c=this.css(b),d=[];a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])});return d}}),a.easing.jswing=a.easing.swing,a.extend(a.easing,{def:"easeOutQuad",swing:function(b,c,d,e,f){return a.easing[a.easing.def](b,c,d,e,f)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b+c;return-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b*b+c;return d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b*b*b+c;return-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b*b*b*b+c;return d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return b==0?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){if(b==0)return c;if(b==e)return c+d;if((b/=e/2)<1)return d/2*Math.pow(2,10*(b-1))+c;return d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){if((b/=e/2)<1)return-d/2*(Math.sqrt(1-b*b)-1)+c;return d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=e*.3,h=d;if(b==0)return c;if((b/=e)==1)return c+d;h1&&t.splice.apply(t,[1,0].concat(t.splice(u,l+1))),d.dequeue()}}(jQuery),function(a,b){a.effects.effect.clip=function(b,c){var d=a(this),e=["position","top","bottom","left","right","height","width"],f=a.effects.setMode(d,b.mode||"hide"),g=f==="show",h=b.direction||"vertical",i=h==="vertical",j=i?"height":"width",k=i?"top":"left",l={},m,n,o;a.effects.save(d,e),d.show(),m=a.effects.createWrapper(d).css({overflow:"hidden"}),n=d[0].tagName==="IMG"?m:d,o=n[j](),g&&(n.css(j,0),n.css(k,o/2)),l[j]=g?o:0,l[k]=g?0:o/2,n.animate(l,{queue:!1,duration:b.duration,easing:b.easing,complete:function(){g||d.hide(),a.effects.restore(d,e),a.effects.removeWrapper(d),c()}})}}(jQuery),function(a,b){a.effects.effect.drop=function(b,c){var d=a(this),e=["position","top","bottom","left","right","opacity","height","width"],f=a.effects.setMode(d,b.mode||"hide"),g=f==="show",h=b.direction||"left",i=h==="up"||h==="down"?"top":"left",j=h==="up"||h==="left"?"pos":"neg",k={opacity:g?1:0},l;a.effects.save(d,e),d.show(),a.effects.createWrapper(d),l=b.distance||d[i=="top"?"outerHeight":"outerWidth"]({margin:!0})/2,g&&d.css("opacity",0).css(i,j=="pos"?-l:l),k[i]=(g?j==="pos"?"+=":"-=":j==="pos"?"-=":"+=")+l,d.animate(k,{queue:!1,duration:b.duration,easing:b.easing,complete:function(){f=="hide"&&d.hide(),a.effects.restore(d,e),a.effects.removeWrapper(d),c()}})}}(jQuery),function(a,b){a.effects.effect.explode=function(b,c){function t(){f.css({visibility:"visible"}),a(l).remove(),h||f.hide(),c()}function s(){l.push(this),l.length==d*e&&t()}var d=b.pieces?Math.round(Math.sqrt(b.pieces)):3,e=d,f=a(this),g=a.effects.setMode(f,b.mode||"hide"),h=g==="show",i=f.show().css("visibility","hidden").offset(),j=Math.ceil(f.outerWidth()/e),k=Math.ceil(f.outerHeight()/d),l=[],m,n,o,p,q,r;for(m=0;m").css({position:"absolute",visibility:"visible",left:-n*j,top:-m*k}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:j,height:k,left:o+(h?q*j:0),top:p+(h?r*k:0),opacity:h?0:1}).animate({left:o+(h?0:q*j),top:p+(h?0:r*k),opacity:h?1:0},b.duration||500,b.easing,s)}}}(jQuery),function(a,b){a.effects.effect.fade=function(b,c){var d=a(this),e=a.effects.setMode(d,b.mode||"toggle"),f=e==="hide";d.show(),d.animate({opacity:f?0:1},{queue:!1,duration:b.duration,easing:b.easing,complete:function(){f&&d.hide(),c()}})}}(jQuery),function(a,b){a.effects.effect.fold=function(b,c){var d=a(this),e=["position","top","bottom","left","right","height","width"],f=a.effects.setMode(d,b.mode||"hide"),g=f==="show",h=f==="hide",i=b.size||15,j=/([0-9]+)%/.exec(i),k=!!b.horizFirst,l=g!=k,m=l?["width","height"]:["height","width"],n=b.duration/2,o,p,q={},r={};a.effects.save(d,e),d.show(),o=a.effects.createWrapper(d).css({overflow:"hidden"}),p=l?[o.width(),o.height()]:[o.height(),o.width()],j&&(i=parseInt(j[1],10)/100*p[h?0:1]),g&&o.css(k?{height:0,width:i}:{height:i,width:0}),q[m[0]]=g?p[0]:i,r[m[1]]=g?p[1]:0,o.animate(q,n,b.easing).animate(r,n,b.easing,function(){h&&d.hide(),a.effects.restore(d,e),a.effects.removeWrapper(d),c()})}}(jQuery),function(a,b){a.effects.effect.highlight=function(b,c){var d=a(this),e=["backgroundImage","backgroundColor","opacity"],f= +a.effects.setMode(d,b.mode||"show"),g={backgroundColor:d.css("backgroundColor")};f==="hide"&&(g.opacity=0),a.effects.save(d,e),d.show().css({backgroundImage:"none",backgroundColor:b.color||"#ffff99"}).animate(g,{queue:!1,duration:b.duration,easing:b.easing,complete:function(){f==="hide"&&d.hide(),a.effects.restore(d,e),c()}})}}(jQuery),function(a,b){a.effects.effect.pulsate=function(b,c){var d=a(this),e=a.effects.setMode(d,b.mode||"show"),f=e==="show",g=e==="hide",h=f||e==="hide",i=(b.times||5)*2+(h?1:0),j=b.duration/i,k=0,l=d.queue(),m=l.length,n;if(f||!d.is(":visible"))d.css("opacity",0).show(),k=1;for(n=1;n1&&l.splice.apply(l,[1,0].concat(l.splice(m,i+1))),d.dequeue()}}(jQuery),function(a,b){a.effects.effect.puff=function(b,c){var d=a(this),e=a.effects.setMode(d,b.mode||"hide"),f=e==="hide",g=parseInt(b.percent,10)||150,h=g/100,i={height:d.height(),width:d.width()};a.extend(b,{effect:"scale",queue:!1,fade:!0,mode:e,complete:c,percent:f?g:100,from:f?i:{height:i.height*h,width:i.width*h}}),d.effect(b)},a.effects.effect.scale=function(b,c){var d=a(this),e=a.extend(!0,{},b),f=a.effects.setMode(d,b.mode||"effect"),g=parseInt(b.percent,10)||(parseInt(b.percent,10)==0?0:f=="hide"?0:100),h=b.direction||"both",i=b.origin,j={height:d.height(),width:d.width(),outerHeight:d.outerHeight(),outerWidth:d.outerWidth()},k={y:h!="horizontal"?g/100:1,x:h!="vertical"?g/100:1};e.effect="size",e.queue=!1,e.complete=c,f!="effect"&&(e.origin=i||["middle","center"],e.restore=!0),e.from=b.from||(f=="show"?{height:0,width:0}:j),e.to={height:j.height*k.y,width:j.width*k.x,outerHeight:j.outerHeight*k.y,outerWidth:j.outerWidth*k.x},e.fade&&(f=="show"&&(e.from.opacity=0,e.to.opacity=1),f=="hide"&&(e.from.opacity=1,e.to.opacity=0)),d.effect(e)},a.effects.effect.size=function(b,c){var d=a(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],f=["position","top","bottom","left","right","overflow","opacity"],g=["width","height","overflow"],h=["fontSize"],i=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],j=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],k=a.effects.setMode(d,b.mode||"effect"),l=b.restore||k!=="effect",m=b.scale||"both",n=b.origin||["middle","center"],o,p,q,r=d.css("position");k==="show"&&d.show(),o={height:d.height(),width:d.width(),outerHeight:d.outerHeight(),outerWidth:d.outerWidth()},d.from=b.from||o,d.to=b.to||o,q={from:{y:d.from.height/o.height,x:d.from.width/o.width},to:{y:d.to.height/o.height,x:d.to.width/o.width}};if(m=="box"||m=="both")q.from.y!==q.to.y&&(e=e.concat(i),d.from=a.effects.setTransition(d,i,q.from.y,d.from),d.to=a.effects.setTransition(d,i,q.to.y,d.to)),q.from.x!==q.to.x&&(e=e.concat(j),d.from=a.effects.setTransition(d,j,q.from.x,d.from),d.to=a.effects.setTransition(d,j,q.to.x,d.to));(m=="content"||m=="both")&&q.from.y!==q.to.y&&(e=e.concat(h),d.from=a.effects.setTransition(d,h,q.from.y,d.from),d.to=a.effects.setTransition(d,h,q.to.y,d.to)),a.effects.save(d,l?e:f),d.show(),a.effects.createWrapper(d),d.css("overflow","hidden").css(d.from),n&&(p=a.effects.getBaseline(n,o),d.from.top=(o.outerHeight-d.outerHeight())*p.y,d.from.left=(o.outerWidth-d.outerWidth())*p.x,d.to.top=(o.outerHeight-d.to.outerHeight)*p.y,d.to.left=(o.outerWidth-d.to.outerWidth)*p.x),d.css(d.from);if(m=="content"||m=="both")i=i.concat(["marginTop","marginBottom"]).concat(h),j=j.concat(["marginLeft","marginRight"]),g=e.concat(i).concat(j),d.find("*[width]").each(function(){var c=a(this),d={height:c.height(),width:c.width()};l&&a.effects.save(c,g),c.from={height:d.height*q.from.y,width:d.width*q.from.x},c.to={height:d.height*q.to.y,width:d.width*q.to.x},q.from.y!=q.to.y&&(c.from=a.effects.setTransition(c,i,q.from.y,c.from),c.to=a.effects.setTransition(c,i,q.to.y,c.to)),q.from.x!=q.to.x&&(c.from=a.effects.setTransition(c,j,q.from.x,c.from),c.to=a.effects.setTransition(c,j,q.to.x,c.to)),c.css(c.from),c.animate(c.to,b.duration,b.easing,function(){l&&a.effects.restore(c,g)})});d.animate(d.to,{queue:!1,duration:b.duration,easing:b.easing,complete:function(){d.to.opacity===0&&d.css("opacity",d.from.opacity),k=="hide"&&d.hide(),a.effects.restore(d,l?e:f),l||(r==="static"?d.css({position:"relative",top:d.to.top,left:d.to.left}):a.each(["top","left"],function(a,b){d.css(b,function(c,e){var f=parseInt(e,10),g=a?d.to.left:d.to.top,h=a?d.to.outerWidth-d.from.outerWidth:d.to.outerHeight-d.from.outerHeight,i=n[a]===b,j=n[a]==="middle"||n[a]==="center";if(e==="auto")return g+"px";return f+g+"px"})})),a.effects.removeWrapper(d),c()}})}}(jQuery),function(a,b){a.effects.effect.shake=function(b,c){var d=a(this),e=["position","top","bottom","left","right","height","width"],f=a.effects.setMode(d,b.mode||"effect"),g=b.direction||"left",h=b.distance||20,i=b.times||3,j=i*2+1,k=b.duration,l=g=="up"||g=="down"?"top":"left",m=g=="up"||g=="left",n={},o={},p={},q,r=d.queue(),s=r.length;a.effects.save(d,e),d.show(),a.effects.createWrapper(d),n[l]=(m?"-=":"+=")+h,o[l]=(m?"+=":"-=")+h*2,p[l]=(m?"-=":"+=")+h*2,d.animate(n,k,b.easing);for(q=1;q1&&r.splice.apply(r,[1,0].concat(r.splice(s,j+1))),d.dequeue()}}(jQuery),function(a,b){a.effects.effect.slide=function(b,c){var d=a(this),e=["position","top","bottom","left","right","width","height"],f=a.effects.setMode(d,b.mode||"show"),g=f==="show",h=b.direction||"left",i=h=="up"||h=="down"?"top":"left",j=h=="up"||h=="left",k,l={},m;a.effects.save(d,e),d.show(),k=b.distance||d[i==="top"?"outerHeight":"outerWidth"]({margin:!0}),a.effects.createWrapper(d).css({overflow:"hidden"}),g&&d.css(i,j?isNaN(k)?"-"+k:-k:k),l[i]=(g?j?"+=":"-=":j?"-=":"+=")+k,d.animate(l,{queue:!1,duration:b.duration,easing:b.easing,complete:function(){f==="hide"&&d.hide(),a.effects.restore(d,e),a.effects.removeWrapper(d),c()}})}}(jQuery),function(a,b){a.effects.effect.transfer=function(b,c){var d=a(this),e=a(b.to),f=e.css("position")==="fixed",g=a("body"),h=f?g.scrollTop():0,i=f?g.scrollLeft():0,j=e.offset(),k={top:j.top-h,left:j.left-i,height:e.innerHeight(),width:e.innerWidth()},l=d.offset(),m=a('
    ').appendTo(document.body).addClass(b.className).css({top:l.top-h,left:l.left-i,height:d.innerHeight(),width:d.innerWidth(),position:f?"fixed":"absolute"}).animate(k,b.duration,b.easing,function(){m.remove(),c()})}}(jQuery),function(a,b){a.widget("ui.accordion",{version:"@VERSION",options:{active:0,animated:"slide",collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var b=this,c=b.options;b.lastToggle={},b.element.addClass("ui-accordion ui-widget ui-helper-reset"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),b._hoverable(b.headers),b._focusable(b.headers),b.headers.find(":first-child").addClass("ui-accordion-heading"),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"),!c.collapsible&&c.active===!1&&(c.active=0),c.active<0&&(c.active+=this.headers.length),b.active=b._findActive(c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.refresh(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",a.proxy(b,"_keydown")).next().attr("role","tabpanel"),b.headers.not(b.active).attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),this._setupEvents(c.event)},_createIcons:function(){var b=this.options.icons;b&&(a("").addClass("ui-accordion-header-icon ui-icon "+b.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(b.header).addClass(b.activeHeader),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-accordion-header-icon").remove(),this.element.removeClass("ui-accordion-icons")},_destroy:function(){this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex").find("a").removeAttr("tabIndex").end().find(".ui-accordion-heading").removeClass("ui-accordion-heading"),this._destroyIcons();var a=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");this.options.heightStyle!=="content"&&a.css("height","")},_setOption:function(a,b){a==="active"?this._activate(b):(a==="event"&&(this.options.event&&this.headers.unbind(this.options.event+".accordion",this._eventHandler),this._setupEvents(b)),this._super(a,b),a==="collapsible"&&!b&&this.options.active===!1&&this._activate(0),a==="icons"&&(this._destroyIcons(),b&&this._createIcons()),a==="disabled"&&this.headers.add(this.headers.next()).toggleClass("ui-accordion-disabled ui-state-disabled",!!b))},_keydown:function(b){if(!(this.options.disabled||b.altKey||b.ctrlKey)){var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._eventHandler(b)}f&&(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),b.preventDefault())}},refresh:function(){var b=this.options,c=this.element.parent(),d,e;b.heightStyle==="fill"?(a.support.minHeight||(e=c.css("overflow"),c.css("overflow","hidden")),d=c.height(),this.element.siblings(":visible").each(function(){var b=a(this),c=b.css("position");c!=="absolute"&&c!=="fixed"&&(d-=b.outerHeight(!0))}),e&&c.css("overflow",e),this.headers.each(function(){d-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,d-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")):b.heightStyle==="auto"&&(d=0,this.headers.next().each(function(){d=Math.max(d,a(this).height("").height())}).height(d));return this},_activate:function(b){var c=this._findActive(b)[0];c!==this.active[0]&&(c=c||this.active[0],this._eventHandler({target:c,currentTarget:c,preventDefault:a.noop}))},_findActive:function(b){return typeof b=="number"?this.headers.eq(b):a()},_setupEvents:function(b){b&&this.headers.bind(b.split(" ").join(".accordion ")+".accordion",a.proxy(this,"_eventHandler"))},_eventHandler:function(b){var c=this.options,d=this.active,e=a(b.currentTarget),f=e[0]===d[0],g=f&&c.collapsible,h=g?a():e.next(),i=d.next(),j={oldHeader:d,oldContent:i,newHeader:g?a():e,newContent:h};b.preventDefault();c.disabled||f&&!c.collapsible||this._trigger("beforeActivate",b,j)===!1||(c.active=g?!1:this.headers.index(e),this.active=f?a():e,this._toggle(j),d.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-accordion-header-icon").removeClass(c.icons.activeHeader).addClass(c.icons.header),f||(e.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-accordion-header-icon").removeClass(c.icons.header).addClass(c.icons.activeHeader),e.next().addClass("ui-accordion-content-active")))},_toggle:function(b){function g(){c._completed(b)}var c=this,d=c.options,e=b.newContent,f=b.oldContent;if(d.animated){var h=a.ui.accordion.animations,i=d.animated,j;h[i]||(j={easing:a.easing[i]?i:"slide",duration:700},i="slide"),h[i]({widget:c,toShow:e,toHide:f,prevShow:c.lastToggle.toShow,prevHide:c.lastToggle.toHide,complete:g,down:e.length&&(!f.length||e.index()",options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var b=this,c,d,e;this.isMultiLine=this.element.is("textarea,[contenteditable]"),this.valueMethod=this.element[this.element.is("input,textarea")?"val":"text"],this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(f){if(b.options.disabled||b.element.prop("readOnly"))c=!0,e=!0,d=!0;else{c=!1,e=!1,d=!1;var g=a.ui.keyCode;switch(f.keyCode){case g.PAGE_UP:c=!0,b._move("previousPage",f);break;case g.PAGE_DOWN:c=!0,b._move("nextPage",f);break;case g.UP:c=!0,b._keyEvent("previous",f);break;case g.DOWN:c=!0,b._keyEvent("next",f);break;case g.ENTER:case g.NUMPAD_ENTER:b.menu.active&&(c=!0,f.preventDefault());case g.TAB:if(!b.menu.active)return;b.menu.select(f);break;case g.ESCAPE:b.menu.element.is(":visible")&&(b._value(b.term),b.close(f));break;default:d=!0,b._searchTimeout(f)}}}).bind("keypress.autocomplete",function(e){if(c)c=!1,e.preventDefault();else{if(d)return;var f=a.ui.keyCode;switch(e.keyCode){case f.PAGE_UP:b._move("previousPage",e);break;case f.PAGE_DOWN:b._move("nextPage",e);break;case f.UP:b._keyEvent("previous",e);break;case f.DOWN:b._keyEvent("next",e)}}}).bind("input.autocomplete",function(a){e?(e=!1,a.preventDefault()):b._searchTimeout(a)}).bind("focus.autocomplete",function(){b.options.disabled||(b.selectedItem=null,b.previous=b._value())}).bind("blur.autocomplete",function(a){b.options.disabled||(clearTimeout(b.searching),b.cancelSearch=!0,b.closing=setTimeout(function(){b.close(a),b._change(a)},150))}),this._initSource(),this.response=function(){return b._response.apply(b,arguments)},this.menu=a("
      ").addClass("ui-autocomplete").appendTo(this.document.find(this.options.appendTo||"body")[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){b.document.one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({input:a(),focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b._value(d.value)},select:function(a,c){var d=c.item.data("item.autocomplete"),e=b.previous;b.element[0]!==b.document[0].activeElement&&(b.element.focus(),b.previous=e,setTimeout(function(){b.previous=e,b.selectedItem=d},1)),!1!==b._trigger("select",a,{item:d})&&b._value(d.value),b.term=b._value(),b.close(a),b.selectedItem=d}}).zIndex(this.element.zIndex()+1).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),this._bind(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove()},_setOption:function(a,b){this._super(a,b),a==="source"&&this._initSource(),a==="appendTo"&&this.menu.element.appendTo(this.document.find(b||"body")[0]),a==="disabled"&&b&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,d,e;a.isArray(this.options.source)?(d=this.options.source,this.source=function(b,c){c(a.ui.autocomplete.filter(d,b.term))}):typeof this.options.source=="string"?(e=this.options.source,this.source=function(d,f){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:e,data:d,dataType:"json",autocompleteRequest:++c,success:function(a,b){this.autocompleteRequest===c&&f(a)},error:function(){this.autocompleteRequest===c&&f([])}})}):this.source=this.options.source},_searchTimeout:function(a){var b=this;clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!==b._value()&&(b.selectedItem=null,b.search(null,a))},b.options.delay)},search:function(a,b){a=a!=null?a:this._value(),this.term=this._value();if(a.length").data("item.autocomplete",c).append(a("").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible"))this.search(null,b);else{if(this.menu.isFirstItem()&&/^previous/.test(a)||this.menu.isLastItem()&&/^next/.test(a)){this._value(this.term),this.menu.blur();return}this.menu[a](b)}},widget:function(){return this.menu.element},_value:function(a){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})}(jQuery),function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form}));return e};a.widget("ui.button",{version:"@VERSION",defaultElement:"').addClass(this._triggerClass).html(g==""?f:$("").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){$.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._showDatepicker(a[0]);return!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;db&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);c.hasClass(this.markerClassName)||(c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block"))},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$(''),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f);return this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})}},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(a){$.datepicker.log(a)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if(!$.datepicker._isDisabledDatepicker(a)&&$.datepicker._lastInput!=a){var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){e|=$(this).css("position")=="fixed";return!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&($.effects.effect[g]||$.effects[g])?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a));var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+$(document).scrollLeft(),i=document.documentElement.clientHeight+$(document).scrollTop();b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0);return b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=$.data(a,PROP_NAME))&&this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=this,f=function(){$.datepicker._tidyDialog(b),e._curInst=null};$.effects&&($.effects.effect[c]||$.effects[c])?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,f):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,f),c||f(),this._datepickerShowing=!1;var g=this._get(b,"onClose");g&&g.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!!$.datepicker._curInst){var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);this._isDisabledDatepicker(d[0])||(this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e))},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if(!$(d).hasClass(this._unselectableClass)&&!this._isDisabledDatepicker(e[0])){var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();b.setMonth(0),b.setDate(1);return Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1-1){j=1,k=l;for(;;){var v=this._getDaysInMonth(i,j-1);if(k<=v)break;j++,k-=v}}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+112?a.getHours()+2:0);return a},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&pp)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?''+q+"":e?"":''+q+"",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?''+s+"":e?"":''+s+"",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'",x=d?'
      '+(c?w:"")+(this._isInRange(a,v)?'":"")+(c?"":w)+"
      ":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='
      '+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'
      '+"";var R=z?'":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="=5?' class="ui-datepicker-week-end"':"")+">"+''+C[T]+""}Q+=R+"";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z";var _=z?'":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Ym;_+='",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+""}n++,n>11&&(n=0,o++),Q+="
      '+this._get(a,"weekHeader")+"
      '+this._get(a,"calculateWeek")(Y)+""+(bb&&!G?" ":bc?''+Y.getDate()+"":''+Y.getDate()+"")+"
      "+(j?"
      "+(g[0]>0&&N==g[1]-1?'
      ':""):""),M+=Q}K+=M}K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'':""),a._keyEvent=!1;return K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='
      ',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
      ";return l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e;return e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth()));return this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth +,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));return this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)})},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="@VERSION",window["DP_jQuery_"+dpuuid]=$}(jQuery),function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{version:"@VERSION",options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.oldPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("
      ")).addClass(c+d.dialogClass).css({display:"none",outline:0,zIndex:d.zIndex}).attr("tabIndex",-1).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}).appendTo("body"),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a("").addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").click(function(a){a.preventDefault(),b.close(a)}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);i.find("*").add(i).disableSelection(),this._hoverable(j),this._focusable(j),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},_destroy:function(){var a=this,b,c=this.oldPosition;a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),b=c.parent.children().eq(c.index),b.length?b.before(a.element):c.parent.append(a.element)},widget:function(){return this.uiDialog},close:function(b){if(!this._isOpen)return c;var c=this,d,e;if(!1!==c._trigger("beforeClose",b)){c._isOpen=!1,c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d);return c}},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;if(e.modal&&!b||!e.stack&&!e.modal)return d._trigger("focus",c);e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c);return d},open:function(){if(!this._isOpen){var b=this,c=b.options,d=b.uiDialog;b._size(),b._position(c.position),d.show(c.show),b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode===a.ui.keyCode.TAB){var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey){d.focus(1);return!1}if(b.target===d[0]&&b.shiftKey){e.focus(1);return!1}}});var e=b.element.find(":tabbable");e.length||(e=d.find(".ui-dialog-buttonpane :tabbable"),e.length||(e=d)),e.eq(0).focus(),b._isOpen=!0,b._trigger("open");return b}},_createButtons:function(b){var c=this,d=!1;c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)});if(d){var e=a("
      ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("
      ").addClass("ui-dialog-buttonset").appendTo(e);a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a("