\documentclass[12pt]{article} \usepackage{hybrid} \begin{document} \lstset{% basicstyle={\tts},basewidth={0.50em}, numbers=none,numberstyle=\tiny,numbersep=10pt, aboveskip=10pt,belowskip=0pt, frame=single,framesep=2pt,framerule=0pt} \bgcolour{grey95} \begin{center} {\Large\bf A hybrid LaTeX collection.}\\[20pt] {Leo Brewin}\\[5pt] {School of Mathematics, Monash University}\\[5pt] {\tts Leo.Brewin@monash.edu}\\[5pt] {August 2018}\\[10pt] {Version 0.1}\\[10pt] {\href{https://github.com/leo-brewin/hybrid-latex}{https://github.com/leo-brewin/hybrid-latex}}\\[20pt] {\bf\small Abstract}\\[10pt] {\small\MyPar{0.80}% {This collection of LaTeX packages and Python scripts provides simple tools to allow active Python to be embedded in a LaTeX document. It does this by defining a number of simple macros and Python scripts that build a bridge between the output generated by the active code and the LaTeX code. Each language is defined independently of the other languages. The scripts and macros for one language are almost identical to those for the other languages in the collection differing only in the names of the macros and some minor language specific tweaks. This makes it a simple matter to extend the collection to other languages.}} \end{center} \vskip 1cm \parindent=0pt \parskip=0pt plus 0pt minus 0pt \tableofcontents \vfill \clearpage \parindent=0pt \parskip=8pt plus 2pt minus 1pt \section{Introduction} Programs like Mathematica, Maple, Python and so on do a wonderful job of symbolic, numeric and graphical computations. On the other hand, LaTeX produces exceptional typeset documents but is less adept at symbolic and other forms of computation. It is a case of horses for courses. A common approach is to use one or more codes (in Python, Maple etc.) to do the computations and a separate LaTeX code to collect and document the results. It seems reasonable then to attempt to consolidate these separate codes into a single hybrid LaTeX document. That is the main purpose of this collection -- to provide tools that support active code within a LaTeX document. This document describes the CTAN version of this package. An extended version of the pacakge that allows inclusion of Python, Mathematica, Maple, Matlab and Cadabra code can be found on the {\href{https://github.com/leo-brewin/hybrid-latex}{GitHub repository}}. \section{The pyLaTeX package} There are other packages that do the same job, such as \href{https://github.com/gpoore/pythontex}{\PythonTeX} and \href{https://github.com/sagemath/sagetex}{\SageTeX}. In each case the journey from source to pdf is similar; the Python code is mined from the LaTeX source, passed over to Python and the output feed back into the LaTeX source. The packages differ in both the tools used to mine the Python code and the manner in which the output is made visible to the LaTeX source. In both \PythonTeX\ and \SageTeX, the Python code is mined using a first pass of LaTeX whereas \pyLaTeX\ uses a Python script to do the same job. There are two main reasons for adopting Python as the code miner. First, it is much easier to extend \pyLaTeX\ to incorporate other foreign languages (such as Mathematica, Matlab, Cadabra etc.). Doing so in \PythonTeX\ and \SageTeX\ requires careful tweaking of the underlying LaTeX class files -- such adventures requires a solid understanding of the LaTeX programming language and is not for the faint of heart. The second reason is that LaTeX is not the ideal tool to mine Python (or any other code) from a LaTeX document. There are much better text processing tools (such as Python) that can do the same job while being much easier (for the developer) to read, debug and extend. There are also some important differences in the way the end user accesses the Python output for use in the LaTeX source. In \PythonTeX\ and \SageTeX\ the Python output is saved to a collection of files (roughly one file per Python code block) while \pyLaTeX\ creates a single file. In all cases the contents of these files are made available to the LaTeX source by way of special LaTeX macros. The \PythonTeX\ and \SageTeX\ output files are tightly coupled to the original LaTeX source. This means that their contents can not be easily shared with other LaTeX sources (without manual intervention). In contrast, the \pyLaTeX\ output is a single file that contains a collection of LaTeX macros, one for each piece of (tagged) Python output, that can be read by any other LaTeX source. Thus a user could split a larger LaTeX source into a collection of smaller sources (e.g., chapters of a book) with the Python output included as needed. An example of this sharing of Python output can be found in the examples directory. The file {\tts summary.tex} does no symbolic calculations of its own but instead pulls in selected parts of the Python output from other examples in that directory. Another important difference between \pyLaTeX\ and \PythonTeX\ and \SageTeX\ is that \pyLaTeX\ uses tags to nominate which pieces of the Python output should be made available to the LaTeX source. Both \PythonTeX\ and \SageTeX\ allow all Python output to accessed in the LaTeX source. The problem with that method is that it is not possible to record the history of a single Python expression. For example, if the Python code computes the expression {\tts foo} five times then only the fifth instance will be seen by LaTeX. \section{Requirements} \subsection{Latex} The \pyLaTeX\ package draws on a number of latex packages all of which should be available in any recent LaTeX distribution. The examples described in this document were run using the {\tts TeXLive-2018} distribution for macOS. The \pyLaTeX\ package provides both a normal style file, {\tts pylatex.sty} and a class file {\tts pylatex.cls}. The preamble to the style file contains the following declarations. \vskip 12pt \begin{latex} \usepackage{comment} \usepackage{listings} \usepackage{keyval} \usepackage{etoolbox} \usepackage{xcolor} \usepackage{pymacros} \end{latex} The {\tts pymacros} package is a key part of the \pyLaTeX\ collection as it defines the core macros for \pyLaTeX. The class file first includes the style file then executes the following statements \vskip 12pt \begin{latex} \usepackage[papersize={297mm,210mm}, hmargin=2cm,tmargin=1.0cm,bmargin=1.5cm]{geometry} \usepackage{amsmath} \usepackage{amssymb} \usepackage{hyperref} \usepackage{breqn} \end{latex} The extra packages included in the class file are not essential but have proven useful in many cases and thus are included as a convenient default. Note that the options to the geometry package sets the output to A4 landscape format. This can be changed, either by editing the class file or by including a line like the following somewhere in the preamble of the users document. \vskip 6pt \begin{latex} \geometry{margin=2.0cm,paperheight=25cm} \end{latex} \subsection{Python} There are no particular requirements on the Python environment in order to use the \pyLaTeX\ package though the examples listed below do require {\tts sympy} version 1.1.1 or later. The simple measure is that if your embedded Python code can be run in your normal Python environment then that same code should work equally well using \pyLaTeX. All of the examples described in this document were run under macOS using the default Apple Python environment (Python 2.7) as well as under the Anaconda 5.2 (Python3.6) environment. \section{Setup} There is no setup tool as you only have a few files to install. The following files can be found inside the {\tts Python} directory of the hybrid collection. \begin{tabular}{rl} {\tts shell/pylatex.sh}:&Copied to anywhere that is visible on your path.\\[5pt] {\tts python/pypostproc.py}:&Copied to anywhere that is visible on your path.\\ {\tts python/pypreproc.py}:&Ditto\\ {\tts python/merge-tex.py}:&Ditto\\[5pt] {\tts latex/pylatex.cls}:&Copied to anywhere that is visible to LaTeX.\\ {\tts latex/pylatex.sty}:&Ditto\\ {\tts latex/pymacros.sty}:&Ditto \end{tabular} For example, the shell and Python scripts could be copied to {\tts \$HOME/local/sh/} while the LaTeX files could be copied to {\tts \$HOME/tex/inputs/}. Provided those directories are on the appropriate paths (i.e., PATH and TEXINPUTS), that should be all that needs doing. Note that each of the Python scripts uses the following shebang (i.e., the first line in the file) \begin{lstlisting} #!/usr/local/bin/python3 \end{lstlisting} You may need to change this to match the path to your version of {\tts python3}. \section{Compiling} To compile the file {\tts foo.tex} use \begin{lstlisting} pylatex.sh -i foo \end{lstlisting} The {\tts pylatex.sh} script will call Pyhton and LaTeX as required to produce the pdf output. Along the way a number of intermediate files will be created (most of which will be deleted by default). Using the above command will produce not only the pdf but also {\tts foo.pytex}. This file contains a list of macros, one for each \pyLaTeX\ tag in {\tts foo.tex}, that are executed when the \pyLaTeX\ macros such as {\tts\verb|\py{bah}|} are called (in this case {\tts bah} is a tag associated with part of the Python code in the {\tts foo.tex} source). This same file can also be included in other LaTeX files using {\tts\verb|\input{foo.pytex}|}. This makes the Python output from {\tts foo.tex} available to other LaTeX files. Executing {\tts pylatex.sh} with the {\tts -h} flag will produce the following usage information. \begin{lstlisting} usage : pylatex.sh -i file [-I] [-P] [-s] [-k] [-x] [-h] options : -i file : source file (without .tex extension) -I file : full path to pymacros.sty file -P path : where to find the Python binary -s : silent, don't open the pdf file -k : keep all temporary files -x : don't call latex -h : this help message example : pylatex.sh -i file -P/usr/local/bin/python \end{lstlisting} The intermediate files produced by the {\tts -k} option are (excluding the standard LaTeX files) \bgroup \def\MYn{\vrule height 0pt depth 5pt width 0pt} \def\MYN{\vrule height 0pt depth 0pt width 0pt} \begin{tabular}{rl} {\tts foo.py:}&\MyPar{0.75}% {A copy of all the Python code stripped bare of (most) tags.}\\ {\tts foo_.py:}&\MyPar{0.75}% {Similar to {\tts foo.py} but with additional Python code to catch Python output for the \pyLaTeX\ tags.}\\ {\tts foo.pyidx:}&\MyPar{0.75}% {An index of all \pyLaTeX\ tags.}\\ {\tts foo.pytex:}&\MyPar{0.75}% {A set of macros, one for each tag, expanding to the Python output.}\\ {\tts foo.pytxt:}&\MyPar{0.75}% {The raw Python output from {\tts foo_.py}.} \end{tabular} \egroup The {\tts -k} option is useful in cases where there is a bug in the users Python code. This option will force {\tts pylatex.sh} to retain all intermediate files, in particular the mined Python code {\tts foo.py}. This file can then be debugged and in turn the original LaTeX source can be corrected. The {\tts -I} option can be used in cases where the output from {\tts foo.tex} is intended for use in other LaTeX sources that do not use the \pyLaTeX\ style file {\tts pylatex.sty}. This could be useful for sharing results with colleagues who have not installed the \pyLaTeX\ package or when submitting a paper to a journal. The nett effect of the {\tts -I} option is to prepend the {\tts foo.pytex} file with the LaTeX definitions for all of the \pyLaTeX\ macros. Another approach would be to not use the {\tts -I} but share both the {\tts foo.pytex} and {\tts pymacros.sty} file with colleagues or journals. The only files that must be kept are {\tts foo.tex} (obviously) and {\tts foo.pytex}. This pair of files alone is sufficient for successful execution of LaTeX. The file {\tts foo.pytex} only needs to be recreated (using {\tts pylatex.sh}) when changes have been made to the Python code in {\tts foo.tex}. It is important to note that the Python code mined from the LaTeX source will be written to a single file. Thus it is important that all parts of this file interact harmoniously. If there is any possibility that one part of the (combined) code may adversely effect other parts then some action must be taken. One solution is to use language features of Python to avoid the clash, such as placing conflicting code in separate functions. Another solution is to move the conflicting code to separate LaTeX documents, run {\tts pylatex.sh} over each document, then include the results in the original LaTeX source using {\tts\verb|\input|} on the corresponding {\tts .pytex} files. \subsection{Caution} Be very careful -- each of the above named temporary files will overwrite any existing files of the same name. An easy road to disaster lies this way. Suppose you have an existing Python file named {\tts foo.py} and suppose you wish to catch its output for later use in some other LaTeX document. You might start by creating a wrapper file, {\tts foo.tex}, such as the following \vspace{10pt} \PySetup{action=verbatim} % note: the * in the 1st column is to ensure the python preprocessor does not respond % to any of the \begin{...} or \end{...} lines. The \end{document} line is the % real problem as it terminates the preprocessing. \bgroup \bgcolour{white} \begin{latex} * \documentclass[12pt]{pylatex} * \begin{document} * \begin{python} * \Input{foo.py} * \end{python} * \end{document} \end{latex} \egroup \PySetup{action=show} The {\tts pylatex.sh} will expand the {\tts\verb|\Input{foo.py}|} command to include the contents of {\tts foo.py}. No damage done -- so far. But now {\tts pylatex.sh} will read the newly merged file and will create its own version of {\tts foo.py} without \emph{any} of the \pyLaTeX\ tags. Thus any subsequent processing of {\tts foo.tex} will \emph{not} capture any Python output -- because all of the Python tags have been deleted. \subsection{The pypreproc.py and pypostproc.py scripts} The job of the {\tts pypreproc.py} script is to harvest the Python code from the LaTeX source. For a source named {\tt foo.tex} the script could be run using \begin{lstlisting} pypreproc.py -i foo \end{lstlisting} This will produce {\tts foo.py, foo_.py} and {\tts foo.pyidx}. The file {\tts foo.py} is an almost\footnote{It may retain a few comments.} exact copy of the active Python code while {\tts foo_.py} is a version of {\tts foo.py} containing extra Python commands to catch the nominated Python output. This file is passed to Python to create the {\tts foo.pytxt} file which in turn is passed to {\tts pypostproc.py} using \begin{lstlisting} pypostproc.py -i foo \end{lstlisting} which should create the {\tts foo.pytex} file. The pre and post processor scripts, {\tts pypreproc.py} and {\tts pypreproc.py}, would rarely be used on their own. Though if something fails in the execution of the {\tts pylatex.sh} script it might prove useful to run these scripts on their own. Bug reports are always welcome (working on the time proven axiom that no code is ever bug free). \subsection{The merge-tex.py script} A common practice when writing LaTeX documents is to use a driver file to pull in other smaller LaTeX documents (e.g., a driver for a book could pull in the chapters as separate documents). Each of the chapters could contain some active Python code -- so how can such code be made visible to the Python preprocessor {\tts pypreproc.py}? That is the job of the {\tts merge-tex.py} script. It will read each file and copy the contents to a single merged file (named {\tts .merged.tex}). This file is then read by {\tts pypreproc.py}. Not all included files will contain active Python code so {\tts merge-tex.py} only looks for lines like {\tts\verb|\Input{foo.tex}|}. Other files included using {\tts\verb|\input|} or {\tts\verb|\include|} are ignored by {\tts merge-tex.py}. Thus the {\tts .merged.tex} need not be a faithful copy of the original source -- but that is not a problem since {\tts .merged.tex} exists solely for {\tts pypreproc.py} to harvest the active code after which it is no longer used. The {\tts merge-tex.py} script is language agnostic -- all it does is read its input and respond to any {\tts \verb|\Input|} lines. If the input file is {\tts foo.tex} then a merged file {\tts bah.tex} can be created using \begin{lstlisting} merge-tex.py -i foo.tex -o bah.tex \end{lstlisting} Note that the {\tts .tex} file extensions \emph{are} required (unlike {\tts pypreproc.py} and {\tts pypostproc.py}). Note also that {\tts merge-tex.py} will follow nested files up to 10 deep. \section{Usage} Using \pyLaTeX\ entails the addition of user defined tags, in the form of Python comments, within the LaTeX source. These tags serve to connect the Python output to the LaTeX source. A typical example is shown in the following code. \vspace{10pt} \PySetup{action=verbatim} % Note: The * in the 1st column is to ensure the python preprocessor does not respond % to any of the \begin{...} or \end{...} lines. The \end{document} line is the % real problem as it terminates the preprocessing. % The * is hidden from LaTeX by way of the listinings option gobble=2. \bgroup \bgcolour{white} \latexstyle \begin{latex} * \documentclass[12pt]{pylatex} * \begin{document} * \begin{python} \end{latex} \pythonstyle \begin{python} * from sympy import * * x = Symbol('x') * ans = exp(-x) # py (ans.01,ans) * taylor = ans.series(x, 0, 4) # py (ans.02,taylor) * taylor = ans.series(x, 0, 8) # py (ans.03,taylor) \end{python} \latexstyle \begin{latex} * \end{python} * \begin{align*} * &\py*{ans.01}\\ * &\py*{ans.02}\\ * &\py*{ans.03} * \end{align*} * \end{document} \end{latex} \egroup \PySetup{action=show} This will lead to a pdf file that contains not just the Python output but also, for reference, a copy of the Python source (though this can be suppressed, see the section \hyperlink{sec:custom}{below} on customisation). \vspace{5pt} \begin{python} from sympy import * x = Symbol('x') ans = exp(-x) # py (ans.01,ans) taylor = ans.series(x, 0, 4) # py (ans.02,taylor) taylor = ans.series(x, 0, 8) # py (ans.03,taylor) \end{python} \vspace{-10pt} \begin{align*} &\py*{ans.01}\\ &\py*{ans.02}\\ &\py*{ans.03} \end{align*} The key elements to note are the \pyLaTeX\ tags (e.g., {\tts py(ans.01,ans)}) and the Python environment block. The tags are always part of a Python comment and are always of the form {\tts py(foo,bah)} where {\tts bah} is a Python symbol (or any printable entity) and {\tts foo} is the tag (later used in the LaTeX source). The \pyLaTeX\ tag can be any string of characters from the set {\tts a-zA-Z0-9.\_}. In the above example there are three tags, {\tts ans.01, ans.02} and {\tts ans.03}. The dot postfix is not essential but it provides a simple way to record a sequence of Python outputs. These tags are used later in the body of the LaTeX code and are accessed in the above example using the \pyLaTeX\ macro {\tts\verb|\py|}. This macro takes just one argument namely the corresponding \pyLaTeX\ tag. The macro {\tts\verb|\py{foo}|} will expand to the Python output for the tag {\tts foo}. Other macros are provided such as {\tts\verb|\py*{foo}|} which will expand to {\tts foo := } followed by the Python output. The full set of macros are described in the section \hyperlink{sec:pylatexmacros}{LaTeX macros}. The \pyLaTeX\ tags can be placed anywhere within the Python block. In the above example the tags were placed on the same line as the Python code. This is just for aesthetic effect -- they could equally well have been located on following lines. The \pyLaTeX\ tags should be unique within the LaTeX file. If the same tag name is used more than once the output associated with that tag will be from the last instance of that tag. Note that the {\tts pypreproc.py} script will interpret {\tts py(foo)} as a shorthand for {\tts py(foo,foo)}. \subsection{Undefined tags} If any of the \pyLaTeX\ macros are called for a tag that was \emph{not} defined then \hbox{(??)} will be printed. Note that this may cause a LaTeX syntax error when the \hbox{(??)} appears in an unexpected context (e.g., in cases where the output of {\tts\verb|\py|} was expected to expand to one or more {\tts\verb|\\|}'s). \subsection{Tagged blocks} There is a second form of tag, known as a tagged block, in which a block of Python code is enclosed in a matching {\tts\verb|# pyBeg(foo)|}, {\tts\verb|# pyEnd(foo)|} pair. An example of a tagged block can be seen in the following code. The tag is given the name {\tts Pascal} and can be accessed in the LaTeX code using any of the \pyLaTeX\ macros, in this case {\tts\verb|\py|}. The intention of tagged blocks is that they can be used to capture any Python output generated within the tagged block (except the output that is caught by simple tags such as shown in the previous example). Here is a short example\footnote{This example is very \emph{inefficient} as it uses recursive calls for \emph{every} element in the table.} that demonstrates the use of a single tagged block. \vspace{10pt} \PySetup{action=verbatim} % note: the * in the 1st column is to ensure the python preprocessor does not respond % to any of the \begin{...} or \end{...} lines. The \end{document} line is the % real problem as it terminates the preprocessing. \bgroup \bgcolour{white} \latexstyle \begin{latex} * \documentclass[12pt]{pylatex} * \begin{document} * * \begin{python} \end{latex} \pythonstyle \begin{python} * def build(n): * if n==0: * return [1] * else: * P = build(n-1) * return [1] + [P[i]+P[i+1] for i in range(n-1)] + [1] * * def display(n): * for i in range(n): * ans = "" * for j in range(0,len(build(i))): * ans = ans + "\m{" + str(build(i)[j]) + "}" * print (ans+"\cr") * * # pyBeg (Pascal) * display(7) * # pyEnd (Pascal) \end{python} \latexstyle \begin{latex} * \end{python} * * \def\m#1{\hbox to 1cm{\hfill #1\hfill}} * \halign{\hbox to \textwidth{\hfill#\hfill}\cr\py{Pascal}} * * \end{document} \end{latex} \egroup \PySetup{action=hide} \begin{python} def build(n): if n==0: return [1] else: P = build(n-1) return [1] + [P[i]+P[i+1] for i in range(n-1)] + [1] def display(n): for i in range(n): ans = "" for j in range(0,len(build(i))): ans = ans + "\m{" + str(build(i)[j]) + "}" print (ans+"\cr") # pyBeg (Pascal) display(7) # pyEnd (Pascal) \end{python} \clearpage \PySetup{action=show} The output of the above code (excluding the echoed Python code) is Pascal's triangle (as expected). \def\m#1{\hbox to 1cm{\hfill #1\hfill}} \halign{\hbox to \textwidth{\hfill#\hfill}\cr\py{Pascal}} All Python code must be contained within the Python environment block, i.e., within a {\tts\verb|\begin{python}|} {\tts\verb|...|} {\tts\verb|\end{python}|} pair. There is no facility to allow \emph{inline} execution of Python code (though this is allowed in other packages, notably \PythonTeX). The reason for taking this approach was to force a clear separation between native LaTex code and active Python blocks. This makes it easier to locate the Python code. If an inline calculation is needed then it is a simple matter of including the Python code in a Python block and using a tag to catch and display the result. Tagged blocks can be nested (though it is not clear what use this might serve) and they can contain simple tags. The simple tags will always take priority over tagged blocks in capturing Python output. Tagged blocks should respect the usual rules of begin-end blocks -- they can nested but they must not overlap. The Python pre and post processors (within the {\tts pylatex.sh} script) will report errors when tagged blocks are not properly structured (i.e., overlapping, unmatched {\tts pyBeg/pyEnd} items etc.). \subsection{LaTeX macros} \hypertarget{sec:pylatexmacros}{} The \pyLaTeX\ package provides a number commands for typesetting tagged expressions. \newbox\Slashpya \setbox\Slashpya=\hbox{\tts\verb|\py{foo}|} \newbox\Slashpyb \setbox\Slashpyb=\hbox{\tts\verb|\py*{foo}|} \newbox\SlashPya \setbox\SlashPya=\hbox{\tts\verb|\Py{foo}|} \newbox\SlashPyb \setbox\SlashPyb=\hbox{\tts\verb|\Py*[bah]{foo}|} \newbox\Slashhfill \setbox\Slashhfill=\hbox{\tts\verb|[\hfill]|} \newbox\SlashPySetup \setbox\SlashPySetup=\hbox{\tts\verb|\PySetup{key=value}|} \newbox\SlashDmatha \setbox\SlashDmatha=\hbox{\tts\verb|\Dmath[bah]{foo}|} \newbox\SlashDmathb \setbox\SlashDmathb=\hbox{\tts\verb|\Dmath*[bah]{foo}|} \newbox\SlashttTag \setbox\SlashttTag=\hbox{\tts\verb|\ttTag{foo}|} \newbox\SlashInput \setbox\SlashInput=\hbox{\tts\verb|\Input{foo.tex}|} \begin{longtable}{rl} {\copy\Slashpya}&\MyPar{0.70}{% Display the value of {\tts foo} without any additional decorations.}\\ {\copy\Slashpyb}&\MyPar{0.70}{% Similar to \copy\Slashpya\ but adds {\tts foo$\colonEq$} immediately to the left of {\tts foo}.}\\ {\copy\SlashPya}&\MyPar{0.70}{% Display the value of {\tts foo} and set the equation tag to be ({\tts foo}). Since this macro creates its own equation tag it should not be used in any maths environment that also creates an equation tag (e.g., {\tts align, equation} etc.) It can not be used in any of the {\tts breqn} environments ({\tts breqn} will report a package error).}\\ {\copy\SlashPyb}&\MyPar{0.70}{% Use this version of \copy\SlashPya\ in any of the (starred) {\tts breqn} environments. The optional argument {\tts [bah]} specifies the spacing between the end of {\tts foo} and the right hand edge of the tag. The default is \copy\Slashhfill\ which forces the tag to the far right.}\\ {\copy\SlashDmatha}&\MyPar{0.70}{% This is a shortcut for the {\tts dmath} environment. The optional and required arguments of \copy\SlashDmatha\ are passed onto the {\tts dmath} environment. See page (\pageref{ex:Dmath}) for an example.}\\ {\copy\SlashDmathb}&\MyPar{0.70}{% This is similar to \copy\SlashDmatha\ but with the one small change that it applies to the {\tts dmath*} environment.}\\ {\copy\SlashttTag}&\MyPar{0.70}{% This is a simple macro that typesets a tag name such as {\tts foo} in a small typewriter font enclosed in matching parenthesis, e.g., ({\tts foo}).}\\ {\copy\SlashPySetup}&\MyPar{0.70}{% This command takes one argument in the form of a key=value pair. Its purpose is to set global options for the following Python blocks. The current list of options is limited to one key with three values. These are described in the following section.}\\ \end{longtable} \subsection{Custom formats} \hypertarget{sec:custom}{} The \pyLaTeX\ package allows for some minor customisation of the formatting of the Python code. The macro {\tts\verb|\PySetup|} can be used to set the preferred options using key-value pairs. There is only one key as described in the following table. \begin{tabular}{rl} {\tts action=show}&% \MyPar{0.70}{Make the Python code visible and active (i.e., cancel the {\tts hide} and {\tts verbatim} actions).}\\ {\tts action=hide}&% \MyPar{0.70}{Hide the python code but still allow the Python code to be active.}\\ {\tts action=verbatim}&% \MyPar{0.70}{This will make the Python code inactive (i.e., it will not be passed to Python).}\\[5pt] \end{tabular} Multiple calls to {\tts\verb|\PySetup|} can be made and apply to all subsequent Python environments or until changed by a later call to {\tts\verb|\PySetup|}. The default value is {\tts action=show}. The \pyLaTeX\ package uses the {\tts listings} package which allows further formatting changes to be made. For example, to add line numbers and a shaded background to the Python code use \begin{lstlisting} \lstset{numbers=left,backgroundcolor=\color{lightgrey}} \end{lstlisting} Many other options are available, see the {\tts listings} documentation for full details. \subsection{Python indentation} Python has very strict (but simple) indentation rules that must be observed not only within a single Python block but across all Python blocks. Why? Because all of the Python blocks will be collected into a separate single Python code and that code must observe the Python indentation rules. \subsection{Error reporting} None of the packages in this collection treat errors from the active code with any degree of aplomb -- at best they report that an error occurred, at worst they silently ignore the error leaving {\tts pdflatex} to pick up the pieces. This is far from ideal. If in doubt, run the main script (e.g., {\tts pylatex.sh}) using the {\tts -k -x} command line options then inspect the file {\tts foo.pytxt} for any errors. If there are errors then you can debug the extracted code {\tts foo.py} later returning the corrected code back to the LaTeX source {\tts foo.tex}. \subsection{Matplotlib and macOS} There is a well known issue when using Matplotlib on macOS where some Matplotlib codes may fail. The \href{https://matplotlib.org/faq/osx_framework.html}{Matplotlib documentation} provides a number of suggestions including to use {\tts pythonw} rather than {\tts python}. For such cases use the {\tts -P} flag to set the path to the {\tts pythonw} command when invoking the {\tts pylatex.sh}. This has been tried and tested under the Anaconda Python3 environment for macOS. \section{Examples} The {\tts examples} directory contains a small collection of complete \pyLaTeX\ codes that showcase the various features of the \pyLaTeX\ package. The Python source contains inline comments that result in long lines of text that do not comfortably fit on an A4 page in portrait mode. Thus most of the examples have been formatted in A4 landscape mode (this is the default setting for the \pyLaTeX\ class). Consequently it is not practical to include those examples in this file. The following table provides a very brief summary of each example (with hyperlinks to the corresponding pdf's in {\tts ../python/examples/}). \newbox\exa \setbox\exa=\hbox{\href{../python/examples/example-01.pdf}{Example 1}} \newbox\exb \setbox\exb=\hbox{\href{../python/examples/example-02.pdf}{Example 2}} \newbox\exc \setbox\exc=\hbox{\href{../python/examples/example-03.pdf}{Example 3}} \newbox\exd \setbox\exd=\hbox{\href{../python/examples/example-04.pdf}{Example 4}} \newbox\exe \setbox\exe=\hbox{\href{../python/examples/example-05.pdf}{Example 5}} \newbox\exf \setbox\exf=\hbox{\href{../python/examples/example-06.pdf}{Example 6}} \newbox\exg \setbox\exg=\hbox{\href{../python/examples/example-07.pdf}{Example 7}} \newbox\exh \setbox\exh=\hbox{\href{../python/examples/example-08.pdf}{Example 8}} \newbox\exi \setbox\exi=\hbox{\href{../python/examples/example-09.pdf}{Example 9}} \newbox\exz \setbox\exz=\hbox{\href{../python/examples/summary.pdf}{Summary}} \begin{longtable}{rl} \box\exa:&\MyPar{0.80}% {This is a collection of basic mathematical computations. It contains examples of simple tags and tagged blocks.}\\ \box\exb:&\MyPar{0.80}% {This is the first of two examples drawn from the \PythonTeX\ website \href{https://github.com/gpoore/pythontex/}{(here)}. It shows a nice example of using a tagged block.}\\ \box\exc:&\MyPar{0.80}% {This is the second example taken from the \PythonTeX\ website \href{https://github.com/gpoore/pythontex/}{(here)}. It shows a step-by-step computation of a simple triple integral.}\\ \box\exd:&\MyPar{0.80}% {This example shows how {\tts Matplotlib} and friends can be used to construct a simple xy-plot.}\\ \box\exe:&\MyPar{0.80}% {This example shows how problems with the placement of equation tags can be resolved by careful choice of the optional argument to {\copy\SlashPyStar}.}\\ \box\exf:&\MyPar{0.80}% {This is a simple example that uses Python to compute the first few iterations of a Newton-Raphson method.}\\ \box\exg:&\MyPar{0.80}% {This example contains a single tag-block. It captures basic system data.}\\ \box\exh:&\MyPar{0.80}% {This example shows how to completely hide the Python code as well a trick for hiding just the tags.}\\ \box\exi:&\MyPar{0.80}% {This example is a proof of concept example. It shows one approach for passing LaTeX information to the Python code. The code is not elegant but it does the job.}\\ \box\exz:&\MyPar{0.80}% {There is no Python code in this example. Instead, the results from the above examples are included by inputting the corresponding {\tts .pytex} file.} \end{longtable} \section{Splitting long lines using breqn} On some occasions the output from a computation may be too long to fit comfortably on one line. In such cases some form of line splitting is required. A less than ideal approach is to manually edit the output by inserting carefully chosen line breaks. Not only is this approach tedious and inelegant it also requires the line breaks to be reset whenever the document format is changed (e.g., from A4 to letter size) or when some of the computations are changed (e.g., showing twice as many terms in a series expansion). A better approach is to use the {\tts breqn} package which uses sophisticated algorithms to find good line breaks with minimal input from the user. In many cases {\tts breqn} will produce an acceptable output. But it is not without its own limitations\footnote{The {\tts breqn} documentation does note that it is a work in progress.} as some of the following examples will demonstrate. The fact is that there are no algorithms that will guarantee prefect line splitting as there will always be some subjective element in what constitutes a good line break. The following series of examples are intended as guide of what to expect when using {\tts breqn} and also to demonstrate some possible remedies. Here is a simple example based on a truncated Taylor series expansion of $1/(1+x)$ around $x=0$. \bgroup \lstset{gobble=2,numbers=left} \begin{python} from sympy import * x = Symbol('x') ans = 1/(1+x) # py (fun,ans) taylor = ans.series(x, 0, 6) # py (ans.101,taylor) taylor = ans.series(x, 0, 9) # py (ans.102,taylor) taylor = ans.series(x, 0, 12) # py (ans.103,taylor) taylor = ans.series(x, 0, 15) # py (ans.104,taylor) taylor = ans.series(x, 0, 30) # py (ans.105,taylor) \end{python} \egroup For an expansion with only a handful of terms the usual {\tts align} environment produces an acceptable output as demonstrated in the following code and output. \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \begin{align*} \py{fun} &= \py {ans.101}\tag{\ttTag{ans.101}}\\ &= \py {ans.102}\tag{\ttTag{ans.102}}\\ &= \py {ans.103}\tag{\ttTag{ans.103}} \end{align*} \end{latex} \egroup \begin{align*} \py{fun} &= \py {ans.101}\tag{\ttTag{ans.101}}\\ &= \py {ans.102}\tag{\ttTag{ans.102}}\\ &= \py {ans.103}\tag{\ttTag{ans.103}} \end{align*} In this and the following examples the equation tags have been explicitly matched to the corresponding {\tts sympy} expressions. This makes it somewhat easier to follow the progress of a computation. The normal equation numbering (e.g., (1), (2) etc.) can be recovered by deleting the calls to {\tts\verb!\tag{...}!}. The {\tts\verb|\ttTag|} macro, defined in the \pyLaTeX\ package, does as its name suggests -- typesets the tag in the {\tts\verb|\tt|} font. The above works well for short expressions but for longer expressions it is much better to use the {\tts breqn} package. The key points to note in the following example are the use of the {\tts dmath} environment and the manner in which the equation tags have been set. \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \usepackage{breqn} ... \begin{dmath}[number={\ttTag{ans.105}}] \py {fun} = \py {ans.105} \end{dmath} \end{latex} \egroup The corresponding output is \Dmath[number={\ttTag{ans.105}}]{\py{fun} = \py{ans.105}} The {\tts dmath} environment is one of a number environments provided by the {\tts breqn} package. Its job is to chose sensible line breaks that produce a pleasant output (though what constitutes \emph{pleasant} may be up for debate). Note that all of the {\tts breqn} environments do \emph{not} support the {\tts\verb!\tag!} macro for setting equation tags. The only way to do so is through the {\tts\verb!number={...}!} optional argument as shown in the above example. To suppress the equation label use the {\tts dmath*} environment. \bgroup \advance\leftskip1cm \advance\rightskip1cm \hypertarget{landing}{{\bf Note:}} This sentence may seem out of place but its purpose is to demonstrate a claim made later is this documentation that, with a suitably modified label macro, the {\tts hyperref} package can be used to jump to the correct page when clicking on a hyperlink for an equation. For example, clicking on this link \eqref{eq:target} should take us to page \pageref{eq:target}. But now, back to the main discussion. \par \egroup The {\tts breqn} package also provides a {\tts dgroup} environment. This can be used to group a sequence of {\tts dmath} environments to align the output on a targeted symbol (usually the first equals sign). Here is a short example \vskip 12pt \bgroup \bgcolour{white} \lstlatex{numbers=left} \begin{latex} \begin{dgroup} \begin{dmath}[number={\ttTag{ans.103}}] \py {fun} = \py {ans.103} \end{dmath} \begin{dmath}[number={\ttTag{ans.104}}] {} = \py {ans.104} \end{dmath} \begin{dmath}[number={\ttTag{ans.105}}] {} = \py {ans.105} \end{dmath} \end{dgroup} \end{latex} \egroup and here is the corresponding output \begin{dgroup} \begin{dmath}[number={\ttTag{ans.103}}] \py {fun} = \py {ans.103} \end{dmath} \begin{dmath}[number={\ttTag{ans.104}}] {} = \py {ans.104} \end{dmath} \begin{dmath}[number={\ttTag{ans.105}}] {} = \py {ans.105} \end{dmath} \end{dgroup} There are a few points to be made here. First is the less then ideal placement of tags. Second is the somewhat ungainly syntax. Both of these points will be discussed in more detail shortly. Next, notice the {\tts\verb!{}!} preceding the equal signs in lines 3 and 4. This supplies an empty left hand side for each equation and is essential to ensure proper alignment (on the equals sign) across all three equations. Unlike other maths environments, {\tts breqn} does not allow you to specify which symbol to use as the alignment target -- that choice is made deep within the inner workings of {\tts dmath} and friends. It will choose symbols including {\tts\verb!=-+:()!}. If you wish to tell {\tts dmath} to not use a particular symbol you can wrap that symbol inside {\tts\verb!\hiderel!} as in the following example. \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \begin{dgroup*} \begin{dmath*} f(x) \hiderel{=} \py {fun} = \py {ans.101} \end{dmath*} \begin{dmath*} {} = \py {ans.102} \end{dmath*} \end{dgroup*} \end{latex} \egroup \begin{dgroup*} \begin{dmath*} f(x) \hiderel{=} \py {fun} = \Py*{ans.101} \end{dmath*} \begin{dmath*} {} = \Py*{ans.102} \end{dmath*} \end{dgroup*} Consider now the earlier example in which the equation tags were not well placed and where the syntax was described as ungainly. The syntax can be tidied slightly using one of the features of the {\tts breqn} package -- it allows the {\tts dmath} and {\tts dmath*} environments to be wrapped in user defined macros such as \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \newcommand*{\Dmath}[2][]{\begin{dmath}[#1]#2\end{dmath}} \end{latex} \egroup This defines {\tts\verb!\Dmath!} as a macro that takes one required argument and one optional argument (both of which are passed on to {\tts dmath}). It is not a huge saving but even so it does save a few keystrokes. Here is one of the previous examples rewritten using {\tts\verb!\Dmath!}. \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \begin{dgroup} \Dmath[number={\ttTag{ans.103}}]{ \py {fun} = \py {ans.103} } \Dmath[number={\ttTag{ans.104}}]{ {} = \py {ans.104} } \Dmath[number={\ttTag{ans.105}}]{ {} = \py {ans.105} } \end{dgroup} \end{latex} \egroup The \pyLaTeX\ package defines {\tts\verb|\Dmath|} for the {\tts dmath} environment as well as {\tts\verb|\Dmath*|} as a shortcut for the {\tts dmath*} environment. The use of {\tts\verb|\Dmath*|} does save some keystrokes but it does not fix the problem where the text is obscured by the tag. There seems to be no simple way to tell {\tts breqn} to avoid such problems while retaining {\tts breqn}'s method of placing the tags. The {\tts\verb|\Py*|} macro avoids this problem by presenting {\tts dmath*} with a concatenated string built from the text (e.g., the output of {\tts\verb|\py{foo}|}), some flexible white space (usually {\tts\verb|\hfill|}) and the tag (e.g., {\tts foo}). This string is processed by {\tts dmath*} and line splits are inserted at its discretion. This will guarantee that the all of the text and the tag will be displayed. The user defined whitespace can always be chosen so that the tag does not overlap the text. This is a bare minimum of what could be deemed an acceptable output -- non overlap of the text and the tag. The output might not be optimal but at least it is readable. Here is the same example as above but this time using {\tts\verb|\Py*|} to display the text and the tags. \vskip 12pt \pglabel{ex:Dmath} \bgroup \bgcolour{white} \begin{latex} \begin{dgroup*} \Dmath*{ \py {fun} = \Py* {ans.103} } \Dmath*{ {} = \Py*[\hskip 2cm] {ans.104} } \Dmath*{ {} = \Py*[\hskip 3cm] {ans.105} } \end{dgroup*} \end{latex} \egroup \begin{dgroup*} \Dmath*{ \py {fun} = \Py* {ans.103} } \Dmath*{ {} = \Py*[\hskip 2cm] {ans.104} } \Dmath*{ {} = \Py*[\hskip 3cm] {ans.105} } \end{dgroup*} The whitespace between the text and the tag is passed through the optional argument of {\tts\verb|\Py*|} with the default set as {\tts\verb|\hfill|}. The inner workings of {\tts\verb|\Py*|} sets the tag using {\tts\verb|\llap|} and thus the whitespace optional argument measures the space between the right hand edge of the tag and left hand end of the equation text. Note also that this example uses the starred version of {\tts dgroup} and {\tts\verb|\Dmath*|}. This is to ensure that {\tts breqn} plays no part in forming the tag (as that is handled by {\tts\verb|\Py*|}). The \pyLaTeX\ package defines both {\tts\verb|\Py|} and {\tts\verb|\Py*|}. The {\tts\verb|\Py|} macro is intended for use only in the starred maths environments (e.g., {\tts align*, equation*} etc.). Like {\tts\verb|\Py*|}, it also sets the equation tag to match the expression but it does so using standard methods (internally it calls {\tts\verb|\tag|}). This last point (that {\tts\verb|\Py*|} uses {\tts\verb|\tag|}) also means that it can not be used in any of the {\tts breqn} environments (doing so will cause LaTeX to issue a {\tts breqn} package error). Both {\tts\verb|\Py|} and {\tts\verb|\Py*|} support the usual method of labelling and referencing equations using {\tts\verb|\label{foo}|} and {\tts\verb|\ref{foo}|}. However, there are good reasons to use a modified version of the {\tts\verb|\label|} macro (as described below) to improve the accuracy of the label-reference pairs when using hyperlinks (i.e., so that the reference points to the correct page where the label was issued). \subsection{Hyperref, hyperlinks and breqn} The {\tts breqn} package does support the {\tts hyperref} package though as discussed \href{https://tex.stackexchange.com/questions/193380/hyperref-pageref-links-point-t o-first-page}{(here)} the hyperlinks to an equation may not work as expected (clicking on a link may take you to the wrong page). The suggested fix is to define equation labels via a modified label macro such as the following \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \newcommand{\pglabel}[1]{\phantomsection\label{#1}} \end{latex} \egroup An example of its use might be \vskip 12pt \bgroup \bgcolour{white} \begin{latex} \begin{dmath}[number={\ttTag{ans.105}}] \py{fun} = \py{ans.105} \pglabel{eq:target} \end{dmath} \end{latex} \egroup \begin{dmath}[number={\ttTag{ans.105}}] \py{fun} = \py{ans.105} \pglabel{eq:target} \end{dmath} Then clicking on the link defined by {\tts\verb!\ref{eq:target}!} will bring the reader to this page. An example of such a link was seen earlier in this document (click \hyperlink{landing}{here} to jump back to that page). \section{Licence} This software is licensed under the MIT License (MIT). Please see the {\tts LICENCE.txt} file for more information. \section{Version history} \leftline{\bf v0.1 (2018/08/22)}% 22 Aug 2018 \begin{itemize} \item Initial public release. \end{itemize} \end{document}