Skip to content
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

[Bug]: LaTeX option clash error when pgf.preamble uses certain packages #28213

Open
voidstarstar opened this issue May 13, 2024 · 0 comments · May be fixed by #28167
Open

[Bug]: LaTeX option clash error when pgf.preamble uses certain packages #28213

voidstarstar opened this issue May 13, 2024 · 0 comments · May be fixed by #28167

Comments

@voidstarstar
Copy link

Bug summary

I think in LaTeX, if \usepackage is called multiple times for the same package, it is only actually loaded on the first call. Any desired options must be included in this first call. If a subsequent call contains different options, it will cause an "option clash" error. If a subsequent call contains no options, it will not cause this error and will silently be ignored.

Given the above mechanics, there is a bug in matplotlib. Matplotlib needs certain packages (hyperref, geometry, etc.), but there is no way to know if the user defined custom preamble (pgf.preamble) will also includes these. Currently, matplotlib loads some of these packages before and some after the custom preamble.

To reproduce the bug, a custom preamble can be created that loads all of the packages that matplotlib depends on, but passes different options to them.

Code for reproduction

import matplotlib.pyplot as plt
import matplotlib as mpl

mpl.use('pgf')
preamble = '\n'.join([
    r'\usepackage[no-math]{fontspec}',
    r'\usepackage[nohyphen]{underscore}',
    r'\usepackage[demo]{graphicx}',
    r'\usepackage[draft]{hyperref}',
    r'\usepackage[margin=1in]{geometry}',
    r'\usepackage[draft]{pgf}',
    r'\usepackage[ascii]{inputenc}',
    r'\usepackage[safe]{textcomp}',
    ])
mpl.rcParams['pgf.preamble'] = preamble

# Define the x and y data
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]

# Create a figure and axis object
fig, ax = plt.subplots()

# Plot the data
ax.plot(x, y)

# Set the title and axis labels
ax.set_title('Line Plot')
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')

# Save the plot as a PNG file
plt.savefig('plot.png')

Actual outcome

Matplotlib crashes because the LaTeX compiler produces an option clash error.

Expected outcome

Matplotlib will use the user defined options, but override them when applicable.

Additional information

Solution:

This problem can be solved using the \PassOptionsToPackage command. This command can contain the options that matplotlib requires and be called prior to the custom preamble in a pre-processing phase. Then after the custom preamble, the package can be loaded by calling \usepackage without any options in a post-processing phase.

There are 2 possible outcomes:

  1. The custom preamble does not contain the package. In this case, the post-processing phase loads the package by appending the options stated in the pre-processing phase.
  2. The custom preamble contains the package. In this case, the package will be loaded in the custom preamble by appending the options stated in the pre-processing phase. Then the post-processing phase is silently ignored.

Note: When matplotlib loads packages after the custom preamble and without any options (such as fontspec), no error will occur, so the code is fine as it is.

This issue is solved by #28167.

Operating system

Ubuntu

Matplotlib Version

3.7.5

Matplotlib Backend

pgf

Python version

3.8

Jupyter version

No response

Installation

pip

@voidstarstar voidstarstar linked a pull request May 13, 2024 that will close this issue
5 tasks
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

Successfully merging a pull request may close this issue.

1 participant