Matplotlib Figure API

92 views
Skip to first unread message

Joerg Schnitzbauer

unread,
Mar 1, 2012, 4:32:44 PM3/1/12
to Reinteract
Hello everyone,

I am completely new to Reinteract, and I am trying to figure out how I
can embed whole Matplotlib figures.
I really would like to use it in the Matplotlib API manner, like this:



from refig import ReFigure

fig = ReFigure()
axes = fig.add_subplot(111)
[...]
axes.plot(x,y)
[...]
fig
[ fig appears on the worksheet ]



I tried to write a module "refig" as follows:



from reinteract.custom_result import CustomResult as _CustomResult
from matplotlib.figure import Figure as _Figure
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as
_FigureCanvas

class ReFigure(_Figure,_CustomResult):
def __init__(self):
_Figure.__init__(self)

def create_widget(self):
return _FigureCanvas(self)



I assumed this would work, because _FigureCanvas is a GTK widget.
However, the line where I expect to see the figure stays empty.
Is there something that I am missing here?


As a test, I tried the equivalent thing with a gtk.Button:



import gtk as _gtk
from reinteract.custom_result import CustomResult as _CustomResult

class ReButton(_gtk.Button,_CustomResult):
def __init__(self,text):
_gtk.Button.__init__(self,text)

def create_widget(self):
return self



This worked fine. A button appears on the worksheet.

I found the following code to work for the Figure, but it feels like a
bad hack that probably should not be used like this. Also, the axes
are only drawn, if I minimize/maximize the window or switch back and
forth through tabs.



from matplotlib.figure import Figure as _Figure
from reinteract.custom_result import CustomResult as _CustomResult
from replot import PlotWidget as _PlotWidget

class ReFigure(_Figure,_CustomResult):
def __init__(self):
_Figure.__init__(self)

def create_widget(self):
plotwidget = _PlotWidget(self)
plotwidget.figure = self
return plotwidget


I would be happy to learn about how the gtk widgets are implemented.
Apparently I am missing something important.

Thanks in advance!
Reinteract is great work. I would really love to see it advance!

Best,
Joerg

Robert Schroll

unread,
Mar 2, 2012, 7:57:34 AM3/2/12
to reint...@googlegroups.com
On 03/01/2012 04:32 PM, Joerg Schnitzbauer wrote:
> Hello everyone,
>
> I am completely new to Reinteract, and I am trying to figure out how I
> can embed whole Matplotlib figures.
> I really would like to use it in the Matplotlib API manner, like this:

May I suggest that you take a look at refigure2
(http://rschroll.github.com/refigure2/), which is my (second) attempt to
provide a pylab-like plotting interface for Reinteract. If you're using
Reinteract 0.5, the released version of refigure2 is for you. But if
you're using 0.5.9 or .10, you might want to checkout the git version.
It allows you to do stuff like this:

build figure():
subplot(121)
plot(x, y)
...

Hopefully this will be somewhat useful for you.

If you're still interested in why your method didn't work, I might be
able to offer some insight. But not right now, because I have to run.

Hope that helps,
Robert

Joerg Schnitzbauer

unread,
Mar 2, 2012, 2:28:08 PM3/2/12
to Reinteract
Great! The git version of refigure2 works fine for me. Thanks.

I would be happy to learn how it works, and why my example didn't.
I am studying the code right now, but some explanations from you would
be really helpful.

Best,
Joerg

Joerg Schnitzbauer

unread,
Mar 2, 2012, 3:03:26 PM3/2/12
to Reinteract
Hello again,

I found the reason why my output seemed to be empty:
I have to set a size request for the canvas. The following code works:


from reinteract.custom_result import CustomResult as _CustomResult
from matplotlib.figure import Figure as _Figure
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as
_FigureCanvas

class ReFigure(_Figure,_CustomResult):
def __init__(self):
_Figure.__init__(self)

def create_widget(self):
canvas = _FigureCanvas(self)
canvas.set_size_request(400,300)
return canvas


Still, refigure2 seems to be a much more elaborate implementation.

Joerg

On Mar 2, 4:57 am, Robert Schroll <rschr...@gmail.com> wrote:

Robert Schroll

unread,
Mar 3, 2012, 2:40:15 PM3/3/12
to reint...@googlegroups.com
On 03/02/2012 02:28 PM, Joerg Schnitzbauer wrote:
> I would be happy to learn how it works, and why my example didn't.
> I am studying the code right now, but some explanations from you would
> be really helpful.

It looks like you found the primary problem (which was not what I was
expecting, but it does ring a bell now that you mention it). But there
are a few other problems refigure2 has to deal with. I'll mention them
here briefly. Hopefully with the code, one can see how these were dealt
with. But if you, or anyone else, has further questions, I'm happy to
try to answer them.

1) Don't do anything GTK-related until the create_widget method call.
The create_widget method is called in the main thread, so GTK calls are
safe there. But all other code is called from worker threads, from
which you shouldn't make GTK calls. Doing so leads to subtle and
hard-to-trace bugs, like this:
https://github.com/rschroll/refigure2/issues/1

2) Dealing with re-execution partway through a figure creation.
Matplotlib keeps quite a bit of state behind the scenes about what's
going on to the current figure. Reinteract doesn't track this, so if
you were to go back and tweak a plot command, you're apt to end up with
two lines on your figure. replot deals with this is a clever manner, by
recording the plotting commands in a way the Reinteract can trace, and
then playing to back during figure creation. refigure2 adopts a
stupider, but robust, method: putting all the plotting commands within a
single block, so they are all executed each time any one of them is edited.

3) Keeping track of the current figure. This isn't a problem when using
the object-oriented interface to matplotlib, but the pylab interface
keeps track of the current figure and axes behind the scenes, and sends
plotting commands to them. If multiple worksheets are executing at
once, plotting commands could end up affecting random figures.
refigure2 deals with this by creating a lock inside of which all the
plotting is done.

Hopefully this is of interest to anyone making an extension around a
Python module that keeps state internally.

Robert

Jörg Schnitzbauer

unread,
Mar 4, 2012, 4:53:13 PM3/4/12
to reint...@googlegroups.com
That makes a lot of sense. Thanks for sharing!

I attached a hacked version of the git file with some minor
adjustments for my usage. Please feel welcome to add them to the
official version.

It has the following adjustments:

1. The user can choose if a toolbar should be displayed upon figure
initialization:

with figure(toolbar=False) as f:
...

The default is True.

2. If the toolbar is not displayed AND the facecolor is not explicitly
set by the user as a keyword argument (e.g. figure(facecolor='red')),
the facecolor defaults to white.
This is just cosmetics so that the figure integrates IMO nicer into
the worksheet.

Best,
Joerg

> --
> You received this message because you are subscribed to the Google Groups
> "Reinteract" group.
> To post to this group, send email to reint...@googlegroups.com.
> To unsubscribe from this group, send email to
> reinteract+...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/reinteract?hl=en.
>

refigure2.py
Reply all
Reply to author
Forward
0 new messages