Change to aspect ratio handling

All, Motivated in part by an old patch (1233294) submitted

    > to sourceforge by Nikolai Hlubek, I took a look at how
    > aspect ratio is handled in mpl, and concluded it wasn't
    > quite right:

Just a few quick comments since I haven't had a chance to look over
this in any detail.

    > 1) The aspect='preserve' kwarg in image caused the image to
    > retain its aspect ratio only with some resize events, not
    > with all. The implementation in the image.py code does not
    > look right to me.

    > Therefore I have reworked the aspect-handling code in
    > axes.py, and I think it is working reasonably well. Indeed,
    > I don't see any remaining need for an "aspect" kwarg in
    > image.py, and I would like to take it out unless someone
    > raises an objection.

The aspect handling of images has been known to be broken from the
early days, but in those days we didn't even have aspect='equal'
functionality, and so adding preserved aspect ratio proved to
daunting. Noone has revisited the issue (until now) since Mark Bakkar
finally (mostly) got proper aspect handling in the axes. So your
observations are on target, and the image aspect handling is an
anachronism that everyone quickly learned to ignore.

    > def set_aspect(self, aspect='auto', fixLimits=None,
    > aspect_adjusts='position'): """ aspect: 'auto' - automatic;
    > fill position rectangle with data 'normal' - same as 'auto';
    > deprecated 'equal' - same scaling from data to plot units
    > for x and y A - a circle will be stretched such that the
    > height is A times the width. aspect=1 is the same as
    > aspect='equal'.

Mark Bakkar wrote most of the aspect handling for the axes, and so he
can response most intelligently to these changes. You should send him
your original post since he may not be on this list. He's CCd above.

    > One question: is there an easy way to automatically trigger
    > a redraw in an interactive backend (e.g. ipython with
    > gtkagg) at the end of the set_aspect() method, for example?
    > The way it works now is that one can make a plot, call the
    > set_aspect() method on the resulting axes object, and the
    > result will appear as soon as the window is manipulated with
    > the mouse; but this manipulation is needed to trigger a
    > redraw.

You should be able to do something like

  if rcParams['interactive']:
     self.figure.canvas.draw()

where self is an Axes instance. Untested, but I think it is valid
across backends.

Thanks for the submission -- I look forward to testing it.

JDH

John, Mark, Fernando, Nikolai,

I decided to go ahead with the next stage: I committed a few more changes so that I think imshow will now work the way people would like. To see the basic behavior most quickly, fire up ipython and do

In [1]:z = rand(20,40)

In [2]:imshow(z, aspect='auto')
Out[2]:<matplotlib.image.AxesImage instance at 0xb5be81ec>

In [3]:imshow(z)
Out[3]:<matplotlib.image.AxesImage instance at 0xb5c02c0c>

In the first case, as you resize the window with the mouse, the aspect ratio will change with the window. In the second case, the aspect ratio will be 1:1 regardless of what you do, including zooming. I made the second case the default because it seems to me that an image normally is meant to be viewed with a 1:1 aspect ratio--with square pixels. (I am assuming the display pixels are square, or close enough to it.)

(You could also do imshow(z, aspect=23.7), for example; you can specify any stretch factor you want.)

I left matshow with the 'auto' behavior, which is the default for ordinary axes, and which was its original behavior. If you would prefer 'equal' (1:1), or following the rc['image.aspect'], I would be happy to make that change.

Testing and comments are invited.

Thanks.

Eric

John Hunter wrote:

···

"Eric" == Eric Firing <efiring@...229...> writes:

    > All, Motivated in part by an old patch (1233294) submitted
    > to sourceforge by Nikolai Hlubek, I took a look at how
    > aspect ratio is handled in mpl, and concluded it wasn't
    > quite right:

Just a few quick comments since I haven't had a chance to look over
this in any detail.

    > 1) The aspect='preserve' kwarg in image caused the image to
    > retain its aspect ratio only with some resize events, not
    > with all. The implementation in the image.py code does not
    > look right to me.

    > Therefore I have reworked the aspect-handling code in
    > axes.py, and I think it is working reasonably well. Indeed,
    > I don't see any remaining need for an "aspect" kwarg in
    > image.py, and I would like to take it out unless someone
    > raises an objection.

The aspect handling of images has been known to be broken from the
early days, but in those days we didn't even have aspect='equal'
functionality, and so adding preserved aspect ratio proved to
daunting. Noone has revisited the issue (until now) since Mark Bakkar
finally (mostly) got proper aspect handling in the axes. So your
observations are on target, and the image aspect handling is an
anachronism that everyone quickly learned to ignore.

    > def set_aspect(self, aspect='auto', fixLimits=None,
    > aspect_adjusts='position'): """ aspect: 'auto' - automatic;
    > fill position rectangle with data 'normal' - same as 'auto';
    > deprecated 'equal' - same scaling from data to plot units
    > for x and y A - a circle will be stretched such that the
    > height is A times the width. aspect=1 is the same as
    > aspect='equal'.

Mark Bakkar wrote most of the aspect handling for the axes, and so he
can response most intelligently to these changes. You should send him
your original post since he may not be on this list. He's CCd above.

    > One question: is there an easy way to automatically trigger
    > a redraw in an interactive backend (e.g. ipython with
    > gtkagg) at the end of the set_aspect() method, for example?
    > The way it works now is that one can make a plot, call the
    > set_aspect() method on the resulting axes object, and the
    > result will appear as soon as the window is manipulated with
    > the mouse; but this manipulation is needed to trigger a
    > redraw.

You should be able to do something like

  if rcParams['interactive']:
     self.figure.canvas.draw()

where self is an Axes instance. Untested, but I think it is valid
across backends.

Thanks for the submission -- I look forward to testing it.

JDH

-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
matplotlib-devel List Signup and Options

Eric -

Good to see you are taking aspect ratio handling to the next level.
Your proposed changes sound good.

Regarding the ‘fixLimits’, this was implemented as the aspect ratio handling was
different when the axes limits were fixed or not. Having them fixed is exceedingly useful,
and used by quite a few people, as far as I know. But I understand this will still be possible.

The code never worked when the window was resized interactively. Am I understaning you
correctly that the new code does this correctly? Across backends? That would be very nice.

The set_aspect function is called from axis() in pylab.py and I think somewhere in backend_basics after a zoom event.

Let me know when you uploaded stuff that is ready for testing and I’ll give it a try,

Mark

···

On 3/20/06, Eric Firing <efiring@…229…> wrote:

John, Mark, Fernando, Nikolai,

I decided to go ahead with the next stage: I committed a few more
changes so that I think imshow will now work the way people would like.
To see the basic behavior most quickly, fire up ipython and do

In [1]:z = rand(20,40)

In [2]:imshow(z, aspect=‘auto’)
Out[2]:<matplotlib.image.AxesImage instance at 0xb5be81ec>

In [3]:imshow(z)
Out[3]:<matplotlib.image.AxesImage instance at 0xb5c02c0c>

In the first case, as you resize the window with the mouse, the aspect
ratio will change with the window. In the second case, the aspect ratio
will be 1:1 regardless of what you do, including zooming. I made the

second case the default because it seems to me that an image normally is
meant to be viewed with a 1:1 aspect ratio–with square pixels. (I am
assuming the display pixels are square, or close enough to it.)

(You could also do imshow(z, aspect=23.7), for example; you can specify
any stretch factor you want.)

I left matshow with the ‘auto’ behavior, which is the default for
ordinary axes, and which was its original behavior. If you would prefer

‘equal’ (1:1), or following the rc[‘image.aspect’], I would be happy to
make that change.

Testing and comments are invited.

Thanks.

Eric

John Hunter wrote:

“Eric” == Eric Firing <
efiring@…229…> writes:

> All, Motivated in part by an old patch (1233294) submitted
> to sourceforge by Nikolai Hlubek, I took a look at how
> aspect ratio is handled in mpl, and concluded it wasn't
> quite right:

Just a few quick comments since I haven’t had a chance to look over
this in any detail.

> 1) The aspect='preserve' kwarg in image caused the image to
> retain its aspect ratio only with some resize events, not
> with all.  The implementation in the image.py code does not
> look right to me.



> Therefore I have reworked the aspect-handling code in
> axes.py, and I think it is working reasonably well.  Indeed,
> I don't see any remaining need for an "aspect" kwarg in
> image.py, and I would like to take it out unless someone
> raises an objection.

The aspect handling of images has been known to be broken from the

early days, but in those days we didn’t even have aspect=‘equal’
functionality, and so adding preserved aspect ratio proved to
daunting. Noone has revisited the issue (until now) since Mark Bakkar

finally (mostly) got proper aspect handling in the axes. So your
observations are on target, and the image aspect handling is an
anachronism that everyone quickly learned to ignore.

>      def set_aspect(self, aspect='auto', fixLimits=None,
> aspect_adjusts='position'): """ aspect: 'auto' - automatic;
> fill position rectangle with data 'normal' - same as 'auto';
> deprecated 'equal' - same scaling from data to plot units
> for x and y A - a circle will be stretched such that the
> height is A times the width. aspect=1 is the same as
> aspect='equal'.

Mark Bakkar wrote most of the aspect handling for the axes, and so he

can response most intelligently to these changes. You should send him
your original post since he may not be on this list. He’s CCd above.

> One question: is there an easy way to automatically trigger
> a redraw in an interactive backend (e.g. ipython with
> gtkagg) at the end of the set_aspect() method, for example?
> The way it works now is that one can make a plot, call the
> set_aspect() method on the resulting axes object, and the
> result will appear as soon as the window is manipulated with
> the mouse; but this manipulation is needed to trigger a
> redraw.

You should be able to do something like

if rcParams[‘interactive’]:
self.figure.canvas.draw()

where self is an Axes instance. Untested, but I think it is valid

across backends.

Thanks for the submission – I look forward to testing it.

JDH


This SF.Net email is sponsored by xPML, a groundbreaking scripting language

that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!

http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642


Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Mark,

Go ahead and test the svn version now. I still need to write the CHANGELOG entry, I will probably take out the fixLimits kwarg (but leave its functionality), and there may be some other things that need tweaking; but the essential functionality is in place.

Mark Bakker wrote:

Eric -

Good to see you are taking aspect ratio handling to the next level.
Your proposed changes sound good.

Regarding the 'fixLimits', this was implemented as the aspect ratio handling was
different when the axes limits were fixed or not. Having them fixed is exceedingly useful,
and used by quite a few people, as far as I know. But I understand this will still be possible.

Yes. The default when aspect ratio is not 'auto' is to maintain the aspect ratio by changing the screen dimensions of the axes box, but the option is available to do it by changing xlim and/or ylim instead.

The code never worked when the window was resized interactively. Am I understaning you
correctly that the new code does this correctly? Across backends? That would be very nice.

Yes, I think it does, but I have not tested it extensively. There is nothing backend-specific. The change that makes it work interactively is to put the aspect ratio calculations in a separate function and then call that function in axes.draw. I have not yet tried John's suggestion for triggering a redraw automatically after calling set_aspect.

The set_aspect function is called from axis() in pylab.py and I think somewhere in backend_basics after a zoom event.

Thanks for pointing that out--I thought I had found everything, but I certainly had not. I will take a look at those calls; at the least, they will need to be changed slightly if I remove the fixLimits kwarg.

I will try to make another pass through the code this evening.

Eric

···

Let me know when you uploaded stuff that is ready for testing and I'll give it a try,

Mark

On 3/20/06, *Eric Firing* <efiring@...229... > <mailto:efiring@…229…>> wrote:

    John, Mark, Fernando, Nikolai,

    I decided to go ahead with the next stage: I committed a few more
    changes so that I think imshow will now work the way people would like.
       To see the basic behavior most quickly, fire up ipython and do

    In [1]:z = rand(20,40)

    In [2]:imshow(z, aspect='auto')
    Out[2]:<matplotlib.image.AxesImage instance at 0xb5be81ec>

    In [3]:imshow(z)
    Out[3]:<matplotlib.image.AxesImage instance at 0xb5c02c0c>

    In the first case, as you resize the window with the mouse, the aspect
    ratio will change with the window. In the second case, the aspect ratio
    will be 1:1 regardless of what you do, including zooming. I made the
    second case the default because it seems to me that an image normally is
    meant to be viewed with a 1:1 aspect ratio--with square pixels. (I am
    assuming the display pixels are square, or close enough to it.)

    (You could also do imshow(z, aspect=23.7), for example; you can specify
    any stretch factor you want.)

    I left matshow with the 'auto' behavior, which is the default for
    ordinary axes, and which was its original behavior. If you would
    prefer
    'equal' (1:1), or following the rc['image.aspect'], I would be happy to
    make that change.

    Testing and comments are invited.

    Thanks.

    Eric

    John Hunter wrote:
     >>>>>>"Eric" == Eric Firing < efiring@...229...
    <mailto:efiring@…229…>> writes:
     >
     > > All, Motivated in part by an old patch (1233294) submitted
     > > to sourceforge by Nikolai Hlubek, I took a look at how
     > > aspect ratio is handled in mpl, and concluded it wasn't
     > > quite right:
     >
     > Just a few quick comments since I haven't had a chance to look over
     > this in any detail.
     >
     > > 1) The aspect='preserve' kwarg in image caused the image to
     > > retain its aspect ratio only with some resize events, not
     > > with all. The implementation in the image.py code does not
     > > look right to me.
     >
     > > Therefore I have reworked the aspect-handling code in
     > > axes.py, and I think it is working reasonably
    well. Indeed,
     > > I don't see any remaining need for an "aspect" kwarg in
     > > image.py, and I would like to take it out unless someone
     > > raises an objection.
     >
     > The aspect handling of images has been known to be broken from the
     > early days, but in those days we didn't even have aspect='equal'
     > functionality, and so adding preserved aspect ratio proved to
     > daunting. Noone has revisited the issue (until now) since Mark
    Bakkar
     > finally (mostly) got proper aspect handling in the axes. So your
     > observations are on target, and the image aspect handling is an
     > anachronism that everyone quickly learned to ignore.
     >
     > > def set_aspect(self, aspect='auto', fixLimits=None,
     > > aspect_adjusts='position'): """ aspect: 'auto' - automatic;
     > > fill position rectangle with data 'normal' - same as
    'auto';
     > > deprecated 'equal' - same scaling from data to plot units
     > > for x and y A - a circle will be stretched such that the
     > > height is A times the width. aspect=1 is the same as
     > > aspect='equal'.
     >
     > Mark Bakkar wrote most of the aspect handling for the axes, and
    so he
     > can response most intelligently to these changes. You should
    send him
     > your original post since he may not be on this list. He's CCd above.
     >
     > > One question: is there an easy way to automatically
    trigger
     > > a redraw in an interactive backend (e.g. ipython with
     > > gtkagg) at the end of the set_aspect() method, for example?
     > > The way it works now is that one can make a plot, call the
     > > set_aspect() method on the resulting axes object, and the
     > > result will appear as soon as the window is manipulated
    with
     > > the mouse; but this manipulation is needed to trigger a
     > > redraw.
     >
     > You should be able to do something like
     >
     > if rcParams['interactive']:
     > self.figure.canvas.draw()
     >
     > where self is an Axes instance. Untested, but I think it is valid
     > across backends.
     >
     > Thanks for the submission -- I look forward to testing it.
     >
     > JDH
     >
     > -------------------------------------------------------
     > This SF.Net email is sponsored by xPML, a groundbreaking
    scripting language
     > that extends applications into web and mobile media. Attend the
    live webcast
     > and join the prime developer group breaking into this new coding
    territory!
     >
    http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
    <http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642&gt;
     > _______________________________________________
     > Matplotlib-devel mailing list
     > Matplotlib-devel@lists.sourceforge.net
    <mailto:Matplotlib-devel@lists.sourceforge.net>
     > matplotlib-devel List Signup and Options