diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/hybrid-latex/doc |
Initial commit
Diffstat (limited to 'macros/latex/contrib/hybrid-latex/doc')
-rw-r--r-- | macros/latex/contrib/hybrid-latex/doc/hybrid.pdf | bin | 0 -> 240299 bytes | |||
-rw-r--r-- | macros/latex/contrib/hybrid-latex/doc/hybrid.pytex | 36 | ||||
-rw-r--r-- | macros/latex/contrib/hybrid-latex/doc/hybrid.sty | 77 | ||||
-rw-r--r-- | macros/latex/contrib/hybrid-latex/doc/hybrid.tex | 1089 |
4 files changed, 1202 insertions, 0 deletions
diff --git a/macros/latex/contrib/hybrid-latex/doc/hybrid.pdf b/macros/latex/contrib/hybrid-latex/doc/hybrid.pdf Binary files differnew file mode 100644 index 0000000000..aa4d14d230 --- /dev/null +++ b/macros/latex/contrib/hybrid-latex/doc/hybrid.pdf diff --git a/macros/latex/contrib/hybrid-latex/doc/hybrid.pytex b/macros/latex/contrib/hybrid-latex/doc/hybrid.pytex new file mode 100644 index 0000000000..ad2d228b6a --- /dev/null +++ b/macros/latex/contrib/hybrid-latex/doc/hybrid.pytex @@ -0,0 +1,36 @@ +\pytag{ans.01}{% +e^{- x}% +} +\pytag{ans.02}{% +1 - x + \frac{x^{2}}{2} - \frac{x^{3}}{6} + \mathcal{O}\left(x^{4}\right)% +} +\pytag{ans.03}{% +1 - x + \frac{x^{2}}{2} - \frac{x^{3}}{6} + \frac{x^{4}}{24} - \frac{x^{5}}{120} + \frac{x^{6}}{720} - \frac{x^{7}}{5040} + \mathcal{O}\left(x^{8}\right)% +} +\pytag{Pascal}{% +\m{1}\cr% +\m{1}\m{1}\cr% +\m{1}\m{2}\m{1}\cr% +\m{1}\m{3}\m{3}\m{1}\cr% +\m{1}\m{4}\m{6}\m{4}\m{1}\cr% +\m{1}\m{5}\m{10}\m{10}\m{5}\m{1}\cr% +\m{1}\m{6}\m{15}\m{20}\m{15}\m{6}\m{1}\cr% +} +\pytag{fun}{% +\frac{1}{x + 1}% +} +\pytag{ans.101}{% +1 - x + x^{2} - x^{3} + x^{4} - x^{5} + \mathcal{O}\left(x^{6}\right)% +} +\pytag{ans.102}{% +1 - x + x^{2} - x^{3} + x^{4} - x^{5} + x^{6} - x^{7} + x^{8} + \mathcal{O}\left(x^{9}\right)% +} +\pytag{ans.103}{% +1 - x + x^{2} - x^{3} + x^{4} - x^{5} + x^{6} - x^{7} + x^{8} - x^{9} + x^{10} - x^{11} + \mathcal{O}\left(x^{12}\right)% +} +\pytag{ans.104}{% +1 - x + x^{2} - x^{3} + x^{4} - x^{5} + x^{6} - x^{7} + x^{8} - x^{9} + x^{10} - x^{11} + x^{12} - x^{13} + x^{14} + \mathcal{O}\left(x^{15}\right)% +} +\pytag{ans.105}{% +1 - x + x^{2} - x^{3} + x^{4} - x^{5} + x^{6} - x^{7} + x^{8} - x^{9} + x^{10} - x^{11} + x^{12} - x^{13} + x^{14} - x^{15} + x^{16} - x^{17} + x^{18} - x^{19} + x^{20} - x^{21} + x^{22} - x^{23} + x^{24} - x^{25} + x^{26} - x^{27} + x^{28} - x^{29} + \mathcal{O}\left(x^{30}\right)% +} diff --git a/macros/latex/contrib/hybrid-latex/doc/hybrid.sty b/macros/latex/contrib/hybrid-latex/doc/hybrid.sty new file mode 100644 index 0000000000..d0c6efedeb --- /dev/null +++ b/macros/latex/contrib/hybrid-latex/doc/hybrid.sty @@ -0,0 +1,77 @@ +\usepackage{pylatex} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{listings} +\usepackage{xcolor} +\usepackage{graphicx} +\usepackage{geometry} +\usepackage[toc]{multitoc} +\usepackage{hyperref} +\usepackage{breqn} +\usepackage{longtable} + +\renewcommand*{\multicolumntoc}{2} +\setlength{\columnseprule}{0pt} +\setlength{\columnsep}{25pt} + +\hypersetup{colorlinks=true,filecolor=magenta} +% \geometry{papersize={210mm,297mm},hmargin=2cm,tmargin=1.0cm,bmargin=1.5cm} +% \geometry{papersize={210mm,297mm},hmargin=2cm,tmargin=1.0cm,bmargin=2.0cm} +\geometry{papersize={210mm,297mm},hmargin=2cm,tmargin=1.5cm,bmargin=2.0cm} +% \geometry{papersize={210mm,297mm},hmargin=2.5cm,tmargin=1.5cm,bmargin=2.5cm} + +\definecolor{grey95}{rgb}{0.95,0.95,0.95} + +\parindent=0pt +\parskip=8pt plus 2pt minus 1pt + +\def\tts{\tt\small} + +\def\MYn{\vrule height 0pt depth 5pt width 0pt} +\def\MYN{\vrule height 15pt depth 0pt width 0pt} + +\def\MyPar#1#2{\parbox[t]{#1\textwidth}{\sloppy \MYN#2\MYn}} + +\newbox\SlashPy +\setbox\SlashPy=\hbox{\tts\verb|\Py|} + +\newbox\SlashPyStar +\setbox\SlashPyStar=\hbox{\tts\verb|\Py*|} + +\def\PythonTeX{{\tts PythonTeX}} +\def\SymPyTeX{{\tts SymPyTeX}} +\def\SageTeX{{\tts SageTeX}} + +\def\pyLaTeX{{\tts pyLaTeX}} +\def\matLaTeX{{\tts matLaTeX}} +\def\mmaLaTeX{{\tts mmaLaTeX}} +\def\mplLaTeX{{\tts mplLaTeX}} +\def\cdbLaTeX{{\tts cdbLaTeX}} + +\def\bgcolour#1{\lstset{backgroundcolor=\color{#1}}} + +\def\pythonstyle{\lstset{% +language=python, +gobble=2, +basicstyle={\tts},basewidth={0.50em}, +numbers=none,numberstyle=\tiny,numbersep=10pt, +aboveskip=0pt,belowskip=0pt, +frame=none,framesep=0pt,framerule=0pt, +}} + +\def\latexstyle{\lstset{% +language={[LaTeX]TeX}, +gobble=2, +basicstyle={\tts},basewidth={0.50em}, +numbers=none,numberstyle=\tiny,numbersep=10pt, +aboveskip=0pt,belowskip=0pt, +frame=none,framesep=0pt,framerule=0pt, +texcsstyle=*\bfseries\color{blue}, +stringstyle=\color{green}, +commentstyle=\color{blue}\slshape, +}} + +\def\lstlatex#1{\def\latexmore{\lstset{#1}}} +\lstlatex{} + +\lstnewenvironment{latex}{\begingroup\latexstyle\latexmore}{\endgroup} diff --git a/macros/latex/contrib/hybrid-latex/doc/hybrid.tex b/macros/latex/contrib/hybrid-latex/doc/hybrid.tex new file mode 100644 index 0000000000..c226321e90 --- /dev/null +++ b/macros/latex/contrib/hybrid-latex/doc/hybrid.tex @@ -0,0 +1,1089 @@ +\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<path to pymacros.sty>] + [-P<path to python>] [-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} |