Skip to content

Y-axis labels are impossible to align by baseline #1734

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
jpaalasm opened this issue Feb 2, 2013 · 11 comments
Closed

Y-axis labels are impossible to align by baseline #1734

jpaalasm opened this issue Feb 2, 2013 · 11 comments
Milestone

Comments

@jpaalasm
Copy link

jpaalasm commented Feb 2, 2013

As the example below shows, axis labels are not aligned by text baseline by default, which would be typographically correct.

import pylab

fig, ((ax1, ax2), (ax3, ax4)) = pylab.subplots(2, 2, figsize=(4,3.8))

for ax in ax1, ax2, ax3, ax4:
    ax.set_xticks([])
    ax.set_yticks([])

ax1.set_ylabel("aaaaaaaajaaaaaaa")
ax3.set_ylabel("aaaaaaaaaaaaaaaa")

ax3.set_xlabel("aaaaaaaajaaaaaaa")
ax4.set_xlabel("aaaaaaaaaaaaaaaa")

For the x-axis labels, alignment by baseline is possible to configure (code below), but it seems to be impossible to do for y-axis labels, because set_horizontalalignment("baseline") is not allowed.

ax3.xaxis.get_label().set_verticalalignment("baseline")
ax4.xaxis.get_label().set_verticalalignment("baseline")
ax3.xaxis.labelpad = 15
ax4.xaxis.labelpad = 15
@jpaalasm
Copy link
Author

Here's a screenshot that shows the incorrect label alignment.

incorrect label alignment

@pelson
Copy link
Member

pelson commented Mar 13, 2013

Because the text is rotated on the yaxis, you still want to use vertical alignment for the y labels. Adding:

ax1.yaxis.get_label().set_verticalalignment("baseline")
ax3.yaxis.get_label().set_verticalalignment("baseline")

Seems to do the trick for me. Can you confirm?

I've labelled this as a confirmed bug because this behaviour is a surprise to me - I'd be interested in seeing if we can use the baseline vertical alignment for labels as default.

Thanks for raising @jpaalasm.

@jpaalasm
Copy link
Author

Well, that does not work, because verticalalignment is not vertical with respect to the rotated text, but with respect to the figure.

It produces the following result (matplotlib 1.2.0).

verticalalignment

@pelson
Copy link
Member

pelson commented Mar 13, 2013

import pylab

fig, ((ax1, ax2), (ax3, ax4)) = pylab.subplots(2, 2, figsize=(4,3.8))

for ax in ax1, ax2, ax3, ax4:
    ax.set_xticks([])
    ax.set_yticks([])

ax1.set_ylabel("aaaaaaaajaaaaaaa")
ax3.set_ylabel("aaaaaaaaaaaaaaaa")

ax3.set_xlabel("aaaaaaaajaaaaaaa")
ax4.set_xlabel("aaaaaaaaaaaaaaaa")

ax3.xaxis.labelpad = 15
ax4.xaxis.labelpad = 15
ax4.xaxis.get_label().set_verticalalignment("baseline")
ax3.xaxis.get_label().set_verticalalignment("baseline")

ax1.yaxis.get_label().set_verticalalignment("baseline")
ax3.yaxis.get_label().set_verticalalignment("baseline")

pylab.show()

Definitely works for me. Are you using the Macos backend by any chance? Are you able to confirm that this work for you on any Agg backend (TkAgg?).

@jpaalasm
Copy link
Author

I am using TkAgg (I put "print matplotlib.get_backend()" just above pylab.show() to find out), but the figure I get is exactly the same as what I uploaded in the previous comment.

@pelson
Copy link
Member

pelson commented Mar 13, 2013

My apologies @jpaalasm - I was in the middle of doing some mpl development and wasn't able to try this out on v1.3. I can see the same behaviour in mpl v1.2.1.

Interestingly, this behaviour was changed by @pwuertz in b9fba92. I'm afraid I don't know of a workaround for using anything other than the master repository.

@pwuertz
Copy link
Contributor

pwuertz commented Mar 13, 2013

Yea, this scenario was one of the reasons why I proposed this anchored-rotation patch. With the default text rotation model up to matplotlib v1.2 the rotated text is aligned by its bounding box in the un-rotated system. There is no way to define a baseline there.

There should be a workaround for v1.2 by applying the same settings found in b9fba92. Try something like this:

ylabel = ax1.yaxis.get_label()
ylabel.set_rotation_mode('anchor')
ylabel.set_va('baseline')
ylabel.set_ha('center')
ylabel.set_rotation('vertical')

Hopefully this works for you, but be aware that this change may trigger some bugs. I remember one or two follow-up patches that had to be applied to v1.3.

@pwuertz pwuertz closed this as completed Mar 13, 2013
@pwuertz pwuertz reopened this Mar 13, 2013
@pwuertz
Copy link
Contributor

pwuertz commented Mar 13, 2013

(sorry wrong button)

@pwuertz
Copy link
Contributor

pwuertz commented Mar 13, 2013

@pelson I guess the reason for not making baseline the default alignment is that matplotlib uses a fixed layout by default. So if you set 'baseline' instead of 'top' for the xlabel and include some huge symbol (maybe an integral sign), it will probably collide with the graph or the ticks. You'd have to use tight_layout for more reliable positioning.

@mdboom
Copy link
Member

mdboom commented May 21, 2013

It seems that setting the va to baseline works on master, so I think we can consider this closed. @jpaalasm, @pwuertz: do you agree?

We probably will want to move to using baseline as the default in a future release of matplotlib. Maybe we should create a new 1.4.x targetted issue for that?

@pwuertz
Copy link
Contributor

pwuertz commented May 22, 2013

@mdboom: Agreed. With anchored rotation as the default this issue is solved.
A new issue for 1.4.x could discuss the side-effects I raised above concerning default-baseline.

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

No branches or pull requests

4 participants