Skip to content

Implement PdfPages for backend pgf #10548

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

Merged
merged 26 commits into from
Feb 28, 2018
Merged

Conversation

maxnoe
Copy link
Contributor

@maxnoe maxnoe commented Feb 20, 2018

PR Summary

This adds a PdfPages class for backend_pgf analogous to the one in backend_pdf to be able to use the pgf backend with multi page pdfs.

Looking forward to reviews

PR Checklist

  • Has Pytest style unit tests
  • Code is PEP 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

for `'Creator'`, `'Producer'` and `'CreationDate'`. They
can be removed by setting them to `None`.
"""
self.outputfile = filename
Copy link
Contributor

Choose a reason for hiding this comment

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

all these attributes should be private unless you explicitly have a reason to make some public.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure

@anntzer
Copy link
Contributor

anntzer commented Feb 20, 2018

Would be nice to see how hard it is to implement a single MultiPage context for all relevant backends by adding the right methods to the RendererFoo classes. See e.g. https://github.com/anntzer/mplcairo/blob/master/lib/mplcairo/multipage.py as well.

But that may be too hard and a separate PR like this can work too.

@jkseppan
Copy link
Member

Yes, a generic multipage interface would be nice, but I wouldn't make it a requirement for this PR. Similarly, I wouldn't worry about implementing pdf metadata in the first version, just note in the documentation that it's not yet supported. The LaTeX hyperref package is probably the way to go for implementing that.

@jkseppan
Copy link
Member

We have tests that check that the output matches a baseline image. I think they currently exist only for the agg, pdf and svg backends, and I wouldn't really call them unit tests since they produce a complete output file and check the output. See https://github.com/matplotlib/matplotlib/tree/master/lib/matplotlib/testing for the infrastructure for the comparison tests. You could extend the pdf conversion to support multipage files, but that might get somewhat tricky.

'_file',
)

def __init__(self, filename, keep_empty=True, metadata=None):
Copy link
Contributor

Choose a reason for hiding this comment

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

probably arguments after filename can be made keyword only

"""
self._outputfile = filename
self._n_figures = 0
self.keep_empty = keep_empty
Copy link
Contributor

Choose a reason for hiding this comment

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

would make private too

Finalize this object, running LaTeX in a temporary directory
and moving the final pdf file to `filename`.
"""
self._file.write(r'\end{document}'.encode('utf-8') + b'\n')
Copy link
Contributor

Choose a reason for hiding this comment

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

just use a single literal bytestring

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 21, 2018

I implemented your comments and setting metadata using hyperref

@maxnoe maxnoe changed the title WIP: Implement PdfPages for backend pgf Implement PdfPages for backend pgf Feb 21, 2018
@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 21, 2018

The Tests fail because the file I created in doc/users/next_whats_new is nowhere included. Where should it be included or what should I change?

@jkseppan
Copy link
Member

Add something like this: 2124ac8

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 21, 2018

Now the test fails because the lualatex version on travis is ancient. Any idea what to do about that? Edit the requires_lualatex decorator so it also checks for a version?

@jkseppan
Copy link
Member

Installing a newer TeX Live on Travis is a possibility but it sounds like it would really slow down the build. Does Appveyor have a sufficiently new luatex? If so, I think we could just check the version and skip the test if it is too old.

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 23, 2018

The failing Test Looks unrelated. Any idea what happened there? @jkseppan

@jkseppan
Copy link
Member

Yes, the failure looks unrelated. I restarted the test to see if it happens again.

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 23, 2018

@jkseppan Ok thanks. The tests are passing now.

return parse_lualatex_version(output.decode())


def parse_lualatex_version(output):
Copy link
Contributor

Choose a reason for hiding this comment

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

that probably doesn't need to be public

@@ -49,13 +51,31 @@
except:
warnings.warn('error getting fonts from fc-list', UserWarning)


luatex_version_re = re.compile(
Copy link
Contributor

Choose a reason for hiding this comment

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

that definitely doesn't need to be public

def get_texcommand():
"""Get chosen TeX system from rc."""
texsystem_options = ["xelatex", "lualatex", "pdflatex"]
texsystem = rcParams["pgf.texsystem"]
return texsystem if texsystem in texsystem_options else "xelatex"


def get_lualatex_version():
Copy link
Contributor

Choose a reason for hiding this comment

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

Note to other devs: would be nice to get #9571/#9639 merged first and integrate this version checking into that framework.

In the meantime, this function could(?) stay private.

@jkseppan
Copy link
Member

@maxnoe Just in case it's not obvious: I think what @anntzer means by public vs private is that the indicated functions and variables could be named starting with an underscore (_luatex_version_re, etc) so that users of Matplotlib don't come to depend on them directly.

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 24, 2018

@anntzer I made all the version functions/attributes private

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 27, 2018

@anntzer @jkseppan I resolved the conflicts

@maxnoe
Copy link
Contributor Author

maxnoe commented Feb 27, 2018

@anntzer @jkseppan The tests are passing again

latex_header = r"""\PassOptionsToPackage{{
{metadata}
}}{{hyperref}}
\RequirePackage{{hyperref}}
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason why it's not a standard "usepackage[...]{hyperref}"? (perhaps, I dunno)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because People might use hyperref in their rc params latex header and like this it avoids the "hyperref loaded with incompatible options" error

Copy link
Contributor

Choose a reason for hiding this comment

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

so that's equivalent to "if hyperref is already loaded by the preamble, then merge these options with those passed in the preamble"? (again, just asking)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, and the user specified options take precedence.

if self._n_figures == 0:
self._write_header(*figure.get_size_inches())
else:
if get_texcommand() == 'lualatex':
Copy link
Contributor

Choose a reason for hiding this comment

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

if get_texcommand == lualated and get_lualatex_version > ...?

np = r'\newpage\pdfpagewidth={}in\pdfpageheight={}in%'
self._file.write(np.format(
*figure.get_size_inches()
).encode('utf-8') + b'\n'
Copy link
Contributor

Choose a reason for hiding this comment

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

just include the newline in the format-string above?
here it may make sense to just use a bytes literal and %-interpolation

@@ -40,6 +41,8 @@ def check_for(texsystem):
reason='xelatex + pgf is required')
needs_pdflatex = pytest.mark.skipif(not check_for('pdflatex'),
reason='pdflatex + pgf is required')
needs_lualatex = pytest.mark.skipif(not check_for('lualatex'),
reason='lualatex + pgf is required')
Copy link
Contributor

Choose a reason for hiding this comment

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

indent

@@ -56,6 +56,30 @@

.. _pgf-rcfonts:


Multi-Page PDF Files
Copy link
Contributor

Choose a reason for hiding this comment

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

add entries to doc/api/howto_faq (which mentions the old pdfpages) and examples/misc/multipage_pdf?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@anntzer anntzer merged commit a2db882 into matplotlib:master Feb 28, 2018
@anntzer
Copy link
Contributor

anntzer commented Feb 28, 2018

Thanks for the PR!

@anntzer
Copy link
Contributor

anntzer commented Feb 28, 2018

@meeseeksdev backport to v3.0

@anntzer anntzer added this to the v3.0 milestone Feb 28, 2018
@maxnoe maxnoe deleted the pgf_pdf_pages branch February 28, 2018 09:11
@lumberbot-app
Copy link

lumberbot-app bot commented Feb 28, 2018

Something went wrong ... Please have a look at my logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants