Thanks to visit codestin.com
Credit goes to github.com

Skip to content

added axes inversion to cla() #5450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed

added axes inversion to cla() #5450

wants to merge 6 commits into from

Conversation

jrmlhermitte
Copy link
Contributor

This has been bothering me a little. When axes are cleared, the x/y-axis should have the positive direction consistently point the same way.

Here is sample code:

import numpy as np
import matplotlib.pyplot as plt
img = np.random.random((100,100))
plt.imshow(img)
plt.cla()
x = np.linspace(0,2*np.pi,100)
plt.plot(x,np.cos(x))

Upon clearing, the yaxis is inverted. This is because plotting the image inverts the y axis since the origin is located in the upper left hand corner. If not image was previously plotted to the figure, the y axis would not have been inverted. I have tested it and it works nicely.

What do you think? Is this worth adding? As a user, I can definitely say this is a feature that would greatly simplify my life.

I'm pinging @fariza and @OceanWolf since they reviewed a pull request touching similar functions. (@OceanWolf, still have not done the div by zero checking but will later)

thanks for reading!

@jrmlhermitte jrmlhermitte changed the title added axes inversion to clear added axes inversion to cla() Nov 9, 2015
@jenshnielsen
Copy link
Member

👍 I think it is definitely reasonable to expect clearing the reset the inversion.

I think we should add a test for this. Something like do a plot to an inverted axis. Check that the axis is inverted, clear, do a new plot and check that the axis is not inverted.

@WeatherGod
Copy link
Member

I am a bit more nuanced. I think it should clear so long as autoscaling is
still on. But what if the axis was explicitly set that way? Should clearing
also clear the limits? I am not so sure about that.

On Mon, Nov 9, 2015 at 11:25 AM, Jens Hedegaard Nielsen <
[email protected]> wrote:

:1: I think it is definitely reasonable to expect clearing the reset the
inversion.

I think we should add a test for this. Something like do a plot to an
inverted axis. Check that the axis is inverted, clear, do a new plot and
check that the axis is not inverted.


Reply to this email directly or view it on GitHub
#5450 (comment)
.

@jrmlhermitte
Copy link
Contributor Author

Thanks @jenshnielsen . I like @WeatherGod 's idea. How about not setting:

self._autoscaleXon = True

in the axes clear and then checking to see whether or not autoscale is set before clearing? I'll check later to see whether this is the right place to do it.

@@ -1060,6 +1060,10 @@ def cla(self):
self.yaxis.set_visible(yaxis_visible)
self.patch.set_visible(patch_visible)
self.stale = True
if(self.xaxis_inverted()):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to do this without the tests?

These should go above setting self.stale = True

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way to do this is in each of the "else" blocks of the "if sharex", sharey conditionals, add self.viewLim.intervalx = (0, 1) etc. The actual values won't matter, only the fact that they are in the normal order.

@jrmlhermitte
Copy link
Contributor Author

Thanks @efiring. I have done this and it works wonderfully and it's a clever way to avoid the test, while taking into account the shared axes (oops!). I wasn't aware of this piece until now (never used them before), thanks for the patience in dealing with a "noob". ;-)

@jenshnielsen you mentioned a test. Do you mean adding a test routine somewhere in the library itself? I am not familiar with this.

Here is a proposed test for now, sorry it is lengthy. It also tests shared axes.

import numpy as np
import matplotlib.pyplot as plt
# comment out for non-interactive plotting
plt.ion()

# figure 0 should look like figure 2, i.e.
# plotting should be independent of clearing history
# this specifically tests that the axes directions
# are independent of history

# plotting 1 d graph, positive is up
plt.figure(0);
x = np.linspace(0,2*np.pi,100);
plt.plot(x,np.cos(x))

# plotting a figure positive is down
plt.figure(1);
img = np.random.random((100,100))
plt.imshow(img)

# plotting an image, then 1d graph, axis is now down
plt.figure(2);
img = np.random.random((100,100))
plt.imshow(img)

plt.cla()
x = np.linspace(0,2*np.pi,100);
plt.plot(x,np.cos(x))
plt.autoscale()

# ensure that vice versa also not affected
plt.figure(3);
x = np.linspace(0,2*np.pi,100);
plt.plot(x,np.cos(x))

plt.cla()
img = np.random.random((100,100))
plt.imshow(img)

# try shared y-axis and clear one figure whose axis is shared, 
# axes are not flipped back (expected result)
plt.figure(4);
ax1= plt.subplot(211);
plt.imshow(img)
plt.subplot(212,sharey=ax1);
plt.imshow(img)
plt.cla();
plt.plot(x,100*np.cos(x))

# clear the master shared axis
plt.figure(5);
ax1= plt.subplot(211);
plt.imshow(img)
plt.subplot(212,sharey=ax1);
plt.imshow(img)
plt.subplot(211);
plt.cla();
plt.plot(x,100*np.cos(x))

@efiring
Copy link
Member

efiring commented Nov 12, 2015

@ordirules The test for cla() in axes3d is failing, so something will need to be changed there.

@jenshnielsen
Copy link
Member

@ordirules I think you are on the right track. The test would most likely go into https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/tests/test_axes.py have a look at these tests and the resources at http://matplotlib.org/devel/testing.html

A test could look like this:

@cleanup
from nose.tools import assert_false
def test_inverted_cla():
    # plotting an image, then 1d graph, axis is now down
    fig, ax = plt.subplots()
    # test that a new axis is not inverted per default
    assert not(ax.xaxis_inverted())
    assert not(ax.yaxis_inverted())
    img = np.random.random((100,100))
    ax.imshow(img)
    # test that a image axis is inverted
    assert not(ax.xaxis_inverted())
    assert ax.yaxis_inverted()
    ax.cla()
    x = np.linspace(0,2*np.pi,100);
    ax.plot(x,np.cos(x))
    # test if the axis are inverted
    # assert something
    plt.autoscale()
    # test if the axis are inverted
    # assert something

We use assert to test if something is true or false. We could also test for the axis limits
We need the @cleanup decorator to make sure that this test don't affect other tests.

@WeatherGod
Copy link
Member

Yeah, this patch totally breaks cla() for axes3d. Essentially, axes3d assumes that viewLims is never mucked with directly. It probably would be better to utilize set_xlim/set_ylim instead in a manner similar above in the sharex/y condition. It would also be a good idea to add similar code to set_zlim() in axes3d.py as well.

@jrmlhermitte
Copy link
Contributor Author

thanks this all sounds interesting. will take a look later, currently pretty busy. thanks I'm learning a lot about this lib :-).
(@WeatherGod, regarding a previous post, I agree that cla()'s purpose seems to be just bring everything back from scratch without having to kill the figure, but I still like that idea of saving the view limits somehow that you suggested. It could be something nice to incorporate in as a future PR.)

@efiring
Copy link
Member

efiring commented Nov 12, 2015

I would plead for not making this more complicated than really necessary.

@tacaswell tacaswell modified the milestones: next bug fix release (2.0.1), proposed next point release (2.1) Nov 24, 2015
@jrmlhermitte
Copy link
Contributor Author

sorry, I have been incredibly late on this, pretty busy. Anyway, now I understand what nosetests are :-)

I have added tests for the following:

  1. cla() resets axes if inverted for line plots and images
  2. autoscale should not change axes inversion (i.e. when image is plotted)
  3. with shared axes, only when the master axis is cleared should axes inversion be removed (two tests: one clearing master axis and the other clearing nonmaster). For this test, I am not so sure, is it a reasonable assumption to make that shared axes should have one axis as a master?
    thanks @jenshnielsen for the information on the tests, pretty neat!

@WeatherGod I have replaced the change of the viewLims to "set_xlim" and "set_ylim." since the axes are cleared, I just set them to (0,1) as mentioned before. I could grab the xlim and ylims but that adds extra code and overhead. Thanks @efiring , honestly, this was your idea and it seems to work great so far :-).

One more comment to @WeatherGod regarding axes3d. I would rather not touch them (or make it a separate PR) since this adds an extra layer of complexity and I am not too familiar with it. What do you think?

@tacaswell
Copy link
Member

huh, we are testing some interesting projections in the test suite that do not liken set_*lim.

@ordirules just made the connection that I know you in other contexts, sorry about that.

@jrmlhermitte
Copy link
Contributor Author

Yeah, looks like it's line 168 of geo.py of this current commit, throwing an error, I'll paste the code here just to make it easier to discuss:

   def set_xlim(self, *args, **kwargs):
        raise TypeError("It is not possible to change axes limits "
                        "for geographic projections. Please consider "
                        "using Basemap or Cartopy.")

Perhaps should the new projections override cla() then? I think cla() as was mentioned before bring the axes back to their original state. I am by no means an expert on this, but thought I'd throw this out.

@tacaswell no worries, great hackathon you organized btw, was a success :-)

@tacaswell
Copy link
Member

Another option is to try...except TypeError: pass setting the limits.

@jrmlhermitte
Copy link
Contributor Author

that sounds much simpler. let's try it and see
(PS: I did run nosetests on the test_molleweide_grid before pushing this of course, but you never know what new issues come up!)

# test that a new axis is not inverted per default
assert not(ax.xaxis_inverted())
assert not(ax.yaxis_inverted())
img = np.random.random((100,100))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why this file isn't PEP8-tested, but there should be spaces after commas and around operators. Also, please remove the useless semicolons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure we do not pep8 test the tests

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, but they will be when the pytest PR is merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the comment, I have this bad habit of putting semicolons (I squash multiple commands in a line when testing then forget to remove after unsquashing)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't touch axes3d, then an issue should be filed so we don't forget
to fix it, but I really think it should be quite straight-forward.
On Dec 24, 2015 10:58 AM, "Julien Lhermitte" [email protected]
wrote:

In lib/matplotlib/tests/test_axes.py
#5450 (comment):

@@ -135,6 +135,48 @@ def test_twinx_cla():
assert_true(ax.patch.get_visible())
assert_true(ax.yaxis.get_visible())

+@cleanup
+def test_inverted_cla():

  • Github PR added axes inversion to cla() #5450. Setting autoscale should reset

  • axes to be non-inverted.

  • plotting an image, then 1d graph, axis is now down

  • fig = plt.figure(0);
  • ax = fig.gca()
  • test that a new axis is not inverted per default

  • assert not(ax.xaxis_inverted())
  • assert not(ax.yaxis_inverted())
  • img = np.random.random((100,100))

thanks for the comment, I have this bad habit of putting semicolons (I
squash multiple commands in a line when testing then forget to remove after
unsquashing)


Reply to this email directly or view it on GitHub
https://github.com/matplotlib/matplotlib/pull/5450/files#r48419484.

@jrmlhermitte
Copy link
Contributor Author

I am closing this as I think it's a matter of preference. For the record, I get around this by using clf() instead of cla(). I believe this is a better option. So to summarize all previous posts, cla() probably should leave axes states untouched and just clear the data (so keep information about axes inversion). If you want the default initial state of axes, then clear them and create new?

Just an opinion, sorry for keeping this open so long, I have been busy with other things. Thanks for your support.

@tacaswell
Copy link
Member

I do not think there was any disagreement about doing this. It seems like the only outstanding work was to add the same 3 lines in the 3D code.

@jrmlhermitte
Copy link
Contributor Author

oops I did not see @WeatherGod 's comment on the outdated diff.
if there's consensus then I'm fine with it.
I added the change to zlim, rebased and forced pushed and now I can no longer re-open the PR. Is there a way around this or should I just open a new PR?

@jrmlhermitte
Copy link
Contributor Author

@tacaswell moved to #8455
Sorry, I forgot to mention this here! thanks for the support @tacaswell !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants