Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

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

Closed
jpaalasm opened this Issue · 11 comments

4 participants

@jpaalasm

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

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

incorrect label alignment

@pelson
Collaborator

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

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
Collaborator
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

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
Collaborator

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
Collaborator

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
@pwuertz pwuertz reopened this
@pwuertz
Collaborator

(sorry wrong button)

@pwuertz
Collaborator

@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
Owner

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
Collaborator

@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.

@mdboom mdboom closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.