|
From: <ds...@us...> - 2008-07-17 12:47:44
|
Revision: 5772
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5772&view=rev
Author: dsdale
Date: 2008-07-17 12:47:22 +0000 (Thu, 17 Jul 2008)
Log Message:
-----------
Merged revisions 5771 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_91_maint
........
r5771 | dsdale | 2008-07-17 08:01:50 -0400 (Thu, 17 Jul 2008) | 2 lines
improve error reporting in texmanager
........
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/texmanager.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-5723
+ /branches/v0_91_maint:1-5771
Added: svn:mergeinfo
+ /branches/v0_91_maint:5753-5771
Modified: trunk/matplotlib/lib/matplotlib/texmanager.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/texmanager.py 2008-07-17 12:01:50 UTC (rev 5771)
+++ trunk/matplotlib/lib/matplotlib/texmanager.py 2008-07-17 12:47:22 UTC (rev 5772)
@@ -273,16 +273,22 @@
%(os.path.split(texfile)[-1], outfile))
mpl.verbose.report(command, 'debug')
exit_status = os.system(command)
- fh = file(outfile)
+ try:
+ fh = file(outfile)
+ report = fh.read()
+ fh.close()
+ except IOError:
+ report = 'No latex error report available.'
if exit_status:
raise RuntimeError(('LaTeX was not able to process the following \
-string:\n%s\nHere is the full report generated by LaTeX: \n\n'% repr(tex)) + fh.read())
- else: mpl.verbose.report(fh.read(), 'debug')
- fh.close()
+string:\n%s\nHere is the full report generated by LaTeX: \n\n'% repr(tex)) + report)
+ else: mpl.verbose.report(report, 'debug')
for fname in glob.glob(basefile+'*'):
if fname.endswith('dvi'): pass
elif fname.endswith('tex'): pass
- else: os.remove(fname)
+ else:
+ try: os.remove(fname)
+ except OSError: pass
return dvifile
@@ -305,14 +311,19 @@
os.path.split(dvifile)[-1], outfile))
mpl.verbose.report(command, 'debug')
exit_status = os.system(command)
- fh = file(outfile)
+ try:
+ fh = file(outfile)
+ report = fh.read()
+ fh.close()
+ except IOError:
+ report = 'No dvipng error report available.'
if exit_status:
raise RuntimeError('dvipng was not able to \
process the flowing file:\n%s\nHere is the full report generated by dvipng: \
-\n\n'% dvifile + fh.read())
- else: mpl.verbose.report(fh.read(), 'debug')
- fh.close()
- os.remove(outfile)
+\n\n'% dvifile + report)
+ else: mpl.verbose.report(report, 'debug')
+ try: os.remove(outfile)
+ except OSError: pass
return pngfile
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-07-17 17:40:49
|
Revision: 5775
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5775&view=rev
Author: mdboom
Date: 2008-07-17 17:40:47 +0000 (Thu, 17 Jul 2008)
Log Message:
-----------
Fix problem with NaNs at end of path.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/src/agg_py_path_iterator.h
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-17 17:16:12 UTC (rev 5774)
+++ trunk/matplotlib/CHANGELOG 2008-07-17 17:40:47 UTC (rev 5775)
@@ -1,3 +1,6 @@
+2008-07-17 Fix bug with NaNs at end of path (thanks, Andrew Straw for
+ the report) - MGD
+
2008-07-12 Added support for external backends with the
"module://my_backend" syntax - JDH
Modified: trunk/matplotlib/src/agg_py_path_iterator.h
===================================================================
--- trunk/matplotlib/src/agg_py_path_iterator.h 2008-07-17 17:16:12 UTC (rev 5774)
+++ trunk/matplotlib/src/agg_py_path_iterator.h 2008-07-17 17:40:47 UTC (rev 5775)
@@ -75,11 +75,13 @@
{
if (m_iterator >= m_total_vertices) return agg::path_cmd_stop;
unsigned code = vertex_with_code(m_iterator++, x, y);
- while ((MPL_isnan64(*x) || MPL_isnan64(*y)) &&
- m_iterator < m_total_vertices)
- {
+ if (MPL_isnan64(*x) || MPL_isnan64(*y)) {
+ do {
vertex(m_iterator++, x, y);
- code = agg::path_cmd_move_to;
+ } while ((MPL_isnan64(*x) || MPL_isnan64(*y)) &&
+ m_iterator < m_total_vertices);
+ return (m_iterator >= m_total_vertices) ? agg::path_cmd_stop :
+ agg::path_cmd_move_to;
}
return code;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-17 18:57:07
|
Revision: 5780
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5780&view=rev
Author: jdh2358
Date: 2008-07-17 18:56:48 +0000 (Thu, 17 Jul 2008)
Log Message:
-----------
some fixes for numpy svn deprecation warnings
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
trunk/matplotlib/lib/mpl_toolkits/exceltools.py
trunk/matplotlib/src/_path.cpp
trunk/matplotlib/src/_png.cpp
trunk/matplotlib/src/ft2font.cpp
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py 2008-07-17 18:27:36 UTC (rev 5779)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py 2008-07-17 18:56:48 UTC (rev 5780)
@@ -459,7 +459,8 @@
if Gcf.get_num_fig_managers()==0 and \
not matplotlib.is_interactive() and \
gtk.main_level() >= 1:
- gtk.main_quit()
+ #gtk.main_quit()
+ pass
def show(self):
# show the figure window
Modified: trunk/matplotlib/lib/mpl_toolkits/exceltools.py
===================================================================
--- trunk/matplotlib/lib/mpl_toolkits/exceltools.py 2008-07-17 18:27:36 UTC (rev 5779)
+++ trunk/matplotlib/lib/mpl_toolkits/exceltools.py 2008-07-17 18:56:48 UTC (rev 5780)
@@ -5,7 +5,7 @@
import matplotlib.mlab as mlab
import mpl_toolkits.exceltools as exceltools
-
+
r = mlab.csv2rec('somefile.csv', checkrows=0)
formatd = dict(
@@ -52,7 +52,7 @@
return format
-def rec2excel(r, ws, formatd=None, rownum=0, colnum=0):
+def rec2excel(r, ws, formatd=None, rownum=0, colnum=0, nanstr='NaN'):
"""
save record array r to excel pyExcelerator worksheet ws
starting at rownum. if ws is string like, assume it is a
@@ -62,6 +62,7 @@
formatd is a dictionary mapping dtype name -> mlab.Format instances
+ nanstr is the string that mpl will put into excel for np.nan value
The next rownum after writing is returned
"""
@@ -106,7 +107,7 @@
ws.write(rownum, colnum+i, val)
else:
if mlab.safe_isnan(val):
- ws.write(rownum, colnum+i, 'NaN')
+ ws.write(rownum, colnum+i, nanstr)
else:
ws.write(rownum, colnum+i, val, format.xlstyle)
rownum += 1
Modified: trunk/matplotlib/src/_path.cpp
===================================================================
--- trunk/matplotlib/src/_path.cpp 2008-07-17 18:27:36 UTC (rev 5779)
+++ trunk/matplotlib/src/_path.cpp 2008-07-17 18:56:48 UTC (rev 5780)
@@ -857,7 +857,7 @@
{
size_t size = p->size();
dims[0] = p->size();
- PyArrayObject* pyarray = (PyArrayObject*)PyArray_FromDims(2, dims, PyArray_DOUBLE);
+ PyArrayObject* pyarray = (PyArrayObject*)PyArray_SimpleNew(2, dims, PyArray_DOUBLE);
for (size_t i = 0; i < size; ++i)
{
((double *)pyarray->data)[2*i] = (*p)[i].x;
Modified: trunk/matplotlib/src/_png.cpp
===================================================================
--- trunk/matplotlib/src/_png.cpp 2008-07-17 18:27:36 UTC (rev 5779)
+++ trunk/matplotlib/src/_png.cpp 2008-07-17 18:56:48 UTC (rev 5780)
@@ -254,7 +254,7 @@
dimensions[1] = width; //numcols
dimensions[2] = 4;
- PyArrayObject *A = (PyArrayObject *) PyArray_FromDims(3, dimensions, PyArray_FLOAT);
+ PyArrayObject *A = (PyArrayObject *) PyArray_SimpleNew(3, dimensions, PyArray_FLOAT);
for (png_uint_32 y = 0; y < height; y++) {
Modified: trunk/matplotlib/src/ft2font.cpp
===================================================================
--- trunk/matplotlib/src/ft2font.cpp 2008-07-17 18:27:36 UTC (rev 5779)
+++ trunk/matplotlib/src/ft2font.cpp 2008-07-17 18:56:48 UTC (rev 5780)
@@ -274,7 +274,7 @@
/*
- PyArrayObject *A = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_UBYTE);
+ PyArrayObject *A = (PyArrayObject *) PyArray_SimpleNew(2, dimensions, PyArray_UBYTE);
unsigned char *src = _buffer;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-17 19:16:55
|
Revision: 5781
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5781&view=rev
Author: jdh2358
Date: 2008-07-17 19:15:58 +0000 (Thu, 17 Jul 2008)
Log Message:
-----------
more fixes for numpy svn deprecation warnings
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/nan_test.py
trunk/matplotlib/examples/pylab_examples/quadmesh_demo.py
trunk/matplotlib/lib/matplotlib/__init__.py
trunk/matplotlib/src/_backend_gdk.c
trunk/matplotlib/src/_path.cpp
trunk/matplotlib/src/_png.cpp
trunk/matplotlib/src/cntr.c
trunk/matplotlib/src/nxutils.c
Modified: trunk/matplotlib/examples/pylab_examples/nan_test.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/nan_test.py 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/examples/pylab_examples/nan_test.py 2008-07-17 19:15:58 UTC (rev 5781)
@@ -22,8 +22,7 @@
plot(t, s, '-', lw=2)
xlabel('time (s)')
-ylabel('voltage (mV)')
-title('More NaNs at 0.0 and 1.0')
+ylabel('more nans')
grid(True)
show()
Modified: trunk/matplotlib/examples/pylab_examples/quadmesh_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/quadmesh_demo.py 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/examples/pylab_examples/quadmesh_demo.py 2008-07-17 19:15:58 UTC (rev 5781)
@@ -40,6 +40,7 @@
# Or use the default, which is transparent:
col = ax.pcolormesh(Qx,Qz,Zm)
ax.set_title('With masked values')
-show()
+
savefig("quadmesh_demo")
+show()
Modified: trunk/matplotlib/lib/matplotlib/__init__.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/__init__.py 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/lib/matplotlib/__init__.py 2008-07-17 19:15:58 UTC (rev 5781)
@@ -89,7 +89,7 @@
"""
from __future__ import generators
-__version__ = '0.98.2'
+__version__ = '0.98.3'
__revision__ = '$Revision$'
__date__ = '$Date$'
Modified: trunk/matplotlib/src/_backend_gdk.c
===================================================================
--- trunk/matplotlib/src/_backend_gdk.c 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/src/_backend_gdk.c 2008-07-17 19:15:58 UTC (rev 5781)
@@ -28,7 +28,7 @@
PyGObject *py_pixbuf;
GdkPixbuf *gdk_pixbuf;
PyArrayObject *array;
- int dims[3] = { 0, 0, 3 };
+ npy_intp dims[3] = { 0, 0, 3 };
if (!PyArg_ParseTuple(args, "O!:pixbuf_get_pixels_array",
&PyGdkPixbuf_Type, &py_pixbuf))
Modified: trunk/matplotlib/src/_path.cpp
===================================================================
--- trunk/matplotlib/src/_path.cpp 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/src/_path.cpp 2008-07-17 19:15:58 UTC (rev 5781)
@@ -846,7 +846,7 @@
::clip_to_rect(path, x0, y0, x1, y1, inside, results);
- int dims[2];
+ npy_intp dims[2];
dims[1] = 2;
PyObject* py_results = PyList_New(results.size());
if (!py_results)
Modified: trunk/matplotlib/src/_png.cpp
===================================================================
--- trunk/matplotlib/src/_png.cpp 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/src/_png.cpp 2008-07-17 19:15:58 UTC (rev 5781)
@@ -249,7 +249,7 @@
- int dimensions[3];
+ npy_intp dimensions[3];
dimensions[0] = height; //numrows
dimensions[1] = width; //numcols
dimensions[2] = 4;
Modified: trunk/matplotlib/src/cntr.c
===================================================================
--- trunk/matplotlib/src/cntr.c 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/src/cntr.c 2008-07-17 19:15:58 UTC (rev 5781)
@@ -1333,7 +1333,7 @@
{
PyObject *point, *all_contours;
PyArrayObject *xv, *yv;
- int dims[1];
+ npy_intp dims[1];
int i;
long j, k;
@@ -1343,8 +1343,8 @@
for (i = 0; i < nparts; i++)
{
dims[0] = np[i];
- xv = (PyArrayObject *) PyArray_FromDims(1, dims, PyArray_DOUBLE);
- yv = (PyArrayObject *) PyArray_FromDims(1, dims, PyArray_DOUBLE);
+ xv = (PyArrayObject *) PyArray_SimpleNew(1, dims, PyArray_DOUBLE);
+ yv = (PyArrayObject *) PyArray_SimpleNew(1, dims, PyArray_DOUBLE);
if (xv == NULL || yv == NULL) goto error;
for (j = 0; j < dims[0]; j++)
{
@@ -1370,7 +1370,7 @@
{
PyObject *all_contours;
PyArrayObject *xyv;
- int dims[2];
+ npy_intp dims[2];
int i;
long j, k;
@@ -1381,7 +1381,7 @@
{
dims[0] = np[i];
dims[1] = 2;
- xyv = (PyArrayObject *) PyArray_FromDims(2, dims, PyArray_DOUBLE);
+ xyv = (PyArrayObject *) PyArray_SimpleNew(2, dims, PyArray_DOUBLE);
if (xyv == NULL) goto error;
for (j = 0; j < dims[0]; j++)
{
Modified: trunk/matplotlib/src/nxutils.c
===================================================================
--- trunk/matplotlib/src/nxutils.c 2008-07-17 18:56:48 UTC (rev 5780)
+++ trunk/matplotlib/src/nxutils.c 2008-07-17 19:15:58 UTC (rev 5781)
@@ -108,7 +108,7 @@
PyObject *xypointsarg, *vertsarg, *ret;
PyArrayObject *xypoints, *verts;
PyArrayObject *mask;
- int dimensions[1];
+ npy_intp dimensions[1];
if (! PyArg_ParseTuple(args, "OO", &xypointsarg, &vertsarg))
return NULL;
@@ -187,7 +187,7 @@
npoints = xypoints->dimensions[0];
dimensions[0] = npoints;
- mask = (PyArrayObject *)PyArray_FromDims(1,dimensions,PyArray_INT);
+ mask = (PyArrayObject *)PyArray_SimpleNew(1,dimensions,PyArray_INT);
if (mask==NULL) {
Py_XDECREF(verts);
Py_XDECREF(xypoints);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-17 21:06:22
|
Revision: 5785
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5785&view=rev
Author: jdh2358
Date: 2008-07-17 21:06:17 +0000 (Thu, 17 Jul 2008)
Log Message:
-----------
removed screen noise comments from gtkagg and image since I no longer consider this to be a bug
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py
trunk/matplotlib/src/_image.cpp
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py 2008-07-17 20:51:38 UTC (rev 5784)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py 2008-07-17 21:06:17 UTC (rev 5785)
@@ -81,13 +81,6 @@
w = int(ren.width)
h = int(ren.height)
- # There apparently is a bug here on some versions of pygtk
- # (2.6) that crops up in corner cases. Eg, in
- # figimage_demo.py, there is background pixel noise because
- # the figure frame is off and the blended image background has
- # alpha 0. and you see the uninitialzed data ("screen noise").
- # If in _image.cpp Image:from_image you fill the background
- # with a non transparent value, it goes away.
pixbuf = gtk.gdk.pixbuf_new_from_data(
buf, gtk.gdk.COLORSPACE_RGB, True, 8, w, h, w*4)
pixmap.draw_pixbuf(pixmap.new_gc(), pixbuf, 0, 0, 0, 0, w, h,
Modified: trunk/matplotlib/src/_image.cpp
===================================================================
--- trunk/matplotlib/src/_image.cpp 2008-07-17 20:51:38 UTC (rev 5784)
+++ trunk/matplotlib/src/_image.cpp 2008-07-17 21:06:17 UTC (rev 5785)
@@ -743,9 +743,6 @@
renderer_base rb(pixf);
- //clear the background of the rendering buffer with alpha 1 and the
- //gtkagg screen noise problem in figimage_demo.py goes away -- see
- //comment backend_gtkagg.py _render_figure method JDH
rb.clear(agg::rgba(1, 1, 1, 1));
for (size_t imnum=0; imnum< N; imnum++) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <dmk...@us...> - 2008-07-17 19:21:20
|
Revision: 5782
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5782&view=rev
Author: dmkaplan
Date: 2008-07-17 19:20:32 +0000 (Thu, 17 Jul 2008)
Log Message:
-----------
Adding more functionality for interacting with figure windows through
mouse clicks and keyboard clicks. This includes adding a
waitforbuttonpress function, as well as manual contour label location
selection for clabel. The underlying Blocking* classes that drive
this interaction have been moved into a separate file
"lib/matplotlib/blocking_input.py". Also added a changelog entry.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/contour.py
trunk/matplotlib/lib/matplotlib/figure.py
trunk/matplotlib/lib/matplotlib/pyplot.py
Added Paths:
-----------
trunk/matplotlib/lib/matplotlib/blocking_input.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-17 19:15:58 UTC (rev 5781)
+++ trunk/matplotlib/CHANGELOG 2008-07-17 19:20:32 UTC (rev 5782)
@@ -1,3 +1,6 @@
+2008-07-17 Added ability to manually select contour label locations.
+ Also added a waitforbuttonpress function. - DMK
+
2008-07-17 Fix bug with NaNs at end of path (thanks, Andrew Straw for
the report) - MGD
Added: trunk/matplotlib/lib/matplotlib/blocking_input.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/blocking_input.py (rev 0)
+++ trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-17 19:20:32 UTC (rev 5782)
@@ -0,0 +1,540 @@
+"""
+This provides several classes used for blocking interaction with figure windows:
+
+:class:`BlockingInput`
+ creates a callable object to retrieve events in a blocking way for interactive sessions
+
+:class:`BlockingKeyMouseInput`
+ creates a callable object to retrieve key or mouse clicks in a blocking way for interactive sessions.
+ Note: Subclass of BlockingInput. Used by waitforbuttonpress
+
+:class:`BlockingMouseInput`
+ creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions.
+ Note: Subclass of BlockingInput. Used by ginput
+
+:class:`BlockingContourLabeler`
+ creates a callable object to retrieve mouse clicks in a blocking way that will then be used to place labels on a ContourSet
+ Note: Subclass of BlockingMouseInput. Used by clabel
+"""
+
+import time
+import numpy as np
+import matplotlib.path as path
+
+class BlockingInput(object):
+ """
+ Class that creates a callable object to retrieve events in a
+ blocking way.
+ """
+ def __init__(self, fig, eventslist=()):
+ self.fig = fig
+ assert isinstance(eventslist, tuple), "Requires a tuple of event name strings"
+ self.eventslist = eventslist
+
+ def on_event(self, event):
+ """
+ Event handler that will be passed to the current figure to
+ retrieve events.
+ """
+ # Add a new event to list - using a separate function is
+ # overkill for the base class, but this is consistent with
+ # subclasses
+ self.add_event(event)
+
+ if self.verbose:
+ print "Event %i" % len(self.events)
+
+ # This will extract info from events
+ self.post_event()
+
+ # Check if we have enough events already
+ if len(self.events) >= self.n and self.n > 0:
+ self.done = True
+
+ def post_event(self):
+ """For baseclass, do nothing but collect events"""
+ pass
+
+ def cleanup(self):
+ """Disconnect all callbacks"""
+ for cb in self.callbacks:
+ self.fig.canvas.mpl_disconnect(cb)
+
+ self.callbacks=[]
+
+ def add_event(self,event):
+ """For base class, this just appends an event to events."""
+ self.events.append(event)
+
+ def pop_event(self,index=-1):
+ """
+ This removes an event from the event list. Defaults to
+ removing last event, but an index can be supplied. Note that
+ this does not check that there are events, much like the
+ normal pop method. If not events exist, this will throw an
+ exception.
+ """
+ self.events.pop(index)
+
+ def pop(self,index=-1):
+ self.pop_event(index)
+ pop.__doc__=pop_event.__doc__
+
+ def __call__(self, n=1, timeout=30, verbose=False ):
+ """
+ Blocking call to retrieve n events
+ """
+
+ assert isinstance(n, int), "Requires an integer argument"
+ self.n = n
+
+ self.events = []
+ self.done = False
+ self.verbose = verbose
+ self.callbacks = []
+
+ # Ensure that the figure is shown
+ self.fig.show()
+
+ # connect the events to the on_event function call
+ for n in self.eventslist:
+ self.callbacks.append( self.fig.canvas.mpl_connect(n, self.on_event) )
+
+ try:
+ # wait for n clicks
+ counter = 0
+ while not self.done:
+ self.fig.canvas.flush_events()
+ time.sleep(0.01)
+
+ # check for a timeout
+ counter += 1
+ if timeout > 0 and counter > timeout/0.01:
+ print "Timeout reached";
+ break;
+ finally: # Activated on exception like ctrl-c
+ self.cleanup()
+
+ # Disconnect the callbacks
+ self.cleanup()
+
+ # Return the events in this case
+ return self.events
+
+class BlockingMouseInput(BlockingInput):
+ """
+ Class that creates a callable object to retrieve mouse clicks in a
+ blocking way.
+ """
+ def __init__(self, fig):
+ BlockingInput.__init__(self, fig=fig,
+ eventslist=('button_press_event',) )
+
+ def post_event(self):
+ """
+ This will be called to process events
+ """
+ assert len(self.events)>0, "No events yet"
+
+ event = self.events[-1]
+ button = event.button
+
+ # Using additional methods for each button is a bit overkill
+ # for this class, but it allows for easy overloading. Also,
+ # this would make it easy to attach other type of non-mouse
+ # events to these "mouse" actions. For example, the matlab
+ # version of ginput also allows you to add points with
+ # keyboard clicks. This could easily be added to this class
+ # with relatively minor modification to post_event and
+ # __init__.
+ if button == 3:
+ self.button3(event)
+ elif button == 2:
+ self.button2(event)
+ else:
+ self.button1(event)
+
+ def button1( self, event ):
+ """
+ Will be called for any event involving a button other than
+ button 2 or 3. This will add a click if it is inside axes.
+ """
+ if event.inaxes:
+ self.add_click(event)
+ else: # If not a valid click, remove from event list
+ BlockingInput.pop(self)
+
+ def button2( self, event ):
+ """
+ Will be called for any event involving button 2.
+ Button 2 ends blocking input.
+ """
+
+ # Remove last event just for cleanliness
+ BlockingInput.pop(self)
+
+ # This will exit even if not in infinite mode. This is
+ # consistent with matlab and sometimes quite useful, but will
+ # require the user to test how many points were actually
+ # returned before using data.
+ self.done = True
+
+ def button3( self, event ):
+ """
+ Will be called for any event involving button 3.
+ Button 3 removes the last click.
+ """
+ # Remove this last event
+ BlockingInput.pop(self)
+
+ # Now remove any existing clicks if possible
+ if len(self.events)>0:
+ self.pop()
+
+ def add_click(self,event):
+ """
+ This add the coordinates of an event to the list of clicks
+ """
+ self.clicks.append((event.xdata,event.ydata))
+ if self.verbose:
+ print "input %i: %f,%f" % (len(self.clicks),
+ event.xdata, event.ydata)
+
+ # If desired plot up click
+ if self.show_clicks:
+ self.marks.extend(
+ event.inaxes.plot([event.xdata,], [event.ydata,], 'r+') )
+ self.fig.canvas.draw()
+
+ def pop_click(self,index=-1):
+ """
+ This removes a click from the list of clicks. Defaults to
+ removing the last click.
+ """
+ self.clicks.pop(index)
+
+ if self.show_clicks:
+ mark = self.marks.pop(index)
+ mark.remove()
+ self.fig.canvas.draw()
+
+ def pop(self,index=-1):
+ """
+ This removes a click and the associated event from the object.
+ Defaults to removing the last click, but any index can be
+ supplied.
+ """
+ self.pop_click(index)
+ BlockingInput.pop(self,index)
+
+ def cleanup(self):
+ # clean the figure
+ if self.show_clicks:
+ for mark in self.marks:
+ mark.remove()
+ self.marks = []
+ self.fig.canvas.draw()
+
+ # Call base class to remove callbacks
+ BlockingInput.cleanup(self)
+
+ def __call__(self, n=1, timeout=30, verbose=False, show_clicks=True):
+ """
+ Blocking call to retrieve n coordinate pairs through mouse
+ clicks.
+ """
+ self.show_clicks = show_clicks
+ self.clicks = []
+ self.marks = []
+ BlockingInput.__call__(self,n=n,timeout=timeout,verbose=verbose)
+
+ return self.clicks
+
+class BlockingContourLabeler( BlockingMouseInput ):
+ """
+ Class that creates a callable object that uses mouse clicks on a
+ figure window to place contour labels.
+ """
+ def __init__(self,cs):
+ self.cs = cs
+ BlockingMouseInput.__init__(self, fig=cs.ax.figure )
+
+ def button1(self,event):
+ """
+ This will be called if an event involving a button other than
+ 2 or 3 occcurs. This will add a label to a contour.
+ """
+ if event.inaxes == self.cs.ax:
+ conmin,segmin,imin,xmin,ymin = self.cs.find_nearest_contour(
+ event.x, event.y)[:5]
+
+ paths = self.cs.collections[conmin].get_paths()
+ lc = paths[segmin].vertices
+
+ # Figure out label rotation. This is very cludgy.
+ # Ideally, there would be one method in ContourLabeler
+ # that would figure out the best rotation for a label at a
+ # point, but the way automatic label rotation is done is
+ # quite mysterious to me and doesn't seem easy to
+ # generalize to non-automatic label placement. The method
+ # used below is not very robust! It basically looks one
+ # point before and one point after label location on
+ # contour and takes mean of angles of two vectors formed.
+ # This produces "acceptable" results, but not nearly as
+ # nice as automatic method.
+ ll = lc[max(0,imin-1):imin+2] # Get points around point
+ dd = np.diff(ll,axis=0)
+ rotation = np.mean( np.arctan2(dd[:,1], dd[:,0]) ) * 180 / np.pi
+ if rotation > 90:
+ rotation = rotation -180
+ if rotation < -90:
+ rotation = 180 + rotation
+
+ self.cs.add_label(xmin,ymin,rotation,conmin)
+
+ if self.inline:
+ # Get label width for breaking contours
+ lw = self.cs.get_label_width(self.cs.label_levels[conmin],
+ self.cs.fmt,
+ self.cs.fslist[conmin])
+ # Break contour
+ new=self.cs.break_linecontour(lc,rotation,lw,imin)
+ if len(new[0]):
+ paths[segmin] = path.Path(new[0])
+ if len(new[1]):
+ paths.extend([path.Path(new[1])])
+
+ self.fig.canvas.draw()
+ else: # Remove event if not valid
+ BlockingInput.pop(self)
+
+ def button3(self,event):
+ """
+ This will be called if button 3 is clicked. This will remove
+ a label if not in inline mode. Unfortunately, if one is doing
+ inline labels, then there is currently no way to fix the
+ broken contour - once humpty-dumpty is broken, he can't be put
+ back together. In inline mode, this does nothing.
+ """
+ if self.inline:
+ pass
+ else:
+ self.cs.pop_label()
+ self.cs.ax.figure.canvas.draw()
+
+ def __call__(self,inline,n=-1,timeout=-1):
+ self.inline=inline
+ BlockingMouseInput.__call__(self,n=n,timeout=timeout,verbose=False,
+ show_clicks=False)
+
+class BlockingKeyMouseInput(BlockingInput):
+ """
+ Class that creates a callable object to retrieve a single mouse or
+ keyboard click
+ """
+ def __init__(self, fig):
+ BlockingInput.__init__(self, fig=fig, eventslist=('button_press_event','key_press_event') )
+
+ def post_event(self):
+ """
+ Determines if it is a key event
+ """
+ assert len(self.events)>0, "No events yet"
+
+ self.keyormouse = self.events[-1].name == 'key_press_event'
+
+ def __call__(self, timeout=30, verbose=False):
+ """
+ Blocking call to retrieve a single mouse or key click
+ Returns True if key click, False if mouse, or None if timeout
+ """
+ self.keyormouse = None
+ BlockingInput.__call__(self,n=1,timeout=timeout,verbose=verbose)
+
+ return self.keyormouse
+
+"""
+This provides several classes used for interaction with figure windows:
+
+:class:`BlockingInput`
+ creates a callable object to retrieve events in a blocking way for interactive sessions
+
+:class:`BlockingKeyMouseInput`
+ creates a callable object to retrieve key or mouse clicks in a blocking way for interactive sessions.
+ Note: Subclass of BlockingInput. Used by waitforbuttonpress
+
+:class:`BlockingMouseInput`
+ creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions.
+ Note: Subclass of BlockingInput. Used by ginput
+"""
+
+import time
+
+class BlockingInput(object):
+ """
+ Class that creates a callable object to retrieve events in a
+ blocking way.
+ """
+ def __init__(self, fig, eventslist=()):
+ self.fig = fig
+ assert isinstance(eventslist, tuple), \
+ "Requires a tuple of event name strings"
+ self.eventslist = eventslist
+
+ def on_event(self, event):
+ """
+ Event handler that will be passed to the current figure to
+ retrieve events.
+ """
+ self.events.append(event)
+
+ if self.verbose:
+ print "Event %i" % len(self.events)
+
+ # This will extract info from events
+ self.post_event()
+
+ if len(self.events) >= self.n and self.n > 0:
+ self.done = True
+
+ def post_event(self):
+ """For baseclass, do nothing but collect events"""
+ pass
+
+ def cleanup(self):
+ """Remove callbacks"""
+ for cb in self.callbacks:
+ self.fig.canvas.mpl_disconnect(cb)
+
+ self.callbacks=[]
+
+ def __call__(self, n=1, timeout=30, verbose=False ):
+ """
+ Blocking call to retrieve n events
+ """
+
+ assert isinstance(n, int), "Requires an integer argument"
+ self.n = n
+
+ self.events = []
+ self.done = False
+ self.verbose = verbose
+ self.callbacks = []
+
+ # Ensure that the figure is shown
+ self.fig.show()
+
+ # connect the events to the on_event function call
+ for n in self.eventslist:
+ self.callbacks.append( self.fig.canvas.mpl_connect(n, self.on_event) )
+
+ try:
+ # wait for n clicks
+ counter = 0
+ while not self.done:
+ self.fig.canvas.flush_events()
+ time.sleep(0.01)
+
+ # check for a timeout
+ counter += 1
+ if timeout > 0 and counter > timeout/0.01:
+ print "Timeout reached";
+ break;
+ finally: # Activated on exception like ctrl-c
+ self.cleanup()
+
+ # Disconnect the callbacks
+ self.cleanup()
+
+ # Return the events in this case
+ return self.events
+
+class BlockingMouseInput(BlockingInput):
+ """
+ Class that creates a callable object to retrieve mouse clicks in a
+ blocking way.
+ """
+ def __init__(self, fig):
+ BlockingInput.__init__(self, fig=fig, eventslist=('button_press_event',) )
+
+ def post_event(self):
+ """
+ This will be called to process events
+ """
+ assert len(self.events)>0, "No events yet"
+
+ event = self.events[-1]
+
+ if event.button == 3:
+ # If it's a right click, pop the last coordinates.
+ if len(self.clicks) > 0:
+ self.clicks.pop()
+ del self.events[-2:] # Remove button=3 event and previous event
+
+ if self.show_clicks:
+ mark = self.marks.pop()
+ mark.remove()
+ self.fig.canvas.draw()
+ elif event.button == 2 and self.n < 0:
+ # If it's a middle click, and we are in infinite mode, finish
+ self.done = True
+ elif event.inaxes:
+ # If it's a valid click, append the coordinates to the list
+ self.clicks.append((event.xdata, event.ydata))
+ if self.verbose:
+ print "input %i: %f,%f" % (len(self.clicks),
+ event.xdata, event.ydata)
+ if self.show_clicks:
+ self.marks.extend(
+ event.inaxes.plot([event.xdata,], [event.ydata,], 'r+') )
+ self.fig.canvas.draw()
+
+ def cleanup(self):
+ # clean the figure
+ if self.show_clicks:
+ for mark in self.marks:
+ mark.remove()
+ self.marks = []
+ self.fig.canvas.draw()
+
+ # Call base class to remove callbacks
+ BlockingInput.cleanup(self)
+
+ def __call__(self, n=1, timeout=30, verbose=False, show_clicks=True):
+ """
+ Blocking call to retrieve n coordinate pairs through mouse
+ clicks.
+ """
+ self.show_clicks = show_clicks
+ self.clicks = []
+ self.marks = []
+ BlockingInput.__call__(self,n=n,timeout=timeout,verbose=verbose)
+
+ return self.clicks
+
+class BlockingKeyMouseInput(BlockingInput):
+ """
+ Class that creates a callable object to retrieve a single mouse or
+ keyboard click
+ """
+ def __init__(self, fig):
+ BlockingInput.__init__(self, fig=fig, eventslist=('button_press_event','key_press_event') )
+
+ def post_event(self):
+ """
+ Determines if it is a key event
+ """
+ assert len(self.events)>0, "No events yet"
+
+ self.keyormouse = self.events[-1].name == 'key_press_event'
+
+ def __call__(self, timeout=30, verbose=False):
+ """
+ Blocking call to retrieve a single mouse or key click
+ Returns True if key click, False if mouse, or None if timeout
+ """
+ self.keyormouse = None
+ BlockingInput.__call__(self,n=1,timeout=timeout,verbose=verbose)
+
+ return self.keyormouse
+
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2008-07-17 19:15:58 UTC (rev 5781)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2008-07-17 19:20:32 UTC (rev 5782)
@@ -17,6 +17,9 @@
import matplotlib.text as text
import matplotlib.cbook as cbook
+# Import needed for adding manual selection capability to clabel
+from matplotlib.blocking_input import BlockingContourLabeler
+
# We can't use a single line collection for contour because a line
# collection can have only a single line style, and we want to be able to have
# dashed negative contours, for example, and solid positive contours.
@@ -69,6 +72,13 @@
*fmt*:
a format string for the label. Default is '%1.3f'
+ *manual*:
+ if *True*, contour labels will be placed manually using
+ mouse clicks. Click the first button near a contour to
+ add a label, click the second button (or potentially both
+ mouse buttons at once) to finish adding labels. The third
+ button can be used to remove the last label added, but
+ only if labels are not inline.
"""
fontsize = kwargs.get('fontsize', None)
@@ -76,8 +86,9 @@
self.fmt = kwargs.get('fmt', '%1.3f')
_colors = kwargs.get('colors', None)
+ # Detect if manual selection is desired and remove from argument list
+ self.manual_select=kwargs.get('manual',False)
-
if len(args) == 0:
levels = self.levels
indices = range(len(self.levels))
@@ -126,10 +137,16 @@
#self.cl_cvalues = [] # same
self.cl_xy = []
- self.labels(inline)
+ if self.manual_select:
+ print 'Select label locations manually using first mouse button.'
+ print 'End manual selection with second mouse button.'
+ if not inline:
+ print 'Remove last label by clicking third mouse button.'
- for label in self.cl:
- self.ax.add_artist(label)
+ blocking_contour_labeler = BlockingContourLabeler(self)
+ blocking_contour_labeler(inline)
+ else:
+ self.labels(inline)
self.label_list = cbook.silent_list('text.Text', self.cl)
return self.label_list
@@ -335,19 +352,85 @@
return x,y, rotation, dind
+ def add_label(self,x,y,rotation,icon):
+ dx,dy = self.ax.transData.inverted().transform_point((x,y))
+ t = text.Text(dx, dy, rotation = rotation,
+ horizontalalignment='center',
+ verticalalignment='center')
+
+ color = self.label_mappable.to_rgba(self.label_cvalues[icon],
+ alpha=self.alpha)
+
+ _text = self.get_text(self.label_levels[icon],self.fmt)
+ self.set_label_props(t, _text, color)
+ self.cl.append(t)
+ self.cl_cvalues.append(self.label_cvalues[icon])
+
+ # Add label to plot here - useful for manual mode label selection
+ self.ax.add_artist(t)
+
+ def pop_label(self,index=-1):
+ '''Defaults to removing last label, but any index can be supplied'''
+ self.cl_cvalues.pop(index)
+ t = self.cl.pop(index)
+ t.remove()
+
+ def find_nearest_contour( self, x, y, pixel=True ):
+ """
+ Finds contour that is closest to a point. Defaults to
+ measuring distance in pixels (screen space - useful for manual
+ contour labeling), but this can be controlled via a keyword
+ argument.
+
+ Returns a tuple containing the contour, segment, index of
+ segment, x & y of segment point and distance to minimum point.
+ """
+
+ # This function uses a method that is probably quite
+ # inefficient based on converting each contour segment to
+ # pixel coordinates and then comparing the given point to
+ # those coordinates for each contour. This will probably be
+ # quite slow for complex contours, but for normal use it works
+ # sufficiently well that the time is not noticeable.
+ # Nonetheless, improvements could probably be made.
+
+ dmin = 1e10
+ conmin = None
+ segmin = None
+ xmin = None
+ ymin = None
+
+ for icon in self.label_indices:
+ con = self.collections[icon]
+ paths = con.get_paths()
+ for segNum, linepath in enumerate(paths):
+ lc = linepath.vertices
+
+ # transfer all data points to screen coordinates if desired
+ if pixel:
+ lc = self.ax.transData.transform(lc)
+
+ ds = (lc[:,0]-x)**2 + (lc[:,1]-y)**2
+ d = min( ds )
+ if d < dmin:
+ dmin = d
+ conmin = icon
+ segmin = segNum
+ imin = mpl.mlab.find( ds == d )[0]
+ xmin = lc[imin,0]
+ ymin = lc[imin,1]
+
+ return (conmin,segmin,imin,xmin,ymin,dmin)
+
def labels(self, inline):
levels = self.label_levels
fslist = self.fslist
trans = self.ax.transData
- _colors = self.label_mappable.to_rgba(self.label_cvalues,
- alpha=self.alpha)
- fmt = self.fmt
- for icon, lev, color, cvalue, fsize in zip(self.label_indices,
- self.label_levels,
- _colors,
- self.label_cvalues, fslist):
+
+ for icon, lev, fsize in zip(self.label_indices,
+ self.label_levels, fslist):
con = self.collections[icon]
- lw = self.get_label_width(lev, fmt, fsize)
+ lw = self.get_label_width(lev, self.fmt, fsize)
additions = []
paths = con.get_paths()
for segNum, linepath in enumerate(paths):
@@ -362,16 +445,8 @@
slc = trans.transform(linecontour)
if self.print_label(slc,lw):
x,y, rotation, ind = self.locate_label(slc, lw)
- # transfer the location of the label back to
- # data coordinates
- dx,dy = trans.inverted().transform_point((x,y))
- t = text.Text(dx, dy, rotation = rotation,
- horizontalalignment='center',
- verticalalignment='center')
- _text = self.get_text(lev,fmt)
- self.set_label_props(t, _text, color)
- self.cl.append(t)
- self.cl_cvalues.append(cvalue)
+ self.add_label(x,y,rotation,icon)
+
if inline:
new = self.break_linecontour(linecontour, rotation, lw, ind)
if len(new[0]):
Modified: trunk/matplotlib/lib/matplotlib/figure.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/figure.py 2008-07-17 19:15:58 UTC (rev 5781)
+++ trunk/matplotlib/lib/matplotlib/figure.py 2008-07-17 19:20:32 UTC (rev 5782)
@@ -6,9 +6,6 @@
:class:`SubplotParams`
control the default spacing of the subplots
-:class:`BlockingMouseInput`
- creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions
-
:class:`Figure`
top level container for all plot elements
@@ -32,6 +29,7 @@
from transforms import Affine2D, Bbox, BboxTransformTo, TransformedBbox
from projections import projection_factory, get_projection_names, \
get_projection_class
+from matplotlib.blocking_input import BlockingMouseInput, BlockingKeyMouseInput
import matplotlib.cbook as cbook
@@ -117,87 +115,6 @@
setattr(self, s, val)
-
-class BlockingMouseInput(object):
- """
- Class that creates a callable object to retrieve mouse clicks in a
- blocking way.
- """
- def __init__(self, fig):
- self.fig = fig
-
-
- def on_click(self, event):
- """
- Event handler that will be passed to the current figure to
- retrieve clicks.
- """
- if event.button == 3:
- # If it's a right click, pop the last coordinates.
- if len(self.clicks) > 0:
- self.clicks.pop()
- if self.show_clicks:
- mark = self.marks.pop()
- mark.remove()
- self.fig.canvas.draw()
- elif event.button == 2 and self.n < 0:
- # If it's a middle click, and we are in infinite mode, finish
- self.done = True
- elif event.inaxes:
- # If it's a valid click, append the coordinates to the list
- self.clicks.append((event.xdata, event.ydata))
- if self.verbose:
- print "input %i: %f,%f" % (len(self.clicks),
- event.xdata, event.ydata)
- if self.show_clicks:
- self.marks.extend(
- event.inaxes.plot([event.xdata,], [event.ydata,], 'r+') )
- self.fig.canvas.draw()
- if self.n > 0 and len(self.clicks) >= self.n:
- self.done = True
-
-
- def __call__(self, n=1, timeout=30, verbose=False, show_clicks=True):
- """
- Blocking call to retrieve n coordinate pairs through mouse
- clicks.
- """
- self.verbose = verbose
- self.done = False
- self.clicks = []
- self.show_clicks = True
- self.marks = []
-
- assert isinstance(n, int), "Requires an integer argument"
- self.n = n
-
- # Ensure that the figure is shown
- self.fig.show()
- # connect the click events to the on_click function call
- self.callback = self.fig.canvas.mpl_connect('button_press_event',
- self.on_click)
- # wait for n clicks
- counter = 0
- while no...
[truncated message content] |
|
From: <jd...@us...> - 2008-07-18 14:49:15
|
Revision: 5788
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5788&view=rev
Author: jdh2358
Date: 2008-07-18 14:49:09 +0000 (Fri, 18 Jul 2008)
Log Message:
-----------
Merged revisions 5787 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_91_maint
........
r5787 | jdh2358 | 2008-07-18 09:46:32 -0500 (Fri, 18 Jul 2008) | 1 line
added Tuukka's YAArrow fix for horiz and vertical lines
........
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/patches.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-5771
+ /branches/v0_91_maint:1-5787
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2008-07-18 14:46:32 UTC (rev 5787)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2008-07-18 14:49:09 UTC (rev 5788)
@@ -858,6 +858,12 @@
*y2*) of the returned points is *k*.
"""
x1,y1,x2,y2,k = map(float, (x1,y1,x2,y2,k))
+
+ if y2-y1 == 0:
+ return x2, y2+k, x2, y2-k
+ elif x2-x1 == 0:
+ return x2+k, y2, x2-k, y2
+
m = (y2-y1)/(x2-x1)
pm = -1./m
a = 1
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <as...@us...> - 2008-07-18 23:15:40
|
Revision: 5791
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5791&view=rev
Author: astraw
Date: 2008-07-18 23:15:37 +0000 (Fri, 18 Jul 2008)
Log Message:
-----------
Check for nan and inf in axes.delete_masked_points().
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/axes.py
Added Paths:
-----------
trunk/matplotlib/unit/axes_unit.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-18 20:43:58 UTC (rev 5790)
+++ trunk/matplotlib/CHANGELOG 2008-07-18 23:15:37 UTC (rev 5791)
@@ -1,3 +1,6 @@
+2008-07-18 Check for nan and inf in axes.delete_masked_points().
+ This should help hexbin and scatter deal with nans. - ADS
+
2008-07-17 Added ability to manually select contour label locations.
Also added a waitforbuttonpress function. - DMK
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2008-07-18 20:43:58 UTC (rev 5790)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2008-07-18 23:15:37 UTC (rev 5791)
@@ -1,5 +1,5 @@
from __future__ import division, generators
-import math, sys, warnings, datetime, new
+import math, sys, warnings, datetime, new, types
import numpy as np
from numpy import ma
@@ -36,6 +36,8 @@
Find all masked points in a set of arguments, and return
the arguments with only the unmasked points remaining.
+ This will also delete any points that are not finite (nan or inf).
+
The overall mask is calculated from any masks that are present.
If a mask is found, any argument that does not have the same
dimensions is left unchanged; therefore the argument list may
@@ -49,9 +51,11 @@
useful.
"""
masks = [ma.getmaskarray(x) for x in args if hasattr(x, 'mask')]
+ isfinite = [np.isfinite(x) for x in args]
+ masks.extend( [~x for x in isfinite if not isinstance(x,types.NotImplementedType)] )
if len(masks) == 0:
return args
- mask = reduce(ma.mask_or, masks)
+ mask = reduce(np.logical_or, masks)
margs = []
for x in args:
if (not is_string_like(x)
Added: trunk/matplotlib/unit/axes_unit.py
===================================================================
--- trunk/matplotlib/unit/axes_unit.py (rev 0)
+++ trunk/matplotlib/unit/axes_unit.py 2008-07-18 23:15:37 UTC (rev 5791)
@@ -0,0 +1,62 @@
+import unittest
+import numpy as np
+import matplotlib.axes as axes
+
+class TestAxes(unittest.TestCase):
+ def test_delete_masked_points_arrays(self):
+ input = ( [1,2,3,np.nan,5],
+ np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,5))]*2
+ actual = axes.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ( np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
+ np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,5))]*2
+ actual = axes.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ( [1,2,3,np.nan,5],
+ np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
+ np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,5))]*3
+ actual = axes.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ()
+ expected = ()
+ actual = axes.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+
+ input = ( [1,2,3,np.nan,5],
+ )
+ expected = [np.array((1,2,3,5))]*1
+ actual = axes.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ( np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,4,5))]*1
+ actual = axes.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ def test_delete_masked_points_strings(self):
+ input = ( 'hello',
+ )
+ expected = ('hello',)
+ actual = axes.delete_masked_points(*input)
+ assert actual == expected
+
+ input = ( u'hello',
+ )
+ expected = (u'hello',)
+ actual = axes.delete_masked_points(*input)
+ assert actual == expected
+
+
+if __name__=='__main__':
+ unittest.main()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ef...@us...> - 2008-07-20 18:21:17
|
Revision: 5796
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5796&view=rev
Author: efiring
Date: 2008-07-20 18:21:11 +0000 (Sun, 20 Jul 2008)
Log Message:
-----------
Moved and modified axes_unit.py to cbook_unit.py.
At present it is only testing delete_masked_points,
which was moved from axes to cbook.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
Added Paths:
-----------
trunk/matplotlib/unit/cbook_unit.py
Removed Paths:
-------------
trunk/matplotlib/unit/axes_unit.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-20 07:14:46 UTC (rev 5795)
+++ trunk/matplotlib/CHANGELOG 2008-07-20 18:21:11 UTC (rev 5796)
@@ -1,8 +1,13 @@
+
+2008-07-20 Renamed unit/axes_unit.py to cbook_unit.py and modified
+ in accord with Ryan's move of delete_masked_points from
+ axes to cbook. - EF
+
2008-07-18 Check for nan and inf in axes.delete_masked_points().
- This should help hexbin and scatter deal with nans. - ADS
+ This should help hexbin and scatter deal with nans. - ADS
2008-07-17 Added ability to manually select contour label locations.
- Also added a waitforbuttonpress function. - DMK
+ Also added a waitforbuttonpress function. - DMK
2008-07-17 Fix bug with NaNs at end of path (thanks, Andrew Straw for
the report) - MGD
Deleted: trunk/matplotlib/unit/axes_unit.py
===================================================================
--- trunk/matplotlib/unit/axes_unit.py 2008-07-20 07:14:46 UTC (rev 5795)
+++ trunk/matplotlib/unit/axes_unit.py 2008-07-20 18:21:11 UTC (rev 5796)
@@ -1,62 +0,0 @@
-import unittest
-import numpy as np
-import matplotlib.axes as axes
-
-class TestAxes(unittest.TestCase):
- def test_delete_masked_points_arrays(self):
- input = ( [1,2,3,np.nan,5],
- np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,5))]*2
- actual = axes.delete_masked_points(*input)
- assert np.allclose(actual, expected)
-
- input = ( np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
- np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,5))]*2
- actual = axes.delete_masked_points(*input)
- assert np.allclose(actual, expected)
-
- input = ( [1,2,3,np.nan,5],
- np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
- np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,5))]*3
- actual = axes.delete_masked_points(*input)
- assert np.allclose(actual, expected)
-
- input = ()
- expected = ()
- actual = axes.delete_masked_points(*input)
- assert np.allclose(actual, expected)
-
-
- input = ( [1,2,3,np.nan,5],
- )
- expected = [np.array((1,2,3,5))]*1
- actual = axes.delete_masked_points(*input)
- assert np.allclose(actual, expected)
-
- input = ( np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,4,5))]*1
- actual = axes.delete_masked_points(*input)
- assert np.allclose(actual, expected)
-
- def test_delete_masked_points_strings(self):
- input = ( 'hello',
- )
- expected = ('hello',)
- actual = axes.delete_masked_points(*input)
- assert actual == expected
-
- input = ( u'hello',
- )
- expected = (u'hello',)
- actual = axes.delete_masked_points(*input)
- assert actual == expected
-
-
-if __name__=='__main__':
- unittest.main()
Copied: trunk/matplotlib/unit/cbook_unit.py (from rev 5795, trunk/matplotlib/unit/axes_unit.py)
===================================================================
--- trunk/matplotlib/unit/cbook_unit.py (rev 0)
+++ trunk/matplotlib/unit/cbook_unit.py 2008-07-20 18:21:11 UTC (rev 5796)
@@ -0,0 +1,62 @@
+import unittest
+import numpy as np
+import matplotlib.cbook as cbook
+
+class TestAxes(unittest.TestCase):
+ def test_delete_masked_points_arrays(self):
+ input = ( [1,2,3,np.nan,5],
+ np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,5))]*2
+ actual = cbook.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ( np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
+ np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,5))]*2
+ actual = cbook.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ( [1,2,3,np.nan,5],
+ np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
+ np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,5))]*3
+ actual = cbook.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ()
+ expected = ()
+ actual = cbook.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+
+ input = ( [1,2,3,np.nan,5],
+ )
+ expected = [np.array((1,2,3,5))]*1
+ actual = cbook.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ input = ( np.array((1,2,3,4,5)),
+ )
+ expected = [np.array((1,2,3,4,5))]*1
+ actual = cbook.delete_masked_points(*input)
+ assert np.allclose(actual, expected)
+
+ def test_delete_masked_points_strings(self):
+ input = ( 'hello',
+ )
+ expected = ('hello',)
+ actual = cbook.delete_masked_points(*input)
+ assert actual == expected
+
+ input = ( u'hello',
+ )
+ expected = (u'hello',)
+ actual = cbook.delete_masked_points(*input)
+ assert actual == expected
+
+
+if __name__=='__main__':
+ unittest.main()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ef...@us...> - 2008-07-21 00:22:33
|
Revision: 5797
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5797&view=rev
Author: efiring
Date: 2008-07-21 00:22:19 +0000 (Mon, 21 Jul 2008)
Log Message:
-----------
Expanded delete_masked_points to handle more types of argument
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/cbook.py
trunk/matplotlib/lib/matplotlib/collections.py
trunk/matplotlib/unit/cbook_unit.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-20 18:21:11 UTC (rev 5796)
+++ trunk/matplotlib/CHANGELOG 2008-07-21 00:22:19 UTC (rev 5797)
@@ -1,3 +1,6 @@
+2008-07-20 Rewrote cbook.delete_masked_points and corresponding
+ unit test to support rgb color array inputs, datetime
+ inputs, etc. - EF
2008-07-20 Renamed unit/axes_unit.py to cbook_unit.py and modified
in accord with Ryan's move of delete_masked_points from
Modified: trunk/matplotlib/lib/matplotlib/cbook.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/cbook.py 2008-07-20 18:21:11 UTC (rev 5796)
+++ trunk/matplotlib/lib/matplotlib/cbook.py 2008-07-21 00:22:19 UTC (rev 5797)
@@ -6,7 +6,7 @@
import re, os, errno, sys, StringIO, traceback, locale, threading, types
import time, datetime
import numpy as np
-from numpy import ma
+import numpy.ma as ma
from weakref import ref
major, minor1, minor2, s, tmp = sys.version_info
@@ -1168,41 +1168,82 @@
def delete_masked_points(*args):
"""
- Find all masked points in a set of arguments, and return
- the arguments with only the unmasked points remaining.
+ Find all masked and/or non-finite points in a set of arguments,
+ and return the arguments with only the unmasked points remaining.
- This will also delete any points that are not finite (nan or inf).
+ Arguments can be in any of 5 categories:
- The overall mask is calculated from any masks that are present.
- If a mask is found, any argument that does not have the same
- dimensions is left unchanged; therefore the argument list may
- include arguments that can take string or array values, for
- example.
+ 1) 1-D masked arrays
+ 2) 1-D ndarrays
+ 3) ndarrays with more than one dimension
+ 4) other non-string iterables
+ 5) anything else
- Array arguments must have the same length; masked arguments must
- be one-dimensional.
+ The first argument must be in one of the first four categories;
+ any argument with a length differing from that of the first
+ argument (and hence anything in category 5) then will be
+ passed through unchanged.
- Written as a helper for scatter, but may be more generally
- useful.
+ Masks are obtained from all arguments of the correct length
+ in categories 1, 2, and 4; a point is bad if masked in a masked
+ array or if it is a nan or inf. No attempt is made to
+ extract a mask from categories 2, 3, and 4 if *np.isfinite()*
+ does not yield a Boolean array.
+
+ All input arguments that are not passed unchanged are returned
+ as ndarrays after removing the points or rows corresponding to
+ masks in any of the arguments.
+
+ A vastly simpler version of this function was originally
+ written as a helper for Axes.scatter().
+
"""
- masks = [ma.getmaskarray(x) for x in args if hasattr(x, 'mask')]
- isfinite = [np.isfinite(x) for x in args]
- masks.extend( [~x for x in isfinite if not isinstance(x,types.NotImplementedType)] )
- if len(masks) == 0:
- return args
- mask = reduce(np.logical_or, masks)
+ if not len(args):
+ return ()
+ if (is_string_like(args[0]) or not iterable(args[0])):
+ raise ValueError("First argument must be a sequence")
+ nrecs = len(args[0])
margs = []
- for x in args:
- if (not is_string_like(x)
- and iterable(x)
- and len(x) == len(mask)):
- if (hasattr(x, 'get_compressed_copy')):
- compressed_x = x.get_compressed_copy(mask)
+ seqlist = [False] * len(args)
+ for i, x in enumerate(args):
+ if (not is_string_like(x)) and iterable(x) and len(x) == nrecs:
+ seqlist[i] = True
+ if ma.isMA(x):
+ if x.ndim > 1:
+ raise ValueError("Masked arrays must be 1-D")
else:
- compressed_x = ma.masked_array(x, mask=mask).compressed()
- margs.append(compressed_x)
- else:
- margs.append(x)
+ x = np.asarray(x)
+ margs.append(x)
+ masks = [] # list of masks that are True where good
+ for i, x in enumerate(margs):
+ if seqlist[i]:
+ if x.ndim > 1:
+ continue # Don't try to get nan locations unless 1-D.
+ if ma.isMA(x):
+ masks.append(~ma.getmaskarray(x)) # invert the mask
+ xd = x.data
+ else:
+ xd = x
+ try:
+ mask = np.isfinite(xd)
+ if isinstance(mask, np.ndarray):
+ masks.append(mask)
+ except: #Fixme: put in tuple of possible exceptions?
+ pass
+ if len(masks):
+ mask = reduce(np.logical_and, masks)
+ igood = mask.nonzero()[0]
+ if len(igood) < nrecs:
+ for i, x in enumerate(margs):
+ if seqlist[i]:
+ if (hasattr(x, 'get_compressed_copy')):
+ compressed_x = x.get_compressed_copy(~mask)
+ else:
+ compressed_x = x.take(igood, axis=0)
+ margs[i] = compressed_x
+ for i, x in enumerate(margs):
+ if seqlist[i] and ma.isMA(x):
+ margs[i] = x.filled()
return margs
Modified: trunk/matplotlib/lib/matplotlib/collections.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/collections.py 2008-07-20 18:21:11 UTC (rev 5796)
+++ trunk/matplotlib/lib/matplotlib/collections.py 2008-07-21 00:22:19 UTC (rev 5797)
@@ -90,7 +90,7 @@
self._uniform_offsets = None
self._offsets = np.array([], np.float_)
if offsets is not None:
- offsets = np.asarray(offsets, np.float_)
+ offsets = np.asarray(offsets)
if len(offsets.shape) == 1:
offsets = offsets[np.newaxis,:] # Make it Nx2.
if transOffset is not None:
Modified: trunk/matplotlib/unit/cbook_unit.py
===================================================================
--- trunk/matplotlib/unit/cbook_unit.py 2008-07-20 18:21:11 UTC (rev 5796)
+++ trunk/matplotlib/unit/cbook_unit.py 2008-07-21 00:22:19 UTC (rev 5797)
@@ -1,62 +1,52 @@
import unittest
+from datetime import datetime
+
import numpy as np
import matplotlib.cbook as cbook
+import matplotlib.colors as mcolors
-class TestAxes(unittest.TestCase):
- def test_delete_masked_points_arrays(self):
- input = ( [1,2,3,np.nan,5],
- np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,5))]*2
- actual = cbook.delete_masked_points(*input)
- assert np.allclose(actual, expected)
+from matplotlib.cbook import delete_masked_points as dmp
- input = ( np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
- np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,5))]*2
- actual = cbook.delete_masked_points(*input)
- assert np.allclose(actual, expected)
+class Test_delete_masked_points(unittest.TestCase):
+ def setUp(self):
+ self.mask1 = [False, False, True, True, False, False]
+ self.arr0 = np.arange(1.0,7.0)
+ self.arr1 = [1,2,3,np.nan,np.nan,6]
+ self.arr2 = np.array(self.arr1)
+ self.arr3 = np.ma.array(self.arr2, mask=self.mask1)
+ self.arr_s = ['a', 'b', 'c', 'd', 'e', 'f']
+ self.arr_s2 = np.array(self.arr_s)
+ self.arr_dt = [datetime(2008, 1, 1), datetime(2008, 1, 2),
+ datetime(2008, 1, 3), datetime(2008, 1, 4),
+ datetime(2008, 1, 5), datetime(2008, 1, 6)]
+ self.arr_dt2 = np.array(self.arr_dt)
+ self.arr_colors = ['r', 'g', 'b', 'c', 'm', 'y']
+ self.arr_rgba = mcolors.colorConverter.to_rgba_array(self.arr_colors)
- input = ( [1,2,3,np.nan,5],
- np.ma.array( [1,2,3,4,5], mask=[False,False,False,True,False] ),
- np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,5))]*3
- actual = cbook.delete_masked_points(*input)
- assert np.allclose(actual, expected)
+ def test_bad_first_arg(self):
+ self.assertRaises(ValueError, dmp, 'a string', self.arr0)
- input = ()
- expected = ()
- actual = cbook.delete_masked_points(*input)
- assert np.allclose(actual, expected)
+ def test_string_seq(self):
+ actual = dmp(self.arr_s, self.arr1)
+ ind = [0, 1, 2, 5]
+ expected = (self.arr_s2.take(ind), self.arr2.take(ind))
+ def test_datetime(self):
+ actual = dmp(self.arr_dt, self.arr3)
+ ind = [0, 1, 5]
+ expected = (self.arr_dt2.take(ind),
+ self.arr3.take(ind).compressed())
+ self.assert_(np.all(actual[0] == expected[0]) and
+ np.all(actual[1] == expected[1]))
- input = ( [1,2,3,np.nan,5],
- )
- expected = [np.array((1,2,3,5))]*1
- actual = cbook.delete_masked_points(*input)
- assert np.allclose(actual, expected)
+ def test_rgba(self):
+ actual = dmp(self.arr3, self.arr_rgba)
+ ind = [0, 1, 5]
+ expected = (self.arr3.take(ind).compressed(),
+ self.arr_rgba.take(ind, axis=0))
+ self.assert_(np.all(actual[0] == expected[0]) and
+ np.all(actual[1] == expected[1]))
- input = ( np.array((1,2,3,4,5)),
- )
- expected = [np.array((1,2,3,4,5))]*1
- actual = cbook.delete_masked_points(*input)
- assert np.allclose(actual, expected)
- def test_delete_masked_points_strings(self):
- input = ( 'hello',
- )
- expected = ('hello',)
- actual = cbook.delete_masked_points(*input)
- assert actual == expected
-
- input = ( u'hello',
- )
- expected = (u'hello',)
- actual = cbook.delete_masked_points(*input)
- assert actual == expected
-
-
if __name__=='__main__':
unittest.main()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-21 09:51:40
|
Revision: 5798
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5798&view=rev
Author: jdh2358
Date: 2008-07-21 09:50:36 +0000 (Mon, 21 Jul 2008)
Log Message:
-----------
Added Gael's backend fallback patch
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/scatter_demo.py
trunk/matplotlib/lib/matplotlib/backends/__init__.py
trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
trunk/matplotlib/lib/matplotlib/pyplot.py
trunk/matplotlib/lib/matplotlib/rcsetup.py
trunk/matplotlib/matplotlibrc.template
Modified: trunk/matplotlib/examples/pylab_examples/scatter_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/scatter_demo.py 2008-07-21 00:22:19 UTC (rev 5797)
+++ trunk/matplotlib/examples/pylab_examples/scatter_demo.py 2008-07-21 09:50:36 UTC (rev 5798)
@@ -6,5 +6,6 @@
y = 0.9*rand(N)
area = pi*(10 * rand(N))**2 # 0 to 10 point radiuses
scatter(x,y,s=area, marker='^', c='r')
-
+savefig('test.ps')
+savefig('test.pdf')
show()
Modified: trunk/matplotlib/lib/matplotlib/backends/__init__.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/__init__.py 2008-07-21 00:22:19 UTC (rev 5797)
+++ trunk/matplotlib/lib/matplotlib/backends/__init__.py 2008-07-21 09:50:36 UTC (rev 5798)
@@ -23,7 +23,9 @@
# Things we pull in from all backends
new_figure_manager = backend_mod.new_figure_manager
-
+ # image backends like pdf, agg or svg do not need to do anything
+ # for "show" or "draw_if_interactive", so if they are not defined
+ # by the backend, just do nothing
def do_nothing(*args, **kwargs): pass
backend_version = getattr(backend_mod,'backend_version', 'unknown')
show = getattr(backend_mod, 'show', do_nothing)
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py 2008-07-21 00:22:19 UTC (rev 5797)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py 2008-07-21 09:50:36 UTC (rev 5798)
@@ -67,7 +67,8 @@
for manager in Gcf.get_all_fig_managers():
manager.window.show()
- if mainloop and gtk.main_level() == 0:
+ if mainloop and gtk.main_level() == 0 and \
+ len(Gcf.get_all_fig_managers())>0:
gtk.main()
def new_figure_manager(num, *args, **kwargs):
Modified: trunk/matplotlib/lib/matplotlib/pyplot.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/pyplot.py 2008-07-21 00:22:19 UTC (rev 5797)
+++ trunk/matplotlib/lib/matplotlib/pyplot.py 2008-07-21 09:50:36 UTC (rev 5798)
@@ -1,12 +1,13 @@
import sys
import matplotlib
-from matplotlib import _pylab_helpers
+from matplotlib import _pylab_helpers, interactive
from matplotlib.cbook import dedent, silent_list, is_string_like, is_numlike
from matplotlib.figure import Figure, figaspect
from matplotlib.backend_bases import FigureCanvasBase
from matplotlib.image import imread as _imread
from matplotlib import rcParams, rcParamsDefault, get_backend
+from matplotlib.rcsetup import interactive_bk as _interactive_bk
from matplotlib.artist import getp, get, Artist
from matplotlib.artist import setp as _setp
from matplotlib.axes import Axes
@@ -32,7 +33,42 @@
MaxNLocator
+## Backend detection ##
+def _backend_selection():
+ """ If rcParams['backend_fallback'] is true, check to see if the
+ current backend is compatible with the current running event
+ loop, and if not switches to a compatible one.
+ """
+ backend = rcParams['backend']
+ if not rcParams['backend_fallback'] or \
+ backend not in _interactive_bk:
+ return
+ is_agg_backend = rcParams['backend'].endswith('Agg')
+ if 'wx' in sys.modules and not backend in ('WX', 'WXAgg'):
+ import wx
+ if wx.App.IsMainLoopRunning():
+ rcParams['backend'] = 'wx' + 'Agg' * is_agg_backend
+ elif 'qt' in sys.modules and not backend == 'QtAgg':
+ import qt
+ if not qt.qApp.startingUp():
+ # The mainloop is running.
+ rcParams['backend'] = 'qtAgg'
+ elif 'PyQt4.QtCore' in sys.modules and not backend == 'Qt4Agg':
+ import PyQt4.QtGui
+ if not PyQt4.QtGui.qApp.startingUp():
+ # The mainloop is running.
+ rcParams['backend'] = 'qt4Agg'
+ elif 'gtk' in sys.modules and not backend in ('GTK', 'GTKAgg',
+ 'GTKCairo'):
+ import gobject
+ if gobject.MainLoop().is_running():
+ rcParams['backend'] = 'gtk' + 'Agg' * is_agg_backend
+ elif 'Tkinter' in sys.modules and not backend == 'TkAgg':
+ #import Tkinter
+ pass #what if anything do we need to do for tkinter?
+_backend_selection()
+
## Global ##
from matplotlib.backends import pylab_setup
Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-07-21 00:22:19 UTC (rev 5797)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-07-21 09:50:36 UTC (rev 5798)
@@ -305,6 +305,7 @@
# a map from key -> value, converter
defaultParams = {
'backend' : ['Agg', validate_backend], # agg is certainly present
+ 'backend_fallback' : [True, validate_bool], # agg is certainly present
'numerix' : ['numpy', validate_numerix],
'maskedarray' : [False, validate_bool],
'toolbar' : ['toolbar2', validate_toolbar],
Modified: trunk/matplotlib/matplotlibrc.template
===================================================================
--- trunk/matplotlib/matplotlibrc.template 2008-07-21 00:22:19 UTC (rev 5797)
+++ trunk/matplotlib/matplotlibrc.template 2008-07-21 09:50:36 UTC (rev 5798)
@@ -26,6 +26,11 @@
# to the module name (which must be in the PYTHONPATH) as
# 'module://my_backend'
backend : %(backend)s
+
+# if you are runing pyplot inside a GUI and your backend choice
+# conflicts, we will automatically try and find a compatible one for
+# you if backend_fallback is True
+#backend_fallback: True
numerix : %(numerix)s # numpy, Numeric or numarray
#maskedarray : False # True to use external maskedarray module
# instead of numpy.ma; this is a temporary
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <dmk...@us...> - 2008-07-21 12:29:44
|
Revision: 5799
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5799&view=rev
Author: dmkaplan
Date: 2008-07-21 12:26:35 +0000 (Mon, 21 Jul 2008)
Log Message:
-----------
Recommitting my changes to clabel to allow for manual labeling after fixing
problems with indexing identified by Eric Firing on 19 July 2008.
In addition, I have made the following changes:
1) Placed more comments in contour.py with the intention of eventually doing
a rewrite or restructuring of that code.
2) Added two pylab_examples: contour_label_demo.py that tests out some of the
more advanced things that can now be done with contour labeling, and
ginput_manual_clabel.py that demonstrates some uses of ginput,
waitforbuttonpress, and clabel(...,manual=True). The first of these has been
integrated into backend_driver.py, but the second cannot be because it
requires interaction.
Modified Paths:
--------------
trunk/matplotlib/examples/tests/backend_driver.py
trunk/matplotlib/lib/matplotlib/blocking_input.py
trunk/matplotlib/lib/matplotlib/contour.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/contour_label_demo.py
trunk/matplotlib/examples/pylab_examples/ginput_manual_clabel.py
Added: trunk/matplotlib/examples/pylab_examples/contour_label_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/contour_label_demo.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/contour_label_demo.py 2008-07-21 12:26:35 UTC (rev 5799)
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+"""
+Illustrate some of the more advanced things that one can do with
+contour labels.
+
+See also contour_demo.py.
+"""
+import matplotlib
+import numpy as np
+import matplotlib.cm as cm
+import matplotlib.mlab as mlab
+import matplotlib.pyplot as plt
+
+matplotlib.rcParams['xtick.direction'] = 'out'
+matplotlib.rcParams['ytick.direction'] = 'out'
+
+##################################################
+# Define our surface
+##################################################
+delta = 0.025
+x = np.arange(-3.0, 3.0, delta)
+y = np.arange(-2.0, 2.0, delta)
+X, Y = np.meshgrid(x, y)
+Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
+Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
+# difference of Gaussians
+Z = 10.0 * (Z2 - Z1)
+
+##################################################
+# Make contour labels using creative float classes
+# Follows suggestion of Manuel Metz
+##################################################
+plt.figure()
+
+# Basic contour plot
+CS = plt.contour(X, Y, Z)
+
+# Define a class that forces representation of float to look a certain way
+# This remove trailing zero so '1.0' becomes '1'
+class nf(float):
+ def __repr__(self):
+ str = '%.1f' % (self.__float__(),)
+ if str[-1]=='0':
+ return '%.0f' % self.__float__()
+ else:
+ return '%.1f' % self.__float__()
+
+# Recast levels to new class
+CS.levels = [nf(val) for val in CS.levels ]
+
+# Label levels with specially formatted floats
+plt.clabel(CS, CS.levels, inline=True, fmt='%r %%', fontsize=10)
+
+##################################################
+# Label contours with arbitrary strings using a
+# dictionary
+##################################################
+plt.figure()
+
+# Basic contour plot
+CS = plt.contour(X, Y, Z)
+
+fmt = {}
+strs = [ 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh' ]
+for l,s in zip( CS.levels, strs ):
+ fmt[l] = s
+
+# Label every other level using strings
+plt.clabel(CS,CS.levels[::2],inline=True,fmt=fmt,fontsize=10)
+
+##################################################
+# Show the hole thing
+##################################################
+plt.show()
Added: trunk/matplotlib/examples/pylab_examples/ginput_manual_clabel.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/ginput_manual_clabel.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/ginput_manual_clabel.py 2008-07-21 12:26:35 UTC (rev 5799)
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+"""
+This provides examples of uses of interactive functions, such as ginput,
+waitforbuttonpress and manual clabel placement.
+
+This script must be run interactively using a backend that has a
+graphical user interface (for example, from inside ipython using
+GTKAgg backend, but not PS backend).
+"""
+import time
+import matplotlib
+import numpy as np
+import matplotlib.cm as cm
+import matplotlib.mlab as mlab
+import matplotlib.pyplot as plt
+
+def tellme(s):
+ print s
+ plt.title(s,fontsize=16)
+ plt.draw()
+
+##################################################
+# Define a triangle by clicking three points
+##################################################
+plt.clf()
+plt.axis([-1.,1.,-1.,1.])
+plt.setp(plt.gca(),autoscale_on=False)
+
+tellme('You will define a triangle, click to begin')
+
+plt.waitforbuttonpress()
+
+happy = False
+while not happy:
+ pts = []
+ while len(pts) < 3:
+ tellme('Select 3 corners with mouse')
+ pts = np.asarray( plt.ginput(3,timeout=-1) )
+ if len(pts) < 3:
+ tellme('Too few points, starting over')
+ time.sleep(1) # Wait a second
+
+ ph = plt.fill( pts[:,0], pts[:,1], 'r', lw=2 )
+
+ tellme('Happy? Key click for yes, mouse click for no')
+
+ happy = plt.waitforbuttonpress()
+
+ # Get rid of fill
+ if not happy:
+ for p in ph: p.remove()
+
+##################################################
+# Now contour according to distance from triangle
+# corners - just an example
+##################################################
+
+# Define a nice function of distance from individual pts
+def f(x,y,pts):
+ z = np.zeros_like(x)
+ for p in pts:
+ z = z + 1/(np.sqrt((x-p[0])**2+(y-p[1])**2))
+ return 1/z
+
+X,Y = np.meshgrid( np.linspace(-1,1,51), np.linspace(-1,1,51) )
+Z = f(X,Y,pts)
+
+CS = plt.contour( X, Y, Z, 20 )
+
+tellme( 'Use mouse to select contour label locations, middle button to finish' )
+CL = plt.clabel( CS, manual=True )
+
+##################################################
+# Now do a zoom
+##################################################
+tellme( 'Now do a nested zoom, click to begin' )
+plt.waitforbuttonpress()
+
+happy = False
+while not happy:
+ tellme( 'Select two corners of zoom, middle mouse button to finish' )
+ pts = np.asarray( plt.ginput(2,timeout=-1) )
+
+ happy = len(pts) < 2
+ if happy: break
+
+ pts = np.sort(pts,axis=0)
+ plt.axis( pts.T.ravel() )
Modified: trunk/matplotlib/examples/tests/backend_driver.py
===================================================================
--- trunk/matplotlib/examples/tests/backend_driver.py 2008-07-21 09:50:36 UTC (rev 5798)
+++ trunk/matplotlib/examples/tests/backend_driver.py 2008-07-21 12:26:35 UTC (rev 5799)
@@ -39,6 +39,7 @@
'color_demo.py',
'cohere_demo.py',
'contour_demo.py',
+ 'contour_label_demo.py',
'contourf_demo.py',
'csd_demo.py',
'custom_ticker1.py',
Modified: trunk/matplotlib/lib/matplotlib/blocking_input.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-21 09:50:36 UTC (rev 5798)
+++ trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-21 12:26:35 UTC (rev 5799)
@@ -5,11 +5,11 @@
creates a callable object to retrieve events in a blocking way for interactive sessions
:class:`BlockingKeyMouseInput`
- creates a callable object to retrieve key or mouse clicks in a blocking way for interactive sessions.
+ creates a callable object to retrieve key or mouse clicks in a blocking way for interactive sessions.
Note: Subclass of BlockingInput. Used by waitforbuttonpress
:class:`BlockingMouseInput`
- creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions.
+ creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions.
Note: Subclass of BlockingInput. Used by ginput
:class:`BlockingContourLabeler`
@@ -46,7 +46,7 @@
# This will extract info from events
self.post_event()
-
+
# Check if we have enough events already
if len(self.events) >= self.n and self.n > 0:
self.done = True
@@ -84,7 +84,7 @@
"""
Blocking call to retrieve n events
"""
-
+
assert isinstance(n, int), "Requires an integer argument"
self.n = n
@@ -94,7 +94,7 @@
# Ensure that the figure is shown
self.fig.show()
-
+
# connect the events to the on_event function call
for n in self.eventslist:
self.callbacks.append( self.fig.canvas.mpl_connect(n, self.on_event) )
@@ -124,7 +124,7 @@
blocking way.
"""
def __init__(self, fig):
- BlockingInput.__init__(self, fig=fig,
+ BlockingInput.__init__(self, fig=fig,
eventslist=('button_press_event',) )
def post_event(self):
@@ -194,7 +194,7 @@
"""
self.clicks.append((event.xdata,event.ydata))
- verbose.report("input %i: %f,%f" %
+ verbose.report("input %i: %f,%f" %
(len(self.clicks),event.xdata, event.ydata))
# If desired plot up click
@@ -209,7 +209,7 @@
removing the last click.
"""
self.clicks.pop(index)
-
+
if self.show_clicks:
mark = self.marks.pop(index)
mark.remove()
@@ -234,7 +234,7 @@
# Call base class to remove callbacks
BlockingInput.cleanup(self)
-
+
def __call__(self, n=1, timeout=30, show_clicks=True):
"""
Blocking call to retrieve n coordinate pairs through mouse
@@ -261,11 +261,18 @@
This will be called if an event involving a button other than
2 or 3 occcurs. This will add a label to a contour.
"""
- if event.inaxes == self.cs.ax:
- conmin,segmin,imin,xmin,ymin = self.cs.find_nearest_contour(
- event.x, event.y)[:5]
- paths = self.cs.collections[conmin].get_paths()
+ # Shorthand
+ cs = self.cs
+
+ if event.inaxes == cs.ax:
+ conmin,segmin,imin,xmin,ymin = cs.find_nearest_contour(
+ event.x, event.y, cs.label_indices)[:5]
+
+ # Get index of nearest level in subset of levels used for labeling
+ lmin = cs.label_indices.index(conmin)
+
+ paths = cs.collections[conmin].get_paths()
lc = paths[segmin].vertices
# Figure out label rotation. This is very cludgy.
@@ -287,15 +294,15 @@
if rotation < -90:
rotation = 180 + rotation
- self.cs.add_label(xmin,ymin,rotation,conmin)
+ cs.add_label(xmin,ymin,rotation,cs.label_levels[lmin],
+ cs.label_cvalues[lmin])
if self.inline:
# Get label width for breaking contours
- lw = self.cs.get_label_width(self.cs.label_levels[conmin],
- self.cs.fmt,
- self.cs.fslist[conmin])
+ lw = cs.get_label_width(cs.label_levels[lmin],
+ cs.fmt, cs.fslist[lmin])
# Break contour
- new=self.cs.break_linecontour(lc,rotation,lw,imin)
+ new=cs.break_linecontour(lc,rotation,lw,imin)
if len(new[0]):
paths[segmin] = path.Path(new[0])
if len(new[1]):
@@ -304,7 +311,7 @@
self.fig.canvas.draw()
else: # Remove event if not valid
BlockingInput.pop(self)
-
+
def button3(self,event):
"""
This will be called if button 3 is clicked. This will remove
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2008-07-21 09:50:36 UTC (rev 5798)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2008-07-21 12:26:35 UTC (rev 5799)
@@ -17,6 +17,9 @@
import matplotlib.text as text
import matplotlib.cbook as cbook
+# Import needed for adding manual selection capability to clabel
+from matplotlib.blocking_input import BlockingContourLabeler
+
# We can't use a single line collection for contour because a line
# collection can have only a single line style, and we want to be able to have
# dashed negative contours, for example, and solid positive contours.
@@ -68,16 +71,49 @@
*fmt*:
a format string for the label. Default is '%1.3f'
+ Alternatively, this can be a dictionary matching contour
+ levels with arbitrary strings to use for each contour level
+ (i.e., fmt[level]=string)
+ *manual*:
+ if *True*, contour labels will be placed manually using
+ mouse clicks. Click the first button near a contour to
+ add a label, click the second button (or potentially both
+ mouse buttons at once) to finish adding labels. The third
+ button can be used to remove the last label added, but
+ only if labels are not inline.
"""
+
+ """"
+ NOTES on how this all works:
+
+ clabel basically takes the input arguments and uses them to
+ add a list of "label specific" attributes to the ContourSet
+ object. These attributes currently include: label_indices,
+ label_levels, label_cvalues, fp (font properties), fslist
+ (fontsize list), label_mappable, cl (list of text objects of
+ labels), cl_xy (coordinates of labels), cl_cvalues (color
+ values of the actual labels).
+
+ Note that these property names do not conform to the standards
+ set for coding matplotlib and I (DMK) eventually plan on
+ changing them so that they are clearer and conform to
+ standards.
+
+ Once these attributes are set, clabel passes control to the
+ labels method (case of automatic label placement) or
+ BlockingContourLabeler (case of manual label placement.
+ """
+
fontsize = kwargs.get('fontsize', None)
inline = kwargs.get('inline', 1)
self.fmt = kwargs.get('fmt', '%1.3f')
_colors = kwargs.get('colors', None)
+ # Detect if manual selection is desired and remove from argument list
+ self.manual_select=kwargs.get('manual',False)
-
if len(args) == 0:
levels = self.levels
indices = range(len(self.levels))
@@ -126,10 +162,16 @@
#self.cl_cvalues = [] # same
self.cl_xy = []
- self.labels(inline)
+ if self.manual_select:
+ print 'Select label locations manually using first mouse button.'
+ print 'End manual selection with second mouse button.'
+ if not inline:
+ print 'Remove last label by clicking third mouse button.'
- for label in self.cl:
- self.ax.add_artist(label)
+ blocking_contour_labeler = BlockingContourLabeler(self)
+ blocking_contour_labeler(inline)
+ else:
+ self.labels(inline)
self.label_list = cbook.silent_list('text.Text', self.cl)
return self.label_list
@@ -141,10 +183,10 @@
if lcsize > 10 * labelwidth:
return 1
- xmax = np.amax(np.array(linecontour)[:,0])
- xmin = np.amin(np.array(linecontour)[:,0])
- ymax = np.amax(np.array(linecontour)[:,1])
- ymin = np.amin(np.array(linecontour)[:,1])
+ xmax = np.amax(linecontour[:,0])
+ xmin = np.amin(linecontour[:,0])
+ ymax = np.amax(linecontour[:,1])
+ ymin = np.amin(linecontour[:,1])
lw = labelwidth
if (xmax - xmin) > 1.2* lw or (ymax - ymin) > 1.2 * lw:
@@ -180,12 +222,10 @@
if self.too_close(x,y, lw):
continue
else:
- self.cl_xy.append((x,y))
return x,y, ind
ind = adist[0]
x, y = XX[ind][hysize], YY[ind][hysize]
- self.cl_xy.append((x,y))
return x,y, ind
def get_label_width(self, lev, fmt, fsize):
@@ -193,7 +233,7 @@
if cbook.is_string_like(lev):
lw = (len(lev)) * fsize
else:
- lw = (len(fmt%lev)) * fsize
+ lw = (len(self.get_text(lev,fmt))) * fsize
return lw
@@ -210,9 +250,11 @@
if cbook.is_string_like(lev):
return lev
else:
- return fmt%lev
+ if isinstance(fmt,dict):
+ return fmt[lev]
+ else:
+ return fmt%lev
-
def break_linecontour(self, linecontour, rot, labelwidth, ind):
"break a contour in two contours at the location of the label"
lcsize = len(linecontour)
@@ -226,8 +268,8 @@
slc = trans.transform(linecontour)
x,y = slc[ind]
- xx= np.asarray(slc)[:,0].copy()
- yy=np.asarray(slc)[:,1].copy()
+ xx=slc[:,0].copy()
+ yy=slc[:,1].copy()
#indices which are under the label
inds, = np.nonzero(((xx < x+xlabel) & (xx > x-xlabel)) &
@@ -308,8 +350,8 @@
else:
ysize = labelwidth
- XX = np.resize(np.asarray(linecontour)[:,0],(xsize, ysize))
- YY = np.resize(np.asarray(linecontour)[:,1],(xsize, ysize))
+ XX = np.resize(linecontour[:,0],(xsize, ysize))
+ YY = np.resize(linecontour[:,1],(xsize, ysize))
#I might have fouled up the following:
yfirst = YY[:,0].reshape(xsize, 1)
ylast = YY[:,-1].reshape(xsize, 1)
@@ -335,19 +377,38 @@
return x,y, rotation, dind
+ def add_label(self,x,y,rotation,lev,cvalue):
+ dx,dy = self.ax.transData.inverted().transform_point((x,y))
+ t = text.Text(dx, dy, rotation = rotation,
+ horizontalalignment='center',
+ verticalalignment='center')
+
+ color = self.label_mappable.to_rgba(cvalue,alpha=self.alpha)
+
+ _text = self.get_text(lev,self.fmt)
+ self.set_label_props(t, _text, color)
+ self.cl.append(t)
+ self.cl_cvalues.append(cvalue)
+ self.cl_xy.append((x,y))
+
+ # Add label to plot here - useful for manual mode label selection
+ self.ax.add_artist(t)
+
+ def pop_label(self,index=-1):
+ '''Defaults to removing last label, but any index can be supplied'''
+ self.cl_cvalues.pop(index)
+ t = self.cl.pop(index)
+ t.remove()
+
def labels(self, inline):
- levels = self.label_levels
- fslist = self.fslist
- trans = self.ax.transData
- _colors = self.label_mappable.to_rgba(self.label_cvalues,
- alpha=self.alpha)
- fmt = self.fmt
- for icon, lev, color, cvalue, fsize in zip(self.label_indices,
- self.label_levels,
- _colors,
- self.label_cvalues, fslist):
+ trans = self.ax.transData # A bit of shorthand
+
+ for icon, lev, fsize, cvalue in zip(
+ self.label_indices, self.label_levels, self.fslist,
+ self.label_cvalues ):
+
con = self.collections[icon]
- lw = self.get_label_width(lev, fmt, fsize)
+ lw = self.get_label_width(lev, self.fmt, fsize)
additions = []
paths = con.get_paths()
for segNum, linepath in enumerate(paths):
@@ -356,28 +417,27 @@
# avoid division by zero
if np.all(linecontour[0] == linecontour[-1]):
linecontour = np.concatenate((linecontour,
- linecontour[1][np.newaxis,:]))
+ linecontour[1][np.newaxis,:]))
#linecontour.append(linecontour[1])
# transfer all data points to screen coordinates
slc = trans.transform(linecontour)
if self.print_label(slc,lw):
x,y, rotation, ind = self.locate_label(slc, lw)
- # transfer the location of the label back to
- # data coordinates
- dx,dy = trans.inverted().transform_point((x,y))
- t = text.Text(dx, dy, rotation = rotation,
- horizontalalignment='center',
- verticalalignment='center')
- _text = self.get_text(lev,fmt)
- self.set_label_props(t, _text, color)
- self.cl.append(t)
- self.cl_cvalues.append(cvalue)
+
+ # Actually add the label
+ self.add_label(x,y,rotation,lev,cvalue)
+
+ # Use break_linecontour to split contours for inlining
if inline:
- new = self.break_linecontour(linecontour, rotation, lw, ind)
+ new = self.break_linecontour(linecontour, rotation,
+ lw, ind)
if len(new[0]):
paths[segNum] = path.Path(new[0])
if len(new[1]):
additions.append(path.Path(new[1]))
+
+ # After looping over all segments on a contour, append
+ # new paths to existing
paths.extend(additions)
@@ -802,19 +862,8 @@
Use keyword args to control colors, linewidth, origin, cmap ... see
below for more details.
- *X*, *Y*, and *Z* may be arrays all with the same 2-D shape, or
- *X* and *Y* can be 1-D while *Z* is 2-D. In the latter
- case, the following must be true:
+ *X*, *Y*, and *Z* must be arrays with the same dimensions.
- ::
-
- Z.shape == len(Y), len(X)
-
- Note that the first index of *Z*, the row number, corresponds
- to the vertical coordinate on the page, while the second
- index, the column number, corresponds to the horizontal
- coordinate on the page.
-
*Z* may be a masked array, but filled contouring may not
handle internal masked regions correctly.
@@ -908,3 +957,70 @@
.. plot:: contour_demo.py
"""
+
+ def find_nearest_contour( self, x, y, indices=None, pixel=True ):
+ """
+ Finds contour that is closest to a point. Defaults to
+ measuring distance in pixels (screen space - useful for manual
+ contour labeling), but this can be controlled via a keyword
+ argument.
+
+ Returns a tuple containing the contour, segment, index of
+ segment, x & y of segment point and distance to minimum point.
+
+ Call signature::
+
+ conmin,segmin,imin,xmin,ymin,dmin = find_nearest_contour(
+ self, x, y, indices=None, pixel=True )
+
+ Optional keyword arguments::
+
+ *indices*:
+ Indexes of contour levels to consider when looking for
+ nearest point. Defaults to using all levels.
+
+ *pixel*:
+ If *True*, measure distance in pixel space, if not, measure
+ distance in axes space. Defaults to *True*.
+
+ """
+
+ # This function uses a method that is probably quite
+ # inefficient based on converting each contour segment to
+ # pixel coordinates and then comparing the given point to
+ # those coordinates for each contour. This will probably be
+ # quite slow for complex contours, but for normal use it works
+ # sufficiently well that the time is not noticeable.
+ # Nonetheless, improvements could probably be made.
+
+ if indices==None:
+ indices = range(len(self.levels))
+
+ dmin = 1e10
+ conmin = None
+ segmin = None
+ xmin = None
+ ymin = None
+
+ for icon in indices:
+ con = self.collections[icon]
+ paths = con.get_paths()
+ for segNum, linepath in enumerate(paths):
+ lc = linepath.vertices
+
+ # transfer all data points to screen coordinates if desired
+ if pixel:
+ lc = self.ax.transData.transform(lc)
+
+ ds = (lc[:,0]-x)**2 + (lc[:,1]-y)**2
+ d = min( ds )
+ if d < dmin:
+ dmin = d
+ conmin = icon
+ segmin = segNum
+ imin = mpl.mlab.find( ds == d )[0]
+ xmin = lc[imin,0]
+ ymin = lc[imin,1]
+
+ return (conmin,segmin,imin,xmin,ymin,dmin)
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ef...@us...> - 2008-07-21 19:08:32
|
Revision: 5802
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5802&view=rev
Author: efiring
Date: 2008-07-21 19:08:29 +0000 (Mon, 21 Jul 2008)
Log Message:
-----------
In image.py, ensure input can be ndarray or MaskedArray (Klaus Zimmerman).
Masked 2-D arrays are handled automatically by the color mapping
framework, so they need to be passed through; but there is no
point in converting 3-D arrays into masked arrays because there
is no support for dealing with a mask in that case.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/image.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-21 12:58:53 UTC (rev 5801)
+++ trunk/matplotlib/CHANGELOG 2008-07-21 19:08:29 UTC (rev 5802)
@@ -1,3 +1,7 @@
+2008-07-21 Changed the "asarray" strategy in image.py so that
+ colormapping of masked input should work for all
+ image types (thanks Klaus Zimmerman) - EF
+
2008-07-20 Rewrote cbook.delete_masked_points and corresponding
unit test to support rgb color array inputs, datetime
inputs, etc. - EF
Modified: trunk/matplotlib/lib/matplotlib/image.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/image.py 2008-07-21 12:58:53 UTC (rev 5801)
+++ trunk/matplotlib/lib/matplotlib/image.py 2008-07-21 19:08:29 UTC (rev 5802)
@@ -272,10 +272,11 @@
ACCEPTS: numpy/PIL Image A"""
# check if data is PIL Image without importing Image
if hasattr(A,'getpixel'):
- X = pil_to_array(A)
+ self._A = pil_to_array(A)
+ elif ma.isMA(A):
+ self._A = A
else:
- X = ma.asarray(A) # assume array
- self._A = X
+ self._A = np.asarray(A) # assume array
self._imcache =None
self._rgbacache = None
@@ -408,7 +409,8 @@
def set_data(self, x, y, A):
x = np.asarray(x,np.float32)
y = np.asarray(y,np.float32)
- A = np.asarray(A)
+ if not ma.isMA(A):
+ A = np.asarray(A)
if len(x.shape) != 1 or len(y.shape) != 1\
or A.shape[0:2] != (y.shape[0], x.shape[0]):
raise TypeError("Axes don't match array shape")
@@ -535,7 +537,8 @@
def set_data(self, x, y, A):
- A = ma.asarray(A)
+ if not ma.isMA(A):
+ A = np.asarray(A)
if x is None:
x = np.arange(0, A.shape[1]+1, dtype=np.float64)
else:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ef...@us...> - 2008-07-21 19:39:15
|
Revision: 5803
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5803&view=rev
Author: efiring
Date: 2008-07-21 19:39:12 +0000 (Mon, 21 Jul 2008)
Log Message:
-----------
Add get_offsets, set_offsets to Collection (Ryan Kraus)
Modified Paths:
--------------
trunk/matplotlib/API_CHANGES
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/collections.py
Modified: trunk/matplotlib/API_CHANGES
===================================================================
--- trunk/matplotlib/API_CHANGES 2008-07-21 19:08:29 UTC (rev 5802)
+++ trunk/matplotlib/API_CHANGES 2008-07-21 19:39:12 UTC (rev 5803)
@@ -1,6 +1,9 @@
Changes for 0.98.x
==================
+* Methods get_offsets and set_offsets added to Collections base
+ class.
+
* Figure.figurePatch renamed Figure.patch, Axes.axesPatch renamed
Axes.patch, Axes.axesFrame renamed Axes.frame, Axes.get_frame, which
returns Axes.patch, is deprecated. Examples and users guide updated
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-21 19:08:29 UTC (rev 5802)
+++ trunk/matplotlib/CHANGELOG 2008-07-21 19:39:12 UTC (rev 5803)
@@ -1,3 +1,6 @@
+2008-07-21 Committed patch by Ryan May to add get_offsets and
+ set_offsets to Collections base class - EF
+
2008-07-21 Changed the "asarray" strategy in image.py so that
colormapping of masked input should work for all
image types (thanks Klaus Zimmerman) - EF
Modified: trunk/matplotlib/lib/matplotlib/collections.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/collections.py 2008-07-21 19:08:29 UTC (rev 5802)
+++ trunk/matplotlib/lib/matplotlib/collections.py 2008-07-21 19:39:12 UTC (rev 5803)
@@ -218,6 +218,32 @@
def set_pickradius(self,pickradius): self.pickradius = 5
def get_pickradius(self): return self.pickradius
+ def set_offsets(self, offsets):
+ """
+ Set the offsets for the collection. *offsets* can be a scalar
+ or a sequence.
+
+ ACCEPTS: float or sequence of floats
+ """
+ offsets = np.asarray(offsets, np.float_)
+ if len(offsets.shape) == 1:
+ offsets = offsets[np.newaxis,:] # Make it Nx2.
+ #This decision is based on how they are initialized above
+ if self._uniform_offsets is None:
+ self._offsets = offsets
+ else:
+ self._uniform_offsets = offsets
+
+ def get_offsets(self):
+ """
+ Return the offsets for the collection.
+ """
+ #This decision is based on how they are initialized above in __init__()
+ if self._uniform_offsets is None:
+ return self._offsets
+ else:
+ return self._uniform_offsets
+
def set_linewidths(self, lw):
"""
Set the linewidth(s) for the collection. *lw* can be a scalar
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-07-21 22:42:54
|
Revision: 5804
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5804&view=rev
Author: mdboom
Date: 2008-07-21 22:42:52 +0000 (Mon, 21 Jul 2008)
Log Message:
-----------
Re-introduce offset_copy
Modified Paths:
--------------
trunk/matplotlib/API_CHANGES
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/transforms.py
Modified: trunk/matplotlib/API_CHANGES
===================================================================
--- trunk/matplotlib/API_CHANGES 2008-07-21 19:39:12 UTC (rev 5803)
+++ trunk/matplotlib/API_CHANGES 2008-07-21 22:42:52 UTC (rev 5804)
@@ -130,8 +130,6 @@
Transform.inverse_xy_tup(points) Transform.inverted().transform(points)
- offset_copy(trans, x, y) trans + Affine2D().translate(x, y)
-
axes.py
Axes.get_position() Axes.get_position()
[Axes.get_position() used to return a list of points, not it
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-21 19:39:12 UTC (rev 5803)
+++ trunk/matplotlib/CHANGELOG 2008-07-21 22:42:52 UTC (rev 5804)
@@ -1,3 +1,6 @@
+2008-07-21 Re-introduced offset_copy that works in the context of the
+ new transforms. - MGD
+
2008-07-21 Committed patch by Ryan May to add get_offsets and
set_offsets to Collections base class - EF
Modified: trunk/matplotlib/lib/matplotlib/transforms.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/transforms.py 2008-07-21 19:39:12 UTC (rev 5803)
+++ trunk/matplotlib/lib/matplotlib/transforms.py 2008-07-21 22:42:52 UTC (rev 5804)
@@ -2144,6 +2144,27 @@
((a < b) and (a < val and b > val))
or (b < val and a > val))
+def offset_copy(trans, fig, x=0.0, y=0.0, units='inches'):
+ '''
+ Return a new transform with an added offset.
+ args:
+ trans is any transform
+ kwargs:
+ fig is the current figure; it can be None if units are 'dots'
+ x, y give the offset
+ units is 'inches', 'points' or 'dots'
+ '''
+ if units == 'dots':
+ return trans + Affine2D().translate(x, y)
+ if fig is None:
+ raise ValueError('For units of inches or points a fig kwarg is needed')
+ if units == 'points':
+ x /= 72.0
+ y /= 72.0
+ elif not units == 'inches':
+ raise ValueError('units must be dots, points, or inches')
+ return trans + ScaledTranslation(x, y, fig.dpi_scale_trans)
+
if __name__ == '__main__':
import copy
from random import random
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-07-22 01:52:15
|
Revision: 5805
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5805&view=rev
Author: jswhit
Date: 2008-07-22 01:52:12 +0000 (Tue, 22 Jul 2008)
Log Message:
-----------
added scikits.delaunay as matplotlib.delaunay, added griddata function to mlab.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/examples/tests/backend_driver.py
trunk/matplotlib/setup.py
trunk/matplotlib/setupext.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/griddata_demo.py
trunk/matplotlib/lib/matplotlib/delaunay/
trunk/matplotlib/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp
trunk/matplotlib/lib/matplotlib/delaunay/VoronoiDiagramGenerator.h
trunk/matplotlib/lib/matplotlib/delaunay/__init__.py
trunk/matplotlib/lib/matplotlib/delaunay/_delaunay.cpp
trunk/matplotlib/lib/matplotlib/delaunay/delaunay_utils.cpp
trunk/matplotlib/lib/matplotlib/delaunay/delaunay_utils.h
trunk/matplotlib/lib/matplotlib/delaunay/interpolate.py
trunk/matplotlib/lib/matplotlib/delaunay/natneighbors.cpp
trunk/matplotlib/lib/matplotlib/delaunay/natneighbors.h
trunk/matplotlib/lib/matplotlib/delaunay/testfuncs.py
trunk/matplotlib/lib/matplotlib/delaunay/triangulate.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-21 22:42:52 UTC (rev 5804)
+++ trunk/matplotlib/CHANGELOG 2008-07-22 01:52:12 UTC (rev 5805)
@@ -1,3 +1,8 @@
+2008-07-21 Added scikits.delaunay as matplotlib.delaunay. Added griddata
+ function in matplotlib.mlab, with example (griddata_demo.py) in
+ pylab_examples. griddata function will use mpl_toolkits._natgrid
+ if installed (haven't yet created the toolkit). - JSW
+
2008-07-21 Re-introduced offset_copy that works in the context of the
new transforms. - MGD
Added: trunk/matplotlib/examples/pylab_examples/griddata_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/griddata_demo.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/griddata_demo.py 2008-07-22 01:52:12 UTC (rev 5805)
@@ -0,0 +1,40 @@
+from numpy.random import uniform, seed
+from matplotlib.mlab import griddata
+import matplotlib.pyplot as plt
+import numpy as np
+# make up data.
+#npts = int(raw_input('enter # of random points to plot:'))
+seed(-1)
+npts = 200
+x = uniform(-2,2,npts)
+y = uniform(-2,2,npts)
+z = x*np.exp(-x**2-y**2)
+# define grid.
+xi = np.linspace(-2.1,2.1,100)
+yi = np.linspace(-2.1,2.1,100)
+# grid the data.
+zi = griddata(x,y,z,xi,yi)
+# contour the gridded data, plotting dots at the nonuniform data points.
+CS = plt.contour(xi,yi,zi,15,linewidths=0.5,colors='k')
+CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)
+plt.colorbar() # draw colorbar
+# plot data points.
+plt.scatter(x,y,marker='o',c='b',s=5)
+plt.xlim(-2,2)
+plt.ylim(-2,2)
+plt.title('griddata test (%d points)' % npts)
+plt.show()
+
+# test case that scikits.delaunay fails on, but natgrid passes..
+#data = np.array([[-1, -1], [-1, 0], [-1, 1],
+# [ 0, -1], [ 0, 0], [ 0, 1],
+# [ 1, -1 - np.finfo(np.float_).eps], [ 1, 0], [ 1, 1],
+# ])
+#x = data[:,0]
+#y = data[:,1]
+#z = x*np.exp(-x**2-y**2)
+## define grid.
+#xi = np.linspace(-1.1,1.1,100)
+#yi = np.linspace(-1.1,1.1,100)
+## grid the data.
+#zi = griddata(x,y,z,xi,yi)
Modified: trunk/matplotlib/examples/tests/backend_driver.py
===================================================================
--- trunk/matplotlib/examples/tests/backend_driver.py 2008-07-21 22:42:52 UTC (rev 5804)
+++ trunk/matplotlib/examples/tests/backend_driver.py 2008-07-22 01:52:12 UTC (rev 5805)
@@ -41,6 +41,7 @@
'contour_demo.py',
'contour_label_demo.py',
'contourf_demo.py',
+ 'griddata_demo.py',
'csd_demo.py',
'custom_ticker1.py',
'customize_rc.py',
Added: trunk/matplotlib/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp
===================================================================
--- trunk/matplotlib/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp (rev 0)
+++ trunk/matplotlib/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp 2008-07-22 01:52:12 UTC (rev 5805)
@@ -0,0 +1,1152 @@
+/*
+ * The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T
+ * Bell Laboratories.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * This code was originally written by Stephan Fortune in C code. Shane O'Sullivan,
+ * have since modified it, encapsulating it in a C++ class and, fixing memory leaks and
+ * adding accessors to the Voronoi Edges.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * Subsequently, Robert Kern modified it to yield Python objects.
+ * Copyright 2005 Robert Kern <rob...@gm...>
+ * See LICENSE.txt in the scipy source directory.
+ */
+
+#include "VoronoiDiagramGenerator.h"
+
+VoronoiDiagramGenerator::VoronoiDiagramGenerator()
+{
+ siteidx = 0;
+ sites = 0;
+
+ allMemoryList = new FreeNodeArrayList;
+ allMemoryList->memory = 0;
+ allMemoryList->next = 0;
+ currentMemoryBlock = allMemoryList;
+ allEdges = 0;
+ allEdgeList = 0;
+ iteratorEdges = 0;
+ iterEdgeList = 0;
+ minDistanceBetweenSites = 0;
+}
+
+VoronoiDiagramGenerator::~VoronoiDiagramGenerator()
+{
+ cleanupEdgeList();
+ cleanup();
+ cleanupEdges();
+
+ if(allMemoryList != 0)
+ delete allMemoryList;
+}
+
+
+
+bool VoronoiDiagramGenerator::generateVoronoi(double *xValues, double *yValues, int numPoints, double minX, double maxX, double minY, double maxY, double minDist)
+{
+ cleanupEdgeList();
+ cleanup();
+ cleanupEdges();
+ int i;
+
+ minDistanceBetweenSites = minDist;
+
+ nsites=numPoints;
+ plot = 0;
+ triangulate = 0;
+ debug = 1;
+ sorted = 0;
+ freeinit(&sfl, sizeof (Site));
+
+ sites = (struct Site *) myalloc(nsites*sizeof( *sites));
+
+ if(sites == 0)
+ return false;
+
+ xmin = xValues[0];
+ ymin = yValues[0];
+ xmax = xValues[0];
+ ymax = yValues[0];
+
+ for(i = 0; i< nsites; i++)
+ {
+ sites[i].coord.x = xValues[i];
+ sites[i].coord.y = yValues[i];
+ sites[i].sitenbr = i;
+ sites[i].refcnt = 0;
+
+ if(xValues[i] < xmin)
+ xmin = xValues[i];
+ else if(xValues[i] > xmax)
+ xmax = xValues[i];
+
+ if(yValues[i] < ymin)
+ ymin = yValues[i];
+ else if(yValues[i] > ymax)
+ ymax = yValues[i];
+
+ //printf("\n%f %f\n",xValues[i],yValues[i]);
+ }
+
+ qsort(sites, nsites, sizeof (*sites), scomp);
+
+ siteidx = 0;
+ geominit();
+ double temp = 0;
+ if(minX > maxX)
+ {
+ temp = minX;
+ minX = maxX;
+ maxX = temp;
+ }
+ if(minY > maxY)
+ {
+ temp = minY;
+ minY = maxY;
+ maxY = temp;
+ }
+ borderMinX = minX;
+ borderMinY = minY;
+ borderMaxX = maxX;
+ borderMaxY = maxY;
+
+ siteidx = 0;
+
+ voronoi(triangulate);
+
+ return true;
+}
+
+bool VoronoiDiagramGenerator::ELinitialize()
+{
+ int i;
+ freeinit(&hfl, sizeof **ELhash);
+ ELhashsize = 2 * sqrt_nsites;
+ ELhash = (struct Halfedge **) myalloc ( sizeof *ELhash * ELhashsize);
+
+ if(ELhash == 0)
+ return false;
+
+ for(i=0; i<ELhashsize; i +=1) ELhash[i] = (struct Halfedge *)NULL;
+ ELleftend = HEcreate( (struct Edge *)NULL, 0);
+ ELrightend = HEcreate( (struct Edge *)NULL, 0);
+ ELleftend -> ELleft = (struct Halfedge *)NULL;
+ ELleftend -> ELright = ELrightend;
+ ELrightend -> ELleft = ELleftend;
+ ELrightend -> ELright = (struct Halfedge *)NULL;
+ ELhash[0] = ELleftend;
+ ELhash[ELhashsize-1] = ELrightend;
+
+ return true;
+}
+
+
+struct Halfedge* VoronoiDiagramGenerator::HEcreate(struct Edge *e,int pm)
+{
+ struct Halfedge *answer;
+ answer = (struct Halfedge *) getfree(&hfl);
+ answer -> ELedge = e;
+ answer -> ELpm = pm;
+ answer -> PQnext = (struct Halfedge *) NULL;
+ answer -> vertex = (struct Site *) NULL;
+ answer -> ELrefcnt = 0;
+ return(answer);
+}
+
+
+void VoronoiDiagramGenerator::ELinsert(struct Halfedge *lb, struct Halfedge *newHe)
+{
+ newHe -> ELleft = lb;
+ newHe -> ELright = lb -> ELright;
+ (lb -> ELright) -> ELleft = newHe;
+ lb -> ELright = newHe;
+}
+
+/* Get entry from hash table, pruning any deleted nodes */
+struct Halfedge * VoronoiDiagramGenerator::ELgethash(int b)
+{
+ struct Halfedge *he;
+
+ if(b<0 || b>=ELhashsize)
+ return((struct Halfedge *) NULL);
+ he = ELhash[b];
+ if (he == (struct Halfedge *) NULL || he->ELedge != (struct Edge *) DELETED )
+ return (he);
+
+ /* Hash table points to deleted half edge. Patch as necessary. */
+ ELhash[b] = (struct Halfedge *) NULL;
+ if ((he -> ELrefcnt -= 1) == 0)
+ makefree((Freenode*)he, &hfl);
+ return ((struct Halfedge *) NULL);
+}
+
+struct Halfedge * VoronoiDiagramGenerator::ELleftbnd(struct Point *p)
+{
+ int i, bucket;
+ struct Halfedge *he;
+
+ /* Use hash table to get close to desired halfedge */
+ bucket = (int)((p->x - xmin)/deltax * ELhashsize); //use the hash function to find the place in the hash map that this HalfEdge should be
+
+ if(bucket<0) bucket =0; //make sure that the bucket position in within the range of the hash array
+ if(bucket>=ELhashsize) bucket = ELhashsize - 1;
+
+ he = ELgethash(bucket);
+ if(he == (struct Halfedge *) NULL) //if the HE isn't found, search backwards and forwards in the hash map for the first non-null entry
+ {
+ for(i=1; 1 ; i += 1)
+ {
+ if ((he=ELgethash(bucket-i)) != (struct Halfedge *) NULL)
+ break;
+ if ((he=ELgethash(bucket+i)) != (struct Halfedge *) NULL)
+ break;
+ };
+ totalsearch += i;
+ };
+ ntry += 1;
+ /* Now search linear list of halfedges for the correct one */
+ if (he==ELleftend || (he != ELrightend && right_of(he,p)))
+ {
+ do
+ {
+ he = he -> ELright;
+ } while (he!=ELrightend && right_of(he,p)); //keep going right on the list until either the end is reached, or you find the 1st edge which the point
+ he = he -> ELleft; //isn't to the right of
+ }
+ else //if the point is to the left of the HalfEdge, then search left for the HE just to the left of the point
+ do
+ {
+ he = he -> ELleft;
+ } while (he!=ELleftend && !right_of(he,p));
+
+ /* Update hash table and reference counts */
+ if(bucket > 0 && bucket <ELhashsize-1)
+ {
+ if(ELhash[bucket] != (struct Halfedge *) NULL)
+ {
+ ELhash[bucket] -> ELrefcnt -= 1;
+ }
+ ELhash[bucket] = he;
+ ELhash[bucket] -> ELrefcnt += 1;
+ };
+ return (he);
+}
+
+
+/* This delete routine can't reclaim node, since pointers from hash
+table may be present. */
+void VoronoiDiagramGenerator::ELdelete(struct Halfedge *he)
+{
+ (he -> ELleft) -> ELright = he -> ELright;
+ (he -> ELright) -> ELleft = he -> ELleft;
+ he -> ELedge = (struct Edge *)DELETED;
+}
+
+
+struct Halfedge * VoronoiDiagramGenerator::ELright(struct Halfedge *he)
+{
+ return (he -> ELright);
+}
+
+struct Halfedge * VoronoiDiagramGenerator::ELleft(struct Halfedge *he)
+{
+ return (he -> ELleft);
+}
+
+
+struct Site * VoronoiDiagramGenerator::leftreg(struct Halfedge *he)
+{
+ if(he -> ELedge == (struct Edge *)NULL)
+ return(bottomsite);
+ return( he -> ELpm == le ?
+ he -> ELedge -> reg[le] : he -> ELedge -> reg[re]);
+}
+
+struct Site * VoronoiDiagramGenerator::rightreg(struct Halfedge *he)
+{
+ if(he -> ELedge == (struct Edge *)NULL) //if this halfedge has no edge, return the bottom site (whatever that is)
+ return(bottomsite);
+
+ //if the ELpm field is zero, return the site 0 that this edge bisects, otherwise return site number 1
+ return( he -> ELpm == le ? he -> ELedge -> reg[re] : he -> ELedge -> reg[le]);
+}
+
+void VoronoiDiagramGenerator::geominit()
+{
+ double sn;
+
+ freeinit(&efl, sizeof(Edge));
+ nvertices = 0;
+ nedges = 0;
+ sn = (double)nsites+4;
+ sqrt_nsites = (int)sqrt(sn);
+ deltay = ymax - ymin;
+ deltax = xmax - xmin;
+}
+
+
+struct Edge * VoronoiDiagramGenerator::bisect(struct Site *s1, struct Site *s2)
+{
+ double dx,dy,adx,ady;
+ struct Edge *newedge;
+
+ newedge = (struct Edge *) getfree(&efl);
+
+ newedge -> reg[0] = s1; //store the sites that this edge is bisecting
+ newedge -> reg[1] = s2;
+ ref(s1);
+ ref(s2);
+ newedge -> ep[0] = (struct Site *) NULL; //to begin with, there are no endpoints on the bisector - it goes to infinity
+ newedge -> ep[1] = (struct Site *) NULL;
+
+ dx = s2->coord.x - s1->coord.x; //get the difference in x dist between the sites
+ dy = s2->coord.y - s1->coord.y;
+ adx = dx>0 ? dx : -dx; //make sure that the difference in positive
+ ady = dy>0 ? dy : -dy;
+ newedge -> c = (double)(s1->coord.x * dx + s1->coord.y * dy + (dx*dx + dy*dy)*0.5);//get the slope of the line
+
+ if (adx>ady)
+ {
+ newedge -> a = 1.0; newedge -> b = dy/dx; newedge -> c /= dx;//set formula of line, with x fixed to 1
+ }
+ else
+ {
+ newedge -> b = 1.0; newedge -> a = dx/dy; newedge -> c /= dy;//set formula of line, with y fixed to 1
+ };
+
+ newedge -> edgenbr = nedges;
+
+ //printf("\nbisect(%d) ((%f,%f) and (%f,%f)",nedges,s1->coord.x,s1->coord.y,s2->coord.x,s2->coord.y);
+
+ nedges += 1;
+ return(newedge);
+}
+
+//create a new site where the HalfEdges el1 and el2 intersect - note that the Point in the argument list is not used, don't know why it's there
+struct Site * VoronoiDiagramGenerator::intersect(struct Halfedge *el1, struct Halfedge *el2, struct Point *p)
+{
+ struct Edge *e1,*e2, *e;
+ struct Halfedge *el;
+ double d, xint, yint;
+ int right_of_site;
+ struct Site *v;
+
+ e1 = el1 -> ELedge;
+ e2 = el2 -> ELedge;
+ if(e1 == (struct Edge*)NULL || e2 == (struct Edge*)NULL)
+ return ((struct Site *) NULL);
+
+ //if the two edges bisect the same parent, return null
+ if (e1->reg[1] == e2->reg[1])
+ return ((struct Site *) NULL);
+
+ d = e1->a * e2->b - e1->b * e2->a;
+ if (-1.0e-10<d && d<1.0e-10)
+ return ((struct Site *) NULL);
+
+ xint = (e1->c*e2->b - e2->c*e1->b)/d;
+ yint = (e2->c*e1->a - e1->c*e2->a)/d;
+
+ if( (e1->reg[1]->coord.y < e2->reg[1]->coord.y) ||
+ (e1->reg[1]->coord.y == e2->reg[1]->coord.y &&
+ e1->reg[1]->coord.x < e2->reg[1]->coord.x) )
+ {
+ el = el1;
+ e = e1;
+ }
+ else
+ {
+ el = el2;
+ e = e2;
+ };
+
+ right_of_site = xint >= e -> reg[1] -> coord.x;
+ if ((right_of_site && el -> ELpm == le) || (!right_of_site && el -> ELpm == re))
+ return ((struct Site *) NULL);
+
+ //create a new site at the point of intersection - this is a new vector event waiting to happen
+ v = (struct Site *) getfree(&sfl);
+ v -> refcnt = 0;
+ v -> coord.x = xint;
+ v -> coord.y = yint;
+ return(v);
+}
+
+/* returns 1 if p is to right of halfedge e */
+int VoronoiDiagramGenerator::right_of(struct Halfedge *el,struct Point *p)
+{
+ struct Edge *e;
+ struct Site *topsite;
+ int right_of_site, above, fast;
+ double dxp, dyp, dxs, t1, t2, t3, yl;
+
+ e = el -> ELedge;
+ topsite = e -> reg[1];
+ right_of_site = p -> x > topsite -> coord.x;
+ if(right_of_site && el -> ELpm == le) return(1);
+ if(!right_of_site && el -> ELpm == re) return (0);
+
+ if (e->a == 1.0)
+ { dyp = p->y - topsite->coord.y;
+ dxp = p->x - topsite->coord.x;
+ fast = 0;
+ if ((!right_of_site & (e->b<0.0)) | (right_of_site & (e->b>=0.0)) )
+ { above = dyp>= e->b*dxp;
+ fast = above;
+ }
+ else
+ { above = p->x + p->y*e->b > e-> c;
+ if(e->b<0.0) above = !above;
+ if (!above) fast = 1;
+ };
+ if (!fast)
+ { dxs = topsite->coord.x - (e->reg[0])->coord.x;
+ above = e->b * (dxp*dxp - dyp*dyp) <
+ dxs*dyp*(1.0+2.0*dxp/dxs + e->b*e->b);
+ if(e->b<0.0) above = !above;
+ };
+ }
+ else /*e->b==1.0 */
+ { yl = e->c - e->a*p->x;
+ t1 = p->y - yl;
+ t2 = p->x - topsite->coord.x;
+ t3 = yl - topsite->coord.y;
+ above = t1*t1 > t2*t2 + t3*t3;
+ };
+ return (el->ELpm==le ? above : !above);
+}
+
+
+void VoronoiDiagramGenerator::endpoint(struct Edge *e,int lr,struct Site * s)
+{
+ e -> ep[lr] = s;
+ ref(s);
+ if(e -> ep[re-lr]== (struct Site *) NULL)
+ return;
+
+ clip_line(e);
+
+ deref(e->reg[le]);
+ deref(e->reg[re]);
+ makefree((Freenode*)e, &efl);
+}
+
+
+double VoronoiDiagramGenerator::dist(struct Site *s,struct Site *t)
+{
+ double dx,dy;
+ dx = s->coord.x - t->coord.x;
+ dy = s->coord.y - t->coord.y;
+ return (double)(sqrt(dx*dx + dy*dy));
+}
+
+
+void VoronoiDiagramGenerator::makevertex(struct Site *v)
+{
+ v -> sitenbr = nvertices;
+ nvertices += 1;
+ out_vertex(v);
+}
+
+
+void VoronoiDiagramGenerator::deref(struct Site *v)
+{
+ v -> refcnt -= 1;
+ if (v -> refcnt == 0 )
+ makefree((Freenode*)v, &sfl);
+}
+
+void VoronoiDiagramGenerator::ref(struct Site *v)
+{
+ v -> refcnt += 1;
+}
+
+//push the HalfEdge into the ordered linked list of vertices
+void VoronoiDiagramGenerator::PQinsert(struct Halfedge *he,struct Site * v, double offset)
+{
+ struct Halfedge *last, *next;
+
+ he -> vertex = v;
+ ref(v);
+ he -> ystar = (double)(v -> coord.y + offset);
+ last = &PQhash[PQbucket(he)];
+ while ((next = last -> PQnext) != (struct Halfedge *) NULL &&
+ (he -> ystar > next -> ystar ||
+ (he -> ystar == next -> ystar && v -> coord.x > next->vertex->coord.x)))
+ {
+ last = next;
+ };
+ he -> PQnext = last -> PQnext;
+ last -> PQnext = he;
+ PQcount += 1;
+}
+
+//remove the HalfEdge from the list of vertices
+void VoronoiDiagramGenerator::PQdelete(struct Halfedge *he)
+{
+ struct Halfedge *last;
+
+ if(he -> vertex != (struct Site *) NULL)
+ {
+ last = &PQhash[PQbucket(he)];
+ while (last -> PQnext != he)
+ last = last -> PQnext;
+
+ last -> PQnext = he -> PQnext;
+ PQcount -= 1;
+ deref(he -> vertex);
+ he -> vertex = (struct Site *) NULL;
+ };
+}
+
+int VoronoiDiagramGenerator::PQbucket(struct Halfedge *he)
+{
+ int bucket;
+
+ bucket = (int)((he->ystar - ymin)/deltay * PQhashsize);
+ if (bucket<0) bucket = 0;
+ if (bucket>=PQhashsize) bucket = PQhashsize-1 ;
+ if (bucket < PQmin) PQmin = bucket;
+ return(bucket);
+}
+
+
+
+int VoronoiDiagramGenerator::PQempty()
+{
+ return(PQcount==0);
+}
+
+
+struct Point VoronoiDiagramGenerator::PQ_min()
+{
+ struct Point answer;
+
+ while(PQhash[PQmin].PQnext == (struct Halfedge *)NULL) {PQmin += 1;};
+ answer.x = PQhash[PQmin].PQnext -> vertex -> coord.x;
+ answer.y = PQhash[PQmin].PQnext -> ystar;
+ return (answer);
+}
+
+struct Halfedge * VoronoiDiagramGenerator::PQextractmin()
+{
+ struct Halfedge *curr;
+
+ curr = PQhash[PQmin].PQnext;
+ PQhash[PQmin].PQnext = curr -> PQnext;
+ PQcount -= 1;
+ return(curr);
+}
+
+
+bool VoronoiDiagramGenerator::PQinitialize()
+{
+ int i;
+
+ PQcount = 0;
+ PQmin = 0;
+ PQhashsize = 4 * sqrt_nsites;
+ PQhash = (struct Halfedge *) myalloc(PQhashsize * sizeof *PQhash);
+
+ if(PQhash == 0)
+ return false;
+
+ for(i=0; i<PQhashsize; i+=1) PQhash[i].PQnext = (struct Halfedge *)NULL;
+
+ return true;
+}
+
+
+void VoronoiDiagramGenerator::freeinit(struct Freelist *fl,int size)
+{
+ fl -> head = (struct Freenode *) NULL;
+ fl -> nodesize = size;
+}
+
+char * VoronoiDiagramGenerator::getfree(struct Freelist *fl)
+{
+ int i;
+ struct Freenode *t;
+
+ if(fl->head == (struct Freenode *) NULL)
+ {
+ t = (struct Freenode *) myalloc(sqrt_nsites * fl->nodesize);
+
+ if(t == 0)
+ return 0;
+
+ currentMemoryBlock->next = new FreeNodeArrayList;
+ currentMemoryBlock = currentMemoryBlock->next;
+ currentMemoryBlock->memory = t;
+ currentMemoryBlock->next = 0;
+
+ for(i=0; i<sqrt_nsites; i+=1)
+ makefree((struct Freenode *)((char *)t+i*fl->nodesize), fl);
+ };
+ t = fl -> head;
+ fl -> head = (fl -> head) -> nextfree;
+ return((char *)t);
+}
+
+
+
+void VoronoiDiagramGenerator::makefree(struct Freenode *curr,struct Freelist *fl)
+{
+ curr -> nextfree = fl -> head;
+ fl -> head = curr;
+}
+
+void VoronoiDiagramGenerator::cleanup()
+{
+ if(sites != 0)
+ {
+ free(sites);
+ sites = 0;
+ }
+
+ FreeNodeArrayList* current=0, *prev = 0;
+
+ current = prev = allMemoryList;
+
+ while(current->next != 0)
+ {
+ prev = current;
+ current = current->next;
+ free(prev->memory);
+ delete prev;
+ prev = 0;
+ }
+
+ if(current != 0 && current->memory != 0)
+ {
+ free(current->memory);
+ delete current;
+ }
+
+ allMemoryList = new FreeNodeArrayList;
+ allMemoryList->next = 0;
+ allMemoryList->memory = 0;
+ currentMemoryBlock = allMemoryList;
+}
+
+void VoronoiDiagramGenerator::cleanupEdges()
+{
+ GraphEdge* geCurrent = 0, *gePrev = 0;
+ geCurrent = gePrev = allEdges;
+
+ while(geCurrent != 0 && geCurrent->next != 0)
+ {
+ gePrev = geCurrent;
+ geCurrent = geCurrent->next;
+ delete gePrev;
+ }
+
+ allEdges = 0;
+
+}
+
+void VoronoiDiagramGenerator::cleanupEdgeList()
+{
+ EdgeList* elCurrent = 0, *elPrev = 0;
+ elCurrent = elPrev = allEdgeList;
+
+ while (elCurrent != 0 && elCurrent->next != 0)
+ {
+ elPrev = elCurrent;
+ elCurrent = elCurrent->next;
+ delete elPrev;
+ }
+
+ allEdgeList = 0;
+}
+
+void VoronoiDiagramGenerator::pushGraphEdge(double x1, double y1, double x2, double y2)
+{
+ GraphEdge* newEdge = new GraphEdge;
+ newEdge->next = allEdges;
+ allEdges = newEdge;
+ newEdge->x1 = x1;
+ newEdge->y1 = y1;
+ newEdge->x2 = x2;
+ newEdge->y2 = y2;
+}
+
+void VoronoiDiagramGenerator::pushEdgeList(Edge *e)
+{
+ EdgeList* newEdge = new EdgeList;
+ newEdge->next = allEdgeList;
+ allEdgeList = newEdge;
+ newEdge->a = e->a;
+ newEdge->b = e->b;
+ newEdge->c = e->c;
+ if (e->ep[0]) {
+ newEdge->ep0nbr = e->ep[0]->sitenbr;
+ newEdge->ep0x = e->ep[0]->coord.x;
+ newEdge->ep0y = e->ep[0]->coord.y;
+ } else {
+ newEdge->ep0nbr = -1;
+ }
+ if (e->ep[1]) {
+ newEdge->ep1nbr = e->ep[1]->sitenbr;
+ newEdge->ep1x = e->ep[1]->coord.x;
+ newEdge->ep1y = e->ep[1]->coord.y;
+ } else {
+ newEdge->ep1nbr = -1;
+ }
+ newEdge->reg0nbr = e->reg[0]->sitenbr;
+ newEdge->reg1nbr = e->reg[1]->sitenbr;
+ newEdge->edgenbr = e->edgenbr;
+}
+
+char * VoronoiDiagramGenerator::myalloc(unsigned n)
+{
+ char *t=0;
+ t=(char*)malloc(n);
+ total_alloc += n;
+ return(t);
+}
+
+
+/* for those who don't have Cherry's plot */
+/* #include <plot.h> */
+void VoronoiDiagramGenerator::openpl(){}
+void VoronoiDiagramGenerator::line(double x1, double y1, double x2, double y2)
+{
+ pushGraphEdge(x1,y1,x2,y2);
+
+}
+void VoronoiDiagramGenerator::circle(double x, double y, double radius){}
+void VoronoiDiagramGenerator::range(double minX, double minY, double maxX, double maxY){}
+
+
+
+void VoronoiDiagramGenerator::out_bisector(struct Edge *e)
+{
+
+
+}
+
+
+void VoronoiDiagramGenerator::out_ep(struct Edge *e)
+{
+
+
+}
+
+void VoronoiDiagramGenerator::out_vertex(struct Site *v)
+{
+
+}
+
+
+void VoronoiDiagramGenerator::out_site(struct Site *s)
+{
+ if(!triangulate & plot & !debug)
+ circle (s->coord.x, s->coord.y, cradius);
+
+}
+
+
+void VoronoiDiagramGenerator::out_triple(struct Site *s1, struct Site *s2,struct Site * s3)
+{
+
+}
+
+
+
+void VoronoiDiagramGenerator::plotinit()
+{
+// double dx,dy,d;
+//
+// dy = ymax - ymin;
+// dx = xmax - xmin;
+// d = (double)(( dx > dy ? dx : dy) * 1.1);
+// pxmin = (double)(xmin - (d-dx)/2.0);
+// pxmax = (double)(xmax + (d-dx)/2.0);
+// pymin = (double)(ymin - (d-dy)/2.0);
+// pymax = (double)(ymax + (d-dy)/2.0);
+// cradius = (double)((pxmax - pxmin)/350.0);
+// openpl();
+// range(pxmin, pymin, pxmax, pymax);
+}
+
+
+void VoronoiDiagramGenerator::clip_line(struct Edge *e)
+{
+// struct Site *s1, *s2;
+// double x1=0,x2=0,y1=0,y2=0;
+
+ pushEdgeList(e);
+
+// x1 = e->reg[0]->coord.x;
+// x2 = e->reg[1]->coord.x;
+// y1 = e->reg[0]->coord.y;
+// y2 = e->reg[1]->coord.y;
+//
+// //if the distance between the two points this line was created from is less than
+// //the square root of 2, then ignore it
+// if(sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) < minDistanceBetweenSites)
+// {
+// return;
+// }
+// pxmin = borderMinX;
+// pxmax = borderMaxX;
+// pymin = borderMinY;
+// pymax = borderMaxY;
+//
+// if(e -> a == 1.0 && e ->b >= 0.0)
+// {
+// s1 = e -> ep[1];
+// s2 = e -> ep[0];
+// }
+// else
+// {
+// s1 = e -> ep[0];
+// s2 = e -> ep[1];
+// };
+//
+// if(e -> a == 1.0)
+// {
+// y1 = pymin;
+// if (s1!=(struct Site *)NULL && s1->coord.y > pymin)
+// {
+// y1 = s1->coord.y;
+// }
+// if(y1>pymax)
+// {
+// // printf("\nClipped (1) y1 = %f to %f",y1,pymax);
+// y1 = pymax;
+// //return;
+// }
+// x1 = e -> c - e -> b * y1;
+// y2 = pymax;
+// if (s2!=(struct Site *)NULL && s2->coord.y < pymax)
+// y2 = s2->coord.y;
+//
+// if(y2<pymin)
+// {
+// //printf("\nClipped (2) y2 = %f to %f",y2,pymin);
+// y2 = pymin;
+// //return;
+// }
+// x2 = (e->c) - (e->b) * y2;
+// if (((x1> pxmax) & (x2>pxmax)) | ((x1<pxmin)&(x2<pxmin)))
+// {
+// //printf("\nClipLine jumping out(3), x1 = %f, pxmin = %f, pxmax = %f",x1,pxmin,pxmax);
+// return;
+// }
+// if(x1> pxmax)
+// { x1 = pxmax; y1 = (e -> c - x1)/e -> b;};
+// if(x1<pxmin)
+// { x1 = pxmin; y1 = (e -> c - x1)/e -> b;};
+// if(x2>pxmax)
+// { x2 = pxmax; y2 = (e -> c - x2)/e -> b;};
+// if(x2<pxmin)
+// { x2 = pxmin; y2 = (e -> c - x2)/e -> b;};
+// }
+// else
+// {
+// x1 = pxmin;
+// if (s1!=(struct Site *)NULL && s1->coord.x > pxmin)
+// x1 = s1->coord.x;
+// if(x1>pxmax)
+// {
+// //printf("\nClipped (3) x1 = %f to %f",x1,pxmin);
+// //return;
+// x1 = pxmax;
+// }
+// y1 = e -> c - e -> a * x1;
+// x2 = pxmax;
+// if (s2!=(struct Site *)NULL && s2->coord.x < pxmax)
+// x2 = s2->coord.x;
+// if(x2<pxmin)
+// {
+// //printf("\nClipped (4) x2 = %f to %f",x2,pxmin);
+// //return;
+// x2 = pxmin;
+// }
+// y2 = e -> c - e -> a * x2;
+// if (((y1> pymax) & (y2>pymax)) | ((y1<pymin)&(y2<pymin)))
+// {
+// //printf("\nClipLine jumping out(6), y1 = %f, pymin = %f, pymax = %f",y2,pymin,pymax);
+// return;
+// }
+// if(y1> pymax)
+// { y1 = pymax; x1 = (e -> c - y1)/e -> a;};
+// if(y1<pymin)
+// { y1 = pymin; x1 = (e -> c - y1)/e -> a;};
+// if(y2>pymax)
+// { y2 = pymax; x2 = (e -> c - y2)/e -> a;};
+// if(y2<pymin)
+// { y2 = pymin; x2 = (e -> c - y2)/e -> a;};
+// };
+//
+// //printf("\nPushing line (%f,%f,%f,%f)",x1,y1,x2,y2);
+// line(x1,y1,x2,y2);
+}
+
+
+/* implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
+deltax, deltay (can all be estimates).
+Performance suffers if they are wrong; better to make nsites,
+deltax, and deltay too big than too small. (?) */
+
+bool VoronoiDiagramGenerator::voronoi(int triangulate)
+{
+ struct Site *newsite, *bot, *top, *temp, *p;
+ struct Site *v;
+ struct Point newintstar;
+ int pm;
+ struct Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
+ struct Edge *e;
+
+ PQinitialize();
+ bottomsite = nextone();
+ out_site(bottomsite);
+ bool retval = ELinitialize();
+
+ if(!retval)
+ return false;
+
+ newsite = nextone();
...
[truncated message content] |
|
From: <ry...@us...> - 2008-07-23 03:08:44
|
Revision: 5819
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5819&view=rev
Author: ryanmay
Date: 2008-07-23 03:08:41 +0000 (Wed, 23 Jul 2008)
Log Message:
-----------
Added Barbs polygon collection (similar to Quiver) for plotting wind barbs. Added corresponding helpers to Axes and pyplot as well. (examples/pylab_examples/barb_demo.py shows it off.)
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/boilerplate.py
trunk/matplotlib/examples/tests/backend_driver.py
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/lib/matplotlib/pyplot.py
trunk/matplotlib/lib/matplotlib/quiver.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/barb_demo.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-23 02:44:49 UTC (rev 5818)
+++ trunk/matplotlib/CHANGELOG 2008-07-23 03:08:41 UTC (rev 5819)
@@ -1,3 +1,7 @@
+2008-07-22 Added Barbs polygon collection (similar to Quiver) for plotting
+ wind barbs. Added corresponding helpers to Axes and pyplot as
+ well. (examples/pylab_examples/barb_demo.py shows it off.) - RMM
+
2008-07-21 Added scikits.delaunay as matplotlib.delaunay. Added griddata
function in matplotlib.mlab, with example (griddata_demo.py) in
pylab_examples. griddata function will use mpl_toolkits._natgrid
Modified: trunk/matplotlib/boilerplate.py
===================================================================
--- trunk/matplotlib/boilerplate.py 2008-07-23 02:44:49 UTC (rev 5818)
+++ trunk/matplotlib/boilerplate.py 2008-07-23 03:08:41 UTC (rev 5819)
@@ -86,6 +86,7 @@
'step',
'vlines',
'xcorr',
+ 'barbs',
)
_misccommands = (
Added: trunk/matplotlib/examples/pylab_examples/barb_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/barb_demo.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/barb_demo.py 2008-07-23 03:08:41 UTC (rev 5819)
@@ -0,0 +1,33 @@
+'''
+Demonstration of wind barb plots
+'''
+import matplotlib.pyplot as plt
+import numpy as np
+
+x = np.linspace(-5, 5, 5)
+X,Y = np.meshgrid(x, x)
+U, V = 12*X, 12*Y
+
+data = [(-1.5,.5,-6,-6),
+ (1,-1,-46,46),
+ (-3,-1,11,-11),
+ (1,1.5,80,80)]
+
+#Default parameters for arbitrary set of vectors
+ax = plt.subplot(2,2,1)
+ax.barbs(*zip(*data))
+
+#Default parameters, uniform grid
+ax = plt.subplot(2,2,2)
+ax.barbs(X, Y, U, V)
+
+#Change parameters for arbitrary set of vectors
+ax = plt.subplot(2,2,3)
+ax.barbs(flagcolor='r', barbcolor=['b','g'], barb_increments=dict(half=10,
+ full=20, flag=100), *zip(*data))
+
+#Showing colormapping with uniform grid.
+ax = plt.subplot(2,2,4)
+ax.barbs(X, Y, U, V, np.sqrt(U*U + V*V), fill_empty=True, rounding=False)
+
+plt.show()
Modified: trunk/matplotlib/examples/tests/backend_driver.py
===================================================================
--- trunk/matplotlib/examples/tests/backend_driver.py 2008-07-23 02:44:49 UTC (rev 5818)
+++ trunk/matplotlib/examples/tests/backend_driver.py 2008-07-23 03:08:41 UTC (rev 5819)
@@ -33,6 +33,7 @@
'axhspan_demo.py',
'bar_stacked.py',
'barchart_demo.py',
+ 'barb_demo.py',
'boxplot_demo.py',
'broken_barh.py',
'barh_demo.py',
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2008-07-23 02:44:49 UTC (rev 5818)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2008-07-23 03:08:41 UTC (rev 5819)
@@ -5224,6 +5224,15 @@
return q
quiver.__doc__ = mquiver.Quiver.quiver_doc
+ def barbs(self, *args, **kw):
+ if not self._hold: self.cla()
+ b = mquiver.Barbs(self, *args, **kw)
+ self.add_collection(b)
+ self.update_datalim(b.get_offsets())
+ self.autoscale_view()
+ return b
+ barbs.__doc__ = mquiver.Barbs.barbs_doc
+
def fill(self, *args, **kwargs):
"""
call signature::
Modified: trunk/matplotlib/lib/matplotlib/pyplot.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/pyplot.py 2008-07-23 02:44:49 UTC (rev 5818)
+++ trunk/matplotlib/lib/matplotlib/pyplot.py 2008-07-23 03:08:41 UTC (rev 5819)
@@ -2342,6 +2342,28 @@
# This function was autogenerated by boilerplate.py. Do not edit as
# changes will be lost
+def barbs(*args, **kwargs):
+ # allow callers to override the hold state by passing hold=True|False
+ b = ishold()
+ h = kwargs.pop('hold', None)
+ if h is not None:
+ hold(h)
+ try:
+ ret = gca().barbs(*args, **kwargs)
+ draw_if_interactive()
+ except:
+ hold(b)
+ raise
+
+ hold(b)
+ return ret
+if Axes.barbs.__doc__ is not None:
+ barbs.__doc__ = dedent(Axes.barbs.__doc__) + """
+
+Additional kwargs: hold = [True|False] overrides default hold state"""
+
+# This function was autogenerated by boilerplate.py. Do not edit as
+# changes will be lost
def cla(*args, **kwargs):
ret = gca().cla(*args, **kwargs)
Modified: trunk/matplotlib/lib/matplotlib/quiver.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-23 02:44:49 UTC (rev 5818)
+++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-23 03:08:41 UTC (rev 5819)
@@ -1,9 +1,14 @@
"""
-Support for plotting fields of arrows.
+Support for plotting vector fields.
-Presently this contains a single class, Quiver, but it
-might make sense to consolidate other arrow plotting here.
+Presently this contains Quiver and Barb. Quiver plots an arrow in the
+direction of the vector, with the size of the arrow related to the
+magnitude of the vector.
+Barbs are like quiver in that they point along a vector, but
+the magnitude of the vector is given schematically by the presence of barbs
+or flags on the barb.
+
This will also become a home for things such as standard
deviation ellipses, which can and will be derived very easily from
the Quiver code.
@@ -17,6 +22,8 @@
import matplotlib.text as mtext
import matplotlib.artist as martist
import matplotlib.font_manager as font_manager
+from matplotlib.cbook import delete_masked_points
+from matplotlib.patches import CirclePolygon
import math
@@ -498,3 +505,388 @@
return X, Y
quiver_doc = _quiver_doc
+
+_barbs_doc = """
+Plot a 2-D field of barbs.
+
+call signatures::
+
+ barb(U, V, **kw)
+ barb(U, V, C, **kw)
+ barb(X, Y, U, V, **kw)
+ barb(X, Y, U, V, C, **kw)
+
+Arguments:
+
+ *X*, *Y*:
+ The x and y coordinates of the barb locations
+ (default is head of barb; see *pivot* kwarg)
+
+ *U*, *V*:
+ give the *x* and *y* components of the barb shaft
+
+ *C*:
+ an optional array used to map colors to the barbs
+
+All arguments may be 1-D or 2-D arrays or sequences. If *X* and *Y*
+are absent, they will be generated as a uniform grid. If *U* and *V*
+are 2-D arrays but *X* and *Y* are 1-D, and if len(*X*) and len(*Y*)
+match the column and row dimensions of *U*, then *X* and *Y* will be
+expanded with :func:`numpy.meshgrid`.
+
+*U*, *V*, *C* may be masked arrays, but masked *X*, *Y* are not
+supported at present.
+
+Keyword arguments:
+
+ *length*:
+ Length of the barb in points; the other parts of the barb
+ are scaled against this.
+ Default is 9
+
+ *pivot*: [ 'tip' | 'middle' ]
+ The part of the arrow that is at the grid point; the arrow
+ rotates about this point, hence the name *pivot*.
+ Default is 'tip'
+
+ *barbcolor*: [ color | color sequence ]
+ Specifies the color all parts of the barb except any flags.
+ This parameter is analagous to the *edgecolor* parameter
+ for polygons, which can be used instead. However this parameter
+ will override facecolor.
+
+ *flagcolor*: [ color | color sequence ]
+ Specifies the color of any flags on the barb.
+ This parameter is analagous to the *facecolor* parameter
+ for polygons, which can be used instead. However this parameter
+ will override facecolor. If this is not set (and *C* has not either)
+ then *flagcolor* will be set to match *barbcolor* so that the barb
+ has a uniform color. If *C* has been set, *flagcolor* has no effect.
+
+ *sizes*:
+ A dictionary of coefficients specifying the ratio of a given feature
+ to the length of the barb. Only those values one wishes to override
+ need to be included. These features include:
+ 'spacing' - space between features (flags, full/half barbs)
+ 'height' - height (distance from shaft to top) of a flag or full barb
+ 'width' - width of a flag, twice the width of a full barb
+ 'emptybarb' - radius of the circle used for low magnitudes
+
+ *fill_empty*:
+ A flag on whether the empty barbs (circles) that are drawn should be filled
+ with the flag color. If they are not filled, they will be drawn such that
+ no color is applied to the center.
+ Default is False
+
+ *rounding*:
+ A flag to indicate whether the vector magnitude should be rounded when
+ allocating barb components. If True, the magnitude is rounded to the
+ nearest multiple of the half-barb increment. If False, the magnitude
+ is simply truncated to the next lowest multiple.
+ Default is True
+
+ *barb_increments*:
+ A dictionary of increments specifying values to associate with different
+ parts of the barb. Only those values one wishes to override need to be
+ included.
+ 'half' - half barbs (Default is 5)
+ 'full' - full barbs (Default is 10)
+ 'flag' - flags (default is 50)
+
+Barbs are traditionally used in meteorology as a way to plot the speed
+and direction of wind observations, but can technically be used to plot
+any two dimensional vector quantity. As opposed to arrows, which give
+vector magnitude by the length of the arrow, the barbs give more quantitative
+information about the vector magnitude by putting slanted lines or a triangle
+for various increments in magnitude, as show schematically below:
+
+ /\ \
+ / \ \
+ / \ \ \
+/ \ \ \
+------------------------------
+
+The largest increment is given by a triangle (or "flag"). After those come full
+lines (barbs). The smallest increment is a half line. There is only, of
+course, ever at most 1 half line. If the magnitude is small and only needs a
+single half-line and no full lines or triangles, the half-line is offset from
+the end of the barb so that it can be easily distinguished from barbs with a
+single full line. The magnitude for the barb shown above would nominally be
+65, using the standard increments of 50, 10, and 5.
+
+linewidths and edgecolors can be used to customize the barb.
+Additional :class:`~matplotlib.collections.PolyCollection`
+keyword arguments:
+
+%(PolyCollection)s
+""" % martist.kwdocd
+
+class Barbs(collections.PolyCollection):
+ '''
+ Specialized PolyCollection for barbs.
+
+ The only API method is set_UVC(), which can be used
+ to change the size, orientation, and color of the
+ arrows. Locations are changed using the set_offsets() collection
+ method.Possibly this method will be useful in animations.
+
+ There is one internal function _find_tails() which finds exactly
+ what should be put on the barb given the vector magnitude. From there
+ _make_barbs() is used to find the vertices of the polygon to represent the
+ barb based on this information.
+ '''
+ #This may be an abuse of polygons here to render what is essentially maybe
+ #1 triangle and a series of lines. It works fine as far as I can tell
+ #however.
+ def __init__(self, ax, *args, **kw):
+ self._pivot = kw.pop('pivot', 'tip')
+ self._length = kw.pop('length', 7)
+ barbcolor = kw.pop('barbcolor', None)
+ flagcolor = kw.pop('flagcolor', None)
+ self.sizes = kw.pop('sizes', dict())
+ self.fill_empty = kw.pop('fill_empty', False)
+ self.barb_increments = kw.pop('barb_increments', dict())
+ self.rounding = kw.pop('rounding', True)
+
+ #Flagcolor and and barbcolor provide convenience parameters for setting
+ #the facecolor and edgecolor, respectively, of the barb polygon. We
+ #also work here to make the flag the same color as the rest of the barb
+ #by default
+ if None in (barbcolor, flagcolor):
+ kw['edgecolors'] = 'face'
+ if flagcolor:
+ kw['facecolors'] = flagcolor
+ elif barbcolor:
+ kw['facecolors'] = barbcolor
+ else:
+ #Set to facecolor passed in or default to black
+ kw.setdefault('facecolors', 'k')
+ else:
+ kw['edgecolors'] = barbcolor
+ kw['facecolors'] = flagcolor
+
+ #Parse out the data arrays from the various configurations supported
+ x, y, u, v, c = self._parse_args(*args)
+ self.x = x
+ self.y = y
+ xy = np.hstack((x[:,np.newaxis], y[:,np.newaxis]))
+
+ #Make a collection
+ barb_size = self._length**2 / 4 #Empirically determined
+ collections.PolyCollection.__init__(self, [], (barb_size,), offsets=xy,
+ transOffset=ax.transData, **kw)
+ self.set_transform(transforms.IdentityTransform())
+
+ self.set_UVC(u, v, c)
+
+ __init__.__doc__ = """
+ The constructor takes one required argument, an Axes
+ instance, followed by the args and kwargs described
+ by the following pylab interface documentation:
+ %s""" % _barbs_doc
+
+ def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50):
+ '''Find how many of each of the tail pieces is necessary. Flag
+ specifies the increment for a flag, barb for a full barb, and half for
+ half a barb. Mag should be the magnitude of a vector (ie. >= 0).
+
+ This returns a tuple of:
+ (number of flags, number of barbs, half_flag, empty_flag)
+ half_flag is a boolean whether half of a barb is needed, since there
+ should only ever be one half on a given barb. Empty flag is an array
+ of flags to easily tell if a barb is empty (too low to plot any
+ barbs/flags.'''
+
+ #If rounding, round to the nearest multiple of half, the smallest
+ #increment
+ if rounding:
+ mag = half * (mag / half + 0.5).astype(np.int)
+
+ num_flags = np.floor(mag / flag).astype(np.int)
+ mag = np.mod(mag, flag)
+
+ num_barb = np.floor(mag / full).astype(np.int)
+ mag = np.mod(mag, full)
+
+ half_flag = mag >= half
+ empty_flag = ~(half_flag | (num_flags > 0) | (num_barb > 0))
+
+ return num_flags, num_barb, half_flag, empty_flag
+
+ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length,
+ pivot, sizes, fill_empty):
+ '''This function actually creates the wind barbs. u and v are
+ components of the vector in the x and y directions, respectively.
+ nflags, nbarbs, and half_barb, empty_flag are, respectively, the number
+ of flags, number of barbs, flag for half a barb, and flag for empty
+ barb, ostensibly obtained from _find_tails. length is the length of
+ the barb staff in points. pivot specifies the point on the barb around
+ which the entire barb should be rotated. Right now valid options are
+ 'head' and 'middle'. sizes is a dictionary of coefficients specifying
+ the ratio of a given feature to the length of the barb. These features
+ include:
+
+ spacing - space between features (flags, full/half barbs)
+ height - height (distance from shaft of top) of a flag or full barb
+ width - width of a flag, twice the width of a full barb
+ emptybarb - radius of the circle used for low magnitudes
+
+ This function returns list of arrays of vertices, defining a polygon for
+ each of the wind barbs. These polygons have been rotated to properly
+ align with the vector direction.'''
+
+ #These control the spacing and size of barb elements relative to the
+ #length of the shaft
+ spacing = length * sizes.get('spacing', 0.125)
+ full_height = length * sizes.get('height', 0.4)
+ full_width = length * sizes.get('width', 0.25)
+ empty_rad = length * sizes.get('emptybarb', 0.15)
+
+ #Controls y point where to pivot the barb.
+ pivot_points = dict(tip=0.0, middle=-length/2.)
+
+ endx = 0.0
+ endy = pivot_points[pivot.lower()]
+
+ #Get the appropriate angle for the vector components. The offset is due
+ #to the way the barb is initially drawn, going down the y-axis. This
+ #makes sense in a meteorological mode of thinking since there 0 degrees
+ #corresponds to north (the y-axis traditionally)
+ angles = -(ma.arctan2(v, u) + np.pi/2)
+
+ #Used for low magnitude. We just get the vertices, so if we make it
+ #out here, it can be reused. The center set here should put the
+ #center of the circle at the location(offset), rather than at the
+ #same point as the barb pivot; this seems more sensible.
+ circ = CirclePolygon((0,0), radius=empty_rad).get_verts()
+ if fill_empty:
+ empty_barb = circ
+ else:
+ #If we don't want the empty one filled, we make a degenerate polygon
+ #that wraps back over itself
+ empty_barb = np.concatenate((circ, circ[::-1]))
+
+ barb_list = []
+ for index, angle in np.ndenumerate(angles):
+ #If the vector magnitude is too weak to draw anything, plot an
+ #empty circle instead
+ if empty_flag[index]:
+ #We can skip the transform since the circle has no preferred
+ #orientation
+ barb_list.append(empty_barb)
+ continue
+
+ poly_verts = [(endx, endy)]
+ offset = length
+
+ #Add vertices for each flag
+ for i in range(nflags[index]):
+ #The spacing that works for the barbs is a little to much for
+ #the flags, but this only occurs when we have more than 1 flag.
+ if offset != length: offset += spacing / 2.
+ poly_verts.extend([[endx, endy + offset],
+ [endx + full_height, endy - full_width/2 + offset],
+ [endx, endy - full_width + offset]])
+
+ offset -= full_width + spacing
+
+ #Add vertices for each barb. These really are lines, but works
+ #great adding 3 vertices that basically pull the polygon out and
+ #back down the line
+ for i in range(nbarbs[index]):
+ poly_verts.extend([(endx, endy + offset),
+ (endx + full_height, endy + offset + full_width/2),
+ (endx, endy + offset)])
+
+ offset -= spacing
+
+ #Add the vertices for half a barb, if needed
+ if half_barb[index]:
+ #If the half barb is the first on the staff, traditionally it is
+ #offset from the end to make it easy to distinguish from a barb
+ #with a full one
+ if offset == length:
+ poly_verts.append((endx, endy + offset))
+ offset -= 1.5 * spacing
+ poly_verts.extend([(endx, endy + offset),
+ (endx + full_height/2, endy + offset + full_width/4),
+ (endx, endy + offset)])
+
+ #Rotate the barb according the angle. Making the barb first and then
+ #rotating it made the math for drawing the barb really easy. Also,
+ #the transform framework makes doing the rotation simple.
+ poly_verts = transforms.Affine2D().rotate(-angle).transform(
+ poly_verts)
+ barb_list.append(poly_verts)
+
+ return barb_list
+
+ #Taken shamelessly from Quiver
+ def _parse_args(self, *args):
+ X, Y, U, V, C = [None]*5
+ args = list(args)
+ if len(args) == 3 or len(args) == 5:
+ C = ma.asarray(args.pop(-1)).ravel()
+ V = ma.asarray(args.pop(-1))
+ U = ma.asarray(args.pop(-1))
+ nn = np.shape(U)
+ nc = nn[0]
+ nr = 1
+ if len(nn) > 1:
+ nr = nn[1]
+ if len(args) == 2: # remaining after removing U,V,C
+ X, Y = [np.array(a).ravel() for a in args]
+ if len(X) == nc and len(Y) == nr:
+ X, Y = [a.ravel() for a in np.meshgrid(X, Y)]
+ else:
+ indexgrid = np.meshgrid(np.arange(nc), np.arange(nr))
+ X, Y = [np.ravel(a) for a in indexgrid]
+ return X, Y, U, V, C
+
+ def set_UVC(self, U, V, C=None):
+ self.u = ma.asarray(U).ravel()
+ self.v = ma.asarray(V).ravel()
+ if C is not None:
+ c = ma.asarray(C).ravel()
+ x,y,u,v,c = delete_masked_points(self.x.ravel(), self.y.ravel(),
+ self.u, self.v, c)
+ else:
+ x,y,u,v = delete_masked_points(self.x.ravel(), self.y.ravel(),
+ self.u, self.v)
+
+ magnitude = np.sqrt(u*u + v*v)
+ flags, barbs, halves, empty = self._find_tails(magnitude,
+ self.rounding, **self.barb_increments)
+
+ #Get the vertices for each of the barbs
+
+ plot_barbs = self._make_barbs(u, v, flags, barbs, halves, empty,
+ self._length, self._pivot, self.sizes, self.fill_empty)
+ self.set_verts(plot_barbs)
+
+ #Set the color array
+ if C is not None:
+ self.set_array(c)
+
+ #Update the offsets in case the masked data changed
+ xy = np.hstack((x[:,np.newaxis], y[:,np.newaxis]))
+ self._offsets = xy
+
+ def set_offsets(self, xy):
+ '''
+ Set the offsets for the barb polygons. This saves the offets passed in
+ and actually sets version masked as appropriate for the existing U/V
+ data. *offsets* should be a sequence.
+
+ ACCEPTS: sequence of pairs of floats
+ '''
+ self.x = xy[:,0]
+ self.y = xy[:,1]
+ x,y,u,v = delete_masked_points(self.x.ravel(), self.y.ravel(), self.u,
+ self.v)
+ xy = np.hstack((x[:,np.newaxis], y[:,np.newaxis]))
+ collections.PolyCollection.set_offsets(self, xy)
+ set_offsets.__doc__ = collections.PolyCollection.set_offsets.__doc__
+
+ barbs_doc = _barbs_doc
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <dmk...@us...> - 2008-07-24 08:50:47
|
Revision: 5830
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5830&view=rev
Author: dmkaplan
Date: 2008-07-24 08:50:43 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
Committing rewrite of clabel inlining and label rotation code. Also, renaming
ContourLabeler attributes to something like .labelAttribute. A few of the old
attribute names have been maintained (in addition to new versions) for
backward compatibility, but these should be remove in +1 releases.
Added appropriate comments to CHANGELOG and API_CHANGES.
Modified Paths:
--------------
trunk/matplotlib/API_CHANGES
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/blocking_input.py
trunk/matplotlib/lib/matplotlib/contour.py
Modified: trunk/matplotlib/API_CHANGES
===================================================================
--- trunk/matplotlib/API_CHANGES 2008-07-24 08:06:45 UTC (rev 5829)
+++ trunk/matplotlib/API_CHANGES 2008-07-24 08:50:43 UTC (rev 5830)
@@ -8,6 +8,12 @@
Axes.patch, Axes.axesFrame renamed Axes.frame, Axes.get_frame, which
returns Axes.patch, is deprecated. Examples and users guide updated
+* Changes in the ContourLabeler attributes (clabel function) so that they
+ all have a form like .labelAttribute. The three attributes that are most
+ likely to be used by end users, .cl, .cl_xy and .cl_cvalues have been
+ maintained for the moment (in addition to their renamed versions), but they
+ are depricated and will eventually be removed.
+
Changes for 0.98.1
==================
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-24 08:06:45 UTC (rev 5829)
+++ trunk/matplotlib/CHANGELOG 2008-07-24 08:50:43 UTC (rev 5830)
@@ -1,3 +1,6 @@
+2008-07-24 Rewrite of a significant portion of the clabel code (class
+ ContourLabeler) to improve inlining. - DMK
+
2008-07-22 Added Barbs polygon collection (similar to Quiver) for plotting
wind barbs. Added corresponding helpers to Axes and pyplot as
well. (examples/pylab_examples/barb_demo.py shows it off.) - RMM
@@ -4,7 +7,7 @@
2008-07-21 Added scikits.delaunay as matplotlib.delaunay. Added griddata
function in matplotlib.mlab, with example (griddata_demo.py) in
- pylab_examples. griddata function will use mpl_toolkits._natgrid
+ pylab_examples. griddata function will use mpl_toolkits._natgrid
if installed (haven't yet created the toolkit). - JSW
2008-07-21 Re-introduced offset_copy that works in the context of the
Modified: trunk/matplotlib/lib/matplotlib/blocking_input.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-24 08:06:45 UTC (rev 5829)
+++ trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-24 08:50:43 UTC (rev 5830)
@@ -19,8 +19,9 @@
import time
import numpy as np
+
from matplotlib import path, verbose
-from cbook import is_sequence_of_strings
+from matplotlib.cbook import is_sequence_of_strings
class BlockingInput(object):
"""
@@ -267,47 +268,39 @@
if event.inaxes == cs.ax:
conmin,segmin,imin,xmin,ymin = cs.find_nearest_contour(
- event.x, event.y, cs.label_indices)[:5]
+ event.x, event.y, cs.labelIndiceList)[:5]
# Get index of nearest level in subset of levels used for labeling
- lmin = cs.label_indices.index(conmin)
+ lmin = cs.labelIndiceList.index(conmin)
+ # Coordinates of contour
paths = cs.collections[conmin].get_paths()
lc = paths[segmin].vertices
- # Figure out label rotation. This is very cludgy.
- # Ideally, there would be one method in ContourLabeler
- # that would figure out the best rotation for a label at a
- # point, but the way automatic label rotation is done is
- # quite mysterious to me and doesn't seem easy to
- # generalize to non-automatic label placement. The method
- # used below is not very robust! It basically looks one
- # point before and one point after label location on
- # contour and takes mean of angles of two vectors formed.
- # This produces "acceptable" results, but not nearly as
- # nice as automatic method.
- ll = lc[max(0,imin-1):imin+2] # Get points around point
- dd = np.diff(ll,axis=0)
- rotation = np.mean( np.arctan2(dd[:,1], dd[:,0]) ) * 180 / np.pi
- if rotation > 90:
- rotation = rotation -180
- if rotation < -90:
- rotation = 180 + rotation
+ # In pixel/screen space
+ slc = cs.ax.transData.transform(lc)
- cs.add_label(xmin,ymin,rotation,cs.label_levels[lmin],
- cs.label_cvalues[lmin])
+ # Get label width for rotating labels and breaking contours
+ lw = cs.get_label_width(cs.labelLevelList[lmin],
+ cs.labelFmt, cs.labelFontSizeList[lmin])
+ # Figure out label rotation.
+ rotation,nlc = cs.calc_label_rot_and_inline(
+ slc, imin, lw, lc if self.inline else [],
+ self.inline_spacing )
+
+ cs.add_label(xmin,ymin,rotation,cs.labelLevelList[lmin],
+ cs.labelCValueList[lmin])
+
if self.inline:
- # Get label width for breaking contours
- lw = cs.get_label_width(cs.label_levels[lmin],
- cs.fmt, cs.fslist[lmin])
- # Break contour
- new=cs.break_linecontour(lc,rotation,lw,imin)
- if len(new[0]):
- paths[segmin] = path.Path(new[0])
- if len(new[1]):
- paths.extend([path.Path(new[1])])
+ # Remove old, not looping over paths so we can do this up front
+ paths.pop(segmin)
+ # Add paths if not empty or single point
+ for n in nlc:
+ if len(n)>1:
+ paths.append( path.Path(n) )
+
self.fig.canvas.draw()
else: # Remove event if not valid
BlockingInput.pop(self)
@@ -320,14 +313,21 @@
broken contour - once humpty-dumpty is broken, he can't be put
back together. In inline mode, this does nothing.
"""
+ # Remove this last event - not too important for clabel use
+ # since clabel normally doesn't have a maximum number of
+ # events, but best for cleanliness sake.
+ BlockingInput.pop(self)
+
if self.inline:
pass
else:
self.cs.pop_label()
self.cs.ax.figure.canvas.draw()
- def __call__(self,inline,n=-1,timeout=-1):
+ def __call__(self,inline,inline_spacing=5,n=-1,timeout=-1):
self.inline=inline
+ self.inline_spacing=inline_spacing
+
BlockingMouseInput.__call__(self,n=n,timeout=timeout,
show_clicks=False)
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2008-07-24 08:06:45 UTC (rev 5829)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2008-07-24 08:50:43 UTC (rev 5830)
@@ -69,6 +69,12 @@
controls whether the underlying contour is removed or
not. Default is *True*.
+ *inline_spacing*:
+ space in pixels to leave on each side of label when
+ placing inline. Defaults to 5. This spacing will be
+ exact for labels at locations where the contour is
+ straight, less so for labels on curved contours.
+
*fmt*:
a format string for the label. Default is '%1.3f'
Alternatively, this can be a dictionary matching contour
@@ -108,11 +114,12 @@
fontsize = kwargs.get('fontsize', None)
inline = kwargs.get('inline', 1)
- self.fmt = kwargs.get('fmt', '%1.3f')
+ inline_spacing = kwargs.get('inline_spacing', 5)
+ self.labelFmt = kwargs.get('fmt', '%1.3f')
_colors = kwargs.get('colors', None)
# Detect if manual selection is desired and remove from argument list
- self.manual_select=kwargs.get('manual',False)
+ self.labelManual=kwargs.get('manual',False)
if len(args) == 0:
levels = self.levels
@@ -131,52 +138,59 @@
raise ValueError(msg)
else:
raise TypeError("Illegal arguments to clabel, see help(clabel)")
- self.label_levels = levels
- self.label_indices = indices
+ self.labelLevelList = levels
+ self.labelIndiceList = indices
- self.fp = font_manager.FontProperties()
+ self.labelFontProps = font_manager.FontProperties()
if fontsize == None:
- font_size = int(self.fp.get_size_in_points())
+ font_size = int(self.labelFontProps.get_size_in_points())
else:
if type(fontsize) not in [int, float, str]:
raise TypeError("Font size must be an integer number.")
# Can't it be floating point, as indicated in line above?
else:
if type(fontsize) == str:
- font_size = int(self.fp.get_size_in_points())
+ font_size = int(self.labelFontProps.get_size_in_points())
else:
- self.fp.set_size(fontsize)
+ self.labelFontProps.set_size(fontsize)
font_size = fontsize
- self.fslist = [font_size] * len(levels)
+ self.labelFontSizeList = [font_size] * len(levels)
if _colors == None:
- self.label_mappable = self
- self.label_cvalues = np.take(self.cvalues, self.label_indices)
+ self.labelMappable = self
+ self.labelCValueList = np.take(self.cvalues, self.labelIndiceList)
else:
- cmap = colors.ListedColormap(_colors, N=len(self.label_levels))
- self.label_cvalues = range(len(self.label_levels))
- self.label_mappable = cm.ScalarMappable(cmap = cmap,
- norm = colors.NoNorm())
+ cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList))
+ self.labelCValueList = range(len(self.labelLevelList))
+ self.labelMappable = cm.ScalarMappable(cmap = cmap,
+ norm = colors.NoNorm())
- #self.cl = [] # Initialized in ContourSet.__init__
- #self.cl_cvalues = [] # same
- self.cl_xy = []
+ #self.labelTexts = [] # Initialized in ContourSet.__init__
+ #self.labelCValues = [] # same
+ self.labelXYs = []
- if self.manual_select:
+ if self.labelManual:
print 'Select label locations manually using first mouse button.'
print 'End manual selection with second mouse button.'
if not inline:
print 'Remove last label by clicking third mouse button.'
blocking_contour_labeler = BlockingContourLabeler(self)
- blocking_contour_labeler(inline)
+ blocking_contour_labeler(inline,inline_spacing)
else:
- self.labels(inline)
+ self.labels(inline,inline_spacing)
- self.label_list = cbook.silent_list('text.Text', self.cl)
- return self.label_list
+ # Hold on to some old attribute names. These are depricated and will
+ # be moved in the near future (sometime after 2008-08-01), but keeping
+ # for now for backwards compatibility
+ self.cl = self.labelTexts
+ self.cl_xy = self.labelXYs
+ self.cl_cvalues = self.labelCValues
+ self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts)
+ return self.labelTextsList
+
def print_label(self, linecontour,labelwidth):
"if contours are too short, don't plot a label"
lcsize = len(linecontour)
@@ -196,9 +210,9 @@
def too_close(self, x,y, lw):
"if there's a label already nearby, find a better place"
- if self.cl_xy != []:
+ if self.labelXYs != []:
dist = [np.sqrt((x-loc[0]) ** 2 + (y-loc[1]) ** 2)
- for loc in self.cl_xy]
+ for loc in self.labelXYs]
for d in dist:
if d < 1.2*lw:
return 1
@@ -237,12 +251,35 @@
return lw
+ def get_real_label_width( self, lev, fmt, fsize ):
+ """
+ This computes actual onscreen label width.
+ This uses some black magic to determine onscreen extent of non-drawn
+ label. This magic may not be very robust.
+ """
+ # Find middle of axes
+ xx = np.mean( np.asarray(self.ax.axis()).reshape(2,2), axis=1 )
+ # Temporarily create text object
+ t = text.Text( xx[0], xx[1] )
+ self.set_label_props( t, self.get_text(lev,fmt), 'k' )
+
+ # Some black magic to get onscreen extent
+ # NOTE: This will only work for already drawn figures, as the canvas
+ # does not have a renderer otherwise. This is the reason this function
+ # can't be integrated into the rest of the code.
+ bbox = t.get_window_extent(renderer=self.ax.figure.canvas.renderer)
+
+ # difference in pixel extent of image
+ lw = np.diff(bbox.corners()[0::2,0])[0]
+
+ return lw
+
def set_label_props(self, label, text, color):
"set the label properties - color, fontsize, text"
label.set_text(text)
label.set_color(color)
- label.set_fontproperties(self.fp)
+ label.set_fontproperties(self.labelFontProps)
label.set_clip_box(self.ax.bbox)
def get_text(self, lev, fmt):
@@ -255,85 +292,6 @@
else:
return fmt%lev
- def break_linecontour(self, linecontour, rot, labelwidth, ind):
- "break a contour in two contours at the location of the label"
- lcsize = len(linecontour)
- hlw = int(labelwidth/2)
-
- #length of label in screen coords
- ylabel = abs(hlw * np.sin(rot*np.pi/180))
- xlabel = abs(hlw * np.cos(rot*np.pi/180))
-
- trans = self.ax.transData
-
- slc = trans.transform(linecontour)
- x,y = slc[ind]
- xx=slc[:,0].copy()
- yy=slc[:,1].copy()
-
- #indices which are under the label
- inds, = np.nonzero(((xx < x+xlabel) & (xx > x-xlabel)) &
- ((yy < y+ylabel) & (yy > y-ylabel)))
-
- if len(inds) >0:
- #if the label happens to be over the beginning of the
- #contour, the entire contour is removed, i.e.
- #indices to be removed are
- #inds= [0,1,2,3,305,306,307]
- #should rewrite this in a better way
- linds, = np.nonzero(inds[1:]- inds[:-1] != 1)
- if inds[0] == 0 and len(linds) != 0:
- ii = inds[linds[0]]
- lc1 =linecontour[ii+1:inds[ii+1]]
- lc2 = []
-
- else:
- lc1=linecontour[:inds[0]]
- lc2= linecontour[inds[-1]+1:]
-
- else:
- lc1=linecontour[:ind]
- lc2 = linecontour[ind+1:]
-
-
- if rot <0:
- new_x1, new_y1 = x-xlabel, y+ylabel
- new_x2, new_y2 = x+xlabel, y-ylabel
- else:
- new_x1, new_y1 = x-xlabel, y-ylabel
- new_x2, new_y2 = x+xlabel, y+ylabel
-
- inverse = trans.inverted()
- new_x1d, new_y1d = inverse.transform_point((new_x1, new_y1))
- new_x2d, new_y2d = inverse.transform_point((new_x2, new_y2))
- new_xy1 = np.array(((new_x1d, new_y1d),))
- new_xy2 = np.array(((new_x2d, new_y2d),))
-
-
- if rot > 0:
- if (len(lc1) > 0 and (lc1[-1][0] <= new_x1d)
- and (lc1[-1][1] <= new_y1d)):
- lc1 = np.concatenate((lc1, new_xy1))
- #lc1.append((new_x1d, new_y1d))
-
- if (len(lc2) > 0 and (lc2[0][0] >= new_x2d)
- and (lc2[0][1] >= new_y2d)):
- lc2 = np.concatenate((new_xy2, lc2))
- #lc2.insert(0, (new_x2d, new_y2d))
- else:
- if (len(lc1) > 0 and ((lc1[-1][0] <= new_x1d)
- and (lc1[-1][1] >= new_y1d))):
- lc1 = np.concatenate((lc1, new_xy1))
- #lc1.append((new_x1d, new_y1d))
-
- if (len(lc2) > 0 and ((lc2[0][0] >= new_x2d)
- and (lc2[0][1] <= new_y2d))):
- lc2 = np.concatenate((new_xy2, lc2))
- #lc2.insert(0, (new_x2d, new_y2d))
-
- return [lc1,lc2]
-
-
def locate_label(self, linecontour, labelwidth):
"""find a good place to plot a label (relatively flat
part of the contour) and the angle of rotation for the
@@ -362,12 +320,6 @@
dist = np.add.reduce(([(abs(s)[i]/L[i]) for i in range(xsize)]),-1)
x,y,ind = self.get_label_coords(dist, XX, YY, ysize, labelwidth)
#print 'ind, x, y', ind, x, y
- angle = np.arctan2(ylast - yfirst, xlast - xfirst).ravel()
- rotation = angle[ind]*180/np.pi
- if rotation > 90:
- rotation = rotation -180
- if rotation < -90:
- rotation = 180 + rotation
# There must be a more efficient way...
lc = [tuple(l) for l in linecontour]
@@ -375,72 +327,181 @@
#print 'dind', dind
#dind = list(linecontour).index((x,y))
- return x,y, rotation, dind
+ return x, y, dind
+ def calc_label_rot_and_inline( self, slc, ind, lw, lc=[], spacing=5 ):
+ """
+ This function calculates the appropriate label rotation given
+ the linecontour coordinates in screen units, the index of the
+ label location and the label width.
+
+ It will also break contour and calculate inlining if *lc* is
+ not empty. *spacing* is the space around the label in pixels
+ to leave empty.
+
+ Do both of these tasks at once to avoid calling cbook.path_length
+ multiple times, which is relatively costly.
+
+ The method used here involves calculating the path length
+ along the contour in pixel coordinates and then looking
+ approximately label width / 2 away from central point to
+ determine rotation and then to break contour if desired.
+ """
+
+ # Half the label width
+ hlw = lw/2.0
+
+ # Check if closed and, if so, rotate contour so label is at edge
+ closed = cbook.is_closed_polygon(slc)
+ if closed:
+ slc = np.r_[ slc[ind:-1], slc[:ind+1] ]
+
+ if len(lc): # Rotate lc also if not empty
+ lc = np.r_[ lc[ind:-1], lc[:ind+1] ]
+
+ ind = 0
+
+ # Path length in pixel space
+ pl = cbook.path_length(slc)
+ pl = pl-pl[ind]
+
+ # Use linear interpolation to get points around label
+ xi = np.array( [ -hlw, hlw ] )
+ if closed: # Look at end also for closed contours
+ dp = np.array([pl[-1],0])
+ else:
+ dp = np.zeros_like(xi)
+
+ ll = cbook.less_simple_linear_interpolation( pl, slc, dp+xi,
+ extrap=True )
+
+ # get vector in pixel space coordinates from one point to other
+ dd = np.diff( ll, axis=0 ).ravel()
+
+ # Get angle of vector - must be calculated in pixel space for
+ # text rotation to work correctly
+ if np.all(dd==0): # Must deal with case of zero length label
+ rotation = 0.0
+ else:
+ rotation = np.arctan2(dd[1], dd[0]) * 180.0 / np.pi
+
+ # Fix angle so text is never upside-down
+ if rotation > 90:
+ rotation = rotation - 180.0
+ if rotation < -90:
+ rotation = 180.0 + rotation
+
+ # Break contour if desired
+ nlc = []
+ if len(lc):
+ # Expand range by spacing
+ xi = dp + xi + np.array([-spacing,spacing])
+
+ # Get indices near points of interest
+ I = cbook.less_simple_linear_interpolation(
+ pl, np.arange(len(pl)), xi, extrap=False )
+
+ # If those indices aren't beyond contour edge, find x,y
+ if (not np.isnan(I[0])) and int(I[0])<>I[0]:
+ xy1 = cbook.less_simple_linear_interpolation(
+ pl, lc, [ xi[0] ] )
+
+ if (not np.isnan(I[1])) and int(I[1])<>I[1]:
+ xy2 = cbook.less_simple_linear_interpolation(
+ pl, lc, [ xi[1] ] )
+
+ # Make integer
+ I = [ np.floor(I[0]), np.ceil(I[1]) ]
+
+ # Actually break contours
+ if closed:
+ # This will remove contour if shorter than label
+ if np.all(~np.isnan(I)):
+ nlc.append( np.r_[ xy2, lc[I[1]:I[0]+1], xy1 ] )
+ else:
+ # These will remove pieces of contour if they have length zero
+ if not np.isnan(I[0]):
+ nlc.append( np.r_[ lc[:I[0]+1], xy1 ] )
+ if not np.isnan(I[1]):
+ nlc.append( np.r_[ xy2, lc[I[1]:] ] )
+
+ # The current implementation removes contours completely
+ # covered by labels. Uncomment line below to keep
+ # original contour if this is the preferred behavoir.
+ #if not len(nlc): nlc = [ lc ]
+
+ return (rotation,nlc)
+
+
def add_label(self,x,y,rotation,lev,cvalue):
dx,dy = self.ax.transData.inverted().transform_point((x,y))
t = text.Text(dx, dy, rotation = rotation,
horizontalalignment='center',
verticalalignment='center')
- color = self.label_mappable.to_rgba(cvalue,alpha=self.alpha)
+ color = self.labelMappable.to_rgba(cvalue,alpha=self.alpha)
- _text = self.get_text(lev,self.fmt)
+ _text = self.get_text(lev,self.labelFmt)
self.set_label_props(t, _text, color)
- self.cl.append(t)
- self.cl_cvalues.append(cvalue)
- self.cl_xy.append((x,y))
+ self.labelTexts.append(t)
+ self.labelCValues.append(cvalue)
+ self.labelXYs.append((x,y))
# Add label to plot here - useful for manual mode label selection
self.ax.add_artist(t)
def pop_label(self,index=-1):
'''Defaults to removing last label, but any index can be supplied'''
- self.cl_cvalues.pop(index)
- t = self.cl.pop(index)
+ self.labelCValues.pop(index)
+ t = self.labelTexts.pop(index)
t.remove()
- def labels(self, inline):
+ def labels(self, inline, inline_spacing):
trans = self.ax.transData # A bit of shorthand
for icon, lev, fsize, cvalue in zip(
- self.label_indices, self.label_levels, self.fslist,
- self.label_cvalues ):
+ self.labelIndiceList, self.labelLevelList, self.labelFontSizeList,
+ self.labelCValueList ):
con = self.collections[icon]
- lw = self.get_label_width(lev, self.fmt, fsize)
+ lw = self.get_label_width(lev, self.labelFmt, fsize)
additions = []
paths = con.get_paths()
for segNum, linepath in enumerate(paths):
- linecontour = linepath.vertices
- # for closed contours add one more point to
- # avoid division by zero
- if np.all(linecontour[0] == linecontour[-1]):
- linecontour = np.concatenate((linecontour,
- linecontour[1][np.newaxis,:]))
- #linecontour.append(linecontour[1])
- # transfer all data points to screen coordinates
- slc = trans.transform(linecontour)
+ lc = linepath.vertices # Line contour
+ slc0 = trans.transform(lc) # Line contour in screen coords
+
+ # For closed polygons, add extra point to avoid division by
+ # zero in print_label and locate_label. Other than these
+ # functions, this is not necessary and should probably be
+ # eventually removed.
+ if cbook.is_closed_polygon( lc ):
+ slc = np.r_[ slc0, slc0[1:2,:] ]
+ else:
+ slc = slc0
+
if self.print_label(slc,lw):
- x,y, rotation, ind = self.locate_label(slc, lw)
+ x,y,ind = self.locate_label(slc, lw)
+ rotation,new=self.calc_label_rot_and_inline(
+ slc0, ind, lw, lc if inline else [],
+ inline_spacing )
+
# Actually add the label
self.add_label(x,y,rotation,lev,cvalue)
- # Use break_linecontour to split contours for inlining
+ # If inline, add new contours
if inline:
- new = self.break_linecontour(linecontour, rotation,
- lw, ind)
- if len(new[0]):
- paths[segNum] = path.Path(new[0])
- if len(new[1]):
- additions.append(path.Path(new[1]))
+ for n in new:
+ # Add path if not empty or single point
+ if len(n)>1: additions.append( path.Path(n) )
- # After looping over all segments on a contour, append
- # new paths to existing
- paths.extend(additions)
+ # After looping over all segments on a contour, remove old
+ # paths and add new ones if inlining
+ if inline:
+ del paths[:]
+ paths.extend(additions)
-
class ContourSet(cm.ScalarMappable, ContourLabeler):
"""
Create and store a set of contour lines or filled regions.
@@ -512,8 +573,8 @@
else:
self.collections = cbook.silent_list('collections.LineCollection')
# label lists must be initialized here
- self.cl = []
- self.cl_cvalues = []
+ self.labelTexts = []
+ self.labelCValues = []
kw = {'cmap': cmap}
if norm is not None:
@@ -574,9 +635,9 @@
for color, collection in zip(tcolors, self.collections):
collection.set_alpha(self.alpha)
collection.set_color(color)
- for label, cv in zip(self.cl, self.cl_cvalues):
+ for label, cv in zip(self.labelTexts, self.labelCValues):
label.set_alpha(self.alpha)
- label.set_color(self.label_mappable.to_rgba(cv))
+ label.set_color(self.labelMappable.to_rgba(cv))
# add label colors
cm.ScalarMappable.changed(self)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-24 13:30:56
|
Revision: 5836
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5836&view=rev
Author: jdh2358
Date: 2008-07-24 13:30:53 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
Merged revisions 5834 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_91_maint
........
r5834 | jdh2358 | 2008-07-24 08:15:23 -0500 (Thu, 24 Jul 2008) | 1 line
deprecated mlab2 functions from mlab
........
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/blocking_input.py
trunk/matplotlib/lib/matplotlib/contour.py
trunk/matplotlib/lib/matplotlib/mlab.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-5833
+ /branches/v0_91_maint:1-5835
Modified: trunk/matplotlib/lib/matplotlib/blocking_input.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-24 13:21:17 UTC (rev 5835)
+++ trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-24 13:30:53 UTC (rev 5836)
@@ -274,11 +274,22 @@
lw = cs.get_label_width(cs.labelLevelList[lmin],
cs.labelFmt, cs.labelFontSizeList[lmin])
+ """
+ # requires python 2.5
# Figure out label rotation.
rotation,nlc = cs.calc_label_rot_and_inline(
slc, imin, lw, lc if self.inline else [],
self.inline_spacing )
+ """
+ # Figure out label rotation.
+ if self.inline: lcarg = lc
+ else: lcarg = []
+ rotation,nlc = cs.calc_label_rot_and_inline(
+ slc, imin, lw, lcarg,
+ self.inline_spacing )
+
+
cs.add_label(xmin,ymin,rotation,cs.labelLevelList[lmin],
cs.labelCValueList[lmin])
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2008-07-24 13:21:17 UTC (rev 5835)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2008-07-24 13:30:53 UTC (rev 5836)
@@ -329,15 +329,15 @@
return x, y, dind
- def calc_label_rot_and_inline( self, slc, ind, lw, lc=[], spacing=5 ):
+ def calc_label_rot_and_inline( self, slc, ind, lw, lc=None, spacing=5 ):
"""
This function calculates the appropriate label rotation given
the linecontour coordinates in screen units, the index of the
label location and the label width.
It will also break contour and calculate inlining if *lc* is
- not empty. *spacing* is the space around the label in pixels
- to leave empty.
+ not empty (lc defaults to the empty list if None). *spacing*
+ is the space around the label in pixels to leave empty.
Do both of these tasks at once to avoid calling cbook.path_length
multiple times, which is relatively costly.
@@ -348,6 +348,7 @@
determine rotation and then to break contour if desired.
"""
+ if lc is None: lc = []
# Half the label width
hlw = lw/2.0
@@ -483,8 +484,10 @@
if self.print_label(slc,lw):
x,y,ind = self.locate_label(slc, lw)
+ if inline: lcarg = lc
+ else: lcarg = []
rotation,new=self.calc_label_rot_and_inline(
- slc0, ind, lw, lc if inline else [],
+ slc0, ind, lw, lcarg,
inline_spacing )
# Actually add the label
Modified: trunk/matplotlib/lib/matplotlib/mlab.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mlab.py 2008-07-24 13:21:17 UTC (rev 5835)
+++ trunk/matplotlib/lib/matplotlib/mlab.py 2008-07-24 13:30:53 UTC (rev 5836)
@@ -1771,181 +1771,51 @@
### end fperez numutils code
-### begin mlab2 functions
-# From MLab2: http://pdilib.sourceforge.net/MLab2.py
-readme = \
- """
-MLab2.py, release 1
-Created on February 2003 by Thomas Wendler as part of the Emotionis Project.
-This script is supposed to implement Matlab functions that were left out in
-numerix.mlab.py (part of Numeric Python).
-For further information on the Emotionis Project or on this script, please
-contact their authors:
-Rodrigo Benenson, rodrigob at elo dot utfsm dot cl
-Thomas Wendler, thomasw at elo dot utfsm dot cl
-Look at: http://pdilib.sf.net for new releases.
-"""
-## mlab2 functions numpified and checked 2007/08/04
-_eps_approx = 1e-13
-
-#from numpy import fix
-def fix(x):
- """
- Rounds towards zero.
- x_rounded = fix(x) rounds the elements of x to the nearest integers
- towards zero.
- For negative numbers is equivalent to ceil and for positive to floor.
- """
- warnings.warn("Use numpy.fix()", DeprecationWarning)
- return np.fix(x)
-
def rem(x,y):
"""
- Remainder after division.
- rem(x,y) is equivalent to x - y.*fix(x./y) in case y is not zero.
- By convention (but contrary to numpy), rem(x,0) returns None.
- This also differs from numpy.remainder, which uses floor instead of
- fix.
+ Deprecated - see numpy.remainder
"""
- x,y = np.asarray(x), np.asarray(y)
- if np.any(y == 0):
- return None
- return x - y * np.fix(x/y)
+ raise NotImplementedError('Deprecated - see numpy.remainder')
-
def norm(x,y=2):
"""
- This function is deprecated - use numpy.linalg.norm instead.
-
- Norm of a matrix or a vector. Functions similar to the Matlab (TM)
- function of the same name.
-
- Call signature::
-
- norm(x,y=2)
-
- This function behaves differently for vectors and matrices. For vectors,
- it returns the y'th norm of x (i.e. (sum(abs(x)**y))**(1.0/y).
-
- For matrices, if y=2, then it returns the largest singular value
- of X, namely max(linalg.svd(x)). If y=1, returns the largest
- column sum of x (i.e., max(sum(abs(x),axis=0)) ). If y=inf,
- returns the largest row sum. If y='fro', returns the Frobenius
- norm, sqrt(sum(diag(dot(x.transpose(),x)))).
+ Deprecated - see numpy.linalg.norm
"""
- warnings.warn( "Use numpy.linalg.norm instead", DeprecationWarning )
+ raise NotImplementedError('Deprecated - see numpy.linalg.norm')
- x = np.asarray(x)
- if x.ndim == 2:
- if y==2:
- return np.max(np.linalg.svd(x)[1])
- elif y==1:
- return np.max(np.sum(np.absolute((x)), axis=0))
- elif y=='inf':
- return np.max(np.sum(np.absolute((np.transpose(x))), axis=0))
- elif y=='fro':
- xx = np.dot(x.transpose(), x)
- return np.sqrt(np.sum(np.diag(xx), axis=0))
- else:
- raise ValueError('Second argument not permitted for matrices')
- else:
- xa = np.absolute(x)
- if y == 'inf':
- return np.max(xa)
- elif y == '-inf':
- return np.min(xa)
- else:
- return np.power(np.sum(np.power(xa,y)),1/float(y))
-
-
def orth(A):
"""
- Orthogonalization procedure similar to Matlab (TM) function of the same
- name.
-
- Call signature::
-
- Q = orth(A)
-
- Returns an orthonormal basis with the range of A. Q is an orthonormal
- matrix (i.e., dot( Q.transpose(), Q ) is an identity matrix) and the
- columns of Q span the same space as the columns of A.
+ Deprecated - needs clean room implementation
"""
+ raise NotImplementedError('Deprecated - needs clean room implementation')
- A = np.asarray(A)
- U,S,V = np.linalg.svd(A)
-
- m,n = A.shape
- if m > 1:
- s = S
- elif m == 1:
- s = S[0]
- else:
- s = 0
-
- tol = max(m,n) * np.max(s) * _eps_approx
- r = np.sum(s > tol)
- Q = np.take(U,range(r),1)
-
- return Q
-
def rank(x):
"""
- Returns the rank of a matrix.
- The rank is understood here as the an estimation of the number of
- linearly independent rows or columns (depending on the size of the
- matrix).
- Note that numerix.mlab.rank() is not equivalent to Matlab's rank.
- This function is!
+ Deprecated - see numpy.rank
"""
- x = np.asarray(x)
- s = np.linalg.svd(x, compute_uv=False)
- maxabs = np.max(np.absolute(s))
- maxdim = max(x.shape)
- tol = maxabs * maxdim * _eps_approx
- return np.sum(s > tol)
+ raise NotImplementedError('Deprecated - see numpy.rank')
def sqrtm(x):
"""
- Returns the square root of a square matrix.
- This means that s=sqrtm(x) implies dot(s,s) = x.
- Note that s and x are matrices.
+ Deprecated - needs clean room implementation
"""
- return mfuncC(np.sqrt, x)
+ raise NotImplementedError('Deprecated - needs clean room implementation')
def mfuncC(f, x):
"""
- mfuncC(f, x) : matrix function with possibly complex eigenvalues.
- Note: Numeric defines (v,u) = eig(x) => x*u.T = u.T * Diag(v)
- This function is needed by sqrtm and allows further functions.
+ Deprecated
"""
+ raise NotImplementedError('Deprecated - needs clean room implementation')
- x = np.asarray(x)
- (v,uT) = np.linalg.eig(x)
- V = np.diag(f(v+0j))
- # todo: warning: this is not exactly what matlab does
- # MATLAB "B/A is roughly the same as B*inv(A)"
- y = np.dot(uT, np.dot(V, np.linalg.inv(uT)))
- return approx_real(y)
-
def approx_real(x):
-
"""
- approx_real(x) : returns x.real if |x.imag| < |x.real| * _eps_approx.
- This function is needed by sqrtm and allows further functions.
+ Deprecated - needs clean room implementation
"""
- ai = np.absolute(x.imag)
- ar = np.absolute(x.real)
- if np.max(ai) <= np.max(ar) * _eps_approx:
- return x.real
- else:
- return x
+ raise NotImplementedError('Deprecated - needs clean room implementation')
-### end mlab2 functions
-
#helpers for loading, saving, manipulating and viewing numpy record arrays
def safe_isnan(x):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <pki...@us...> - 2008-07-24 14:54:24
|
Revision: 5839
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5839&view=rev
Author: pkienzle
Date: 2008-07-24 14:54:22 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
Fix wx start/stop event loop
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/ginput_demo.py
trunk/matplotlib/lib/matplotlib/backends/backend_wx.py
trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py
Modified: trunk/matplotlib/examples/pylab_examples/ginput_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/ginput_demo.py 2008-07-24 14:22:20 UTC (rev 5838)
+++ trunk/matplotlib/examples/pylab_examples/ginput_demo.py 2008-07-24 14:54:22 UTC (rev 5839)
@@ -2,5 +2,6 @@
t = arange(10)
plot(t, sin(t))
print "Please click"
-x = ginput(3, verbose=True)
+x = ginput(3)
+print "clicked",x
show()
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wx.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2008-07-24 14:22:20 UTC (rev 5838)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2008-07-24 14:54:22 UTC (rev 5839)
@@ -732,6 +732,8 @@
wx.EVT_IDLE(self, self._onIdle)
+ self._event_loop = wx.EventLoop()
+
self.macros = {} # dict from wx id to seq of macros
self.Printer_Init()
@@ -907,6 +909,44 @@
def flush_events(self):
wx.Yield()
+ def start_event_loop(self, timeout=0):
+ """
+ Start an event loop. This is used to start a blocking event
+ loop so that interactive functions, such as ginput and
+ waitforbuttonpress, can wait for events. This should not be
+ confused with the main GUI event loop, which is always running
+ and has nothing to do with this.
+
+ Call signature::
+
+ start_event_loop(self,timeout=0)
+
+ This call blocks until a callback function triggers
+ stop_event_loop() or *timeout* is reached. If *timeout* is
+ <=0, never timeout.
+ """
+ id = wx.NewId()
+ timer = wx.Timer(self, id=id)
+ if timeout > 0:
+ timer.Start(timeout*1000, oneShot=True)
+ bind(self, wx.EVT_TIMER, self.stop_event_loop, id=id)
+ self._event_loop.Run()
+ timer.Stop()
+
+ def stop_event_loop(self, event=None):
+ """
+ Stop an event loop. This is used to stop a blocking event
+ loop so that interactive functions, such as ginput and
+ waitforbuttonpress, can wait for events.
+
+ Call signature::
+
+ stop_event_loop_default(self)
+ """
+ if self._event_loop.IsRunning():
+ self._event_loop.Exit()
+
+
def _get_imagesave_wildcards(self):
'return the wildcard string for the filesave dialog'
default_filetype = self.get_default_filetype()
@@ -1185,46 +1225,6 @@
if figManager is not None:
figManager.canvas.draw()
- def start_event_loop(self, timeout=0):
- """
- Start an event loop. This is used to start a blocking event
- loop so that interactive functions, such as ginput and
- waitforbuttonpress, can wait for events. This should not be
- confused with the main GUI event loop, which is always running
- and has nothing to do with this.
-
- Call signature::
-
- start_event_loop(self,timeout=0)
-
- This call blocks until a callback function triggers
- stop_event_loop() or *timeout* is reached. If *timeout* is
- <=0, never timeout.
- """
- root = self.GetTopLevelParent()
- bind(root, wx.EVT_CLOSE, self.stop_event_loop)
-
- id = wx.NewId()
- timer = wx.Timer(self, id=id)
- if timeout > 0:
- timer.Start(timeout*1000, oneShot=True)
- bind(self, wx.EVT_TIMER, self.stop_event_loop, id=id)
- self._event_loop.Run()
- timer.Stop()
-
- def stop_event_loop(self, event=None):
- """
- Stop an event loop. This is used to stop a blocking event
- loop so that interactive functions, such as ginput and
- waitforbuttonpress, can wait for events.
-
- Call signature::
-
- stop_event_loop_default(self)
- """
- if self._event_loop.IsRunning():
- self._event_loop.Exit()
-
# Event binding code changed after version 2.5
if wx.VERSION_STRING >= '2.5':
def bind(actor,event,action,**kw):
@@ -1359,6 +1359,7 @@
def _onClose(self, evt):
DEBUG_MSG("onClose()", 1, self)
+ self.canvas.stop_event_loop()
Gcf.destroy(self.num)
#self.Destroy()
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py 2008-07-24 14:22:20 UTC (rev 5838)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py 2008-07-24 14:54:22 UTC (rev 5839)
@@ -41,7 +41,7 @@
toolbar = None
return toolbar
-class FigureCanvasWxAgg(FigureCanvasAgg, FigureCanvasWx):
+class FigureCanvasWxAgg(FigureCanvasWx, FigureCanvasAgg):
"""
The FigureCanvas contains the figure and does event handling.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-24 18:35:27
|
Revision: 5842
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5842&view=rev
Author: jdh2358
Date: 2008-07-24 18:35:24 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
updated api changes and changelog to reflect mlab2 deprecation
Modified Paths:
--------------
trunk/matplotlib/API_CHANGES
trunk/matplotlib/CHANGELOG
Modified: trunk/matplotlib/API_CHANGES
===================================================================
--- trunk/matplotlib/API_CHANGES 2008-07-24 17:07:43 UTC (rev 5841)
+++ trunk/matplotlib/API_CHANGES 2008-07-24 18:35:24 UTC (rev 5842)
@@ -1,6 +1,11 @@
+
Changes for 0.98.x
==================
+* Deprecated (raise NotImplementedError) all the mlab2 functions from
+ matplotlib.mlab out of concern that some of them were not clean room
+ implementations.
+
* Methods get_offsets and set_offsets added to Collections base
class.
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-24 17:07:43 UTC (rev 5841)
+++ trunk/matplotlib/CHANGELOG 2008-07-24 18:35:24 UTC (rev 5842)
@@ -1,3 +1,7 @@
+2008-07-24 Deprecated (raise NotImplementedError) all the mlab2
+ functions from matplotlib.mlab out of concern that some of
+ them were not clean room implementations. JDH
+
2008-07-24 Rewrite of a significant portion of the clabel code (class
ContourLabeler) to improve inlining. - DMK
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-24 21:56:08
|
Revision: 5850
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5850&view=rev
Author: jdh2358
Date: 2008-07-24 21:56:06 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
minor cleanup of units example, added some to backend driver, more to be fixed
Modified Paths:
--------------
trunk/matplotlib/examples/tests/backend_driver.py
trunk/matplotlib/examples/units/artist_tests.py
trunk/matplotlib/examples/units/bar_demo2.py
trunk/matplotlib/examples/units/bar_unit_demo.py
trunk/matplotlib/examples/units/basic_units.py
trunk/matplotlib/examples/units/evans_test.py
trunk/matplotlib/examples/units/evans_test2.py
trunk/matplotlib/examples/units/radian_demo.py
trunk/matplotlib/examples/units/units_scatter.py
trunk/matplotlib/unit/memleak_hawaii3.py
Modified: trunk/matplotlib/examples/tests/backend_driver.py
===================================================================
--- trunk/matplotlib/examples/tests/backend_driver.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/tests/backend_driver.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -121,9 +121,23 @@
'color_cycle.py',
]
+units_dir = os.path.join('..', 'units')
+units_files = [
+ 'annotate_with_units.py',
+ #'artist_tests.py', # broken, fixme
+ 'bar_demo2.py',
+ #'bar_unit_demo.py', # broken, fixme
+ #'ellipse_with_units.py', # broken, fixme
+ 'radian_demo.py',
+ 'units_sample.py',
+ #'units_scatter.py', # broken, fixme
+ ]
+
files = [os.path.join(pylab_dir, fname) for fname in pylab_files] +\
- [os.path.join(api_dir, fname) for fname in api_files]
+ [os.path.join(api_dir, fname) for fname in api_files] +\
+ [os.path.join(units_dir, fname) for fname in units_files]
+
# tests known to fail on a given backend
Modified: trunk/matplotlib/examples/units/artist_tests.py
===================================================================
--- trunk/matplotlib/examples/units/artist_tests.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/artist_tests.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -14,9 +14,9 @@
import matplotlib.units as units
from basic_units import cm, inch
+import numpy as np
+from pylab import figure, show
-from pylab import figure, show, nx
-
fig = figure()
ax = fig.add_subplot(111)
ax.xaxis.set_units(cm)
@@ -26,7 +26,7 @@
verts = []
for i in range(10):
# a random line segment in inches
- verts.append(zip(*inch*10*nx.mlab.rand(2, random.randint(2,15))))
+ verts.append(zip(*inch*10*np.random.rand(2, random.randint(2,15))))
lc = collections.LineCollection(verts, axes=ax)
ax.add_collection(lc)
Modified: trunk/matplotlib/examples/units/bar_demo2.py
===================================================================
--- trunk/matplotlib/examples/units/bar_demo2.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/bar_demo2.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -7,10 +7,11 @@
units)
"""
+import numpy as np
from basic_units import cm, inch
-from pylab import figure, show, nx
+from pylab import figure, show
-cms = cm *nx.arange(0, 10, 2)
+cms = cm *np.arange(0, 10, 2)
bottom=0*cm
width=0.8*cm
Modified: trunk/matplotlib/examples/units/bar_unit_demo.py
===================================================================
--- trunk/matplotlib/examples/units/bar_unit_demo.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/bar_unit_demo.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -1,6 +1,7 @@
#!/usr/bin/env python
+import numpy as np
from basic_units import cm, inch
-from pylab import figure, show,nx
+from pylab import figure, show
N = 5
menMeans = (150*cm, 160*cm, 146*cm, 172*cm, 155*cm)
@@ -9,7 +10,7 @@
fig = figure()
ax = fig.add_subplot(111)
-ind = nx.arange(N) # the x locations for the groups
+ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars
p1 = ax.bar(ind, menMeans, width, color='r', bottom=0*cm, yerr=menStd)
Modified: trunk/matplotlib/examples/units/basic_units.py
===================================================================
--- trunk/matplotlib/examples/units/basic_units.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/basic_units.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -1,9 +1,8 @@
import math
+import numpy as np
-
import matplotlib.units as units
import matplotlib.ticker as ticker
-import matplotlib.numerix as nx
from matplotlib.axes import Axes
from matplotlib.cbook import iterable
@@ -122,7 +121,7 @@
self.proxy_target = self.value
def get_compressed_copy(self, mask):
- compressed_value = nx.ma.masked_array(self.value, mask=mask).compressed()
+ compressed_value = np.ma.masked_array(self.value, mask=mask).compressed()
return TaggedValue(compressed_value, self.unit)
def __getattribute__(self, name):
@@ -135,9 +134,9 @@
def __array__(self, t = None, context = None):
if t is not None:
- return nx.asarray(self.value).astype(t)
+ return np.asarray(self.value).astype(t)
else:
- return nx.asarray(self.value, 'O')
+ return np.asarray(self.value, 'O')
def __array_wrap__(self, array, context):
return TaggedValue(array, self.unit)
@@ -159,7 +158,7 @@
return IteratorProxy(iter(self.value), self.unit)
def get_compressed_copy(self, mask):
- new_value = nx.ma.masked_array(self.value, mask=mask).compressed()
+ new_value = np.ma.masked_array(self.value, mask=mask).compressed()
return TaggedValue(new_value, self.unit)
def convert_to(self, unit):
@@ -211,7 +210,7 @@
return TaggedValue(array, self)
def __array__(self, t=None, context=None):
- ret = nx.array([1])
+ ret = np.array([1])
if t is not None:
return ret.astype(t)
else:
@@ -275,8 +274,8 @@
radians = BasicUnit('rad', 'radians')
degrees = BasicUnit('deg', 'degrees')
-radians.add_conversion_factor(degrees, 180.0/nx.pi)
-degrees.add_conversion_factor(radians, nx.pi/180.0)
+radians.add_conversion_factor(degrees, 180.0/np.pi)
+degrees.add_conversion_factor(radians, np.pi/180.0)
secs = BasicUnit('s', 'seconds')
hertz = BasicUnit('Hz', 'Hertz')
@@ -287,7 +286,7 @@
# radians formatting
def rad_fn(x,pos=None):
- n = int((x / nx.pi) * 2.0 + 0.25)
+ n = int((x / np.pi) * 2.0 + 0.25)
if n == 0:
return '0'
elif n == 1:
@@ -307,7 +306,7 @@
if unit==radians:
return units.AxisInfo(
- majloc=ticker.MultipleLocator(base=nx.pi/2),
+ majloc=ticker.MultipleLocator(base=np.pi/2),
majfmt=ticker.FuncFormatter(rad_fn),
label=unit.fullname,
)
Modified: trunk/matplotlib/examples/units/evans_test.py
===================================================================
--- trunk/matplotlib/examples/units/evans_test.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/evans_test.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -11,7 +11,7 @@
from matplotlib.cbook import iterable
import matplotlib.units as units
import matplotlib.ticker as ticker
-from pylab import figure, show, nx
+from pylab import figure, show
class Foo:
def __init__( self, val, unit=1.0 ):
Modified: trunk/matplotlib/examples/units/evans_test2.py
===================================================================
--- trunk/matplotlib/examples/units/evans_test2.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/evans_test2.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -3,13 +3,14 @@
This example shows how the unit class can determine the tick locating,
formatting and axis labeling.
"""
+import numpy as np
from basic_units import radians, degrees, cos
-from pylab import figure, show, nx
+from pylab import figure, show
from matplotlib.cbook import iterable
import math
-x = nx.arange(0, 15, 0.01) * radians
+x = np.arange(0, 15, 0.01) * radians
fig = figure()
Modified: trunk/matplotlib/examples/units/radian_demo.py
===================================================================
--- trunk/matplotlib/examples/units/radian_demo.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/radian_demo.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -1,7 +1,8 @@
+import numpy as np
from basic_units import radians, degrees, cos
-from pylab import figure, show, nx
+from pylab import figure, show
-x = nx.arange(0, 15, 0.01) * radians
+x = np.arange(0, 15, 0.01) * radians
fig = figure()
fig.subplots_adjust(hspace=0.3)
Modified: trunk/matplotlib/examples/units/units_scatter.py
===================================================================
--- trunk/matplotlib/examples/units/units_scatter.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/examples/units/units_scatter.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -8,14 +8,16 @@
The example below shows support for unit conversions over masked
arrays.
"""
+import numpy as np
from basic_units import secs, hertz, minutes
-from matplotlib.pylab import figure, show, nx
+from matplotlib.pylab import figure, show
# create masked array
-xsecs = secs*nx.ma.MaskedArray((1,2,3,4,5,6,7,8), nx.Float, mask=(1,0,1,0,0,0,1,0))
-#xsecs = secs*nx.arange(1,10.)
+xsecs = secs*np.ma.MaskedArray((1,2,3,4,5,6,7,8), (1,0,1,0,0,0,1,0), np.float)
+#xsecs = secs*np.arange(1,10.)
+
fig = figure()
ax1 = fig.add_subplot(3,1,1)
ax1.scatter(xsecs, xsecs)
Modified: trunk/matplotlib/unit/memleak_hawaii3.py
===================================================================
--- trunk/matplotlib/unit/memleak_hawaii3.py 2008-07-24 21:23:04 UTC (rev 5849)
+++ trunk/matplotlib/unit/memleak_hawaii3.py 2008-07-24 21:56:06 UTC (rev 5850)
@@ -2,7 +2,7 @@
import os, sys, time, gc
import matplotlib
-matplotlib.use('PDF')
+matplotlib.use('Agg')
from matplotlib.cbook import report_memory
import numpy as np
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <pki...@us...> - 2008-07-24 22:30:02
|
Revision: 5853
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5853&view=rev
Author: pkienzle
Date: 2008-07-24 22:29:57 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
support mouse wheel in wx
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/image_slices_viewer.py
trunk/matplotlib/lib/matplotlib/backend_bases.py
trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
trunk/matplotlib/lib/matplotlib/backends/backend_wx.py
Modified: trunk/matplotlib/examples/pylab_examples/image_slices_viewer.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/image_slices_viewer.py 2008-07-24 21:56:57 UTC (rev 5852)
+++ trunk/matplotlib/examples/pylab_examples/image_slices_viewer.py 2008-07-24 22:29:57 UTC (rev 5853)
@@ -17,7 +17,7 @@
self.update()
def onscroll(self, event):
- print event.button
+ print event.button, event.step
if event.button=='up':
self.ind = numpy.clip(self.ind+1, 0, self.slices-1)
else:
Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-07-24 21:56:57 UTC (rev 5852)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-07-24 22:29:57 UTC (rev 5853)
@@ -768,7 +768,10 @@
*key*
the key pressed: None, chr(range(255), 'shift', 'win', or 'control'
+ *step*
+ number of scroll steps (positive for 'up', negative for 'down')
+
Example usage::
def on_press(event):
@@ -783,16 +786,18 @@
inaxes = None # the Axes instance if mouse us over axes
xdata = None # x coord of mouse in data coords
ydata = None # y coord of mouse in data coords
+ step = None # scroll steps for scroll events
def __init__(self, name, canvas, x, y, button=None, key=None,
- guiEvent=None):
+ step=0, guiEvent=None):
"""
x, y in figure coords, 0,0 = bottom, left
- button pressed None, 1, 2, 3
+ button pressed None, 1, 2, 3, 'up', 'down'
"""
LocationEvent.__init__(self, name, canvas, x, y, guiEvent=guiEvent)
self.button = button
self.key = key
+ self.step = step
class PickEvent(Event):
"""
@@ -1050,7 +1055,7 @@
event = PickEvent(s, self, mouseevent, artist, **kwargs)
self.callbacks.process(s, event)
- def scroll_event(self, x, y, button, guiEvent=None):
+ def scroll_event(self, x, y, step, guiEvent=None):
"""
Backend derived classes should call this function on any
scroll wheel event. x,y are the canvas coords: 0,0 is lower,
@@ -1059,9 +1064,13 @@
This method will be call all functions connected to the
'scroll_event' with a :class:`MouseEvent` instance.
"""
- self._button = button
+ if step >= 0:
+ self._button = 'up'
+ else:
+ self._button = 'down'
s = 'scroll_event'
- mouseevent = MouseEvent(s, self, x, y, button, self._key, guiEvent=guiEvent)
+ mouseevent = MouseEvent(s, self, x, y, self._button, self._key,
+ step=step, guiEvent=guiEvent)
self.callbacks.process(s, mouseevent)
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py 2008-07-24 21:56:57 UTC (rev 5852)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py 2008-07-24 22:29:57 UTC (rev 5853)
@@ -181,10 +181,10 @@
# flipy so y=0 is bottom of canvas
y = self.allocation.height - event.y
if event.direction==gdk.SCROLL_UP:
- direction = 'up'
+ step = 1
else:
- direction = 'down'
- FigureCanvasBase.scroll_event(self, x, y, direction)
+ step = -1
+ FigureCanvasBase.scroll_event(self, x, y, step)
return False # finish event propagation?
def button_press_event(self, widget, event):
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wx.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2008-07-24 21:56:57 UTC (rev 5852)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2008-07-24 22:29:57 UTC (rev 5853)
@@ -1160,9 +1160,36 @@
FigureCanvasBase.button_release_event(self, x, y, 1, guiEvent=evt)
def _onMouseWheel(self, evt):
- # TODO: implement mouse wheel handler
- pass
+ """Translate mouse wheel events into matplotlib events"""
+ # Determine mouse location
+ x = evt.GetX()
+ y = self.figure.bbox.height - evt.GetY()
+
+ # Convert delta/rotation/rate into a floating point step size
+ delta = evt.GetWheelDelta()
+ rotation = evt.GetWheelRotation()
+ rate = evt.GetLinesPerAction()
+ #print "delta,rotation,rate",delta,rotation,rate
+ step = rate*float(rotation)/delta
+
+ # Done handling event
+ evt.Skip()
+
+ # Mac is giving two events for every wheel event
+ # Need to skip every second one
+ if wx.Platform == '__WXMAC__':
+ if not hasattr(self,'_skipwheelevent'):
+ self._skipwheelevent = True
+ elif self._skipwheelevent:
+ self._skipwheelevent = False
+ return # Return without processing event
+ else:
+ self._skipwheelevent = True
+
+ # Convert to mpl event
+ FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=evt)
+
def _onMotion(self, evt):
"""Start measuring on an axis."""
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ry...@us...> - 2008-07-25 01:43:45
|
Revision: 5861
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5861&view=rev
Author: ryanmay
Date: 2008-07-25 01:43:43 +0000 (Fri, 25 Jul 2008)
Log Message:
-----------
Add support for flipping which side of the barb the features are drawn. Useful to the meteorologists in the southern hemisphere plus anyone who might have an aesthetic preference.
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/barb_demo.py
trunk/matplotlib/lib/matplotlib/quiver.py
Modified: trunk/matplotlib/examples/pylab_examples/barb_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/barb_demo.py 2008-07-24 22:50:41 UTC (rev 5860)
+++ trunk/matplotlib/examples/pylab_examples/barb_demo.py 2008-07-25 01:43:43 UTC (rev 5861)
@@ -36,6 +36,7 @@
#Change colors as well as the increments for parts of the barbs
ax = plt.subplot(2,2,4)
ax.barbs(data['x'], data['y'], data['u'], data['v'], flagcolor='r',
- barbcolor=['b','g'], barb_increments=dict(half=10, full=20, flag=100))
+ barbcolor=['b','g'], barb_increments=dict(half=10, full=20, flag=100),
+ flip_barb=True)
plt.show()
Modified: trunk/matplotlib/lib/matplotlib/quiver.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-24 22:50:41 UTC (rev 5860)
+++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 01:43:43 UTC (rev 5861)
@@ -592,6 +592,16 @@
'half' - half barbs (Default is 5)
'full' - full barbs (Default is 10)
'flag' - flags (default is 50)
+
+ *flip_barb*:
+ Either a single boolean flag or an array of booleans. Single boolean
+ indicates whether the lines and flags should point opposite to normal
+ for all barbs. An array (which should be the same size as the other
+ data arrays) indicates whether to flip for each individual barb.
+ Normal behavior is for the barbs and lines to point right (comes from
+ wind barbs having these features point towards low pressure in the
+ Northern Hemisphere.)
+ Default is False
Barbs are traditionally used in meteorology as a way to plot the speed
and direction of wind observations, but can technically be used to plot
@@ -647,7 +657,8 @@
self.fill_empty = kw.pop('fill_empty', False)
self.barb_increments = kw.pop('barb_increments', dict())
self.rounding = kw.pop('rounding', True)
-
+ self.flip = kw.pop('flip_barb', False)
+
#Flagcolor and and barbcolor provide convenience parameters for setting
#the facecolor and edgecolor, respectively, of the barb polygon. We
#also work here to make the flag the same color as the rest of the barb
@@ -714,7 +725,7 @@
return num_flags, num_barb, half_flag, empty_flag
def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length,
- pivot, sizes, fill_empty):
+ pivot, sizes, fill_empty, flip):
'''This function actually creates the wind barbs. u and v are
components of the vector in the x and y directions, respectively.
nflags, nbarbs, and half_barb, empty_flag are, respectively, the number
@@ -730,7 +741,13 @@
height - height (distance from shaft of top) of a flag or full barb
width - width of a flag, twice the width of a full barb
emptybarb - radius of the circle used for low magnitudes
-
+
+ fill_empty specifies whether the circle representing an empty barb
+ should be filled or not (this changes the drawing of the polygon).
+ flip is a flag indicating whether the features should be flipped to
+ the other side of the barb (useful for winds in the southern
+ hemisphere.
+
This function returns list of arrays of vertices, defining a polygon for
each of the wind barbs. These polygons have been rotated to properly
align with the vector direction.'''
@@ -744,6 +761,9 @@
#Controls y point where to pivot the barb.
pivot_points = dict(tip=0.0, middle=-length/2.)
+
+ #Check for flip
+ if flip: full_height = -full_height
endx = 0.0
endy = pivot_points[pivot.lower()]
@@ -861,7 +881,7 @@
#Get the vertices for each of the barbs
plot_barbs = self._make_barbs(u, v, flags, barbs, halves, empty,
- self._length, self._pivot, self.sizes, self.fill_empty)
+ self._length, self._pivot, self.sizes, self.fill_empty, self.flip)
self.set_verts(plot_barbs)
#Set the color array
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-07-25 13:17:14
|
Revision: 5873
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5873&view=rev
Author: jdh2358
Date: 2008-07-25 13:17:10 +0000 (Fri, 25 Jul 2008)
Log Message:
-----------
committed tonys minor changes
Modified Paths:
--------------
trunk/matplotlib/examples/event_handling/lasso_demo.py
trunk/matplotlib/lib/matplotlib/axis.py
Modified: trunk/matplotlib/examples/event_handling/lasso_demo.py
===================================================================
--- trunk/matplotlib/examples/event_handling/lasso_demo.py 2008-07-25 11:58:15 UTC (rev 5872)
+++ trunk/matplotlib/examples/event_handling/lasso_demo.py 2008-07-25 13:17:10 UTC (rev 5873)
@@ -69,7 +69,7 @@
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso)
-if 0:
+if __name__ == '__main__':
data = [Datum(*xy) for xy in rand(100, 2)]
Modified: trunk/matplotlib/lib/matplotlib/axis.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axis.py 2008-07-25 11:58:15 UTC (rev 5872)
+++ trunk/matplotlib/lib/matplotlib/axis.py 2008-07-25 13:17:10 UTC (rev 5873)
@@ -147,7 +147,7 @@
"""
self._pad = val
- def get_pad(self, val):
+ def get_pad(self):
'Get the value of the tick label pad in points'
return self._pad
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|