FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

set_ylim not working with plt.axis('equal') · Issue #8093 · matplotlib/matplotlib · GitHub

Repository navigation

set_ylim not working with plt.axis('equal') #8093

Closed

Description

set_ylim has no effect when using plt.axis('equal'):

plt.plot((.1, .3))
plt.axis('equal')
plt.gca().set_ylim(.1, .2)

Activity

  1. dstansby commented on Feb 17, 2017

    Member

    What Matplotlib version, Python version and Platform are you using? On Linux, python 3.5.2 and matplotlib master branch I get the figure below. Is that what you were expecting or not?

  2. fkbreitl commented on Feb 17, 2017

    Author

    Sorry I forgot to mention I am using matplotlib 2.0.0 and the last command has no effect in my case.
    So the y-axis remains from 5 to 8.

  3. dstansby commented on Feb 17, 2017

    Member

    Hmm, this is working fine for me on 2.0.0 using python 3.6, in a fresh conda environment. What version of python are you using and what OS are you running?

  4. WeatherGod commented on Feb 17, 2017

    Member
  5. fkbreitl commented on Feb 17, 2017

    Author

    Sorry I didn't provide this information. I see it with Python 2.7.13 using IPython 5.1.0.
    When using plt.savefig I obtain the correct result mentioned by you above.

    However, my example was not well chosen. The actual problem appears in this example (also when using plt.savefig without IPython):

    plt.plot((.1, .3))
    plt.axis('equal')
    plt.gca().set_ylim(.1, .2)
    

    However, maybe this is in fact not a bug but a feature, since this behavior guaranties a fixed aspect ratio of plots, which could be handy when generating multiple plots. I was just surprised that the axes can be longer than the given limits. But it can be a good thing that matplotlib sees them as lower limits with respect to the other axis. Maybe the current behavior is not a bad idea and no changes are actually required.

  6. dstansby commented on Feb 17, 2017

    Member

    Yep, I can confirm that example doesn't seem to be working.

  7. anntzer commented on Feb 18, 2017

    Contributor
  8. tacaswell commented on Feb 20, 2017

    Member

    @fkbreitl Just to check, you edited the orginal post? I can not see a difference between the two examples...

    I think the fundamental problem is that with a fixed aspect ratio the system is over constrained so we drop one of the constraints. The logic for all of this lives in apply_aspect, appears to have some special-casing for log scales, and would definitely benefit from better documentation!

  9. fkbreitl commented on Feb 20, 2017

    Author

    @tacaswell The difference is that the first example respects the limits and the second doesn't.

    If you say apply_aspect can help, then it would in fact be very useful to know how. The documentation is probably a very good place for that.

  10. tacaswell commented on Feb 20, 2017

    Member

    But I don't see how the examples are different, they are both

    plt.plot((.1, .3))
    plt.axis('equal')
    plt.gca().set_ylim(.1, .2)

    I suggest having a look at the source.

  11. added this to the milestone on Feb 20, 2017
  12. fkbreitl commented on Feb 20, 2017

    Author

    @tacaswell Oh, you are right. It seems like dstansby edited my example.
    I think my original example was something like

    plt.plot((1,9))
    plt.axis('equal')
    plt.gca().set_ylim(5, 7)
    
  13. beuse commented on Apr 4, 2017

    I found this page searching for a solution to the same problem. Here is a code snippet:

    for angle in range(0,180+step,step):
        .
        fig = plt.figure('Angle {0}'.format(angle))
        plt.plot(x,y,'-')
        # plt.gca().set_adjustable('box') # this didn't help
        plt.grid()
        plt.axis('equal')  # if this is removed, then plt.axis works
        plt.axis((-8.0,8.0,-8.0,8.0))
    plt.show()
    

    The x-axis was correct, but the y-axis autoscaled. Interestingly, if I tried to manually scale the y=axis (using the check mark on the displayed plot) the values would not be accepted when I pushed apply. Python 3.5.2, Matplotlib 1.5.3

  14. tacaswell commented on Apr 6, 2017

    Member

    @beuse You want ax.axis('square') I think.

  15. 11 remaining items

  16. modified the milestones: needs sorting, v3.2.0 on Aug 12, 2019
  17. aggna commented on Aug 19, 2019

    @timhoffm @tacaswell hopefully this one is more demonstrative of the problem.
    Anyways, I still couldn't find a proper automated fix for my problem, but managed to manually make everything correct.

    Case 1

    If I don't have two subplots, axis('equal') works fine.

    Case 2

    The automated code fails to work when you have two subplots. For some reason, it fixes a figure size (even if you don't give it one) and axis('equal') only works to change axis limits, hence cropping the plot.

    Case 3

    Manually chosing the figure size and subplot sizes first, depending on the data that is being plotted.

    Case 4

    Manually chosing the figure size and subplot sizes first, depending on the data that is being plotted. Then use axis('equal') to take care of finetuning in guessed size.

    Attaching code.

    Set up - no plotting yet

    import matplotlib.pyplot as plt
    import numpy as np
    
    # Quantities used in all cases:
    radius = 15
    height = 10
    dots   = np.array([[17,0,11],
                  [-20,0,0],
                  [17,3,0],
                  [3,16,4]])
    
    theta = np.arange(0,2*np.pi,0.01)
    rotor_x  = radius*np.cos(theta)
    rotor_y  = radius*np.sin(theta)
    rotor_z = height/2*np.ones(len(rotor_x))
    vert_z = np.arange(-height/2,height/2,height/20)
    vert_x = radius*np.ones(len(vert_z))
    rotor_color = 'magenta'
    
    
    # Quantities used in Case 3 and 4:
    
    max_y = max(radius,max((dots[:,1])))
    min_y = min(-radius,min(dots[:,1]))
    max_x = max(radius,max((dots[:,0])))
    min_x = min(-radius,min(dots[:,0]))
    max_z = max(height/2,max((dots[:,2])))
    min_z = min(-height/2,min((dots[:,2])))
        
    y_size = (max_y - min_y)
    z_size = (max_z - min_z)
    x_size = (max_x - min_x)
    
    total_height = 0.1*(y_size + z_size ) + 1
    total_width = 0.1*(x_size)
    

    Case 1 code

    ## Case 1
    
    sp1 = plt.axes()
    
    # Make a circle
    h = sp1.plot(rotor_x,rotor_y,color = rotor_color)
    sp1.set_ylabel('y (mm)')
    # Make some dots
    for i in range(len(dots)):
        sensor_cartesian = dots[i]
        hsens = sp1.scatter(sensor_cartesian[0],sensor_cartesian[1])
    sp1.axis('equal')
    sp1.text(0,0,'Case 1')
        
    plt.savefig('Case_1.png',bbox_inches='tight')
    

    Case 2/3/4 code

    ## Case 2/3/4:
    
    case =4
    
    if case==2:
        # For case 2, let axis equal do the job
        fig, [sp1,sp2] = plt.subplots(nrows=2, ncols=1, sharex='col' 
                               ,gridspec_kw={'height_ratios': [3, 1]})
    elif (case==3 or case==4):
        # For case 3 and 4, manually chose the figure size and subplot size
        fig, [sp1,sp2] = plt.subplots(nrows=2, ncols=1, sharex='col' 
                                        ,gridspec_kw={'height_ratios': [y_size/z_size, 1]}
                                      ,figsize = (total_width,total_height)
                                  )
    # Make axis equal for case 2 or 4:
    if (case==2 or case==4):
        sp1.axis('equal')
        sp2.axis('equal')
    
    # Make a circle
    h = sp1.plot(rotor_x,rotor_y,color = rotor_color)
    sp1.set_ylabel('y (mm)')
    sp2.set_xlabel('x (mm)')
            
    # Make the corresponding rectangle
    sp2.plot(rotor_x,rotor_z,rotor_x,-rotor_z,color = rotor_color)
    sp2.plot(vert_x,vert_z,-vert_x,vert_z,color = rotor_color)
    sp2.set_ylabel('z (mm)')
    
    # Plot all the dots
    for i in range(len(dots)):
        sensor_cartesian = dots[i]
        hsens = sp1.scatter(sensor_cartesian[0],sensor_cartesian[1])
        sp2.scatter(sensor_cartesian[0],sensor_cartesian[2],color = hsens.get_facecolor())
    
           
    sp1.text(0,0,'Case %d'%case)
    fig.savefig('Case_%d.png'%case,bbox_inches = 'tight')
    
  18. timhoffm commented on Aug 22, 2019

    Member

    @aggna This is correct and documented behavior.

    • A figure is always created with a fixed size. The figure may be created implicitly if necessary, when using pyplot. If not explicit size is given, it is taken from plt.rcParams['figure.figsize'].
    • axis('equal') scales the data limits to get the aspect right. See https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.axis.html.
    • Alternatively, you may use axis('scale')) to resize the axes instead.
    • There is no way of autoscaling a figure to fix the aspect. The figure size is always fixed.
  19. jklymak commented on Aug 22, 2019

    Member

    Printing a figure w/ bbox_inches='tight' will resize the figure. And a lot of people do that implicitly when they use %matplotlib inline in ipython/jupyter notebooks. I think its a mistake for the inline backend to do that, because it leads to lots of confusion, but...

  20. ImportanceOfBeingErnest commented on Aug 23, 2019

    Member

    I think I understand the issue. Minimal example:

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.array([-20, -3, 0, 17])
    y = np.array([0, -16, 16, 0])
    
    fig, (ax1,ax2) = plt.subplots(nrows=2, ncols=1, sharex='col', 
                                  gridspec_kw={'height_ratios': [3, 1]})
    
    ax1.set_aspect('equal', adjustable="datalim", share=True)
    ax2.set_aspect('equal', adjustable="datalim", share=True)
    
    h1, = ax1.plot(x, y)
    h2, = ax2.plot(x, y / 4)
    

    The problem: The lines are cut off. Now unlike other similar issues, which arise because the system is overconstrained, this is not the case here. The only constraints here are the equal aspect for both axes, and the sharing between the x axes. This would in principle still allow to adjust the x axis limits, such that the whole line is shown.

    So the expected outcome would be this:

  21. jklymak commented on Aug 23, 2019

    Member

    Yeah theoretically. But you’d need a constraint solver to figure it out. I’d say expecting sharing,autoscaling, and maintaining aspect across a number of axes is a pretty hard problem and you can either set up a big machinery to solve it or the user need not rely on autoscaling.

  22. aggna commented on Aug 23, 2019

    @ImportanceOfBeingErnest Yes, that's what I was thinking axis('equal') would do. But alas!
    @timhoffm Thanks for clarifying the expected behaviour.

  23. aggna commented on Aug 23, 2019

    @jklymak The constraints aren't that complicated to solve, IMO. Just a bit of subtraction and division, as you can see from my O[10] lines of code in the second block in setup.

    All plotting algorithms probably have the code structure that takes data range and uses those to implement the default axes limit. So now all they gotta do is take the grid-spec and figsize into account to decide the new axes limits.

  24. jklymak commented on Aug 23, 2019

    Member

    So now all they gotta do is take the grid-spec and figsize into account to decide the new axes limits.

    Sounds easy!

  25. aggna commented on Aug 23, 2019

    @timhoffm Did you mean axis('scaled') ?
    I tried it, but that one gave much more ridiculous results, so I abandoned it early on.

    For folks who might encounter this problem later at some point, here's what you get if you replace axis('equal') by axis('scaled') in the above code, keeping everything else the same (I had to adjust the text location, but that's not the main point):



  26. ImportanceOfBeingErnest commented on Aug 23, 2019

    Member

    Let's not confuse things here. The figure size is fixed (bbox_inches="tight" does not change the figure size, it just renders on a larger/smaller pixel space). Anything that would change the figure size is on a totally different level. The issue isolated above is about the datalimits. Possibly this is hard, too, but I still need to convince myself of that.

  27. jklymak commented on Aug 23, 2019

    Member

    The figure size is fixed (bbox_inches="tight" does not change the figure size, it just renders on a larger/smaller pixel space).

    It renders a different figure size in inches, but if you mean it doesn't change the figure size parameter for calculation of the axes positions, I agree with that. (I wouldn't think in pixels, since that does often change on a savefig, and is irrelevant for many of the backends).

  28. Victor-Victorovich commented on May 10, 2021

    try using plt.gca().set_aspect('equal')

    This worked for me. I had the same issue as OP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL