% File: numodel-plot-manual.tex
% Standalone manual for the numodel-plot package.

\documentclass{ltxdoc}
\usepackage[left=3.5cm, right=2cm, top=2cm, bottom=2cm,
            marginparwidth=3.5cm, marginparsep=0.3cm]{geometry}
\usepackage{numodel-plot}
\usepackage{subcaption}
\EnableCrossrefs
\CodelineIndex

% Fonts.  fontspec + unicode-math require LuaLaTeX.
\usepackage{fontspec}
\setmainfont{Arial}
\usepackage{unicode-math}
\setmathfont{Lete Sans Math}
\setmonofont{Fira Mono}

% Breakable inline verbatim (see numodel-manual.tex for rationale).
\usepackage{fvextra}
\AtBeginDocument{%
  \MakeShortVerb{\|}%
  \DeleteShortVerb{\|}%
  \DefineShortVerb[breaklines,breakanywhere]{\|}%
}

% tcolorbox+listings for example boxes that both display and execute.
\usepackage{tcolorbox}
\tcbuselibrary{listings,skins,breakable}

\lstdefinestyle{numodelcode}{
  basicstyle=\small\ttfamily,
  breaklines=true,
  columns=fullflexible,
  keepspaces=true,
  showstringspaces=false,
}

\NewTCBListing{plotexample}{}{%
  enhanced,
  breakable,
  listing style=numodelcode,
  colback=black!3,
  colframe=black!50,
  boxrule=0.4pt,
  arc=2pt,
  before skip=10pt,
  after skip=10pt,
}

% Match tick-label backgrounds to the plotexample colback so the
% manual's example plots blend into the listing's gray frame instead
% of the package default (fill=white).  See §"Tick label backgrounds"
% in the body for how end users adapt this to their own document.
\pgfplotsset{numodel/axis/.append style={%
  xticklabel style={fill=black!3},%
  yticklabel style={fill=black!3}%
}}

\begin{document}

\CheckSum{0}

\changes{v0.1}{2026/04/24}{Initial version, extracted from internal
  project sources.}
\changes{v0.2.0}{2026/05/16}{l3build workflow; bundle structure
  with numodel; \cs{drawplot} now invokes \cs{calcplotdims}
  internally; default axis-label-format renamed to \texttt{ieee}.}
\changes{v0.3.0}{2026/05/17}{Fix \cs{par}-token leak in
  \cs{calcplotdims} that bloated the picture bounding box inside
  horizontal boxes; fix \texttt{grid / unknown} key syntax so custom
  \texttt{grid=} values work; move \texttt{legend pos=outer north
  east} into the \texttt{numodel/axis} style so it can be overridden;
  add rendered example plots throughout the manual.}
\changes{v0.4.0}{2026/05/19}{Version-sync release with
  \textsf{numodel}~v0.4.0; no functional changes to
  \textsf{numodel-plot} itself.  Example files renamed from
  \texttt{numodel-plot-simple.tex}/\texttt{numodel-plot-scaled.tex}
  to \texttt{numodel-plot-example-basic.tex}/\texttt{numodel-plot-example-scaled.tex}.}
\changes{v0.5.0}{2026/05/23}{Version-sync release with
  \textsf{numodel}~v0.5.0; no functional changes to
  \textsf{numodel-plot} itself.}

\GetFileInfo{numodel-plot.sty}

\DoNotIndex{\newcommand,\newenvironment,\def,\edef,\let,\global,
  \RequirePackage,\usepgfplotslibrary,\pgfplotsset,\ProvidesPackage,
  \NeedsTeXFormat,\makeatletter,\makeatother,\endinput,\providecommand,
  \NewDocumentCommand,\ExplSyntaxOn,\ExplSyntaxOff,\ifnum,\ifdefined,
  \fi,\else,\relax,\undefined,\fpeval,\si,\qty,\num,\penalty,\nobreak,
  \begin,\end,\thinspace}

\title{The \textsf{numodel-plot} package\thanks{This document
  corresponds to \textsf{numodel-plot}~\fileversion, dated \today.}}
\author{Paul Zuurbier \\ \texttt{mail@paulzuurbier.nl}}
\date{\today}
\maketitle

\begin{abstract}
A PGFPlots engine that auto-sizes plots to a whole number of tick
intervals, supports configurable axis-label formats (IEEE-style
by default; ISO 80000-1 also supported), and automatically selects
label placement for 1-, 2-, and 4-quadrant graphs.  Part of the \textsf{numodel} package suite, but
can be loaded standalone as an independent PGFPlots styling layer.
\end{abstract}

\tableofcontents

\section{Introduction}

\textsf{numodel-plot} fills a gap between bare PGFPlots and the
heavy styling required for physics-teaching material: it sizes every
axis to an integer number of centimetre ticks, lays out the axis
origin according to which quadrants of the coordinate plane contain
data, and renders axis labels as either |quantity (unit)| (IEEE,
the default) or one of four alternative conventions selectable at
package level.  It was extracted from a Dutch high-school physics
test set where uniform plot appearance across hundreds of graphs is
more valuable than per-graph tweaking, and hence adopts an
opinionated default style.  Users who need one-off deviations are
expected to drop to plain PGFPlots with the variable macros
|\xmin|, |\xmax|, \ldots{} exposed by this package.

\newpage
\section{Usage}

Minimum working example (assuming |\usepackage{numodel-plot}| in
the preamble):

\begin{plotexample}
\def\xmin{-5}   \def\xmax{10}
\def\ymin{-3}   \def\ymax{5}
\def\xlabelqty{t}  \def\xlabelunit{\s}
\def\ylabelqty{v}  \def\ylabelunit{\m\per\s}
\drawplot{\addplot[domain=\xmin:\xmax]{0.5*x};}
\end{plotexample}

The user sets the data range (|\xmin|\ldots|\ymax|) and optionally a
quantity symbol plus \textsf{siunitx} unit for each axis.
|\drawplot| internally calls |\calcplotdims| to round the range to a
clean tick lattice and compute the axis size in centimetres, then
renders a full |tikzpicture|+|axis| environment whose body is the
argument (one or more |\addplot| lines).

Labels are built automatically from |\xlabelqty|+|\xlabelunit| (and
likewise for the $y$-axis).  If the data magnitude exceeds $10^{4}$
or is below $10^{-2}$, a factor~$10^{n}$ is injected into the label
and PGFPlots' own |scaled ticks| are configured so that tick numbers
remain small.  In the next example the data magnitude is
$5\times10^{7}$ and the unit |\mega\joule\per\kilo\gram| already
carries two engineering prefixes; the package extracts every prefix
and combines them with the magnitude into a single power-of-ten
factor:
\begin{plotexample}
\def\xmin{0}   \def\xmax{10}
\def\ymin{0}   \def\ymax{5e7}
\def\xlabelqty{m}  \def\xlabelunit{\kilo\gram}
\def\ylabelqty{E}  \def\ylabelunit{\mega\joule\per\kilo\gram}
\drawplot{\addplot[domain=\xmin:\xmax]{5e6*x};}
\end{plotexample}

Users preferring full control can omit |\xlabelqty|/|\xlabelunit|
and set |\xlabel|/|\ylabel| directly; the package will use them
verbatim.

\section{Configuration}

\DescribeMacro{\numodelplotsetup}
Configuration is set through a single key--value interface:
\begin{quote}
\begin{verbatim}
\numodelplotsetup{axis-label-format=ieee, grid=mm-dots}
\end{verbatim}
\end{quote}

\subsection{Keys}

\begin{description}
\item[\texttt{axis-label-format}] Default |ieee|.  Determines the
  notation emitted for axis labels built from |\xlabelqty| and
  |\xlabelunit|:
  \begin{center}
  \begin{tabular}{lll}
    \texttt{ieee}      & \verb|v (m/s)|      & IEEE (default) \\
    \texttt{iso}       & \verb|v / (m/s)|    & ISO 80000-1 \\
    \texttt{brackets}  & \verb|v [m/s]|      & older physics convention \\
    \texttt{qty-only}  & \verb|v|            & quantity symbol only \\
    \texttt{unit-only} & \verb|m/s|          & unit only \\
  \end{tabular}
  \end{center}
  When scaling is applied (data exceeds $10^{4}$ or below
  $10^{-2}$), the factor is integrated into the label, e.g.\
  \verb|v (10^4 m/s)| for IEEE.  Under |qty-only| the exponent
  remains in PGFPlots' scaled-tick label instead (otherwise the
  scale information would be lost).
\item[\texttt{grid}] Default |mm-dots| (black millimetre dots,
  matching engineering millimetre paper).  Accepts |none|, or any
  PGFPlots style list which will be passed verbatim to the
  |numodel/grid| style.
\item[\texttt{xcmmax}, \texttt{ycmmax}] Maximum axis width and
  height in centimetres (defaults 12 and 10).
\end{description}

The first three axis-label formats render as follows.  Each plot
uses |\numodelplotsetup{xcmmax=3, ycmmax=3}| so the axis itself is
trimmed to a 2~cm by 3~cm tick lattice (the package's invariant 1~cm
major-grid spacing is preserved):

\begin{plotexample}
\captionsetup{type=figure}%
\begin{subfigure}{0.33\textwidth}\centering
\numodelplotsetup{xcmmax=3, ycmmax=3, axis-label-format=ieee}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{v}\def\xlabelunit{\m\per\s}%
\def\ylabelqty{F}\def\ylabelunit{\N}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.4*x};}
\caption*{\texttt{ieee}}
\end{subfigure}\hspace{-1cm}%
\begin{subfigure}{0.33\textwidth}\centering
\numodelplotsetup{xcmmax=3, ycmmax=3, axis-label-format=iso}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{v}\def\xlabelunit{\m\per\s}%
\def\ylabelqty{F}\def\ylabelunit{\N}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.4*x};}
\caption*{\texttt{iso}}
\end{subfigure}\hspace{-1cm}%
\begin{subfigure}{0.33\textwidth}\centering
\numodelplotsetup{xcmmax=3, ycmmax=3, axis-label-format=brackets}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{v}\def\xlabelunit{\m\per\s}%
\def\ylabelqty{F}\def\ylabelunit{\N}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.4*x};}
\caption*{\texttt{brackets}}
\end{subfigure}
\end{plotexample}
\numodelplotsetup{axis-label-format=ieee}%

Three grid variants, sized the same way:

\begin{plotexample}
\captionsetup{type=figure}%
\begin{subfigure}{0.33\textwidth}\centering
\numodelplotsetup{xcmmax=3, ycmmax=3, grid=mm-dots}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{t}\def\xlabelunit{\s}%
\def\ylabelqty{v}\def\ylabelunit{\m\per\s}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.5*x};}
\caption*{\texttt{mm-dots}}
\end{subfigure}\hspace{-1cm}%
\begin{subfigure}{0.33\textwidth}\centering
\numodelplotsetup{xcmmax=3, ycmmax=3, grid=none}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{t}\def\xlabelunit{\s}%
\def\ylabelqty{v}\def\ylabelunit{\m\per\s}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.5*x};}
\caption*{\texttt{none}}
\end{subfigure}\hspace{-1cm}%
\begin{subfigure}{0.33\textwidth}\centering
\numodelplotsetup{xcmmax=3, ycmmax=3,
  grid={grid=major, grid style={gray, very thin}}}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{t}\def\xlabelunit{\s}%
\def\ylabelqty{v}\def\ylabelunit{\m\per\s}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.5*x};}
\caption*{\texttt{\{major,gray\}}}
\end{subfigure}
\end{plotexample}
\numodelplotsetup{grid=mm-dots}%

\subsection{PGFPlots styles}

The package defines three PGFPlots styles applied by |\drawplot|:
|numodel/grid|, |numodel/ticks|, |numodel/axis|.  These can be
overridden wholesale through |\pgfplotsset{numodel/axis/.style={...}}|
from the calling preamble, giving projects a single choke point for
house-style customisation.  One override per style, on the same
plot:

\begin{plotexample}
\captionsetup{type=figure}%
\begin{subfigure}{0.33\textwidth}\centering
\pgfplotsset{numodel/grid/.style={grid=major,
  grid style={gray!50, very thin}}}%
\numodelplotsetup{xcmmax=3, ycmmax=3}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{t}\def\xlabelunit{\s}%
\def\ylabelqty{v}\def\ylabelunit{\m\per\s}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.5*x};}
\caption*{\texttt{numodel/grid}}
\end{subfigure}\hspace{-1cm}%
\begin{subfigure}{0.33\textwidth}\centering
\pgfplotsset{numodel/ticks/.style={tick style={red, thick},
  minor tick num=4}}%
\numodelplotsetup{xcmmax=3, ycmmax=3}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{t}\def\xlabelunit{\s}%
\def\ylabelqty{v}\def\ylabelunit{\m\per\s}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.5*x};}
\caption*{\texttt{numodel/ticks}}
\end{subfigure}\hspace{-1cm}%
\begin{subfigure}{0.33\textwidth}\centering
\pgfplotsset{numodel/axis/.append style={axis line style={->}}}%
\numodelplotsetup{xcmmax=3, ycmmax=3}%
\def\xmin{0}\def\xmax{10}\def\ymin{0}\def\ymax{5}%
\def\xlabelqty{t}\def\xlabelunit{\s}%
\def\ylabelqty{v}\def\ylabelunit{\m\per\s}%
\drawplot{\addplot[domain=\xmin:\xmax,thick]{0.5*x};}
\caption*{\texttt{numodel/axis}}
\end{subfigure}
\end{plotexample}

\subsection{Tick label backgrounds}

To keep scale numbers optically separated from the grid and from
plot lines passing behind them, the |numodel/axis| style draws each
tick label on a semi-transparent white rectangle (|fill=white|,
|fill opacity=0.8|, |inner sep=1pt|).  The same style also keeps
tick labels visible where a crossing axis would otherwise hide them
(|hide obscured x ticks=false| and the $y$-counterpart); the white
rectangle then provides the visual separation from the axis line.

If the surrounding document has a coloured background --- a sidebar
box, a slide template, the |plotexample| environment used in this
manual --- the white rectangles will stand out against it.  Match
them to the surrounding colour with
\begin{quote}
\begin{verbatim}
\pgfplotsset{numodel/axis/.append style={
  xticklabel style={fill=<your-color>},
  yticklabel style={fill=<your-color>}
}}
\end{verbatim}
\end{quote}
or remove the rectangles entirely with |fill=none|.  In pgfplots,
|xticklabel style={...}| appends to the existing tick-label style
rather than replacing it, so the other settings (number format,
comma-as-decimal-separator, opacity) are preserved.

\section{Public API}

\DescribeMacro{\drawplot}
Renders a |tikzpicture| containing an |axis| whose body is the
single mandatory argument.  Typically a block of |\addplot| and
|\addlegendentry| lines.  Calls |\calcplotdims| internally, so the
user does not need to invoke it separately.

\DescribeMacro{\calcplotdims}
Reads |\xmin|, |\xmax|, |\ymin|, |\ymax|, and (if set)
|\xlabelqty|/|\xlabelunit|/|\ylabelqty|/|\ylabelunit|.  Writes
|\xcm|, |\ycm|, |\xtickdistance|, |\ytickdistance|, |\xlabel|,
|\ylabel|, and may rewrite |\xmin|\ldots|\ymax| to align with the
tick lattice (floor/ceil to the nearest tick).  It also appends
axis-positioning styles to |numodel/axis| based on which quadrants
the data occupies.  |\drawplot| invokes it automatically; expose for
advanced cases where dimensions are needed before rendering (overlay
TikZ, custom |axis| environment).

\DescribeMacro{\xlabelqty}\DescribeMacro{\xlabelunit}
\DescribeMacro{\ylabelqty}\DescribeMacro{\ylabelunit}
Input hooks for automatic label construction.  |\xlabelqty| is the
mathematical quantity symbol (e.g.\ |v|, |F|, |E|); the corresponding
|\xlabelunit| is a bare \textsf{siunitx} unit macro sequence
(e.g.\ |\m\per\s|, |\J|, |\N\m|) \emph{without} a surrounding |\si{}|
or |\qty{}| wrapper.

\DescribeMacro{\xcmmax}\DescribeMacro{\ycmmax}
Maximum axis dimensions in centimetres.  Can be set directly through
|\def| for backwards compatibility, or via |\numodelplotsetup|.

\DescribeMacro{\qtyPlain}
Like \textsf{siunitx}'s |\qty| but prints no numeric mantissa when
the final output after prefix extraction has mantissa~1 and
exponent~0.  Used internally to inject scale factors into axis
labels; exposed because the same need recurs in other scaled-axis
contexts.

\DescribeMacro{\pzuIfUnitNonEngTF}
Boolean conditional testing whether a unit macro sequence contains a
non-engineering SI prefix (|\centi|, |\deci|, |\deca|, |\hecto|,
plus the \textsf{siunitx} short forms |\cm|, |\dm|, |\hPa|, \ldots).
Used internally to suppress scaling on units where the user has
already encoded the order of magnitude; exposed for completeness.

\section{Requirements}

\textsf{numodel-plot} requires \textsf{expl3}, \textsf{xparse},
\textsf{l3keys2e}, \textsf{siunitx} (mandatory, for quantities in
labels), and \textsf{pgfplots} (with the |fillbetween| library).
LuaLaTeX is not required at the plot layer (it is required by the
sibling \textsf{numodel} package).

\end{document}
