patch for adding manual label location selection to clabel

In addition to your patch you can put start/stop_event_loop
methods into the the canvas. That way backends can specialize
their implementation so they don't need a busy loop while waiting
for the event.

Then you can replace the termination notice in BlockingInput:

- self.done = True
+ self.fig.canvas.stop_event_loop()

and move the busy loop to the backend:

         # wait for n clicks
- counter = 0
- while not self.done:
- self.fig.canvas.flush_events()
- time.sleep(0.01)

···

On Thu, Jul 17, 2008 at 09:46:16AM +0200, David M. Kaplan wrote:

I don't think the blocking code will be that hard to maintain. It
basically just depends on events, callback functions and time.sleep. If
those are cross-platform, then it shouldn't be a problem. But only time
will tell. My ability and desire to test on multiple platforms is
limited - I use ubuntu/gnome-gtk/linux 100%.

-
- # check for a timeout
- counter += 1
- if timeout > 0 and counter > timeout/0.01:
- print "ginput timeout";
- break;
+ self.fig.canvas.start_event_loop(timeout=timeout)

In backend_bases.py I have a generic interactive version
based on sleep:

class FigureCanvasBase:
    ...
    def start_event_loop(self, timeout=0):
        """
        Run the event loop.

        This call blocks until an event callback triggers
        stop_event_loop() or the timeout interval is exceeded.
        """
        if timeout == 0: timeout = npy.inf
        timestep = 0.01
        counter = 0
        self._looping = True
        while self._looping and counter*timestep < timeout:
            self.flush_events()
            time.sleep(timestep)
            counter += 1

    def stop_event_loop(self):
        """
        Stop the event loop.

        The function which started the event loop can now run to completion.
        """
        self._looping = False

In the wx canvas this is specialized as:

class FigureCanvasWx(FigureCanvasBase, wx.Panel):
    ...
    def start_event_loop(self, timeout=0):
        """
        Run the event loop.

        This call blocks until an event callback triggers
        stop_event_loop() or the timeout interval is exceeded.
        """
        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 the event loop.

        The function which started the event loop can now run to completion.
        """
        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):
        actor.Bind(event,action,**kw)
else:
    def bind(actor,event,action,id=None):
        if id is not None:
            event(actor, id, action)
        else:
            event(actor,action)

Hi,

This sounds like a great idea. My trunk version of matplotlib does not
have these changes. I presume you would like me to commit them? If so,
let me know and it would be great if you could give your code a test
using the wx backend afterward.

Cheers,
David

···

On Thu, 2008-07-17 at 12:13 -0400, Paul Kienzle wrote:

On Thu, Jul 17, 2008 at 09:46:16AM +0200, David M. Kaplan wrote:
> I don't think the blocking code will be that hard to maintain. It
> basically just depends on events, callback functions and time.sleep. If
> those are cross-platform, then it shouldn't be a problem. But only time
> will tell. My ability and desire to test on multiple platforms is
> limited - I use ubuntu/gnome-gtk/linux 100%.

In addition to your patch you can put start/stop_event_loop
methods into the the canvas. That way backends can specialize
their implementation so they don't need a busy loop while waiting
for the event.

Then you can replace the termination notice in BlockingInput:

- self.done = True
+ self.fig.canvas.stop_event_loop()

and move the busy loop to the backend:

         # 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 "ginput timeout";
- break;
+ self.fig.canvas.start_event_loop(timeout=timeout)

In backend_bases.py I have a generic interactive version
based on sleep:

class FigureCanvasBase:
    ...
    def start_event_loop(self, timeout=0):
        """
        Run the event loop.

        This call blocks until an event callback triggers
        stop_event_loop() or the timeout interval is exceeded.
        """
        if timeout == 0: timeout = npy.inf
        timestep = 0.01
        counter = 0
        self._looping = True
        while self._looping and counter*timestep < timeout:
            self.flush_events()
            time.sleep(timestep)
            counter += 1

    def stop_event_loop(self):
        """
        Stop the event loop.

        The function which started the event loop can now run to completion.
        """
        self._looping = False

In the wx canvas this is specialized as:

class FigureCanvasWx(FigureCanvasBase, wx.Panel):
    ...
    def start_event_loop(self, timeout=0):
        """
        Run the event loop.

        This call blocks until an event callback triggers
        stop_event_loop() or the timeout interval is exceeded.
        """
        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 the event loop.

        The function which started the event loop can now run to completion.
        """
        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):
        actor.Bind(event,action,**kw)
else:
    def bind(actor,event,action,id=None):
        if id is not None:
            event(actor, id, action)
        else:
            event(actor,action)

--
**********************************
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
**********************************