Skip to content

Commit

Permalink
Added function to directly get the format from LaTeX
Browse files Browse the repository at this point in the history
  • Loading branch information
loreucci committed Oct 21, 2021
1 parent dfdf3fd commit 0f476da
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
3 changes: 3 additions & 0 deletions docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ specified with the ``documentclass`` command, like in

\documentclass[letterpaper, 10pt]{article}

All these values can be gathered directly from the LaTeX processor, using
:func:`matplotlib_latex_bridge.get_format_from_latex`, if a working LaTeX installation is present.

A more fine-grained control over the font sizes can be achieved by using :func:`matplotlib_latex_bridge.set_font_sizes`
and :func:`matplotlib_latex_bridge.set_font_family`.

Expand Down
6 changes: 6 additions & 0 deletions docs/source/matplotlib_latex_bridge.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ in the initial setup.
.. autofunction:: figure_textwidth

.. autofunction:: figure

Getting format from LaTeX
-------------------------
This function can be used to get format informations directly from LaTeX, but requires a working LaTeX installation.

.. autofunction:: get_format_from_latex
3 changes: 2 additions & 1 deletion src/matplotlib_latex_bridge/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from .matplotlib_latex_bridge import setup_page,\
set_font_sizes, set_font_family,\
set_default_figsize, get_default_figsize,\
figure_columnwidth, figure_textwidth, figure
figure_columnwidth, figure_textwidth, figure, \
get_format_from_latex

import matplotlib_latex_bridge.formats

Expand Down
102 changes: 102 additions & 0 deletions src/matplotlib_latex_bridge/matplotlib_latex_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
import matplotlib.pyplot as plt
import os
import sys
import re
import subprocess
import tempfile
import shutil


mlb_initialized = False
Expand Down Expand Up @@ -225,3 +229,101 @@ def figure(width=None, height=None, **kwargs):
print("Requested width ({}) is larger that textwidth ({})".format(w, mlb_textwidth), file=sys.stderr)

return plt.figure(figsize=(w, h), **kwargs)


def get_format_from_latex(documentclass, columns=None, papersize=None, fontsize=None, otheroptions=None):
"""
Get the format by invoking the LaTeX processor
This functions compiles a sample file with the LaTeX processor and parse its output to get information about
text and column widths and fontsize.
The output of this function can be directly used to setup the page.
Using this function requires a working LaTeX installation.
:param documentclass: layout standard to use (ex. article, report, book, ...)
:param columns: number of columns (ex. twocolumn)
:param papersize: size of the paper (ex. a4paper, letterpaper, ...)
:param fontsize: size of the font (ex. 10pt, 11pt, 12pt)
:param otheroptions: comma-separated additional options
:return: dictionary with textwidth, columnwidth and fontsize
"""

# check for LaTeX
haslatex = any((os.access(os.path.join(path, "latex"), os.X_OK) and os.path.isfile(os.path.join(path, "latex")))
for path in os.environ["PATH"].split(os.pathsep))

if not haslatex:
raise RuntimeError("No LaTeX installation found")

# build file content
options = ""
if columns:
options = options + str(columns) + ","
if papersize:
options = options + str(papersize) + ","
if fontsize:
if type(fontsize) != str:
options = options + str(fontsize) + "pt,"
else:
options = options + fontsize + ","
if otheroptions:
options = otheroptions + otheroptions
latex_file_content = r"\documentclass[{options}]{{{documentclass}}}".format(documentclass=documentclass,
options=options) + \
r"""
\usepackage{layouts}
\begin{document}
textwidth: \printinunitsof{in}\prntlen{\textwidth}
\message{textwidth: \prntlen{\textwidth}^^J}
columnwidth: \printinunitsof{in}\prntlen{\columnwidth}
\message{columnwidth: \prntlen{\columnwidth}^^J}
\message{fontsize: \the\font^^J}
\end{document}
"""

# create temporary directory to run latex
tmpdir = tempfile.mkdtemp()

# write latex file
with open(tmpdir + "/file.tex", "w") as texfile:
texfile.write(latex_file_content)

# run latex
latex_output = subprocess.check_output(["latex", "file.tex"], cwd=tmpdir).decode()

shutil.rmtree(tmpdir)

latex_output = latex_output.replace("\n", "")

# find widths
twr = re.compile(r"\\relax ([0-9]+\.[0-9]+)in")
m = twr.findall(latex_output)

if len(m) != 2:
raise RuntimeError("Something went wrong with the execution of LaTeX")

textwidth = float(m[0])
columnwidth = float(m[1])

# find font size
fr = re.compile(r"fontsize:.*/([0-9]+\.?[0-9]*)")
m = fr.search(latex_output)

if m is None:
raise RuntimeError("Something went wrong with the execution of LaTeX")

fontsize = float(m.groups()[0])

return {
"textwidth": textwidth,
"columnwidth": columnwidth,
"fontsize": fontsize
}
14 changes: 14 additions & 0 deletions tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,19 @@ def test_width_percentage_error(self, mock_stderr):
self.assertIn("Invalid percentual width", mock_stderr.getvalue())


class TestLatex(unittest.TestCase):

def test_format_from_latex(self):

fmt = mlb.get_format_from_latex(documentclass="article",
columns="twocolumn",
papersize="letterpaper",
fontsize=12)

self.assertAlmostEqual(fmt["textwidth"], 6.49083)
self.assertAlmostEqual(fmt["columnwidth"], 3.17621)
self.assertAlmostEqual(fmt["fontsize"], 12)


if __name__ == '__main__':
unittest.main()

0 comments on commit 0f476da

Please sign in to comment.