1% Annotate LaTeX Equations
  2% 
  3% (c) 2022 by ST John, https://github.com/st--/
  4% Licensed under MIT License
  5% 
  6\NeedsTeXFormat{LaTeX2e}[1994/06/01]
  7\ProvidesPackage{assets/texpackages/annotate-equations}
  8  [2023/05/06 v0.2.2 easily annotate equations using TikZ]
  9
 10%%% lualatex compatibility, from https://tex.stackexchange.com/a/351520/171664
 11\RequirePackage{ifluatex}
 12\ifluatex
 13\RequirePackage{luatex85}
 14\RequirePackage{pdftexcmds}
 15  \makeatletter
 16  \let\pdfstrcmp\pdf@strcmp
 17  \let\pdffilemoddate\pdf@filemoddate
 18  \makeatother
 19\fi
 20%%%
 21
 22\RequirePackage{tikz}
 23\RequirePackage{xcolor}
 24
 25\usetikzlibrary{backgrounds}
 26\usetikzlibrary{arrows,shapes}
 27\usetikzlibrary{tikzmark} % for \tikzmarknode
 28\usetikzlibrary{calc} % for computing the midpoint between two nodes, e.g. at ($(p1.north)!0.5!(p2.north)$) 
 29
 30
 31%%%%% SETTINGS %%%%%
 32
 33\newcommand{\eqnhighlightheight}{}  % colorbox will shrink to content
 34\renewcommand{\eqnhighlightheight}{\mathstrut} % colorbox will always have full height
 35
 36\newcommand{\eqnhighlightshade}{17}  % light
 37%\renewcommand{\eqnhighlightshade}{47}  % dark
 38
 39\newcommand{\eqnannotationstrut}{\strut} % Package default
 40\newcommand{\eqnannotationfont}{\sffamily\footnotesize}
 41
 42
 43\providecommand\EAmarkanchor{north} % default set to "above"
 44\providecommand\EAwesteast{east} % default set to "right"
 45\providecommand\EAlabelanchor{south} % default set to "label above"
 46% for pgfkeys, see https://tex.stackexchange.com/a/34318/171664
 47% for no-value keys, see https://tex.stackexchange.com/a/401848/171664
 48\pgfkeys{
 49    /eqnannotate/.is family, /eqnannotate,
 50    above/.code = {\renewcommand\EAmarkanchor{north}},
 51    below/.code = {\renewcommand\EAmarkanchor{south}},
 52    left/.code = {\renewcommand\EAwesteast{west}},
 53    right/.code = {\renewcommand\EAwesteast{east}},
 54    label above/.code = {\renewcommand\EAlabelanchor{south}},
 55    label below/.code = {\renewcommand\EAlabelanchor{north}},
 56}
 57
 58\tikzset{annotate equations/arrow/.style={}}
 59\tikzset{annotate equations/text/.style={font=\eqnannotationfont}}
 60
 61%%%%% %%%%%%%% %%%%%
 62
 63
 64\newcommand*{\eqnhighlightcolorbox}[2]{%
 65% \colorbox sets the second argument in text mode, so for use within equations we wrap it in $ $ again
 66    \mathchoice% to get right font size in each mode:
 67        {\colorbox{#1}{$\displaystyle #2$}}%
 68        {\colorbox{#1}{$\textstyle #2$}}%
 69        {\colorbox{#1}{$\scriptstyle #2$}}%
 70        {\colorbox{#1}{$\scriptscriptstyle #2$}}%
 71}
 72
 73%%% the fbox with 0pt rule fixes the height of eqnmark vs eqnmarkbox issue
 74\newcommand*{\eqnhighlightfbox}[2]{%
 75% \fbox sets the second argument in text mode, so for use within equations we wrap it in $ $ again
 76    \mathchoice% to get right font size in each mode:
 77        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\displaystyle\color{#1}#2$}\endgroup}%
 78        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\textstyle\color{#1}#2$}\endgroup}%
 79        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\scriptstyle\color{#1}#2$}\endgroup}%
 80        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\scriptscriptstyle\color{#1}#2$}\endgroup}%
 81}
 82
 83% . is the current color
 84
 85\newcommand*{\eqnhighlight}[2]{\begingroup\colorlet{currentcolor}{.}\eqnhighlightcolorbox{#1!\eqnhighlightshade}{\eqnhighlightheight #2}\endgroup}
 86\newcommand*{\eqncolor}[2]{\begingroup\colorlet{currentcolor}{.}\eqnhighlightfbox{#1}{\eqnhighlightheight #2}\endgroup}
 87
 88%%% Arguments to \eqnmark[box]: [highlight color]{node name}{term to highlight}
 89\newcommand*{\eqnmarkbox}[3][currentcolor]{\addvalue{#2}{#1}\tikzmarknode{#2}{\eqnhighlight{#1}{#3}}}
 90\newcommand*{\eqnmark}[3][currentcolor]{\addvalue{#2}{#1}\tikzmarknode{#2}{\eqncolor{#1}{#3}}}
 91
 92% Store current color in a dictionary (lookup table),
 93% from https://tex.stackexchange.com/a/48931/171664 :
 94\def\addvalue#1#2{\expandafter\gdef\csname eqnannotate@data@#1\endcsname{#2}}
 95\def\usevalue#1{%
 96  \ifcsname eqnannotate@data@#1\endcsname
 97    \csname eqnannotate@data@#1\expandafter\endcsname
 98  \else
 99    currentcolor%
100  \fi
101}
102
103
104%%%%% Helpers for swapping north/south / west/east / -/+ depending on above/below / left/right etc.:
105\newcommand*{\swapNorthSouth}[1]{%
106    \ifnum\pdfstrcmp{#1}{south}=0 north\else south\fi
107}
108\newcommand*{\swapWestEast}[1]{%
109    \ifnum\pdfstrcmp{#1}{east}=0 west\else east\fi
110}
111\newcommand*{\EAxshift}[1]{%
112    \ifnum\pdfstrcmp{#1}{east}=0 -0.3ex\else 0.3ex\fi
113}
114%%%%%
115
116
117\newcounter{eqnannotatenode}
118\newcommand*{\eqnannotateCurrentNode}{eqnannotatenode\theeqnannotatenode}
119
120
121\newcommand{\annotatetwo}[5][]{%
122    \begingroup% %%% so we don't leak the \def's below
123    \stepcounter{eqnannotatenode}%
124    %%% #1: (optional) extra args for \node e.g. yshift=...
125    \pgfkeys{/eqnannotate, #2}% %%% all configuration options
126    \def\myEAmarkOne{#3}%
127    \def\myEAmarkTwo{#4}%
128    \colorlet{currentcolor}{.}%
129    \def\myEAtext{#5}%
130    \def\myEAcolor{\usevalue{\myEAmarkOne}}%
131    \begin{tikzpicture}[overlay,remember picture,>=stealth,nodes={align=left,inner ysep=1pt},<-]
132        % default anchor is at center
133		\node[anchor=\swapNorthSouth{\EAmarkanchor},color=\myEAcolor!85,
134			annotate equations/text,#1
135			]  % color blended with white to 85%, any (optional) extra args #1
136            (\eqnannotateCurrentNode)   % use counter-based "local node"
137            at ($(\myEAmarkOne.\EAmarkanchor)!0.5!(\myEAmarkTwo.\EAmarkanchor)$)  % centered between the two nodes
138            {\myEAtext\eqnannotationstrut};
139        % double arrow to two uses within the equation:
140        \draw [<->,color=\myEAcolor, annotate equations/arrow] (\myEAmarkOne.\EAmarkanchor) |- ([yshift=0.1ex] \eqnannotateCurrentNode.\EAlabelanchor) -| (\myEAmarkTwo.\EAmarkanchor);  % from node 1 via annotation to node 2, with anchor #6 each
141    \end{tikzpicture}%
142    \endgroup% %%% close group again
143}
144
145
146%%% \extractfirst from https://tex.stackexchange.com/a/115733/171664
147\RequirePackage{expl3}
148\RequirePackage{xparse}
149\ExplSyntaxOn
150\NewDocumentCommand{\extractfirst}{mm}
151 {
152  \tl_set:Nx #1 {\clist_item:Nn #2 { 1 } }
153 }
154\ExplSyntaxOff
155%%%
156
157\newcommand{\annotate}[4][]{%
158    \begingroup% %%% so we don't leak the \def's below
159    \stepcounter{eqnannotatenode}%
160    %
161    %
162    %
163    % #1: (optional) extra args for \node e.g. yshift=...
164    \pgfkeys{/eqnannotate, #2}%
165    \def\myEAmarks{#3}%
166    \extractfirst\myEAmark\myEAmarks% %%% get first node for color and annotation
167    \def\myEAtext{#4}%
168    %
169    %
170    \colorlet{currentcolor}{.}%
171    \def\myEAcolor{\usevalue{\myEAmark}}%
172    %
173    \def\EAspace{ }% %%% workaround: did not find any other way of getting a space into \myEAlabelanchor without upsetting LaTeX/PGF/... somehow
174    \edef\myEAlabelanchor{\EAlabelanchor\EAspace\EAwesteast}%
175    %
176    %
177    \def\myEAxshift{\EAxshift{\EAwesteast}}%
178    \begin{tikzpicture}[overlay,remember picture,>=stealth,nodes={align=left,inner ysep=1pt},<-]
179		\node[anchor=\swapNorthSouth{\EAmarkanchor} \swapWestEast{\EAwesteast},
180			color=\myEAcolor!85,annotate equations/text,#1] % TODO for some reason, passing #1 through command doesn't work...
181                % anchor=west: align left edge of text on top of tikzmark in equation
182                % should be north west for below and south west for above ...
183            (\eqnannotateCurrentNode) at (\myEAmark.\EAmarkanchor)  % \EAmarkanchor north: above the equation, south: below
184            {\myEAtext\eqnannotationstrut};
185        \foreach \EAmark in \myEAmarks
186        \draw [color=\myEAcolor, annotate equations/arrow] (\EAmark.\EAmarkanchor)  % arrow from the equation
187                % \EAmarkanchor north: above the equation, south: below
188            |- ([xshift=\myEAxshift,yshift=0.1ex] \eqnannotateCurrentNode.\myEAlabelanchor);
189                % - south east: we want line to end at bottom right of annotation text;
190                % - negative xshift makes it a little bit shorter;
191                % - yshift for aesthetics (\strut is ever so slightly too tall).
192    \end{tikzpicture}%
193    \endgroup% %%% close group again
194}
195
196\endinput
197%%
198%% End of file