An easier way to create figure and group of axes; useful?

John Hunter wrote:

I think the only two options should be scalar or 2-d array, it seems a
bit much to have a 1-d array option as well.

I disagree here -- if you are 2,1 or 1,2 rows x cols, 1D indexing is
natural. This is also the most common use case so the most important
to get right.

OK, but then how do you handle the fact that you might get a 0-d, 1-d or 2-d result? Eric's "squeeze" flag would result in that. Having squeeze1d and squeeze2d flags seems a bit much.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...236...

squeeze configured with a kwarg seems like a good compromise. As long
as the behavior is well documented it shouldn't pose any problems.
And we still have access to fig.axes in the same format is has always
been in.

JDH

···

On Thu, Mar 18, 2010 at 2:24 PM, Christopher Barker <Chris.Barker@...236...> wrote:

John Hunter wrote:

I think the only two options should be scalar or 2-d array, it seems a
bit much to have a 1-d array option as well.

I disagree here -- if you are 2,1 or 1,2 rows x cols, 1D indexing is
natural. This is also the most common use case so the most important
to get right.

OK, but then how do you handle the fact that you might get a 0-d, 1-d or
2-d result? Eric's "squeeze" flag would result in that. Having squeeze1d
and squeeze2d flags seems a bit much.

I agree with John that for nx1 or 1xn, 1-d indexing seems more
natural, and is the more pythonic solution given how numpy doesn't
distinguish between row and column arrays when they are 1-d, in
contrast to matlab. This is why I went for the approach above.

Based on the feedback, I'll finish it tonight with squeeze=True as a
kwarg, that behaves:

- if True (default): single axis is returned as a scalar, Nx1 or 1xN
are returned as numpy 1-d arrays, and only NxM with N>1 and M>1 are
returned as a 2d array.

- if False, no squeezing at all is done, the return value is always a
2-d array, even if it ends up being 1x1.

I think this gives a very convenient interactive/lightweight scripting
interface, while letting application builders who may need to write
generic code that is dimension agnostic have robust code that needs no
special-casing by passing squeeze=False.

Unless I hear otherwise, I'll make the commit with these changes
(updating the docstring and example script accordingly).

Cheers,

f

···

On Thu, Mar 18, 2010 at 11:47 AM, John Hunter <jdh2358@...149...> wrote:

I disagree here -- if you are 2,1 or 1,2 rows x cols, 1D indexing is
natural. This is also the most common use case so the most important
to get right. If you aren't doing multiple subplots, a plain ol
subplot(111) may be preferred to fig_subplots anyhow.

Fernando Perez wrote:

Based on the feedback, I'll finish it tonight with squeeze=True as a
kwarg, that behaves:

- if True (default): single axis is returned as a scalar, Nx1 or 1xN
are returned as numpy 1-d arrays, and only NxM with N>1 and M>1 are
returned as a 2d array.

- if False, no squeezing at all is done, the return value is always a
2-d array, even if it ends up being 1x1.

Good solution, and thanks for working on this!

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...236...

Thanks.

I have one more question on this feature. I personally think that
this should be the way to use mpl in general when scripting, and the
way I want to teach, because it's easy and short while encouraging
access to more robust patterns (figure/axes handing instead of the
stateful pyplot). For this reason, I think the name should be really
well chosen, and I'm not convinced fig_subplot is a very good one.

I know naming discussions can be annoying, but if this ends up being
the most popular/common entry point for making plots, it may be worth
spending a moment on picking it right. Ideas (I'm *awful* at naming)?

- plot_array?
- plots?
- subplots?
- parray?
- plotarr?

- something actually good from someone else?

I'll finish the patch tonight, we can always fix the name later as
it's a trivial search/replace on fig_subplots -> new_great_name.

Cheers,

f

···

On Thu, Mar 18, 2010 at 3:49 PM, Christopher Barker <Chris.Barker@...236...> wrote:

Good solution, and thanks for working on this!

I also think the name should be changed, and there should be an entry
in the matplotlib.figure.Figure API. One additional suggestion is
"subarray" and matplotlib.pyplot.subarray would be a thin wrapper to
matplotlib.figure.Figure.add_subarray. The former would return (fig,
axarray) using gcf() to get the current figure, and the latter would
simply create the subarray and return it. The would break a bit with
the pyplot "axes" and "subplot" commands that only return the Axes and
Subplot instances (and not the implicit Figure instance created/used)
but I can live with that because part of the goal here is to give easy
access to axes and figure creation so the user can get in the habit of
using the API directly for most things.

As for the other name suggestions, I like "subplots".

JDH

···

On Thu, Mar 18, 2010 at 7:46 PM, Fernando Perez <fperez.net@...149...> wrote:

On Thu, Mar 18, 2010 at 3:49 PM, Christopher Barker > <Chris.Barker@...236...> wrote:

Good solution, and thanks for working on this!

Thanks.

I have one more question on this feature. I personally think that
this should be the way to use mpl in general when scripting, and the
way I want to teach, because it's easy and short while encouraging
access to more robust patterns (figure/axes handing instead of the
stateful pyplot). For this reason, I think the name should be really
well chosen, and I'm not convinced fig_subplot is a very good one.

I know naming discussions can be annoying, but if this ends up being
the most popular/common entry point for making plots, it may be worth
spending a moment on picking it right. Ideas (I'm *awful* at naming)?

- plot_array?
- plots?
- subplots?
- parray?
- plotarr?

- something actually good from someone else?

I'll finish the patch tonight, we can always fix the name later as
it's a trivial search/replace on fig_subplots -> new_great_name.

Fernando Perez wrote:

I personally think that
this should be the way to use mpl in general when scripting, and the
way I want to teach,

+ Inf !

I've wanted to do this for years (make a easier way to do scripting the OO way), but I only get around to a tiny fraction of the things I want to do.

For this reason, I think the name should be really
well chosen, and I'm not convinced fig_subplot is a very good one.

I'll leave the name decisions to you folks, I just wanted to be encouraging!

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...236...

Without further feedback, I went with John's vote on 'subplots' and
have committed the changes to the API as agreed, now naming it
plt.subplots(). I'm sorry but I didn't implement the full
Figure.add_subarray() changes you suggested, ran out of time...

There is, however, a fly in the ointment: while this new code feels
very nice from playing wtih it in scripts like the example just
committed:

http://matplotlib.svn.sourceforge.net/viewvc/matplotlib/trunk/matplotlib/examples/pylab_examples/subplots_demo.py?revision=8202&view=markup

it is NOT pleasant to use interactively, because the OO api requires
explicit draw() calls all the time.

I just realized this now using it more, and it's a bummer, because
it makes it less likely that one will use this type of code in
everyday interactive exploration.

I wonder if it's possible to put things like a draw_if_interactive()
call at the end of the OO methods... I realize that pyplot was the
only one meant to do that, but if we are to encourage using the OO api
more, then it's going to have to be as pleasant to use as pyplot... I
don't know the codebase well enough to mess with this right now, so I
hope someone who's more versed in that part of the code can make a fix
for this whose impact isn't too severe on the runtime of OO code.

Cheers,

f

ps - Chris, thanks for the encouragement :slight_smile:

···

On Thu, Mar 18, 2010 at 6:39 PM, John Hunter <jdh2358@...149...> wrote:

I also think the name should be changed, and there should be an entry
in the matplotlib.figure.Figure API. One additional suggestion is
"subarray" and matplotlib.pyplot.subarray would be a thin wrapper to
matplotlib.figure.Figure.add_subarray. The former would return (fig,
axarray) using gcf() to get the current figure, and the latter would
simply create the subarray and return it. The would break a bit with
the pyplot "axes" and "subplot" commands that only return the Axes and
Subplot instances (and not the implicit Figure instance created/used)
but I can live with that because part of the goal here is to give easy
access to axes and figure creation so the user can get in the habit of
using the API directly for most things.

As for the other name suggestions, I like "subplots".

I'm not very inclined to this but I'll wait to hear what others think.
I use oo api in the interactive mode but I still prefer to call draw()
explicitly.
Of course, we can make it optional.

By the way, given that we now have "suplots" in the pyplot namespace,
can we have sca also?
For example,

# Two subplots, the axes array is 1-d
f, axarr = subplots(2, sharex=True)

sca(axarr[0])
plot(x, y)
title('Sharing X axis')

sca(axarr[1])
scatter(x, y)

Or, how about we make axes an context manager.

# Two subplots, the axes array is 1-d
f, axarr = subplots(2, sharex=True)

with axarr[0]:
   plot(x, y)
   title('Sharing X axis')

with axarr[1]:
   scatter(x, y)

This may not very useful in the interactive mode, but may make a
script (written in pylab mode) more readable.

Regards,

-JJ

···

On Sat, Mar 20, 2010 at 5:05 AM, Fernando Perez <fperez.net@...149...> wrote:

I wonder if it's possible to put things like a draw_if_interactive()
call at the end of the OO methods... I realize that pyplot was the
only one meant to do that, but if we are to encourage using the OO api
more, then it's going to have to be as pleasant to use as pyplot... I
don't know the codebase well enough to mess with this right now, so I
hope someone who's more versed in that part of the code can make a fix
for this whose impact isn't too severe on the runtime of OO code.

Jae-Joon Lee wrote:

By the way, given that we now have "suplots" in the pyplot namespace,
can we have sca also?

Done in svn 8205.

For example,

# Two subplots, the axes array is 1-d
f, axarr = subplots(2, sharex=True)

sca(axarr[0])
plot(x, y)
title('Sharing X axis')

sca(axarr[1])
scatter(x, y)

Or, how about we make axes an context manager.

This would require dropping support for Python 2.4.

Eric

···

# Two subplots, the axes array is 1-d
f, axarr = subplots(2, sharex=True)

with axarr[0]:
   plot(x, y)
   title('Sharing X axis')

with axarr[1]:
   scatter(x, y)

This may not very useful in the interactive mode, but may make a
script (written in pylab mode) more readable.

Regards,

-JJ

Done in svn 8205.

Thanks!

Or, how about we make axes an context manager.

This would require dropping support for Python 2.4.

I don't think making the Axes a context manager means dropping python
2.4 support
(note that I'm not saying we use "with" statement in the mpl source).
Everything should work fine in python 2.4 (please correct me if I'm wrong).
It just gives a user a choice. If a user runs his/her script with
python 2.5 and higher, he/she has an option to use an axes as an
context manager. Of course, if he/she want his/her own code supported
in python 2.4, he/she should not use "with" statement.

Regards,

-JJ

···

On Sat, Mar 20, 2010 at 8:40 PM, Eric Firing <efiring@...229...> wrote:

I see what you're saying. While the use of the language syntax is
restricted to 2.5 and above, we could add the needed methods to the
Axes object, which would just be ignored by python <2.5. That's not a
bad idea.

I'm +1 on the idea.

Ryan

···

On Sun, Mar 21, 2010 at 12:35 PM, Jae-Joon Lee <lee.j.joon@...149...> wrote:

On Sat, Mar 20, 2010 at 8:40 PM, Eric Firing <efiring@...229...> wrote:

Or, how about we make axes an context manager.

This would require dropping support for Python 2.4.

I don't think making the Axes a context manager means dropping python
2.4 support
(note that I'm not saying we use "with" statement in the mpl source).
Everything should work fine in python 2.4 (please correct me if I'm wrong).
It just gives a user a choice. If a user runs his/her script with
python 2.5 and higher, he/she has an option to use an axes as an
context manager. Of course, if he/she want his/her own code supported
in python 2.4, he/she should not use "with" statement.

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

Ryan May wrote:

Or, how about we make axes an context manager.

This would require dropping support for Python 2.4.

I don't think making the Axes a context manager means dropping python
2.4 support
(note that I'm not saying we use "with" statement in the mpl source).
Everything should work fine in python 2.4 (please correct me if I'm wrong).
It just gives a user a choice. If a user runs his/her script with
python 2.5 and higher, he/she has an option to use an axes as an
context manager. Of course, if he/she want his/her own code supported
in python 2.4, he/she should not use "with" statement.

I see what you're saying. While the use of the language syntax is
restricted to 2.5 and above, we could add the needed methods to the
Axes object, which would just be ignored by python <2.5. That's not a
bad idea.

I'm +1 on the idea.

Is the added complexity, scrambling pylab into the OO layer, and need for explanation, really worth the gain? As far as I can see, it merely adds one more way to do something--and not a particularly recommended way. It is no more concise than using sca(). It may be slightly more readable because of the indentation, but that is the only advantage I see.

Eric

···

On Sun, Mar 21, 2010 at 12:35 PM, Jae-Joon Lee <lee.j.joon@...149...> wrote:

On Sat, Mar 20, 2010 at 8:40 PM, Eric Firing <efiring@...229...> wrote:

Ryan

Is the added complexity, scrambling pylab into the OO layer, and need for
explanation, really worth the gain? As far as I can see, it merely adds one

more way to do something–and not a particularly recommended way. It is no
more concise than using sca(). It may be slightly more readable because of
the indentation, but that is the only advantage I see.

  • complexity

    I guess the code below is a “minimal” implementation (it worked okay with my limited tests).

context manager

def enter(self):
import matplotlib.pyplot as plt
plt.sca(self)
return self
def exit(self, type, value, tb):
pass

  • readability
  1. with “with” statement

fig, axarr = subplots(2,2)

for ax1, ax2 in axarr:
with ax1:
plot([1,2,3])

with ax2:
plot([2,3,4])

  1. with “sca”

fig, axarr = subplots(2,2)

for ax1, ax2 in axarr:
sca(ax1)
plot([1,2,3])

sca(ax2)
plot([2,3,4])

While I certainly prefer 1) over 2) as far as the readability is concerned, I currently don’t have a strong opinion whether the readability beats the complexity in this case.

So, unless there are more of positive feedbacks from others, I’ll consider it dropped.

Regards,

-JJ

···

On Sun, Mar 21, 2010 at 2:30 PM, Eric Firing <efiring@…229…> wrote:

Eric,

A minor question. I wonder whether an explicit for-loop inside pyplot.sca is necessary?

Here is a slight variation w/o a for-loop (well, the for-loop is implicitly done with the “in” operator I guess) that seems to work for me, but I may be missing something.

managers = _pylab_helpers.Gcf.get_all_fig_managers()

if ax.figure.canvas.manager in managers and \

ax in ax.figure.axes:

_pylab_helpers.Gcf.set_active(ax.figure.canvas.manager)

ax.figure.sca(ax)

return

raise ValueError(“Axes instance argument was not found in a figure.”)

Regards,

-JJ

···

On Sat, Mar 20, 2010 at 8:40 PM, Eric Firing <efiring@…552…229…> wrote:

By the way, given that we now have “suplots” in the pyplot namespace,

can we have sca also?

Done in svn 8205.

Jae-Joon Lee wrote:

        By the way, given that we now have "suplots" in the pyplot
        namespace,
        can we have sca also?

    Done in svn 8205.

Eric,

A minor question. I wonder whether an explicit for-loop inside pyplot.sca is necessary?
Here is a slight variation w/o a for-loop (well, the for-loop is implicitly done with the "in" operator I guess) that seems to work for me, but I may be missing something.

    managers = _pylab_helpers.Gcf.get_all_fig_managers()
    if ax.figure.canvas.manager in managers and \
           ax in ax.figure.axes:
        _pylab_helpers.Gcf.set_active(ax.figure.canvas.manager)
        ax.figure.sca(ax)
        return
    raise ValueError("Axes instance argument was not found in a figure.")

Regards,

-JJ

JJ,

I think your version would need an additional try/except or conditional, because a Figure doesn't necessarily have a canvas assigned to it, and a canvas doesn't necessarily have a manager. Granted, the problem would arise only under odd circumstances involving a mixture of pyplot and OO styles--and maybe there is actually something that would prevent the problem from arising at all--but I would want to be sure the problem either was handled, or could not arise. So, I think my version ends up being simpler, safer, and easier to understand--at least for me.

Eric

···

On Sat, Mar 20, 2010 at 8:40 PM, Eric Firing <efiring@…229… > <mailto:efiring@…229…>> wrote:

I see. Thanks!

-JJ

···

On Sun, Mar 21, 2010 at 6:07 PM, Eric Firing <efiring@…552…229…> wrote:

I think your version would need an additional try/except or conditional, because a Figure doesn’t necessarily have a canvas assigned to it, and a canvas doesn’t necessarily have a manager. Granted, the problem would arise only under odd circumstances involving a mixture of pyplot and OO styles–and maybe there is actually something that would prevent the problem from arising at all–but I would want to be sure the problem either was handled, or could not arise. So, I think my version ends up being simpler, safer, and easier to understand–at least for me.

Mmh, back to this one: I do think it would be something useful to have
somewhere, because typing draw() after *every* operation when working
interactively does get tiresome, it seems to me... If we encourage
calling subplots() for new teaching, then we do want it to be as
pleasant as pyplot to use interactively, I think...

Is it technically expensive to put in?

Cheers,

f

···

On Sat, Mar 20, 2010 at 4:00 PM, Jae-Joon Lee <lee.j.joon@...149...> wrote:

On Sat, Mar 20, 2010 at 5:05 AM, Fernando Perez <fperez.net@...149...> wrote:

I wonder if it's possible to put things like a draw_if_interactive()
call at the end of the OO methods... I realize that pyplot was the
only one meant to do that, but if we are to encourage using the OO api
more, then it's going to have to be as pleasant to use as pyplot... I
don't know the codebase well enough to mess with this right now, so I
hope someone who's more versed in that part of the code can make a fix
for this whose impact isn't too severe on the runtime of OO code.

I'm not very inclined to this but I'll wait to hear what others think.
I use oo api in the interactive mode but I still prefer to call draw()
explicitly.
Of course, we can make it optional.

I think the first issue that needs to be addressed is whether we want
to encourage OO api in the interactive mode (I mean, when a user
expect the figure gets updated as soon as a command is executed).

Using *subplots* does not necessarily mean that we need to use OO api,
since we now have *sca* in the pyplot namespace.

So. how other developers think?
Are we going to encourage OO api in the interactive mode?

Regards,

-JJ

···

On Sun, Mar 21, 2010 at 8:10 PM, Fernando Perez <fperez.net@...149...> wrote:

Mmh, back to this one: I do think it would be something useful to have
somewhere, because typing draw() after *every* operation when working
interactively does get tiresome, it seems to me... If we encourage
calling subplots() for new teaching, then we do want it to be as
pleasant as pyplot to use interactively, I think...

Fernando Perez skrev 2010-03-22 01:10:

···

On Sat, Mar 20, 2010 at 4:00 PM, Jae-Joon Lee<lee.j.joon@...149...> wrote:

On Sat, Mar 20, 2010 at 5:05 AM, Fernando Perez<fperez.net@...149...> wrote:

I wonder if it's possible to put things like a draw_if_interactive()
call at the end of the OO methods... I realize that pyplot was the
only one meant to do that, but if we are to encourage using the OO api
more, then it's going to have to be as pleasant to use as pyplot... I
don't know the codebase well enough to mess with this right now, so I
hope someone who's more versed in that part of the code can make a fix
for this whose impact isn't too severe on the runtime of OO code.

I'm not very inclined to this but I'll wait to hear what others think.
I use oo api in the interactive mode but I still prefer to call draw()
explicitly.
Of course, we can make it optional.

Mmh, back to this one: I do think it would be something useful to have
somewhere, because typing draw() after *every* operation when working
interactively does get tiresome, it seems to me... If we encourage
calling subplots() for new teaching, then we do want it to be as
pleasant as pyplot to use interactively, I think...

Would it be possible to put the draw in the ipython_prompt hook. That way it is always called after you have done something.

/Jörgen