You can subscribe to this list here.
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(115) |
Aug
(120) |
Sep
(137) |
Oct
(170) |
Nov
(461) |
Dec
(263) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
(120) |
Feb
(74) |
Mar
(35) |
Apr
(74) |
May
(245) |
Jun
(356) |
Jul
(240) |
Aug
(115) |
Sep
(78) |
Oct
(225) |
Nov
(98) |
Dec
(271) |
2009 |
Jan
(132) |
Feb
(84) |
Mar
(74) |
Apr
(56) |
May
(90) |
Jun
(79) |
Jul
(83) |
Aug
(296) |
Sep
(214) |
Oct
(76) |
Nov
(82) |
Dec
(66) |
2010 |
Jan
(46) |
Feb
(58) |
Mar
(51) |
Apr
(77) |
May
(58) |
Jun
(126) |
Jul
(128) |
Aug
(64) |
Sep
(50) |
Oct
(44) |
Nov
(48) |
Dec
(54) |
2011 |
Jan
(68) |
Feb
(52) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <md...@us...> - 2007-11-08 16:26:37
|
Revision: 4161 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4161&view=rev Author: mdboom Date: 2007-11-08 08:26:31 -0800 (Thu, 08 Nov 2007) Log Message: ----------- Updating the simple_plot_fps benchmark. Modified Paths: -------------- branches/transforms/examples/simple_plot_fps.py Modified: branches/transforms/examples/simple_plot_fps.py =================================================================== --- branches/transforms/examples/simple_plot_fps.py 2007-11-08 14:31:15 UTC (rev 4160) +++ branches/transforms/examples/simple_plot_fps.py 2007-11-08 16:26:31 UTC (rev 4161) @@ -5,8 +5,7 @@ """ from pylab import * -plot([1,2]) -show() +ion() t = arange(0.0, 1.0+0.001, 0.001) s = cos(2*2*pi*t) @@ -21,14 +20,10 @@ #savefig('simple_plot') import time -from matplotlib import transforms - + frames = 100.0 -t = time.clock() -ion() +t = time.time() for i in xrange(int(frames)): - transforms.CATCH = True part = i / frames axis([0.0, 1.0 - part, -1.0 + part, 1.0 - part]) - show() -print "fps:", frames / (time.clock() - t) +print "fps:", frames / (time.time() - t) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-08 14:31:19
|
Revision: 4160 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4160&view=rev Author: mdboom Date: 2007-11-08 06:31:15 -0800 (Thu, 08 Nov 2007) Log Message: ----------- Throw in dummy characters for symbols not in the Bakoma fonts. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-11-08 14:06:25 UTC (rev 4159) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-11-08 14:31:15 UTC (rev 4160) @@ -672,6 +672,7 @@ _slanted_symbols = Set(r"\int \oint".split()) def _get_glyph(self, fontname, sym, fontsize): + symbol_name = None if fontname in self.fontmap and latex_to_bakoma.has_key(sym): basename, num = latex_to_bakoma[sym] slanted = (basename == "cmmi10") or sym in self._slanted_symbols @@ -682,11 +683,21 @@ slanted = (fontname == "it") cached_font = self._get_font(fontname) num = ord(sym) - symbol_name = cached_font.font.get_glyph_name( - cached_font.charmap[num]) - else: - raise ValueError('unrecognized symbol "%s"' % sym) + gid = cached_font.charmap.get(num) + if gid is not None: + symbol_name = cached_font.font.get_glyph_name( + cached_font.charmap[num]) + if symbol_name is None: + warn("Unrecognized symbol '%s'. Substituting with a dummy symbol." + % sym.encode('ascii', 'backslashreplace'), MathTextWarning) + fontname = 'it' + cached_font = self._get_font(fontname) + num = 0x3F # currency character, for lack of anything better + gid = cached_font.charmap[num] + symbol_name = cached_font.font.get_glyph_name(gid) + slanted = False + return cached_font, num, symbol_name, fontsize, slanted # The Bakoma fonts contain many pre-sized alternatives for the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-08 14:06:27
|
Revision: 4159 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4159&view=rev Author: mdboom Date: 2007-11-08 06:06:25 -0800 (Thu, 08 Nov 2007) Log Message: ----------- Get wxagg extension working again. Factor out the new Bbox conversion code into agg_py_transforms.h Modified Paths: -------------- branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h branches/transforms/src/_gtkagg.cpp branches/transforms/src/_tkagg.cpp branches/transforms/src/_wxagg.cpp branches/transforms/src/agg_py_transforms.h Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-08 14:05:18 UTC (rev 4158) +++ branches/transforms/src/_backend_agg.cpp 2007-11-08 14:06:25 UTC (rev 4159) @@ -273,33 +273,6 @@ }; -bool -RendererAgg::bbox_to_rect(const Py::Object& bbox_obj, double* l, double* b, double* r, double* t) { - PyArrayObject* bbox = NULL; - - if (bbox_obj.ptr() != Py_None) { - bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.ptr(), PyArray_DOUBLE, 2, 2); - - if (!bbox || PyArray_NDIM(bbox) != 2 || PyArray_DIM(bbox, 0) != 2 || PyArray_DIM(bbox, 1) != 2) { - Py_XDECREF(bbox); - throw Py::TypeError - ("Expected a Bbox object."); - } - - *l = *(double*)PyArray_GETPTR2(bbox, 0, 0); - double _b = *(double*)PyArray_GETPTR2(bbox, 0, 1); - *r = *(double*)PyArray_GETPTR2(bbox, 1, 0); - double _t = *(double*)PyArray_GETPTR2(bbox, 1, 1); - *b = height - _t; - *t = height - _b; - - Py_XDECREF(bbox); - return true; - } - - return false; -} - template<class R> void RendererAgg::set_clipbox(const Py::Object& cliprect, R rasterizer) { @@ -308,7 +281,7 @@ _VERBOSE("RendererAgg::set_clipbox"); double l, b, r, t; - if (bbox_to_rect(cliprect, &l, &b, &r, &t)) { + if (py_convert_bbox(cliprect.ptr(), l, b, r, t)) { rasterizer->clip_box((int)l, (int)b, (int)r, (int)t); } @@ -408,7 +381,7 @@ Py::Object box_obj = args[0]; double l, b, r, t; - if (!bbox_to_rect(box_obj, &l, &b, &r, &t)) + if (!py_convert_bbox(box_obj.ptr(), l, b, r, t)) throw Py::TypeError("Invalid bbox provided to copy_from_bbox"); agg::rect rect((int)l, (int)b, (int)r, (int)t); Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-11-08 14:05:18 UTC (rev 4158) +++ branches/transforms/src/_backend_agg.h 2007-11-08 14:06:25 UTC (rev 4159) @@ -215,7 +215,6 @@ double points_to_pixels_snapto( const Py::Object& points); agg::rgba rgb_to_color(const Py::SeqBase<Py::Object>& rgb, double alpha); facepair_t _get_rgba_face(const Py::Object& rgbFace, double alpha); - bool bbox_to_rect(const Py::Object& bbox, double* l, double* b, double* r, double* t); template<class R> void set_clipbox(const Py::Object& cliprect, R rasterizer); bool render_clippath(const Py::Object& clippath, const agg::trans_affine& clippath_trans); Modified: branches/transforms/src/_gtkagg.cpp =================================================================== --- branches/transforms/src/_gtkagg.cpp 2007-11-08 14:05:18 UTC (rev 4158) +++ branches/transforms/src/_gtkagg.cpp 2007-11-08 14:06:25 UTC (rev 4159) @@ -14,6 +14,7 @@ #include "_backend_agg.h" #define PY_ARRAY_TYPES_PREFIX NumPy #include "numpy/arrayobject.h" +#include "agg_py_transforms.h" // the extension module class _gtkagg_module : public Py::ExtensionModule<_gtkagg_module> @@ -71,31 +72,12 @@ else { //bbox is not None; copy the image in the bbox PyObject* clipbox = args[2].ptr(); - PyArrayObject* bbox = NULL; double l, b, r, t; - try { - bbox = (PyArrayObject*) PyArray_FromObject(clipbox, PyArray_DOUBLE, 2, 2); - - if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { - throw Py::TypeError - ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); - } - - l = *(double*)PyArray_GETPTR2(bbox, 0, 0); - b = *(double*)PyArray_GETPTR2(bbox, 0, 1); - r = *(double*)PyArray_GETPTR2(bbox, 1, 0); - t = *(double*)PyArray_GETPTR2(bbox, 1, 1); - - Py_XDECREF(bbox); - bbox = NULL; - } catch (...) { - Py_XDECREF(bbox); - bbox = NULL; - throw; + if (!py_convert_bbox(clipbox, l, b, r, t)) { + throw Py::TypeError + ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); } - //std::cout << b << " " - // << t << " "; destx = (int)l; desty = srcheight-(int)t; @@ -118,11 +100,8 @@ agg::rect_base<int> region(destx, desty, (int)r, srcheight-(int)b); destrb.copy_from(*aggRenderer->renderingBuffer, ®ion, -destx, -desty); - - } - /*std::cout << desty << " " << destheight << " " << srcheight << std::endl;*/ Modified: branches/transforms/src/_tkagg.cpp =================================================================== --- branches/transforms/src/_tkagg.cpp 2007-11-08 14:05:18 UTC (rev 4158) +++ branches/transforms/src/_tkagg.cpp 2007-11-08 14:06:25 UTC (rev 4159) @@ -14,6 +14,7 @@ #include "agg_basics.h" #include "_backend_agg.h" +#include "agg_py_transforms.h" extern "C" { #ifdef __APPLE__ @@ -85,30 +86,9 @@ /* check for bbox/blitting */ bboxo = (PyObject*)atol(argv[4]); - if (bboxo != Py_None) { + if (py_convert_bbox(bboxo, l, b, r, t)) { has_bbox = true; - PyArrayObject* bbox = NULL; - try { - bbox = (PyArrayObject*) PyArray_FromObject(bboxo, PyArray_DOUBLE, 2, 2); - - if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { - throw Py::TypeError - ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); - } - - l = *(double*)PyArray_GETPTR2(bbox, 0, 0); - b = *(double*)PyArray_GETPTR2(bbox, 0, 1); - r = *(double*)PyArray_GETPTR2(bbox, 1, 0); - t = *(double*)PyArray_GETPTR2(bbox, 1, 1); - Py_XDECREF(bbox); - bbox = NULL; - } catch (...) { - Py_XDECREF(bbox); - bbox = NULL; - throw; - } - destx = (int)l; desty = srcheight-(int)t; destwidth = (int)(r-l); Modified: branches/transforms/src/_wxagg.cpp =================================================================== --- branches/transforms/src/_wxagg.cpp 2007-11-08 14:05:18 UTC (rev 4158) +++ branches/transforms/src/_wxagg.cpp 2007-11-08 14:06:25 UTC (rev 4159) @@ -46,9 +46,9 @@ #include "agg_basics.h" #include "_backend_agg.h" -#include "_transforms.h" #include "agg_pixfmt_rgba.h" #include "util/agg_color_conv_rgb8.h" +#include "agg_py_transforms.h" #include <wx/image.h> #include <wx/bitmap.h> @@ -56,8 +56,8 @@ // forward declarations -static wxImage *convert_agg2image(RendererAgg *aggRenderer, Bbox *clipbox); -static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Bbox *clipbox); +static wxImage *convert_agg2image(RendererAgg *aggRenderer, Py::Object clipbox); +static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Py::Object clipbox); // the extension module @@ -94,9 +94,7 @@ RendererAgg* aggRenderer = static_cast<RendererAgg*>( args[0].getAttr("_renderer").ptr()); - Bbox *clipbox = NULL; - if (args[1].ptr() != Py_None) - clipbox = static_cast<Bbox*>(args[1].ptr()); + Py::Object clipbox = args[1]; // convert the buffer wxImage *image = convert_agg2image(aggRenderer, clipbox); @@ -118,9 +116,7 @@ RendererAgg* aggRenderer = static_cast<RendererAgg*>( args[0].getAttr("_renderer").ptr()); - Bbox *clipbox = NULL; - if (args[1].ptr() != Py_None) - clipbox = static_cast<Bbox*>(args[1].ptr()); + Py::Object clipbox = args[1]; // convert the buffer wxBitmap *bitmap = convert_agg2bitmap(aggRenderer, clipbox); @@ -141,7 +137,7 @@ // Implementation Functions // -static wxImage *convert_agg2image(RendererAgg *aggRenderer, Bbox *clipbox) +static wxImage *convert_agg2image(RendererAgg *aggRenderer, Py::Object clipbox) { int srcWidth = 1; int srcHeight = 1; @@ -150,7 +146,9 @@ bool deleteSrcBuffer = false; agg::int8u *srcBuffer = NULL; - if (clipbox == NULL) { + double l, b, r, t; + + if (!py_convert_bbox(clipbox.ptr(), l, b, r, t)) { // Convert everything: rgba => rgb -> image srcBuffer = aggRenderer->pixBuffer; srcWidth = (int) aggRenderer->get_width(); @@ -158,11 +156,6 @@ srcStride = (int) aggRenderer->get_width()*4; } else { // Convert a region: rgba => clipped rgba => rgb -> image - double l = clipbox->ll_api()->x_api()->val() ; - double b = clipbox->ll_api()->y_api()->val(); - double r = clipbox->ur_api()->x_api()->val() ; - double t = clipbox->ur_api()->y_api()->val() ; - srcWidth = (int) (r-l); srcHeight = (int) (t-b); srcStride = srcWidth*4; @@ -230,7 +223,7 @@ } -static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Bbox *clipbox) +static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Py::Object clipbox) { // Convert everything: rgba => rgb -> image => bitmap // Convert a region: rgba => clipped rgba => rgb -> image => bitmap Modified: branches/transforms/src/agg_py_transforms.h =================================================================== --- branches/transforms/src/agg_py_transforms.h 2007-11-08 14:05:18 UTC (rev 4158) +++ branches/transforms/src/agg_py_transforms.h 2007-11-08 14:06:25 UTC (rev 4159) @@ -7,7 +7,6 @@ #include "CXX/Objects.hxx" #include "agg_trans_affine.h" - /** A helper function to convert from a Numpy affine transformation matrix * to an agg::trans_affine. */ @@ -20,10 +19,10 @@ matrix = (PyArrayObject*) PyArray_FromObject(obj.ptr(), PyArray_DOUBLE, 2, 2); if (!matrix) throw std::exception(); - if (matrix->nd == 2 || matrix->dimensions[0] == 3 || matrix->dimensions[1] == 3) { - size_t stride0 = matrix->strides[0]; - size_t stride1 = matrix->strides[1]; - char* row0 = matrix->data; + if (PyArray_NDIM(matrix) == 2 || PyArray_DIM(matrix, 0) == 3 || PyArray_DIM(matrix, 1) == 3) { + size_t stride0 = PyArray_STRIDE(matrix, 0); + size_t stride1 = PyArray_STRIDE(matrix, 1); + char* row0 = PyArray_BYTES(matrix); char* row1 = row0 + stride0; double a = *(double*)(row0); @@ -55,4 +54,35 @@ return agg::trans_affine(); } +bool py_convert_bbox(PyObject* bbox_obj, double& l, double& b, double& r, double& t) { + PyArrayObject* bbox = NULL; + + if (bbox_obj == Py_None) + return false; + + try { + bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj, PyArray_DOUBLE, 2, 2); + + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { + throw Py::TypeError + ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); + } + + l = *(double*)PyArray_GETPTR2(bbox, 0, 0); + b = *(double*)PyArray_GETPTR2(bbox, 0, 1); + r = *(double*)PyArray_GETPTR2(bbox, 1, 0); + t = *(double*)PyArray_GETPTR2(bbox, 1, 1); + + Py_XDECREF(bbox); + bbox = NULL; + return true; + } catch (...) { + Py_XDECREF(bbox); + bbox = NULL; + throw; + } + + return false; +} + #endif // __AGG_PY_TRANSFORMS_H__ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-08 14:05:38
|
Revision: 4158 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4158&view=rev Author: mdboom Date: 2007-11-08 06:05:18 -0800 (Thu, 08 Nov 2007) Log Message: ----------- Add a background color to the axes so it's easier to tell if there is a bug in the masked values. Modified Paths: -------------- branches/transforms/examples/quadmesh_demo.py Modified: branches/transforms/examples/quadmesh_demo.py =================================================================== --- branches/transforms/examples/quadmesh_demo.py 2007-11-08 13:21:17 UTC (rev 4157) +++ branches/transforms/examples/quadmesh_demo.py 2007-11-08 14:05:18 UTC (rev 4158) @@ -7,7 +7,7 @@ """ import numpy as npy -from matplotlib.pyplot import figure, show +from matplotlib.pyplot import figure, show, savefig from matplotlib import cm, colors from matplotlib.numerix import npyma as ma @@ -26,10 +26,12 @@ fig = figure() ax = fig.add_subplot(121) +ax.set_axis_bgcolor("#bdb76b") ax.pcolormesh(Qx,Qz,Z) ax.set_title('Without masked values') ax = fig.add_subplot(122) +ax.set_axis_bgcolor("#bdb76b") # You can control the color of the masked region: #cmap = cm.jet #cmap.set_bad('r', 1.0) @@ -39,3 +41,4 @@ ax.set_title('With masked values') show() +savefig("quadmesh_demo") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-08 13:21:20
|
Revision: 4157 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4157&view=rev Author: mdboom Date: 2007-11-08 05:21:17 -0800 (Thu, 08 Nov 2007) Log Message: ----------- Small bugfix to compile on gcc 4.x (Thanks, Eric) Modified Paths: -------------- branches/transforms/src/_backend_agg.h Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-11-08 00:24:57 UTC (rev 4156) +++ branches/transforms/src/_backend_agg.h 2007-11-08 13:21:17 UTC (rev 4157) @@ -165,7 +165,7 @@ Py::Object draw_image(const Py::Tuple & args); Py::Object draw_path(const Py::Tuple & args); Py::Object draw_path_collection(const Py::Tuple & args); - Py::Object RendererAgg::draw_quad_mesh(const Py::Tuple& args); + Py::Object draw_quad_mesh(const Py::Tuple& args); Py::Object write_rgba(const Py::Tuple & args); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ds...@us...> - 2007-11-08 00:25:00
|
Revision: 4156 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4156&view=rev Author: dsdale Date: 2007-11-07 16:24:57 -0800 (Wed, 07 Nov 2007) Log Message: ----------- update enthought package to version 2.6b1, stripped of setuptools installed in site-packages, if not already present Modified Paths: -------------- trunk/matplotlib/examples/rc_traits.py trunk/matplotlib/lib/matplotlib/__init__.py trunk/matplotlib/setupext.py Added Paths: ----------- trunk/matplotlib/lib/enthought/ trunk/matplotlib/lib/enthought/__init__.py trunk/matplotlib/lib/enthought/etsconfig/ trunk/matplotlib/lib/enthought/etsconfig/__init__.py trunk/matplotlib/lib/enthought/etsconfig/api.py trunk/matplotlib/lib/enthought/etsconfig/etsconfig.py trunk/matplotlib/lib/enthought/etsconfig/tests/ trunk/matplotlib/lib/enthought/etsconfig/tests/etsconfig_test_case.py trunk/matplotlib/lib/enthought/etsconfig/version.py trunk/matplotlib/lib/enthought/traits/ trunk/matplotlib/lib/enthought/traits/MANIFEST.in trunk/matplotlib/lib/enthought/traits/README.txt trunk/matplotlib/lib/enthought/traits/__init__.py trunk/matplotlib/lib/enthought/traits/__init__.pyc trunk/matplotlib/lib/enthought/traits/api.py trunk/matplotlib/lib/enthought/traits/category.py trunk/matplotlib/lib/enthought/traits/core.py trunk/matplotlib/lib/enthought/traits/core_traits.py trunk/matplotlib/lib/enthought/traits/ctraits.c trunk/matplotlib/lib/enthought/traits/has_dynamic_views.py trunk/matplotlib/lib/enthought/traits/has_traits.py trunk/matplotlib/lib/enthought/traits/images/ trunk/matplotlib/lib/enthought/traits/images/list_editor.gif trunk/matplotlib/lib/enthought/traits/info_traits.py trunk/matplotlib/lib/enthought/traits/plugins/ trunk/matplotlib/lib/enthought/traits/plugins/enthought_traits_vet.py trunk/matplotlib/lib/enthought/traits/standard.py trunk/matplotlib/lib/enthought/traits/tests/ trunk/matplotlib/lib/enthought/traits/tests/__init__.py trunk/matplotlib/lib/enthought/traits/tests/array_test_case.py trunk/matplotlib/lib/enthought/traits/tests/category_test_case.py trunk/matplotlib/lib/enthought/traits/tests/clone_test_case.py trunk/matplotlib/lib/enthought/traits/tests/container_events_test_case.py trunk/matplotlib/lib/enthought/traits/tests/delegate_test_case.py trunk/matplotlib/lib/enthought/traits/tests/images/ trunk/matplotlib/lib/enthought/traits/tests/images/bottom_left_origin.gif trunk/matplotlib/lib/enthought/traits/tests/images/bottom_right_origin.gif trunk/matplotlib/lib/enthought/traits/tests/images/top_left_origin.gif trunk/matplotlib/lib/enthought/traits/tests/images/top_right_origin.gif trunk/matplotlib/lib/enthought/traits/tests/keyword_args_test_case.py trunk/matplotlib/lib/enthought/traits/tests/list_test_case.py trunk/matplotlib/lib/enthought/traits/tests/other.py trunk/matplotlib/lib/enthought/traits/tests/range_test_case.py trunk/matplotlib/lib/enthought/traits/tests/regression/ trunk/matplotlib/lib/enthought/traits/tests/regression/__init__.py trunk/matplotlib/lib/enthought/traits/tests/regression/pickle_validated_dict_test_case.py trunk/matplotlib/lib/enthought/traits/tests/rich_compare_test_case.py trunk/matplotlib/lib/enthought/traits/tests/simple.py trunk/matplotlib/lib/enthought/traits/tests/simple_test_case.py trunk/matplotlib/lib/enthought/traits/tests/test_copy_traits.py trunk/matplotlib/lib/enthought/traits/tests/test_copyable_trait_names.py trunk/matplotlib/lib/enthought/traits/tests/test_event_order.py trunk/matplotlib/lib/enthought/traits/tests/test_events.py trunk/matplotlib/lib/enthought/traits/tests/test_listeners.py trunk/matplotlib/lib/enthought/traits/tests/test_property_notifications.py trunk/matplotlib/lib/enthought/traits/tests/test_str_handler.py trunk/matplotlib/lib/enthought/traits/tests/test_timing.py trunk/matplotlib/lib/enthought/traits/tests/test_trait_cycle.py trunk/matplotlib/lib/enthought/traits/tests/test_traits.py trunk/matplotlib/lib/enthought/traits/tests/test_ui.py trunk/matplotlib/lib/enthought/traits/tests/test_ui3.py trunk/matplotlib/lib/enthought/traits/tests/test_ui4.py trunk/matplotlib/lib/enthought/traits/tests/test_ui5.py trunk/matplotlib/lib/enthought/traits/tests/undefined_test_case.py trunk/matplotlib/lib/enthought/traits/trait_base.py trunk/matplotlib/lib/enthought/traits/trait_db.py trunk/matplotlib/lib/enthought/traits/trait_errors.py trunk/matplotlib/lib/enthought/traits/trait_handlers.py trunk/matplotlib/lib/enthought/traits/trait_notifiers.py trunk/matplotlib/lib/enthought/traits/trait_numeric.py trunk/matplotlib/lib/enthought/traits/traits.py trunk/matplotlib/lib/enthought/traits/ui/ trunk/matplotlib/lib/enthought/traits/ui/__init__.py trunk/matplotlib/lib/enthought/traits/ui/__init__.pyc trunk/matplotlib/lib/enthought/traits/ui/api.py trunk/matplotlib/lib/enthought/traits/ui/delegating_handler.py trunk/matplotlib/lib/enthought/traits/ui/dockable_view_element.py trunk/matplotlib/lib/enthought/traits/ui/editor.py trunk/matplotlib/lib/enthought/traits/ui/editor_factory.py trunk/matplotlib/lib/enthought/traits/ui/editors.py trunk/matplotlib/lib/enthought/traits/ui/extras/ trunk/matplotlib/lib/enthought/traits/ui/extras/__init__.py trunk/matplotlib/lib/enthought/traits/ui/extras/checkbox_column.py trunk/matplotlib/lib/enthought/traits/ui/extras/core.py trunk/matplotlib/lib/enthought/traits/ui/group.py trunk/matplotlib/lib/enthought/traits/ui/handler.py trunk/matplotlib/lib/enthought/traits/ui/help.py trunk/matplotlib/lib/enthought/traits/ui/help_template.py trunk/matplotlib/lib/enthought/traits/ui/helper.py trunk/matplotlib/lib/enthought/traits/ui/images/ trunk/matplotlib/lib/enthought/traits/ui/images/array_node.png trunk/matplotlib/lib/enthought/traits/ui/images/bool_node.png trunk/matplotlib/lib/enthought/traits/ui/images/complex_node.png trunk/matplotlib/lib/enthought/traits/ui/images/dict_node.png trunk/matplotlib/lib/enthought/traits/ui/images/float_node.png trunk/matplotlib/lib/enthought/traits/ui/images/int_node.png trunk/matplotlib/lib/enthought/traits/ui/images/list_node.png trunk/matplotlib/lib/enthought/traits/ui/images/none_node.png trunk/matplotlib/lib/enthought/traits/ui/images/object_node.png trunk/matplotlib/lib/enthought/traits/ui/images/other_node.png trunk/matplotlib/lib/enthought/traits/ui/images/string_node.png trunk/matplotlib/lib/enthought/traits/ui/images/traits_node.png trunk/matplotlib/lib/enthought/traits/ui/images/tuple_node.png trunk/matplotlib/lib/enthought/traits/ui/include.py trunk/matplotlib/lib/enthought/traits/ui/instance_choice.py trunk/matplotlib/lib/enthought/traits/ui/item.py trunk/matplotlib/lib/enthought/traits/ui/key_bindings.py trunk/matplotlib/lib/enthought/traits/ui/menu.py trunk/matplotlib/lib/enthought/traits/ui/message.py trunk/matplotlib/lib/enthought/traits/ui/null/ trunk/matplotlib/lib/enthought/traits/ui/null/__init__.py trunk/matplotlib/lib/enthought/traits/ui/null/color_trait.py trunk/matplotlib/lib/enthought/traits/ui/null/font_trait.py trunk/matplotlib/lib/enthought/traits/ui/null/rgb_color_trait.py trunk/matplotlib/lib/enthought/traits/ui/null/toolkit.py trunk/matplotlib/lib/enthought/traits/ui/table_column.py trunk/matplotlib/lib/enthought/traits/ui/table_filter.py trunk/matplotlib/lib/enthought/traits/ui/tests/ trunk/matplotlib/lib/enthought/traits/ui/tests/array_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/buttons_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/check_list_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/check_list_editor_test2.py trunk/matplotlib/lib/enthought/traits/ui/tests/code_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/enum_dynamic_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/html_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_drag_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_editor_test2.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_editor_test3.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_editor_test4.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_editor_test5.py trunk/matplotlib/lib/enthought/traits/ui/tests/instance_editor_test6.py trunk/matplotlib/lib/enthought/traits/ui/tests/list_traits_ui_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/set_dynamic_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/shell_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/table_editor_color_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/table_editor_focus_bug.py trunk/matplotlib/lib/enthought/traits/ui/tests/table_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/table_editor_test2.py trunk/matplotlib/lib/enthought/traits/ui/tests/table_list_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tests/tree_editor_test.py trunk/matplotlib/lib/enthought/traits/ui/tk/ trunk/matplotlib/lib/enthought/traits/ui/tk/__init__.py trunk/matplotlib/lib/enthought/traits/ui/tk/boolean_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/button_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/check_list_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/color_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/compound_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/constants.py trunk/matplotlib/lib/enthought/traits/ui/tk/directory_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/editor_factory.py trunk/matplotlib/lib/enthought/traits/ui/tk/enum_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/file_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/font_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/helper.py trunk/matplotlib/lib/enthought/traits/ui/tk/image_control.py trunk/matplotlib/lib/enthought/traits/ui/tk/image_enum_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/instance_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/list_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/menu.py trunk/matplotlib/lib/enthought/traits/ui/tk/range_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/rgb_color_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/text_editor.py trunk/matplotlib/lib/enthought/traits/ui/tk/toolkit.py trunk/matplotlib/lib/enthought/traits/ui/tk/ui_modal.py trunk/matplotlib/lib/enthought/traits/ui/tk/ui_nonmodal.py trunk/matplotlib/lib/enthought/traits/ui/tk/ui_panel.py trunk/matplotlib/lib/enthought/traits/ui/tk/ui_wizard.py trunk/matplotlib/lib/enthought/traits/ui/tk/view_application.py trunk/matplotlib/lib/enthought/traits/ui/toolkit.py trunk/matplotlib/lib/enthought/traits/ui/traits.py trunk/matplotlib/lib/enthought/traits/ui/tree_node.py trunk/matplotlib/lib/enthought/traits/ui/tuidb.py trunk/matplotlib/lib/enthought/traits/ui/ui.py trunk/matplotlib/lib/enthought/traits/ui/ui_info.py trunk/matplotlib/lib/enthought/traits/ui/ui_traits.py trunk/matplotlib/lib/enthought/traits/ui/undo.py trunk/matplotlib/lib/enthought/traits/ui/value_tree.py trunk/matplotlib/lib/enthought/traits/ui/view.py trunk/matplotlib/lib/enthought/traits/ui/view_element.py trunk/matplotlib/lib/enthought/traits/ui/view_elements.py trunk/matplotlib/lib/enthought/traits/version.py Removed Paths: ------------- trunk/matplotlib/lib/matplotlib/enthought/ Modified: trunk/matplotlib/examples/rc_traits.py =================================================================== --- trunk/matplotlib/examples/rc_traits.py 2007-11-08 00:09:17 UTC (rev 4155) +++ trunk/matplotlib/examples/rc_traits.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -7,7 +7,7 @@ # below. import sys, os, re -import matplotlib.enthought.traits.api as traits +import enthought.traits.api as traits from matplotlib.cbook import is_string_like from matplotlib.artist import Artist Added: trunk/matplotlib/lib/enthought/__init__.py =================================================================== --- trunk/matplotlib/lib/enthought/__init__.py (rev 0) +++ trunk/matplotlib/lib/enthought/__init__.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,11 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2007 by Enthought, Inc. +# All rights reserved. +#------------------------------------------------------------------------------ + +try: + pass +except: + pass + + Added: trunk/matplotlib/lib/enthought/etsconfig/__init__.py =================================================================== Added: trunk/matplotlib/lib/enthought/etsconfig/api.py =================================================================== --- trunk/matplotlib/lib/enthought/etsconfig/api.py (rev 0) +++ trunk/matplotlib/lib/enthought/etsconfig/api.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,4 @@ +from enthought.etsconfig.version import version, version as __version__ + + +from etsconfig import ETSConfig Added: trunk/matplotlib/lib/enthought/etsconfig/etsconfig.py =================================================================== --- trunk/matplotlib/lib/enthought/etsconfig/etsconfig.py (rev 0) +++ trunk/matplotlib/lib/enthought/etsconfig/etsconfig.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,385 @@ +""" Enthought Tool Suite configuration information. """ + + +# Standard library imports. +import sys +import os +from os import path + + +class ETSConfig(object): + """ + Enthought Tool Suite configuration information. + + This class should not use ANY other package in the tool suite so that it + will always work no matter which other packages are present. + + """ + + ########################################################################### + # 'object' interface. + ########################################################################### + + #### operator methods ##################################################### + + def __init__(self): + """ + Constructor. + + Note that this constructor can only ever be called from within this + module, since we don't expose the class. + + """ + + # Shadow attributes for properties. + self._application_data = None + self._application_home = None + self._company = None + self._toolkit = None + self._user_data = None + + return + + + ########################################################################### + # 'ETSConfig' interface. + ########################################################################### + + #### properties ########################################################### + + def _get_application_data(self): + """ + Property getter. + + This is a directory that applications and packages can safely write + non-user accessible data to i.e. configuration information, preferences + etc. + + Do not put anything in here that the user might want to navigate to + e.g. projects, user data files etc. + + The actual location differs between operating systems. + + """ + + if self._application_data is None: + self._application_data = self._initialize_application_data() + + return self._application_data + + + def _set_application_data(self, application_data): + """ + Property setter. + + """ + + self._application_data = application_data + + return + + + application_data = property(_get_application_data, _set_application_data) + + + def _get_application_home(self): + """ + Property getter. + + This is a directory named after the current, running application that + imported this module that applications and packages can safely write + non-user accessible data to i.e. configuration information, preferences + etc. It is a sub-directory of self.application_data, named after the + directory that contains the "main" python script that started the + process. For example, if application foo is started with a script named + "run.py" in a directory named "foo", then the application home would be: + <ETSConfig.application_data>/foo, regardless of if it was launched + with "python <path_to_foo>/run.py" or "cd <path_to_foo>; python run.py" + + This is useful for library modules used in apps that need to store + state, preferences, etc. for the specific app only, and not for all apps + which use that library module. If the library module uses + ETSConfig.application_home, they can store prefs for the app all in + one place and do not need to know the details of where each app might + reside. + + Do not put anything in here that the user might want to navigate to + e.g. projects, user home files etc. + + The actual location differs between operating systems. + + """ + + if self._application_home is None: + self._application_home = path.join(self.application_data, + self._get_application_dirname()) + + return self._application_home + + + def _set_application_home(self, application_home): + """ + Property setter. + + """ + + self._application_home = application_home + + return + + + application_home = property(_get_application_home, _set_application_home) + + + def _get_company(self): + """ + Property getter. + + """ + + if self._company is None: + self._company = self._initialize_company() + + return self._company + + + def _set_company(self, company): + """ + Property setter for the company name. + + """ + + self._company = company + + return + + + company = property(_get_company, _set_company) + + + def _get_toolkit(self): + """ + Property getter for the GUI toolkit. The value returned is, in order + of preference: the value set by the application; the value passed on + the command line using the '-toolkit' option; the value specified by + the 'ETS_TOOLKIT' environment variable; otherwise the empty string. + + """ + + if self._toolkit is None: + self._toolkit = self._initialize_toolkit() + + return self._toolkit + + + def _set_toolkit(self, toolkit): + """ + Property setter for the GUI toolkit. The toolkit can be set more than + once, but only if it is the same one each time. An application that is + written for a particular toolkit can explicitly set it before any other + module that gets the value is imported. + + """ + + if self._toolkit and self._toolkit != toolkit: + raise ValueError, "cannot set toolkit to %s because it has already been set to %s" % (toolkit, self._toolkit) + + self._toolkit = toolkit + + return + + + toolkit = property(_get_toolkit, _set_toolkit) + + + def _get_user_data(self): + """ + Property getter. + + This is a directory that users can safely write user accessible data + to i.e. user-defined functions, edited functions, etc. + + The actual location differs between operating systems. + + """ + + if self._user_data is None: + self._user_data = self._initialize_user_data() + + return self._user_data + + + def _set_user_data(self, user_data): + """ + Property setter. + + """ + + self._user_data = user_data + + return + + + user_data = property(_get_user_data, _set_user_data) + + + #### private methods ##################################################### + + # fixme: In future, these methods could allow the properties to be set + # via the (as yet non-existent) preference/configuration mechanism. This + # would allow configuration via (in order of precedence):- + # + # - a configuration file + # - environment variables + # - the command line + + def _get_application_dirname(self): + """ + Return the name of the directory (not a path) that the "main" + Python script which started this process resides in, or "" if it could + not be determined or is not appropriate. + + For example, if the script that started the current process was named + "run.py" in a directory named "foo", and was launched with "python + run.py", the name "foo" would be returned (this assumes the directory + name is the name of the app, which seems to be as good of an assumption + as any). + + """ + + dirname = "" + + main_mod = sys.modules.get('__main__', None) + if main_mod is not None: + if hasattr(main_mod, '__file__'): + main_mod_file = path.abspath(main_mod.__file__) + dirname = path.basename(path.dirname(main_mod_file)) + + return dirname + + + def _initialize_application_data(self): + """ + Initializes the (default) application data directory. + + """ + + if sys.platform == 'win32': + environment_variable = 'APPDATA' + directory_name = self.company + + else: + environment_variable = 'HOME' + directory_name = '.' + self.company.lower() + + # Lookup the environment variable. + parent_directory = os.environ.get(environment_variable, None) + if parent_directory is None: + raise ValueError( + 'Environment variable "%s" not set' % environment_variable + ) + + application_data = os.path.join(parent_directory, directory_name) + + # If a file already exists with this name then make sure that it is + # a directory! + if os.path.exists(application_data): + if not os.path.isdir(application_data): + raise ValueError('File "%s" already exists' % application_data) + + # Otherwise, create the directory. + else: + os.makedirs(application_data) + + return application_data + + + def _initialize_company(self): + """ + Initializes the (default) company. + + """ + + return 'Enthought' + + + def _initialize_toolkit(self): + """ + Initializes the toolkit. + + """ + + # We handle the command line option even though it doesn't have the + # highest precedence because we always want to remove it from the + # command line. + if '-toolkit' in sys.argv: + opt_idx = sys.argv.index('-toolkit') + + try: + opt_toolkit = sys.argv[opt_idx + 1] + except IndexError: + raise ValueError, "the -toolkit command line argument must be followed by a toolkit name" + + # Remove the option. + del sys.argv[opt_idx:opt_idx + 1] + else: + opt_toolkit = None + + if self._toolkit is not None: + toolkit = self._toolkit + elif opt_toolkit is not None: + toolkit = opt_toolkit + else: + toolkit = os.environ.get('ETS_TOOLKIT', '') + + return toolkit + + + def _initialize_user_data(self): + """ + Initializes the (default) user data directory. + + """ + + # We check what the os.path.expanduser returns + parent_directory = os.path.expanduser('~') + directory_name = self.company + + + if sys.platform == 'win32': + # Check if the usr_dir is C:\\John Doe\\Documents and Settings. + # If yes, then we should modify the usr_dir to be 'My Documents'. + # If no, then the user must have modified the os.environ + # variables and the directory chosen is a desirable one. + desired_dir = os.path.join(parent_directory, 'My Documents') + + if os.path.exists(desired_dir): + parent_directory = desired_dir + + else: + directory_name = directory_name.lower() + + # The final directory. + usr_dir = os.path.join(parent_directory, directory_name) + + # If a file already exists with this name then make sure that it is + # a directory! + if os.path.exists(usr_dir): + if not os.path.isdir(usr_dir): + raise ValueError('File "%s" already exists' % usr_dir) + + # Otherwise, create the directory. + else: + os.makedirs(usr_dir) + + return usr_dir + + + +# We very purposefully only have one object and do not export the class. We +# could have just made everything class methods, but that always seems a bit +# gorpy, especially with properties etc. +ETSConfig = ETSConfig() + + +#### EOF ###################################################################### Added: trunk/matplotlib/lib/enthought/etsconfig/tests/etsconfig_test_case.py =================================================================== --- trunk/matplotlib/lib/enthought/etsconfig/tests/etsconfig_test_case.py (rev 0) +++ trunk/matplotlib/lib/enthought/etsconfig/tests/etsconfig_test_case.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,241 @@ +""" Tests the 'ETSConfig' configuration object. """ + + +# Standard library imports. +import os, time, unittest + +# Enthought library imports. +from enthought.etsconfig.api import ETSConfig + + +class ETSConfigTestCase(unittest.TestCase): + """ Tests the 'ETSConfig' configuration object. """ + + ########################################################################### + # 'TestCase' interface. + ########################################################################### + + #### public methods ####################################################### + + def setUp(self): + """ + Prepares the test fixture before each test method is called. + + """ + + return + + def tearDown(self): + """ + Called immediately after each test method has been called. + + """ + + return + + + ########################################################################### + # 'ETSConfigTestCase' interface. + ########################################################################### + + #### public methods ####################################################### + + def test_application_data(self): + """ + application data + + """ + + dirname = ETSConfig.application_data + + self.assertEqual(os.path.exists(dirname), True) + self.assertEqual(os.path.isdir(dirname), True) + + return + + def test_set_application_data(self): + """ + set application data + + """ + + old = ETSConfig.application_data + + ETSConfig.application_data = 'foo' + self.assertEqual('foo', ETSConfig.application_data) + + ETSConfig.application_data = old + self.assertEqual(old, ETSConfig.application_data) + + return + + + def test_application_data_is_idempotent(self): + """ + application data is idempotent + + """ + + # Just do the previous test again! + self.test_application_data() + + return + + + def test_write_to_application_data_directory(self): + """ + write to application data directory + + """ + + ETSConfig.company = 'Blah' + dirname = ETSConfig.application_data + + path = os.path.join(dirname, 'dummy.txt') + data = str(time.time()) + + f = file(path, 'w') + f.write(data) + f.close() + + self.assertEqual(os.path.exists(path), True) + + f = file(path) + result = f.read() + f.close() + + os.remove(path) + + self.assertEqual(data, result) + + return + + + def test_default_company(self): + """ + default company + + """ + + self.assertEqual(ETSConfig.company, 'Enthought') + + return + + + def test_set_company(self): + """ + set company + + """ + + old = ETSConfig.company + + ETSConfig.company = 'foo' + self.assertEqual('foo', ETSConfig.company) + + ETSConfig.company = old + self.assertEqual(old, ETSConfig.company) + + return + + + def _test_default_application_home(self): + """ + application home + + """ + + # This test is only valid when run with the 'main' at the end of this + # file: "python app_dat_locator_test_case.py", in which case the + # app_name will be the directory this file is in ('tests'). + app_home = ETSConfig.application_home + (dirname, app_name) = os.path.split(app_home) + + self.assertEqual(dirname, ETSConfig.application_data) + self.assertEqual(app_name, 'tests') + + + def test_user_data(self): + """ + user data + + """ + + dirname = ETSConfig.user_data + + self.assertEqual(os.path.exists(dirname), True) + self.assertEqual(os.path.isdir(dirname), True) + + return + + + def test_set_user_data(self): + """ + set user data + + """ + + old = ETSConfig.user_data + + ETSConfig.user_data = 'foo' + self.assertEqual('foo', ETSConfig.user_data) + + ETSConfig.user_data = old + self.assertEqual(old, ETSConfig.user_data) + + return + + + def test_user_data_is_idempotent(self): + """ + user data is idempotent + + """ + + # Just do the previous test again! + self.test_user_data() + + return + + + def test_write_to_user_data_directory(self): + """ + write to user data directory + + """ + + ETSConfig.company = 'Blah' + dirname = ETSConfig.user_data + + path = os.path.join(dirname, 'dummy.txt') + data = str(time.time()) + + f = file(path, 'w') + f.write(data) + f.close() + + self.assertEqual(os.path.exists(path), True) + + f = file(path) + result = f.read() + f.close() + + os.remove(path) + + self.assertEqual(data, result) + + return + + +# For running as an individual set of tests. +if __name__ == '__main__': + + # Add the non-default test of application_home...non-default because it must + # be run using this module as a script to be valid. + suite = unittest.TestLoader().loadTestsFromTestCase(ETSConfigTestCase) + suite.addTest(ETSConfigTestCase('_test_default_application_home')) + + unittest.TextTestRunner(verbosity=2).run(suite) + + +#### EOF ###################################################################### Added: trunk/matplotlib/lib/enthought/etsconfig/version.py =================================================================== --- trunk/matplotlib/lib/enthought/etsconfig/version.py (rev 0) +++ trunk/matplotlib/lib/enthought/etsconfig/version.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,10 @@ +# Wrapped in a try/except in those situations where someone hasn't installed +# as an egg. What do we do then? For now, we just punt since we don't want +# to define the version number in two places. +#try: +# import pkg_resources +# version = pkg_resources.require('enthought.etsconfig')[0].version +#except: +# version = '' +version = '2.6b1-mpl' + Added: trunk/matplotlib/lib/enthought/traits/MANIFEST.in =================================================================== --- trunk/matplotlib/lib/enthought/traits/MANIFEST.in (rev 0) +++ trunk/matplotlib/lib/enthought/traits/MANIFEST.in 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1 @@ +exclude *_test*.py Added: trunk/matplotlib/lib/enthought/traits/README.txt =================================================================== --- trunk/matplotlib/lib/enthought/traits/README.txt (rev 0) +++ trunk/matplotlib/lib/enthought/traits/README.txt 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,67 @@ +Introduction +------------ + +'Traits' is a Python package for creating 'manifestly'-typed Python attributes. + +Installation +------------ + +The Traits package is installed using the standard Python 'distutils' package. + +Enter the following command in the 'traits-1.0' directory: + + python setup.py install + +This will perform a normal install of the Traits package into your Python +installation. Refer to the Python 'distutils' documentation for more +installation options. + +Download +-------- + +The Traits package is available as part of the Enthought Tool Suite (ETS), +available from: + + http://code.enthought.com/ets/ + +To install ETS using Enthought's egg-based 'Enstaller', download and run: + + http://code.enthought.com/enstaller/run_enstaller.py + +License +------- + +The 'traits' package is available under a BSD style license. + +Contact +------- + +If you encounter any problems using the 'traits' package, or have any comments +or suggestions about the package, please contact the author: + + David C. Morrill + dmo...@en... + +For discussion of the Traits package, as well as other tools in the Enthought +Tool Suite, use the enthought-dev mailing list: + + https://mail.enthought.com/mailman/listinfo/enthought-dev + + http://dir.gmane.org/gmane.comp.python.enthought.devel + +Prerequisites +------------- + +The base Traits package should work on any platform supporting Python >= 1.5.2. + +The user interface capabilities of the traits package require additional +Python packages to be installed. + +The UI toolkit backend that is actively maintained is wxPython. To use it, +install a version >= 2.3.3.1 (available from: http://www.wxpython.org). + +A UI toolkit backend for Tkinter exists, but is not actively maintained or +tested. If you wish to try Traits with Tkinter, you must also install: + + - Tkinter (usually installed as part of your Python distribution) + - PMW (Python MegaWidgets) (available from: http://pmw.sourceforge.net) Added: trunk/matplotlib/lib/enthought/traits/__init__.py =================================================================== --- trunk/matplotlib/lib/enthought/traits/__init__.py (rev 0) +++ trunk/matplotlib/lib/enthought/traits/__init__.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,26 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: David C. Morrill +# Date: 06/21/2002 +# Description: Define a 'traits' package that allows other classes to easily +# define 'type-checked' and/or 'delegated' traits for their +# instances. +# +# Note: A 'trait' is similar to a 'property', but is used instead +# of the word 'property' to differentiate it from the Python +# language 'property' feature. +#------------------------------------------------------------------------------ + +try: + # if the code is ran from an egg, the namespace must be declared + pass +except: + pass Added: trunk/matplotlib/lib/enthought/traits/__init__.pyc =================================================================== (Binary files differ) Property changes on: trunk/matplotlib/lib/enthought/traits/__init__.pyc ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/matplotlib/lib/enthought/traits/api.py =================================================================== --- trunk/matplotlib/lib/enthought/traits/api.py (rev 0) +++ trunk/matplotlib/lib/enthought/traits/api.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,159 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# Written by: David C. Morrill +# +# Date: 12/06/2005 +# +#------------------------------------------------------------------------------ + + +""" Pseudo-package for all of the core symbols from Traits and TraitsUI. +Use this module for importing Traits names into your namespace. For example:: + + from enthought.traits.api import HasTraits + +""" + +from enthought.traits.version import version, version as __version__ + + +from info_traits \ + import __doc__ + +from trait_base \ + import Undefined, Missing, Self + +from trait_errors \ + import TraitError, TraitNotificationError, DelegationError + +from trait_notifiers \ + import push_exception_handler, pop_exception_handler, \ + TraitChangeNotifyWrapper + +from category \ + import Category + +from trait_db \ + import tdb + +from traits \ + import Event, List, Dict, Tuple, Range, Constant, CTrait, Trait, Delegate, \ + Property, Expression, Button, ToolbarButton, PythonValue, Any, Int, \ + Long, Float, Str, Unicode, Complex, Bool, CInt, CLong, CFloat, \ + CStr, CUnicode, WeakRef + +from traits \ + import CComplex, CBool, false, true, Regex, String, Password, File, \ + Directory, Function, Method, Class, Instance, Module, Type, This, \ + self, Either, Python, Disallow, ReadOnly, undefined, missing, ListInt + +from traits \ + import ListFloat, ListStr, ListUnicode, ListComplex, ListBool, \ + ListFunction, ListMethod, ListClass, ListInstance, ListThis, \ + DictStrAny, DictStrStr, DictStrInt, DictStrLong, DictStrFloat + +from traits \ + import DictStrBool, DictStrList, TraitFactory, Callable, Array, CArray, \ + Enum, Code, HTML, Default, Color, RGBColor, Font + +from has_traits \ + import method, HasTraits, HasStrictTraits, HasPrivateTraits, \ + SingletonHasTraits, SingletonHasStrictTraits, \ + SingletonHasPrivateTraits, MetaHasTraits, Vetoable, VetoableEvent, \ + traits_super + +from trait_handlers \ + import TraitHandler, TraitRange, TraitString, TraitType, TraitCastType, \ + TraitInstance, ThisClass, TraitClass, TraitFunction, TraitEnum, \ + TraitPrefixList, TraitMap, TraitPrefixMap, TraitCompound, \ + TraitList, TraitListEvent, TraitDict, TraitDictEvent, TraitTuple + +from traits \ + import UIDebugger + +################### +# ui imports +if False: + + from ui.handler \ + import Handler, ViewHandler, default_handler + + from ui.view \ + import View + + from ui.group \ + import Group, HGroup, VGroup, VGrid, HFlow, VFlow, HSplit, VSplit, Tabbed + + from ui.ui \ + import UI + + from ui.ui_info \ + import UIInfo + + from ui.help \ + import on_help_call + + from ui.include \ + import Include + + from ui.item \ + import Item, Label, Heading, Spring, spring + + from ui.editor_factory \ + import EditorFactory + + from ui.editor \ + import Editor + + from ui.toolkit \ + import toolkit + + from ui.undo \ + import UndoHistory, AbstractUndoItem, UndoItem, ListUndoItem, \ + UndoHistoryUndoItem + + from ui.view_element \ + import ViewElement, ViewSubElement + + from ui.help_template \ + import help_template + + from ui.message \ + import message, error + + from ui.tree_node \ + import TreeNode, ObjectTreeNode, TreeNodeObject, MultiTreeNode + + from ui.editors \ + import ArrayEditor, BooleanEditor, ButtonEditor, CheckListEditor, \ + CodeEditor, ColorEditor, RGBColorEditor, \ + CompoundEditor, DirectoryEditor, EnumEditor, FileEditor, \ + FontEditor, ImageEnumEditor, InstanceEditor, \ + ListEditor, RangeEditor, TextEditor, TreeEditor, \ + TableEditor, TupleEditor, DropEditor, DNDEditor, CustomEditor + + from ui.editors \ + import ColorTrait, RGBColorTrait, \ + FontTrait, SetEditor, HTMLEditor, KeyBindingEditor, \ + ShellEditor, TitleEditor, ValueEditor, NullEditor + + +import ui.view_elements + +#------------------------------------------------------------------------------- +# Patch the main traits module with the correct definition for the ViewElements +# class: +#------------------------------------------------------------------------------- + +import has_traits as has_traits +has_traits.ViewElements = ui.view_elements.ViewElements + +#------------------------------------------------------------------------------- +# Patch the main traits module with the correct definition for the ViewElement +# and ViewSubElement class: +#------------------------------------------------------------------------------- + +has_traits.ViewElement = ui.view_element.ViewElement Added: trunk/matplotlib/lib/enthought/traits/category.py =================================================================== --- trunk/matplotlib/lib/enthought/traits/category.py (rev 0) +++ trunk/matplotlib/lib/enthought/traits/category.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,105 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: David C. Morrill +# Date: 11/06/2004 +#------------------------------------------------------------------------------ +""" Adds a "category" capability to Traits-based classes, +similar to that provided by the Cocoa (Objective-C) environment for the +Macintosh. + +You can use categories to extend an existing HasTraits class, as an alternative +to subclassing. An advantage of categories over subclassing is that you can +access the added members on instances of the original class, without having to +change them to instances of a subclass. Unlike subclassing, categories do not +allow overriding trait attributes. +""" +#------------------------------------------------------------------------------- +# Imports: +#------------------------------------------------------------------------------- + +from has_traits \ + import MetaHasTraits, MetaHasTraitsObject, BaseTraits, ClassTraits, \ + PrefixTraits, ViewTraits + +#------------------------------------------------------------------------------- +# 'MetaCategory' class: +#------------------------------------------------------------------------------- + +class MetaCategory ( MetaHasTraits ): + + def __new__ ( cls, class_name, bases, class_dict ): + + # Make sure the correct usage is being applied: + if len( bases ) > 2: + raise TypeError, \ + "Correct usage is: class FooCategory(Category,Foo):" + + # Process any traits-related information in the class dictionary: + MetaCategoryObject( cls, class_name, bases, class_dict, True ) + + # Move all remaining items in our class dictionary to the base class's + # dictionary: + if len( bases ) == 2: + category_class = bases[1] + for name, value in class_dict.items(): + if not hasattr( category_class, name ): + setattr( category_class, name, value ) + del class_dict[ name ] + + # Finish building the class using the updated class dictionary: + return type.__new__( cls, class_name, bases, class_dict ) + +#------------------------------------------------------------------------------- +# 'MetaCategoryObject' class: +#------------------------------------------------------------------------------- + +class MetaCategoryObject ( MetaHasTraitsObject ): + + #--------------------------------------------------------------------------- + # Adds the traits meta-data to the class: + #--------------------------------------------------------------------------- + + def add_traits_meta_data ( self, bases, class_dict, base_traits, + class_traits, instance_traits, prefix_traits, + view_elements ): + if len( bases ) == 2: + # Update the class and each of the existing subclasses: + bases[1]._add_trait_category( base_traits, class_traits, + instance_traits, prefix_traits, view_elements ) + else: + MetaHasTraitsObject.add_traits_meta_data( self, bases, + class_dict, base_traits, class_traits, instance_traits, + prefix_traits, view_elements ) + +#------------------------------------------------------------------------------- +# 'Category' class: +#------------------------------------------------------------------------------- + +class Category ( object ): + """ Used for defining "category" extensions to existing classes. + + To define a class as a category, specify "Category," followed by the name + of the base class name in the base class list. + + The following example demonstrates defining a category:: + + from enthought.traits.api import HasTraits, Str, Category + + class Base(HasTraits): + x = Str("Base x") + y = Str("Base y") + + class BaseExtra(Category, Base): + z = Str("BaseExtra z") + """ + + __metaclass__ = MetaCategory + Added: trunk/matplotlib/lib/enthought/traits/core.py =================================================================== --- trunk/matplotlib/lib/enthought/traits/core.py (rev 0) +++ trunk/matplotlib/lib/enthought/traits/core.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,20 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# Written by: David C. Morrill +# +# Date: 12/06/2005 +# +#------------------------------------------------------------------------------ +""" Pseudo-package for all of the core symbols from Traits and TraitsUI. +""" +from enthought.traits.api \ + import * + +try: + from enthought.traits.ui.api \ + import * +except: + pass Added: trunk/matplotlib/lib/enthought/traits/core_traits.py =================================================================== --- trunk/matplotlib/lib/enthought/traits/core_traits.py (rev 0) +++ trunk/matplotlib/lib/enthought/traits/core_traits.py 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,84 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2005, Enthought, Inc. +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in enthought/LICENSE.txt and may be redistributed only +# under the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# Thanks for using Enthought open source! +# +# Author: David C. Morrill +# Date: 11/26/2004 +# ------------------------------------------------------------------------------ +""" Adds all of the core traits to the Traits database. +""" +if __name__ == '__main__': + + from enthought.traits.api import Event, List, Dict, Any, Int, Long, Float, Str + from enthought.traits.api import Unicode, Complex, Bool, CInt, CLong, CFloat + from enthought.traits.api import CStr, CUnicode, CComplex, CBool, false, true + from enthought.traits.api import String, Password, File, Directory, Function + from enthought.traits.api import Method, Class, Module, Type, This, self, Python + from enthought.traits.api import ReadOnly, ListInt, ListFloat, ListStr + from enthought.traits.api import ListUnicode, ListComplex, ListBool + from enthought.traits.api import ListFunction, ListMethod, ListClass + from enthought.traits.api import ListInstance, ListThis, DictStrAny, DictStrStr + from enthought.traits.api import DictStrInt, DictStrLong, DictStrFloat + from enthought.traits.api import DictStrBool,DictStrList + from enthought.traits.api import tdb + + define = tdb.define + define( 'Event', Event ) + define( 'List', List ) + define( 'Dict', Dict ) + define( 'Any', Any ) + define( 'Int', Int ) + define( 'Long', Long ) + define( 'Float', Float ) + define( 'Str', Str ) + define( 'Unicode', Unicode ) + define( 'Complex', Complex ) + define( 'Bool', Bool ) + define( 'CInt', CInt ) + define( 'CLong', CLong ) + define( 'CFloat', CFloat ) + define( 'CStr', CStr ) + define( 'CUnicode', CUnicode ) + define( 'CComplex', CComplex ) + define( 'CBool', CBool ) + define( 'false', false ) + define( 'true', true ) + define( 'String', String ) + define( 'Password', Password ) + define( 'File', File ) + define( 'Directory', Directory ) +# define( 'Function', Function ) +# define( 'Method', Method ) +# define( 'Class', Class ) +# define( 'Module', Module ) + define( 'Type', Type ) + define( 'This', This ) +# define( 'self', self ) + define( 'Python', Python ) +## define( 'ReadOnly', ReadOnly ) <-- 'Undefined' doesn't have right + # semantics when persisted + define( 'ListInt', ListInt ) + define( 'ListFloat', ListFloat ) + define( 'ListStr', ListStr ) + define( 'ListUnicode', ListUnicode ) + define( 'ListComplex', ListComplex ) + define( 'ListBool', ListBool ) +# define( 'ListFunction', ListFunction ) +# define( 'ListMethod', ListMethod ) +# define( 'ListClass', ListClass ) +# define( 'ListInstance', ListInstance ) + define( 'ListThis', ListThis ) + define( 'DictStrAny', DictStrAny ) + define( 'DictStrStr', DictStrStr ) + define( 'DictStrInt', DictStrInt ) + define( 'DictStrLong', DictStrLong ) + define( 'DictStrFloat', DictStrFloat ) + define( 'DictStrBool', DictStrBool ) + define( 'DictStrList', DictStrList ) + Added: trunk/matplotlib/lib/enthought/traits/ctraits.c =================================================================== --- trunk/matplotlib/lib/enthought/traits/ctraits.c (rev 0) +++ trunk/matplotlib/lib/enthought/traits/ctraits.c 2007-11-08 00:24:57 UTC (rev 4156) @@ -0,0 +1,4518 @@ +/****************************************************************************** +* Copyright (c) 2005, Enthought, Inc. +* All rights reserved. +* +* This software is provided without warranty under the terms of the BSD +* license included in enthought/LICENSE.txt and may be redistributed only +* under the conditions described in the aforementioned license. The license +* is also available online at http://www.enthought.com/licenses/BSD.txt +* Thanks for using Enthought open source! +* +* Author: David C. Morrill +* Date: 06/15/2004 +* Description: C based implementation of the Traits package +******************************************************************************/ + +/*----------------------------------------------------------------------------- +| Includes: ++----------------------------------------------------------------------------*/ + +#include "Python.h" +#include "structmember.h" + +/*----------------------------------------------------------------------------- +| Constants: ++----------------------------------------------------------------------------*/ + +static PyObject * class_traits; /* == "__class_traits__" */ +static PyObject * editor_property; /* == "editor" */ +static PyObject * class_prefix; /* == "__prefix__" */ +static PyObject * empty_tuple; /* == () */ +static PyObject * undefined; /* Global 'undefined' value */ +static PyObject * TraitError; /* TraitError exception */ +static PyObject * DelegationError; /* DelegationError exception */ +static PyObject * TraitListObject; /* TraitListObject class */ +static PyObject * TraitDictObject; /* TraitDictObject class */ +static PyTypeObject * ctrait_type; /* Python-level CTrait type reference */ +static PyObject * is_callable; /* Marker for 'callable' value */ +static PyObject * _HasTraits_monitors; /* Object creation monitors. */ + +/*----------------------------------------------------------------------------- +| Macro definitions: ++----------------------------------------------------------------------------*/ + +/* The following macro is automatically defined in Python 2.4 and later: */ +#ifndef Py_VISIT +#define Py_VISIT(op) \ +do { \ + if (op) { \ + int vret = visit((PyObject *)(op), arg); \ + if (vret) return vret; \ + } \ +} while (0) +#endif + +/* The following macro is automatically defined in Python 2.4 and later: */ +#ifndef Py_CLEAR +#define Py_CLEAR(op) \ +do { \ + if (op) { \ + PyObject *tmp = (PyObject *)(op); \ + (op) = NULL; \ + Py_DECREF(tmp); \ + } \ +} while (0) +#endif + +#define DEFERRED_ADDRESS(ADDR) 0 +#define PyTrait_CheckExact(op) ((op)->ob_type == ctrait_type) + +#define PyHasTraits_Check(op) PyObject_TypeCheck(op, &has_traits_type) +#define PyHasTraits_CheckExact(op) ((op)->ob_type == &has_traits_type) + +/* Trait method related: */ + +#define TP_DESCR_GET(t) \ + (PyType_HasFeature(t, Py_TPFLAGS_HAVE_CLASS) ? (t)->tp_descr_get : NULL) +#define OFF(x) offsetof(trait_method_object, x) + +/* Field accessors: */ +#define trait_method_GET_NAME(meth) \ + (((trait_method_object *) meth)->tm_name) +#define trait_method_GET_FUNCTION(meth) \ + (((trait_method_object *) meth)->tm_func) +#define trait_method_GET_SELF(meth) \ + (((trait_method_object *) meth)->tm_self) +#define trait_method_GET_TRAITS(meth) \ + (((trait_method_object *) meth)->tm_traits) +#define trait_method_GET_CLASS(meth) \ + (((trait_method_object *) meth)->tm_class) + +/* Python version dependent macros: */ +#if ( (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 3) ) +#define PyMODINIT_FUNC void +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif +#endif +#if (PY_VERSION_HEX < 0x02050000) +typedef int Py_ssize_t; +#endif + +/*----------------------------------------------------------------------------- +| Forward declarations: ++----------------------------------------------------------------------------*/ + +static PyTypeObject trait_type; +static PyTypeObject trait_method_type; + +/*----------------------------------------------------------------------------- +| 'ctraits' module doc string: ++----------------------------------------------------------------------------*/ + +PyDoc_STRVAR( ctraits__doc__, +"The ctraits module defines the CHasTraits and CTrait C extension types that\n" +"define the core performance oriented portions of the Traits package." ); + +/*----------------------------------------------------------------------------- +| HasTraits behavior modification flags: ++----------------------------------------------------------------------------*/ + +/* Object has been initialized: */ +#define HASTRAITS_INITED 0x00000001 + +/* Do not send notifications when a trait changes value: */ +#define HASTRAITS_NO_NOTIFY 0x00000002 + +/* Requests that no event notifications be sent when this object is assigned to + a trait: */ +#define HASTRAITS_VETO_NOTIFY 0x00000004 + +/*----------------------------------------------------------------------------- +| 'CHasTraits' instance definition: +| +| Note: traits are normally stored in the type's dictionary, but are added to +| the instance's traits dictionary 'trait_dict' when the traits are defined +| dynamically or 'on_trait_change' is called on an instance of the trait. +| +| All 'anytrait_changed' notification handlers are stored in the instance's +| 'notifiers' list. ++----------------------------------------------------------------------------*/ + +typedef struct { + PyObject_HEAD /* Standard Python object header */ + PyDictObject * ctrait_dict; /* Class traits dictionary */ + PyDictObject * itrait_dict; /* Instance traits dictionary */ + PyListObject * notifiers; /* List of 'any trait changed' notification + handlers */ + int flags; /* Behavior modification flags */ + PyObject * obj_dict; /* Object attribute dictionary ('__dict__') */ + /* NOTE: 'obj_dict' field MUST be last field */ +} has_traits_object; + +static int call_notifiers ( PyListObject *, PyListObject *, + has_traits_object *, PyObject *, PyObject *, + PyObject * new_value ); + +/*----------------------------------------------------------------------------- +| 'CTrait' flag values: ++----------------------------------------------------------------------------*/ + +/* The trait is a Property: */ +#define TRAIT_PROPERTY 0x00000001 + +/* Should the delegate be modified (or the original object)? */ +#define TRAIT_MODIFY_DELEGATE 0x00000002 + +/* Should a simple object identity test be performed (or a rich compare)? */ +#define TRAIT_OBJECT_IDENTITY 0x00000004 + +/*----------------------------------------------------------------------------- +| 'CTrait' instance definition: ++----------------------------------------------------------------------------*/ + +typedef struct _trait_object a_trait_object; +typedef PyObject * (*trait_getattr)( a_trait_object *, has_traits_object *, + PyObject * ); +typedef int (*trait_setattr)( a_trait_object *, a_trait_object *, + has_traits_object *, PyObject *, PyObject * ); +typedef int (*trait_post_setattr)( a_trait_object *, has_traits_object *, + PyObject *, PyObject * ); +typedef PyObject * (*trait_validate)( a_trait_object *, has_traits_object *, + PyObject *, PyObject * ); +typedef PyObject * (*delegate_attr_name_func)( a_trait_object *, + has_traits_object *, PyObject * ); + +typedef struct _trait_object { + PyObject_HEAD /* Standard Python object header */ + int flags; /* Flag bits */ + trait_getattr getattr; /* Get trait value handler */ + trait_setattr setattr; /* Set trait value handler */ + trait_post_setattr post_setattr; /* Optional post 'setattr' handler */ + PyObject * py_post_setattr; /* Python-based post 'setattr' hndlr */ + trait_validate validate; /* Validate trait value handler */ + P... [truncated message content] |
From: <ds...@us...> - 2007-11-08 00:09:21
|
Revision: 4155 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4155&view=rev Author: dsdale Date: 2007-11-07 16:09:17 -0800 (Wed, 07 Nov 2007) Log Message: ----------- move configobj.py to lib/, install in site-packages only if required Modified Paths: -------------- trunk/matplotlib/examples/rc_traits.py trunk/matplotlib/lib/matplotlib/__init__.py trunk/matplotlib/setup.py trunk/matplotlib/setupext.py Added Paths: ----------- trunk/matplotlib/lib/configobj.py Removed Paths: ------------- trunk/matplotlib/lib/matplotlib/config/configobj.py Modified: trunk/matplotlib/examples/rc_traits.py =================================================================== --- trunk/matplotlib/examples/rc_traits.py 2007-11-07 21:20:45 UTC (rev 4154) +++ trunk/matplotlib/examples/rc_traits.py 2007-11-08 00:09:17 UTC (rev 4155) @@ -7,7 +7,7 @@ # below. import sys, os, re -import matplotlib.enthought.traits as traits +import matplotlib.enthought.traits.api as traits from matplotlib.cbook import is_string_like from matplotlib.artist import Artist Added: trunk/matplotlib/lib/configobj.py =================================================================== --- trunk/matplotlib/lib/configobj.py (rev 0) +++ trunk/matplotlib/lib/configobj.py 2007-11-08 00:09:17 UTC (rev 4155) @@ -0,0 +1,2279 @@ +# configobj.py +# A config file reader/writer that supports nested sections in config files. +# Copyright (C) 2005-2006 Michael Foord, Nicola Larosa +# E-mail: fuzzyman AT voidspace DOT org DOT uk +# nico AT tekNico DOT net + +# ConfigObj 4 +# http://www.voidspace.org.uk/python/configobj.html + +# Released subject to the BSD License +# Please see http://www.voidspace.org.uk/python/license.shtml + +# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml +# For information about bugfixes, updates and support, please join the +# ConfigObj mailing list: +# http://lists.sourceforge.net/lists/listinfo/configobj-develop +# Comments, suggestions and bug reports welcome. + +from __future__ import generators + +import sys +INTP_VER = sys.version_info[:2] +if INTP_VER < (2, 2): + raise RuntimeError("Python v.2.2 or later needed") + +import os, re +compiler = None +try: + import compiler +except ImportError: + # for IronPython + pass +from types import StringTypes +from warnings import warn +try: + from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE +except ImportError: + # Python 2.2 does not have these + # UTF-8 + BOM_UTF8 = '\xef\xbb\xbf' + # UTF-16, little endian + BOM_UTF16_LE = '\xff\xfe' + # UTF-16, big endian + BOM_UTF16_BE = '\xfe\xff' + if sys.byteorder == 'little': + # UTF-16, native endianness + BOM_UTF16 = BOM_UTF16_LE + else: + # UTF-16, native endianness + BOM_UTF16 = BOM_UTF16_BE + +# A dictionary mapping BOM to +# the encoding to decode with, and what to set the +# encoding attribute to. +BOMS = { + BOM_UTF8: ('utf_8', None), + BOM_UTF16_BE: ('utf16_be', 'utf_16'), + BOM_UTF16_LE: ('utf16_le', 'utf_16'), + BOM_UTF16: ('utf_16', 'utf_16'), + } +# All legal variants of the BOM codecs. +# TODO: the list of aliases is not meant to be exhaustive, is there a +# better way ? +BOM_LIST = { + 'utf_16': 'utf_16', + 'u16': 'utf_16', + 'utf16': 'utf_16', + 'utf-16': 'utf_16', + 'utf16_be': 'utf16_be', + 'utf_16_be': 'utf16_be', + 'utf-16be': 'utf16_be', + 'utf16_le': 'utf16_le', + 'utf_16_le': 'utf16_le', + 'utf-16le': 'utf16_le', + 'utf_8': 'utf_8', + 'u8': 'utf_8', + 'utf': 'utf_8', + 'utf8': 'utf_8', + 'utf-8': 'utf_8', + } + +# Map of encodings to the BOM to write. +BOM_SET = { + 'utf_8': BOM_UTF8, + 'utf_16': BOM_UTF16, + 'utf16_be': BOM_UTF16_BE, + 'utf16_le': BOM_UTF16_LE, + None: BOM_UTF8 + } + +try: + from validate import VdtMissingValue +except ImportError: + VdtMissingValue = None + +try: + enumerate +except NameError: + def enumerate(obj): + """enumerate for Python 2.2.""" + i = -1 + for item in obj: + i += 1 + yield i, item + +try: + True, False +except NameError: + True, False = 1, 0 + + +__version__ = '4.4.0' + +__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $' + +__docformat__ = "restructuredtext en" + +__all__ = ( + '__version__', + 'DEFAULT_INDENT_TYPE', + 'DEFAULT_INTERPOLATION', + 'ConfigObjError', + 'NestingError', + 'ParseError', + 'DuplicateError', + 'ConfigspecError', + 'ConfigObj', + 'SimpleVal', + 'InterpolationError', + 'InterpolationLoopError', + 'MissingInterpolationOption', + 'RepeatSectionError', + 'UnreprError', + 'UnknownType', + '__docformat__', + 'flatten_errors', +) + +DEFAULT_INTERPOLATION = 'configparser' +DEFAULT_INDENT_TYPE = ' ' +MAX_INTERPOL_DEPTH = 10 + +OPTION_DEFAULTS = { + 'interpolation': True, + 'raise_errors': False, + 'list_values': True, + 'create_empty': False, + 'file_error': False, + 'configspec': None, + 'stringify': True, + # option may be set to one of ('', ' ', '\t') + 'indent_type': None, + 'encoding': None, + 'default_encoding': None, + 'unrepr': False, + 'write_empty_values': False, +} + + +def getObj(s): + s = "a=" + s + if compiler is None: + raise ImportError('compiler module not available') + p = compiler.parse(s) + return p.getChildren()[1].getChildren()[0].getChildren()[1] + +class UnknownType(Exception): + pass + +class Builder: + + def build(self, o): + m = getattr(self, 'build_' + o.__class__.__name__, None) + if m is None: + raise UnknownType(o.__class__.__name__) + return m(o) + + def build_List(self, o): + return map(self.build, o.getChildren()) + + def build_Const(self, o): + return o.value + + def build_Dict(self, o): + d = {} + i = iter(map(self.build, o.getChildren())) + for el in i: + d[el] = i.next() + return d + + def build_Tuple(self, o): + return tuple(self.build_List(o)) + + def build_Name(self, o): + if o.name == 'None': + return None + if o.name == 'True': + return True + if o.name == 'False': + return False + + # An undefinted Name + raise UnknownType('Undefined Name') + + def build_Add(self, o): + real, imag = map(self.build_Const, o.getChildren()) + try: + real = float(real) + except TypeError: + raise UnknownType('Add') + if not isinstance(imag, complex) or imag.real != 0.0: + raise UnknownType('Add') + return real+imag + + def build_Getattr(self, o): + parent = self.build(o.expr) + return getattr(parent, o.attrname) + + def build_UnarySub(self, o): + return -self.build_Const(o.getChildren()[0]) + + def build_UnaryAdd(self, o): + return self.build_Const(o.getChildren()[0]) + +def unrepr(s): + if not s: + return s + return Builder().build(getObj(s)) + +def _splitlines(instring): + """Split a string on lines, without losing line endings or truncating.""" + + +class ConfigObjError(SyntaxError): + """ + This is the base class for all errors that ConfigObj raises. + It is a subclass of SyntaxError. + """ + def __init__(self, message='', line_number=None, line=''): + self.line = line + self.line_number = line_number + self.message = message + SyntaxError.__init__(self, message) + +class NestingError(ConfigObjError): + """ + This error indicates a level of nesting that doesn't match. + """ + +class ParseError(ConfigObjError): + """ + This error indicates that a line is badly written. + It is neither a valid ``key = value`` line, + nor a valid section marker line. + """ + +class DuplicateError(ConfigObjError): + """ + The keyword or section specified already exists. + """ + +class ConfigspecError(ConfigObjError): + """ + An error occured whilst parsing a configspec. + """ + +class InterpolationError(ConfigObjError): + """Base class for the two interpolation errors.""" + +class InterpolationLoopError(InterpolationError): + """Maximum interpolation depth exceeded in string interpolation.""" + + def __init__(self, option): + InterpolationError.__init__( + self, + 'interpolation loop detected in value "%s".' % option) + +class RepeatSectionError(ConfigObjError): + """ + This error indicates additional sections in a section with a + ``__many__`` (repeated) section. + """ + +class MissingInterpolationOption(InterpolationError): + """A value specified for interpolation was missing.""" + + def __init__(self, option): + InterpolationError.__init__( + self, + 'missing option "%s" in interpolation.' % option) + +class UnreprError(ConfigObjError): + """An error parsing in unrepr mode.""" + + +class InterpolationEngine(object): + """ + A helper class to help perform string interpolation. + + This class is an abstract base class; its descendants perform + the actual work. + """ + + # compiled regexp to use in self.interpolate() + _KEYCRE = re.compile(r"%\(([^)]*)\)s") + + def __init__(self, section): + # the Section instance that "owns" this engine + self.section = section + + def interpolate(self, key, value): + def recursive_interpolate(key, value, section, backtrail): + """The function that does the actual work. + + ``value``: the string we're trying to interpolate. + ``section``: the section in which that string was found + ``backtrail``: a dict to keep track of where we've been, + to detect and prevent infinite recursion loops + + This is similar to a depth-first-search algorithm. + """ + # Have we been here already? + if backtrail.has_key((key, section.name)): + # Yes - infinite loop detected + raise InterpolationLoopError(key) + # Place a marker on our backtrail so we won't come back here again + backtrail[(key, section.name)] = 1 + + # Now start the actual work + match = self._KEYCRE.search(value) + while match: + # The actual parsing of the match is implementation-dependent, + # so delegate to our helper function + k, v, s = self._parse_match(match) + if k is None: + # That's the signal that no further interpolation is needed + replacement = v + else: + # Further interpolation may be needed to obtain final value + replacement = recursive_interpolate(k, v, s, backtrail) + # Replace the matched string with its final value + start, end = match.span() + value = ''.join((value[:start], replacement, value[end:])) + new_search_start = start + len(replacement) + # Pick up the next interpolation key, if any, for next time + # through the while loop + match = self._KEYCRE.search(value, new_search_start) + + # Now safe to come back here again; remove marker from backtrail + del backtrail[(key, section.name)] + + return value + + # Back in interpolate(), all we have to do is kick off the recursive + # function with appropriate starting values + value = recursive_interpolate(key, value, self.section, {}) + return value + + def _fetch(self, key): + """Helper function to fetch values from owning section. + + Returns a 2-tuple: the value, and the section where it was found. + """ + # switch off interpolation before we try and fetch anything ! + save_interp = self.section.main.interpolation + self.section.main.interpolation = False + + # Start at section that "owns" this InterpolationEngine + current_section = self.section + while True: + # try the current section first + val = current_section.get(key) + if val is not None: + break + # try "DEFAULT" next + val = current_section.get('DEFAULT', {}).get(key) + if val is not None: + break + # move up to parent and try again + # top-level's parent is itself + if current_section.parent is current_section: + # reached top level, time to give up + break + current_section = current_section.parent + + # restore interpolation to previous value before returning + self.section.main.interpolation = save_interp + if val is None: + raise MissingInterpolationOption(key) + return val, current_section + + def _parse_match(self, match): + """Implementation-dependent helper function. + + Will be passed a match object corresponding to the interpolation + key we just found (e.g., "%(foo)s" or "$foo"). Should look up that + key in the appropriate config file section (using the ``_fetch()`` + helper function) and return a 3-tuple: (key, value, section) + + ``key`` is the name of the key we're looking for + ``value`` is the value found for that key + ``section`` is a reference to the section where it was found + + ``key`` and ``section`` should be None if no further + interpolation should be performed on the resulting value + (e.g., if we interpolated "$$" and returned "$"). + """ + raise NotImplementedError + + +class ConfigParserInterpolation(InterpolationEngine): + """Behaves like ConfigParser.""" + _KEYCRE = re.compile(r"%\(([^)]*)\)s") + + def _parse_match(self, match): + key = match.group(1) + value, section = self._fetch(key) + return key, value, section + + +class TemplateInterpolation(InterpolationEngine): + """Behaves like string.Template.""" + _delimiter = '$' + _KEYCRE = re.compile(r""" + \$(?: + (?P<escaped>\$) | # Two $ signs + (?P<named>[_a-z][_a-z0-9]*) | # $name format + {(?P<braced>[^}]*)} # ${name} format + ) + """, re.IGNORECASE | re.VERBOSE) + + def _parse_match(self, match): + # Valid name (in or out of braces): fetch value from section + key = match.group('named') or match.group('braced') + if key is not None: + value, section = self._fetch(key) + return key, value, section + # Escaped delimiter (e.g., $$): return single delimiter + if match.group('escaped') is not None: + # Return None for key and section to indicate it's time to stop + return None, self._delimiter, None + # Anything else: ignore completely, just return it unchanged + return None, match.group(), None + +interpolation_engines = { + 'configparser': ConfigParserInterpolation, + 'template': TemplateInterpolation, +} + +class Section(dict): + """ + A dictionary-like object that represents a section in a config file. + + It does string interpolation if the 'interpolation' attribute + of the 'main' object is set to True. + + Interpolation is tried first from this object, then from the 'DEFAULT' + section of this object, next from the parent and its 'DEFAULT' section, + and so on until the main object is reached. + + A Section will behave like an ordered dictionary - following the + order of the ``scalars`` and ``sections`` attributes. + You can use this to change the order of members. + + Iteration follows the order: scalars, then sections. + """ + + def __init__(self, parent, depth, main, indict=None, name=None): + """ + * parent is the section above + * depth is the depth level of this section + * main is the main ConfigObj + * indict is a dictionary to initialise the section with + """ + if indict is None: + indict = {} + dict.__init__(self) + # used for nesting level *and* interpolation + self.parent = parent + # used for the interpolation attribute + self.main = main + # level of nesting depth of this Section + self.depth = depth + # the sequence of scalar values in this Section + self.scalars = [] + # the sequence of sections in this Section + self.sections = [] + # purely for information + self.name = name + # for comments :-) + self.comments = {} + self.inline_comments = {} + # for the configspec + self.configspec = {} + self._order = [] + self._configspec_comments = {} + self._configspec_inline_comments = {} + self._cs_section_comments = {} + self._cs_section_inline_comments = {} + # for defaults + self.defaults = [] + # + # we do this explicitly so that __setitem__ is used properly + # (rather than just passing to ``dict.__init__``) + for entry in indict: + self[entry] = indict[entry] + + def _interpolate(self, key, value): + try: + # do we already have an interpolation engine? + engine = self._interpolation_engine + except AttributeError: + # not yet: first time running _interpolate(), so pick the engine + name = self.main.interpolation + if name == True: # note that "if name:" would be incorrect here + # backwards-compatibility: interpolation=True means use default + name = DEFAULT_INTERPOLATION + name = name.lower() # so that "Template", "template", etc. all work + class_ = interpolation_engines.get(name, None) + if class_ is None: + # invalid value for self.main.interpolation + self.main.interpolation = False + return value + else: + # save reference to engine so we don't have to do this again + engine = self._interpolation_engine = class_(self) + # let the engine do the actual work + return engine.interpolate(key, value) + + def __getitem__(self, key): + """Fetch the item and do string interpolation.""" + val = dict.__getitem__(self, key) + if self.main.interpolation and isinstance(val, StringTypes): + return self._interpolate(key, val) + return val + + def __setitem__(self, key, value, unrepr=False): + """ + Correctly set a value. + + Making dictionary values Section instances. + (We have to special case 'Section' instances - which are also dicts) + + Keys must be strings. + Values need only be strings (or lists of strings) if + ``main.stringify`` is set. + + `unrepr`` must be set when setting a value to a dictionary, without + creating a new sub-section. + """ + if not isinstance(key, StringTypes): + raise ValueError, 'The key "%s" is not a string.' % key + # add the comment + if not self.comments.has_key(key): + self.comments[key] = [] + self.inline_comments[key] = '' + # remove the entry from defaults + if key in self.defaults: + self.defaults.remove(key) + # + if isinstance(value, Section): + if not self.has_key(key): + self.sections.append(key) + dict.__setitem__(self, key, value) + elif isinstance(value, dict) and not unrepr: + # First create the new depth level, + # then create the section + if not self.has_key(key): + self.sections.append(key) + new_depth = self.depth + 1 + dict.__setitem__( + self, + key, + Section( + self, + new_depth, + self.main, + indict=value, + name=key)) + else: + if not self.has_key(key): + self.scalars.append(key) + if not self.main.stringify: + if isinstance(value, StringTypes): + pass + elif isinstance(value, (list, tuple)): + for entry in value: + if not isinstance(entry, StringTypes): + raise TypeError, ( + 'Value is not a string "%s".' % entry) + else: + raise TypeError, 'Value is not a string "%s".' % value + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + """Remove items from the sequence when deleting.""" + dict. __delitem__(self, key) + if key in self.scalars: + self.scalars.remove(key) + else: + self.sections.remove(key) + del self.comments[key] + del self.inline_comments[key] + + def get(self, key, default=None): + """A version of ``get`` that doesn't bypass string interpolation.""" + try: + return self[key] + except KeyError: + return default + + def update(self, indict): + """ + A version of update that uses our ``__setitem__``. + """ + for entry in indict: + self[entry] = indict[entry] + + def pop(self, key, *args): + """ """ + val = dict.pop(self, key, *args) + if key in self.scalars: + del self.comments[key] + del self.inline_comments[key] + self.scalars.remove(key) + elif key in self.sections: + del self.comments[key] + del self.inline_comments[key] + self.sections.remove(key) + if self.main.interpolation and isinstance(val, StringTypes): + return self._interpolate(key, val) + return val + + def popitem(self): + """Pops the first (key,val)""" + sequence = (self.scalars + self.sections) + if not sequence: + raise KeyError, ": 'popitem(): dictionary is empty'" + key = sequence[0] + val = self[key] + del self[key] + return key, val + + def clear(self): + """ + A version of clear that also affects scalars/sections + Also clears comments and configspec. + + Leaves other attributes alone : + depth/main/parent are not affected + """ + dict.clear(self) + self.scalars = [] + self.sections = [] + self.comments = {} + self.inline_comments = {} + self.configspec = {} + + def setdefault(self, key, default=None): + """A version of setdefault that sets sequence if appropriate.""" + try: + return self[key] + except KeyError: + self[key] = default + return self[key] + + def items(self): + """ """ + return zip((self.scalars + self.sections), self.values()) + + def keys(self): + """ """ + return (self.scalars + self.sections) + + def values(self): + """ """ + return [self[key] for key in (self.scalars + self.sections)] + + def iteritems(self): + """ """ + return iter(self.items()) + + def iterkeys(self): + """ """ + return iter((self.scalars + self.sections)) + + __iter__ = iterkeys + + def itervalues(self): + """ """ + return iter(self.values()) + + def __repr__(self): + return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key]))) + for key in (self.scalars + self.sections)]) + + __str__ = __repr__ + + # Extra methods - not in a normal dictionary + + def dict(self): + """ + Return a deepcopy of self as a dictionary. + + All members that are ``Section`` instances are recursively turned to + ordinary dictionaries - by calling their ``dict`` method. + + >>> n = a.dict() + >>> n == a + 1 + >>> n is a + 0 + """ + newdict = {} + for entry in self: + this_entry = self[entry] + if isinstance(this_entry, Section): + this_entry = this_entry.dict() + elif isinstance(this_entry, list): + # create a copy rather than a reference + this_entry = list(this_entry) + elif isinstance(this_entry, tuple): + # create a copy rather than a reference + this_entry = tuple(this_entry) + newdict[entry] = this_entry + return newdict + + def merge(self, indict): + """ + A recursive update - useful for merging config files. + + >>> a = '''[section1] + ... option1 = True + ... [[subsection]] + ... more_options = False + ... # end of file'''.splitlines() + >>> b = '''# File is user.ini + ... [section1] + ... option1 = False + ... # end of file'''.splitlines() + >>> c1 = ConfigObj(b) + >>> c2 = ConfigObj(a) + >>> c2.merge(c1) + >>> c2 + {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}} + """ + for key, val in indict.items(): + if (key in self and isinstance(self[key], dict) and + isinstance(val, dict)): + self[key].merge(val) + else: + self[key] = val + + def rename(self, oldkey, newkey): + """ + Change a keyname to another, without changing position in sequence. + + Implemented so that transformations can be made on keys, + as well as on values. (used by encode and decode) + + Also renames comments. + """ + if oldkey in self.scalars: + the_list = self.scalars + elif oldkey in self.sections: + the_list = self.sections + else: + raise KeyError, 'Key "%s" not found.' % oldkey + pos = the_list.index(oldkey) + # + val = self[oldkey] + dict.__delitem__(self, oldkey) + dict.__setitem__(self, newkey, val) + the_list.remove(oldkey) + the_list.insert(pos, newkey) + comm = self.comments[oldkey] + inline_comment = self.inline_comments[oldkey] + del self.comments[oldkey] + del self.inline_comments[oldkey] + self.comments[newkey] = comm + self.inline_comments[newkey] = inline_comment + + def walk(self, function, raise_errors=True, + call_on_sections=False, **keywargs): + """ + Walk every member and call a function on the keyword and value. + + Return a dictionary of the return values + + If the function raises an exception, raise the errror + unless ``raise_errors=False``, in which case set the return value to + ``False``. + + Any unrecognised keyword arguments you pass to walk, will be pased on + to the function you pass in. + + Note: if ``call_on_sections`` is ``True`` then - on encountering a + subsection, *first* the function is called for the *whole* subsection, + and then recurses into it's members. This means your function must be + able to handle strings, dictionaries and lists. This allows you + to change the key of subsections as well as for ordinary members. The + return value when called on the whole subsection has to be discarded. + + See the encode and decode methods for examples, including functions. + + .. caution:: + + You can use ``walk`` to transform the names of members of a section + but you mustn't add or delete members. + + >>> config = '''[XXXXsection] + ... XXXXkey = XXXXvalue'''.splitlines() + >>> cfg = ConfigObj(config) + >>> cfg + {'XXXXsection': {'XXXXkey': 'XXXXvalue'}} + >>> def transform(section, key): + ... val = section[key] + ... newkey = key.replace('XXXX', 'CLIENT1') + ... section.rename(key, newkey) + ... if isinstance(val, (tuple, list, dict)): + ... pass + ... else: + ... val = val.replace('XXXX', 'CLIENT1') + ... section[newkey] = val + >>> cfg.walk(transform, call_on_sections=True) + {'CLIENT1section': {'CLIENT1key': None}} + >>> cfg + {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}} + """ + out = {} + # scalars first + for i in range(len(self.scalars)): + entry = self.scalars[i] + try: + val = function(self, entry, **keywargs) + # bound again in case name has changed + entry = self.scalars[i] + out[entry] = val + except Exception: + if raise_errors: + raise + else: + entry = self.scalars[i] + out[entry] = False + # then sections + for i in range(len(self.sections)): + entry = self.sections[i] + if call_on_sections: + try: + function(self, entry, **keywargs) + except Exception: + if raise_errors: + raise + else: + entry = self.sections[i] + out[entry] = False + # bound again in case name has changed + entry = self.sections[i] + # previous result is discarded + out[entry] = self[entry].walk( + function, + raise_errors=raise_errors, + call_on_sections=call_on_sections, + **keywargs) + return out + + def decode(self, encoding): + """ + Decode all strings and values to unicode, using the specified encoding. + + Works with subsections and list values. + + Uses the ``walk`` method. + + Testing ``encode`` and ``decode``. + >>> m = ConfigObj(a) + >>> m.decode('ascii') + >>> def testuni(val): + ... for entry in val: + ... if not isinstance(entry, unicode): + ... print >> sys.stderr, type(entry) + ... raise AssertionError, 'decode failed.' + ... if isinstance(val[entry], dict): + ... testuni(val[entry]) + ... elif not isinstance(val[entry], unicode): + ... raise AssertionError, 'decode failed.' + >>> testuni(m) + >>> m.encode('ascii') + >>> a == m + 1 + """ + warn('use of ``decode`` is deprecated.', DeprecationWarning) + def decode(section, key, encoding=encoding, warn=True): + """ """ + val = section[key] + if isinstance(val, (list, tuple)): + newval = [] + for entry in val: + newval.append(entry.decode(encoding)) + elif isinstance(val, dict): + newval = val + else: + newval = val.decode(encoding) + newkey = key.decode(encoding) + section.rename(key, newkey) + section[newkey] = newval + # using ``call_on_sections`` allows us to modify section names + self.walk(decode, call_on_sections=True) + + def encode(self, encoding): + """ + Encode all strings and values from unicode, + using the specified encoding. + + Works with subsections and list values. + Uses the ``walk`` method. + """ + warn('use of ``encode`` is deprecated.', DeprecationWarning) + def encode(section, key, encoding=encoding): + """ """ + val = section[key] + if isinstance(val, (list, tuple)): + newval = [] + for entry in val: + newval.append(entry.encode(encoding)) + elif isinstance(val, dict): + newval = val + else: + newval = val.encode(encoding) + newkey = key.encode(encoding) + section.rename(key, newkey) + section[newkey] = newval + self.walk(encode, call_on_sections=True) + + def istrue(self, key): + """A deprecated version of ``as_bool``.""" + warn('use of ``istrue`` is deprecated. Use ``as_bool`` method ' + 'instead.', DeprecationWarning) + return self.as_bool(key) + + def as_bool(self, key): + """ + Accepts a key as input. The corresponding value must be a string or + the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to + retain compatibility with Python 2.2. + + If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns + ``True``. + + If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns + ``False``. + + ``as_bool`` is not case sensitive. + + Any other input will raise a ``ValueError``. + + >>> a = ConfigObj() + >>> a['a'] = 'fish' + >>> a.as_bool('a') + Traceback (most recent call last): + ValueError: Value "fish" is neither True nor False + >>> a['b'] = 'True' + >>> a.as_bool('b') + 1 + >>> a['b'] = 'off' + >>> a.as_bool('b') + 0 + """ + val = self[key] + if val == True: + return True + elif val == False: + return False + else: + try: + if not isinstance(val, StringTypes): + raise KeyError + else: + return self.main._bools[val.lower()] + except KeyError: + raise ValueError('Value "%s" is neither True nor False' % val) + + def as_int(self, key): + """ + A convenience method which coerces the specified value to an integer. + + If the value is an invalid literal for ``int``, a ``ValueError`` will + be raised. + + >>> a = ConfigObj() + >>> a['a'] = 'fish' + >>> a.as_int('a') + Traceback (most recent call last): + ValueError: invalid literal for int(): fish + >>> a['b'] = '1' + >>> a.as_int('b') + 1 + >>> a['b'] = '3.2' + >>> a.as_int('b') + Traceback (most recent call last): + ValueError: invalid literal for int(): 3.2 + """ + return int(self[key]) + + def as_float(self, key): + """ + A convenience method which coerces the specified value to a float. + + If the value is an invalid literal for ``float``, a ``ValueError`` will + be raised. + + >>> a = ConfigObj() + >>> a['a'] = 'fish' + >>> a.as_float('a') + Traceback (most recent call last): + ValueError: invalid literal for float(): fish + >>> a['b'] = '1' + >>> a.as_float('b') + 1.0 + >>> a['b'] = '3.2' + >>> a.as_float('b') + 3.2000000000000002 + """ + return float(self[key]) + + +class ConfigObj(Section): + """An object to read, create, and write config files.""" + + _keyword = re.compile(r'''^ # line start + (\s*) # indentation + ( # keyword + (?:".*?")| # double quotes + (?:'.*?')| # single quotes + (?:[^'"=].*?) # no quotes + ) + \s*=\s* # divider + (.*) # value (including list values and comments) + $ # line end + ''', + re.VERBOSE) + + _sectionmarker = re.compile(r'''^ + (\s*) # 1: indentation + ((?:\[\s*)+) # 2: section marker open + ( # 3: section name open + (?:"\s*\S.*?\s*")| # at least one non-space with double quotes + (?:'\s*\S.*?\s*')| # at least one non-space with single quotes + (?:[^'"\s].*?) # at least one non-space unquoted + ) # section name close + ((?:\s*\])+) # 4: section marker close + \s*(\#.*)? # 5: optional comment + $''', + re.VERBOSE) + + # this regexp pulls list values out as a single string + # or single values and comments + # FIXME: this regex adds a '' to the end of comma terminated lists + # workaround in ``_handle_value`` + _valueexp = re.compile(r'''^ + (?: + (?: + ( + (?: + (?: + (?:".*?")| # double quotes + (?:'.*?')| # single quotes + (?:[^'",\#][^,\#]*?) # unquoted + ) + \s*,\s* # comma + )* # match all list items ending in a comma (if any) + ) + ( + (?:".*?")| # double quotes + (?:'.*?')| # single quotes + (?:[^'",\#\s][^,]*?)| # unquoted + (?:(?<!,)) # Empty value + )? # last item in a list - or string value + )| + (,) # alternatively a single comma - empty list + ) + \s*(\#.*)? # optional comment + $''', + re.VERBOSE) + + # use findall to get the members of a list value + _listvalueexp = re.compile(r''' + ( + (?:".*?")| # double quotes + (?:'.*?')| # single quotes + (?:[^'",\#].*?) # unquoted + ) + \s*,\s* # comma + ''', + re.VERBOSE) + + # this regexp is used for the value + # when lists are switched off + _nolistvalue = re.compile(r'''^ + ( + (?:".*?")| # double quotes + (?:'.*?')| # single quotes + (?:[^'"\#].*?)| # unquoted + (?:) # Empty value + ) + \s*(\#.*)? # optional comment + $''', + re.VERBOSE) + + # regexes for finding triple quoted values on one line + _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$") + _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$') + _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$") + _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$') + + _triple_quote = { + "'''": (_single_line_single, _multi_line_single), + '"""': (_single_line_double, _multi_line_double), + } + + # Used by the ``istrue`` Section method + _bools = { + 'yes': True, 'no': False, + 'on': True, 'off': False, + '1': True, '0': False, + 'true': True, 'false': False, + } + + def __init__(self, infile=None, options=None, **kwargs): + """ + Parse or create a config file object. + + ``ConfigObj(infile=None, options=None, **kwargs)`` + """ + if infile is None: + infile = [] + if options is None: + options = {} + else: + options = dict(options) + # keyword arguments take precedence over an options dictionary + options.update(kwargs) + # init the superclass + Section.__init__(self, self, 0, self) + # + defaults = OPTION_DEFAULTS.copy() + for entry in options.keys(): + if entry not in defaults.keys(): + raise TypeError, 'Unrecognised option "%s".' % entry + # TODO: check the values too. + # + # Add any explicit options to the defaults + defaults.update(options) + # + # initialise a few variables + self.filename = None + self._errors = [] + self.raise_errors = defaults['raise_errors'] + self.interpolation = defaults['interpolation'] + self.list_values = defaults['list_values'] + self.create_empty = defaults['create_empty'] + self.file_error = defaults['file_error'] + self.stringify = defaults['stringify'] + self.indent_type = defaults['indent_type'] + self.encoding = defaults['encoding'] + self.default_encoding = defaults['default_encoding'] + self.BOM = False + self.newlines = None + self.write_empty_values = defaults['write_empty_values'] + self.unrepr = defaults['unrepr'] + # + self.initial_comment = [] + self.final_comment = [] + # + self._terminated = False + # + if isinstance(infile, StringTypes): + self.filename = infile + if os.path.isfile(infile): + infile = open(infile).read() or [] + elif self.file_error: + # raise an error if the file doesn't exist + raise IOError, 'Config file not found: "%s".' % self.filename + else: + # file doesn't already exist + if self.create_empty: + # this is a good test that the filename specified + # isn't impossible - like on a non existent device + h = open(infile, 'w') + h.write('') + h.close() + infile = [] + elif isinstance(infile, (list, tuple)): + infile = list(infile) + elif isinstance(infile, dict): + # initialise self + # the Section class handles creating subsections + if isinstance(infile, ConfigObj): + # get a copy of our ConfigObj + infile = infile.dict() + for entry in infile: + self[entry] = infile[entry] + del self._errors + if defaults['configspec'] is not None: + self._handle_configspec(defaults['configspec']) + else: + self.configspec = None + return + elif hasattr(infile, 'read'): + # This supports file like objects + infile = infile.read() or [] + # needs splitting into lines - but needs doing *after* decoding + # in case it's not an 8 bit encoding + else: + raise TypeError, ('infile must be a filename,' + ' file like object, or list of lines.') + # + if infile: + # don't do it for the empty ConfigObj + infile = self._handle_bom(infile) + # infile is now *always* a list + # + # Set the newlines attribute (first line ending it finds) + # and strip trailing '\n' or '\r' from lines + for line in infile: + if (not line) or (line[-1] not in ('\r', '\n', '\r\n')): + continue + for end in ('\r\n', '\n', '\r'): + if line.endswith(end): + self.newlines = end + break + break + if infile[-1] and infile[-1] in ('\r', '\n', '\r\n'): + self._terminated = True + infile = [line.rstrip('\r\n') for line in infile] + # + self._parse(infile) + # if we had any errors, now is the time to raise them + if self._errors: + info = "at line %s." % self._errors[0].line_number + if len(self._errors) > 1: + msg = ("Parsing failed with several errors.\nFirst error %s" % + info) + error = ConfigObjError(msg) + else: + error = self._errors[0] + # set the errors attribute; it's a list of tuples: + # (error_type, message, line_number) + error.errors = self._errors + # set the config attribute + error.config = self + raise error + # delete private attributes + del self._errors + # + if defaults['configspec'] is None: + self.configspec = None + else: + self._handle_configspec(defaults['configspec']) + + def __repr__(self): + return 'ConfigObj({%s})' % ', '.join( + [('%s: %s' % (repr(key), repr(self[key]))) for key in + (self.scalars + self.sections)]) + + def _handle_bom(self, infile): + """ + Handle any BOM, and decode if necessary. + + If an encoding is specified, that *must* be used - but the BOM should + still be removed (and the BOM attribute set). + + (If the encoding is wrongly specified, then a BOM for an alternative + encoding won't be discovered or removed.) + + If an encoding is not specified, UTF8 or UTF16 BOM will be detected and + removed. The BOM attribute will be set. UTF16 will be decoded to + unicode. + + NOTE: This method must not be called with an empty ``infile``. + + Specifying the *wrong* encoding is likely to cause a + ``UnicodeDecodeError``. + + ``infile`` must always be returned as a list of lines, but may be + passed in as a single string. + """ + if ((self.encoding is not None) and + (self.encoding.lower() not in BOM_LIST)): + # No need to check for a BOM + # the encoding specified doesn't have one + # just decode + return self._decode(infile, self.encoding) + # + if isinstance(infile, (list, tuple)): + line = infile[0] + else: + line = infile + if self.encoding is not None: + # encoding explicitly supplied + # And it could have an associated BOM + # TODO: if encoding is just UTF16 - we ought to check for both + # TODO: big endian and little endian versions. + enc = BOM_LIST[self.encoding.lower()] + if enc == 'utf_16': + # For UTF16 we try big endian and little endian + for BOM, (encoding, final_encoding) in BOMS.items(): + if not final_encoding: + # skip UTF8 + continue + if infile.startswith(BOM): + ### BOM discovered + ##self.BOM = True + # Don't need to remove BOM + return self._decode(infile, encoding) + # + # If we get this far, will *probably* raise a DecodeError + # As it doesn't appear to start with a BOM + return self._decode(infile, self.encoding) + # + # Must be UTF8 + BOM = BOM_SET[enc] + if not line.startswith(BOM): + return self._decode(infile, self.encoding) + # + newline = line[len(BOM):] + # + # BOM removed + if isinstance(infile, (list, tuple)): + infile[0] = newline + else: + infile = newline + self.BOM = True + return self._decode(infile, self.encoding) + # + # No encoding specified - so we need to check for UTF8/UTF16 + for BOM, (encoding, final_encoding) in BOMS.items(): + if not line.startswith(BOM): + continue + else: + # BOM discovered + self.encoding = final_encoding + if not final_encoding: + self.BOM = True + # UTF8 + # remove BOM + newline = line[len(BOM):] + if isinstance(infile, (list, tuple)): + infile[0] = newline + else: + infile = newline + # UTF8 - don't decode + if isinstance(infile, StringTypes): + return infile.splitlines(True) + else: + return infile + # UTF16 - have to decode + return self._decode(infile, encoding) + # + # No BOM discovered and no encoding specified, just return + if isinstance(infile, StringTypes): + # infile read from a file will be a single string + return infile.splitlines(True) + else: + return infile + + def _a_to_u(self, aString): + """Decode ASCII strings to unicode if a self.encoding is specified.""" + if self.encoding: + return aString.decode('ascii') + else: + return aString + + def _decode(self, infile, encoding): + """ + Decode infile to unicode. Using the specified encoding. + + if is a string, it also needs converting to a list. + """ + if isinstance(infile, StringTypes): + # can't be unicode + # NOTE: Could raise a ``UnicodeDecodeError`` + return infile.decode(encoding).splitlines(True) + for i, line in enumerate(infile): + if not isinstance(line, unicode): + # NOTE: The isinstance test here handles mixed lists of unicode/string + # NOTE: But the decode will break on any non-string values + # NOTE: Or could raise a ``UnicodeDecodeError`` + infile[i] = line.decode(encoding) + return infile + + def _decode_element(self, line): + """Decode element to unicode if necessary.""" + if not self.encoding: + return line + if isinstance(line, str) and self.default_encoding: + return line.decode(self.default_encoding) + return line + + def _str(self, value): + """ + Used by ``stringify`` within validate, to turn non-string values + into strings. + """ + if not isinstance(value, StringTypes): + return str(value) + else: + return value + + def _parse(self, infile): + """Actually parse the config file.""" + temp_list_values = self.list_values + if self.unrepr: + self.list_values = False + comment_list = [] + done_start = False + this_section = self + maxline = len(infile) - 1 + cur_index = -1 + reset_comment = False + while cur_index < maxline: + if reset_comment: + comment_list = [] + cur_index += 1 + line = infile[cur_index] + sline = line.strip() + # do we have anything on the line ? + if not sline or sline.startswith('#'): + reset_comment = False + comment_list.append(line) + continue + if not done_start: + # preserve initial comment + self.initial_comment = comment_list + comment_list = [] + done_start = True + reset_comment = True + # first we check if it's a section marker + mat = self._sectionmarker.match(line) + if mat is not None: + # is a section line + (indent, sect_open, sect_name, sect_close, comment) = ( + mat.groups()) + if indent and (self.indent_type is None): + self.indent_type = indent + cur_depth = sect_open.count('[') + if cur_depth != sect_close.count(']'): + self._handle_error( + "Cannot compute the section depth at line %s.", + NestingError, infile, cur_index) + continue + # + if cur_depth < this_section.depth: + # the new section is dropping back to a previous level + try: + parent = self._match_depth( + this_section, + cur_depth).parent + except SyntaxError: + self._handle_error( + "Cannot compute nesting level at line %s.", + NestingError, infile, cur_index) + continue + elif cur_depth == this_section.depth: + # the new section is a sibling of the current section + parent = this_section.parent + elif cur_depth == this_section.depth + 1: + # the new section is a child the current section + parent = this_section + else: + self._handle_error( + "Section too nested at line %s.", + NestingError, infile, cur_index) + # + sect_name = self._unquote(sect_name) + if parent.has_key(sect_name): + self._handle_error( + 'Duplicate section name at line %s.', + DuplicateError, infile, cur_index) + continue + # create the new section + this_section = Section( + parent, + cur_depth, + self, + name=sect_name) + parent[sect_name] = this_section + parent.inline_comments[sect_name] = comment + parent.comments[sect_name] = comment_list + continue + # + # it's not a section marker, + # so it should be a valid ``key = value`` line + mat = self._keyword.match(line) + if mat is None: + # it neither matched as a keyword + # or a section marker + self._handle_error( + 'Invalid line at line "%s".', + ParseError, infile, cur_index) + else: + # is a keyword value + # value will include any inline comment + (indent, key, value) = mat.groups() + if indent and (self.indent_type is None): + self.indent_type = indent + # check for a multiline value + if value[:3] in ['"""', "'''"]: + try: + (value, comment, cur_index) = self._multiline( + value, infile, cur_index, maxline) + except SyntaxError: + self._handle_error( + 'Parse error in value at line %s.', + ParseError, infile, cur_index) + continue + else: + if self.unrepr: + comment = '' + try: + value = unrepr(value) + except Exception, e: + if type(e) == UnknownType: + msg = 'Unknown name or type in value at line %s.' + else: + msg = 'Parse error in value at line %s.' + self._handle_error(msg, UnreprError, infile, + cur_index) + continue + else: + if self.unrepr: + comment = '' + try: + value = unrepr(value) + except Exception, e: + if isinstance(e, UnknownType): + msg = 'Unknown name or type in value at line %s.' + else: + msg = 'Parse error in value at line %s.' + self._handle_error(msg, UnreprError, infile, + cur_index) + continue + else: + # extract comment and lists + try: + (value, comment) = self._handle_value(value) + except SyntaxError: + self._handle_error( + 'Parse error in value at line %s.', + ParseError, infile, cur_index) + continue + # + key = self._unquote(key) + if this_section.has_key(key): + self._handle_error( + 'Duplicate keyword name at line %s.', + DuplicateError, infile, cur_index) + continue + # add the key. + # we set unrepr because if we have got this far we will never + # be creating a new section + this_section.__setitem__(key, value, unrepr=True) + this_section.inline_comments[key] = comment + this_section.comments[key] = comment_list + continue + # + if self.indent_type is None: + # no indentation used, set the type accordingly + self.indent_type = '' + # + if self._terminated: + comment_list.append('') + # preserve the final comment + if not self and not self.initial_comment: + self.initial_comment = comment_list + elif not reset_comment: + self.final_comment = comment_list + self.list_values = temp_list_values + + def _match_depth(self, sect, depth): + """ + Given a section and a depth level, walk back through the sections + parents to see if the depth level matches a previous section. + + Return a reference to the right section, + or raise a SyntaxError. + """ + while depth < sect.depth: + if sect is sect.parent: + # we've reached the top level already + raise SyntaxError + sect = sect.parent + if sect.depth == depth: + return sect + # shouldn't get here + raise SyntaxError + + def _handle_error(self, text, ErrorClass, infile, cur_index): + """ + Handle an error according to the error settings. + + Either raise the error or store it. + The error will have occured at ``cur_index`` + """ + line = infile[cur_index] + cur_index += 1 + message = text % cur_index + error = ErrorClass(message, cur_index, line) + if self.raise_errors: + # raise the error - parsing stops here + raise error + # store the error + # reraise when parsing has finished + self._errors.append(error) + + def _unquote(self, value): + """Return an unquoted version of a value""" + if (value[0] == value[-1]) and (value[0] in ('"', "'")): + value = value[1:-1] + return value + + def _quote(self, value, multiline=True): + """ + Return a safely quoted version of a value. + + Raise a ConfigObjError if the value cannot be safely quoted. + If multiline is ``True`` (default) then use triple quotes + if necessary. + + Don't quote values that don't need it. + Recursively quote members of a list and return a comma joined list. + Multiline is ``False`` for... [truncated message content] |
From: <md...@us...> - 2007-11-07 21:21:33
|
Revision: 4154 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4154&view=rev Author: mdboom Date: 2007-11-07 13:20:45 -0800 (Wed, 07 Nov 2007) Log Message: ----------- First pass at Cairo support on the branch. Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_cairo.py branches/transforms/lib/matplotlib/path.py Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 20:38:46 UTC (rev 4153) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 21:20:45 UTC (rev 4154) @@ -62,7 +62,7 @@ that path multiple times with the different offsets, colors, styles etc. The methods _iter_collection_raw_paths and _iter_collection are provided to help with (and standardize) - the implementation that in each backend. + the implementation across backends. """ path_ids = [] for path, transform in self._iter_collection_raw_paths( @@ -91,10 +91,9 @@ if showedges: edgecolors = npy.array([[0.0, 0.0, 0.0, 1.0]], npy.float_) - linewidths = npy.array([1.0], npy.float_) else: - edgecolors = linewidths = npy.array([], npy.float_) - linewidths = npy.array([0.0], npy.float_) + edgecolors = facecolors + linewidths = npy.array([1.0], npy.float_) return self.draw_path_collection( master_transform, cliprect, clippath, clippath_trans, @@ -195,8 +194,10 @@ rgbFace = facecolors[i % Nfacecolors] if Nedgecolors: gc.set_foreground(edgecolors[i % Nedgecolors]) - gc.set_linewidth(linewidths[i % Nlinewidths]) - gc.set_dashes(*linestyles[i % Nlinestyles]) + if Nlinewidths: + gc.set_linewidth(linewidths[i % Nlinewidths]) + if Nlinestyles: + gc.set_dashes(*linestyles[i % Nlinestyles]) gc.set_antialiased(antialiaseds[i % Naa]) yield xo, yo, path_id, gc, rgbFace @@ -466,7 +467,7 @@ if isRGB: self._rgb = fg else: - self._rgb = colors.colorConverter.to_rgb(fg) + self._rgb = colors.colorConverter.to_rgba(fg) def set_graylevel(self, frac): """ Modified: branches/transforms/lib/matplotlib/backends/backend_cairo.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_cairo.py 2007-11-07 20:38:46 UTC (rev 4153) +++ branches/transforms/lib/matplotlib/backends/backend_cairo.py 2007-11-07 21:20:45 UTC (rev 4154) @@ -39,7 +39,8 @@ from matplotlib.cbook import enumerate, izip, is_string_like from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser -from matplotlib.transforms import Bbox +from matplotlib.path import Path +from matplotlib.transforms import Bbox, Affine2D from matplotlib.font_manager import ttfFontProperty from matplotlib import rcParams @@ -48,9 +49,9 @@ # Image::color_conv(format) for draw_image() if sys.byteorder == 'little': - BYTE_FORMAT = 0 # BGRA + BYTE_FORMAT = 0 # BGRA else: - BYTE_FORMAT = 1 # ARGB + BYTE_FORMAT = 1 # ARGB class RendererCairo(RendererBase): @@ -91,10 +92,10 @@ self.mathtext_parser = MathTextParser('Cairo') def set_ctx_from_surface (self, surface): - self.ctx = cairo.Context (surface) - self.ctx.save() # restore, save - when call new_gc() + self.ctx = cairo.Context (surface) + self.ctx.save() # restore, save - when call new_gc() + - def set_width_height(self, width, height): self.width = width self.height = height @@ -109,9 +110,12 @@ #_.ctx.save() - if fill_c: + if fill_c is not None: ctx.save() - ctx.set_source_rgb (*fill_c) + if len(fill_c) == 3: + ctx.set_source_rgb (*fill_c) + else: + ctx.set_source_rgba (*fill_c) #if stroke_c: # always (implicitly) set at the moment ctx.fill_preserve() #else: @@ -124,22 +128,48 @@ #_.ctx.restore() # revert to the default attributes - - def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, - rotation): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) + #@staticmethod + def convert_path(ctx, tpath): + for points, code in tpath.iter_segments(): + if code == Path.MOVETO: + ctx.move_to(*points) + elif code == Path.LINETO: + ctx.line_to(*points) + elif code == Path.CURVE3: + ctx.curve_to(points[0], points[1], + points[0], points[1], + points[2], points[3]) + elif code == Path.CURVE4: + ctx.curve_to(*points) + elif code == Path.CLOSEPOLY: + ctx.close_path() + convert_path = staticmethod(convert_path) + + def draw_path(self, gc, path, transform, rgbFace=None): ctx = gc.ctx - ctx.save() - ctx.translate(x, self.height - y) - ctx.rotate(rotation) - ctx.scale(width / 2.0, height / 2.0) - ctx.new_sub_path() - ctx.arc(0.0, 0.0, 1.0, npy.pi * angle1 / 180., - npy.pi * angle2 / 180.) - ctx.restore() + ctx.new_path() + transform = transform + \ + Affine2D().scale(1.0, -1.0).translate(0, self.height) + tpath = transform.transform_path(path) + + self.convert_path(ctx, tpath) - self._fill_and_stroke (ctx, rgbFace) + self._fill_and_stroke(ctx, rgbFace) + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): + ctx = gc.ctx + ctx.new_path() + marker_trans = marker_trans + Affine2D().scale(1.0, -1.0) + tmarker_path = marker_trans.transform_path(marker_path) + + trans = trans + Affine2D().scale(1.0, -1.0).translate(0, self.height) + tpath = trans.transform_path(path) + for x, y in tpath.vertices: + ctx.save() + ctx.translate(x, y) + self.convert_path(ctx, tmarker_path) + self._fill_and_stroke(ctx, rgbFace) + ctx.restore() def draw_image(self, x, y, im, bbox): # bbox - not currently used @@ -158,118 +188,6 @@ im.flipud_out() - - def draw_line(self, gc, x1, y1, x2, y2): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - ctx = gc.ctx - ctx.new_path() - ctx.move_to (x1, self.height - y1) - ctx.line_to (x2, self.height - y2) - self._fill_and_stroke (ctx, None) - - - def draw_lines(self, gc, x, y, transform=None): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - - if transform: - if transform.need_nonlinear(): - x, y = transform.nonlinear_only_numerix(x, y) - x, y = transform.numerix_x_y(x, y) - - ctx = gc.ctx - matrix_old = ctx.get_matrix() - ctx.set_matrix (self.matrix_flipy) - - points = izip(x,y) - x, y = points.next() - ctx.new_path() - ctx.move_to (x, y) - - for x,y in points: - ctx.line_to (x, y) - self._fill_and_stroke (ctx, None) - - ctx.set_matrix (matrix_old) - - - def draw_markers_OLD(self, gc, path, rgbFace, x, y, transform): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - - ctx = gc.ctx - - if transform.need_nonlinear(): - x,y = transform.nonlinear_only_numerix(x, y) - - x, y = transform.numerix_x_y(x, y) # do nonlinear and affine transform - - # TODO - use cairo transform - # matrix worked for dotted lines, but not markers in line_styles.py - # it upsets/transforms generate_path() ? - # need to flip y too, and update generate_path() ? - # the a,b,c,d,tx,ty affine which transforms x and y - #vec6 = transform.as_vec6_val() # not used (yet) - #matrix_old = ctx.get_matrix() - #ctx.set_matrix (cairo.Matrix (*vec6)) - - path_list = [path.vertex() for i in range(path.total_vertices())] - - def generate_path (path_list): - for code, xp, yp in path_list: - if code == agg.path_cmd_move_to: - ctx.move_to (xp, -yp) - elif code == agg.path_cmd_line_to: - ctx.line_to (xp, -yp) - elif code == agg.path_cmd_end_poly: - ctx.close_path() - - for x,y in izip(x,y): - ctx.save() - ctx.new_path() - ctx.translate(x, self.height - y) - generate_path (path_list) - - self._fill_and_stroke (ctx, rgbFace) - - ctx.restore() # undo translate() - - #ctx.set_matrix(matrix_old) - - - def draw_point(self, gc, x, y): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - # render by drawing a 0.5 radius circle - ctx = gc.ctx - ctx.new_path() - ctx.arc (x, self.height - y, 0.5, 0, 2*npy.pi) - self._fill_and_stroke (ctx, gc.get_rgb()) - - - def draw_polygon(self, gc, rgbFace, points): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - - ctx = gc.ctx - matrix_old = ctx.get_matrix() - ctx.set_matrix (self.matrix_flipy) - - ctx.new_path() - x, y = points[0] - ctx.move_to (x, y) - for x,y in points[1:]: - ctx.line_to (x, y) - ctx.close_path() - - self._fill_and_stroke (ctx, rgbFace) - - ctx.set_matrix (matrix_old) - - def draw_rectangle(self, gc, rgbFace, x, y, width, height): - if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - ctx = gc.ctx - ctx.new_path() - ctx.rectangle (x, self.height - y - height, width, height) - self._fill_and_stroke (ctx, rgbFace) - - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): # Note: x,y are device/display coords, not user-coords, unlike other # draw_* methods @@ -287,7 +205,7 @@ self.fontweights[prop.get_weight()]) # size = prop.get_size_in_points() * self.dpi.get() / 96.0 - size = prop.get_size_in_points() * self.dpi.get() / 72.0 + size = prop.get_size_in_points() * self.dpi / 72.0 ctx.save() if angle: @@ -301,7 +219,7 @@ ctx = gc.ctx width, height, descent, glyphs, rects = self.mathtext_parser.parse( - s, self.dpi.get(), prop) + s, self.dpi, prop) ctx.save() ctx.translate(x, y) @@ -319,7 +237,7 @@ self.fontweights[fontProp.weight]) # size = prop.get_size_in_points() * self.dpi.get() / 96.0 - size = fontsize * self.dpi.get() / 72.0 + size = fontsize * self.dpi / 72.0 ctx.set_font_size(size) ctx.show_text(s.encode("utf-8")) ctx.restore() @@ -349,7 +267,7 @@ if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) if ismath: width, height, descent, fonts, used_characters = self.mathtext_parser.parse( - s, self.dpi.get(), prop) + s, self.dpi, prop) return width, height, descent ctx = self.text_ctx @@ -362,7 +280,7 @@ # but if /96.0 is used the font is too small #size = prop.get_size_in_points() * self.dpi.get() / 96.0 - size = prop.get_size_in_points() * self.dpi.get() / 72.0 + size = prop.get_size_in_points() * self.dpi / 72.0 # problem - scale remembers last setting and font can become # enormous causing program to crash @@ -384,7 +302,7 @@ def points_to_pixels(self, points): if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) - return points/72.0 * self.dpi.get() + return points/72.0 * self.dpi class GraphicsContextCairo(GraphicsContextBase): @@ -428,7 +346,7 @@ def set_clip_rectangle(self, rectangle): self._cliprect = rectangle - x,y,w,h = rectangle + x,y,w,h = rectangle.bounds # pixel-aligned clip-regions are faster x,y,w,h = round(x), round(y), round(w), round(h) ctx = self.ctx @@ -439,6 +357,17 @@ # in fill_and_stroke() inside ctx.save() ... ctx.restore() + def set_clip_path(self, path): + if path is not None: + tpath, affine = path.get_transformed_path_and_affine() + ctx = self.ctx + ctx.new_path() + affine = affine + Affine2D().scale(1.0, -1.0).translate(0.0, self.renderer.height) + tpath = affine.transform_path(tpath) + RendererCairo.convert_path(ctx, tpath) + ctx.clip() + + def set_dashes(self, offset, dashes): self._dashes = offset, dashes if dashes == None: @@ -450,12 +379,17 @@ def set_foreground(self, fg, isRGB=None): GraphicsContextBase.set_foreground(self, fg, isRGB) - self.ctx.set_source_rgb(*self._rgb) + if len(self._rgb) == 3: + self.ctx.set_source_rgb(*self._rgb) + else: + self.ctx.set_source_rgba(*self._rgb) - def set_graylevel(self, frac): GraphicsContextBase.set_graylevel(self, frac) - self.ctx.set_source_rgb(*self._rgb) + if len(self._rgb) == 3: + self.ctx.set_source_rgb(*self._rgb) + else: + self.ctx.set_source_rgba(*self._rgb) def set_joinstyle(self, js): Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-11-07 20:38:46 UTC (rev 4153) +++ branches/transforms/lib/matplotlib/path.py 2007-11-07 21:20:45 UTC (rev 4154) @@ -209,8 +209,11 @@ """ vertices = simple_linear_interpolation(self.vertices, steps) codes = self.codes - new_codes = Path.LINETO * npy.ones(((len(codes) - 1) * steps + 1, )) - new_codes[0::steps] = codes + if codes is not None: + new_codes = Path.LINETO * npy.ones(((len(codes) - 1) * steps + 1, )) + new_codes[0::steps] = codes + else: + new_codes = None return Path(vertices, new_codes) _unit_rectangle = None This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-07 20:38:49
|
Revision: 4153 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4153&view=rev Author: mdboom Date: 2007-11-07 12:38:46 -0800 (Wed, 07 Nov 2007) Log Message: ----------- Update to use modern Numpy C API Modified Paths: -------------- branches/transforms/src/_backend_agg.cpp branches/transforms/src/_path.cpp Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-07 20:13:35 UTC (rev 4152) +++ branches/transforms/src/_backend_agg.cpp 2007-11-07 20:38:46 UTC (rev 4153) @@ -280,7 +280,7 @@ if (bbox_obj.ptr() != Py_None) { bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { + if (!bbox || PyArray_NDIM(bbox) != 2 || PyArray_DIM(bbox, 0) != 2 || PyArray_DIM(bbox, 1) != 2) { Py_XDECREF(bbox); throw Py::TypeError ("Expected a Bbox object."); @@ -942,23 +942,23 @@ try { offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); if (!offsets || - (offsets->nd == 2 && offsets->dimensions[1] != 2) || - (offsets->nd == 1 && offsets->dimensions[0])) { + (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || + (PyArray_NDIM(offsets) == 1 && PyArray_DIM(offsets, 0) != 0)) { throw Py::ValueError("Offsets array must be Nx2"); } PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject (facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); if (!facecolors || - (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || - (facecolors->nd == 2 && facecolors->dimensions[1] != 4)) + (PyArray_NDIM(facecolors) == 1 && PyArray_DIM(facecolors, 0) != 0) || + (PyArray_NDIM(facecolors) == 2 && PyArray_DIM(facecolors, 1) != 4)) throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty"); PyArrayObject* edgecolors = (PyArrayObject*)PyArray_FromObject (edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); if (!edgecolors || - (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || - (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) + (PyArray_NDIM(edgecolors) == 1 && PyArray_DIM(edgecolors, 0) != 0) || + (PyArray_NDIM(edgecolors) == 2 && PyArray_DIM(edgecolors, 1) != 4)) throw Py::ValueError("Edgecolors must be a Nx4 numpy array"); size_t Npaths = path_generator.num_paths(); @@ -1178,11 +1178,11 @@ throw Py::ValueError("Invalid coordinates array."); } - Py::Tuple shape(3); - shape[0] = Py::Int((int)meshHeight + 1); - shape[1] = Py::Int((int)meshWidth + 1); - shape[2] = Py::Int(2); - m_coordinates = (PyArrayObject*)PyArray_Reshape(coordinates_array, shape.ptr()); + PyArray_Dims shape; + npy_intp dims[] = { meshHeight + 1, meshWidth + 1, 2 }; + shape.ptr = dims; + shape.len = 3; + m_coordinates = (PyArrayObject*)PyArray_Newshape(coordinates_array, &shape, PyArray_CORDER); } inline ~QuadMeshGenerator() { @@ -1237,13 +1237,13 @@ if (showedges) { int dims[] = { 1, 4, 0 }; double data[] = { 0, 0, 0, 1 }; - edgecolors_obj = PyArray_FromDimsAndData(2, dims, PyArray_DOUBLE, (char*)data); + edgecolors_obj = PyArray_SimpleNewFromData(2, dims, PyArray_DOUBLE, (char*)data); } else { if (antialiased) { edgecolors_obj = facecolors_obj; } else { int dims[] = { 0, 0 }; - edgecolors_obj = PyArray_FromDims(1, dims, PyArray_DOUBLE); + edgecolors_obj = PyArray_SimpleNew(1, dims, PyArray_DOUBLE); } } Modified: branches/transforms/src/_path.cpp =================================================================== --- branches/transforms/src/_path.cpp 2007-11-07 20:13:35 UTC (rev 4152) +++ branches/transforms/src/_path.cpp 2007-11-07 20:38:46 UTC (rev 4153) @@ -263,8 +263,8 @@ try { offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); if (!offsets || - (offsets->nd == 2 && offsets->dimensions[1] != 2) || - (offsets->nd == 1 && offsets->dimensions[0])) { + (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || + (PyArray_NDIM(offsets) == 1 && PyArray_DIM(offsets, 0) != 0)) { throw Py::ValueError("Offsets array must be Nx2"); } @@ -338,9 +338,12 @@ agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); bool filled = Py::Int(args[8]); - PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!offsets || offsets->dimensions[1] != 2) + PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); + if (!offsets || + (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || + (PyArray_NDIM(offsets) == 1 && PyArray_DIM(offsets, 0) != 0)) { throw Py::ValueError("Offsets array must be Nx2"); + } size_t Npaths = paths.length(); size_t Noffsets = offsets->dimensions[0]; @@ -360,17 +363,24 @@ } Py::List result; + agg::trans_affine trans; for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); - - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - offset_trans.transform(&xo, &yo); - agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine trans = transforms[i % Ntransforms]; - trans *= transOffset; + if (Ntransforms) { + trans = transforms[i % Ntransforms]; + } else { + trans = master_transform; + } + + if (Noffsets) { + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + trans *= agg::trans_affine_translation(xo, yo); + } + if (filled) { if (::point_in_path(x, y, path, trans)) result.append(Py::Int((int)i)); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-07 20:13:38
|
Revision: 4152 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4152&view=rev Author: mdboom Date: 2007-11-07 12:13:35 -0800 (Wed, 07 Nov 2007) Log Message: ----------- Further speed improvements. Quadmesh extension code (still not as fast as the old version, for various reasons.) Fix bugs in quadmesh masking in PDF and PS backends. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/lines.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h branches/transforms/src/agg_py_path_iterator.h Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/axes.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -4788,7 +4788,8 @@ vmax = kwargs.pop('vmax', None) shading = kwargs.pop('shading', 'flat') edgecolors = kwargs.pop('edgecolors', 'None') - + antialiased = kwargs.pop('antialiased', False) + X, Y, C = self._pcolorargs('pcolormesh', *args) Ny, Nx = X.shape @@ -4807,7 +4808,7 @@ showedges = 0 collection = mcoll.QuadMesh( - Nx - 1, Ny - 1, coords, showedges) # kwargs are not used + Nx - 1, Ny - 1, coords, showedges, antialiased=antialiased) # kwargs are not used collection.set_alpha(alpha) collection.set_array(C) if norm is not None: assert(isinstance(norm, mcolors.Normalize)) Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -9,6 +9,7 @@ import numpy as npy import matplotlib.cbook as cbook import matplotlib.colors as colors +import matplotlib.path as path import matplotlib.transforms as transforms import matplotlib.widgets as widgets from matplotlib import rcParams @@ -75,7 +76,31 @@ path, transform = path_id transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo) self.draw_path(gc, path, transform, rgbFace) + + def draw_quad_mesh(self, master_transform, cliprect, clippath, + clippath_trans, meshWidth, meshHeight, coordinates, + offsets, offsetTrans, facecolors, antialiased, + showedges): + """ + This provides a fallback implementation of draw_quad_mesh that + generates paths and then calls draw_path_collection. + """ + from matplotlib.collections import QuadMesh + paths = QuadMesh.convert_mesh_to_paths( + meshWidth, meshHeight, coordinates) + + if showedges: + edgecolors = npy.array([[0.0, 0.0, 0.0, 1.0]], npy.float_) + linewidths = npy.array([1.0], npy.float_) + else: + edgecolors = linewidths = npy.array([], npy.float_) + linewidths = npy.array([0.0], npy.float_) + return self.draw_path_collection( + master_transform, cliprect, clippath, clippath_trans, + paths, [], offsets, offsetTrans, facecolors, edgecolors, + linewidths, [], [antialiased]) + def _iter_collection_raw_paths(self, master_transform, paths, all_transforms): """ This is a helper method (along with _iter_collection) to make @@ -158,6 +183,9 @@ if Nfacecolors == 0: rgbFace = None + if Nedgecolors == 0: + gc.set_linewidth(0.0) + xo, yo = 0, 0 for i in xrange(N): path_id = path_ids[i % Npaths] Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -66,6 +66,7 @@ self.draw_path = self._renderer.draw_path self.draw_markers = self._renderer.draw_markers self.draw_path_collection = self._renderer.draw_path_collection + self.draw_quad_mesh = self._renderer.draw_quad_mesh self.draw_image = self._renderer.draw_image self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -993,7 +993,7 @@ rgba = npy.fromstring(s, npy.uint8) rgba.shape = (h, w, 4) - rgb = rgba[:,:,:3] + rgb = rgba[:,:,:4] return h, w, rgb.tostring() def _gray(self, im, rc=0.3, gc=0.59, bc=0.11): @@ -1601,10 +1601,12 @@ return `d` def _strokep(self): - return self._linewidth > 0 and self._alpha > 0 + return (self._linewidth > 0 and self._alpha > 0 and + (len(self._rgb) <= 3 or self._rgb[3] != 0.0)) def _fillp(self): - return self._fillcolor is not None or self._hatch + return ((self._fillcolor is not None or self._hatch) and + (len(self._fillcolor) <= 3 or self._fillcolor[3] != 0.0)) def close_and_paint(self): if self._strokep(): Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -745,14 +745,20 @@ if debugPS and command: write("% "+command+"\n") - self.set_linewidth(gc.get_linewidth()) - jint = gc.get_joinstyle() - self.set_linejoin(jint) - cint = gc.get_capstyle() - self.set_linecap(cint) - self.set_linedash(*gc.get_dashes()) - if self.linewidth > 0 and stroke: - self.set_color(*gc.get_rgb()[:3]) + stroke = (stroke and gc.get_linewidth() > 0.0 and + (len(gc.get_rgb()) <= 3 or gc.get_rgb()[3] != 0.0)) + fill = (fill and rgbFace is not None and + (len(rgbFace) <= 3 or rgbFace[3] != 0.0)) + + if stroke: + self.set_linewidth(gc.get_linewidth()) + jint = gc.get_joinstyle() + self.set_linejoin(jint) + cint = gc.get_capstyle() + self.set_linecap(cint) + self.set_linedash(*gc.get_dashes()) + if self.linewidth > 0 and stroke: + self.set_color(*gc.get_rgb()[:3]) cliprect = gc.get_clip_rectangle() if cliprect: @@ -767,7 +773,7 @@ write(ps.strip()) write("\n") - if rgbFace is not None and fill: + if fill: #print 'rgbface', rgbFace write("gsave\n") self.set_color(store=0, *rgbFace[:3]) Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/collections.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -376,53 +376,89 @@ at mesh coordinates (0, 0), then the one at (0, 1), then at (0, 2) .. (0, meshWidth), (1, 0), (1, 1), and so on. """ - def __init__(self, meshWidth, meshHeight, coordinates, showedges): - Path = mpath.Path - + def __init__(self, meshWidth, meshHeight, coordinates, showedges, antialiased=True): Collection.__init__(self) self._meshWidth = meshWidth self._meshHeight = meshHeight self._coordinates = coordinates self._showedges = showedges + self._antialiased = antialiased + self._paths = None + + self._bbox = transforms.Bbox.unit() + self._bbox.update_from_data_xy(coordinates.reshape( + ((meshWidth + 1) * (meshHeight + 1), 2))) + + def get_paths(self, dataTrans=None): + import pdb + pdb.set_trace() + if self._paths is None: + self._paths = self.convert_mesh_to_paths( + self._meshWidth, self._meshHeight, self._coordinates) + return self._paths + + #@staticmethod + def convert_mesh_to_paths(meshWidth, meshHeight, coordinates): + Path = mpath.Path + c = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) # We could let the Path constructor generate the codes for us, # but this is faster, since we know they'll always be the same codes = npy.array( [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY], Path.code_type) - + points = npy.concatenate(( - c[0:-1, 0:-1], - c[0:-1, 1: ], - c[1: , 1: ], - c[1: , 0:-1], - c[0:-1, 0:-1] - ), axis=2) + c[0:-1, 0:-1], + c[0:-1, 1: ], + c[1: , 1: ], + c[1: , 0:-1], + c[0:-1, 0:-1] + ), axis=2) points = points.reshape((meshWidth * meshHeight, 5, 2)) - self._paths = [Path(x, codes) for x in points] - - self._bbox = transforms.Bbox.unit() - self._bbox.update_from_data_xy(c.reshape( - ((meshWidth + 1) * (meshHeight + 1), 2))) - - def get_paths(self, dataTrans=None): - return self._paths - + return [Path(x, codes) for x in points] + convert_mesh_to_paths = staticmethod(convert_mesh_to_paths) + def get_datalim(self, transData): return self._bbox def draw(self, renderer): - self.update_scalarmappable() + if not self.get_visible(): return + renderer.open_group(self.__class__.__name__) + transform = self.get_transform() + transOffset = self._transOffset + offsets = self._offsets - self._linewidths = (1,) - if self._showedges: - self._edgecolors = npy.array([[0.0, 0.0, 0.0, 1.0]], npy.float_) + if self.have_units(): + if len(self._offsets): + xs = self.convert_xunits(self._offsets[:0]) + ys = self.convert_yunits(self._offsets[:1]) + offsets = zip(xs, ys) + + if len(offsets) == 0: + offsets = npy.array([], npy.float_) else: - self._edgecolors = self._facecolors + offsets = npy.asarray(offsets, npy.float_) - Collection.draw(self, renderer) + self.update_scalarmappable() + clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + if clippath_trans is not None: + clippath_trans = clippath_trans.frozen() + + assert transform.is_affine + if not transOffset.is_affine: + offsets = transOffset.transform_non_affine(offsets) + transOffset = transOffset.get_affine() + + renderer.draw_quad_mesh( + transform.frozen(), self.clipbox, clippath, clippath_trans, + self._meshWidth, self._meshHeight, self._coordinates, + offsets, transOffset, self._facecolors, self._antialiased, + self._showedges) + renderer.close_group(self.__class__.__name__) + class PolyCollection(Collection): def __init__(self, verts, **kwargs): """ Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/lines.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -388,8 +388,10 @@ not_masked += 1 if (not_masked < 2 or - ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or - (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): + (x is not self._xorig and + (x.shape != self._xorig.shape or npy.any(x != self._xorig))) or + (y is not self._yorig and + (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): self._xorig = x self._yorig = y self.recache() Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/src/_backend_agg.cpp 2007-11-07 20:13:35 UTC (rev 4152) @@ -302,7 +302,7 @@ template<class R> void -RendererAgg::set_clipbox(Py::Object& cliprect, R rasterizer) { +RendererAgg::set_clipbox(const Py::Object& cliprect, R rasterizer) { //set the clip rectangle from the gc _VERBOSE("RendererAgg::set_clipbox"); @@ -775,10 +775,11 @@ return Py::Object(); } -void RendererAgg::_draw_path(PathIterator& path, agg::trans_affine trans, +template<class PathIteratorType> +void RendererAgg::_draw_path(PathIteratorType& path, agg::trans_affine trans, bool has_clippath, const facepair_t& face, - const GCAgg& gc) { - typedef agg::conv_transform<PathIterator> transformed_path_t; + const GCAgg& gc, bool check_snap) { + typedef agg::conv_transform<PathIteratorType> transformed_path_t; typedef conv_quantize<transformed_path_t> quantize_t; typedef agg::conv_curve<quantize_t> curve_t; typedef agg::conv_stroke<curve_t> stroke_t; @@ -793,7 +794,9 @@ trans *= agg::trans_affine_translation(0.0, (double)height); // Build the transform stack - bool snap = should_snap(path, trans); + bool snap = false; + if (check_snap) + snap = should_snap(path, trans); transformed_path_t tpath(path, trans); quantize_t quantized(tpath, snap); // Benchmarking shows that there is no noticable slowdown to always @@ -908,31 +911,28 @@ set_clipbox(gc.cliprect, theRasterizer); bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans); - _draw_path(path, trans, has_clippath, face, gc); + _draw_path(path, trans, has_clippath, face, gc, true); return Py::Object(); } +template<class PathGenerator> Py::Object -RendererAgg::draw_path_collection(const Py::Tuple& args) { - _VERBOSE("RendererAgg::draw_path_collection"); - args.verify_length(13); - - //segments, trans, clipbox, colors, linewidths, antialiaseds - agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); - Py::Object cliprect = args[1]; - Py::Object clippath = args[2]; - agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); - Py::SeqBase<Py::Object> paths = args[4]; - Py::SeqBase<Py::Object> transforms_obj = args[5]; - Py::Object offsets_obj = args[6]; - agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); - Py::Object facecolors_obj = args[8]; - Py::Object edgecolors_obj = args[9]; - Py::SeqBase<Py::Float> linewidths = args[10]; - Py::SeqBase<Py::Object> linestyles_obj = args[11]; - Py::SeqBase<Py::Int> antialiaseds = args[12]; - +RendererAgg::_draw_path_collection_generic + (const agg::trans_affine& master_transform, + const Py::Object& cliprect, + const Py::Object& clippath, + const agg::trans_affine& clippath_trans, + const PathGenerator& path_generator, + const Py::SeqBase<Py::Object>& transforms_obj, + const Py::Object& offsets_obj, + const agg::trans_affine& offset_trans, + const Py::Object& facecolors_obj, + const Py::Object& edgecolors_obj, + const Py::SeqBase<Py::Float>& linewidths, + const Py::SeqBase<Py::Object>& linestyles_obj, + const Py::SeqBase<Py::Int>& antialiaseds, + bool check_snap) { GCAgg gc(dpi); PyArrayObject* offsets = NULL; @@ -961,7 +961,7 @@ (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) throw Py::ValueError("Edgecolors must be a Nx4 numpy array"); - size_t Npaths = paths.length(); + size_t Npaths = path_generator.num_paths(); size_t Noffsets = offsets->dimensions[0]; size_t N = std::max(Npaths, Noffsets); size_t Ntransforms = std::min(transforms_obj.length(), N); @@ -1010,7 +1010,7 @@ agg::trans_affine trans; for (i = 0; i < N; ++i) { - PathIterator path(paths[i % Npaths]); + typename PathGenerator::path_iterator path = path_generator(i); if (Ntransforms) { trans = transforms[i % Ntransforms]; } else { @@ -1038,14 +1038,20 @@ *(double*)PyArray_GETPTR2(edgecolors, ei, 1), *(double*)PyArray_GETPTR2(edgecolors, ei, 2), *(double*)PyArray_GETPTR2(edgecolors, ei, 3)); - gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; - gc.dashes = dashes[i % Nlinestyles].second; - gc.dashOffset = dashes[i % Nlinestyles].first; + if (Nlinewidths) { + gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; + } else { + gc.linewidth = 1.0; + } + if (Nlinestyles) { + gc.dashes = dashes[i % Nlinestyles].second; + gc.dashOffset = dashes[i % Nlinestyles].first; + } } gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - _draw_path(path, trans, has_clippath, face, gc); + _draw_path(path, trans, has_clippath, face, gc, check_snap); } } catch (...) { Py_XDECREF(offsets); @@ -1059,12 +1065,213 @@ } +class PathListGenerator { + const Py::SeqBase<Py::Object>& m_paths; + +public: + typedef PathIterator path_iterator; + + inline PathListGenerator(const Py::SeqBase<Py::Object>& paths) : + m_paths(paths) { + + } + + inline size_t num_paths() const { + return m_paths.size(); + } + + inline path_iterator operator()(size_t i) const { + return PathIterator(m_paths[i]); + } +}; + Py::Object +RendererAgg::draw_path_collection(const Py::Tuple& args) { + _VERBOSE("RendererAgg::draw_path_collection"); + args.verify_length(13); + + //segments, trans, clipbox, colors, linewidths, antialiaseds + agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); + Py::Object cliprect = args[1]; + Py::Object clippath = args[2]; + agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); + Py::SeqBase<Py::Object> paths = args[4]; + Py::SeqBase<Py::Object> transforms_obj = args[5]; + Py::Object offsets_obj = args[6]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); + Py::Object facecolors_obj = args[8]; + Py::Object edgecolors_obj = args[9]; + Py::SeqBase<Py::Float> linewidths = args[10]; + Py::SeqBase<Py::Object> linestyles_obj = args[11]; + Py::SeqBase<Py::Int> antialiaseds = args[12]; + + PathListGenerator path_generator(paths); + + _draw_path_collection_generic + (master_transform, + cliprect, + clippath, + clippath_trans, + path_generator, + transforms_obj, + offsets_obj, + offset_trans, + facecolors_obj, + edgecolors_obj, + linewidths, + linestyles_obj, + antialiaseds, + true); + + return Py::Object(); +} + +class QuadMeshGenerator { + size_t m_meshWidth; + size_t m_meshHeight; + PyArrayObject* m_coordinates; + + class QuadMeshPathIterator { + size_t m_iterator; + size_t m_m, m_n; + PyArrayObject* m_coordinates; + public: + QuadMeshPathIterator(size_t m, size_t n, PyArrayObject* coordinates) : + m_iterator(0), m_m(m), m_n(n), m_coordinates(coordinates) { + } + + static const size_t offsets[5][2]; + + inline unsigned vertex(unsigned idx, double* x, double* y) { + size_t m = m_m + offsets[idx][0]; + size_t n = m_n + offsets[idx][1]; + *x = *(double*)PyArray_GETPTR3(m_coordinates, m, n, 0); + *y = *(double*)PyArray_GETPTR3(m_coordinates, m, n, 1); + return (idx == 0) ? agg::path_cmd_move_to : agg::path_cmd_line_to; + } + + inline unsigned vertex(double* x, double* y) { + if (m_iterator >= total_vertices()) return agg::path_cmd_stop; + return vertex(m_iterator++, x, y); + } + + inline void rewind(unsigned path_id) { + m_iterator = path_id; + } + + inline unsigned total_vertices() { + return 5; + } + + inline bool has_curves() { + return false; + } + }; + +public: + typedef QuadMeshPathIterator path_iterator; + + inline QuadMeshGenerator(size_t meshWidth, size_t meshHeight, const Py::Object& coordinates) : + m_meshWidth(meshWidth), m_meshHeight(meshHeight), m_coordinates(NULL) { + PyArrayObject* coordinates_array = (PyArrayObject*)PyArray_FromObject(coordinates.ptr(), PyArray_DOUBLE, 1, 3); + if (!coordinates_array) { + throw Py::ValueError("Invalid coordinates array."); + } + + Py::Tuple shape(3); + shape[0] = Py::Int((int)meshHeight + 1); + shape[1] = Py::Int((int)meshWidth + 1); + shape[2] = Py::Int(2); + m_coordinates = (PyArrayObject*)PyArray_Reshape(coordinates_array, shape.ptr()); + } + + inline ~QuadMeshGenerator() { + Py_XDECREF(m_coordinates); + } + + inline size_t num_paths() const { + return m_meshWidth * m_meshHeight; + } + + inline path_iterator operator()(size_t i) const { + return QuadMeshPathIterator(i % m_meshHeight, i / m_meshHeight, m_coordinates); + } +}; + +const size_t QuadMeshGenerator::QuadMeshPathIterator::offsets[5][2] = { + { 0, 0 }, + { 0, 1 }, + { 1, 1 }, + { 1, 0 }, + { 0, 0 } }; + +Py::Object +RendererAgg::draw_quad_mesh(const Py::Tuple& args) { + _VERBOSE("RendererAgg::draw_quad_mesh"); + args.verify_length(12); + + //segments, trans, clipbox, colors, linewidths, antialiaseds + agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); + Py::Object cliprect = args[1]; + Py::Object clippath = args[2]; + agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); + size_t mesh_width = Py::Int(args[4]); + size_t mesh_height = Py::Int(args[5]); + Py::Object coordinates = args[6]; + Py::Object offsets_obj = args[7]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[8]); + Py::Object facecolors_obj = args[9]; + bool antialiased = (bool)Py::Int(args[10]); + bool showedges = (bool)Py::Int(args[11]); + + QuadMeshGenerator path_generator(mesh_width, mesh_height, coordinates); + + Py::SeqBase<Py::Object> transforms_obj; + Py::Object edgecolors_obj; + Py::Tuple linewidths(1); + linewidths[0] = Py::Float(1.0); + Py::SeqBase<Py::Object> linestyles_obj; + Py::Tuple antialiaseds(1); + antialiaseds[0] = Py::Int(antialiased ? 1 : 0); + + if (showedges) { + int dims[] = { 1, 4, 0 }; + double data[] = { 0, 0, 0, 1 }; + edgecolors_obj = PyArray_FromDimsAndData(2, dims, PyArray_DOUBLE, (char*)data); + } else { + if (antialiased) { + edgecolors_obj = facecolors_obj; + } else { + int dims[] = { 0, 0 }; + edgecolors_obj = PyArray_FromDims(1, dims, PyArray_DOUBLE); + } + } + + _draw_path_collection_generic + (master_transform, + cliprect, + clippath, + clippath_trans, + path_generator, + transforms_obj, + offsets_obj, + offset_trans, + facecolors_obj, + edgecolors_obj, + linewidths, + linestyles_obj, + antialiaseds, + false); + + return Py::Object(); +} + +Py::Object RendererAgg::write_rgba(const Py::Tuple& args) { _VERBOSE("RendererAgg::write_rgba"); args.verify_length(1); - std::string fname = Py::String( args[0]); + std::string fname = Py::String(args[0]); std::ofstream of2( fname.c_str(), std::ios::binary|std::ios::out); for (size_t i=0; i<NUMBYTES; i++) { @@ -1073,7 +1280,6 @@ return Py::Object(); } - // this code is heavily adapted from the paint license, which is in // the file paint.license (BSD compatible) included in this // distribution. TODO, add license file to MANIFEST.in and CVS @@ -1398,6 +1604,8 @@ "draw_path(gc, path, transform, rgbFace)\n"); add_varargs_method("draw_path_collection", &RendererAgg::draw_path_collection, "draw_path_collection(master_transform, cliprect, clippath, clippath_trans, paths, transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds)\n"); + add_varargs_method("draw_quad_mesh", &RendererAgg::draw_quad_mesh, + "draw_quad_mesh(master_transform, cliprect, clippath, clippath_trans, meshWidth, meshHeight, coordinates, offsets, offsetTrans, facecolors, antialiaseds, showedges)\n"); add_varargs_method("draw_markers", &RendererAgg::draw_markers, "draw_markers(gc, marker_path, marker_trans, path, rgbFace)\n"); add_varargs_method("draw_text_image", &RendererAgg::draw_text_image, Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/src/_backend_agg.h 2007-11-07 20:13:35 UTC (rev 4152) @@ -165,7 +165,9 @@ Py::Object draw_image(const Py::Tuple & args); Py::Object draw_path(const Py::Tuple & args); Py::Object draw_path_collection(const Py::Tuple & args); + Py::Object RendererAgg::draw_quad_mesh(const Py::Tuple& args); + Py::Object write_rgba(const Py::Tuple & args); Py::Object write_png(const Py::Tuple & args); Py::Object tostring_rgb(const Py::Tuple & args); @@ -215,10 +217,28 @@ facepair_t _get_rgba_face(const Py::Object& rgbFace, double alpha); bool bbox_to_rect(const Py::Object& bbox, double* l, double* b, double* r, double* t); template<class R> - void set_clipbox(Py::Object& cliprect, R rasterizer); + void set_clipbox(const Py::Object& cliprect, R rasterizer); bool render_clippath(const Py::Object& clippath, const agg::trans_affine& clippath_trans); - void _draw_path(PathIterator& path, agg::trans_affine trans, - bool has_clippath, const facepair_t& face, const GCAgg& gc); + template<class PathIteratorType> + void _draw_path(PathIteratorType& path, agg::trans_affine trans, + bool has_clippath, const facepair_t& face, const GCAgg& gc, bool check_snap); + template<class PathGenerator> + Py::Object + _draw_path_collection_generic + (const agg::trans_affine& master_transform, + const Py::Object& cliprect, + const Py::Object& clippath, + const agg::trans_affine& clippath_trans, + const PathGenerator& path_finder, + const Py::SeqBase<Py::Object>& transforms_obj, + const Py::Object& offsets_obj, + const agg::trans_affine& offset_trans, + const Py::Object& facecolors_obj, + const Py::Object& edgecolors_obj, + const Py::SeqBase<Py::Float>& linewidths, + const Py::SeqBase<Py::Object>& linestyles_obj, + const Py::SeqBase<Py::Int>& antialiaseds, + bool check_snap); private: Py::Object lastclippath; Modified: branches/transforms/src/agg_py_path_iterator.h =================================================================== --- branches/transforms/src/agg_py_path_iterator.h 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/src/agg_py_path_iterator.h 2007-11-07 20:13:35 UTC (rev 4152) @@ -7,35 +7,35 @@ #include "agg_path_storage.h" class PathIterator { - PyArrayObject* vertices; - PyArrayObject* codes; + PyArrayObject* m_vertices; + PyArrayObject* m_codes; size_t m_iterator; size_t m_total_vertices; public: PathIterator(const Py::Object& path_obj) : - vertices(NULL), codes(NULL), m_iterator(0) { + m_vertices(NULL), m_codes(NULL), m_iterator(0) { Py::Object vertices_obj = path_obj.getAttr("vertices"); Py::Object codes_obj = path_obj.getAttr("codes"); - vertices = (PyArrayObject*)PyArray_FromObject + m_vertices = (PyArrayObject*)PyArray_FromObject (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) + if (!m_vertices || m_vertices->nd != 2 || m_vertices->dimensions[1] != 2) throw Py::ValueError("Invalid vertices array."); if (codes_obj.ptr() != Py_None) { - codes = (PyArrayObject*)PyArray_FromObject + m_codes = (PyArrayObject*)PyArray_FromObject (codes_obj.ptr(), PyArray_UINT8, 1, 1); - if (!codes) + if (!m_codes) throw Py::ValueError("Invalid codes array."); } - m_total_vertices = vertices->dimensions[0]; + m_total_vertices = m_vertices->dimensions[0]; } ~PathIterator() { - Py_XDECREF(vertices); - Py_XDECREF(codes); + Py_XDECREF(m_vertices); + Py_XDECREF(m_codes); } static const char code_map[]; @@ -43,10 +43,10 @@ inline unsigned vertex(unsigned idx, double* x, double* y) { if (idx > m_total_vertices) throw Py::RuntimeError("Requested vertex past end"); - *x = *(double*)PyArray_GETPTR2(vertices, idx, 0); - *y = *(double*)PyArray_GETPTR2(vertices, idx, 1); - if (codes) { - return code_map[(int)*(char *)PyArray_GETPTR1(codes, idx)]; + *x = *(double*)PyArray_GETPTR2(m_vertices, idx, 0); + *y = *(double*)PyArray_GETPTR2(m_vertices, idx, 1); + if (m_codes) { + return code_map[(int)*(char *)PyArray_GETPTR1(m_codes, idx)]; } else { return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to; } @@ -64,6 +64,10 @@ inline unsigned total_vertices() { return m_total_vertices; } + + inline bool has_curves() { + return m_codes; + } }; // Maps path codes on the Python side to agg path commands This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 18:34:32
|
Revision: 4151 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4151&view=rev Author: jswhit Date: 2007-11-07 10:34:30 -0800 (Wed, 07 Nov 2007) Log Message: ----------- update Copyright Modified Paths: -------------- trunk/toolkits/basemap-testing/README Modified: trunk/toolkits/basemap-testing/README =================================================================== --- trunk/toolkits/basemap-testing/README 2007-11-07 18:30:09 UTC (rev 4150) +++ trunk/toolkits/basemap-testing/README 2007-11-07 18:34:30 UTC (rev 4151) @@ -32,9 +32,10 @@ http://www.ngdc.noaa.gov/seg/cdroms/graham/graham/graham.htm is included. -Everything else (include src/pyproj.pyx and src/pyproj.c): +Everything else (including src/_proj.pyx, src/_geod.pyx, src/_pyproj.pxi, +src/_proj.c and src/_geod.c): -copyright (c) 2004 by Jeffrey Whitaker. +copyright (c) 2007 by Jeffrey Whitaker. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 18:30:17
|
Revision: 4150 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4150&view=rev Author: jswhit Date: 2007-11-07 10:30:09 -0800 (Wed, 07 Nov 2007) Log Message: ----------- add Shapely as a Requirement. Modified Paths: -------------- trunk/toolkits/basemap-testing/README Modified: trunk/toolkits/basemap-testing/README =================================================================== --- trunk/toolkits/basemap-testing/README 2007-11-07 18:23:26 UTC (rev 4149) +++ trunk/toolkits/basemap-testing/README 2007-11-07 18:30:09 UTC (rev 4150) @@ -1,13 +1,20 @@ **Descripton** -basemap.py - plot on map projections (with coastlines and political boundaries) +basemap - plot on map projections (with coastlines and political boundaries) using matplotlib. **Requirements** matplotlib 0.90 (or higher) + numpy 1.0 (or higher) +Shapely (http://trac.gispython.org/projects/PCL/wiki/Shapely - svn version) + +Shapely requires libgoes_c version 2.2.3, available from +http://geos.refractions.net/, and ctypes (which comes with python >= 2.5, +but can be installed separately for python 2.4) + **Copyright** source code from proj.4 (http://proj.maptools.org) is included in the @@ -53,15 +60,12 @@ **Install** -To install from source, download basemap-X.Y.Z.tar.gz from +First, install pre-requisites (see **Requirements** above). + +Then download basemap-X.Y.Z.tar.gz from the sourceforge download site, unpack, cd to basemap-X.Y.Z and run 'python setup.py install'. -Binary, double-clickable installers are also provided for MacOS X and -Windows. The Mac installers have a .dmg file extension, the Windows -installers have a .exe extension. Windows users will probably prefer -s option, since it is non-trivial to build C extensions for python on Windows. - The crude ('c'), low ('l') and intermediate ('i') resolution boundary data files, plus the 5-minute land/sea mask, are installed by default. If you need the high ('h') resolution boundary dataset This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 18:23:27
|
Revision: 4149 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4149&view=rev Author: jswhit Date: 2007-11-07 10:23:26 -0800 (Wed, 07 Nov 2007) Log Message: ----------- use nice colors for ocean and land Modified Paths: -------------- trunk/toolkits/basemap-testing/examples/hires.py Modified: trunk/toolkits/basemap-testing/examples/hires.py =================================================================== --- trunk/toolkits/basemap-testing/examples/hires.py 2007-11-07 18:21:35 UTC (rev 4148) +++ trunk/toolkits/basemap-testing/examples/hires.py 2007-11-07 18:23:26 UTC (rev 4149) @@ -4,6 +4,8 @@ # create new figure fig=figure() +# background color will be used for 'wet' areas. +fig.add_axes([0.1,0.1,0.8,0.8],axisbg='aqua') # create Basemap instance. Use 'high' resolution coastlines. t1 = time.clock() m = Basemap(llcrnrlon=-11.,llcrnrlat=49.,urcrnrlon=5.,urcrnrlat=59., @@ -11,7 +13,7 @@ print 'time to create instance with high-res boundaries = ',time.clock()-t1 # draw coastlines and fill continents. m.drawcoastlines() -m.fillcontinents() +m.fillcontinents(color='coral') # draw political boundaries. m.drawcountries(linewidth=1) # draw major rivers. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 18:21:36
|
Revision: 4148 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4148&view=rev Author: jswhit Date: 2007-11-07 10:21:35 -0800 (Wed, 07 Nov 2007) Log Message: ----------- add hires.py example. Modified Paths: -------------- trunk/toolkits/basemap-testing/examples/README Modified: trunk/toolkits/basemap-testing/examples/README =================================================================== --- trunk/toolkits/basemap-testing/examples/README 2007-11-07 18:19:18 UTC (rev 4147) +++ trunk/toolkits/basemap-testing/examples/README 2007-11-07 18:21:35 UTC (rev 4148) @@ -22,6 +22,9 @@ nytolondon.py shows how to draw a great circle on a map (NY to London) +hires.py illustrates the use of the optional high-resolution coastlines, by +drawing the coastlines, political boundaries and rivers of the British Isles. + ireland.py draws maps of ireland with the crude, low and intermediate resolution boundary datasets. Also does high res coastlines if they are installed. Shows how to pickle and re-load a This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 18:19:19
|
Revision: 4147 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4147&view=rev Author: jswhit Date: 2007-11-07 10:19:18 -0800 (Wed, 07 Nov 2007) Log Message: ----------- update high-res dataset install instructions. Modified Paths: -------------- trunk/toolkits/basemap-testing/README Modified: trunk/toolkits/basemap-testing/README =================================================================== --- trunk/toolkits/basemap-testing/README 2007-11-07 18:13:25 UTC (rev 4146) +++ trunk/toolkits/basemap-testing/README 2007-11-07 18:19:18 UTC (rev 4147) @@ -66,10 +66,14 @@ boundary data files, plus the 5-minute land/sea mask, are installed by default. If you need the high ('h') resolution boundary dataset you can download the files from the sourceforge download site -(basemap-data-hires-X.Y.Z.tar.gz) and manually install them. -To see where basemap expects them to be installed, run -python -c "from matplotlib.toolkits.basemap import basemap_datadir; print basemap_datadir". +(basemap-data-hires-X.Y.Z.tar.gz). To install them, +untar the file in the top-level directory of the basemap source +distribution (where this README file lives), then run +'python setup.py install' again. +Note: if you install from a subversion checkout, you will get the high +resolution coastlines by default. + **Contact** Jeff Whitaker <jef...@no...> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 18:13:32
|
Revision: 4146 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4146&view=rev Author: jswhit Date: 2007-11-07 10:13:25 -0800 (Wed, 07 Nov 2007) Log Message: ----------- updated for new boundary files Modified Paths: -------------- trunk/toolkits/basemap-testing/MANIFEST.in Modified: trunk/toolkits/basemap-testing/MANIFEST.in =================================================================== --- trunk/toolkits/basemap-testing/MANIFEST.in 2007-11-07 16:42:46 UTC (rev 4145) +++ trunk/toolkits/basemap-testing/MANIFEST.in 2007-11-07 18:13:25 UTC (rev 4146) @@ -73,6 +73,6 @@ include pyshapelib/shapelib/*.c pyshapelib/shapelib/*.h include MANIFEST.in include lib/matplotlib/toolkits/basemap/data/5minmask.bin -include lib/matplotlib/toolkits/basemap/data/*_c.txt -include lib/matplotlib/toolkits/basemap/data/*_l.txt -include lib/matplotlib/toolkits/basemap/data/*_i.txt +include lib/matplotlib/toolkits/basemap/data/*_c.dat +include lib/matplotlib/toolkits/basemap/data/*_l.dat +include lib/matplotlib/toolkits/basemap/data/*_i.dat This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 16:42:54
|
Revision: 4145 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4145&view=rev Author: jswhit Date: 2007-11-07 08:42:46 -0800 (Wed, 07 Nov 2007) Log Message: ----------- remove debug code Modified Paths: -------------- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 16:25:58 UTC (rev 4144) +++ trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 16:42:46 UTC (rev 4145) @@ -18,7 +18,6 @@ from shapely.geometry import LineString as LineShape from shapely.geometry import Point as PointShape from shapely import wkb -import time # basemap data files now installed in lib/matplotlib/toolkits/basemap/data basemap_datadir = os.sep.join([os.path.dirname(__file__), 'data']) @@ -744,7 +743,6 @@ bdatmetafile = open(os.path.join(basemap_datadir,name+'meta_'+self.resolution+'.dat'),'r') except: raise IOError, msg - timetot = 0. polygons = [] polygon_types = [] # see if map projection region polygon contains a pole. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 16:26:10
|
Revision: 4144 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4144&view=rev Author: jswhit Date: 2007-11-07 08:25:58 -0800 (Wed, 07 Nov 2007) Log Message: ----------- fix Antarctic polygon closing code Modified Paths: -------------- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 16:12:57 UTC (rev 4143) +++ trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 16:25:58 UTC (rev 4144) @@ -813,6 +813,8 @@ lons.append(lonend) lats.append(-90.) poly = PolygonShape(zip(lons,lats)) + else: + continue # if polygon instersects map projection # region, process it. if poly.intersects(boundarypolyll): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 16:13:00
|
Revision: 4143 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4143&view=rev Author: jswhit Date: 2007-11-07 08:12:57 -0800 (Wed, 07 Nov 2007) Log Message: ----------- optimize code for closing Antarctica Modified Paths: -------------- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 15:31:37 UTC (rev 4142) +++ trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 16:12:57 UTC (rev 4143) @@ -18,6 +18,7 @@ from shapely.geometry import LineString as LineShape from shapely.geometry import Point as PointShape from shapely import wkb +import time # basemap data files now installed in lib/matplotlib/toolkits/basemap/data basemap_datadir = os.sep.join([os.path.dirname(__file__), 'data']) @@ -743,6 +744,7 @@ bdatmetafile = open(os.path.join(basemap_datadir,name+'meta_'+self.resolution+'.dat'),'r') except: raise IOError, msg + timetot = 0. polygons = [] polygon_types = [] # see if map projection region polygon contains a pole. @@ -792,29 +794,25 @@ # coordinates (this saves time, especially for small map # regions and high-resolution boundary geometries). if not containsPole: - # close Antarctica. for projections in which this - # is necessary. - if name == 'gshhs': + # close Antarctica. + if name == 'gshhs' and south < -68: b = npy.asarray(poly.boundary) lons = b[:,0] lats = b[:,1] - if south < -68: - if math.fabs(lons[0]+0.) < 1.e-5: - lons1 = lons[:-2][::-1] - lats1 = lats[:-2][::-1] - lons2 = lons1 + 360. - lons3 = lons2 + 360. - lons = lons1.tolist()+lons2.tolist()+lons3.tolist() - lats = lats1.tolist()+lats1.tolist()+lats1.tolist() - lonstart,latstart = lons[0], lats[0] - lonend,latend = lons[-1], lats[-1] - lons.insert(0,lonstart) - lats.insert(0,-90.) - lons.append(lonend) - lats.append(-90.) - poly = PolygonShape(zip(lons,lats)) - else: - continue + if math.fabs(lons[0]+0.) < 1.e-5: + lons1 = lons[:-2][::-1] + lats1 = lats[:-2][::-1] + lons2 = lons1 + 360. + lons3 = lons2 + 360. + lons = lons1.tolist()+lons2.tolist()+lons3.tolist() + lats = lats1.tolist()+lats1.tolist()+lats1.tolist() + lonstart,latstart = lons[0], lats[0] + lonend,latend = lons[-1], lats[-1] + lons.insert(0,lonstart) + lats.insert(0,-90.) + lons.append(lonend) + lats.append(-90.) + poly = PolygonShape(zip(lons,lats)) # if polygon instersects map projection # region, process it. if poly.intersects(boundarypolyll): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-07 15:31:40
|
Revision: 4142 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4142&view=rev Author: mdboom Date: 2007-11-07 07:31:37 -0800 (Wed, 07 Nov 2007) Log Message: ----------- Further speed improvements. For collections, now has faster ignoring of elements that aren't provided, such as offsets. Paths now do not even store the "default" codes array -- which is MOVETO followed by N LINETOs. These are generated automatically by the iterators if no codes array is provided. (Should also result in significant memory savings for graphs with many points.) Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_path.cpp branches/transforms/src/agg_py_path_iterator.h Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/lib/matplotlib/axes.py 2007-11-07 15:31:37 UTC (rev 4142) @@ -4697,7 +4697,6 @@ kwargs.setdefault('edgecolors', edgecolors) kwargs.setdefault('antialiaseds', (0,)) kwargs.setdefault('linewidths', (0.25,)) - kwargs['closed'] = False collection = mcoll.PolyCollection(verts, **kwargs) Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 15:31:37 UTC (rev 4142) @@ -99,13 +99,12 @@ if Npaths == 0: return + transform = transforms.IdentityTransform() for i in xrange(N): path = paths[i % Npaths] - transform = all_transforms[i % Ntransforms] - if transform is None: - transform = transforms.IdentityTransform() - transform += master_transform - yield path, transform + if Ntransforms: + transform = all_transforms[i % Ntransforms] + yield path, transform + master_transform def _iter_collection(self, path_ids, cliprect, clippath, clippath_trans, offsets, offsetTrans, facecolors, edgecolors, @@ -146,8 +145,8 @@ if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: return - - toffsets = offsetTrans.transform(offsets) + if Noffsets: + toffsets = offsetTrans.transform(offsets) gc = self.new_gc() @@ -159,9 +158,11 @@ if Nfacecolors == 0: rgbFace = None + xo, yo = 0, 0 for i in xrange(N): path_id = path_ids[i % Npaths] - xo, yo = toffsets[i % Noffsets] + if Noffsets: + xo, yo = toffsets[i % Noffsets] if Nfacecolors: rgbFace = facecolors[i % Nfacecolors] if Nedgecolors: Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/lib/matplotlib/collections.py 2007-11-07 15:31:37 UTC (rev 4142) @@ -51,9 +51,9 @@ draw time a call to scalar mappable will be made to set the face colors. """ - _offsets = npy.zeros((1, 2)) + _offsets = npy.array([], npy.float_) _transOffset = transforms.IdentityTransform() - _transforms = [None] + _transforms = [] zorder = 1 def __init__(self, @@ -93,7 +93,7 @@ self._antialiaseds = self._get_value(antialiaseds) self._uniform_offsets = None - self._offsets = npy.zeros((1, 2)) + self._offsets = npy.array([], npy.float_) if offsets is not None: offsets = npy.asarray(offsets, npy.float_) if len(offsets.shape) == 1: @@ -135,10 +135,11 @@ if not transOffset.is_affine: offsets = transOffset.transform_non_affine(offsets) transOffset = transOffset.get_affine() - + offsets = npy.asarray(offsets, npy.float_) + result = mpath.get_path_collection_extents( transform.frozen(), paths, self.get_transforms(), - npy.asarray(offsets, npy.float_), transOffset.frozen()) + offsets, transOffset.frozen()) result = result.inverse_transformed(transData) return result @@ -158,12 +159,12 @@ xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) paths.append(mpath.Path(zip(xs, ys), path.codes)) - if self._offsets is not None: + if len(self._offsets): xs = self.convert_xunits(self._offsets[:0]) ys = self.convert_yunits(self._offsets[:1]) offsets = zip(xs, ys) if len(offsets) == 0: - offsets = npy.zeros((1, 2)) + offsets = npy.array([], npy.float_) else: offsets = npy.asarray(offsets, npy.float_) @@ -384,27 +385,33 @@ self._coordinates = coordinates self._showedges = showedges - # MGDTODO: Is it possible to Numpify this? - coordinates = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) - c = coordinates - paths = [] + c = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) # We could let the Path constructor generate the codes for us, # but this is faster, since we know they'll always be the same - codes = npy.array([Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - for m in xrange(meshHeight): - for n in xrange(meshWidth): - paths.append(Path( - [c[m , n], - c[m , n+1], - c[m+1, n+1], - c[m+1, n], - c[m , n]], - codes)) - self._paths = paths + codes = npy.array( + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY], + Path.code_type) + + points = npy.concatenate(( + c[0:-1, 0:-1], + c[0:-1, 1: ], + c[1: , 1: ], + c[1: , 0:-1], + c[0:-1, 0:-1] + ), axis=2) + points = points.reshape((meshWidth * meshHeight, 5, 2)) + self._paths = [Path(x, codes) for x in points] + + self._bbox = transforms.Bbox.unit() + self._bbox.update_from_data_xy(c.reshape( + ((meshWidth + 1) * (meshHeight + 1), 2))) def get_paths(self, dataTrans=None): return self._paths + def get_datalim(self, transData): + return self._bbox + def draw(self, renderer): self.update_scalarmappable() @@ -425,14 +432,13 @@ %(Collection)s """ - self.closed = kwargs.pop("closed", True) Collection.__init__(self,**kwargs) self.set_verts(verts) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def set_verts(self, verts): '''This allows one to delay initialization of the vertices.''' - self._paths = [mpath.Path(v, closed=self.closed) for v in verts] + self._paths = [mpath.Path(v) for v in verts] def get_paths(self): return self._paths Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/lib/matplotlib/lines.py 2007-11-07 15:31:37 UTC (rev 4142) @@ -928,7 +928,7 @@ path, path_trans) - _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]], closed=False) + _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) def _draw_caretdown(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/lib/matplotlib/patches.py 2007-11-07 15:31:37 UTC (rev 4142) @@ -530,7 +530,7 @@ See Patch documentation for additional kwargs """ Patch.__init__(self, **kwargs) - self._path = Path(xy, closed=True) + self._path = Path(xy) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): @@ -539,7 +539,7 @@ def _get_xy(self): return self._path.vertices def _set_xy(self, vertices): - self._path = Path(vertices, closed=True) + self._path = Path(vertices) xy = property(_get_xy, _set_xy) class Wedge(Patch): Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/lib/matplotlib/path.py 2007-11-07 15:31:37 UTC (rev 4142) @@ -53,6 +53,12 @@ CLOSEPOLY : 1 vertex (ignored) Draw a line segment to the start point of the current polyline. + + Users of Path objects should not access the vertices and codes + arrays directly. Instead, they should use iter_segments to get + the vertex/code pairs. This is important since many Paths do not + store a codes array at all, but have a default one provided for + them by iter_segments. """ # Path codes @@ -67,10 +73,7 @@ code_type = npy.uint8 - _open_codes_cache = WeakValueDictionary() - _closed_codes_cache = WeakValueDictionary() - - def __init__(self, vertices, codes=None, closed=False): + def __init__(self, vertices, codes=None): """ Create a new path with the given vertices and codes. @@ -87,43 +90,17 @@ dimension. If codes is None, vertices will be treated as a series of line - segments. Additionally, if closed is also True, the polyline - will closed. If vertices contains masked values, the - resulting path will be compressed, with MOVETO codes inserted - in the correct places to jump over the masked regions. + segments. If vertices contains masked values, the resulting + path will be compressed, with MOVETO codes inserted in the + correct places to jump over the masked regions. """ if ma.isMaskedArray(vertices): mask = ma.getmask(vertices) else: vertices = npy.asarray(vertices, npy.float_) mask = ma.nomask - - if codes is None: - if closed: - # MGDTODO: Remove me once efficiency concerns are - # taken care of. - warnings.warn(""" -EFFICIENCY CONCERN: Having the Path constructor create a closed -polyline automatically is not always the most efficient way to do -things, since it causes a memory copy of the vertices array. If the -caller can easily close the polygon itself it should do so. -""") - codes = self._closed_codes_cache.get(len(vertices)) - if codes is None: - codes = self.LINETO * npy.ones( - vertices.shape[0] + 1, self.code_type) - codes[0] = self.MOVETO - codes[-1] = self.CLOSEPOLY - self._closed_codes_cache[len(vertices)] = codes - vertices = npy.concatenate((vertices, [vertices[0]])) - else: - codes = self._open_codes_cache.get(len(vertices)) - if codes is None: - codes = self.LINETO * npy.ones( - vertices.shape[0], self.code_type) - codes[0] = self.MOVETO - self._open_codes_cache[len(vertices)] = codes - else: + + if codes is not None: codes = npy.asarray(codes, self.code_type) assert codes.ndim == 1 assert len(codes) == len(vertices) @@ -136,6 +113,10 @@ if mask is not ma.nomask: mask1d = ma.mask_or(mask[:, 0], mask[:, 1]) vertices = ma.compress(npy.invert(mask1d), vertices, 0) + if codes is None: + codes = self.LINETO * npy.ones( + vertices.shape[0], self.code_type) + codes[0] = self.MOVETO codes = npy.where(npy.concatenate((mask1d[-1:], mask1d[:-1])), self.MOVETO, codes) codes = ma.masked_array(codes, mask=mask1d).compressed() @@ -144,23 +125,15 @@ assert vertices.ndim == 2 assert vertices.shape[1] == 2 - self._codes = codes - self._vertices = vertices + self.codes = codes + self.vertices = vertices def __repr__(self): return "Path(%s, %s)" % (self.vertices, self.codes) def __len__(self): - return len(self._vertices) + return len(self.vertices) - def _get_codes(self): - return self._codes - codes = property(_get_codes) - - def _get_vertices(self): - return self._vertices - vertices = property(_get_vertices) - def iter_segments(self): """ Iterates over all of the endpoints in the path. Unlike @@ -171,18 +144,28 @@ NUM_VERTICES = self.NUM_VERTICES vertices = self.vertices codes = self.codes + + if not len(vertices): + return - while i < len(vertices): - code = codes[i] - if code == self.CLOSEPOLY: - yield [], code - i += 1 - elif code == self.STOP: - return - else: - num_vertices = NUM_VERTICES[code] - yield vertices[i:i+num_vertices].flatten(), code - i += num_vertices + if codes is None: + code = self.MOVETO + yield vertices[0], self.MOVETO + i = 1 + for v in vertices[1:]: + yield v, self.LINETO + else: + while i < len(vertices): + code = codes[i] + if code == self.CLOSEPOLY: + yield [], code + i += 1 + elif code == self.STOP: + return + else: + num_vertices = NUM_VERTICES[code] + yield vertices[i:i+num_vertices].flatten(), code + i += num_vertices def transformed(self, transform): """ @@ -242,7 +225,7 @@ return cls._unit_rectangle unit_rectangle = classmethod(unit_rectangle) - _unit_regular_polygons = {} + _unit_regular_polygons = WeakValueDictionary() #@classmethod def unit_regular_polygon(cls, numVertices): """ @@ -262,7 +245,7 @@ return path unit_regular_polygon = classmethod(unit_regular_polygon) - _unit_regular_stars = {} + _unit_regular_stars = WeakValueDictionary() #@classmethod def unit_regular_star(cls, numVertices, innerCircle=0.5): """ @@ -413,6 +396,7 @@ return Path(vertices, codes) arc = classmethod(arc) + #@classmethod def wedge(cls, theta1, theta2): """ Returns a wedge of the unit circle from angle theta1 to angle Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/src/_backend_agg.cpp 2007-11-07 15:31:37 UTC (rev 4142) @@ -940,9 +940,12 @@ PyArrayObject* edgecolors = NULL; try { - offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!offsets || offsets->dimensions[1] != 2) + offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); + if (!offsets || + (offsets->nd == 2 && offsets->dimensions[1] != 2) || + (offsets->nd == 1 && offsets->dimensions[0])) { throw Py::ValueError("Offsets array must be Nx2"); + } PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject (facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); @@ -1004,14 +1007,22 @@ gc.linewidth = 0.0; facepair_t face; face.first = Nfacecolors != 0; - + agg::trans_affine trans; + for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - offset_trans.transform(&xo, &yo); - agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine& trans = transforms[i % Ntransforms]; + if (Ntransforms) { + trans = transforms[i % Ntransforms]; + } else { + trans = master_transform; + } + + if (Noffsets) { + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + trans *= agg::trans_affine_translation(xo, yo); + } if (Nfacecolors) { size_t fi = i % Nfacecolors; @@ -1034,7 +1045,7 @@ gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - _draw_path(path, trans * transOffset, has_clippath, face, gc); + _draw_path(path, trans, has_clippath, face, gc); } } catch (...) { Py_XDECREF(offsets); Modified: branches/transforms/src/_path.cpp =================================================================== --- branches/transforms/src/_path.cpp 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/src/_path.cpp 2007-11-07 15:31:37 UTC (rev 4142) @@ -261,9 +261,12 @@ double x0, y0, x1, y1; try { - offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!offsets || offsets->dimensions[1] != 2) + offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); + if (!offsets || + (offsets->nd == 2 && offsets->dimensions[1] != 2) || + (offsets->nd == 1 && offsets->dimensions[0])) { throw Py::ValueError("Offsets array must be Nx2"); + } size_t Npaths = paths.length(); size_t Noffsets = offsets->dimensions[0]; @@ -287,16 +290,23 @@ y0 = std::numeric_limits<double>::infinity(); x1 = -std::numeric_limits<double>::infinity(); y1 = -std::numeric_limits<double>::infinity(); + agg::trans_affine trans; + for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); - - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - offset_trans.transform(&xo, &yo); - agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine trans = transforms[i % Ntransforms]; - trans *= transOffset; + if (Ntransforms) { + trans = transforms[i % Ntransforms]; + } else { + trans = master_transform; + } + if (Noffsets) { + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + trans *= agg::trans_affine_translation(xo, yo); + } + ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); } } catch (...) { Modified: branches/transforms/src/agg_py_path_iterator.h =================================================================== --- branches/transforms/src/agg_py_path_iterator.h 2007-11-07 15:30:25 UTC (rev 4141) +++ branches/transforms/src/agg_py_path_iterator.h 2007-11-07 15:31:37 UTC (rev 4142) @@ -23,15 +23,14 @@ if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) throw Py::ValueError("Invalid vertices array."); - codes = (PyArrayObject*)PyArray_FromObject - (codes_obj.ptr(), PyArray_UINT8, 1, 1); - if (!codes) - throw Py::ValueError("Invalid codes array."); - - if (codes->dimensions[0] != vertices->dimensions[0]) - throw Py::ValueError("vertices and codes arrays are not the same length."); + if (codes_obj.ptr() != Py_None) { + codes = (PyArrayObject*)PyArray_FromObject + (codes_obj.ptr(), PyArray_UINT8, 1, 1); + if (!codes) + throw Py::ValueError("Invalid codes array."); + } - m_total_vertices = codes->dimensions[0]; + m_total_vertices = vertices->dimensions[0]; } ~PathIterator() { @@ -46,7 +45,11 @@ throw Py::RuntimeError("Requested vertex past end"); *x = *(double*)PyArray_GETPTR2(vertices, idx, 0); *y = *(double*)PyArray_GETPTR2(vertices, idx, 1); - return code_map[(int)*(char *)PyArray_GETPTR1(codes, idx)]; + if (codes) { + return code_map[(int)*(char *)PyArray_GETPTR1(codes, idx)]; + } else { + return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to; + } } inline unsigned vertex(double* x, double* y) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 15:30:27
|
Revision: 4141 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4141&view=rev Author: jswhit Date: 2007-11-07 07:30:25 -0800 (Wed, 07 Nov 2007) Log Message: ----------- use npy.sum, not built-in sum Modified Paths: -------------- trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 13:11:15 UTC (rev 4140) +++ trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 15:30:25 UTC (rev 4141) @@ -1317,10 +1317,10 @@ test2 = npy.fabs(xa-self.llcrnrx) < delx test3 = npy.fabs(ya-self.urcrnry) < dely test4 = npy.fabs(ya-self.llcrnry) < dely - hasp1 = sum(test1*test3) - hasp2 = sum(test2*test3) - hasp4 = sum(test2*test4) - hasp3 = sum(test1*test4) + hasp1 = npy.sum(test1*test3) + hasp2 = npy.sum(test2*test3) + hasp4 = npy.sum(test2*test4) + hasp3 = npy.sum(test1*test4) if not hasp1 or not hasp2 or not hasp3 or not hasp4: xy = zip(xa.tolist(),ya.tolist()) if self.coastpolygontypes[np] != 2: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 13:11:21
|
Revision: 4140 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4140&view=rev Author: jswhit Date: 2007-11-07 05:11:15 -0800 (Wed, 07 Nov 2007) Log Message: ----------- add to list of projections that can't cross pole, close Antarctica for all that don't. Modified Paths: -------------- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 12:56:23 UTC (rev 4139) +++ trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 13:11:15 UTC (rev 4140) @@ -754,12 +754,9 @@ hasSP = boundarypolyxy.contains(SPole) containsPole = hasNP or hasSP # these projections cannot cross pole. - if containsPole and self.projection in ['tmerc','cass','omerc','merc']: + if containsPole and\ + self.projection in ['tmerc','cass','omerc','merc','mill','cyl','robin','moll','sinu','geos']: raise ValueError('%s projection cannot cross pole'%(self.projection)) - # make sure geostationary projection has containsPole=False - # even if only a limited area is requested (since entire - # disk will be used to subset boundary geometries). - if self.projection == 'geos': containsPole = False # make sure orthographic projection has containsPole=True # we will compute the intersections in stereographic # coordinates, then transform to orthographic. @@ -795,9 +792,9 @@ # coordinates (this saves time, especially for small map # regions and high-resolution boundary geometries). if not containsPole: - # close Antarctica for projections in which this + # close Antarctica. for projections in which this # is necessary. - if name == 'gshhs' and self.projection in ['cyl','merc','mill','moll','robin','sinu','geos','tmerc','cass','omerc']: + if name == 'gshhs': b = npy.asarray(poly.boundary) lons = b[:,0] lats = b[:,1] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 12:56:28
|
Revision: 4139 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4139&view=rev Author: jswhit Date: 2007-11-07 04:56:23 -0800 (Wed, 07 Nov 2007) Log Message: ----------- fix tmerc example so it doesn't cross pole. Modified Paths: -------------- trunk/toolkits/basemap-testing/examples/test.py Modified: trunk/toolkits/basemap-testing/examples/test.py =================================================================== --- trunk/toolkits/basemap-testing/examples/test.py 2007-11-07 12:55:37 UTC (rev 4138) +++ trunk/toolkits/basemap-testing/examples/test.py 2007-11-07 12:56:23 UTC (rev 4139) @@ -160,8 +160,8 @@ # create new figure fig=figure() # setup transverse mercator basemap. -m = Basemap(llcrnrlon=170.,llcrnrlat=-45,urcrnrlon=10.,urcrnrlat=45.,\ - resolution='c',area_thresh=10000.,projection='tmerc',\ +m = Basemap(width=2*6370997,height=3.1*6370997,\ + resolution='c',area_thresh=10000.,projection='cass',\ lat_0=0.,lon_0=-90.) fig.add_axes([0.125,0.2,0.6,0.6]) # transform to nx x ny regularly spaced native projection grid This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-07 12:55:41
|
Revision: 4138 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4138&view=rev Author: jswhit Date: 2007-11-07 04:55:37 -0800 (Wed, 07 Nov 2007) Log Message: ----------- some projections should never cross pole. Modified Paths: -------------- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-06 23:03:21 UTC (rev 4137) +++ trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-07 12:55:37 UTC (rev 4138) @@ -749,9 +749,13 @@ NPole = PointShape(self(0.,90.)) SPole = PointShape(self(0.,-90.)) boundarypolyxy = self._boundarypolyxy + boundarypolyll = self._boundarypolyll hasNP = boundarypolyxy.contains(NPole) hasSP = boundarypolyxy.contains(SPole) containsPole = hasNP or hasSP + # these projections cannot cross pole. + if containsPole and self.projection in ['tmerc','cass','omerc','merc']: + raise ValueError('%s projection cannot cross pole'%(self.projection)) # make sure geostationary projection has containsPole=False # even if only a limited area is requested (since entire # disk will be used to subset boundary geometries). @@ -769,7 +773,6 @@ b = npy.asarray(self._boundarypolyll.boundary) blons = b[:,0]; blats = b[:,1] boundarypolyxy = PolygonShape(zip(*maptran(blons,blats))) - # iterate over boundary geometries. for line in bdatmetafile: linesplit = line.split() area = float(linesplit[1]) @@ -794,7 +797,7 @@ if not containsPole: # close Antarctica for projections in which this # is necessary. - if name == 'gshhs' and self.projection in ['cyl','merc','mill','moll','robin','sinu','geos']: + if name == 'gshhs' and self.projection in ['cyl','merc','mill','moll','robin','sinu','geos','tmerc','cass','omerc']: b = npy.asarray(poly.boundary) lons = b[:,0] lats = b[:,1] @@ -817,8 +820,8 @@ continue # if polygon instersects map projection # region, process it. - if poly.intersects(self._boundarypolyll): - poly = poly.intersection(self._boundarypolyll) + if poly.intersects(boundarypolyll): + poly = poly.intersection(boundarypolyll) # create iterable object with geometries # that intersect map region. if hasattr(poly,'geoms'): @@ -887,17 +890,15 @@ continue # create a Line object for other geometries. poly = LineShape(zip(bx,by)) - # if polygon instersects map projection - # region, process it. - if not npy.sum(badmask) and boundarypolyxy.intersects(poly): - #print poly.is_valid, poly.geom_type - #import pylab - #a = npy.asarray(boundarypolyxy.boundary) - #b = npy.asarray(poly.boundary) - #pylab.plot(a[:,0],a[:,1],'b') - #pylab.plot(b[:,0],b[:,1],'b') - #pylab.show() - poly = boundarypolyxy.intersection(poly) + # if geometry instersects map projection + # region, and doesn't have any invalid points, process it. + if not badmask.any() and boundarypolyxy.intersects(poly): + # if geometry intersection calculation fails, + # just skip this polygon. + try: + poly = boundarypolyxy.intersection(poly) + except: + continue # create iterable object with geometries # that intersect map region. if hasattr(poly,'geoms'): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-11-06 23:03:23
|
Revision: 4137 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4137&view=rev Author: jswhit Date: 2007-11-06 15:03:21 -0800 (Tue, 06 Nov 2007) Log Message: ----------- fix Antarctica for 'geos' projection, use npy.sum not python built-in, refine checks for bad polygons to avoid 'Bus errors' in ctypes libgeos interface. Modified Paths: -------------- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-06 21:33:37 UTC (rev 4136) +++ trunk/toolkits/basemap-testing/lib/matplotlib/toolkits/basemap/basemap.py 2007-11-06 23:03:21 UTC (rev 4137) @@ -792,9 +792,9 @@ # coordinates (this saves time, especially for small map # regions and high-resolution boundary geometries). if not containsPole: - # close Antarctica for cylindrical and - # pseudo-cylindrical projections. - if name == 'gshhs' and self.projection in ['cyl','merc','mill','moll','robin','sinu']: + # close Antarctica for projections in which this + # is necessary. + if name == 'gshhs' and self.projection in ['cyl','merc','mill','moll','robin','sinu','geos']: b = npy.asarray(poly.boundary) lons = b[:,0] lats = b[:,1] @@ -818,10 +818,7 @@ # if polygon instersects map projection # region, process it. if poly.intersects(self._boundarypolyll): - try: - poly = poly.intersection(self._boundarypolyll) - except: - continue + poly = poly.intersection(self._boundarypolyll) # create iterable object with geometries # that intersect map region. if hasattr(poly,'geoms'): @@ -866,10 +863,11 @@ bx, by = maptran(blons, blats) else: bx, by = self(blons, blats) - mask = npy.logical_and(bx<1.e20,by<1.e20) + goodmask = npy.logical_and(bx<1.e20,by<1.e20) + badmask = npy.logical_or(bx>1.e20,by>1.e20) # if less than two points are valid in # map proj coords, skip this geometry. - if sum(mask) <= 1: continue + if npy.sum(goodmask) <= 1: continue if name == 'gshhs': # create a polygon object for coastline # geometry. @@ -878,8 +876,8 @@ # if not a polygon, # just remove parts of geometry that are undefined # in this map projection. - bx = npy.compress(mask, bx) - by = npy.compress(mask, by) + bx = npy.compress(goodmask, bx) + by = npy.compress(goodmask, by) # for orthographic projection, all points # outside map projection region are eliminated # with the above step, so we're done. @@ -891,11 +889,15 @@ poly = LineShape(zip(bx,by)) # if polygon instersects map projection # region, process it. - if boundarypolyxy.intersects(poly): - try: - poly = boundarypolyxy.intersection(poly) - except: - continue + if not npy.sum(badmask) and boundarypolyxy.intersects(poly): + #print poly.is_valid, poly.geom_type + #import pylab + #a = npy.asarray(boundarypolyxy.boundary) + #b = npy.asarray(poly.boundary) + #pylab.plot(a[:,0],a[:,1],'b') + #pylab.plot(b[:,0],b[:,1],'b') + #pylab.show() + poly = boundarypolyxy.intersection(poly) # create iterable object with geometries # that intersect map region. if hasattr(poly,'geoms'): @@ -1131,10 +1133,10 @@ test2 = npy.fabs(xa-self.llcrnrx) < delx test3 = npy.fabs(ya-self.urcrnry) < dely test4 = npy.fabs(ya-self.llcrnry) < dely - hasp1 = sum(test1*test3) - hasp2 = sum(test2*test3) - hasp4 = sum(test2*test4) - hasp3 = sum(test1*test4) + hasp1 = npy.sum(test1*test3) + hasp2 = npy.sum(test2*test3) + hasp4 = npy.sum(test2*test4) + hasp3 = npy.sum(test1*test4) if not hasp1 or not hasp2 or not hasp3 or not hasp4: xy = zip(xa.tolist(),ya.tolist()) if self.coastpolygontypes[np] != 2: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |