% \iffalse meta-comment % % numodel-plot.dtx % Copyright (C) 2026 Paul Zuurbier % % This work may be distributed and/or modified under the conditions % of the LaTeX Project Public License, either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in https://www.latex-project.org/lppl.txt % % This work has the LPPL maintenance status 'maintained'. % The Current Maintainer of this work is Paul Zuurbier. % % This work consists of the files numodel-plot.dtx and numodel-plot.ins, % and the derived file numodel-plot.sty. % %<*driver> \ProvidesFile{numodel-plot.dtx}[2026/05/17 v0.3.0 numodel-plot documentation] \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 \RecordChanges \begin{document} \DocInput{numodel-plot.dtx} \end{document} % % % \fi % % \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.} % % \GetFileInfo{numodel-plot.dtx} % % \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. % % \section{Usage} % % Minimum working example: % \begin{quote} % \begin{verbatim} % \usepackage{numodel-plot} % ... % \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]{0.5*x};} % \end{verbatim} % \end{quote} % renders as % \begin{center} % \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]{0.5*x};} % \end{center} % 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{quote} % \begin{verbatim} % \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{verbatim} % \end{quote} % \begin{center} % \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{center} % % 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{center} % \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{center} % \numodelplotsetup{axis-label-format=ieee}% % % Three grid variants, sized the same way: % \begin{center} % \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{center} % \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{center} % \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{center} % % \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). % % \StopEventually{} % % \section{Implementation} % % All internal helper macros use the \texttt{\textbackslash nmp@\ldots} % prefix (standard LaTeX internal convention). Because the package % may be loaded through |\input| as well as |\usepackage|, an % explicit |\makeatletter| wraps the body so that |@| is a letter % regardless of caller. % % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{numodel-plot}[2026/05/17 v0.3.0 Auto-sizing PGFPlots engine] \makeatletter \RequirePackage{expl3} \RequirePackage{xparse} \RequirePackage{l3keys2e} \RequirePackage{siunitx} \RequirePackage{pgfplots} \usepgfplotslibrary{fillbetween} \pgfplotsset{ compat=1.18, numodel/grid/.style={ grid=both, grid style={ line width=0.5pt, draw=black, line cap=round, dash pattern=on 0pt off 1mm }, major grid style={ line width=0.5pt, draw=black, line cap=round, dash pattern=on 0pt off 1mm} }, numodel/ticks/.style={ tick style={black} }, numodel/axis/.style={ xticklabel style={/pgf/number format/.cd, fixed, precision=6, fixed zerofill=false, use comma, 1000 sep={\,}, /tikz/.cd, text depth=0.3ex}, yticklabel style={/pgf/number format/.cd, fixed, precision=6, fixed zerofill=false, use comma, 1000 sep={\,}, /tikz/.cd, text depth=0.3ex}, axis lines=left, xlabel near ticks, ylabel near ticks, ylabel style={rotate=-90}, axis line style={-} } } \ExplSyntaxOn \tl_new:N \g__numodelplot_axislabel_tl \tl_gset:Nn \g__numodelplot_axislabel_tl {ieee} \providecommand{\xcmmax}{12} \providecommand{\ycmmax}{10} \keys_define:nn { numodel-plot } { axis-label-format .choice:, axis-label-format / iso .code:n = \tl_gset:Nn \g__numodelplot_axislabel_tl {iso}, axis-label-format / ieee .code:n = \tl_gset:Nn \g__numodelplot_axislabel_tl {ieee}, axis-label-format / brackets .code:n = \tl_gset:Nn \g__numodelplot_axislabel_tl {brackets}, axis-label-format / qty-only .code:n = \tl_gset:Nn \g__numodelplot_axislabel_tl {qty-only}, axis-label-format / unit-only .code:n = \tl_gset:Nn \g__numodelplot_axislabel_tl {unit-only}, grid .choice:, grid / mm-dots .code:n = \pgfplotsset{ numodel/grid/.style={ grid=both, grid~style={line~width=0.5pt, draw=black, line~cap=round, dash~pattern=on~0pt~off~1mm}, major~grid~style={line~width=0.5pt, draw=black, line~cap=round, dash~pattern=on~0pt~off~1mm} } }, grid / none .code:n = \pgfplotsset{ numodel/grid/.style={grid=none} }, grid / unknown .code:n = \pgfplotsset{ numodel/grid/.style={#1} }, xcmmax .code:n = \def\xcmmax{#1}, ycmmax .code:n = \def\ycmmax{#1}, } \NewDocumentCommand{\numodelplotsetup}{m} { \keys_set:nn { numodel-plot } {#1} } \ExplSyntaxOff \ExplSyntaxOn \bool_new:N \g__pzu_suppress_qp_bool \cs_new_eq:NN \__pzu_orig_int_output:nnn \__siunitx_number_output_integer:nnn \cs_new_eq:NN \__pzu_orig_qty_print_unit:n \__siunitx_quantity_print_unit:n \NewDocumentCommand{\qtyPlain}{O{} m m}{% \group_begin: \bool_gset_false:N \g__pzu_suppress_qp_bool \cs_set:Npn \__siunitx_number_output_integer:nnn ##1##2##3 { \bool_lazy_all:nTF { { \str_if_eq_p:nn { ##1 . ##2 } { 1. } } { \str_if_eq_p:nn {##3} { 0 } } { ! \l__siunitx_number_zero_exponent_bool } { ! \l__siunitx_number_unity_mantissa_bool } } { \bool_gset_true:N \g__pzu_suppress_qp_bool } { \__pzu_orig_int_output:nnn {##1} {##2} {##3} } } \cs_set_protected:Npn \__siunitx_quantity_print_unit:n ##1 { \bool_if:NTF \l__siunitx_quantity_break_bool { \penalty \binoppenalty } { \nobreak } \bool_if:NF \g__pzu_suppress_qp_bool { \tl_use:N \l__siunitx_quantity_product_tl } \siunitx_print_unit:n {##1} } \qty[#1]{#2}{#3}% \group_end: } \ExplSyntaxOff \ExplSyntaxOn \bool_new:N \l__pzu_noneng_bool \tl_const:Nn \c__pzu_noneng_tokens_tl { \centi \deci \deca \hecto \cm \cg \cL \dm \dg \dL \dam \dag \daL \hm \hg \hL \hPa } \prg_new_protected_conditional:Npnn \__pzu_unit_has_noneng:n #1 { TF } { \bool_set_false:N \l__pzu_noneng_bool \tl_map_inline:Nn \c__pzu_noneng_tokens_tl { \tl_if_in:nnT {#1} {##1} { \bool_set_true:N \l__pzu_noneng_bool \tl_map_break: } } \bool_if:NTF \l__pzu_noneng_bool { \prg_return_true: } { \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__pzu_unit_has_noneng:n { o } { TF } \NewDocumentCommand{\pzuIfUnitNonEngTF}{m m m}{% \__pzu_unit_has_noneng:oTF {#1} {#2} {#3}% } \ExplSyntaxOff \ExplSyntaxOn \cs_new_protected:Npn \__numodelplot_xlabel_emit_unscaled: { \str_case:Vn \g__numodelplot_axislabel_tl { {iso} { \def \xlabel { $\nmp@savedxlabelqty \, /\, ( \si{\nmp@savedxlabelunit} )$ } } {ieee} { \def \xlabel { $\nmp@savedxlabelqty \,( \si{\nmp@savedxlabelunit} )$ } } {brackets} { \def \xlabel { $\nmp@savedxlabelqty \,[ \si{\nmp@savedxlabelunit} ]$ } } {qty-only} { \def \xlabel { $\nmp@savedxlabelqty$ } } {unit-only} { \def \xlabel { $\si{\nmp@savedxlabelunit}$ } } } } \cs_new_protected:Npn \__numodelplot_xlabel_emit_scaled: { \str_case:Vn \g__numodelplot_axislabel_tl { {iso} { \edef\xlabel{\noexpand$\noexpand\nmp@savedxlabelqty \noexpand\,/\noexpand\,(\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@xlabelexpuse}{\noexpand\nmp@savedxlabelunit})\noexpand$}% } {ieee} { \edef\xlabel{\noexpand$\noexpand\nmp@savedxlabelqty \noexpand\,(\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@xlabelexpuse}{\noexpand\nmp@savedxlabelunit})\noexpand$}% } {brackets} { \edef\xlabel{\noexpand$\noexpand\nmp@savedxlabelqty \noexpand\,[\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@xlabelexpuse}{\noexpand\nmp@savedxlabelunit}]\noexpand$}% } {qty-only} { \def \xlabel { $\nmp@savedxlabelqty$ } } {unit-only} { \edef\xlabel{\noexpand$\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@xlabelexpuse}{\noexpand\nmp@savedxlabelunit}\noexpand$}% } } } \cs_new_protected:Npn \__numodelplot_ylabel_emit_unscaled: { \str_case:Vn \g__numodelplot_axislabel_tl { {iso} { \def \ylabel { $\nmp@savedylabelqty \, /\, ( \si{\nmp@savedylabelunit} )$ } } {ieee} { \def \ylabel { $\nmp@savedylabelqty \,( \si{\nmp@savedylabelunit} )$ } } {brackets} { \def \ylabel { $\nmp@savedylabelqty \,[ \si{\nmp@savedylabelunit} ]$ } } {qty-only} { \def \ylabel { $\nmp@savedylabelqty$ } } {unit-only} { \def \ylabel { $\si{\nmp@savedylabelunit}$ } } } } \cs_new_protected:Npn \__numodelplot_ylabel_emit_scaled: { \str_case:Vn \g__numodelplot_axislabel_tl { {iso} { \edef\ylabel{\noexpand$\noexpand\nmp@savedylabelqty \noexpand\,/\noexpand\,(\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@ylabelexpuse}{\noexpand\nmp@savedylabelunit})\noexpand$}% } {ieee} { \edef\ylabel{\noexpand$\noexpand\nmp@savedylabelqty \noexpand\,(\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@ylabelexpuse}{\noexpand\nmp@savedylabelunit})\noexpand$}% } {brackets} { \edef\ylabel{\noexpand$\noexpand\nmp@savedylabelqty \noexpand\,[\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@ylabelexpuse}{\noexpand\nmp@savedylabelunit}]\noexpand$}% } {qty-only} { \def \ylabel { $\nmp@savedylabelqty$ } } {unit-only} { \edef\ylabel{\noexpand$\noexpand\qtyPlain [evaluate-expression=false, round-mode=none, prefix-mode=extract-exponent, extract-mass-in-kilograms=true, print-zero-exponent=false, print-unity-mantissa=false]% {1e\nmp@ylabelexpuse}{\noexpand\nmp@savedylabelunit}\noexpand$}% } } } \ExplSyntaxOff \newcommand{\pznmpAppendXScaleTicks}[1]{% \pgfplotsset{numodel/axis/.append style={scaled x ticks=base 10:#1}}% } \newcommand{\pznmpAppendYScaleTicks}[1]{% \pgfplotsset{numodel/axis/.append style={scaled y ticks=base 10:#1}}% } \newcommand{\pznmpSuppressXScaleLabel}{% \pgfplotsset{numodel/axis/.append style={every x tick scale label/.style={opacity=0, inner sep=0pt, at={(0,0)}}}}% } \newcommand{\pznmpSuppressYScaleLabel}{% \pgfplotsset{numodel/axis/.append style={every y tick scale label/.style={opacity=0, inner sep=0pt, at={(0,0)}}}}% } \ExplSyntaxOn \cs_new_protected:Npn \__numodelplot_suppress_xscale_label: { \str_if_eq:VnF \g__numodelplot_axislabel_tl {qty-only} { \pznmpSuppressXScaleLabel } } \cs_new_protected:Npn \__numodelplot_suppress_yscale_label: { \str_if_eq:VnF \g__numodelplot_axislabel_tl {qty-only} { \pznmpSuppressYScaleLabel } } \ExplSyntaxOff \ExplSyntaxOn \NewDocumentCommand{\xlabelbuild}{}{ \let\nmp@savedxlabelqty\xlabelqty \let\nmp@savedxlabelunit\xlabelunit \pzuIfUnitNonEngTF{\xlabelunit}{ \__numodelplot_xlabel_emit_unscaled: \def\nmp@xlabelexp{0} }{ \edef\nmp@xmag{\fpeval{max(abs(\xmin),abs(\xmax))}} \edef\nmp@xlabelexp{\fpeval{ \nmp@xmag > 0 ? 3*floor(ln(\nmp@xmag)/ln(10)/3) : 0 }} \ifnum\nmp@xlabelexp=0\relax \__numodelplot_xlabel_emit_unscaled: \else \edef\nmp@xlabelexpuse{\nmp@xlabelexp} \__numodelplot_xlabel_emit_scaled: \edef\nmp@xlabelexpneg{\fpeval{-\nmp@xlabelexp}} \pznmpAppendXScaleTicks{\nmp@xlabelexpneg} \__numodelplot_suppress_xscale_label: \fi } \global\let\xlabelqty\undefined \global\let\xlabelunit\undefined } \NewDocumentCommand{\ylabelbuild}{}{ \let\nmp@savedylabelqty\ylabelqty \let\nmp@savedylabelunit\ylabelunit \pzuIfUnitNonEngTF{\ylabelunit}{ \__numodelplot_ylabel_emit_unscaled: \def\nmp@ylabelexp{0} }{ \edef\nmp@ymag{\fpeval{max(abs(\ymin),abs(\ymax))}} \edef\nmp@ylabelexp{\fpeval{ \nmp@ymag > 0 ? 3*floor(ln(\nmp@ymag)/ln(10)/3) : 0 }} \ifnum\nmp@ylabelexp=0\relax \__numodelplot_ylabel_emit_unscaled: \else \edef\nmp@ylabelexpuse{\nmp@ylabelexp} \__numodelplot_ylabel_emit_scaled: \edef\nmp@ylabelexpneg{\fpeval{-\nmp@ylabelexp}} \pznmpAppendYScaleTicks{\nmp@ylabelexpneg} \__numodelplot_suppress_yscale_label: \fi } \global\let\ylabelqty\undefined \global\let\ylabelunit\undefined } \ExplSyntaxOff \newcommand{\calcplotdims}{% \edef\nmp@xlog{\fpeval{floor(ln(\xmax-\xmin)/ln(10))}}% \edef\nmp@ylog{\fpeval{floor(ln(\ymax-\ymin)/ln(10))}}% \edef\nmp@xS{\fpeval{(\xmax-\xmin) / (10^\nmp@xlog)}}% \edef\nmp@yS{\fpeval{(\ymax-\ymin) / (10^\nmp@ylog)}}% \edef\xcm{\fpeval{% \nmp@xS <= \xcmmax/10 ? 10 * \nmp@xS :% \nmp@xS <= \xcmmax/5 ? 5 * \nmp@xS :% \nmp@xS <= \xcmmax/4 ? 4 * \nmp@xS :% \nmp@xS <= \xcmmax/2 ? 2 * \nmp@xS :% \nmp@xS <= \xcmmax ? \nmp@xS :% \nmp@xS / 2% }}% \edef\ycm{\fpeval{% \nmp@yS <= \ycmmax/10 ? 10 * \nmp@yS :% \nmp@yS <= \ycmmax/5 ? 5 * \nmp@yS :% \nmp@yS <= \ycmmax/4 ? 4 * \nmp@yS :% \nmp@yS <= \ycmmax/2 ? 2 * \nmp@yS :% \nmp@yS <= \ycmmax ? \nmp@yS :% \nmp@yS / 2% }}% \edef\nmp@xtickdiv{\fpeval{\nmp@xS / \xcm}}% \edef\nmp@ytickdiv{\fpeval{\nmp@yS / \ycm}}% \edef\xtickdistance{\fpeval{\nmp@xtickdiv * 10^\nmp@xlog}}% \edef\ytickdistance{\fpeval{\nmp@ytickdiv * 10^\nmp@ylog}}% \edef\xmax{\fpeval{ceil(\xmax / \xtickdistance) * \xtickdistance}}% \edef\ymax{\fpeval{ceil(\ymax / \ytickdistance) * \ytickdistance}}% \edef\xmin{\fpeval{floor(\xmin / \xtickdistance) * \xtickdistance}}% \edef\ymin{\fpeval{floor(\ymin / \ytickdistance) * \ytickdistance}}% \edef\xcm{\fpeval{(\xmax - \xmin) / \xtickdistance}}% \edef\ycm{\fpeval{(\ymax - \ymin) / \ytickdistance}}% \edef\nmp@yStraddles{\fpeval{(\ymin<0 && \ymax>0) ? 1 : 0}}% \edef\nmp@yAllNonPos{\fpeval{\ymax<=0 ? 1 : 0}}% \edef\nmp@xStraddles{\fpeval{(\xmin<0 && \xmax>0) ? 1 : 0}}% \edef\nmp@xAllNonPos{\fpeval{\xmax<=0 ? 1 : 0}}% \ifnum\nmp@yStraddles=1 \pgfplotsset{numodel/axis/.append style={axis x line*=middle}}% \else \ifnum\nmp@yAllNonPos=1 \pgfplotsset{numodel/axis/.append style={axis x line*=top}}% \fi \fi \ifnum\nmp@xStraddles=1 \pgfplotsset{numodel/axis/.append style={axis y line*=middle}}% \else \ifnum\nmp@xAllNonPos=1 \pgfplotsset{numodel/axis/.append style={axis y line*=right}}% \fi \fi \edef\nmp@axisMoved{\fpeval{(\nmp@yStraddles || \nmp@yAllNonPos || \nmp@xStraddles || \nmp@xAllNonPos) ? 1 : 0}}% \ifnum\nmp@axisMoved=1 \pgfplotsset{numodel/axis/.append style={% every x tick scale label/.style={at={(xticklabel cs:1.05)}, anchor=south west},% every y tick scale label/.style={at={(yticklabel cs:1.05)}, anchor=south east}% }}% \fi \edef\nmp@fourQuad{\fpeval{(\nmp@xStraddles && \nmp@yStraddles) ? 1 : 0}}% \ifnum\nmp@fourQuad=1 \pgfplotsset{numodel/axis/.append style={% xlabel style={at={(xticklabel cs:1.05)}, anchor=west},% ylabel style={at={(yticklabel cs:1.05)}, anchor=south, rotate=0}% }}% \fi \edef\nmp@qIandII{\fpeval{(\nmp@xStraddles && \ymin>=0) ? 1 : 0}}% \ifnum\nmp@qIandII=1 \pgfplotsset{numodel/axis/.append style={% ylabel style={at={(yticklabel cs:1.05)}, anchor=south, rotate=0}% }}% \fi \edef\nmp@qIIandIII{\fpeval{(\nmp@yStraddles && \nmp@xAllNonPos) ? 1 : 0}}% \ifnum\nmp@qIIandIII=1 \pgfplotsset{numodel/axis/.append style={% xlabel style={at={(xticklabel cs:-0.05)}, anchor=east}% }}% \fi \edef\nmp@qIIIandIV{\fpeval{(\nmp@xStraddles && \nmp@yAllNonPos) ? 1 : 0}}% \ifnum\nmp@qIIIandIV=1 \pgfplotsset{numodel/axis/.append style={% ylabel style={at={(yticklabel cs:-0.05)}, anchor=north, rotate=0}% }}% \fi \edef\nmp@qIVandI{\fpeval{(\nmp@yStraddles && \xmin>=0) ? 1 : 0}}% \ifnum\nmp@qIVandI=1 \pgfplotsset{numodel/axis/.append style={% xlabel style={at={(xticklabel cs:1.05)}, anchor=west}% }}% \fi \ifdefined\xlabelqty\ifdefined\xlabelunit\xlabelbuild\fi\fi \ifdefined\ylabelqty\ifdefined\ylabelunit\ylabelbuild\fi\fi } \newcommand{\drawplot}[1]{ \calcplotdims \begin{tikzpicture} \begin{axis}[ numodel/grid, numodel/ticks, numodel/axis, xlabel=\xlabel, ylabel=\ylabel, xmin=\xmin, xmax=\xmax, ymin=\ymin, ymax=\ymax, xtick distance=\xtickdistance, ytick distance=\ytickdistance, width=\xcm cm, height=\ycm cm, scale only axis ] #1 \end{axis} \end{tikzpicture} } \makeatother % \end{macrocode} % % \Finale \endinput