compresson ratio

Crudely: I'm looking for something just as simple in

    > matplotlib.matlab. My last post outlined what I think the
    > current procedure is to achieve the same effect, and it is
    > much more cumbersome. While this matters little when one is
    > leisurely writing a script, it matters a lot when one is
    > doing interactive plotting in a classroom setting.

    > Now you point out that this request has an ambiguity: what
    > "physical" medium am I talking about? Specifically, a true
    > compression ratio on screen requires tricky stuff if dpiy !=
    > dpix. OK, I assume ignoring this will yield a "close
    > enough" result in a classroom setting, so the only time I
    > need it to be exact is when I produce figures for paper
    > display.

w/o having to worry about dpi differences in the x and y direction, it
is much easier, and your hardcopy will be correct in any case.

Do you really need arbitrary compression ratios, or just ratios equal
to 1. I added the option 'equal' to the axis command, which simply
sets the xlim and ylim to be equal and includes the range of both.
I'll include the modified axis method from matlab.py at the end of
this email. Thus you can do

    from matplotlib.matlab import *
    figure(figsize=(6,6))
    ax = axes([0.1, 0.1, 0.8, 0.8])
    plot(rand(100), rand(100), 'o')
    axis('equal')
    show()

Admittedly this is more typing than you want to do in an interactive
session. I experimented with a function 'square' which isn't the
right name but you get the idea. It handles setting the figure size,
axes ratio and lim ratio for you. Some suitably named function could
be included in the standard interface

    from matplotlib.matlab import *

    def square():
        fig = gcf()
        ax = gca()
        figw, figh = fig.get_size_inches()
        l,b,axw,axh = ax.get_position()

        side = min([figw, figh])
        frac = min([axw, axh])

        fig.set_figsize_inches(side, side)
        ax.set_position([l,b,frac,frac])
        axis('equal')
        draw()

    plot(rand(100), rand(100), 'o')
    square()
    show()
     
It's the right idea, but it doesn't work currently if you are using a
GUI backend. The reason it fails is has to do with the pipeline order
in which figure managers, figures etc are created by default, and the
fact that configure events and resize events change the figure width
and height (so you can for example, resize your figure window). It
*does* work if you specify the figure size

    figure(figsize=(8,8))
    plot(rand(100), rand(100), 'o')
    square()
    show()

because then matplotlib has the information it needs at figure
creation time. Of course, you can set the figure size to have a unity
aspect ratio in your rc file and then you could do without the figsize
command altogether. I'll think about how to best fix the GUI resizing
problem. I'll probably need to add an observer to the figure limits
so that the GUI backend can update its size from script calls to
figure size. As an aside, traits are starting to look very useful,
with their build in observer framework.

For now, any feedback on whether this approach looks like the right
one, whether any ratios other than 1 are actually needed, what the
function square should be called and anything else is welcome.

JDH

def axis(*v):
    """
    axis() returns the current axis as a length a length 4 vector

    axis(v) where v= [xmin xmax ymin ymax] sets the min and max of the
    x and y axis limits

    axis('off') turns off the axis lines and labels

    axis('equal') sets the xlim and ylim to be identical
    """
    
    if len(v)==1 and is_string_like(v[0]):
        s = v[0]
        if s.lower()=='on': gca().set_axis_on()
        elif s.lower()=='off': gca().set_axis_off()
        elif s.lower()=='equal':
            ax = gca()
            xmin, xmax = ax.get_xlim()
            ymin, ymax = ax.get_ylim()
            vmin = min([xmin, ymin])
            vmax = max([xmax, ymax])
            ax.set_xlim((vmin, vmax))
            ax.set_ylim((vmin, vmax))
            draw_if_interactive()
            
        else:
            error_msg('Unrecognized string %s to axis; try on or off' % s)
        return
    
    try: v[0]
    except IndexError:
        xlim = gca().get_xlim()
        ylim = gca().get_ylim()
        return [xlim[0], xlim[1], ylim[0], ylim[1]]
    
    v = v[0]
    if len(v) != 4:
        error_msg('v must contain [xmin xmax ymin ymax]')
        return
    gca().set_xlim([v[0], v[1]])
    gca().set_ylim([v[2], v[3]])
    draw_if_interactive()

OK, this does not work for me.
Test case:
d=arange(201)*pi/100
plot(cos(d),sin(d))
square()
show()
This should look like a circle.
It looks like an oval.

Problems:
1. fig.set_figsize_inches is ignored.
It has no effect on figure size.
(It changes the size the figure reports,
as checked by printing it, but not the
size that is drawn---a missing argument
to draw?)
2. axis('equal') should not be desirable,
if it is matlab compatible
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/axis.html
That is, square() should set an axis aspect ratio of unity,
but axis('equal') should equate the *unit length* along each
axis. (For my example circle this is not a problem, but in
generaly this is completely wrong.)

Hope that's useful,
Alan Isaac

···

On Tue, 14 Sep 2004, John Hunter apparently wrote:

    def square():
        fig = gcf()
        ax = gca()
        figw, figh = fig.get_size_inches()
        l,b,axw,axh = ax.get_position()

        side = min([figw, figh])
        frac = min([axw, axh])

        fig.set_figsize_inches(side, side)
        ax.set_position([l,b,frac,frac])
        axis('equal')
        draw()