Adjust Axes3D label positioning
Asked Answered
T

8

46

I am having trouble with axes labels overlapping ticks labels in matplotlib. I've tried to reposition the labels "manually" by applying transforms or by calling set_y(), but no avail.

Here's a snippet that reproduces the problem:

import matplotlib
matplotlib.use("TKAGG")
import matplotlib.pyplot as pyplot
import mpl_toolkits.mplot3d

figure = pyplot.figure()
figure.subplots_adjust(bottom=0.25, top=0.75)
axes = figure.gca(projection='3d')
xLabel = axes.set_xlabel('XXX xxxxxx xxxx x xx x')
yLabel = axes.set_ylabel('YY (y) yyyyyy')
zLabel = axes.set_zlabel('Z zzzz zzz (z)')
plot = axes.plot([1,2,3],[1,2,3])

pyplot.show()

Note how the x and y labels clash with the ticks. Can I solve this elegantly ?

Transubstantiate answered 2/4, 2011 at 20:50 Comment(0)
S
55

I share your frustration. I worked on it for a good half hour and got nowhere. The docs say set_xlabel takes an arg labelpad but I get an error (AttributeError: Unknown property labelpad)! Setting it after the fact doesn't do anything, on xaxis or w_xaxis.

Here's a crude workaround:

import matplotlib
matplotlib.use("TKAGG")
import matplotlib.pyplot as pyplot
import mpl_toolkits.mplot3d

figure = pyplot.figure(figsize=(8,4), facecolor='w')
ax = figure.gca(projection='3d')

xLabel = ax.set_xlabel('\nXXX xxxxxx xxxx x xx x', linespacing=3.2)
yLabel = ax.set_ylabel('\nYY (y) yyyyyy', linespacing=3.1)
zLabel = ax.set_zlabel('\nZ zzzz zzz (z)', linespacing=3.4)
plot = ax.plot([1,2,3],[1,2,3])
ax.dist = 10

pyplot.show()

enter image description here

Sprague answered 3/4, 2011 at 0:7 Comment(6)
I swear you, I tried tens of workarounds, but it didn't occur me to simply add a newline on the start of the labels ! Clever ! Thank you !Transubstantiate
It made me crazy until I came across you simple, yet very clever approach. Thanks ...Bridesmaid
This works for me too, and I recently came to realize that putting one or two newlines on the end of the label string can also help force it into a readable position.Trust
By any chance, do you know how to combine that with latex commands, when the option rcParams["text.usetex"] is set to True ?Tabloid
Still works like a charm (using version 3.4.2)!! Thanks a lot :DGemina
Hello! If I want to put the ticks and labels of the z axis to the left spine, how can I do this? Thanks in advance.Chasten
G
26

Add this for each axis, adapt the number:

axes.yaxis.labelpad=30

It is mentioned in the link by Adam Hughes as not working, but it works for me.

Gibbous answered 8/4, 2016 at 10:28 Comment(1)
This is the only fix that worked for me with mpl v2.0.2.Atronna
D
22

In new versions of matplotlib, this is how to do it:

ax.xaxis._axinfo['label']['space_factor'] = 2.8

See the explanation here:

https://github.com/matplotlib/matplotlib/issues/3610

Tested on v1.4, should work in versions > 1.1 I believe.

Degreeday answered 2/10, 2014 at 20:41 Comment(1)
I have 1.5.1 running in Jupyter and this expression has no apparent effect.Trust
B
20

I really need to follow StackOverflow more often. I am the current maintainer of mplot3d. The reason why the various tricks that typically work in regular 2d plots don't work for 3d plots is because mplot3d was originally written up with hard-coded defaults. There were also bugs in how mplot3d calculated the angle to render the labels.

v1.1.0 contains several fixes to improve the state of things. I fixed the miscalculation of axes label angles, and I made some adjustments to the spacing. For the next release, I would like to have 3d axes to take up more than the default axes spacing, since the default was designed to take into account that tick labels and axes labels would be outside the axes, which is not the case for mplot3d. Because the spacings are determined by relative proportions in mplot3d, having a smaller space to work within forces the labels closer together.

As for other possible avenues for work-arounds, please see the note here. A fair warning, this private dictionary is not intended to be a permanent solution, but rather a necessary evil until the refactor of mplot3d is complete.

Also, v1.1.0 contains many updates to the api of mplot3d. Please check out the revised documentation here.

Bladder answered 10/11, 2011 at 16:22 Comment(2)
Is there an example on how would to access and change self._axinfo? Especially the padding?Rahman
^^^^^^^ See my answerDegreeday
G
8

This changes the padding for all (x, y, z) labels in one shot. I like this approach the most:

from matplotlib import rcParams
rcParams['axes.labelpad'] = 20
Gassy answered 14/5, 2018 at 14:27 Comment(0)
E
4

You can use labelpad after that you plot your figure:

axes = fig.gca(projection='3d')
axes.xaxis.labelpad=20
axes.yaxis.labelpad=20
axes.zaxis.labelpad=20

This might cause the axis labels to go outside the 3D plot so you have to adjust the distance using the dist method:

ax.dist = 13
Emptor answered 10/11, 2019 at 18:19 Comment(0)
B
3

As a design practice, transformed text is not very legible. I would suggest you to use labels for your axis, maybe color encoded. This is how you do it in matplotlib

import matplotlib
matplotlib.use("TKAGG")
import matplotlib.pyplot as pyplot
import mpl_toolkits.mplot3d

figure = pyplot.figure()
figure.subplots_adjust(bottom=0.25, top=0.75)
axes = figure.gca(projection='3d')
xLabel = axes.set_xlabel('X', fontsize=14, fontweight='bold', color='b')
yLabel = axes.set_ylabel('Y',fontsize=14, fontweight='bold', color='r')
zLabel = axes.set_zlabel('Z',fontsize=14, fontweight='bold', color='g')


x = pyplot.Rectangle((0, 0), 0.1, 0.1,fc='b')
y = pyplot.Rectangle((0, 0), 0.1, 0.1,fc='r')
z = pyplot.Rectangle((0, 0), 0.1, 0.1,fc='g')

handles, labels = axes.get_legend_handles_labels()
axes.legend((x,y,z),("XXXXXX","YYYYY","ZZZZZZ"),'best')


plot = axes.plot([1,2,3],[1,2,3])


pyplot.show()

Image result

Brom answered 2/4, 2011 at 21:41 Comment(1)
Color encoding is not a bad-idea, but this is for an scholarly article, which must be legible in B&W print. Thanks for sharing !Transubstantiate
C
0

I'm using mpl 3.4.3 and I am still having this issue. I should note I am using 3D subplots, perhaps that is my issue?

fig = plt.figure(figsize=(3,2))
ax = fig.add_subplot(1,2,i,projection='3d')

I feel like I have tried everything, including answers here. I just cannot get my tick labels or axis label where I want it.

Without touching the padding I have (note the zaxis label for the left plot is off the fig): enter image description here

The following pushes the labels quite far away, as expected:

ax.xaxis.labelpad = 20
ax.yaxis.labelpad = 20
ax.zaxis.labelpad = 20

enter image description here

So I figure reducing those numbers should bring them closer. The following brings the yaxis (realizations) quite close to the tick labels, but not xaxis and zaxis labels:

ax.xaxis.labelpad = 1
ax.yaxis.labelpad = 1
ax.zaxis.labelpad = 1

enter image description here

Tweaking a bit harder on xaxis and zaxis doesn't do anything:

ax.xaxis.labelpad = 0.1
ax.yaxis.labelpad = 1
ax.zaxis.labelpad = 0.001

enter image description here

Sorry this isn't an answer, but I feel like the adjustments I present here and the unexpected behavior may help stimulate an appropriate answer?

Coffeng answered 29/5, 2022 at 1:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.