CTAN Comprehensive TeX Archive Network

Directory graphics/pgf/contrib/trainmap

README.md

trainmap

trainmap is a + TikZ package for drawing schematic railway and transit maps declaratively, in the style of the FGC / Rodalies line diagrams. Instead of positioning every node by hand, you describe a line or a whole network with a small, readable set of commands — \addstation, \addterminal, \forkup, \branch, and so on — and the package takes care of the geometry.

## Table of contents - [Features](#features) - [The two map styles (`mode`)](#the-two-map-styles-mode) - [Documentation](#documentation) - [Installation](#installation) - [Using it in your editor (TeXstudio)](#using-it-in-your-editor-texstudio) - [Quick start](#quick-start) - [Long lines: the serpentine layout](#long-lines-the-serpentine-layout) - [Command reference](#command-reference) - [Configuration keys](#configuration-keys) - [Predefined colours](#predefined-colours) - [How the engine works](#how-the-engine-works) - [Repository layout](#repository-layout) - [License](#license) ## Features - **Two map styles.** An **FGC** style that shows every line at once (with a line badge on each terminal), and a **Rodalies** style for a single line whose code is shown on a square plate at each end. Both still show interchanges. Selected with the `mode` key. - **Key–value configuration** through `pgfkeys`, all under the `/trainmap/` namespace: line colours, stroke widths, label angles and station sizes. Any key can be set once for the whole map or overridden on an individual station. - **Common trunk of parallel tracks.** Several lines can run together as a stacked bundle and then branch off or join at different heights. - **Multi-line station names.** Break a long name across lines with `\\`. - **Standard stations** drawn as a perpendicular tick crossing the whole bundle, with a rotated label (45° by default, configurable). - **Terminal / head stations** drawn as a larger filled disc, a **bold** name and a coloured **badge** carrying the line code (for example `S1`, `L6`). - **Interchange stations** drawn as a rounded capsule that groups all the parallel tracks, for stops shared by several services. - **Branches and forks** with smoothly curved diagonal connectors: `\forkup`, `\forkdown`, `\joinline`, `\branch`, `\track`. - **Automatic serpentine (snake) wrapping** for lines that are too long to fit on one row: set a maximum width and the line folds onto stacked rows joined by nested U-turns. - **Two ways to load it:** as a LaTeX package (`\usepackage{trainmap}`) or as a TikZ library (`\usetikzlibrary{trainmap}`). ## The two map styles (`mode`) The `mode` key selects how the diagram is presented. ### `mode=fgc` (default) — several lines at once Every line of the trunk is drawn. Each `\addterminal` shows a filled disc, the bold station name, and the line badge **below the disc**; interchanges are drawn as capsules. Use this when several services share the diagram (the classic FGC schematic look).

Full source: [`examples/fgc_style_map.tex`](examples/fgc_style_map.tex). ### `mode=rodalies` — a single line Only one line is drawn. Its code is shown as a **square plate at each end** of the whole route, with the line starting right next to the plate — so terminals no longer carry an individual badge. Station names appear as usual and shared stops are still marked as correspondences with `\addinterchange`. The code for the end plates is taken from `line code`, or automatically from the first `\addterminal` if you do not set it. ```latex \begin{trainmap}[mode=rodalies, badge color=tmR4] \settrunk{0/tmR4} \addterminal{Sant Vicenç de Calders}{R4} % opening [R4] plate \addstation{El Vendrell} % ... \addinterchange{Barcelona Sants} % a correspondence % ... \addterminal{Manresa}{R4} % closing [R4] plate \end{trainmap} ``` Because Rodalies lines tend to be long, this mode is normally combined with the [serpentine layout](#long-lines-the-serpentine-layout). See [`examples/rodalies_r4.tex`](examples/rodalies_r4.tex) for the full R4 line. ## Documentation The full user manual is included as **[`trainmap.pdf`](trainmap.pdf)** (source: [`trainmap-doc.tex`](trainmap-doc.tex)). It covers installation, the complete command and key reference, and worked examples with rendered diagrams. ## Installation The package is made of two files that must always travel together: | File | Role | |------|------| | `trainmap.sty` | LaTeX wrapper — enables `\usepackage{trainmap}`. | | `tikzlibrarytrainmap.code.tex` | The implementation — loaded by `\usetikzlibrary{trainmap}`. | ### Option A — from CTAN (once published) `trainmap` is prepared for distribution on [CTAN](https://ctan.org). Once it is available there, install it with your TeX distribution's package manager: ```bash tlmgr install trainmap # TeX Live mpm --install=trainmap # MiKTeX (or use the MiKTeX Console) ``` Most distributions also ship it in their package repositories, so it may already be installed. After that, `\usepackage{trainmap}` just works. ### Option B — next to your document (quickest) Copy **both** files into the same folder as your `.tex` file and compile with `pdflatex`. LaTeX always searches the document's own folder first, so nothing else is required. ### Option C — install into your personal `texmf` tree (available everywhere) ```bash # 1. Find your personal texmf root kpsewhich -var-value TEXMFHOME # Linux/macOS: usually ~/texmf # Windows/MiKTeX: usually C:\Users\

<user>AppDataRoamingMiK

  1. Create the destination folder and copy both files

mkdir -p "$(kpsewhich -var-value TEXMFHOME)/tex/latex/trainmap" cp trainmap.sty tikzlibrarytrainmap.code.tex
"$(kpsewhich -var-value TEXMFHOME)/tex/latex/trainmap/"

  1. Refresh the filename database

mktexlsr # Live

MiK: open the MiK Console -> Tasks -> Refresh file name database

(or run: initexmf –update-fndb)


On Windows you can copy the files manually instead of using the shell; the
destination folder is
`C:\Users\<user>\AppData\Roaming\MiKTeX\tex\latex\trainmap\`.
After a database refresh, `\usepackage{trainmap}` works from any document.

## Using it in your editor (TeXstudio)

**Compiling.** Build with **pdfLaTeX**. In TeXstudio press **F5** (build and
view) or **F6** (build only). If the default compiler is not pdfLaTeX, set it
under *Options → Configure TeXstudio → Build → Default Compiler → PdfLaTeX*.

**Removing the orange highlighting.** By default TeXstudio underlines any
command it does not know — so `\addstation`, `\addterminal`, etc. appear in a
warning colour even though the document compiles perfectly. This is only a
cosmetic check in the editor, not an error. To make TeXstudio recognise the
`trainmap` commands, install the bundled completion file `trainmap.cwl`:

1. In TeXstudio open *Help → Show Manual* is not needed — instead go to
   *Options → Configure TeXstudio → Completion* and note the user completion
   directory, or simply copy `trainmap.cwl` into TeXstudio's completion folder:
   - Windows: `C:\Users\<user>\AppData\Roaming\texstudio\completion\user\`
   - Linux: `~/.config/texstudio/completion/user/`
   - macOS: `~/Library/Application Support/texstudio/completion/user/`
2. Restart TeXstudio.

Once the file is in place and your document contains `\usepackage{trainmap}`,
the commands are treated as known and the orange highlighting disappears; you
also get autocompletion for the commands and their keys.

## Quick start

latex documentclassborder=10pt{standalone} usepackage{trainmap}

begin{document} % mode=rodalies -> a square S1 plate at each end of the line begin{trainmap}mode=rodalies, station step=2.0, badge color=tmS1 settrunk{0/tmS1} % a single orange track (S1) addterminal{Pl. Espanya}{S1} % first end (sets the line code) addstation{Magòria} addstation{Ildefons Cerdà} addinterchange{Sant Josep} % a correspondence / transfer addstationlabel position=below{Gornal} addstation{L'Hospitalet\de Llobregat} % \ = manual line break addterminal{Cornellà}{S1} % last end (closing plate) end{trainmap} end{document}


<p align="center">
  <img src="docs/preview_simple_line.png" alt="Simple S1 line, Rodalies style" width="86%">
</p>

Full source: [`examples/simple_line.tex`](examples/simple_line.tex).

## Long lines: the serpentine layout

When a line has too many stations to fit on a single row, enable **serpentine
wrapping**: set `max width` (the x, in cm, at which the line should wrap) and
optionally `row sep` (the vertical distance between rows). The cursor turns
automatically at the edge, drawing a nested U-turn, and you keep calling
`\addstation` as usual — no manual bookkeeping.
latex begin{trainmap}mode=rodalies, station step=1.6, max width=20, row sep=3.8, badge color=tmR4 settrunk{0/tmR4} addterminal{Sant Vicenç de Calders}{R4} addstation{El Vendrell} % ... many more stations ... addterminal{Manresa}{R4} end{trainmap}

<p align="center">
  <img src="docs/preview_rodalies_r4.png" alt="The R4 line folded into three rows" width="92%">
</p>

Full source: [`examples/rodalies_r4.tex`](examples/rodalies_r4.tex) — the complete
R4 line (38 stations) in Rodalies style, folded over three rows.

For a bundle of several parallel tracks the U-turns nest concentrically, so the
lines stay parallel and never cross. Serpentine wrapping is most useful for one
or a few lines; give `row sep` enough room that the rotated labels of one row do
not reach the row above.

## Command reference

### The `trainmap` environment
latex begin{trainmap}<keys> ... end{trainmap}

Wraps a `tikzpicture`, fixes the drawing unit to 1 cm, and resets the internal
cursor and trunk state. Any `/trainmap/` key may be given in `<keys>` as a map
wide default. You can still add ordinary TikZ code (`\node`, `\draw`,
`\coordinate`, …) inside the environment, which is how the examples place
off-trunk terminals.

### Defining the trunk
latex settrunk{<y>/<colour>, <y>/<colour>, ...}

Declares the parallel tracks that currently make up the common trunk. Each
entry is a vertical offset in centimetres and the colour of that track. The
tracks are drawn automatically between consecutive stations.

`\settrunk` may be **called again at any point** to change the active bundle —
for example after a line branches away it should be dropped from the trunk, or
a new line can be added. In the FGC example the trunk starts as four tracks and
is reduced to three and then two as L7 and L6 leave.

### Stations

| Command | What it draws |
|---------|---------------|
| `\addstation[<keys>]{<name>}` | A **standard station**: a perpendicular tick crossing every track of the trunk, plus a rotated label. |
| `\addterminal[<keys>]{<name>}{<line>}` | A **terminal / head station**: a filled disc in the badge colour and the name in bold above. In `fgc` mode a badge with `<line>` is drawn below the disc; in `rodalies` mode there is no per-terminal badge (the code appears on the end plates instead, and the first terminal's `<line>` becomes the line code if none was set). |
| `\addinterchange[<keys>]{<name>}` | An **interchange station**: a rounded capsule grouping all trunk tracks, with a coloured dot per line, and a bold label. |

Any `<name>` may contain `\\` to break it across several lines.

Every station call **advances the cursor** by `station step` centimetres (in
the current direction) before drawing, and publishes the reached position in the
macros `\tmlastx` and `\tmlasty`. This is how you anchor a branch to a station:
capture the value right after the call.
latex addstationname=gracia{Gràcia} edefgx{tmlastx} % gx now holds Gràcia's x coordinate

Passing `name=<id>` additionally creates three reusable coordinates:
`(<id>)` at the top track, `(<id>-mid)` at the band centre, and `(<id>-bot)` at
the bottom track.

Useful per-station keys: `label position=below` (label under the track),
`station step=<cm>` (a custom gap before this one), `badge color=<colour>`
(for terminals and interchanges).

### Tracks, branches and forks

The `<from>` and `<to>` arguments are passed **with their parentheses**, so they
accept explicit coordinates, named nodes, or `calc` expressions
interchangeably:
latex forkup{(gx,0.36)}{(avtib)}{tmL7} % coordinate -> named node track{(sarria)}{($(sarria)+(2,0)$)}{tmL6} % named node -> calc expression

| Command | What it draws |
|---------|---------------|
| `\track[<opts>]{<from>}{<to>}{<colour>}` | A straight track segment. |
| `\branch[<opts>]{<from>}{<to>}{<colour>}` | A gentle, near-horizontal curved branch. |
| `\forkup[<opts>]{<from>}{<to>}{<colour>}` | A branch that peels **upwards** (alias: `\forkline`). |
| `\forkdown[<opts>]{<from>}{<to>}{<colour>}` | A branch that peels **downwards**. |
| `\joinline[<opts>]{<from>}{<to>}{<colour>}` | A branch **merging back** into the trunk from below. |

`<opts>` is an optional list of raw TikZ options appended to the `\draw`
(for example `[looseness=1.2]` or `[dashed]`).

## Configuration keys

All keys live under `/trainmap/`. Set them on the environment for a map-wide
default, or in a command's `[ ... ]` to override a single element.

| Key | Default | Meaning |
|-----|---------|---------|
| `mode` | `fgc` | Map style: `fgc` (all lines, badges on terminals) or `rodalies` (single line, code on end plates). |
| `line code` | (empty) | Code shown on the end plates in `rodalies` mode. If empty, it is taken from the first `\addterminal`. |
| `line color` | `black` | Fallback colour of a single track. |
| `track width` | `2pt` | Stroke width of a track. |
| `station color` | `black` | Colour of the station tick mark. |
| `station width` | `1.8pt` | Stroke width of the tick mark. |
| `terminal size` | `8pt` | Diameter of the terminal disc. |
| `terminal border` | `1.4pt` | Border width of the terminal disc. |
| `badge color` | `black` | Background colour of the line badge. |
| `capsule width` | `12pt` | Outer width of the interchange capsule. |
| `capsule inner` | `8pt` | Inner (white) width of the capsule. |
| `capsule color` | `black` | Border colour of the capsule. |
| `station step` | `1.6` | Horizontal distance between stations (cm). |
| `track sep` | `0.16` | Suggested vertical gap between parallel tracks (cm). |
| `max width` | `0` | Wrap to a new row once the cursor passes this x (cm). `0` disables wrapping. |
| `row sep` | `2.6` | Vertical distance between wrapped rows (cm). |
| `label angle` | `45` | Rotation of the station labels (degrees). |
| `label position` | `above` | `above` or `below` — label over or under the track. |

## Predefined colours

The package defines the official line colours of **Rodalies de Catalunya** and
**FGC**; you can also use any `xcolor` colour such as `red` or `blue!60!black`.

**Rodalies de Catalunya**

| Name | Line | Name | Line | Name | Line |
|------|------|------|------|------|------|
| `tmR1` | R1 | `tmR8` | R8 | `tmR16` | R16 |
| `tmR2` | R2 | `tmR11` | R11 | `tmR17` | R17 |
| `tmR2N` | R2 Nord | `tmR12` | R12 | `tmRL1` | RL1 |
| `tmR2S` | R2 Sud | `tmR13` | R13 | `tmRL2` | RL2 |
| `tmR3` | R3 | `tmR14` | R14 | `tmRG1` | RG1 |
| `tmR4` | R4 | `tmR15` | R15 | `tmRT1` | RT1 |
| `tmR7` | R7 | | | `tmRT2` | RT2 |

**FGC** — Barcelona-Vallès: `tmL6`, `tmL7`, `tmL12`, `tmS1`, `tmS2`.
Llobregat-Anoia: `tmL8`, `tmR5`, `tmR50`, `tmR6`, `tmR60`.

### Correspondences

Any station accepts a `corr` key listing the connecting lines as
`CODE/colour` pairs; each becomes a small coloured chip stacked beneath the
station (as on the R7 map at the top of this page):
latex addstationcorr={R3/tmR3, R4/tmR4}{Montcada Bifurcació}

## How the engine works

`trainmap` keeps a small amount of state — a horizontal **cursor**, a travelling
**direction**, a **row** index and the list of trunk tracks. Each `\add...`
call advances the cursor, draws the trunk segment(s) leading up to it, and then
draws the station symbol and label. Coordinates are placed with `pgfmath`, so
the vertical positions of the tracks, the tick extents and the label anchors are
all derived from the keys rather than hard-coded.

For the serpentine layout the absolute y of a track stored as `l` is

y(l) = (rowbase + center) + sign (l - center)


On the first row this reduces to `y = l`, so ordinary maps keep their absolute
coordinates (hand-placed branch endpoints remain valid). On a wrapped row the
`sign` flips, which mirrors the track order — exactly what a parallel U-turn
needs so the connecting half-loops nest concentrically instead of crossing.

## Repository layout

trainmap/ ├── trainmap.sty # wrapper ├── tikzlibrarytrainmap.code.tex # Core TikZ library (the implementation) ├── trainmap.cwl # studio/works completion file ├── trainmap-doc.tex # User manual (source) ├── trainmap.pdf # User manual (compiled) ├── examples/ │ ├── simpleline.tex # Rodalies style: one line, end plates │ ├── rodaliesr7.tex # Rodalies style + correspondences (the R7 line) │ ├── fgcstylemap.tex # FGC style: common trunk, branches, interchange │ └── rodaliesr4.tex # Rodalies style + serpentine: the full R4 line ├── docs/ │ ├── previewsimpleline.png │ ├── previewrodaliesr7.png │ ├── previewfgcstylemap.png │ └── previewrodaliesr4.png ├── README.md ├── LICENSE # Project Public License v1.3c └── .gitignore


To build every example locally:
bash cd examples pdflatex simpleline.tex pdflatex rodaliesr7.tex pdflatex fgcstylemap.tex pdflatex rodaliesr4.tex

## License

Released under the **LaTeX Project Public License (LPPL), version 1.3c** or (at
your option) any later version — see [`LICENSE`](LICENSE). This is the standard
license for LaTeX packages and is the license under which `trainmap` is
distributed on CTAN. The package has LPPL maintenance status *maintained*; the
Current Maintainer is **Pol Sardà Palla**.

Download the contents of this package in one zip archive (422.8k).

TrainMap – Draw railway line schematics and transit network maps with

TrainMap is an open-source package built on for designing schematic railway line maps and public transport networks. It abstracts complex vector graphics into high-level declarative commands, allowing users to draw straight and branching rail lines using pgfkeys styling. The package provides native commands for rendering intermediate stations with angled labels (45°) and terminal stations highlighted with bold typography and line-code badges. It includes custom layout environments to prevent label overlap, built-in scaling compatibility for multi-station lines, and a full CTAN-compliant structure featuring LPPL v1.3c licensing, automated build files, and comprehensive usage documentation.

PackageTrainMap
Version1.0.0 2026-08-28
LicensesThe Project Public License 1.3
Copyright2026 Pol Sardà Palla
MaintainerPol Sardà Palla
TopicsDiagrams
Graphics
PGF
...
Guest Book Sitemap Contact Contact Author