|
From: Trevis C. <t_...@mr...> - 2007-06-11 13:39:42
|
Coming from MATLAB, I started using matplotlib in the same fashion (and was very appreciative of the similariry). That is, I would import pylab and call the plotting functions as necessary. However, after seeing some of how others are using matplotlib, it seems most people use axes object methods to take care of plotting needs. I'm now taking this approach as well, but I honestly don't know why I should (or if I should). Will someone explain to me why one approach is better or worse? =20 thanks, trevis =20 ________________________________________________ =20 Trevis Crane Postdoctoral Research Assoc. Department of Physics University of Ilinois 1110 W. Green St. Urbana, IL 61801 =20 p: 217-244-8652 f: 217-244-2278 e: tc...@ui... ________________________________________________ =20 |
|
From: John H. <jd...@gm...> - 2007-06-11 14:08:06
|
On 6/11/07, Trevis Crane <t_...@mr...> wrote: > Coming from MATLAB, I started using matplotlib in the same fashion (and was > very appreciative of the similariry). That is, I would import pylab and > call the plotting functions as necessary. However, after seeing some of how > others are using matplotlib, it seems most people use axes object methods to > take care of plotting needs. I'm now taking this approach as well, but I > honestly don't know why I should (or if I should). Will someone explain to > me why one approach is better or worse? matplotlib supports both because in different contexts one is often superior to the other. The main difference is that the pylab interface is stateful and handles object instantiation when necessary. For example, when you do "plot", it checks to see if there is a current axes and if so plots into it, and if not creates a new axes. When the new axes function is called, it checks to see if there is a current figure and inserts into it if available, and if not creates one. So it is "stateful" because under the hood it is tracking the current axes, figure and some other stuff. When working interactively from the shell or in short scripts, this is a nice feature because it saves typing and syntactic overhead. When working in the shell, eg in ipython -pyab mode, this is usually the way I work. In other contexts the convenience that these functions imply become a liability, because you often want to have explicit control, eg "put this axes in this figure and put this plot into this axes...". In a web application server or a user interface application, this is definitely the way to work. In scripts of moderate complexity it is advisable. The basic idea is that "explicit is better than implicit". Working this way is a little harder at first, but by forcing yourself to understand who is doing what where, you ultimately write better, more stable, more maintainable code. One thing most serious python programmers agree on is that from something import * is bad practice because you usually don't know what names are coming from where, and it creates the possibility of latent bugs. Eg, pylab used to have a "set" command which emulates the matlab command of the same name. It is used to set handle graphics properties. This worked fine, until python introduced the "set" builtin, which works like the mathematical set. Then it became impossible do "from pylab import *" and use the new python builtin "set", so we cleaned up all the old code and renamed the function. The programmer who do import pylab pylab.set was protected from these often subtle and difficult to detect bugs. The import * idiom also makes it tricky to combine code from two scripts or modules into one, because both may be importing different namespaces with overlapping names. I have found, however, when talking to science teachers who are trying to introduce python/numpy/pylab/scipy into the classroom as a matlab replacement that the 'from pylab import *' idiom is important to them, because their students want something that "just works" and is about as easy as matlab. Even though it is probably preferable in the abstract to teach students good practices from the beginning, it might raise the barrier to entry sufficiently that they simply use matlab instead. These teachers are already facing a fair amount of resistance in trying to get python introduced at all, and we should make it as easy on them as possible. So I am not a zealot on this issue. The other reason it is good practice to use the explicit API calls is that code which starts out its life as a small script often has a way of growing into a large script, and then you begin sharing it with your colleagues and maybe writing a web interface or a GUI application built on it. Code written using the API can safely be dropped into larger applications, whereas code written in pylab probably cannot (imagine lots of different functions competing for the current figure w/o knowledge of one another). So the answer of which is better is a question of skill level and context, but my simple advice is to use the pylab syntax from the interactive python shell (and "ipython -pylab" is ideal for this) and the API everywhere else. Most of my scripts are variants of this: import numpy as npy from pylab import figure, close, show fig = figure() ax = fig.add_subplot(111) x = npy.arange(0,10.) ax.plot(x) show() JDH |
|
From: Roman B. <be...@sm...> - 2007-06-11 15:40:21
|
* John Hunter <jd...@gm...> [070611 16:20]:
> So the answer of which is better is a question of skill level and
> context, but my simple advice is to use the pylab syntax from the
> interactive python shell (and "ipython -pylab" is ideal for this) and
> the API everywhere else. Most of my scripts are variants of this:
>
> import numpy as npy
> from pylab import figure, close, show
> fig = figure()
> ax = fig.add_subplot(111)
> x = npy.arange(0,10.)
> ax.plot(x)
> show()
Hello,
is there also a (possible object oriented) way to show/print a given
figure? Like fig.show() or fig.print_figure(). I need it because I have
a script generating (returning) several plots, and the user should be
able to print/show the plots he likes. At the moment I use:
ipython -pylab
from myscript import plotgenerator
fig = plotgenerator()
canvas = get_current_fig_manager().canvas
canvas.figure = fig
canvas.print_figure('myplot.png')
Here plotgenerator does something like:
from matplotlib.figure import Figure
fig = Figure()
ax = myplot.add_subplot(111)
ax.plot(x)
But its cumbersome, and canvas.show() doesn not work (it gives an
exception). Best would be if fig.show() (popping up a new canvas) and
fig.print_figure() worked.
Best Regards, Roman
|
|
From: Roman B. <be...@sm...> - 2007-06-21 19:35:07
|
Hello,
thank you very much for you answer. The oddness clears if you consider
that the generating of the figure might be done in an external library.
Imagine a data analyze package with functions with can also generate one
or more plots. As a library I think here the OO interface is most
appropriate. A user of such a library might want to plot figure objects
returned by the library function at her discretion. And of course the
user in her interactive session uses an pylab session in ipython.
In your example the figure object was already generated from within the
ipython session using fig=figure(1). But this already pops up a canvas
which is not appropriate for a library. In my example I generated the
plot strictly OO with "fig = matplotlib.figure.Figure()". And as I wrote
below, this object cannot be plotted or saved easily, because its not
connected to a canvas, a canvas the library generating the figure knows
nothing about, because it knows nothing about the environment of the
user. In order to save the figure, you have to do the involved:
> >canvas = get_current_fig_manager().canvas
> >canvas.figure = fig
> >canvas.print_figure('myplot.png')
and canvas.show() does not work at all. Much better would methods like:
fig.print_figure() and fig.show(), but this does not work.
Best Regards, Roman
* Ryan Krauss <rya...@gm...> [070621 20:40]:
> [...]
> But to answer your question, I think using the OO interface from an
> ipython session is slightly odd in that your are kind of operating in
> two different paradigms. I had no problem showing and saving a figure
> doing the following (from an "ipython -pylab -p scipy" prompt):
>
> fig=figure(1)
> t=arange(0,1,0.01)
> y=sin(2*pi*t)
> ax=fig.add_subplot(111)
> ax.plot(t,y)
> show()
> ax.set_ylabel('$y(t)$')
> ax.set_xlabel('Time (sec)')
> show()
> savefig('test.png')
>
> FWIW,
>
> Ryan
>
> On 6/13/07, Roman Bertle <be...@sm...> wrote:
> >Hello,
> >
> >why don't you reply on the mailing list? Nevermind, the problem is not
> >that I don't know the OO API or that I don't know python well. The
> >problem is that there is missing something in the OO API. If you
> >generate a figure as I have done below:
> >
> >fig = matplotlib.figure.Figure()
> >ax = fig.add_subplot(111)
> >ax.plot(x)
> >
> >Then its not so easy to actually save or display the figure in a ipython
> >-pylab session. fig has a method savefig(), but it fails because it
> >cannot find a canvas. The only way is to generate a canvas and assign
> >fig to it:
> >
> >canvas = get_current_fig_manager().canvas
> >canvas.figure = fig
> >canvas.print_figure('myplot.png')
> >
> >and you cannot do canvas.draw() or canvas.show(), it raises an
> >Exception. Much better would be a working fig.print_figure() and
> >fig.show(), creating a canvas on the fly, and maybe using an optional
> >keyword argument to providing a canvas object.
> >
> >Regards, Roman
> >
> >
> >* Ryan Krauss <rya...@gm...> [070612 08:17]:
> >> Just my $0.02 as a personal testimony about the truth of what John is
> >> saying. I started out using from pylab import * or from pylab import
> >> figure, cla, clf, plot, semilogx, ... in all my code and didn't bother
> >> learning the OO API. This worked great for the first year or two.
> >> Then I wanted to use some of my data processing libraries with a
> >> wxPython gui and they all started out importing Pylab. This created
> >> quite a bit of pain for me. I was rightly advised to make sure I
> >> never used Pylab in a utility module I might some day want to use with
> >> any gui program and had to significantly edit all my module files.
> >>
> >> So, if you are serious about learning Python, then I think it is worth
> >> a little pain now to save yourself a lot of pain later and learn to
> >> use the OO API whenever you aren't just doing something interactively
> >> at the IPython prompt.
> >>
> >> I have found that
> >> fig = Figure()
> >> ax = fig.add_subplot(111) #(or 212 or whatever)
> >> and then using IPython's tab completion with fig.<tab> and ax.<tab> is
> >> usually sufficient to learn the API commands corresponding to the
> >> pylab commands I used for so long. Don't forget to take advantage of
> >> this beautiful IPython feature to find commands:
> >> In [4]: ax.*xlabel*?
> >> ax.set_xlabel
> >>
> >> (finding the correct API commands to replace pylab.xlabel and
> >> pylab.ylabel tripped my up for a little bit).
> >>
> >>
> >> But, I am also a teacher making my students use Python and I will
> >> mention none of this to them and just encourage them to use from pylab
> >> import * to keep the entry barrier as low as possible.
> >>
> >> FWIW,
> >>
> >> Ryan
> >>
> >> On 6/11/07, Roman Bertle <be...@sm...> wrote:
> >> >* John Hunter <jd...@gm...> [070611 16:20]:
> >> >> So the answer of which is better is a question of skill level and
> >> >> context, but my simple advice is to use the pylab syntax from the
> >> >> interactive python shell (and "ipython -pylab" is ideal for this) and
> >> >> the API everywhere else. Most of my scripts are variants of this:
> >> >>
> >> >> import numpy as npy
> >> >> from pylab import figure, close, show
> >> >> fig = figure()
> >> >> ax = fig.add_subplot(111)
> >> >> x = npy.arange(0,10.)
> >> >> ax.plot(x)
> >> >> show()
> >> >
> >> >Hello,
> >> >
> >> >is there also a (possible object oriented) way to show/print a given
> >> >figure? Like fig.show() or fig.print_figure(). I need it because I have
> >> >a script generating (returning) several plots, and the user should be
> >> >able to print/show the plots he likes. At the moment I use:
> >> >
> >> >ipython -pylab
> >> > from myscript import plotgenerator
> >> > fig = plotgenerator()
> >> > canvas = get_current_fig_manager().canvas
> >> > canvas.figure = fig
> >> > canvas.print_figure('myplot.png')
> >> >
> >> >Here plotgenerator does something like:
> >> > from matplotlib.figure import Figure
> >> > fig = Figure()
> >> > ax = myplot.add_subplot(111)
> >> > ax.plot(x)
> >> >
> >> >But its cumbersome, and canvas.show() doesn not work (it gives an
> >> >exception). Best would be if fig.show() (popping up a new canvas) and
> >> >fig.print_figure() worked.
> >> >
> >> >Best Regards, Roman
|
|
From: Ryan K. <rya...@gm...> - 2007-06-21 23:15:58
|
I don't think we are actually disagreeing with one another. I have
written the kind of library you are talking about and used the same
library from ipython and in a wxpython app. All of my plotting
functions expect a fig instance as an input. When calling the library
from ipython, I pass in a fig=pylab.figure(), when using the data
analysis library with wxpython, my fig comes from the get_figure
method of a wxmpl PlotPanel instance. wxmpl handles all canvas issues
for me.
So, in my libraries, I have inputs that are fig instances. Creating a
fig with pylab.figure() is how I use my library from ipython.
I actually have this code in one of my data analysis library functions
def plotting_function(x, y, other inputs, fig=None):
if fig is None:
from pylab import figure
fig = figure(fignum)
and the code works beautifully as a library and plays well with
ipython and wxpython.
Ryan
On 6/21/07, Roman Bertle <be...@sm...> wrote:
> Hello,
>
> thank you very much for you answer. The oddness clears if you consider
> that the generating of the figure might be done in an external library.
> Imagine a data analyze package with functions with can also generate one
> or more plots. As a library I think here the OO interface is most
> appropriate. A user of such a library might want to plot figure objects
> returned by the library function at her discretion. And of course the
> user in her interactive session uses an pylab session in ipython.
>
> In your example the figure object was already generated from within the
> ipython session using fig=figure(1). But this already pops up a canvas
> which is not appropriate for a library. In my example I generated the
> plot strictly OO with "fig = matplotlib.figure.Figure()". And as I wrote
> below, this object cannot be plotted or saved easily, because its not
> connected to a canvas, a canvas the library generating the figure knows
> nothing about, because it knows nothing about the environment of the
> user. In order to save the figure, you have to do the involved:
> > >canvas = get_current_fig_manager().canvas
> > >canvas.figure = fig
> > >canvas.print_figure('myplot.png')
> and canvas.show() does not work at all. Much better would methods like:
> fig.print_figure() and fig.show(), but this does not work.
>
> Best Regards, Roman
>
> * Ryan Krauss <rya...@gm...> [070621 20:40]:
> > [...]
> > But to answer your question, I think using the OO interface from an
> > ipython session is slightly odd in that your are kind of operating in
> > two different paradigms. I had no problem showing and saving a figure
> > doing the following (from an "ipython -pylab -p scipy" prompt):
> >
> > fig=figure(1)
> > t=arange(0,1,0.01)
> > y=sin(2*pi*t)
> > ax=fig.add_subplot(111)
> > ax.plot(t,y)
> > show()
> > ax.set_ylabel('$y(t)$')
> > ax.set_xlabel('Time (sec)')
> > show()
> > savefig('test.png')
> >
> > FWIW,
> >
> > Ryan
> >
> > On 6/13/07, Roman Bertle <be...@sm...> wrote:
> > >Hello,
> > >
> > >why don't you reply on the mailing list? Nevermind, the problem is not
> > >that I don't know the OO API or that I don't know python well. The
> > >problem is that there is missing something in the OO API. If you
> > >generate a figure as I have done below:
> > >
> > >fig = matplotlib.figure.Figure()
> > >ax = fig.add_subplot(111)
> > >ax.plot(x)
> > >
> > >Then its not so easy to actually save or display the figure in a ipython
> > >-pylab session. fig has a method savefig(), but it fails because it
> > >cannot find a canvas. The only way is to generate a canvas and assign
> > >fig to it:
> > >
> > >canvas = get_current_fig_manager().canvas
> > >canvas.figure = fig
> > >canvas.print_figure('myplot.png')
> > >
> > >and you cannot do canvas.draw() or canvas.show(), it raises an
> > >Exception. Much better would be a working fig.print_figure() and
> > >fig.show(), creating a canvas on the fly, and maybe using an optional
> > >keyword argument to providing a canvas object.
> > >
> > >Regards, Roman
> > >
> > >
> > >* Ryan Krauss <rya...@gm...> [070612 08:17]:
> > >> Just my $0.02 as a personal testimony about the truth of what John is
> > >> saying. I started out using from pylab import * or from pylab import
> > >> figure, cla, clf, plot, semilogx, ... in all my code and didn't bother
> > >> learning the OO API. This worked great for the first year or two.
> > >> Then I wanted to use some of my data processing libraries with a
> > >> wxPython gui and they all started out importing Pylab. This created
> > >> quite a bit of pain for me. I was rightly advised to make sure I
> > >> never used Pylab in a utility module I might some day want to use with
> > >> any gui program and had to significantly edit all my module files.
> > >>
> > >> So, if you are serious about learning Python, then I think it is worth
> > >> a little pain now to save yourself a lot of pain later and learn to
> > >> use the OO API whenever you aren't just doing something interactively
> > >> at the IPython prompt.
> > >>
> > >> I have found that
> > >> fig = Figure()
> > >> ax = fig.add_subplot(111) #(or 212 or whatever)
> > >> and then using IPython's tab completion with fig.<tab> and ax.<tab> is
> > >> usually sufficient to learn the API commands corresponding to the
> > >> pylab commands I used for so long. Don't forget to take advantage of
> > >> this beautiful IPython feature to find commands:
> > >> In [4]: ax.*xlabel*?
> > >> ax.set_xlabel
> > >>
> > >> (finding the correct API commands to replace pylab.xlabel and
> > >> pylab.ylabel tripped my up for a little bit).
> > >>
> > >>
> > >> But, I am also a teacher making my students use Python and I will
> > >> mention none of this to them and just encourage them to use from pylab
> > >> import * to keep the entry barrier as low as possible.
> > >>
> > >> FWIW,
> > >>
> > >> Ryan
> > >>
> > >> On 6/11/07, Roman Bertle <be...@sm...> wrote:
> > >> >* John Hunter <jd...@gm...> [070611 16:20]:
> > >> >> So the answer of which is better is a question of skill level and
> > >> >> context, but my simple advice is to use the pylab syntax from the
> > >> >> interactive python shell (and "ipython -pylab" is ideal for this) and
> > >> >> the API everywhere else. Most of my scripts are variants of this:
> > >> >>
> > >> >> import numpy as npy
> > >> >> from pylab import figure, close, show
> > >> >> fig = figure()
> > >> >> ax = fig.add_subplot(111)
> > >> >> x = npy.arange(0,10.)
> > >> >> ax.plot(x)
> > >> >> show()
> > >> >
> > >> >Hello,
> > >> >
> > >> >is there also a (possible object oriented) way to show/print a given
> > >> >figure? Like fig.show() or fig.print_figure(). I need it because I have
> > >> >a script generating (returning) several plots, and the user should be
> > >> >able to print/show the plots he likes. At the moment I use:
> > >> >
> > >> >ipython -pylab
> > >> > from myscript import plotgenerator
> > >> > fig = plotgenerator()
> > >> > canvas = get_current_fig_manager().canvas
> > >> > canvas.figure = fig
> > >> > canvas.print_figure('myplot.png')
> > >> >
> > >> >Here plotgenerator does something like:
> > >> > from matplotlib.figure import Figure
> > >> > fig = Figure()
> > >> > ax = myplot.add_subplot(111)
> > >> > ax.plot(x)
> > >> >
> > >> >But its cumbersome, and canvas.show() doesn not work (it gives an
> > >> >exception). Best would be if fig.show() (popping up a new canvas) and
> > >> >fig.print_figure() worked.
> > >> >
> > >> >Best Regards, Roman
>
> -------------------------------------------------------------------------
> This SF.net email is sponsored by DB2 Express
> Download DB2 Express C - the FREE version of DB2 express and take
> control of your XML. No limits. Just data. Click to get it now.
> http://sourceforge.net/powerbar/db2/
> _______________________________________________
> Matplotlib-users mailing list
> Mat...@li...
> https://lists.sourceforge.net/lists/listinfo/matplotlib-users
>
|
|
From: Roman B. <be...@sm...> - 2007-06-22 08:57:29
|
* Ryan Krauss <rya...@gm...> [070622 09:47]: > I don't think we are actually disagreeing with one another. I have > written the kind of library you are talking about and used the same > library from ipython and in a wxpython app. All of my plotting > functions expect a fig instance as an input. When calling the library > from ipython, I pass in a fig=pylab.figure(), when using the data > analysis library with wxpython, my fig comes from the get_figure > method of a wxmpl PlotPanel instance. wxmpl handles all canvas issues > for me. > > So, in my libraries, I have inputs that are fig instances. Creating a > fig with pylab.figure() is how I use my library from ipython. > > I actually have this code in one of my data analysis library functions > > def plotting_function(x, y, other inputs, fig=None): > if fig is None: > from pylab import figure > fig = figure(fignum) > > and the code works beautifully as a library and plays well with > ipython and wxpython. Hello, very nice! The only remaining problem is that an analysis library functions might return several figures. In my case the data depends on several parameters, and the function returns a dictionary containing for each parameter set statistics, histograms and plots. The user should be able to decide for which parameter he wants to pop up a plot, or save it to a file, but for your approach all these windows pop up automatically, and not only when the user does a fig.show() for the figure he is interested in. Unfortunately the latter does not work if the figure is an matplotlib.figure.Figure() instance, as in my approach. Best Regards, Roman |
|
From: John H. <jd...@gm...> - 2007-06-22 12:22:08
|
On 6/22/07, Roman Bertle <be...@sm...> wrote:
> very nice! The only remaining problem is that an analysis library
> functions might return several figures. In my case the data depends on
> several parameters, and the function returns a dictionary containing for each
> parameter set statistics, histograms and plots. The user should be able
> to decide for which parameter he wants to pop up a plot, or save it to a
> file, but for your approach all these windows pop up automatically, and
> not only when the user does a fig.show() for the figure he is interested
> in. Unfortunately the latter does not work if the figure is an
> matplotlib.figure.Figure() instance, as in my approach.
I agree with everything you say, only it is difficult to encapsulate
and get the details right for raising and hiding GUI windows across
backends, handling the mainloop etc. Not at all impossible, but it
takes a concerted effort across 5 user interfaces. Note I did
recently (in svn) add a fig.show() method, which will show new figures
created in an event loop after the global show starts the GUI
mainloop.
I do something similar to Ryan, but slightly more general to handle
the case you mention -- the need to possibly create multiple figures.
I define a figure generating function in my GUI code, and pass either
that function, or pylab.figure -- not pylab.figure() -- into my
functions that need to create figures. Client code can then call that
function as often as they wish to create multiple figure windows.
I've included below a class which is callable that is used to generate
GTK figures that I sometimes use in my gtk apps. That way functions I
use in my apps can also be called from pylab by passing in
pylab.figure
But as above, I would be very happy to have a finer degree of control
in pylab. If you would like to take a stab at a patch to your backend
of choice to support better control of figure raising and hiding from
the pylab interface, give it a whirl. It would make it easier for
other backend maintainers to follow your lead and port the code into
the various backends.
class GTKFigure:
def __init__(self, title):
self.title = title
def __call__(self):
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtkagg import
FigureCanvasGTKAgg as FigureCanvas
from matplotlib.backends.backend_gtkagg import
NavigationToolbar2GTKAgg as NavigationToolbar
win = gtk.Window()
win.set_default_size(800,600)
win.set_title(self.title)
vbox = gtk.VBox()
win.add(vbox)
fig = Figure(figsize=(5,4), dpi=80)
canvas = FigureCanvas(fig) # a gtk.DrawingArea
vbox.pack_start(canvas)
toolbar = NavigationToolbar(canvas, win)
vbox.pack_start(toolbar, False, False)
win.show_all()
return fig
|