# Module text: TeX/LaTeX interface¶

## Basic functionality¶

The text module seamlessly integrates Donald E. Knuths famous TeX typesetting engine into PyX. The basic procedure is:

• start a TeX/LaTeX instance as soon as a TeX/LaTeX preamble setting or a text creation is requested
• create boxes containing the requested text and shipout those boxes to the dvi file
• immediately analyse the TeX/LaTeX output for errors; the box extents are also contained in the TeX/LaTeX output and thus become available immediately
• when your TeX installation supports the ipc mode and PyX is configured to use it, the dvi output is also analysed immediately; alternatively PyX quits the TeX/LaTeX instance to read the dvi file once the output needs to be generated or marker positions are accessed
• Type1 fonts are used for the PostScript generation

Note that for using Type1 fonts an appropriate font mapping file has to be provided. When your TeX installation is configured to use Type1 fonts by default, the psfonts.map will contain entries for the standard TeX fonts already. Alternatively, you may either look for updmap used by many TeX distributions to create an appropriate font mapping file. You may also specify one or several alternative font mapping files like psfonts.cmz in the global pyxrc or your local .pyxrc. Finally you can also use the fontmap keyword argument to a texrunners text() method to use different mappings within a single outout file.

## TeX/LaTeX instances: the texrunner class¶

Instances of the class texrunner are responsible for executing and controling a TeX/LaTeX instance.

class text.texrunner(mode="tex", lfs="10pt", docclass="article", docopt=None, usefiles=[], fontmaps=config.get("text", "fontmaps", "psfonts.map"), waitfortex=config.getint("text", "waitfortex", 60), showwaitfortex=config.getint("text", "showwaitfortex", 5), texipc=config.getboolean("text", "texipc", 0), texdebug=None, dvidebug=0, errordebug=1, pyxgraphics=1, texmessagesstart=[], texmessagesdocclass=[], texmessagesbegindoc=[], texmessagesend=[], texmessagesdefaultpreamble=[], texmessagesdefaultrun=[])

mode should the string tex or latex and defines whether TeX or LaTeX will be used. lfs specifies an lfs file to simulate LaTeX font size selection macros in plain TeX. PyX comes with a set of lfs files and a LaTeX script to generate those files. For lfs being None and mode equals tex a list of installed lfs files is shown.

docclass is the document class to be used in LaTeX mode and docopt are the options to be passed to the document class.

usefiles is a list of TeX/LaTeX jobname files. PyX will take care of the creation and storing of the corresponding temporary files. A typical use-case would be usefiles=[“spam.aux”], but you can also use it to access TeXs log and dvi file.

fontmaps is a string containing whitespace separated names of font mapping files. waitfortex is a number of seconds PyX should wait for TeX/LaTeX to process a request. While waiting for TeX/LaTeX a PyX process might seem to do not perform any work anymore. To give some feedback to the user, a messages is issued each waitfortex seconds. The texipc flag indicates whether PyX should use the --ipc option of TeX/LaTeX for immediate dvi file access to increase the execution speed of certain operations. See the output of tex --help whether the option is available at your TeX installation.

texdebug can be set to a filename to store the commands passed to TeX/LaTeX for debugging. The flag dvidebug enables debugging output in the dvi parser similar to dvitype. errordebug controls the amount of information returned, when an texmessage parser raises an error. Valid values are 0, 1, and 2.

pyxgraphics allows use LaTeXs graphics package without further configuration of pyx.def.

The TeX message parsers verify whether TeX/LaTeX could properly process its input. By the parameters texmessagesstart, texmessagesdocclass, texmessagesbegindoc, and texmessagesend you can set TeX message parsers to be used then TeX/LaTeX is started, when the documentclass command is issued (LaTeX only), when the \\begin{document} is sent, and when the TeX/LaTeX is stopped, respectively. The lists of TeX message parsers are merged with the following defaults: [texmessage.start] for texmessagesstart, [texmessage.load] for texmessagesdocclass, [texmessage.load, texmessage.noaux] for texmessagesbegindoc, and [texmessage.texend, texmessage.fontwarning] for texmessagesend.

Similarily texmessagesdefaultpreamble and texmessagesdefaultrun take TeX message parser to be merged to the TeX message parsers given in the preamble() and text() methods. The texmessagesdefaultpreamble and texmessagesdefaultrun are merged with [texmessage.load] and [texmessage.loaddef, texmessage.graphicsload, texmessage.fontwarning, texmessage.boxwarning], respectively.

texrunner instances provides several methods to be called by the user:

texrunner.set(**kwargs)

This method takes the same keyword arguments as the texrunner constructor. Its purpose is to reconfigure an already constructed texrunner instance. The most prominent use-case is to alter the configuration of the default texrunner instance defaulttexrunner which is created at the time of loading of the text module.

The set method fails, when a modification cannot be applied anymore (e.g. TeX/LaTeX has already been started).

texrunner.preamble(expr, texmessages=[])

The preamble() can be called prior to the text() method only or after reseting a texrunner instance by reset(). The expr is passed to the TeX/LaTeX instance not encapsulated in a group. It should not generate any output to the dvi file. In LaTeX preamble expressions are inserted prior to the \\begin{document} and a typical use-case is to load packages by \\usepackage. Note, that you may use \\AtBeginDocument to postpone the immediate evaluation.

texmessages are TeX message parsers to handle the output of TeX/LaTeX. They are merged with the default TeX message parsers for the preamble() method. See the constructur description for details on the default TeX message parsers.

texrunner.text(x, y, expr, textattrs=[], texmessages=[])

x and y are the position where a text should be typeset and expr is the TeX/LaTeX expression to be passed to TeX/LaTeX.

textattrs is a list of TeX/LaTeX settings as described below, PyX transformations, and PyX fill styles (like colors).

texmessages are TeX message parsers to handle the output of TeX/LaTeX. They are merged with the default TeX message parsers for the text() method. See the constructur description for details on the default TeX message parsers.

The text() method returns a textbox instance, which is a special canvas instance. It has the methods width(), height(), and depth() to access the size of the text. Additionally the marker() method, which takes a string s, returns a position in the text, where the expression \\PyXMarker{s} is contained in expr. You should not use @ within your strings s to prevent name clashes with PyX internal macros (although we don’t the marker feature internally right now).

Note that for the outout generation and the marker access the TeX/LaTeX instance must be terminated except when texipc is turned on. However, after such a termination a new TeX/LaTeX instance is started when the text() method is called again.

texrunner.reset(reinit=0)

This method can be used to manually force a restart of TeX/LaTeX. The flag reinit will initialize the TeX/LaTeX by repeating the preamble() calls. New set() and preamble() calls are allowed when reinit was not set only.

## TeX/LaTeX attributes¶

TeX/LaTeX attributes are instances to be passed to a texrunners text() method. They stand for TeX/LaTeX expression fragments and handle dependencies by proper ordering.

class text.halign(boxhalign, flushhalign)

Instances of this class set the horizontal alignment of a text box and the contents of a text box to be left, center and right for boxhalign and flushhalign being 0, 0.5, and 1. Other values are allowed as well, although such an alignment seems quite unusual.

Note that there are two separate classes boxhalign and flushhalign to set the alignment of the box and its contents independently, but those helper classes can’t be cleared independently from each other. Some handy instances available as class members:

halign.boxleft

Left alignment of the text box, i.e. sets boxhalign to 0 and doesn’t set flushhalign.

halign.boxcenter

Center alignment of the text box, i.e. sets boxhalign to 0.5 and doesn’t set flushhalign.

halign.boxright

Right alignment of the text box, i.e. sets boxhalign to 1 and doesn’t set flushhalign.

halign.flushleft

Left alignment of the content of the text box in a multiline box, i.e. sets flushhalign to 0 and doesn’t set boxhalign.

halign.raggedright

Identical to flushleft.

halign.flushcenter

Center alignment of the content of the text box in a multiline box, i.e. sets flushhalign to 0.5 and doesn’t set boxhalign.

halign.raggedcenter

Identical to flushcenter.

halign.flushright

Right alignment of the content of the text box in a multiline box, i.e. sets flushhalign to 1 and doesn’t set boxhalign.

halign.raggedleft

Identical to flushright.

halign.left

Combines boxleft and flushleft, i.e. halign(0, 0).

halign.center

Combines boxcenter and flushcenter, i.e. halign(0.5, 0.5).

halign.right

Combines boxright and flushright, i.e. halign(1, 1).

valign example

class text.valign(valign)

Instances of this class set the vertical alignment of a text box to be top, center and bottom for valign being 0, 0.5, and 1. Other values are allowed as well, although such an alignment seems quite unusual. See the left side of figure valign example for an example.

Some handy instances available as class members:

valign.top

valign(0)

valign.middle

valign(0.5)

valign.bottom

valign(1)

valign.baseline

Identical to clearing the vertical alignment by clear to emphasise that a baseline alignment is not a box-related alignment. Baseline alignment is the default, i.e. no valign is set by default.

class text.parbox(width, baseline=top)

Instances of this class create a box with a finite width, where the typesetter creates multiple lines in. Note, that you can’t create multiple lines in TeX/LaTeX without specifying a box width. Since PyX doesn’t know a box width, it uses TeXs LR-mode by default, which will always put everything into a single line. Since in a vertical box there are several baselines, you can specify the baseline to be used by the optional baseline argument. You can set it to the symbolic names top, parbox.middle, and parbox.bottom only, which are members of valign. See the right side of figure valign example for an example.

Since you need to specify a box width no predefined instances are available as class members.

class text.vshift(lowerratio, heightstr="0")

Instances of this class lower the output by lowerratio of the height of the string heigthstring. Note, that you can apply several shifts to sum up the shift result. However, there is still a clear class member to remove all vertical shifts.

Some handy instances available as class members:

vshift.bottomzero

vshift(0) (this doesn’t shift at all)

vshift.middlezero

vshift(0.5)

vshift.topzero

vshift(1)

vshift.mathaxis

This is a special vertical shift to lower the output by the height of the mathematical axis. The mathematical axis is used by TeX for the vertical alignment in mathematical expressions and is often usefull for vertical alignment. The corresponding vertical shift is less than middlezero and usually fits the height of the minus sign. (It is the height of the minus sign in mathematical mode, since that’s that the mathematical axis is all about.)

There is a TeX/LaTeX attribute to switch to TeXs math mode. The appropriate instances mathmode and clearmathmode (to clear the math mode attribute) are available at module level.

text.mathmode

Enables TeXs mathematical mode in display style.

The size class creates TeX/LaTeX attributes for changing the font size.

class text.size(sizeindex=None, sizename=None, sizelist=defaultsizelist)

LaTeX knows several commands to change the font size. The command names are stored in the sizelist, which defaults to ["normalsize", "large", "Large", "LARGE", "huge", "Huge", None, "tiny", "scriptsize", "footnotesize", "small"].

You can either provide an index sizeindex to access an item in sizelist or set the command name by sizename.

Instances for the LaTeXs default size change commands are available as class members:

size.tiny

size(-4)

size.scriptsize

size(-3)

size.footnotesize

size(-2)

size.small

size(-1)

size.normalsize

size(0)

size.large

size(1)

size.Large

size(2)

size.LARGE

size(3)

size.huge

size(4)

size.Huge

size(5)

There is a TeX/LaTeX attribute to create empty text boxes with the size of the material passed in. The appropriate instances phantom and clearphantom (to clear the phantom attribute) are available at module level.

text.phantom

Skip the text in the box, but keep its size.

## Using the graphics-bundle with LaTeX¶

The packages in the LaTeX graphics bundle (color.sty, graphics.sty, graphicx.sty, ...) make extensive use of \\special commands. PyX defines a clean set of such commands to fit the needs of the LaTeX graphics bundle. This is done via the pyx.def driver file, which tells the graphics bundle about the syntax of the \\special commands as expected by PyX. You can install the driver file pyx.def into your LaTeX search path and add the content of both files color.cfg and graphics.cfg to your personal configuration files. [1] After you have installed the cfg files, please use the text module with unset pyxgraphics keyword argument which will switch off a convenience hack for less experienced LaTeX users. You can then import the LaTeX graphics bundle packages and related packages (e.g. rotating, ...) with the option pyx, e.g. \\usepackage[pyx]{color,graphicx}. Note that the option pyx is only available with unset pyxgraphics keyword argument and a properly installed driver file. Otherwise, omit the specification of a driver when loading the packages.

When you define colors in LaTeX via one of the color models gray, cmyk, rgb, RGB, hsb, then PyX will use the corresponding values (one to four real numbers). In case you use any of the named colors in LaTeX, PyX will use the corresponding predefined color (see module color and the color table at the end of the manual). The additional LaTeX color model pyx allows to use a PyX color expression, such as color.cmyk(0,0,0,0) directly in LaTeX. It is passed to PyX.

When importing Encapsulated PostScript files (eps files) PyX will rotate, scale and clip your file like you expect it. Other graphic formats can not be imported via the graphics package at the moment.

For reference purpose, the following specials can be handled by PyX at the moment:

PyX:color_begin (model) (spec)
starts a color. (model) is one of gray, cmyk, rgb, hsb, texnamed, or pyxcolor. (spec) depends on the model: a name or some numbers
PyX:color_end
ends a color.
PyX:epsinclude file= llx= lly= urx= ury= width= height= clip=0/1
includes an Encapsulated PostScript file (eps files). The values of llx to ury are in the files’ coordinate system and specify the part of the graphics that should become the specified width and height in the outcome. The graphics may be clipped. The last three parameters are optional.
PyX:scale_begin (x) (y)
begins scaling from the current point.
PyX:scale_end
ends scaling.
PyX:rotate_begin (angle)
begins rotation around the current point.
PyX:rotate_end
ends rotation.

## TeX message parsers¶

Message parsers are used to scan the output of TeX/LaTeX. The output is analysed by a sequence of TeX message parsers. Each message parser analyses the output and removes those parts of the output, it feels responsible for. If there is nothing left in the end, the message got validated, otherwise an exception is raised reporting the problem. A message parser might issue a warning when removing some output to give some feedback to the user.

class text.texmessage

This class acts as a container for TeX message parsers instances, which are all instances of classes derived from texmessage.

The following TeX message parser instances are available:

texmessage.start

Check for TeX/LaTeX startup message including scrollmode test.

texmessage.noaux

Ignore LaTeXs no-aux-file warning.

texmessage.end

Check for proper TeX/LaTeX tear down message.

Accepts arbitrary loading of files without checking for details, i.e. accept (file ...) where file is an readable file.

Accepts arbitrary loading of fd files, i.e. accept (file.def) and (file.fd) where file.def or file.fd is an readable file, respectively.

texmessage.ignore

Ignores everything (this is probably a bad idea, but sometimes you might just want to ignore everything).

texmessage.allwarning

Ignores everything but issues a warning.

texmessage.fontwarning

Issues a warning about font substitutions of the LaTeXs NFSS.

texmessage.boxwarning

Issues a warning on under- and overfull horizontal and vertical boxes.

class text.texmessagepattern(pattern, warning=None)

This is a derived class of texmessage. It can be used to construct simple TeX message parsers, which validate a TeX message matching a certain regular expression pattern pattern. When warning is set, a warning message is issued. Several of the TeX message parsers described above are implemented using this class.

## The defaulttexrunner instance¶

text.defaulttexrunner

The defaulttexrunner is an instance of texrunner. It is created when the text module is loaded and it is used as the default texrunner instance by all canvas instances to implement its text() method.

text.preamble(...)

defaulttexrunner.preamble

text.text(...)

defaulttexrunner.text

text.set(...)

defaulttexrunner.set

text.reset(...)

defaulttexrunner.reset

## Some internals on temporary files¶

It is not totally obvious how TeX processes are supervised by PyX and why it’s done that way. However there are good reasons for it and the following description is intended for people wanting and/or needing to understand how temporary files are used by PyX. All others don’t need to care.

Each time PyX needs to start a new TeX process, it creates a base file name for temporary files associated with this process. This file name is used as \jobname by TeX. Since TeX does not handle directory names as part of \jobname, the temporary files will be created in the current directory. The PyX developers decided to not change the current directory at all, avoiding all kind of issues with accessing files in the local directory, like for loading graph data, LaTeX style files etc.

PyX creates a TeX file containing \relax only. It’s only use is to set TeXs \jobname. Immediately after processing \relax TeX falls back to stdin to read more commands. PyX than uses stdin and stdout to avoid various buffering issues which would occur when using files (or named pipes). By that PyX can fetch TeX errors as soon as they occur while keeping the TeX process running (i.e. in a waiting state) for further input. The size of the TeX output is also availble immediately without fetching the dvi file created by TeX, since PyX uses some TeX macros to output the extents of the boxes created for the requested texts to stdout immediately. There is a TeX hack --ipc which PyX knows to take advantage of to fetch informations from the dvi file immediately as well, but it’s not available on all TeXinstallations. Thus this feature is disabled by default and fetching informations from the dvi is tried to be limited to those cases, where no other option exists. By that TeX usually doesn’t need to be started several times.

By default PyX will clean up all temporary files after TeX was stopped. However the usefiles list allows for a renaming of the files from (and to, if existing) the temporary \jobname (+ suffix) handled by PyX. Additionally, since PyX does not write a useful TeX input file in a file and thus a usefiles=["example.tex"] would not contain the code actually passed to TeX, the texdebug feature of the texrunner can be used instead to get a the full input passed to TeX.

In case you need to control the position where the temporary files are created (say, you’re working on a read-only directory), the suggested solution is to switch the current directory before starting with text processing in PyX (i.e. an os.chdir at the beginning of your script will do fine). You than just need to take care of specifying full paths when accessing data from your original working directory, but that’s intended and necessary for that case.

Footnotes

 [1] If you do not know what this is all about, you can just ignore this paragraph. But be sure that the pyxgraphics keyword argument is always set!