Introduction#
aastex lets you write an article for the journals of the American
Astronomical Society as a Python program.
It extends PyLaTeX with the pieces of the
AASTeX LaTeX package
that a manuscript needs: titles, authors and their affiliations, acronyms,
sections, figures, and bibliographies.
In an ordinary manuscript, the numbers quoted in the prose and the figures printed beside them are copied out of an analysis by hand, and they begin to drift from that analysis as soon as it changes. Writing the article as a program removes the copying step. Figures are drawn by the same code that produced the result, and quantities are declared as LaTeX macros computed from Python values, so the text cannot disagree with the analysis behind it.
Since aastex is built on PyLaTeX, anything that library can express is
available here as well;
see the PyLaTeX documentation
for the underlying model of documents, environments, and commands.
Installation#
aastex is available on PyPI and can be installed using pip:
pip install aastex
Compiling an article also requires a LaTeX installation providing the dependencies of the AASTeX class. On Debian and Ubuntu:
sudo apt-get install texlive-publishers texlive-science cm-super latexmk
Writing an article#
The example below builds a small but complete article, one piece at a time.
Each step appends to the same aastex.Document, which is compiled at the
end.
Start by configuring matplotlib to render text with LaTeX, so that the
figures use the same fonts as the surrounding article, and create the document.
aastex.Document defaults to the AASTeX class in its two column style.
import pathlib
import numpy as np
import matplotlib.pyplot as plt
import astropy.units as u
import astropy.constants
import aastex
plt.rcParams['text.usetex'] = True
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.size'] = 9
plt.rcParams['lines.linewidth'] = 1
doc = aastex.Document()
Every article needs a title, and one or more authors.
An aastex.Author carries an aastex.Affiliation, and optionally
an ORCID and an email address, which AASTeX prints in the front matter.
title = aastex.Title("An Interesting Article")
doc.append(title)
msu = aastex.Affiliation(
'Montana State University, Department of Physics, '
'P.O. Box 173840, Bozeman, MT 59717, USA'
)
author = aastex.Author(
name='Roy T. Smart',
affiliation=msu,
email="roytsmart@gmail.com",
corresponding=True,
)
doc.append(author)
An aastex.Acronym is defined once and then used in the prose through a
macro named after it, \NASA in this case.
The first use in the text expands to the full phrase followed by the
abbreviation, and later uses give the abbreviation alone, so the convention is
applied for you no matter how the text is later rearranged.
nasa = aastex.Acronym("NASA", "National Aeronautics and Space Administration")
doc.preamble.append(nasa)
The abstract is a container like any other section of the document, so text is
appended to it.
Here the LaTeX lipsum package provides placeholder prose.
abstract = aastex.Abstract()
abstract.packages.append(aastex.Package("lipsum"))
abstract.append("Some text summarizing the article. ")
abstract.append(r"\lipsum[1-1]")
doc.append(abstract)
This is the step that keeps the article honest.
aastex.Document.set_variable_quantity() defines a LaTeX macro from an
astropy.units.Quantity, formatting the value and its units, so the
prose can cite \speedOfLight instead of a number typed by hand.
Recompute the value and the article follows.
doc.set_variable_quantity(
name="speedOfLight",
value=astropy.constants.c.to(u.km / u.s),
scientific_notation=True,
digits_after_decimal=4,
)
Figures are created from matplotlib figures using
aastex.Figure.add_fig().
The label given to aastex.Figure names both the LaTeX label and the
image file saved next to the article, and the plot may be closed once it has
been added, since it is not saved until the document is compiled.
The constants aastex.column_width_inches and
aastex.text_width_inches give the width of a column and of the full page,
which are the two useful figure widths in a two column article.
fig, ax = plt.subplots(
figsize=(aastex.column_width_inches, 2),
constrained_layout=True,
)
x = np.linspace(-6, 6, num=101)[..., np.newaxis]
y = np.sinc(x) + np.random.normal(scale=0.1, size=(101, 11))
ax.plot(*np.broadcast_arrays(x, y))
figure = aastex.Figure("data")
figure.add_fig(fig, width=None)
plt.close(fig)
figure.add_caption(aastex.NoEscape(
r"Here is a figure caption. \lipsum[5-5]"
))
Now the body of the article.
Note how the section and the figure are formatted into the string:
aastex.Section and aastex.Figure render as references to
themselves, so numbering is never written by hand and never goes stale when the
document is reordered.
The acronym and the variable defined above are used here as \NASA and
\speedOfLight.
intro = aastex.Section("Introduction")
intro.packages.append(aastex.Package("lipsum"))
intro.append(
rf"Here is a citation \citep{{knuth:1984}}. "
rf"The speed of light is \speedOfLight. "
rf"Here is a reference to Section {intro}. "
rf"Here is a reference to Figure {figure}. "
rf"Here is an acronym: \NASA. "
rf"Here is the acronym again: \NASA. "
rf"\lipsum[2-2]"
)
intro.append(figure)
intro.append(r"\lipsum[3-5]")
doc.append(intro)
Finally the bibliography, which reads the BibTeX file sources.bib sitting
beside the article, and resolves the citation used above.
doc.append(aastex.Bibliography("sources"))
aastex.Document.generate_pdf() writes the .tex file, saves each figure
next to it, copies in the AASTeX class and bibliography style, and runs LaTeX.
path_pdf = pathlib.Path("an_interesting_article.pdf")
doc.generate_pdf(filepath=path_pdf.with_suffix(""))
Which outputs the following PDF:
Preparing a submission#
The AAS submission system
requires every file of a manuscript to sit at the same directory level, since it
cannot parse subdirectories.
aastex.Document.generate_archive() compiles the article and gathers the
.tex file, the .bbl file required by the AAS conversion software, the
AASTeX class and bibliography style files, and every figure into a flat archive
which is ready to upload:
doc.generate_archive(
pathlib.Path("an_interesting_article"),
bibliography="sources.bib",
)
Pass format="gztar" for a .tar.gz archive instead of a .zip.
API Reference#
Write AAS journal articles as Python programs. |