[matplotlib-devel] waitforbuttonpress function addition

2008-07-11 Thread David M. Kaplan
Hi,

Following Gael Varoquaux's lead on adding a ginput command to matplotlib
(nice job!), I added a waitforbuttonpress function to matplotlib.  The
patch is attached (generate using svn diff from the
matplotlib/trunk/matplotlib directory).  waitforbuttonpress is a simple
function with a matlab equivalent that returns a list of true/false's -
true for a keyboard click and false for a mouse click.  I use it in
matlab regularly as a simple yes/no question (often to decide whether or
not to save a figure).  

The way I have implemented it is by adding an additional class
BlockingKeyMouseInput, which is quite similar to BlockingMouseInput, but
waits for both key and mouse events.  A smarter person than I could
probably combine these two classes and make something that would serve
both functions.  But I am basically new to python and don't feel
comfortable.  Perhaps someone else could take a look and make
improvements/simplifications?

The other thing that I have noticed with both ginput and
waitforbuttonpress is that if you use ctrl-c to break out of either,
then the callback functions remain attached to their respective events
(e.g., try ginput(n=-1,timeout=-1,verbose=True) and hit ctrl-c).  This
probably isn't a huge problem, but it would be nice if there was a way
to say "if ctrl-c is pressed, cleanup nicely".  Does someone know if
that is possible?

Cheers,
David


-- 
**
David M. Kaplan
Charge de Recherche 1
Institut de Recherche pour le Developpement
Centre de Recherche Halieutique Mediterraneenne et Tropicale
av. Jean Monnet
B.P. 171
34203 Sete cedex
France

Phone: +33 (0)4 99 57 32 27
Fax: +33 (0)4 99 57 32 95
http://www.ur097.ird.fr/team/dkaplan/index.html
**

-- 
**
David M. Kaplan
Assistant Researcher
UCSC / Institute of Marine Sciences
Ocean Sciences
1156 High St.
SC, CA 95064

Phone: 831-459-4789
Fax: 831-459-4882
http://pmc.ucsc.edu/~dmk/
**
Index: lib/matplotlib/pyplot.py
===
--- lib/matplotlib/pyplot.py	(revision 5735)
+++ lib/matplotlib/pyplot.py	(working copy)
@@ -335,7 +335,21 @@
 if Figure.ginput.__doc__ is not None:
 ginput.__doc__ = dedent(Figure.ginput.__doc__)
 
+def waitforbuttonpress(*args, **kwargs):
+"""
+Blocking call to interact with the figure.
 
+This will wait for *n* key or mouse clicks from the user and
+return a list containing True's for keyboard clicks and False's
+for mouse clicks.
+
+If *timeout* is negative, does not timeout.
+"""
+return gcf().waitforbuttonpress(*args, **kwargs)
+if Figure.waitforbuttonpress.__doc__ is not None:
+waitforbuttonpress.__doc__ = dedent(Figure.waitforbuttonpress.__doc__)
+
+
 # Putting things in figures
 
 def figtext(*args, **kwargs):
Index: lib/matplotlib/figure.py
===
--- lib/matplotlib/figure.py	(revision 5735)
+++ lib/matplotlib/figure.py	(working copy)
@@ -6,6 +6,9 @@
 :class:`SubplotParams`
 control the default spacing of the subplots
 
+:class:`BlockingKeyMouseInput`
+creates a callable object to retrieve key or mouse clicks in a blocking way for interactive sessions
+
 :class:`BlockingMouseInput`
 creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions
 
@@ -118,6 +121,78 @@
 setattr(self, s, val)
 
 
+class BlockingKeyMouseInput(object):
+"""
+Class that creates a callable object to retrieve key or mouse clicks in a
+blocking way.
+"""
+def __init__(self, fig):
+self.fig = fig
+
+
+def on_mouse_click(self, event):
+"""
+Event handler that will be passed to the current figure to
+retrieve clicks.
+"""
+self.events.append(event)
+self.buttons.append(event.button)
+self.keyormouse.append(False)
+
+if len(self.keyormouse) >= self.n:
+self.done = True
+
+def on_key_click(self, event):
+"""
+Event handler that will be passed to the current figure to
+retrieve key presses.
+"""
+self.events.append(event)
+self.keys.append(event.key)
+self.keyormouse.append(True)
+
+if len(self.keyormouse) >= self.n:
+self.done = True
+
+def __call__(self, n=1, timeout=-1 ):
+"""
+Blocking call to retrieve n key or mouse events
+"""
+self.done= False
+self.keys  = []
+self.buttons   = []
+self.events   = []
+self.keyormouse = []
+
+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.callbackm = self.fig.canvas.mpl_connect('button_press_event',
+

Re: [matplotlib-devel] waitforbuttonpress function addition

2008-07-11 Thread Gael Varoquaux
On Fri, Jul 11, 2008 at 03:22:30PM +0200, David M. Kaplan wrote:
> The way I have implemented it is by adding an additional class
> BlockingKeyMouseInput, which is quite similar to BlockingMouseInput, but
> waits for both key and mouse events.  A smarter person than I could
> probably combine these two classes and make something that would serve
> both functions.  But I am basically new to python and don't feel
> comfortable.  Perhaps someone else could take a look and make
> improvements/simplifications?

The only significantly different lines are the two lines where an
mplconnect is done to register the callback. You could abstract this in a
method and then have a base class and two sub classes for each call: the
blocking from mouse and the blocking from button.

> The other thing that I have noticed with both ginput and
> waitforbuttonpress is that if you use ctrl-c to break out of either,
> then the callback functions remain attached to their respective events
> (e.g., try ginput(n=-1,timeout=-1,verbose=True) and hit ctrl-c).  This
> probably isn't a huge problem, but it would be nice if there was a way
> to say "if ctrl-c is pressed, cleanup nicely".  Does someone know if
> that is possible?

I think this is a good usecase for a try: ... finally: ... .

I don't have time to do these changes right now, as I am very busy both
with IPython and Mayavi, and will be travelling next two weeks, but you
can have a good at them, and someone else will probably commit your
patch, if you removed the code duplication.

Cheers,

Gaël


-
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08
___
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel


Re: [matplotlib-devel] waitforbuttonpress function addition

2008-07-11 Thread David M. Kaplan
Hi,

Attached is a new patch to replace the previous one that I sent that
does what Gael suggested.  It works well and seems fairly efficient to
me, but again I am new to python and I could be mistaken about what Gael
was suggesting.  Basically, I created a base class that does the
blocking and collects events of any particular set of types specified by
name at initiation.  I then created two subclasses that specify exactly
which events they deal with and do additional processing beyond just
collecting events, one for mouse events and one for mouse+keyboard
events.  These are then called by ginput and waitforbuttonpress
respectively.  I also changed my version of waitforbuttonpress so that
it precisely matches the functionality of matlab's waitforbuttonpress,
with the exception of a timeout option.

Comments welcome.  

Cheers,
David

On Fri, 2008-07-11 at 16:12 +0200, Gael Varoquaux wrote:
> On Fri, Jul 11, 2008 at 03:22:30PM +0200, David M. Kaplan wrote:
> > The way I have implemented it is by adding an additional class
> > BlockingKeyMouseInput, which is quite similar to BlockingMouseInput, but
> > waits for both key and mouse events.  A smarter person than I could
> > probably combine these two classes and make something that would serve
> > both functions.  But I am basically new to python and don't feel
> > comfortable.  Perhaps someone else could take a look and make
> > improvements/simplifications?
> 
> The only significantly different lines are the two lines where an
> mplconnect is done to register the callback. You could abstract this in a
> method and then have a base class and two sub classes for each call: the
> blocking from mouse and the blocking from button.
> 
> > The other thing that I have noticed with both ginput and
> > waitforbuttonpress is that if you use ctrl-c to break out of either,
> > then the callback functions remain attached to their respective events
> > (e.g., try ginput(n=-1,timeout=-1,verbose=True) and hit ctrl-c).  This
> > probably isn't a huge problem, but it would be nice if there was a way
> > to say "if ctrl-c is pressed, cleanup nicely".  Does someone know if
> > that is possible?
> 
> I think this is a good usecase for a try: ... finally: ... .
> 
> I don't have time to do these changes right now, as I am very busy both
> with IPython and Mayavi, and will be travelling next two weeks, but you
> can have a good at them, and someone else will probably commit your
> patch, if you removed the code duplication.
> 
> Cheers,
> 
> Gaël
> 
-- 
**
David M. Kaplan
Assistant Researcher
UCSC / Institute of Marine Sciences
Ocean Sciences
1156 High St.
SC, CA 95064

Phone: 831-459-4789
Fax: 831-459-4882
http://pmc.ucsc.edu/~dmk/
**
Index: lib/matplotlib/pyplot.py
===
--- lib/matplotlib/pyplot.py	(revision 5735)
+++ lib/matplotlib/pyplot.py	(working copy)
@@ -335,7 +335,21 @@
 if Figure.ginput.__doc__ is not None:
 ginput.__doc__ = dedent(Figure.ginput.__doc__)
 
+def waitforbuttonpress(*args, **kwargs):
+"""
+Blocking call to interact with the figure.
 
+This will wait for *n* key or mouse clicks from the user and
+return a list containing True's for keyboard clicks and False's
+for mouse clicks.
+
+If *timeout* is negative, does not timeout.
+"""
+return gcf().waitforbuttonpress(*args, **kwargs)
+if Figure.waitforbuttonpress.__doc__ is not None:
+waitforbuttonpress.__doc__ = dedent(Figure.waitforbuttonpress.__doc__)
+
+
 # Putting things in figures
 
 def figtext(*args, **kwargs):
Index: lib/matplotlib/figure.py
===
--- lib/matplotlib/figure.py	(revision 5735)
+++ lib/matplotlib/figure.py	(working copy)
@@ -6,8 +6,16 @@
 :class:`SubplotParams`
 control the default spacing of the subplots
 
+: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
+creates a callable object to retrieve mouse clicks in a blocking way for interactive sessions.  
+Note: Subclass of BlockingInput.  Used by ginput
 
 :class:`Figure`
 top level container for all plot elements
@@ -118,24 +126,107 @@
 setattr(self, s, val)
 
 
-class BlockingMouseInput(object):
+class BlockingInput(object):
 """
-Class that creates a callable object to retrieve mouse clicks in a
+Class that creates a callable object to retrieve events in a
 blocking way.
 """
-def __init__(self, fig):
+def __init__(self, fig, eventslist=()):
 self.fig = fig

[matplotlib-devel] colormap menu

2008-07-11 Thread Paul Kienzle
Hi,

I created a menu for selecting colormaps from a context menu on the
graph.  The attached code cmapmenu.py contains a runnable example.

I've only implemented support for wx.

In general, I would like to be able to add context menu operations
to individual artists on the plot, and will be doing so for my
own applications.  Is this something that could live in the
matplotlib backends?  Are there users of Qt, Gtk, Tk, ... who
are willing to add support for them?

- Paul

# This program is public domain
"""
Defines CMapMenu, a wx submenu containing colormaps.

=== Example ===

The following defines a context menu with mapper::

import wx
import cmapmenu

...
def onContextMenu(self,event):
popup = wx.Menu()
item = popup.Append(wx.ID_ANY,'&Save image', 'Save image as PNG')
wx.EVT_MENU(self, item.GetId(), self.onSaveImage)
item = popup.Append(wx.ID_ANY,'&Grid on/off', 'Toggle grid lines')
wx.EVT_MENU(self, item.GetId(), self.onGridToggle)
item = popup.AppendMenu(wx.ID_ANY, "Colourmaps",
CMapMenu(self, self.mapper, self.canvas))

The assumption is that mapper and canvas are attributes of the panel for
which the context menu is defined.  When the new colour map is selected,
the mapper will be reset and the figure redrawn.

Sometimes you will want to do more than just update the mapper for the
current canvas.  You may for example want to record the new colormap name
in the application settings file so that it will be there when the
application is reloaded.  To do this, call CMapMenu(callback=self.OnColormap).
This will call the method OnColormap with the parameter name giving the
name of the colormap.
"""
__all__ = ['CMapMenu']

import sys
import wx
import numpy
from matplotlib import cm

def colorbar_bitmap(colormap,length,thickness=10,orientation='horizontal'):
"""
Convert a colormap to a bitmap showing a colorbar for the colormap.

Orientation can be vertical or horizontal (only looks at the first letter).
"""
# Make an RGBA array from the colormap, either horizontally or vertically.
V = colormap(numpy.linspace(0,1,length),bytes=True)
if orientation[0].lower() == 'h':
V = numpy.tile(V,(thickness,1))
bitmap = wx.BitmapFromBufferRGBA(length,thickness,V)
elif orientation[0].lower() == 'v':
V = numpy.tile(V,(1,thickness))
bitmap = wx.BitmapFromBufferRGBA(thickness,length,V)
else:
raise ValueError,"expected orientation [V]ertical or [H]orizontal"
return bitmap

def all_colormaps():
"""
Iterate over the available colormaps
"""
maps = [name 
for name in cm.datad.keys()
if not name.endswith("_r")]
maps.sort()
return maps

def grouped_colormaps():
"""
Colormaps grouped by source.
"""
mlab = ['autumn','winter','spring','summer',
'gray','bone','copper','pink',
'cool','hot',
'hsv','jet','spectral',
#'binary',   # Seems to be a reverse of gray
'prism','flag']
mlab_r = [m+'_r' for m in mlab]
brewer = ['Accent','Dark2',
  'Spectral',
  'Paired',
  'Blues','Greens','Greys','Oranges','Purples','Reds',
  'Pastel1','Pastel2',
  'Set1','Set2','Set3',
  'BrBG','BuGn','BuPu','GnBu',
  'OrRd',
  'PiYG','PRGn','PuBu','PuBuGn',
  'PuOr','PuRd',
  'RdBu','RdGy','RdPu',
  'RdYlBu','RdYlGn',
  'YlGn','YlGnBu','YlOrBr','YlOrRd',
  ]
brewer_r = [m+'_r' for m in brewer]
gist = ['gist_ncar','gist_rainbow',
'gist_stern','gist_earth',
'gist_gray','gist_heat',
#'gist_yarg',  # Seems to be a reverse of gray
]
gist_r = [m+'_r' for m in gist]

return gist + [None] + mlab + [None] + brewer

def event_callback(callback, **kw):
"""
Add keyword arguments to the event callback.
"""
return lambda evt: callback(evt,**kw)
class CMapMenu(wx.Menu):
"""
Menu tree binding to a list of colormaps.
"""
def __init__(self, window,
 mapper=None, canvas=None, callback=None):
"""
Define a context menu for selecting colormaps.

Need a window to use as the event handler.
If mapper is defined, it will be updated with the new colormap.
If canvas is defined, it will update on idle.
"""
wx.Menu.__init__(self)

# OS X needs 16x16 icons; Windows and Linux can be longer
bar_length = 32 if not sys.platform in ['darwin'] else 16
bar_height = 16
self.mapper,self.canvas,self.callback = mapper,canvas,callback
self.selected = None
self.mapid = {}
for name in grouped_colormaps():
if name is None:
self.AppendSeparator()
else:
item = wx.Menu

[matplotlib-devel] Two projects possibly of interest

2008-07-11 Thread Fernando Perez
Howdy,

I stumbled upon these two projects which may be of interest to some in mpl land:

- perceptual image diff: http://pdiff.sourceforge.net/

I have no idea if this works well or not, but if it does, it could be
useful for regression testing of mpl, something which has been sorely
missing and normally involves running the test driver, looking for
errors and possibly inspecting plots by hand (or by eye,  as it were).
 I think that mpl would greatly benefit from some form of automatic
testing.

- Graphite: http://graphite.wikidot.com/faq

Python based real-time graphs from large/high rate data sets.  Every
now and then we get posts here asking about doing plots of high
throughput data, a task for which mpl isn't always ideally suited.
This  might be a good alternative in some cases.  I'm sure it doesn't
do any of the sophisticated/scientific plotting many of us need mpl
for, but for some use cases it may be a good tool.

cheers,

f

-
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08
___
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel