Axes properties are cleared after offsetting spines

I noticed that when you offset the spines of an Axes object, the labels, ticks, and ticklabels/formatting get mostly cleared. Is this intentional and is there a way to prevent (or undo) it?

It’s probably easiest to just look at a notebook:

http://nbviewer.ipython.org/gist/phobson/8818648

That notebook contains a proposed solution from Stack Overflow. Unfortunately, minor ticks and labels are missed (and I can’t understand why as the values are contained in the properties dictionary of the spines).

Background: I’m trying to add an offset kwarg to the despine function in seaborn (https://github.com/mwaskom/seaborn/pull/92). Point of mentioning that is that to make this work, we need to be able to offset the spines after plotting and formatting ticks.

Alternatively, if there was a way to specify a default offset in rcParams before a figure and axes were even created, that might work too.

···

Related to that, when I use the SO solution, about 50% of the time the axes labels are rendered as the label objects, not text. Whatever triggers that doesn’t seem to be deterministic. Resetting the notebook will fix it or break it – there’s no telling how it’s going to go. Here’s the exact same notebook as above, with the mangled figure at the bottom.

http://nbviewer.ipython.org/gist/phobson/8818680

Cheers,

-Paul

[…]
Paul, I may have encountered the same issue a few years ago. May I
suggest that you look at the mailing list thread from that time [1],
try the patch in the thread, and see whether your issue is resolved?
This solution doesn’t provide a work-around in your code, but it may
fix the problem at the root. I took a brief look at the current
state of spines.py, and I found only the same instances of
“self.axis.cla()” that the patch changes to
“self.axis.reset_ticks()”.
Kind regards,
Stan
[1] ,
29 Sep. 2010.

···

On 2014-02-05 02:26, Paul Hobson wrote:

    I noticed that when you offset the spines of an

Axes object, the labels, ticks, and ticklabels/formatting get
mostly cleared. Is this intentional and is there a way to
prevent (or undo) it?

http://matplotlib.1069221.n5.nabble.com/Spine-set-position-unexpectedly-clears-axis-td37865.html

Paul, I just found the work-around that I used in my code. Define
the following function:
(The mention of v. 1.0.0 in the docstring is just the version I was
using at the time, not necessarily the earliest version with this
issue.) Then replace method calls like “spine.set_position(pos)”
with the function call “set_spine_position(spine, pos)”. I hope this
helps.

···

On 2014-03-24 14:08, Stan West wrote:

  May I suggest that you look at the mailing list thread from that

time [1], try the patch in the thread, and see whether your issue
is resolved? This solution doesn’t provide a work-around in your
code, but it may fix the problem at the root.

    def set_spine_position(spine, position):
"""
Set the spine's position without resetting an associated axis.
As of matplotlib v. 1.0.0, if a spine has an associated axis, then spine.set_position() calls axis.cla(), which resets locators, formatters, etc. We temporarily replace that call with axis.reset_ticks(), which is sufficient for our purposes.
"""
axis = spine.axis
if axis is not None:
cla = axis.cla
axis.cla = axis.reset_ticks
spine.set_position(position)
if axis is not None:
axis.cla = cla

Wow. Thanks so much, Stan! This is a huge help and works just as I need it to.

Much appreciated!

···

On Mon, Mar 24, 2014 at 11:26 AM, Stan West <stan.west@…595…> wrote:

On 2014-03-24 14:08, Stan West wrote:

  May I suggest that you look at the mailing list thread from that

time [1], try the patch in the thread, and see whether your issue
is resolved? This solution doesn’t provide a work-around in your
code, but it may fix the problem at the root.

Paul, I just found the work-around that I used in my code. Define

the following function:

    def set_spine_position(spine, position):
"""
Set the spine's position without resetting an associated axis.
As of matplotlib v. 1.0.0, if a spine has an associated axis, then spine.set_position() calls axis.cla(), which resets locators, formatters, etc. We temporarily replace that call with axis.reset_ticks(), which is sufficient for our purposes.
"""
axis = spine.axis
if axis is not None:
cla = axis.cla
axis.cla = axis.reset_ticks
spine.set_position(position)
if axis is not None:
axis.cla = cla
(The mention of v. 1.0.0 in the docstring is just the version I was

using at the time, not necessarily the earliest version with this
issue.) Then replace method calls like “spine.set_position(pos)”
with the function call “set_spine_position(spine, pos)”. I hope this
helps.