matplotlib / matplotlib

matplotlib: plotting with Python
https://matplotlib.org/stable/
20.16k stars 7.61k forks source link

tight_layout and font hinting cuts text near the edge #11551

Open prekageo opened 6 years ago

prekageo commented 6 years ago

Bug report

I plot a figure with default configuration. I use 8 point fonts and tight_layout. In the resulting PDF, the x and y labels are cut.

Code for reproduction

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt

matplotlib.rcParams['font.size'] = 8
# matplotlib.rcParams['text.hinting'] = 'none' # uncomment to fix problem

plt.figure(figsize=(.5,.5))
plt.xlabel('qyg')
plt.ylabel('ETZ')
plt.yticks([])
plt.xticks([])
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().spines['left'].set_visible(False)
plt.tight_layout(pad=0)
plt.savefig('output.pdf')

Actual outcome

bad.pdf

Expected outcome

good.pdf

Matplotlib version

The font used is the default matplotlib font:

$ md5sum DejaVuSans.ttf
49c0f03ec2fa354df7002bcb6331e106  DejaVuSans.ttf

I believe that the problem is here: https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/backend_agg.py#L232 https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/backend_pdf.py#L2144

As you can see the PDF backend always uses LOAD_NO_HINTING while the Agg backend uses whatever the user specifies. The only workaround that I've found is enabling the commented out line in the testcase above.

prekageo commented 4 years ago

For anyone who might try to resolve this issue, the relevant lines of code have changed. For the current master 303d5159f62d52455ee439ea203e14e2158231a0, the lines are: https://github.com/matplotlib/matplotlib/blob/303d5159f62d52455ee439ea203e14e2158231a0/lib/matplotlib/backends/_backend_pdf_ps.py#L102 https://github.com/matplotlib/matplotlib/blob/303d5159f62d52455ee439ea203e14e2158231a0/lib/matplotlib/backends/backend_agg.py#L180

oscargus commented 2 years ago

This seems to have been solved. The current output is: image

(The black border is to make it more clear how much padding there is, indeed a bit more than in the "good.pdf" in the OP.)

prekageo commented 2 years ago

I just tested with the latest main (80015796eddd2e47013ded76718603da40192595) and I still see the same problem. Can you share your reproduction script? Maybe the border fixes the original problem?

And it looks like I do not have access to reopen this issue so tagging @oscargus if he could reopen it. Thanks!

jklymak commented 2 years ago

I can reproduce the problem with tight_layout. If you used constrained_layout, things seem better?

fig = plt.figure(figsize=(.5,.5), layout='constrained')
fig.get_layout_engine().set(h_pad=0, w_pad=0)
# don't call `plt.tight_layout`
pdf

output.pdf

which makes it a bit mysterious why tight_layout is getting the wrong bbox, as the code should be the same.

oscargus commented 2 years ago

Can you share your reproduction script? Maybe the border fixes the original problem?

Sorry, didn't see this until now. I used exactly the same script as here (without anything in the matplotlibrc file IIRC). I was a bit unclear about the border though. That is the background from the PDF viewer (Drawboard PDF, hence the black background.) Seems to work for me with Acrobat reader, Firefox, Chrome and Edge as well.

prekageo commented 2 years ago

Sorry for the delay.

@jklymak Using constrained, the problem goes away.

@oscargus I've opened the attached PDF (https://github.com/matplotlib/matplotlib/files/2155253/bad.pdf) with Acrobat, Firefox and Chrome and it renders in the same way in all 3. The letters are cut near the edge. Can you share your generated PDF? I also opened it with Drawboard online (https://pdf.drawboard.com/documents/5d847711eca34829aabf472a0db7b759) and the text is still cut.

github-actions[bot] commented 1 year ago

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

george-enf commented 1 year ago

Tested with 3.7.1. The problem is still here.

github-actions[bot] commented 2 months ago

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

prekageo commented 2 months ago

Tested with latest main (bdbbb2dc50d9cf901e78a5bbcea8f458b757650d). The problem is still here. Note that a possible solution would be the following patch:

diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc
index d419ed6..da30232 100644
--- a/lib/matplotlib/mpl-data/matplotlibrc
+++ b/lib/matplotlib/mpl-data/matplotlibrc
@@ -290,7 +290,7 @@
 ##                ("native" is a synonym.)
 ## - force_autohint: Use FreeType's auto-hinter.  ("auto" is a synonym.)
 ## - no_hinting: Disable hinting.  ("none" is a synonym.)
-#text.hinting: force_autohint
+#text.hinting: default

 #text.hinting_factor: 8  # Specifies the amount of softness for hinting in the
                          # horizontal direction.  A value of 1 will hint to full

It's worth noting that the change from LOAD_DEFAULT to LOAD_FORCE_AUTOHINT happened in commit 3299a39fff2e0143988e7112b10c3c0ae5392e10 by @mdboom.