Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Reduce object-oriented boilerplate for users#1125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
This is very handy. +1. |
The basic idea seems good. Ideally, I would think that each backend should provide a canvas in way that does not require the huge if...elif structure, but this would require a larger change, so perhaps it should be left until later. figure.py should not need to know about all possible backends; it should be able to do something like "import matplotlib.backends; matplotlib.backends.get_current_canvas()". In any case, all backends supported by rcsetup.validate_backends (and listed in rcsetup.all_backends) should be included; some are missing at present. |
@@ -323,6 +323,48 @@ def __init__(self, | |||
self.clf() | |||
self._cachedRenderer = None | |||
def _current_figure_canvas(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Perhaps this could be a function inbackend_bases
?pylab_setup
pretty much does this for you. Something like:
import matplotlib.backends as mbackends # NOTE: requires a change from #1020backend_mod, _, _, _ = mbackends.pylab_setup()# NOTE: would require all backend modules to have # a FigureCanvas rather than say a FigureCanvasGTKAggbackend_mod.FigureCanvas(self)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Also, needs a docstring, and the name of the method is misleading.
Ah. I've only just read@efiring 's comment. It seems we agree on this issue. I definitely think this should be done properly at this stage, and would think it was cleaner to do this via the "backend_bases" module. Other than that, I think this is a great idea and will make working in a full OO way much easier. |
@pelson: Thanks for finding the way to avoid the large |
Yes@pelson! Good spot. I didn't think it was possible. I will obviously update to reflect this. Awesome! :D |
Now, one can work with the default backend to create figures, withoutthe need to attach a canvas manually. For example:import matplotlibmatplotlib.use('agg')from matplotlib.figure import Figurefig = Figure()ax = fig.add_subplot(1, 1, 1)ax.plot([1, 2, 3], [1, 2, 3])fig.savefig('oo.png')
I've rebased this against master to get theawesome changes from#1175. This will save me from conflicts with the changes I'm about to make. |
I wonder whether as part of this PR, it would make sense to also update the documentation to add clearer information about the pure-OO API? At the moment, it's very hard to find any information about it. Maybe there should be a top-level section under 'User guide' that talks about the pure-OO API and the pros and cons compared to using pyplot or th hybrid pyplot-OO? |
@astrofrog That's a great suggestion. Would any of the wider community appreciate a couple of example scripts that use the object-oriented interface? I'd be happy to write some. |
Ok, 3e4dea3 is a rather large commit.@pelson's suggestion of making each backend have a I'm still a newbie when it comes to the codebase, which is why I need you guys to tell me if I've put something in a sub-optimal place. You've been really helpful with all of my suggestions. So thank you. Please test it out. Specifically, I don't want this to break anything in |
@@ -330,6 +330,12 @@ def __init__(self, | |||
self.clf() | |||
self._cachedRenderer = None | |||
def _setup_canvas(self): | |||
# TODO: docstring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I will do it. I promise.
travisbot commentedSep 2, 2012
@@ -268,7 +268,6 @@ class TimerMac(_macosx.Timer, TimerBase): | |||
''' | |||
# completely implemented at the C-level (in _macosx.Timer) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Double new line was intentional here.
Looks good. I would be happy to merge this once there was a docstring on I know I'm always picky with newlines [and I hate myself for it ;-) ] but normally one would put a double new line between top level objects in a module (classes, functions, groups of constants etc.) and a single new line for the rest (in particular methods). I don't this doing this should block this PR though - I think this is a really helpful change. @astrofrog 's suggestion of adding a section on pure OO & its benefits is a good idea, but lets keep this implementation and PR separate - there is no need to hold up one with the other. |
figure.py now uses pylab_setup() to probe for the backend module to setup the figure canvas.
@pelson - agree, the docs can be worked on in a different PR. |
Should there be a way to optionally make it behave like before, i.e. to disable setting the canvas? e.g. something like EDIT: alternatively, a |
travisbot commentedSep 2, 2012
travisbot commentedSep 2, 2012
I'm not that worried by it. The easy answer is for users to simply do Unless anybody has any concerns, I will merge this in 18 hours. Good stuff@dmcdougall. |
@pelson - ok, I don't have a strong opinion about that, so we can just address it if people ask for it. I might open a PR if I run into issues with this some day. Looking forward to using this! :-) |
@astrofrog Thanks for the interest :) Glad I could help make someone's life easier. |
Ah. I'm sorry@dmcdougall - I was a bit eager. Would you mind adding an entry in the what's new section? |
@pelson And the changelog, too? |
My feeling is not. Your notbreaking anything, simply making one use case easier. We only need one entry: whichever you choose will be fine in this case. |
I also added a nice example exposing the new change, just because there's no example anywhere else. |
travisbot commentedSep 4, 2012
Reduce object-oriented boilerplate for users
Thanks to@dmcdougall for doing the work & to@astrofrog for suggesting it. This is a real nice addition. |
@@ -33,6 +33,7 @@ def _get_toolbar(self, canvas): | |||
toolbar = None | |||
return toolbar | |||
FigureCanvas = FigureManagerGTKAgg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Shouldn't this be FigureCanvasGTKAgg (and moved after the definition of FigureCanvasGTKAgg). At least this doesn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Oops. Yes. Good spot. I will open another PR to address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yes, GtkAgg backend currently does not work, which I believe is due to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Sorry! Fixed in#1201.
""" | ||
import matplotlib.backends as mbackends # lazy import | ||
backend_mod = mbackends.pylab_setup()[0] | ||
return backend_mod.FigureCanvas(self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
What if the module frompylab_setup()[0]
doesn't have a FigureCanvas class. Then the linereturn backend_mod.FigureCanvas(self)
would result in an error. So it does with IPython that uses his own backend module but without aFigureCanvas
class.
The olddef _current_figure_canvas(self)
works because in case it doesn't find the rightFigureCanvas
it returnsNone
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@verbit Line 508 oflib/matplotlib/backends/backend_tkagg
is
FigureCanvas=FigureCanvasTkAgg
so the return value ofpylab_setup[0]
does indeed have aFigureCanvas
for this backend. Do you see this behaviour withqt4agg
orgtk3agg
?
Perhaps this is actually a bug in thetkagg
backend?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I saw this behaviour with IPython's custom backend (see:backend_inline.py) that doesn't return aFigureCanvas
.
I'm just concerned about the fact, that this new_setup_canvas
function might break other applications that don't provide aFigureCanvas
class as they are used to the old way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Fixed in#1214.
The attempt to make OO use easier broke the Tkagg and Wx* backends.
Now, one can work with the default backend to create figures, without
the need to attach a canvas manually. For example:
This is an attempt at resolving issue#1094.
Disclaimer: I have no idea what implications this has on
pyplot
andpylab
, but 'it just works' for me, and I tried theMacOSX
,Agg
andPDF
backends.