Cairo + plot_date = misaligned x-axis labels #1810

Merged
merged 5 commits into from Apr 19, 2013

6 participants

@jsundram

On OSX 10.8.2, using the cairo backend along with plot_date leads to misaligned x-axis labels. No combination I found of setting the verticalalignment of the label (top, bottom, baseline, etc), solved this problem.

Here's a screenshot of the issue (Notice the vertical alignment of April & May).

bug

Here's a gist with minimal code to reproduce the issue. It contains all the info about my matplotlib version, setup, etc. that should be needed.

https://gist.github.com/jsundram/5096973

@jakevdp

I can reproduce on MacOSX backend. No idea what would be causing this

@ivanov
Matplotlib Developers member

we've been trying to figure this out with @jsundram and have concluded that the issue goes back to at least 1.0.0, which means this has probably always been the behavior.

The likely culprit is the fact that some months have various combinations of ascenders and descenders (some have one but not the other, some have both, etc). This is also not limited to the Cairo backend - I'm seeing it on Agg as well, and not only on OS X - I'm running Debian

@ivanov
Matplotlib Developers member

partial improvement: [l.set_va('center') for l in ax.get_xticklabels()]

@ivanov
Matplotlib Developers member

pinging @mdboom and @efiring who did some of the work in axis.py related to ticklabeling and may have deeper understanding of this problem

@mdboom
Matplotlib Developers member

Yes -- this problem has existed at least as long as I've been on the scene. The solutions are all rather tricky given how text is laid out in matplotlib, but maybe it's time to look at this anew.

@mdboom
Matplotlib Developers member

Ok -- I think I was confused -- the rendering is fine on Agg as far as I can tell. @ivanov: can you attach a PNG here showing the problematic output you're seeing with Agg?

There is a legitimate bug in Cairo -- it is not taking the descent into account when placing the text. I suspect the Mac OSX backend is doing the same thing, based on looking at the source code.

I think the correct way to fix this is to update all of the backends to assume the text position is always the baseline, not the bottom of the text's bounding box. That's the natural way that most of the backend formats want to work anyway -- the only exception there is Agg, but it should be easy enough to reverse its behavior. Expect a PR shortly. Can I get a volunteer to test Mac OS-X for me?

@jsundram

@mdboom, I'll be happy to test.

@mdboom mdboom added a commit to mdboom/matplotlib that referenced this pull request Apr 15, 2013
@mdboom mdboom Fix #1810: Fix vertical text alignment in the Cairo and OS-X backends.
The renderer backends' draw_text method is now passed the location of
the text baseline, not the bottom of the text bounding box.
4aed809
@mdboom
Matplotlib Developers member

I've attached a fix to this PR. Rather than taking the easy way out, I took the opportunity to fix this once and for all. Backends are now passed the location of the baseline of the text, rather than the bottom of the bounding box. The only backend that really "natively" wants the latter is the Agg backend, and it now has code to compensate. All other backends have been simplified as a result.

To all: I've created a script that will help diagnose alignment problems (it's also included in this PR as a test). If I'm asking for help testing, please make sure that the output of Agg matches the output of the backend in question.

https://gist.github.com/mdboom/5391801

@jsundram: Would you mind testing the OS-X backend? It should require no changes to the backend itself, as the text layout engine should now be passing it what it wants. This should also address the original issue with the Cairo backend, which I have verified on Linux.

@pwuertz: Can you confirm that I didn't hose something with the PGF backend?

@ivanov: Are you still seeing misaligned text in the Agg backend?

@pelson pelson commented on the diff Apr 16, 2013
lib/matplotlib/backends/backend_agg.py
@@ -154,8 +154,10 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
ox, oy, width, height, descent, font_image, used_characters = \
self.mathtext_parser.parse(s, self.dpi, prop)
- x = np.round(x + ox)
- y = np.round(y - oy)
+ xd = descent * np.sin(angle / (180.0 * np.pi))
@pelson
Matplotlib Developers member
pelson added a line comment Apr 16, 2013

I'm not sure if np.deg2rad is preferable here... it might even be quicker (untested).

@mdboom
Matplotlib Developers member
mdboom added a line comment Apr 16, 2013

Sure. Forgot about that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson
Matplotlib Developers member

In terms of code, this is a really good simplification. If the others find this improves the situation on all of the other backends, I'm 👍 . Nice work @mdboom!

@pwuertz

The change to the PGF backend is looking fine to me and the alignment test script reproduces the results from AGG 👍.

@mdboom
Matplotlib Developers member

@jsundram: Would you mind confirming this branch fixes things in the macosx backend as well as in the originally reported Cairo backend? (I've confirmed the latter on Linux, but more confirmation is never a bad thing).

@jsundram

@mdboom, sure. I'm taking a look at it right now.

@jsundram

@mdboom, it's possible I did something wrong, but this doesn't work for me.

I modified alignment.py (I forked your gist; my version is here: https://gist.github.com/jsundram/5422685) and then:

  1. Ran alignment.py on my existing matplotlib with agg, macosx, and cairo, and stored the output in a folder called "before".
  2. Manually delete matplotlib from site-packages (found the directory via python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib()))
  3. Confirm that matplotlib doesn't exist on my system by attempting to rerun alignment.py. I get the expected ImportError: No module named matplotlib
  4. git clone https://github.com/mdboom/matplotlib.git 1810/
  5. cd 1810
  6. git checkout -b text-baseline-api
  7. python setup.py install
  8. rerun alignment.py with agg, macosx, cairo as backend arguments, store the output in a folder called "after".

Cairo still looks wrong. There are two problems: The summations signs (capital sigmas) show up as Xs, which is unrelated. But if you look at the baseline-aligned text, it shows up underneath the baseline.

cairo

I also tested with https://gist.github.com/jsundram/5096973 to see if the behavior I had originally reported has changed. It hasn't. I did test that script with macosx and agg backends, and they look fine.

In conclusion: something is still broken in Cairo on OSX unless I did something wrong.

@mdboom
Matplotlib Developers member

It looks like your step 6. may be incorrect above. That will create a new branch by that name and give it the same contents as master. I think you instead just want to do git checkout text-baseline-api.

As you note, the Cairo backend has never had working mathtext support, so you can completely ignore the top line in the image for Cairo.

@jsundram

@mdboom, whoops. I reran alignment.py this time with your changes, and all looks good with macosx and cairo backends. This also fixes my original failing test.

Thank you!

cairo

@mdboom
Matplotlib Developers member

Great! I'm glad it was that simple.

Thanks for reporting and your help on this.

@mdboom mdboom merged commit eab2a9e into matplotlib:master Apr 19, 2013

1 check passed

Details default The Travis build passed
@mdboom mdboom added a commit to mdboom/matplotlib that referenced this pull request May 15, 2013
@mdboom mdboom Fix #2015: After the baseline refactoring in #1810, baseline handling…
… was broken for text.usetex = True. This brings it inline with everything else (where the assumption is that y == 0 is the baseline and not the bottom).
48ad92a
@mdboom mdboom deleted the mdboom:text-baseline-api branch Aug 7, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment