Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Feature request - make it simpler to use full OO interface #1094

Closed
astrofrog opened this Issue · 17 comments

8 participants

@astrofrog

I would like to start using the matplotlib OO interface more, as I would prefer to use this when interactive plotting is not needed. It it slightly faster, and behaves more intuitively in terms of reference counting (pyplot keeps a reference to each figure, meaning that if figures are not closed by pyplot, memory goes out of control).

The reason I don't use it is because it's not easy to remember all the set-up of the canvas and figure:

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(1, 1, 1)
ax.scatter(np.random.random(10), np.random.random(10))
fig.savefig('test.png')

So I was wondering whether it would be possible to make Figure more intelligent in terms of canvas? The 'ideal' API in my mind would be:

from matplotlib.figure import Figure

fig = Figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(np.random.random(10), np.random.random(10))
fig.savefig('test.png')

i.e. I want the figure to just use the default backend (since this is set at the root level of matplotlib, not pyplot). So I would expect the following to work:

import matplotlib
matplotlib.use('Agg')
from matplotlib.figure import Figure

fig = Figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(np.random.random(10), np.random.random(10))
fig.savefig('test.png')

and to use the non-interactive Agg backend.

Is this something that has been considered before?

@WeatherGod
Collaborator

It would probably be cleaner this way. Currently, pyplot.figure() invokes the new_figure_manager function that is (somehow) established by the init.py module in matplotlib.backends. It would probably be wise to look at this area of code again to see how we can clean this up anyway.

@dmcdougall
Collaborator

Setting pyplot aside for the moment, is there anything to stop the canvas being set up in the Figure constructor? At the moment, Figure.__init__ has the line:

self.canvas = None

Which is evidenced by:

In [1]: from matplotlib.figure import Figure

In [2]: fig = Figure()

In [3]: print fig.canvas
None

One way to work around this is to retrieve the default backend in the __init__ method in the constructor, which should exist either from a matplotlib.use('mybackend') or from rcParams. This can be done using a matplotlib.get_backend() call.

Is there something deeper I am missing?

@astrofrog

@dmcdougall - this is exactly what I mean, and I believe it would make it a lot easier for people to use this API.

@dmcdougall
Collaborator

So I tried this out, and it seems to work ok. I can't say anything for pyplot. Though, if you're using pyplot, you're probably not interested in the OO interface. I can submit a PR if any of the more experienced mpl developers would like to give some input...

@pelson pelson closed this
@dmcdougall
Collaborator

@efiring Should this be re-opened because of #1221?

@efiring efiring reopened this
@efiring
Owner

This might have worked if carefully restricted to non-interactive backends. I think it requres some careful thought and experimentation, though. It may be that the way to handle it is via a kwarg to the Figure constructor, explicitly designating a non-interactive backend; or maybe in the code as you had it, attaching the canvas to the figure upon Figure initialization would be done only if the default backend is non-interactive. All of the messy figure management machinery is needed only for screen display, not for savefig, I believe.
A problem with this approach is that although it simplifies some things, it adds overall complexity in that something that works for a non-interactive backend fails if the default backend is interactive. So, it might cause more trouble (puzzled users, mailing list traffic) than it is worth.

@berr

@efiring Do you think we can find a way to implement this issue without changing the interactive workflow? I have some spare time on the next few weeks and would like to work on that.

@efiring
Owner

You are certainly welcome to try. I'm out on a ship until mid-Nov., and then busy into December, so I probably won't be much help. If you can come up with something that makes the whole Figure/Canvas dance simpler and easier to understand at the lowest code level as well as at the user level--and that doesn't break anything--that will be very good.

@berr

I'll sure give it a try.
Is there a dev mailing list / irc channel that I can use to find someone if I need guidance? (couldn't find anything on the site)

@mdboom
Owner

matplotlib-devel is a good place to reach other developers:

https://sourceforge.net/mailarchive/forum.php?forum_name=matplotlib-devel

@dmcdougall
Collaborator

@berr I've been working on an alternative solution to this, and currently have an implementation illustrating some degree of success. That said, I would be interested to see if you come up with a similar approach. Do you have a branch I can take a cheeky fork of?

@berr

@dmcdougall Not yet. I'm planning to start this on the next week. Since you've already started, I can use your work as a starting point or even just continue it. Do you have it on a branch that I could see?

@dmcdougall
Collaborator

@berr Yes, but don't let it pollute your train of thought. I tried this once before and failed epicly. This new approach is a better version, and I haven't worked on it for a while so I'm not sure if it still works... The branch is here. I hope it's helpful.

@dmcdougall
Collaborator

IIRC, I had problems with the Qt4 backend...

@demitri

Just want to add my +1 to strongly support a fully OO plotting interface.

@dmcdougall
Collaborator

@demitri Thanks. Good to know this would be used.

@berr Did you try out my branch?

@dmcdougall
Collaborator

Turns out this is rather hard to implement without a significant backend redesign and/or refactor. See discussion in #1457.

@dmcdougall dmcdougall closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.