Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

PGF: Consistently set LaTeX document font size#26893

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
anntzer merged 9 commits intomatplotlib:mainfromSocob:fix-pgf-fontsize
May 7, 2024

Conversation

Socob
Copy link
Contributor

PR summary

Currently, when using the PGF backend, different LaTeX document font size settings are used when measuring widths vs. producing output. Although this is usually not a problem (since all text produced by the PGF backend locally sets the font properties), packages used in the custom preamble (such asunicode-math) may depend on the font size settings, leading to incorrect width measurements since different outcomes are produced in the two cases. This fixes the issue by always setting the LaTeX font size to the rc settingfont.size.

Closes#26892.

PR checklist

voidstarstar reacted with thumbs up emoji
This could cause a mismatch between lengths when measuring vs.producing output for things that depend on the font size setting atthe beginning of the document, e.g. unicode-math.Use \documentclass{article} without options here, which defaults toa font size of 10pt (same as the matplotlib rc default forfont.size).
This allows the output .pgf file to be used in external documentswith arbitrary font size settings (which should match the rc settingfont.size). This avoids mismatches between matplotlib and externalLaTeX documents for things that depend on the font size setting (e.g.unicode-math).If the LaTeX package scrextend is present, this also adjusts thestandard LaTeX font commands (\tiny, ..., \normalsize, ..., \Huge)relative to font.size.
Copy link

@github-actionsgithub-actionsbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join uson gitter for real-time discussion.

For details on testing, writing docs, and our review process, please seethe developer guide

We strive to be a welcoming and open project. Please follow ourCode of Conduct.

@Socob
Copy link
ContributorAuthor

Not sure what’s going on with the flake8 test thing – it doesn’t look like I changed anything about blank lines where it’s complaining.

Copy link
Member

@oscargusoscargus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think this looks good!

However, it may be worthwhile adding an image test to confirm that the new behavior is kept.

Also, it may be that one will need to installscrextend in the CI to get it going (not sure if it is included in any standard distribution or not).

Finally, it may be helpful to add a note that this will work better ifscrextend is available. Maybe as an additional bullet at the end ofhttps://github.com/matplotlib/matplotlib/blob/main/galleries/users_explain/text/pgf.py
(https://matplotlib.org/stable/users/explain/text/pgf.html)

@Socob
Copy link
ContributorAuthor

Socob commentedOct 3, 2023
edited
Loading

However, it may be worthwhile adding an image test to confirm that the new behavior is kept.

Sounds like a good idea – I’ll get on that.

Also, it may be that one will need to installscrextend in the CI to get it going (not sure if it is included in any standard distribution or not).

scrextend is part of the KOMA Script bundle, which is very widely used. In TeX Live, it’s part ofcollection-latexrecommended, the same asfontspec andunderscore which are currently already loaded unconditionally. So normally, it should be present if the other two are.

Either way, the use ofscrextend is really just to set up the font size commands\tiny, ...,\normalsize, ...,\Huge with sensible values. I don’t think these are commonly used, and the fallback takes care of the one that really matters when it comes to this issue (\normalsize).

Finally, it may be helpful to add a note that this will work better ifscrextend is available. Maybe as an additional bullet at the end ofhttps://github.com/matplotlib/matplotlib/blob/main/galleries/users_explain/text/pgf.py (https://matplotlib.org/stable/users/explain/text/pgf.html)

Not sure if this is necessary given the use offontspec andunderscore (see above)? The only reason I added the\IfFileExists check is really just becausescrextend is not absolutelynecessary to fix the main issue, and I wanted to assume as little as possible about the user’s TeX installation.

@SocobSocobforce-pushed thefix-pgf-fontsize branch 3 times, most recently from3a4a86e toab50f7eCompareOctober 3, 2023 19:44
@oscargus
Copy link
Member

Then it should be fine I think!

(Or rather, it would be nice that the required packages are explicitly stated somewhere, I may have missed it though, but this PR doesn't strictly add something to that.)

@tacaswell
Copy link
Member

@pwuertz Do you have bandwidth to review this?

@SocobSocobforce-pushed thefix-pgf-fontsize branch 2 times, most recently from010af0d to0fec213CompareApril 22, 2024 19:20
@Socob
Copy link
ContributorAuthor

I’ve made the last requested change and rebased. So presumably it’s ready to merge?

@voidstarstar
Copy link

I think that thedocumentclass is also set intexmanager.py for use with theusetex flag. In the future, should_DOCUMENTCLASS cover this as well?

r"\documentclass{article}",

@Socob
Copy link
ContributorAuthor

Sincetexmanager.py is used for a completely different purpose, I didn’t touch it. I also don’t think thattexmanager.py and PGF should necessarily use the same\documentclass.

voidstarstar and timhoffm reacted with thumbs up emoji

@Socob
Copy link
ContributorAuthor

Once again added all requested changes!

voidstarstar reacted with hooray emoji

@Socob
Copy link
ContributorAuthor

Is there anything else that needs to be done? I don’t know what the codecov test is complaining about, nothing in there looks related to my changes.

*([
r"\ifdefined\pdftexversion\else % non-pdftex case.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Is there a reason for the change here and immediately below?

Copy link
ContributorAuthor

@SocobSocobMay 2, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

That’s14a5900. I guess it’s only tangentially related to the rest of this PR, but I noticed that\usepackage{fontspec} was always included in the preamble, which is not necessarily desirable when doing custom font setup (i. e.pgf.rcfonts=False).

voidstarstar reacted with thumbs up emoji

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think the ability to exclude\usepackage{fontspec} is a very good improvement. It's sometimes necessary for consistency.From the documentation it sounds likefontspec should only be used whenpgf.rcfonts=True, so this looks like an additional bugfix to me.

r" \%s{%s}[Path=\detokenize{%s/}]"
% (command, path.name, path.parent.as_posix())
for command, path in zip(
["setmainfont", "setsansfont", "setmonofont"],
[pathlib.Path(fm.findfont(family))
for family in ["serif", "sans\\-serif", "monospace"]]
)
] if mpl.rcParams["pgf.rcfonts"] else []),
r"\fi",
] + [r"\fi"] if mpl.rcParams["pgf.rcfonts"] else []),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

... i.e. here?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

See above.

@@ -185,7 +205,7 @@ class LatexManager:
@staticmethod
def _build_latex_header():
latex_header = [
r"\documentclass{article}",
Copy link
Contributor

@anntzeranntzerMay 1, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think these could have been left as they were originally (but removing the 12pt below) no? especially considering that we may want to make the documentclass configurable in the future, which would be more awkward to do if referencing a global.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Not sure what you mean? These all have to be identical, so introducing a single name for them is just DRY. And in fact one of the first things one would do when making the documentclass configurable. I don’t see how it matters whether it’s a global constant or something else – that can always be changed with no effort. The point is to use a single variable for things that have to be the same.

)
@pytest.mark.backend('pgf')
@image_comparison(['pgf_document_font_size.pdf'], style='default', remove_text=True)
def test_document_font_size():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

  1. do you really need unicode-math for this test? I'd say it's not particularly relevant, no?
  2. you could do without the plot at all and simply use figtext() to draw text on an empty figure.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

  1. Notunicode-math specifically, no. But if I remember correctly,unicode-math (and other math font packages) select the font variant they use at package load time based on the document font size, and these variants have different metrics even for the same font size, which is what caused the original issue. So I’d either needunicode-math or some random font package with the same behavior, andunicode-math seems much more universal (especially since matplotlib already uses it by default).
  2. I suppose I could. I just took the easiest path and used the example I already had in[Bug]: PGF font size mismatch between measurement and output #26892. Let me know if you really want me to make and test a new example.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Actually, I think I was mistaken with my comment that matplotlib usesunicode-math (I was thinking offontspec). Nevertheless, the rest still applies.

@voidstarstar
Copy link

I think this PR tries to fix too much. Isn'tfixing the 12pt mismatch the only thing necessary to fix the original bug demonstrated by the code for reproduction? Everything else seems to target a slightly different bug (or bugs) that I do not know how to reproduce, but they sound to me like they might be solved by setting a customdocumentclass (see#28119).

Maybe I'm wrong, but I thought that thefont.size rcParam option was supposed to serve a different purpose than the global document text size and I'm now wondering if this PR confuses the two. I thought thatfont.size was the default size for the figure and that matplotlib providesspecial sizes relative tofont.size for this purpose already. Instead of basing the LaTeX font size commands (\tiny, etc.) onfont.size, wouldn't a better solution be to just allow the user to set their own customdocumentclass (which can include their own global document text size)? I think this would fix the implicit dependence on the size problem mentioned in the original issue.

In other words, if the user could set thedocumentclass in matplotlib to match their own customdocumentclass, wouldn't that fix this issue in a better way without needing to force the global document font size to matchfont.size?

@Socob
Copy link
ContributorAuthor

I really didn’t expect “tries to fix too much” on a PR that adds/changes 21 lines of code (excluding comments/tests/blanks)! I don’t know what you mean by “everything else” beyond adjusting the LaTeX font commands?

Since there is currently no way to set the documentclass,font.size is the only available information on what the user’s document font size is. The matplotlib internal sizes are probably preferable in some cases (when they can be used), but since I was setting\normalsize, I thought it’d be more consistent to adjust the other LaTeX font size commands accordingly (this is 3 lines of code in the PR). Since there is no documentation on this, users will expect that these font commands will work “as expected”, as evidenced byposts such as this one.

Sure, making the documentclass configurable may be a better way to fix this than my (minimal!) change. Feel free to write that PR!

@Socob
Copy link
ContributorAuthor

@anntzer Do my answers resolve your review comments or do you want me to change anything about the PR?

@voidstarstar
Copy link

voidstarstar commentedMay 3, 2024
edited
Loading

I really didn’t expect “tries to fix too much” on a PR that adds/changes 21 lines of code (excluding comments/tests/blanks)! I don’t know what you mean by “everything else” beyond adjusting the LaTeX font commands?

Yes, the "everything else" are the other font related changes (fixing a scope bug by defaulting to\familydefault, fixingfontspec to depend onpgf.rcfonts, and usingscrextend to set relative text sizes). To correct my previous post, these would not be fixed by#28119.

To be clear, I wasn't saying that the changes are bad or that they should not be merged. I actually think most are strong improvements and a dependency for a PR I'm currently writing too. I just did not fully understand the motivation behind thescrextend related code because I think in some cases it mightintroduce a consistency issue since it is a global setting. Thank you for the SO link, it helps me better understand the use case.

@voidstarstar
Copy link

voidstarstar commentedMay 4, 2024
edited
Loading

The following is a proof of concept of the possible consistency issue I mentioned:

LaTeX source:

\documentclass[12pt]{article}\usepackage{pgf}\begin{document}\Huge Before\input{plot.pgf}\Huge After\end{document}

Python source:

importmatplotlibmatplotlib.use("pgf")importmatplotlib.pyplotasplt# Set up PGFmatplotlib.rcParams.update({"pgf.texsystem":"lualatex","font.family":"serif","text.usetex":True,"pgf.rcfonts":False,"font.size":1,"figure.autolayout":True,"axes.labelsize":"xx-small",    })# Create some sample datax= [0,1,2,3,4]y= [0,0.2,0.4,0.1,0.3]# Create the plotfig,ax=plt.subplots(figsize=(4.5,3))ax.plot(x,y)ax.set_title("Sample Plot")ax.set_xlabel(r"\Huge X")ax.set_ylabel("Y")# Save the plotplt.savefig("plot.pgf")plt.savefig("plot.png",dpi=300)

I think the above example might demonstrate the problem I was alluding to. I use extremely big/small sizes to make the problem more obvious visually. Thefont.size is set to 1. This causesscrextend to change\Huge to be much smaller (since it's relative to 1 instead of 12). Matplotlib then internally renders the xlabelr"\Huge X" which is rendered small as expected. The problem arises when the pgf file is imported into LaTeX. The LaTeX document preamble does not includescrextend, so the xlabel is much bigger than expected and therefore is misaligned. We can't includescrextend in the preamble because it changes the font globally, which will affect the other text in the document.

My recommended solution would be to leave the\normalsize and other commands (\tiny, etc.) alone to match the LaTeX file, or if you must change them usingscrextend, do so usingpgf.preamble. Ideally, I think the plot should not rely on changing any global settings.

Sure, making the documentclass configurable may be a better way to fix this than my (minimal!) change. Feel free to write that PR!

I'm currently working on#28167 for this.

@anntzer
Copy link
Contributor

Thank you@voidstarstar for your example. I agree we can't assume that the user will indeed be using koma-script just because it happens to be present in the install (if I understood the problem you're mentioning correctly).

@Socob
Copy link
ContributorAuthor

I think there is a lot of confusion going on here. First of all,\usepackage[fontsize=<N>pt]{scrextend} has nothing to do with whether or not the user is using KOMA-Script. It simply replicates what would happen when setting the document font size, as in\documentclass[<N>pt]{article}. Now, why did I not simply pass the font size to the documentclass? Because the standard LaTeX classes, likearticle, don’t support arbitrary font sizes, wheres KOMA-Script does. Since the user cannot set the documentclass, this is the next-best thing to support as many cases as possible. (And for obvious reasons, I didn’t want to change the documentclass used by the PGF backend in this PR.)

Now, for@voidstarstar’s example: Of course, the assumption is thatthe user will setfont.size to match the font size of their document! What scenario or use case would there be where any other choice makes sense?

My recommended solution would be to leave the\normalsize and other commands (\tiny, etc.) alone to match the LaTeX file

How? matplotlib does not know anything about the user’s LaTeX file! That’s the whole point: Aligning the document font size used by the PGF backend withfont.size allows the user to control what font size is used internally by matplotlib, andto set this to match their own document! If we don’t do this, we have to arbitrarily hard-code a fixed document font size, making itimpossible to include the generated PGF in LaTeX documents with other font sizes (there are workarounds of course, see#26892).

Now, I agree that the ideal solution for this problem would be for the user to be able to set the documentclass, at which point the code I’ve added which is setting the document font size could be removed. But I just wanted to fix the immediate problem to make things workby default, without workarounds in the custom preamble when making this PR!

voidstarstar reacted with thumbs up emoji

@voidstarstar
Copy link

Now, for@voidstarstar’s example: Of course, the assumption is thatthe user will setfont.size to match the font size of their document! What scenario or use case would there be where any other choice makes sense?

This seems like the core of my confusion. Please consider the following use case:

A user is writing a LaTeX paper where the plots are somewhat small for space reasons due to journal imposed page limitations. The font size in the plots must be smaller than the document font size in order for the text to fit. By default, all of the text element sizes (axes.titlesize,axes.labelsize,xtick.labelsize,legend.fontsize, etc.) use relative sizing (large,medium, etc.). This means the user can changefont.size and the entire figure will scale proportionally. These relative sizes are converted to absolute pt sizes when writing the pgf file, so nothing is dependent upon the default document font size.

My recommended solution would be to leave the\normalsize and other commands (\tiny, etc.) alone to match the LaTeX file

How? matplotlib does not know anything about the user’s LaTeX file! That’s the whole point: Aligning the document font size used by the PGF backend withfont.size allows the user to control what font size is used internally by matplotlib, andto set this to match their own document! If we don’t do this, we have to arbitrarily hard-code a fixed document font size, making itimpossible to include the generated PGF in LaTeX documents with other font sizes (there are workarounds of course, see#26892).

The 2nd half of my sentence mentions usingpgf.preamble which is what you did in your workaround. The issue I have with making the workaround built in to matplotlib is that it breaks the use cases wherefont.size does not match the document size.

Now, I agree that the ideal solution for this problem would be for the user to be able to set the documentclass, at which point the code I’ve added which is setting the document font size could be removed. But I just wanted to fix the immediate problem to make things workby default, without workarounds in the custom preamble when making this PR!

I agree. I'm personally not opposed to this as a temporary stepping stone solution.

@Socob
Copy link
ContributorAuthor

A user is writing a LaTeX paper where the plots are somewhat small for space reasons due to journal imposed page limitations. The font size in the plots must be smaller than the document font size in order for the text to fit. By default, all of the text element sizes (axes.titlesize,axes.labelsize,xtick.labelsize,legend.fontsize, etc.) use relative sizing (large,medium, etc.). This means the user can changefont.size and the entire figure will scale proportionally. These relative sizes are converted to absolute pt sizes when writing the pgf file, so nothing is dependent upon the default document font size.

Setting the document font size doesn’t impair this use case at all. You can still setfont.size to something other than the final LaTeX document’s font size; there is only a problem if you’re doing something that’s inherently tied to the document font size, such as using LaTeX font size commands in the plot or using a package likeunicode-math. Clearly, by using these, you’re necessarily introducing a dependence on the document font size into your plot. Only in this case, you have to setfont.size to match your document font size. And in this scenario, I do have a hard time imagining how any other setting could make sense.

Let’s also keep in mind that you’dalways have this problem with a hard-coded document font size (unless your document’s font size just happened to match the matplotlib-internal one), so I don’t see any alternative!

voidstarstar reacted with thumbs up emoji

@voidstarstar
Copy link

Let’s also keep in mind that you’dalways have this problem with a hard-coded document font size (unless your document’s font size just happened to match the matplotlib-internal one), so I don’t see any alternative!

That's a very good point, I agree. The hard-coded document font size is really the core issue, not your code. Your code at least has the benefit of allowing the user to setfont.size to havesome control over it. Until the hard-codeddocumentclass is removed, there will always besome use case that will be broken and the one you are targeting would also benefit more users.

Sorry about the confusion, you are correct. I retract my example/problem mentioned above. This PR has my 👍 (for whatever that's worth).

So it sounds to me like the best course of action would be:

  1. First,PGF: Consistently set LaTeX document font size #26893 (this PR) gets merged.
  2. Then, the temporaryscrextend code introduced by this PR should be removed inAllow custom documentclass for pgf backend #28167 and replaced with a fully customizabledocumentclass.
  3. Finally,Allow custom documentclass for pgf backend #28167 gets merged.

@voidstarstar
Copy link

Thank you@voidstarstar for your example. I agree we can't assume that the user will indeed be using koma-script just because it happens to be present in the install (if I understood the problem you're mentioning correctly).

@anntzer The problem I was mentioning was not really an issue with this PR, but rather an consequence of having a hard-codeddocumentclass. As@Socob mentioned (and I agree with), the code in this PR does not assume koma-script is being used. The command for conveniently changing the default sizes just happens to be part of that library, but seems to be often used on its own. Please disregard my previous objection and example code. My opinion is now LGTM!

Copy link
Contributor

@anntzeranntzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

OK, this seems reasonable in any case and I'll trust@voidstarstar on the details.

voidstarstar reacted with hooray emoji
@anntzeranntzer merged commitbc13abf intomatplotlib:mainMay 7, 2024
43 of 44 checks passed
@anntzeranntzer added this to thev3.10.0 milestoneMay 7, 2024
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@timhoffmtimhoffmtimhoffm left review comments

@voidstarstarvoidstarstarvoidstarstar left review comments

@github-actionsgithub-actions[bot]github-actions[bot] left review comments

@anntzeranntzeranntzer approved these changes

@oscargusoscargusoscargus approved these changes

Assignees
No one assigned
Projects
Status: Waiting for author
Milestone
v3.10.0
Development

Successfully merging this pull request may close these issues.

[Bug]: PGF font size mismatch between measurement and output
6 participants
@Socob@oscargus@tacaswell@voidstarstar@anntzer@timhoffm

[8]ページ先頭

©2009-2025 Movatter.jp