\section{The \pkg{pgfplots-autonode} autonomous library}

\pkg{pgfplots-autonode} is a complete PGFPlots library included in
\pkg{luacoolprop}.  It is useful beyond thermodynamics: any PGFPlots curve
can register a label, expose candidate positions, and let the library choose a
joint placement after the axis has been surveyed.  LuaCoolProp uses precisely
this public mechanism; it contains no competing internal label-placement
algorithm.

\subsection{Why placement is deferred}

PGFPlots first surveys plots and only then knows the final axis transformation.
Autonode samples each labelled plot in physical canvas coordinates, measures
the actual TeX label box, records the visible axis rectangle, and solves the
multi-label assignment at the end of the axis.  Consequently, collision tests
remain meaningful with logarithmic axes, unequal scales, resized figures, and
sloped labels.

\begin{LCPNote}[Two kinds of option]
Axis keys such as \texttt{auto node algorithm} configure the joint solver.
Keys under \texttt{/pgfplots/autonode}, passed to
\macro{\pgfplotsautonode}, configure one label.  This separation is essential:
one axis has one solver policy, while each label has its own candidate range,
box, priority, and preferred position.
\end{LCPNote}

\subsection{Loading the library}

\begin{LCPCommandRef}{usepgfplotslibrary}{\marg{autonode}}
Loads the generic PGFPlots library after the format's PGFPlots frontend.  The
command works in LaTeX, plain TeX, and ConTeXt.  Loading \pkg{luacoolprop}
already loads it, so an explicit call is needed only for standalone use.
\begin{LCPExample}{Standalone LaTeX loading}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\usepgfplotslibrary{autonode}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPExample}{Standalone plain LuaTeX loading}
\input pgfplots.tex
\pgfplotsset{compat=1.18}
\usepgfplotslibrary{autonode}
\end{LCPExample}

\begin{LCPExample}{Standalone ConTeXt loading}
\usemodule[t][pgfplots]
\usepgfplotslibrary{autonode}
\end{LCPExample}

\subsection{Registering a curve label}

\begin{LCPCommandRef}{pgfplotsautonode}{\oarg{label options}\marg{text}}
Registers \meta{text} as a trailing path command for the immediately preceding
\macro{\addplot}.  The bracket argument is syntactically required; use empty
brackets when no per-label option is needed.  End the complete plot statement
with one semicolon, after this command.

\begin{LCPShowcaseWide}{Two intersecting curves, solved together}
\begin{tikzpicture}
\begin{axis}[width=10cm,height=5.8cm,grid=both,
  auto node placement,
  auto node algorithm=repair,
  auto node failure mode=allow-minimal-overlap]
  \addplot[blue,thick,domain=0:4,samples=40] {x}
    \pgfplotsautonode[preferred pos=.65,sloped=true]{$y=x$};
  \addplot[red,thick,domain=0:4,samples=40] {4-x}
    \pgfplotsautonode[preferred pos=.35,sloped=true]{$y=4-x$};
\end{axis}
\end{tikzpicture}
\end{LCPShowcaseWide}
\end{LCPCommandRef}

\begin{LCPWarning}[Trailing-command syntax]
Attach \macro{\pgfplotsautonode} before the plot's final semicolon.  A
semicolon placed earlier closes the path too soon.  The bracket pair is also
mandatory, even when the label has no options.
\end{LCPWarning}

\section{Per-label autonode keys}

The keys in this section belong to \texttt{/pgfplots/autonode} and appear in
the optional argument of \macro{\pgfplotsautonode}.

\subsection{Candidate positions}

\LCPKeyDoc{pgfplots/autonode}{preferred pos}{fraction}{0.5}
  {Sets the desired position along the plot.  It is a preference, not a fixed
   position: the solver may move the label to prevent a collision.}{0.7}
\LCPKeyDoc{pgfplots/autonode}{min pos}{fraction}{0}
  {Excludes candidates before this fraction of the complete plot path.}{0.15}
\LCPKeyDoc{pgfplots/autonode}{max pos}{fraction}{1}
  {Excludes candidates after this fraction of the complete plot path.}{0.85}
\LCPKeyDoc{pgfplots/autonode}{samples}{positive integer}{axis default, initially 51}
  {Sets the number of candidate positions sampled for this label.  More samples
   improve freedom but increase solving work.}{31}
\LCPKeyAlias{pgfplots/autonode}{candidates}{samples}

\begin{LCPKeyRef}{pgfplots/autonode}{candidate strategy}{choice}{around-preferred}
Controls the order and distribution of candidate fractions on the portions of
the plotted path inside the visible axis rectangle.  The fractions supplied by
\texttt{preferred pos}, \texttt{min pos}, and \texttt{max pos} still refer to the
complete PGFPlots path: the library intersects that range with the visible
path, preserves disconnected pieces, and distributes the requested samples
over their combined visible length.  A curve wholly outside the rectangle
produces no label.
\begin{description}
\LCPChoice{pgfplots/autonode}{candidate strategy}{uniform}{Samples the permitted interval uniformly.}
\LCPChoice{pgfplots/autonode}{candidate strategy}{around-preferred}{Starts near the preferred position and expands outwards.}
\LCPChoice{pgfplots/autonode}{candidate strategy}{adaptive}{Uses a deterministic dense neighbourhood around the preferred position plus coarse coverage of the complete interval.}
\end{description}
The spaced spelling \texttt{around preferred} is accepted as an equivalent
choice.\LCPIndexValue{candidate strategy}{around preferred}
\LCPKeyUse{pgfplots/autonode}{candidate strategy}{adaptive}
\end{LCPKeyRef}

\begin{LCPShowcase}[lefthand ratio=.5]{Restricting the search interval}
\begin{tikzpicture}
\begin{axis}[width=5cm,height=4cm,
  auto node placement,domain=0:6.28]
  \addplot[blue,thick,samples=80] {sin(deg(x))}
    \pgfplotsautonode[
      preferred pos=.55,min pos=.35,max pos=.8,
      samples=41,candidate strategy=adaptive]{$\sin x$};
\end{axis}
\end{tikzpicture}
\end{LCPShowcase}

\subsection{Geometry and node appearance}

\LCPKeyDoc{pgfplots/autonode}{normal shift}{TeX dimension}{0pt}
  {Moves the label perpendicular to the sampled curve tangent.  Positive and
   negative values select opposite sides.}{6pt}
\LCPKeyDoc{pgfplots/autonode}{clearance}{TeX dimension}{1pt}
  {Adds an invisible safety margin used by collision tests.  Increase it for
   visually airy layouts or decorated nodes.}{2pt}
\LCPKeyDoc{pgfplots/autonode}{inner sep}{TeX dimension}{1.5pt}
  {Sets the node's inner padding for both measurement and drawing.  A later
   \texttt{inner sep} in \texttt{node options} overrides it in both places.}{2pt}
\LCPKeyDoc{pgfplots/autonode}{font}{TeX font commands}{empty}
  {Sets the font both while measuring and while drawing the label.}
  {{\scriptsize\bfseries}}
\LCPKeyDoc{pgfplots/autonode}{node options}{TikZ node options}{white fill, no draw}
  {Sets the node appearance used in both the scratch measurement and final
   drawing.  Anchors, font, padding, and text width affect the measured box;
   decorations or effects outside the node's PGF bounding box should be paired
   with sufficient \texttt{clearance}.}
  {{fill=yellow!20,draw=orange,rounded corners}}
\LCPKeyDoc{pgfplots/autonode}{sloped}{boolean}{false}
  {Rotates the label along the local curve tangent.}{true}
\LCPKeyDoc{pgfplots/autonode}{allow upside down}{boolean}{false}
  {When false, normalises sloped text to remain readable; when true, preserves
   the tangent orientation even if inverted.}{true}
\begin{LCPKeyRef}{pgfplots/autonode}{above}{style}{not applied}
Convenience style equivalent to \texttt{normal shift=6pt}.
\LCPCodeUse{\pgfplotsautonode[above]{label}}
\end{LCPKeyRef}
\begin{LCPKeyRef}{pgfplots/autonode}{below}{style}{not applied}
Convenience style equivalent to \texttt{normal shift=-6pt}.
\LCPCodeUse{\pgfplotsautonode[below]{label}}
\end{LCPKeyRef}

\begin{LCPShowcase}[lefthand ratio=.5]{A styled, shifted label}
\begin{tikzpicture}
\begin{axis}[width=5cm,height=4cm,
  auto node placement,domain=0:3]
  \addplot[teal!70!black,thick,samples=50] {exp(x/3)}
    \pgfplotsautonode[preferred pos=.55,above,
      sloped=true,
      inner sep=2pt,clearance=2pt,
      node options={fill=teal!8,draw=teal,
        rounded corners,inner sep=2pt}]{$e^{x/3}$};
\end{axis}
\end{tikzpicture}
\end{LCPShowcase}

\subsection{Cost and priority}

\LCPKeyDoc{pgfplots/autonode}{preferred weight}{nonnegative number}{8}
  {Weights displacement from \texttt{preferred pos}.  Raise it when remaining
   near the semantic location matters more than other soft costs.}{15}
\LCPKeyDoc{pgfplots/autonode}{overlap weight}{nonnegative number}{1000}
  {Weights overlap area during repair and local search.  A conflicting pair
   uses the arithmetic mean of its two labels' weights, so the objective is
   symmetric.  The large default makes avoiding collisions far more important
   than matching the preferred position.}{2000}
\LCPKeyDoc{pgfplots/autonode}{priority}{number}{0}
  {Orders labels when not all can be placed.  Larger values are protected
   first; low-priority labels are hidden first under the corresponding failure
   policy.}{10}

\begin{LCPShowcaseWide}{Prioritising the principal curve}
\begin{tikzpicture}
\begin{axis}[width=10cm,height=5.8cm,grid=both,
  auto node placement,auto node algorithm=repair,
  auto node failure mode=hide-low-priority]
  \addplot[blue,very thick,domain=0:4] {2+.2*x}
    \pgfplotsautonode[priority=10,preferred pos=.5] {principal};
  \addplot[gray,domain=0:4] {2.1-.2*x}
    \pgfplotsautonode[priority=0,preferred pos=.5] {secondary};
  \addplot[gray,domain=0:4] {1.9+.05*x}
    \pgfplotsautonode[priority=0,preferred pos=.5] {tertiary};
\end{axis}
\end{tikzpicture}
\end{LCPShowcaseWide}

\section{Axis-level autonode keys}

These keys belong to \texttt{/pgfplots}.  They are placed in an axis option
list or set with \macro{\pgfplotsset}.  Except for diagnostic drawing, changes
affect only solving; they do not change curve geometry.

\subsection{Lifecycle and solver selection}

\begin{LCPKeyRef}{pgfplots}{auto node placement}{style}{not applied by standalone PGFPlots}
Resets the label registry when the key is parsed and installs the end-axis
solve/render hook. This makes consecutive axes independent. It is mandatory
for standalone autonode use and for LuaCoolProp's low-level family commands
inside a manually created axis.  LuaCoolProp's high-level diagram commands,
such as \macro{\LCPPHDiagram}, install it on the axis they create.  Merely
loading LuaCoolProp deliberately does not modify unrelated PGFPlots axes.
Registering a label without this lifecycle key emits a warning instead of
silently dropping the label.
\LCPCodeUse{\begin{axis}[auto node placement]}
\end{LCPKeyRef}

\begin{LCPKeyRef}{pgfplots}{auto node algorithm}{choice}{repair}
Selects the assignment algorithm.
\begin{description}
\LCPChoice{pgfplots}{auto node algorithm}{greedy}{Fast, deterministic first-fit placement; useful for drafts and large label sets.}
\LCPChoice{pgfplots}{auto node algorithm}{repair}{Greedy placement followed by bounded conflict repair; the balanced default.}
\LCPChoice{pgfplots}{auto node algorithm}{local-search}{Iteratively improves a complete assignment up to the iteration budget.}
\LCPChoice{pgfplots}{auto node algorithm}{exact-small}{Searches assignments for small label sets, subject to the exact limits below.}
\end{description}
\LCPKeyUse{pgfplots}{auto node algorithm}{local-search}
\end{LCPKeyRef}

\LCPKeyDoc{pgfplots}{auto node max iterations}{positive integer}{40}
  {Bounds repair/local-search work.  Increasing it can improve dense axes at a
   predictable runtime cost.}{80}
\LCPKeyDoc{pgfplots}{auto node exact max labels}{positive integer}{10}
  {Limits how many labels may enter \texttt{exact-small}; larger problems fall
   back to a bounded strategy.}{8}
\LCPKeyDoc{pgfplots}{auto node exact max states}{positive integer}{50000}
  {Caps the assignment states examined by \texttt{exact-small}.}{100000}

\subsection{Collision model and failure policy}

\begin{LCPKeyRef}{pgfplots}{auto node bbox mode}{choice}{axis-aligned}
Selects the collision box model.
\begin{description}
\LCPChoice{pgfplots}{auto node bbox mode}{axis-aligned}{Uses axis-aligned rectangles; fast and conservative for rotated text.}
\LCPChoice{pgfplots}{auto node bbox mode}{oriented}{Uses oriented boxes for sloped labels; more precise and more expensive.}
\end{description}
\LCPKeyUse{pgfplots}{auto node bbox mode}{oriented}
\end{LCPKeyRef}

\begin{LCPKeyRef}{pgfplots}{auto node failure mode}{choice}{warn}
Defines the result when the chosen assignment still contains an unacceptable
label-to-label conflict.  With the default
\texttt{auto node allow outside=false}, the plot border remains a hard
constraint in every mode: a label with no measured candidate box wholly inside
the plot rectangle is hidden with a warning, or causes a compilation error in
\texttt{error} mode.  No overlap policy draws a rejected outside candidate.
\begin{description}
\LCPChoice{pgfplots}{auto node failure mode}{warn}{Keeps unresolved label-to-label overlaps and emits a concise warning; labels with no inside candidate are hidden.}
\LCPChoice{pgfplots}{auto node failure mode}{error}{Stops compilation; appropriate for strict publication builds.}
\LCPChoice{pgfplots}{auto node failure mode}{hide-low-priority}{Hides the least important labels until remaining conflicts are removed.}
\LCPChoice{pgfplots}{auto node failure mode}{allow-minimal-overlap}{Keeps the complete assignment improved by the selected bounded heuristic without treating residual overlap as fatal; it does not claim a global optimum.}
\end{description}
\LCPKeyUse{pgfplots}{auto node failure mode}{hide-low-priority}
\end{LCPKeyRef}

\LCPKeyDoc{pgfplots}{auto node border margin}{TeX dimension}{2pt}
  {Reserves space between label boxes and the visible plot rectangle.}{4pt}
\LCPKeyDoc{pgfplots}{auto node overlap tolerance}{TeX dimension}{0.2pt}
  {Ignores microscopic intersection caused by rounding or touching edges.}{0.5pt}
\LCPKeyDoc{pgfplots}{auto node allow outside}{boolean}{false}
  {Allows label boxes to extend beyond the plot rectangle.  Tick labels and
   neighbouring figures are not obstacle-aware, so enable this deliberately.}
  {true}

\subsection{Axis defaults for candidate generation}

\LCPKeyDoc{pgfplots}{auto node candidates}{positive integer}{51}
  {Sets the default sample count for labels which do not override
   \texttt{samples}.}{31}
\begin{LCPKeyRef}{pgfplots}{auto node candidate strategy}{choice}{around-preferred}
Sets the default per-label strategy.
\begin{description}
\LCPChoice{pgfplots}{auto node candidate strategy}{uniform}{Uniform interval coverage.}
\LCPChoice{pgfplots}{auto node candidate strategy}{around-preferred}{Preferred-first expanding order.}
\LCPChoice{pgfplots}{auto node candidate strategy}{adaptive}{Deterministically combines dense preferred-position sampling with coarse full-interval coverage.}
\end{description}
The spelling \texttt{around preferred} is accepted too.
\LCPIndexValue{auto node candidate strategy}{around preferred}
\LCPKeyUse{pgfplots}{auto node candidate strategy}{uniform}
\end{LCPKeyRef}

Numeric controls are validated before solving.  Positions must lie in
\([0,1]\), counts and iteration limits must be positive integers, and sizes,
clearances, margins, tolerances, and weights must be nonnegative.  Invalid Lua
backend input emits a warning and uses the documented default; invalid PGF key
choices are rejected by PGF's choice handler.

\subsection{Diagnostics}

\begin{LCPKeyRef}{pgfplots}{auto node debug}{choice}{false}
Controls textual diagnostics.  Bare \texttt{auto node debug} means
\texttt{summary}.
\begin{description}
\LCPChoice{pgfplots}{auto node debug}{false}{No diagnostic output.}
\LCPChoice{pgfplots}{auto node debug}{off}{Synonym for \texttt{false}.}
\LCPChoice{pgfplots}{auto node debug}{summary}{Reports configuration and solve outcome.}
\LCPChoice{pgfplots}{auto node debug}{verbose}{Also reports labels and assignments.}
\LCPChoice{pgfplots}{auto node debug}{trace}{Reports candidate-level details; output can be large.}
\end{description}
\LCPKeyUse{pgfplots}{auto node debug}{verbose}
\end{LCPKeyRef}

\LCPKeyDoc{pgfplots}{auto node show bounding boxes}{boolean}{false}
  {Draws the final measured collision rectangles.}{true}
\LCPKeyDoc{pgfplots}{auto node show candidates}{boolean}{false}
  {Draws valid sampled candidate locations.}{true}
\LCPKeyDoc{pgfplots}{auto node show rejected candidates}{boolean}{false}
  {Also marks rejected candidates, which is useful when border constraints or
   overlaps leave few choices.}{true}

\begin{LCPShowcaseWide}{Visualising candidates and final boxes}
\begin{tikzpicture}
\begin{axis}[width=10cm,height=5.8cm,grid=both,
  auto node placement,auto node candidates=13,
  auto node show candidates=true,
  auto node show rejected candidates=true,
  auto node show bounding boxes=true]
  \addplot[blue,thick,domain=0:4,samples=40] {x^2/4}
    \pgfplotsautonode[preferred pos=.5,sloped=true]{$x^2/4$};
  \addplot[red,thick,domain=0:4,samples=40] {4-x}
    \pgfplotsautonode[preferred pos=.5,sloped=true]{$4-x$};
\end{axis}
\end{tikzpicture}
\end{LCPShowcaseWide}

\section{Choosing a policy}

For a first diagram, use the defaults: \texttt{repair}, axis-aligned boxes,
51 candidates, and warnings.  For final artwork with many sloped labels, try
\texttt{auto node bbox mode=oriented} and increase candidates before increasing
iterations.  Use priorities plus \texttt{hide-low-priority} where a dense
network must remain readable.  Reserve \texttt{exact-small} for genuinely
small label sets and a controlled build budget.

The bounded repair and local-search algorithms are deterministic heuristics.
They improve the weighted assignment but do not certify a global minimum.
Likewise, the candidate strategy named \texttt{adaptive} adapts its sampling
density to the preferred path neighbourhood; it does not perform a second
feedback pass after observing collisions.

Node geometry is measured by typesetting each label once in a scratch TikZ
picture before solving.  The solver uses the resulting bounds relative to the
node anchor, including asymmetric anchors and TikZ padding; sloped bounds are
then rotated with the path tangent.  Avoid label contents with non-idempotent
side effects, because the contents are also typeset when the final node is
drawn.

\subsection{Sampling and the plot boundary}

Autonode samples candidate positions only on the visible pieces of an already
surveyed PGFPlots path.  This avoids label candidates on clipped portions; it
does not discard thermodynamic curve points or change the path handed to
PGFPlots.  That distinction protects curve crossings at the axis border,
named-path intersections, disconnected valid domains, and the meaning of a
fixed \texttt{preferred pos}.  In particular, PGFPlots axis options can set
limits independently of the thermodynamic pressure range, and non-pressure
coordinates need not vary monotonically along a curve.  Truncating CoolProp
sampling from a few out-of-range points would therefore be unsafe.

For high-level TS, HS, and PT diagrams, the curves used to derive automatic
axis limits are reused unchanged for the immediately following plot command.
This removes a complete duplicate thermodynamic sampling pass without changing
the displayed curves or their autonode geometry.  Explicit pressure limits
still constrain the pressure-parameterized generators directly.

The visual diagnostic keys are intended for authoring only.  A reproducible
release figure should normally disable them and choose either
\texttt{auto node failure mode=error} for a hard quality gate or a documented
fallback such as \texttt{hide-low-priority}.
