% Author and maintainer: SuFan (GitHub: Tape5try) % Contact: 3546236610@qq.com % Copyright (c) 2026 SuFan. MIT License; see LICENSE. \NeedsTeXFormat{LaTeX2e}[2020/10/01] \ProvidesPackage{gradbars}[2026/10/06 v0.0.4 Inline data bars for LaTeX] \RequirePackage{tikz} \RequirePackage{xparse} \RequirePackage{expl3} \RequirePackage{collcell} \RequirePackage{booktabs} \RequirePackage{colortbl} \RequirePackage{longtable} \usetikzlibrary{shadings,patterns} \definecolor{gradbarsBlue}{HTML}{2563EB} \definecolor{gradbarsBlueLight}{HTML}{93C5FD} \definecolor{gradbarsTeal}{HTML}{0F766E} \definecolor{gradbarsTealLight}{HTML}{5EEAD4} \definecolor{gradbarsInk}{HTML}{243247} \definecolor{gradbarsTrack}{HTML}{EDF2F7} % Public built-in palette. \definecolor{lightgreen}{RGB}{144,238,144} \definecolor{lightyellow}{RGB}{255,255,224} \definecolor{lightblue}{RGB}{173,216,230} \definecolor{lightred}{RGB}{255,160,122} \definecolor{rose}{RGB}{255,102,204} \definecolor{skyblue}{RGB}{135,206,235} \definecolor{gold}{RGB}{255,215,0} \definecolor{lavender}{RGB}{230,230,250} \definecolor{peach}{RGB}{255,218,185} \newif\ifgradbars@valid \newif\ifgradbars@gradient \def\gradbars@width{24mm} \def\gradbars@height{1.5ex} \def\gradbars@max{100} \def\gradbars@min{0} \def\gradbars@rounded{0pt} \def\gradbars@target{} \def\gradbars@targetcolor{gradbarsInk} \def\gradbars@negativecolor{lightred} \def\gradbars@thresholds{} \def\gradbars@thresholdcolors{lightred,gold,lightgreen} \def\gradbars@errorminus{} \def\gradbars@errorplus{} \def\gradbars@errorcolor{gradbarsInk} \newif\ifgradbars@error \newsavebox\gradbars@labelbox \def\gradbars@precision{1} \def\gradbars@unit{} \def\gradbars@text{} \def\gradbars@alt{} \def\gradbars@accessibility{auto} \newif\ifgradbars@capturealt \def\gradbars@label{outside} \def\gradbars@format{value} \def\gradbars@overflow{clip} \def\gradbars@gap{.6em} \def\gradbars@labelwidth{4.5em} \def\gradbars@font{\relax} \newif\ifgradbars@missing \newif\ifgradbars@stack \newcount\gradbars@styledepth \def\gradbars@missingtext{--} \def\gradbars@numberformat{fixed} \def\gradbars@band{} \def\gradbars@bandcolor{gold} \def\gradbars@bandopacity{0.3} \def\gradbars@stackcolors{gradbarsBlue,gradbarsTeal,gold} \pgfkeys{/gradbars/.is family,/gradbars, style/.code={\gradbarsUseStyle{#1}}, missing text/.store in=\gradbars@missingtext, number format/.is choice, number format/fixed/.code=\def\gradbars@numberformat{fixed}, number format/grouped/.code=\def\gradbars@numberformat{grouped}, number format/scientific/.code=\def\gradbars@numberformat{scientific}, band/.store in=\gradbars@band, band color/.store in=\gradbars@bandcolor, band opacity/.store in=\gradbars@bandopacity, stack colors/.store in=\gradbars@stackcolors, width/.store in=\gradbars@width, height/.store in=\gradbars@height, max/.store in=\gradbars@max, min/.store in=\gradbars@min, rounded/.store in=\gradbars@rounded, target/.store in=\gradbars@target, target color/.store in=\gradbars@targetcolor, negative color/.store in=\gradbars@negativecolor, thresholds/.store in=\gradbars@thresholds, threshold colors/.store in=\gradbars@thresholdcolors, error/.style={error minus=#1,error plus=#1}, error minus/.store in=\gradbars@errorminus, error plus/.store in=\gradbars@errorplus, error color/.store in=\gradbars@errorcolor, precision/.store in=\gradbars@precision, unit/.store in=\gradbars@unit, text/.store in=\gradbars@text, alt/.store in=\gradbars@alt, accessibility/.is choice, accessibility/auto/.code=\def\gradbars@accessibility{auto}, accessibility/artifact/.code=\def\gradbars@accessibility{artifact}, accessibility/off/.code=\def\gradbars@accessibility{off}, label gap/.store in=\gradbars@gap, label width/.store in=\gradbars@labelwidth, font/.store in=\gradbars@font, left color/.store in=\gradbars@left, right color/.store in=\gradbars@right, track color/.store in=\gradbars@track, text color/.store in=\gradbars@textcolor, color/.style={fill=solid,left color=#1}, fill/.is choice, fill/gradient/.code=\gradbars@gradienttrue, fill/solid/.code=\gradbars@gradientfalse, label/.is choice, label/outside/.code=\def\gradbars@label{outside}, label/inside/.code=\def\gradbars@label{inside}, label/none/.code=\def\gradbars@label{none}, label/end/.code=\def\gradbars@label{end}, label/auto/.code=\def\gradbars@label{auto}, value format/.is choice, value format/value/.code=\def\gradbars@format{value}, value format/percent/.code=\def\gradbars@format{percent}, overflow/.is choice, overflow/clip/.code=\def\gradbars@overflow{clip}, overflow/error/.code=\def\gradbars@overflow{error}, theme/.is choice, theme/blue/.style={fill=gradient,left color=gradbarsBlue, right color=gradbarsBlueLight,track color=gradbarsTrack,text color=gradbarsInk}, theme/teal/.style={fill=gradient,left color=gradbarsTeal, right color=gradbarsTealLight,track color=gradbarsTrack,text color=gradbarsInk}, theme/solid/.style={fill=solid,left color=gradbarsBlue, right color=gradbarsBlue,track color=gradbarsTrack,text color=gradbarsInk}, theme/gray/.style={fill=solid,left color=black!65, right color=black!65,track color=black!8,text color=black}, theme/lbyellow/.style={fill=gradient,left color=lightblue!90, right color=lightyellow!60,track color=gradbarsTrack,text color=gradbarsInk}, theme/viblue/.style={fill=gradient,left color=violet!20, right color=lightblue!70,track color=gradbarsTrack,text color=gradbarsInk}, theme/cyblu/.style={fill=gradient,left color=cyan, right color=blue!20,track color=gradbarsTrack,text color=gradbarsInk}, } \pgfkeys{/gradbars,theme=blue} \NewDocumentCommand\gradbarssetup{m}{\pgfkeys{/gradbars,#1}} % Style definitions follow ordinary TeX grouping, like setup. \NewDocumentCommand\gradbarsstyle{m m}{% \expandafter\def\csname gradbars@style@#1\endcsname{#2}} \def\gradbarsUseStyle#1{% \ifcsname gradbars@style@#1\endcsname \ifnum\gradbars@styledepth<32 \advance\gradbars@styledepth by 1 \expandafter\let\expandafter\gradbars@styleoptions\csname gradbars@style@#1\endcsname \expandafter\pgfkeysalso\expandafter{\gradbars@styleoptions}% \advance\gradbars@styledepth by -1 \else\PackageError{gradbars}{Style nesting exceeds 32 levels}{Check for recursive styles.}\fi \else\PackageError{gradbars}{Unknown style: #1}{Define it with gradbarsstyle first.}\fi } % Validate before drawing; floating point arithmetic also supports large counts. \ExplSyntaxOn \cs_new_protected:Npn \gradbarsCheckNumber #1#2 { \tl_set:Nx \l_tmpa_tl {#1} \tl_trim_spaces:N \l_tmpa_tl \regex_match:nVTF { \A [\+\-]? ( \d+ (\.\d*)? | \.\d+ ) \Z } \l_tmpa_tl { } { \gradbars@validfalse \PackageError{gradbars}{Invalid~#2:~expected~a~decimal~number} {Use~0,~86.5,~or~125000.~Expressions~are~not~accepted.} } } \cs_new_protected:Npn \gradbarsFail #1 {\gradbars@validfalse \PackageError{gradbars}{#1}{Check~the~gradbars~options~and~data.}} \cs_new_protected:Npn \gradbarsRange #1#2 { \fp_compare:nT {#2 < \gradbars@min || #2 > \gradbars@max} { \str_if_eq:eeTF {\gradbars@overflow}{error} {\gradbarsFail{#1~exceeds~range}} {\PackageWarning{gradbars}{#1~exceeds~range;~bar~clipped,~label~unchanged}} } } \cs_new:Npn \gradbarsPosition #1 {\fp_eval:n {(max(\gradbars@min,min(\gradbars@max,#1))-\gradbars@min)/ (\gradbars@max-\gradbars@min)}} \clist_new:N \l__gradbars_thresholds_clist \clist_new:N \l__gradbars_colors_clist \cs_new_protected:Npn \gradbarsValidate { \gradbars@missingfalse \tl_set:Nx \l_tmpa_tl {\gradbars@value} \tl_trim_spaces:N \l_tmpa_tl \tl_if_empty:NT \l_tmpa_tl {\gradbars@missingtrue} \str_if_eq:VnT \l_tmpa_tl {NA} {\gradbars@missingtrue} \ifgradbars@missing \def\gradbars@value{0}\fi \gradbarsCheckNumber{\gradbars@value}{value} \gradbarsCheckNumber{\gradbars@min}{min} \gradbarsCheckNumber{\gradbars@max}{max} \tl_set:Nx \l_tmpa_tl {\gradbars@precision} \regex_match:nVTF {\A [0-6] \Z} \l_tmpa_tl { } {\gradbarsFail{Precision~must~be~an~integer~from~0~to~6}} \ifgradbars@valid \fp_compare:nNnF {\gradbars@max} > {0} {\gradbarsFail{Max~must~be~greater~than~zero}} \fp_compare:nNnT {\gradbars@min} > {0} {\gradbarsFail{Min~must~be~zero~or~negative}} \fp_compare:nNnT {\gradbars@min} = {0} {\fp_compare:nNnT {\gradbars@value} < {0} {\gradbarsFail{Negative~values~require~a~negative~min}}} \str_if_eq:eeT {\gradbars@format}{percent} {\fp_compare:nNnT {\gradbars@min} < {0} {\gradbarsFail{Percent~format~requires~min=0}}} \fi \tl_if_empty:oF {\gradbars@target} {\gradbarsCheckNumber{\gradbars@target}{target}} \gradbars@errorfalse \tl_if_empty:oF {\gradbars@errorminus}{\gradbars@errortrue} \tl_if_empty:oF {\gradbars@errorplus}{\gradbars@errortrue} \ifgradbars@error \tl_if_empty:oT {\gradbars@errorminus}{\def\gradbars@errorminus{0}} \tl_if_empty:oT {\gradbars@errorplus}{\def\gradbars@errorplus{0}} \gradbarsCheckNumber{\gradbars@errorminus}{error~minus} \gradbarsCheckNumber{\gradbars@errorplus}{error~plus} \fi \clist_set:Nx \l__gradbars_thresholds_clist {\gradbars@thresholds} \clist_set:Nx \l__gradbars_colors_clist {\gradbars@thresholdcolors} \clist_if_empty:NF \l__gradbars_thresholds_clist { \int_compare:nNnF {\clist_count:N \l__gradbars_thresholds_clist} = {2} {\gradbarsFail{Thresholds~must~contain~two~values}} \int_compare:nNnF {\clist_count:N \l__gradbars_colors_clist} = {3} {\gradbarsFail{Threshold~colors~must~contain~three~colors}} \clist_map_inline:Nn \l__gradbars_thresholds_clist {\gradbarsCheckNumber{##1}{threshold}} } \ifgradbars@valid \gradbarsRange{Value}{\gradbars@value} \tl_if_empty:oF {\gradbars@target} { \fp_compare:nT {\gradbars@target < \gradbars@min || \gradbars@target > \gradbars@max} {\gradbarsFail{Target~must~lie~within~range}} \cs_set:Npx \gradbars@targetpos {\gradbarsPosition{\gradbars@target}} } \ifgradbars@error \fp_compare:nT {\gradbars@errorminus<0 || \gradbars@errorplus<0} {\gradbarsFail{Error~magnitudes~must~be~nonnegative}} \ifgradbars@missing\else \gradbarsRange{Error~lower~endpoint}{\gradbars@value-\gradbars@errorminus} \gradbarsRange{Error~upper~endpoint}{\gradbars@value+\gradbars@errorplus} \cs_set:Npx \gradbars@errorlo {\gradbarsPosition{\gradbars@value-\gradbars@errorminus}} \cs_set:Npx \gradbars@errorhi {\gradbarsPosition{\gradbars@value+\gradbars@errorplus}} \fi \fi \cs_set:Npx \gradbars@zero {\gradbarsPosition{0}} \cs_set:Npx \gradbars@end {\gradbarsPosition{\gradbars@value}} \cs_set:Npx \gradbars@start {\fp_eval:n {min(\gradbars@zero,\gradbars@end)}} \cs_set:Npx \gradbars@stop {\fp_eval:n {max(\gradbars@zero,\gradbars@end)}} \fp_compare:nNnT {\gradbars@value} < {0} {\gradbars@gradientfalse \let\gradbars@left\gradbars@negativecolor} \clist_if_empty:NF \l__gradbars_thresholds_clist { \fp_compare:nNnF {\clist_item:Nn \l__gradbars_thresholds_clist {1}} < {\clist_item:Nn \l__gradbars_thresholds_clist {2}} {\gradbarsFail{Thresholds~must~be~strictly~increasing}} \int_set:Nn \l_tmpa_int {1} \fp_compare:nNnF {\gradbars@value} < {\clist_item:Nn \l__gradbars_thresholds_clist {1}} {\int_set:Nn \l_tmpa_int {2}} \fp_compare:nNnF {\gradbars@value} < {\clist_item:Nn \l__gradbars_thresholds_clist {2}} {\int_set:Nn \l_tmpa_int {3}} \cs_set:Npx \gradbars@left {\clist_item:Nn \l__gradbars_colors_clist {\str_if_eq:eeTF {\gradbars@better}{lower}{4-\l_tmpa_int}{\l_tmpa_int}}} \gradbars@gradientfalse } \str_if_eq:eeTF {\gradbars@format}{percent} {\cs_set:Npx \gradbars@number {\fp_eval:n {100*\gradbars@value/\gradbars@max}}} {\cs_set:Npx \gradbars@number {\fp_eval:n {\gradbars@value}}} \fi } \clist_new:N \l__gradbars_band_clist \clist_new:N \l__gradbars_stack_clist \clist_new:N \l__gradbars_stackcolors_clist \fp_new:N \l__gradbars_sum_fp \fp_new:N \l__gradbars_before_fp \cs_new_protected:Npn \gradbarsValidateExtras { \clist_set:Nx \l__gradbars_band_clist {\gradbars@band} \clist_if_empty:NF \l__gradbars_band_clist { \tl_set:Nx \l_tmpa_tl {\gradbars@band} \regex_match:nVT {\A\s*,|,\s*,|,\s*\Z} \l_tmpa_tl {\gradbarsFail{Band~must~contain~two~endpoints}} \int_compare:nNnF {\clist_count:N \l__gradbars_band_clist} = {2} {\gradbarsFail{Band~must~contain~two~endpoints}} \clist_map_inline:Nn \l__gradbars_band_clist {\gradbarsCheckNumber{##1}{band~endpoint}} \gradbarsCheckNumber{\gradbars@bandopacity}{band~opacity} \ifgradbars@valid \cs_set:Npx \gradbars@bandlo {\clist_item:Nn \l__gradbars_band_clist {1}} \cs_set:Npx \gradbars@bandhi {\clist_item:Nn \l__gradbars_band_clist {2}} \fp_compare:nF {\gradbars@min <= \gradbars@bandlo < \gradbars@bandhi <= \gradbars@max} {\gradbarsFail{Band~must~be~increasing~and~within~range}} \fp_compare:nF {0 <= \gradbars@bandopacity <= 1} {\gradbarsFail{Band~opacity~must~be~between~zero~and~one}} \fi } \ifgradbars@stack \ifgradbars@valid \gradbarsRange{Positive~stack~total}{\gradbars@positive} \gradbarsRange{Negative~stack~total}{\gradbars@negative} \fp_compare:nNnT {\gradbars@negative} < {0} {\fp_compare:nNnT {\gradbars@min} = {0} {\gradbarsFail{Negative~stack~requires~a~negative~min}}} \cs_set:Npx \gradbars@start {\gradbarsPosition{\gradbars@negative}} \cs_set:Npx \gradbars@stop {\gradbarsPosition{\gradbars@positive}} \fi \tl_if_empty:oF {\gradbars@thresholds} {\gradbarsFail{Stacked~bars~do~not~support~thresholds}} \ifgradbars@error \gradbarsFail{Stacked~bars~do~not~support~error~whiskers}\fi \clist_set:Nx \l__gradbars_stackcolors_clist {\gradbars@stackcolors} \clist_if_empty:NT \l__gradbars_stackcolors_clist {\gradbarsFail{Stack~colors~must~not~be~empty}} \fi } \cs_new_protected:Npn \gradbarsDrawBand { \clist_if_empty:NF \l__gradbars_band_clist { \pgfmathsetlengthmacro\gradbars@bandxlo{\gradbarsPosition{\gradbars@bandlo}*(\gradbars@width)} \pgfmathsetlengthmacro\gradbars@bandxhi{\gradbarsPosition{\gradbars@bandhi}*(\gradbars@width)} \path[fill=\gradbars@bandcolor,fill~opacity=\gradbars@bandopacity,draw=none] (\gradbars@bandxlo,-2pt) rectangle ([yshift=2pt]\gradbars@bandxhi,\gradbars@height); } } \cs_new_protected:Npn \gradbarsParseStack #1 { \tl_set:Nx \l_tmpa_tl {#1} % Empty elements are invalid, not silently dropped by clist normalization. \regex_match:nVTF {\A\s*\Z|\A\s*,|,\s*,|,\s*\Z} \l_tmpa_tl {\gradbarsFail{Stack~requires~a~nonempty~list~of~numbers}} { } \clist_set:Nx \l__gradbars_stack_clist {#1} \fp_zero:N \l__gradbars_sum_fp \fp_zero:N \l__gradbars_positive_fp \fp_zero:N \l__gradbars_negative_fp \clist_map_inline:Nn \l__gradbars_stack_clist { \gradbarsCheckNumber{##1}{stack~segment} \ifgradbars@valid \fp_add:Nn \l__gradbars_sum_fp {##1} \fp_compare:nNnTF {##1} < {0} {\fp_add:Nn \l__gradbars_negative_fp {##1}} {\fp_add:Nn \l__gradbars_positive_fp {##1}} \fi } \cs_set:Npx \gradbars@total {\fp_to_decimal:N \l__gradbars_sum_fp} \cs_set:Npx \gradbars@positive {\fp_to_decimal:N \l__gradbars_positive_fp} \cs_set:Npx \gradbars@negative {\fp_to_decimal:N \l__gradbars_negative_fp} \cs_set:Npx \gradbars@gross {\fp_eval:n {\gradbars@positive-\gradbars@negative}} } \cs_new_protected:Npn \gradbarsDrawStack { \gradbarsStackReset \int_zero:N \l_tmpa_int \clist_map_inline:Nn \l__gradbars_stack_clist { \gradbarsStackStep{##1} \int_incr:N \l_tmpa_int \gradbarsCategoryColor{\l_tmpa_int} \pgfmathsetlengthmacro\gradbars@segmentlo {\gradbarsPosition{\l__gradbars_before_fp}*(\gradbars@width)} \pgfmathsetlengthmacro\gradbars@segmenthi {\gradbarsPosition{\l__gradbars_sum_fp}*(\gradbars@width)} \ifdim\gradbars@segmenthi>\gradbars@segmentlo\relax \ifgradbars@outline \draw[draw=\gradbars@segmentcolor,line~width=\gradbars@outlinewidth] (\gradbars@segmentlo,0) rectangle (\gradbars@segmenthi,\gradbars@height); \else \path[fill=\gradbars@segmentcolor,draw=none] (\gradbars@segmentlo,0) rectangle (\gradbars@segmenthi,\gradbars@height); \gradbarsPatternRect{\l_tmpa_int}{\gradbars@segmentlo}{0}{\gradbars@segmenthi}{\gradbars@height} \fi \fi } } \ExplSyntaxOff \def\gradbars@labelcontent{% \ifx\gradbars@text\@empty \ifgradbars@missing\gradbars@missingtext\else \begingroup \def\gradbars@temp{scientific}% \ifx\gradbars@numberformat\gradbars@temp \pgfmathprintnumber[sci,sci zerofill,precision=\gradbars@precision]{\gradbars@number}% \else \def\gradbars@temp{grouped}% \ifx\gradbars@numberformat\gradbars@temp \pgfmathprintnumber[fixed,fixed zerofill,precision=\gradbars@precision,1000 sep={\mathord{,}}]{\gradbars@number}% \else \pgfmathprintnumber[fixed,fixed zerofill,precision=\gradbars@precision,1000 sep={\,}]{\gradbars@number}% \fi \fi \def\gradbars@temp{percent}% \ifx\gradbars@format\gradbars@temp\%\else\gradbars@unit\fi \endgroup \fi \else\gradbars@text\fi } \def\gradbars@draw{% \tikzset{gradbars label background/.style={}}% \ifgradbars@print \tikzset{gradbars label background/.style={fill=white,inner sep=1pt}}% \fi \pgfmathsetlengthmacro\gradbars@xzero{\gradbars@zero*(\gradbars@width)}% \pgfmathsetlengthmacro\gradbars@xend{\gradbars@end*(\gradbars@width)}% \pgfmathsetlengthmacro\gradbars@xstart{\gradbars@start*(\gradbars@width)}% \pgfmathsetlengthmacro\gradbars@xstop{\gradbars@stop*(\gradbars@width)}% \pgfmathsetlengthmacro\gradbars@radius{min(\gradbars@rounded,.5*(\gradbars@height),.5*(\gradbars@width))}% \gradbarsDrawTrack \gradbarsDrawBand \gradbarsDrawShape \ifgradbars@spark\else\ifdim\gradbars@xzero>0pt \draw[gradbarsInk!65,line width=.35pt] (\gradbars@xzero,0)--(\gradbars@xzero,\gradbars@height); \fi\fi \ifx\gradbars@target\@empty\else \pgfmathsetlengthmacro\gradbars@xtarget{\gradbars@targetpos*(\gradbars@width)}% \draw[draw=\gradbars@targetcolor,line width=.6pt] ([yshift=-1pt]\gradbars@xtarget,0)-- ([yshift=1pt]\gradbars@xtarget,\gradbars@height); \fi \ifgradbars@missing\else\ifgradbars@error \pgfmathsetlengthmacro\gradbars@xlo{\gradbars@errorlo*(\gradbars@width)}% \pgfmathsetlengthmacro\gradbars@xhi{\gradbars@errorhi*(\gradbars@width)}% \draw[draw=\gradbars@errorcolor,line width=.5pt] ([yshift=.5*\gradbars@height]\gradbars@xlo,0)-- ([yshift=.5*\gradbars@height]\gradbars@xhi,0); \foreach \gradbars@cap in {\gradbars@xlo,\gradbars@xhi}{ \draw[draw=\gradbars@errorcolor,line width=.5pt] ([yshift=.2*\gradbars@height]\gradbars@cap,0)-- ([yshift=.8*\gradbars@height]\gradbars@cap,0); } \fi\fi \gradbarsDrawReferences \gradbarsDrawOverflow \gradbarsDrawChange \gradbarsResetLabels \ifgradbars@stack \gradbarsDrawSegmentLabels \ifgradbars@legend\gradbarsDrawLegend\fi \fi \gradbarsDrawMainLabel \path[use as bounding box] (0,-\gradbars@rowpadding) rectangle (\gradbars@width,{\gradbars@height+\gradbars@rowpadding}); } \def\gradbars@render{% \gradbars@validtrue \gradbarsResolveShapeLengths \gradbarsValidate \gradbarsValidateExtras \ifdim\gradbars@rounded<0pt \gradbars@validfalse \PackageError{gradbars}{Rounded radius must be nonnegative}{Use rounded=2pt.}% \fi \ifdim\gradbars@width>0pt\else \gradbars@validfalse \PackageError{gradbars}{Width must be positive}{Use a length such as 24mm.}% \fi \ifdim\gradbars@height>0pt\else \gradbars@validfalse \PackageError{gradbars}{Height must be positive}{Use a length such as 1.5ex.}% \fi \ifgradbars@valid \ifpgfpicture \begin{scope}\gradbars@draw\end{scope}% \else \gradbarsPrepareAlt \tikz[baseline={([yshift=-.5ex]0,{.5*\gradbars@height})}]{\gradbars@draw}% \fi \fi } \NewDocumentCommand\gradbar{O{} m}{% \leavevmode\begingroup \gradbarsCaptureTikzAlt \gradbars@capturealttrue \pgfkeys{/gradbars,#1}% \gradbars@capturealtfalse % Resolve font-relative dimensions in the surrounding text font. \ifpgfpicture \pgfinterruptpicture \font@name \edef\gradbars@resolved{% \noexpand\endpgfinterruptpicture \def\noexpand\gradbars@width{\the\dimexpr\gradbars@width\relax}% \def\noexpand\gradbars@height{\the\dimexpr\gradbars@height\relax}% \def\noexpand\gradbars@rounded{\the\dimexpr\gradbars@rounded\relax}% \def\noexpand\gradbars@gap{\the\dimexpr\gradbars@gap\relax}% \def\noexpand\gradbars@labelwidth{\the\dimexpr\gradbars@labelwidth\relax}% }% \gradbars@resolved \fi \def\gradbars@value{#2}% \gradbars@render \endgroup } \NewDocumentCommand\gradstack{O{} m}{% \leavevmode\begingroup \gradbars@validtrue \gradbarsParseStack{#2}% \ifgradbars@valid \gradbars@stacktrue \gradbar[#1]{\gradbars@total}% \fi \endgroup } % v0.0.2: labels, legends and collected table columns. \def\gradbars@stacknames{} \def\gradbars@segmentlabels{none} \def\gradbars@segmentfont{\scriptsize} \def\gradbars@segmenttextcolor{auto} \def\gradbars@labeloverflow{auto} \newif\ifgradbars@legend \newif\ifgradbars@inside \newif\ifgradbars@fit \newsavebox\gradbars@segmentbox \pgfkeys{/gradbars, stack names/.store in=\gradbars@stacknames, legend/.is if=gradbars@legend,legend/.default=true, segment font/.store in=\gradbars@segmentfont, segment text color/.store in=\gradbars@segmenttextcolor, segment labels/.is choice, segment labels/none/.code=\def\gradbars@segmentlabels{none}, segment labels/value/.code=\def\gradbars@segmentlabels{value}, segment labels/percent/.code=\def\gradbars@segmentlabels{percent}, segment labels/name/.code=\def\gradbars@segmentlabels{name}, segment labels/name value/.code=\def\gradbars@segmentlabels{name value}, segment labels/name percent/.code=\def\gradbars@segmentlabels{name percent}, label overflow/.is choice, label overflow/auto/.code=\def\gradbars@labeloverflow{auto}, label overflow/allow/.code=\def\gradbars@labeloverflow{allow} } \def\gradbarsMeasure#1#2#3{% \sbox#1{\pgfinterruptpicture\font@name #2#3\endpgfinterruptpicture}} \ExplSyntaxOn \clist_new:N \l__gradbars_names_clist \seq_new:N \l__gradbars_occupied_seq \dim_new:N \l__gradbars_top_dim \dim_new:N \l__gradbars_labelbottom_dim \dim_new:N \l__gradbars_labelleft_dim \dim_new:N \l__gradbars_labelright_dim \dim_new:N \l__gradbars_leaderx_dim \dim_new:N \l__gradbars_leaderleft_dim \dim_new:N \l__gradbars_leaderright_dim \fp_new:N \l__gradbars_luminance_fp \int_new:N \l__gradbars_index_int \cs_new_protected:Npn \gradbarsContrast #1 { \convertcolorspec{named}{#1}{rgb}\gradbars@rgb \clist_set:Nx \l_tmpa_clist {\gradbars@rgb} \fp_zero:N \l__gradbars_luminance_fp \int_step_inline:nn {3} { \fp_set:Nn \l_tmpa_fp {\clist_item:Nn \l_tmpa_clist {##1}} \fp_compare:nNnTF {\l_tmpa_fp} > {0.04045} {\fp_set:Nn \l_tmpa_fp {((\l_tmpa_fp+0.055)/1.055)^2.4}} {\fp_set:Nn \l_tmpa_fp {\l_tmpa_fp/12.92}} \fp_add:Nn \l__gradbars_luminance_fp {\l_tmpa_fp*\clist_item:nn {0.2126,0.7152,0.0722}{##1}} } \fp_compare:nNnTF {\l__gradbars_luminance_fp} > {0.179} {\def\gradbars@labelcolor{black}}{\def\gradbars@labelcolor{white}} } \let\gradbarsValidatePrevious\gradbarsValidateExtras \cs_set_protected:Npn \gradbarsValidateExtras { \gradbarsValidatePrevious \clist_set:No \l__gradbars_names_clist {\gradbars@stacknames} \ifgradbars@stack \clist_if_empty:NF \l__gradbars_names_clist {\int_compare:nNnF {\clist_count:N \l__gradbars_names_clist} = {\clist_count:N \l__gradbars_stack_clist} {\gradbarsFail{Stack~names~must~match~the~segment~count}}} \bool_set_false:N \l_tmpa_bool \ifgradbars@legend \bool_set_true:N \l_tmpa_bool \fi \str_case_e:nn {\gradbars@segmentlabels} {{name}{\bool_set_true:N \l_tmpa_bool} {name~value}{\bool_set_true:N \l_tmpa_bool} {name~percent}{\bool_set_true:N \l_tmpa_bool}} \bool_if:NT \l_tmpa_bool {\clist_if_empty:NT \l__gradbars_names_clist {\gradbarsFail{Stack~names~are~required~for~names~or~legend}}} \ifgradbars@legend \ifdim\gradbars@width>14pt\relax\else \gradbarsFail{Legend~width~must~exceed~14pt}\fi \fi \else \ifgradbars@legend \gradbarsFail{Automatic~legend~requires~gradstack}\fi \fi } \cs_new_protected:Npn \gradbarsResetLabels {\seq_clear:N \l__gradbars_occupied_seq \dim_set:Nn \l__gradbars_top_dim {\gradbars@height+4pt}} \cs_new_protected:Npn \gradbarsCheckOverlap #1#2#3 { \dim_compare:nNnT {\l__gradbars_labelleft_dim} < {#2+3pt} {\dim_compare:nNnT {\l__gradbars_labelright_dim} > {#1-3pt} {\dim_set:Nn \l__gradbars_labelbottom_dim {\dim_max:nn {\l__gradbars_labelbottom_dim}{#3+3pt}}}} } \cs_new_protected:Npn \gradbarsLeaderBounds #1#2#3 { \dim_set:Nn \l__gradbars_leaderleft_dim {\dim_min:nn {\l__gradbars_leaderleft_dim}{#1-4pt}} \dim_set:Nn \l__gradbars_leaderright_dim {\dim_max:nn {\l__gradbars_leaderright_dim}{#2+4pt}} } \cs_new_protected:Npn \gradbarsPlaceSegment { \pgfmathsetlengthmacro\gradbars@segmentmid{.5*(\gradbars@segmentlo+\gradbars@segmenthi)} \gradbars@fittrue \ifgradbars@outline\gradbars@fitfalse\fi \ifdim\dimexpr\wd\gradbars@segmentbox+4pt\relax>\dimexpr\gradbars@segmenthi-\gradbars@segmentlo\relax \gradbars@fitfalse\fi \ifdim\dimexpr\ht\gradbars@segmentbox+\dp\gradbars@segmentbox+2pt\relax>\gradbars@height\relax \gradbars@fitfalse\fi \ifx\gradbars@target\@empty\else \pgfmathsetlengthmacro\gradbars@distance{abs(\gradbars@xtarget-\gradbars@segmentmid)} \ifdim\gradbars@distance<\dimexpr.5\wd\gradbars@segmentbox+2pt\relax \gradbars@fitfalse\fi \fi \ifgradbars@fit \let\gradbars@labelcolor\gradbars@segmenttextcolor \str_if_eq:eeT {\gradbars@segmenttextcolor}{auto}{\gradbarsContrast{\gradbars@segmentcolor}} \gradbarsMeasure\gradbars@segmentbox\gradbars@segmentfont{\color{\gradbars@labelcolor}\gradbars@segmentcontent} \node[inner~sep=0pt,outer~sep=0pt,text=\gradbars@labelcolor] [gradbars~label~background] at (\gradbars@segmentmid,.5*\gradbars@height){\usebox\gradbars@segmentbox}; \else \pgfmathsetlengthmacro\gradbars@labelx {max(.5*\wd\gradbars@segmentbox,min(\gradbars@segmentmid,\gradbars@width-.5*\wd\gradbars@segmentbox))} \dim_set:Nn \l__gradbars_labelleft_dim {\gradbars@labelx-.5\wd\gradbars@segmentbox} \dim_set:Nn \l__gradbars_labelright_dim {\gradbars@labelx+.5\wd\gradbars@segmentbox} \dim_set:Nn \l__gradbars_labelbottom_dim {\gradbars@height+4pt} \seq_map_inline:Nn \l__gradbars_occupied_seq {\gradbarsCheckOverlap ##1} % Route elevated leaders around earlier label boxes, not through text. \dim_set:Nn \l__gradbars_leaderx_dim {\gradbars@segmentmid} \dim_compare:nNnT {\l__gradbars_labelbottom_dim} > {\gradbars@height+4pt} { \dim_set:Nn \l__gradbars_leaderleft_dim {\gradbars@segmentmid} \dim_set:Nn \l__gradbars_leaderright_dim {\gradbars@segmentmid} \seq_map_inline:Nn \l__gradbars_occupied_seq {\gradbarsLeaderBounds ##1} \dim_compare:nNnTF {\gradbars@segmentmid-\l__gradbars_leaderleft_dim} < {\l__gradbars_leaderright_dim-\gradbars@segmentmid} {\dim_set_eq:NN \l__gradbars_leaderx_dim \l__gradbars_leaderleft_dim} {\dim_set_eq:NN \l__gradbars_leaderx_dim \l__gradbars_leaderright_dim} } \seq_put_right:Nx \l__gradbars_occupied_seq {{\dim_use:N \l__gradbars_labelleft_dim}{\dim_use:N \l__gradbars_labelright_dim} {\dim_eval:n {\l__gradbars_labelbottom_dim+\ht\gradbars@segmentbox+\dp\gradbars@segmentbox}}} \dim_set:Nn \l__gradbars_top_dim {\dim_max:nn {\l__gradbars_top_dim} {\l__gradbars_labelbottom_dim+\ht\gradbars@segmentbox+\dp\gradbars@segmentbox+3pt}} \draw[gradbarsInk!55,line~width=.3pt] (\gradbars@segmentmid,\gradbars@height)-- (\gradbars@segmentmid,\dim_eval:n {\gradbars@height+1pt})-- (\dim_use:N \l__gradbars_leaderx_dim,\dim_eval:n {\gradbars@height+1pt})-- (\dim_use:N \l__gradbars_leaderx_dim,\dim_eval:n {\l__gradbars_labelbottom_dim-2pt})-- (\gradbars@labelx,\dim_eval:n {\l__gradbars_labelbottom_dim-2pt}); \let\gradbars@labelcolor\gradbars@segmenttextcolor \str_if_eq:eeT {\gradbars@segmenttextcolor}{auto}{\def\gradbars@labelcolor{black}} \gradbarsMeasure\gradbars@segmentbox\gradbars@segmentfont{\color{\gradbars@labelcolor}\gradbars@segmentcontent} \node[anchor=south,inner~sep=0pt,outer~sep=0pt,text=\gradbars@labelcolor] at (\gradbars@labelx,\dim_use:N \l__gradbars_labelbottom_dim){\usebox\gradbars@segmentbox}; \fi } \cs_new_protected:Npn \gradbarsDrawSegmentLabels { \str_if_eq:eeF {\gradbars@segmentlabels}{none} { \gradbarsStackReset \int_zero:N \l__gradbars_index_int \clist_map_inline:Nn \l__gradbars_stack_clist { \int_incr:N \l__gradbars_index_int \gradbarsStackStep{##1} \pgfmathsetlengthmacro\gradbars@segmentlo{\gradbarsPosition{\l__gradbars_before_fp}*(\gradbars@width)} \pgfmathsetlengthmacro\gradbars@segmenthi{\gradbarsPosition{\l__gradbars_sum_fp}*(\gradbars@width)} \ifdim\gradbars@segmenthi>\gradbars@segmentlo\relax \gradbarsCategoryColor{\l__gradbars_index_int} \def\gradbars@segmentcontent {\def\gradbars@text{}\def\gradbars@unit{}\def\gradbars@format{value} \cs_set:Npx \gradbars@number {\fp_eval:n {##1}} \str_case_e:nn {\gradbars@segmentlabels} {{percent}{\def\gradbars@format{percent}} {name~percent}{\def\gradbars@format{percent}}} \str_if_eq:eeT {\gradbars@format}{percent} {\cs_set:Npx \gradbars@number {\fp_eval:n {100*abs(##1)/\gradbars@gross}}} \tl_clear:N \l_tmpb_tl \str_case_e:nn {\gradbars@segmentlabels} {{name}{\tl_set:Nn \l_tmpb_tl {name}} {name~value}{\tl_set:Nn \l_tmpb_tl {both}} {name~percent}{\tl_set:Nn \l_tmpb_tl {both}}} \tl_if_empty:NF \l_tmpb_tl {\clist_item:Nn \l__gradbars_names_clist {\l__gradbars_index_int}} \str_if_eq:VnT \l_tmpb_tl {both}{:\space} \str_if_eq:VnF \l_tmpb_tl {name}{\gradbarsSingleLabel}} \gradbarsMeasure\gradbars@segmentbox\gradbars@segmentfont{\gradbars@segmentcontent} \gradbarsPlaceSegment \fi } } } \cs_new_protected:Npn \gradbarsDrawLegend { \dim_set:Nn \l_tmpa_dim {6pt} \int_zero:N \l__gradbars_index_int \clist_map_inline:Nn \l__gradbars_names_clist { \int_incr:N \l__gradbars_index_int \gradbarsCategoryColor{\l__gradbars_index_int} \gradbarsMeasure\gradbars@segmentbox\gradbars@font {\parbox[t]{\dimexpr\gradbars@width-14pt\relax}{\raggedright\strut ##1\strut}} \ifgradbars@outline \draw[draw=\gradbars@segmentcolor,line~width=\gradbars@outlinewidth] (0,-\dim_use:N \l_tmpa_dim) rectangle (8pt,-\dim_eval:n {\l_tmpa_dim+6pt}); \else \path[fill=\gradbars@segmentcolor,draw=none] (0,-\dim_use:N \l_tmpa_dim) rectangle (8pt,-\dim_eval:n {\l_tmpa_dim+6pt}); \gradbarsPatternRect{\l__gradbars_index_int}{0}{-\dim_use:N \l_tmpa_dim} {8pt}{-\dim_eval:n {\l_tmpa_dim+6pt}} \fi \node[anchor=north~west,inner~sep=0pt,outer~sep=0pt,text=gradbarsInk] at (14pt,-\dim_use:N \l_tmpa_dim){\usebox\gradbars@segmentbox}; \dim_add:Nn \l_tmpa_dim {\ht\gradbars@segmentbox+\dp\gradbars@segmentbox+4pt} } } \cs_new_protected:Npn \gradbarsMainBackground { \def\gradbars@labelcolor{black} \ifgradbars@inside \let\gradbars@background\gradbars@track \clist_if_empty:NF \l__gradbars_band_clist {\dim_compare:nNnT {\gradbars@labelx} > {\gradbars@bandxlo} {\dim_compare:nNnT {\gradbars@labelx} < {\gradbars@bandxhi} {\edef\gradbars@background{\gradbars@bandcolor! \fp_eval:n {100*\gradbars@bandopacity}!\gradbars@track}}}} \ifdim\gradbars@labelx>\gradbars@xstart\relax \ifdim\gradbars@labelx<\gradbars@xstop\relax \let\gradbars@background\gradbars@left \ifgradbars@gradient \pgfmathparse{100*(\gradbars@labelx-\gradbars@xstart)/(\gradbars@xstop-\gradbars@xstart)} \edef\gradbars@background{\gradbars@right!\pgfmathresult!\gradbars@left} \fi \ifgradbars@stack \fp_zero:N \l__gradbars_sum_fp \int_zero:N \l__gradbars_index_int \clist_map_inline:Nn \l__gradbars_stack_clist {\fp_add:Nn \l__gradbars_sum_fp {##1}\int_incr:N \l__gradbars_index_int \pgfmathsetlengthmacro\gradbars@segmenthi{\gradbarsPosition{\l__gradbars_sum_fp}*(\gradbars@width)} \dim_compare:nNnT {\gradbars@labelx} < {\gradbars@segmenthi} { \gradbarsCategoryColor{\l__gradbars_index_int} \let\gradbars@background\gradbars@segmentcolor \clist_map_break: }} \fi \fi \fi \gradbarsContrast{\gradbars@background} \fi } \cs_new_protected:Npn \gradbarsDrawMainLabel { \str_if_eq:eeF {\gradbars@label}{none} { \gradbarsMeasure\gradbars@labelbox\gradbars@font{\gradbars@labelcontent} \let\gradbars@placement\gradbars@label \gradbars@insidefalse \str_if_eq:eeT {\gradbars@placement}{auto} {\def\gradbars@placement{outside} \ifdim\dimexpr\wd\gradbars@labelbox+4pt\relax<\dimexpr\gradbars@xstop-\gradbars@xstart\relax \def\gradbars@placement{center}\fi} \str_if_eq:eeF {\gradbars@labeloverflow}{allow} {\str_if_eq:eeT {\gradbars@placement}{inside} {\ifdim\dimexpr\wd\gradbars@labelbox+4pt\relax>\gradbars@width\relax \def\gradbars@placement{outside}\fi} \str_if_eq:eeT {\gradbars@placement}{end} {\ifdim\wd\gradbars@labelbox>\gradbars@width\relax \def\gradbars@placement{outside}\fi}} \str_case_e:nn {\gradbars@placement} {{inside}{\gradbars@insidetrue}{center}{\gradbars@insidetrue}} \ifgradbars@inside \str_if_eq:eeF {\gradbars@shape}{bar} {\def\gradbars@placement{outside}\gradbars@insidefalse} \ifgradbars@stack \fp_compare:nNnT {\gradbars@negative} < {0} {\def\gradbars@placement{outside}\gradbars@insidefalse} \fi \ifgradbars@compare \def\gradbars@placement{outside}\gradbars@insidefalse\fi \ifgradbars@outline \def\gradbars@placement{outside}\gradbars@insidefalse\fi \ifgradbars@rangemode \tl_if_empty:oF {\gradbars@rangepoint} {\def\gradbars@placement{outside}\gradbars@insidefalse} \fi \fi \ifgradbars@inside \str_if_eq:eeF {\gradbars@labeloverflow}{allow} {\ifdim\dimexpr\ht\gradbars@labelbox+\dp\gradbars@labelbox+2pt\relax>\gradbars@height\relax \def\gradbars@placement{outside}\gradbars@insidefalse\fi} \ifgradbars@stack \str_if_eq:eeF {\gradbars@segmentlabels}{none} {\def\gradbars@placement{outside}\gradbars@insidefalse} \fi \ifgradbars@error \def\gradbars@placement{outside}\gradbars@insidefalse\fi \ifgradbars@inside \str_if_eq:eeTF {\gradbars@placement}{center} {\pgfmathsetlengthmacro\gradbars@labelx{.5*(\gradbars@xstart+\gradbars@xstop)}} {\pgfmathsetlengthmacro\gradbars@labelx{\gradbars@width-2pt-.5*\wd\gradbars@labelbox}} \ifx\gradbars@target\@empty\else \pgfmathsetlengthmacro\gradbars@distance{abs(\gradbars@xtarget-\gradbars@labelx)} \ifdim\gradbars@distance<\dimexpr.5\wd\gradbars@labelbox+2pt\relax \def\gradbars@placement{outside}\gradbars@insidefalse\fi \fi \fi \fi \let\gradbars@labelcolor\gradbars@textcolor \str_if_eq:eeT {\gradbars@textcolor}{auto}{\gradbarsMainBackground} \gradbarsMeasure\gradbars@labelbox\gradbars@font{\color{\gradbars@labelcolor}\gradbars@labelcontent} \ifgradbars@inside \node[inner~sep=0pt,outer~sep=0pt,text=\gradbars@labelcolor] [gradbars~label~background] at (\gradbars@labelx,.5*\gradbars@height){\usebox\gradbars@labelbox}; \else \str_if_eq:eeTF {\gradbars@placement}{end} {\pgfmathsetlengthmacro\gradbars@labelx {max(.5*\wd\gradbars@labelbox,min(\gradbars@xend,\gradbars@width-.5*\wd\gradbars@labelbox))} \node[anchor=south,inner~sep=0pt,outer~sep=0pt,text=\gradbars@labelcolor] at (\gradbars@labelx,\dim_use:N \l__gradbars_top_dim){\usebox\gradbars@labelbox};} {\dim_set:Nn \l_tmpa_dim {\gradbars@labelwidth} \str_if_eq:eeF {\gradbars@labeloverflow}{allow} {\dim_set:Nn \l_tmpa_dim {\dim_max:nn {\l_tmpa_dim}{\wd\gradbars@labelbox}}} \node[anchor=west,inner~sep=0pt,outer~sep=0pt,text=\gradbars@labelcolor] at ([xshift=\gradbars@gap,yshift=.5*\gradbars@height]\gradbars@width,0) {\makebox[\dim_use:N \l_tmpa_dim][r]{\usebox\gradbars@labelbox}};} \fi } } \ExplSyntaxOff \NewDocumentCommand\gradbarslegend{O{} m}{% \begingroup\gradbarsCaptureTikzAlt\gradbars@capturealttrue \pgfkeys{/gradbars,#1,stack names={#2}}\gradbars@capturealtfalse% \begingroup\font@name \edef\gradbars@next{\endgroup \def\noexpand\gradbars@width{\the\dimexpr\gradbars@width\relax}}% \gradbars@next \gradbarsResolveShapeLengths \gradbarsStandaloneLegend \endgroup} \ExplSyntaxOn \cs_new_protected:Npn \gradbarsStandaloneLegend { \gradbars@validtrue \clist_set:No \l__gradbars_names_clist {\gradbars@stacknames} \clist_set:No \l__gradbars_stackcolors_clist {\gradbars@stackcolors} \clist_if_empty:NT \l__gradbars_names_clist {\gradbarsFail{Legend~names~must~not~be~empty}} \clist_if_empty:NT \l__gradbars_stackcolors_clist {\gradbarsFail{Stack~colors~must~not~be~empty}} \gradbarsValidatePatterns \ifdim\gradbars@width>14pt\else\gradbarsFail{Legend~width~must~exceed~14pt}\fi \ifgradbars@valid \ifpgfpicture \gradbarsDrawLegend \else\gradbarsPrepareLegendAlt\tikz[baseline=0pt]{\gradbarsDrawLegend}\fi \fi } \ExplSyntaxOff \NewDocumentCommand\gradbarscolumn{m m}{% \gradbarsDefineColumn{#1}{#2}} \ExplSyntaxOn \cs_new_protected:Npn \gradbarsDefineColumn #1#2 { \regex_match:nnTF {\A[A-Za-z]\Z} {#1} {\expandafter\newcolumntype\expandafter{#1} {>{\collectcell{\gradbar[#2]}}l<{\endcollectcell}}} {\PackageError{gradbars}{Column~name~must~be~one~ASCII~letter} {Choose~a~single~unused~letter,~for~example~G.}} } \ExplSyntaxOff % Data import, print patterns and metric direction (v0.0.2). \def\gradbars@better{higher} \def\gradbars@pattern{none} \def\gradbars@patterncolor{black} \def\gradbars@stackpatterns{none} \newif\ifgradbars@print \pgfkeys{/gradbars, print labels/.is if=gradbars@print, better/.is choice, better/higher/.code=\def\gradbars@better{higher}, better/lower/.code=\def\gradbars@better{lower}, pattern/.store in=\gradbars@pattern, pattern color/.store in=\gradbars@patterncolor, stack patterns/.store in=\gradbars@stackpatterns, print/.style={outline=false,print labels=true,theme=gray,color=white,track color=black!8, negative color=white,text color=black,segment text color=black, pattern=diagonal,pattern color=black, stack colors={white},stack patterns={diagonal,dots,crosshatch}, threshold colors={black!10,black!25,black!45}} } \ExplSyntaxOn \prop_const_from_keyval:Nn \c__gradbars_patterns_prop {none=none,diagonal=north~east~lines,reverse=north~west~lines, dots=dots,crosshatch=crosshatch,horizontal=horizontal~lines,vertical=vertical~lines} \clist_new:N \l__gradbars_patterns_clist \tl_new:N \l__gradbars_pattern_tl \cs_new_protected:Npn \gradbarsPatternRect #1#2#3#4#5 { \int_compare:nNnTF {#1} = {0} {\tl_set:No \l__gradbars_pattern_tl {\gradbars@pattern}} {\clist_set:No \l__gradbars_patterns_clist {\gradbars@stackpatterns} \tl_set:Nx \l__gradbars_pattern_tl {\clist_item:Nn \l__gradbars_patterns_clist {1+\int_mod:nn {#1-1}{\clist_count:N \l__gradbars_patterns_clist}}}} \gradbarsCategoryPattern{#1} \prop_get:NVNTF \c__gradbars_patterns_prop \l__gradbars_pattern_tl \l__gradbars_pattern_tl {\tl_if_eq:NnF \l__gradbars_pattern_tl {none} {\path[pattern=\l__gradbars_pattern_tl,pattern~color=\gradbars@patterncolor,draw=none] (#2,#3) rectangle (#4,#5);}} {\gradbarsFail{Unknown~pattern}} } \cs_new_eq:NN \gradbarsValidateBeforePatterns \gradbarsValidateExtras \cs_set_protected:Npn \gradbarsValidateExtras { \gradbarsValidateBeforePatterns \gradbarsValidatePatterns } \cs_new_protected:Npn \gradbarsValidatePatterns { \clist_set:No \l__gradbars_patterns_clist {\gradbars@stackpatterns} \clist_if_empty:NT \l__gradbars_patterns_clist {\gradbarsFail{Stack~patterns~must~not~be~empty}} \clist_put_left:No \l__gradbars_patterns_clist {\gradbars@pattern} \clist_map_inline:Nn \l__gradbars_patterns_clist {\prop_if_in:NnF \c__gradbars_patterns_prop {##1}{\gradbarsFail{Unknown~pattern:~##1}}} } % CSV is read as character data; fields are never executed as TeX. \ior_new:N \l__gradbars_csv_ior \prop_new:N \l__gradbars_csv_prop \seq_new:N \l__gradbars_csv_fields_seq \tl_new:N \l__gradbars_csv_field_tl \tl_new:N \l__gradbars_csv_line_tl \tl_new:N \l__gradbars_csv_value_tl \tl_new:N \l__gradbars_csv_table_tl \clist_new:N \l__gradbars_csv_missing_clist \int_new:N \l__gradbars_csv_state_int \int_new:N \l__gradbars_csv_row_int \int_new:N \l__gradbars_csv_col_int \int_new:N \l__gradbars_csv_width_int \fp_new:N \l__gradbars_csv_min_fp \fp_new:N \l__gradbars_csv_max_fp \keys_define:nn {gradbars/csv} {missing .clist_set:N=\l__gradbars_csv_missing_clist} \cs_generate_variant:Nn \prop_put:Nnn {Nxn,Nxx,NVx} \cs_generate_variant:Nn \prop_get:NnN {cxN} \cs_generate_variant:Nn \prop_if_in:NnTF {cxTF} \cs_new_protected:Npn \gradbarsCSVField {\tl_trim_spaces:N \l__gradbars_csv_field_tl \seq_put_right:NV \l__gradbars_csv_fields_seq \l__gradbars_csv_field_tl \tl_clear:N \l__gradbars_csv_field_tl \int_zero:N \l__gradbars_csv_state_int} \cs_new_protected:Npn \gradbarsCSVParse #1 { \seq_clear:N \l__gradbars_csv_fields_seq \tl_clear:N \l__gradbars_csv_field_tl \int_zero:N \l__gradbars_csv_state_int % states: 0=unquoted, 1=quoted, 2=closing quote, 3=trailing space. \str_map_inline:nn {#1} { \int_case:nn {\l__gradbars_csv_state_int} { {0}{\str_case:nnF {##1} {{,}{\gradbarsCSVField} {"}{\tl_if_blank:VTF \l__gradbars_csv_field_tl {\tl_clear:N \l__gradbars_csv_field_tl\int_set:Nn \l__gradbars_csv_state_int {1}} {\gradbarsFail{Quote~inside~unquoted~CSV~field}}}} {\tl_put_right:Nn \l__gradbars_csv_field_tl {##1}}} {1}{\str_if_eq:nnTF {##1}{"} {\int_set:Nn \l__gradbars_csv_state_int {2}} {\tl_put_right:Nn \l__gradbars_csv_field_tl {##1}}} {2}{\str_case:nnF {##1} {{"}{\tl_put_right:Nn \l__gradbars_csv_field_tl {"}\int_set:Nn \l__gradbars_csv_state_int {1}} {,}{\gradbarsCSVField}} {\str_if_eq:nnTF {##1}{~} {\int_set:Nn \l__gradbars_csv_state_int {3}} {\gradbarsFail{Unexpected~text~after~CSV~quote}}}} {3}{\str_if_eq:nnTF {##1}{,}{\gradbarsCSVField} {\str_if_eq:nnF {##1}{~}{\gradbarsFail{Unexpected~text~after~CSV~quote}}}} } } \int_compare:nNnT {\l__gradbars_csv_state_int} = {1} {\gradbarsFail{Unclosed~CSV~quote;~multiline~fields~are~not~supported}} \gradbarsCSVField } \cs_new_protected:Npn \gradbarsCSVLine #1 { \tl_set:Nn \l__gradbars_csv_line_tl {#1} % pdfTeX reads UTF-8 as bytes; Unicode engines read a single BOM character. \sys_if_engine_pdftex:TF {\regex_replace_once:nnN {\A\x{EF}\x{BB}\x{BF}} {} \l__gradbars_csv_line_tl} {\regex_replace_once:nnN {\A\x{FEFF}} {} \l__gradbars_csv_line_tl} \tl_if_blank:VF \l__gradbars_csv_line_tl { \exp_args:NV \gradbarsCSVParse \l__gradbars_csv_line_tl \int_compare:nNnTF {\l__gradbars_csv_row_int} = {0} { \int_set:Nn \l__gradbars_csv_width_int {\seq_count:N \l__gradbars_csv_fields_seq} \int_zero:N \l__gradbars_csv_col_int \seq_map_inline:Nn \l__gradbars_csv_fields_seq {\int_incr:N \l__gradbars_csv_col_int \tl_if_blank:nT {##1}{\gradbarsFail{CSV~header~must~not~be~empty}} \prop_if_in:NnT \l__gradbars_csv_prop {col/##1}{\gradbarsFail{Duplicate~CSV~header:~##1}} \prop_put:Nnx \l__gradbars_csv_prop {col/##1}{\int_use:N \l__gradbars_csv_col_int}} } { \int_compare:nNnF {\seq_count:N \l__gradbars_csv_fields_seq} = {\l__gradbars_csv_width_int} {\gradbarsFail{CSV~row~has~wrong~field~count}} \int_zero:N \l__gradbars_csv_col_int \seq_map_inline:Nn \l__gradbars_csv_fields_seq {\int_incr:N \l__gradbars_csv_col_int \prop_put:Nxn \l__gradbars_csv_prop {row/\int_use:N \l__gradbars_csv_row_int/\int_use:N \l__gradbars_csv_col_int}{##1}} } \int_incr:N \l__gradbars_csv_row_int } } \NewDocumentCommand\gradbarsloadcsv{O{} m m} { \gradbars@validtrue \regex_match:nnF {\A[A-Za-z][A-Za-z0-9_\-]*\Z}{#2} {\gradbarsFail{CSV~dataset~name~must~start~with~an~ASCII~letter}} \clist_set:Nn \l__gradbars_csv_missing_clist {NA,N/A,null} \keys_set:nn {gradbars/csv}{#1} \prop_clear:N \l__gradbars_csv_prop \int_zero:N \l__gradbars_csv_row_int \file_if_exist:nTF {#3} {\ior_open:Nn \l__gradbars_csv_ior {#3} \ior_str_map_inline:Nn \l__gradbars_csv_ior {\gradbarsCSVLine{##1}} \ior_close:N \l__gradbars_csv_ior} {\gradbarsFail{CSV~file~not~found:~#3}} \int_compare:nNnF {\l__gradbars_csv_row_int} > {0}{\gradbarsFail{CSV~requires~a~header}} \ifgradbars@valid \prop_put:Nnx \l__gradbars_csv_prop {rows}{\int_eval:n {\l__gradbars_csv_row_int-1}} \prop_put:NnV \l__gradbars_csv_prop {missing}\l__gradbars_csv_missing_clist \prop_if_exist:cF {l__gradbars_csv_#2_prop}{\prop_new:c {l__gradbars_csv_#2_prop}} \prop_set_eq:cN {l__gradbars_csv_#2_prop}\l__gradbars_csv_prop \fi } \cs_new_protected:Npn \gradbarsCSVColumn #1#2 { \gradbars@validtrue \prop_if_exist:cTF {l__gradbars_csv_#1_prop} {\prop_if_in:cxTF {l__gradbars_csv_#1_prop}{col/\tl_to_str:n {#2}} {\prop_get:cxN {l__gradbars_csv_#1_prop}{col/\tl_to_str:n {#2}}\l_tmpa_tl \int_set:Nn \l__gradbars_csv_col_int {\l_tmpa_tl}} {\gradbarsFail{Unknown~CSV~column:~#2}}} {\gradbarsFail{Unknown~CSV~dataset:~#1}} } \cs_new_protected:Npn \gradbarsCSVGet #1#2#3 { \gradbarsCSVColumn{#1}{#3} \regex_match:nnF {\A[1-9][0-9]*\Z}{#2}{\gradbarsFail{CSV~row~must~be~a~positive~integer}} \ifgradbars@valid \prop_if_in:cxTF {l__gradbars_csv_#1_prop}{row/#2/\int_use:N \l__gradbars_csv_col_int} {\prop_get:cxN {l__gradbars_csv_#1_prop}{row/#2/\int_use:N \l__gradbars_csv_col_int}\l__gradbars_csv_value_tl} {\gradbarsFail{CSV~row~out~of~range}} \fi } \cs_new_protected:Npn \gradbarsCSVNumber #1 { \prop_get:cnN {l__gradbars_csv_#1_prop}{missing}\l_tmpa_tl \clist_set:NV \l__gradbars_csv_missing_clist \l_tmpa_tl \bool_set_false:N \l_tmpa_bool \tl_if_blank:VT \l__gradbars_csv_value_tl {\bool_set_true:N \l_tmpa_bool} \clist_map_inline:Nn \l__gradbars_csv_missing_clist {\str_if_eq:eeT {\l__gradbars_csv_value_tl}{\tl_to_str:n {##1}}{\bool_set_true:N \l_tmpa_bool}} \bool_if:NTF \l_tmpa_bool {\tl_set:Nn \l__gradbars_csv_value_tl {NA}} {\gradbarsCheckNumber{\l__gradbars_csv_value_tl}{CSV~numeric~cell}} } \NewDocumentCommand\gradbarscsvcell{m m m} {\group_begin:\gradbarsCSVGet{#1}{#2}{#3} \ifgradbars@valid\tl_use:N \l__gradbars_csv_value_tl\fi\group_end:} \NewDocumentCommand\gradbarcsv{O{} m m m} {\group_begin:\gradbarsCSVGet{#2}{#3}{#4} \ifgradbars@valid\gradbarsCSVNumber{#2} \ifgradbars@valid\gradbar[#1]{\l__gradbars_csv_value_tl}\fi\fi\group_end:} \cs_new_protected:Npn \gradbarsCSVRange #1#2 { \gradbarsCSVColumn{#1}{#2} \fp_zero:N \l__gradbars_csv_min_fp \fp_zero:N \l__gradbars_csv_max_fp \ifgradbars@valid \int_step_inline:nn {\prop_item:cn {l__gradbars_csv_#1_prop}{rows}} {\prop_get:cxN {l__gradbars_csv_#1_prop}{row/##1/\int_use:N \l__gradbars_csv_col_int}\l__gradbars_csv_value_tl \gradbarsCSVNumber{#1} \ifgradbars@valid \str_if_eq:VnF \l__gradbars_csv_value_tl {NA} {\fp_set:Nn \l__gradbars_csv_min_fp {min(\l__gradbars_csv_min_fp,\l__gradbars_csv_value_tl)} \fp_set:Nn \l__gradbars_csv_max_fp {max(\l__gradbars_csv_max_fp,\l__gradbars_csv_value_tl)}} \fi} % Keep a positive upper limit even for all-zero/all-missing/negative columns. \fp_compare:nNnT {\l__gradbars_csv_max_fp} = {0}{\fp_set:Nn \l__gradbars_csv_max_fp {1}} \fi } \NewDocumentCommand\gradbarscsvstyle{m m m} {\gradbarsCSVRange{#2}{#3} \ifgradbars@valid \cs_set:cpx {gradbars@style@#1} {min=\fp_to_decimal:N \l__gradbars_csv_min_fp,max=\fp_to_decimal:N \l__gradbars_csv_max_fp} \fi} \NewDocumentCommand\gradbarscsvtable{O{} m m m} { \group_begin: \gradbarsCSVRange{#2}{#4} \ifgradbars@valid \tl_set:Nx \l__gradbars_csv_table_tl {\exp_not:N \gradbarssetup{min=\fp_to_decimal:N \l__gradbars_csv_min_fp, max=\fp_to_decimal:N \l__gradbars_csv_max_fp} \exp_not:N \begin{tabular}{@{}ll@{}}\exp_not:N \hline \tl_to_str:n {#3}&\tl_to_str:n {#4}\exp_not:N \\\exp_not:N \hline} \int_step_inline:nn {\prop_item:cn {l__gradbars_csv_#2_prop}{rows}} {\gradbarsCSVGet{#2}{##1}{#3} \ifgradbars@valid \tl_put_right:Nx \l__gradbars_csv_table_tl {\exp_not:V \l__gradbars_csv_value_tl & \exp_not:N \gradbarcsv[\exp_not:n {#1}]{#2}{##1}{\exp_not:n {#4}}\exp_not:N \\} \fi} \tl_put_right:Nn \l__gradbars_csv_table_tl {\hline\end{tabular}} \ifgradbars@valid\tl_use:N \l__gradbars_csv_table_tl\fi \fi \group_end: } \ExplSyntaxOff % Compact comparison shapes and reusable visual presets, v0.0.2. \newif\ifgradbars@compare \newif\ifgradbars@rangemode \newif\ifgradbars@referencemissing \newif\ifgradbars@rangemissing \newif\ifgradbars@outline \def\gradbars@shape{bar} \def\gradbars@reference{0} \def\gradbars@comparecolor{black!20} \def\gradbars@compareratio{.45} \def\gradbars@rangelo{0} \def\gradbars@rangehi{0} \def\gradbars@rangepoint{} \def\gradbars@markersize{2pt} \def\gradbars@stemwidth{.6pt} \def\gradbars@outlinewidth{.4pt} \def\gradbars@rowpadding{0pt} \pgfkeys{/gradbars, shape/.is choice, shape/bar/.code=\def\gradbars@shape{bar}, shape/lollipop/.code=\def\gradbars@shape{lollipop}, compare color/.store in=\gradbars@comparecolor, compare ratio/.store in=\gradbars@compareratio, range point/.store in=\gradbars@rangepoint, marker size/.store in=\gradbars@markersize, stem width/.store in=\gradbars@stemwidth, outline/.is if=gradbars@outline,outline/.default=true, outline width/.store in=\gradbars@outlinewidth, row padding/.store in=\gradbars@rowpadding, preset/.is choice, preset/paper/.style={theme=solid,shape=bar,outline=false, height=5pt,rounded=0pt,track color=black!4,label=outside, font=\small,label gap=.35em,row padding=.5pt,pattern=none,stack patterns={none},print labels=false}, preset/report/.style={theme=solid,shape=bar,outline=false, height=12pt,rounded=3pt,track color=black!6,label=outside, font=\normalsize,label gap=.6em,row padding=2pt,target color=gradbarsInk, threshold colors={lightred,gold,lightgreen},pattern=none,stack patterns={none},print labels=false}, preset/presentation/.style={theme=solid,shape=bar,outline=false, height=18pt,rounded=2pt,label=auto,text color=auto, font=\large,label gap=.7em,row padding=4pt,track color=black!10, pattern=none,stack patterns={none},print labels=false}, preset/outline/.style={theme=gray,shape=bar,outline=true, height=7pt,rounded=0pt,track color=white,left color=black!80, compare color=black!35,label=outside,font=\small, outline width=.35pt,stem width=.4pt,label gap=.4em,row padding=1pt, pattern=none,stack patterns={none},print labels=false} } \def\gradbarsResolveShapeLengths{% \begingroup\font@name \edef\gradbars@next{\endgroup \def\noexpand\gradbars@markersize{\the\dimexpr\gradbars@markersize\relax}% \def\noexpand\gradbars@stemwidth{\the\dimexpr\gradbars@stemwidth\relax}% \def\noexpand\gradbars@outlinewidth{\the\dimexpr\gradbars@outlinewidth\relax}% \def\noexpand\gradbars@rowpadding{\the\dimexpr\gradbars@rowpadding\relax}}% \gradbars@next} \NewDocumentCommand\gradcompare{O{} m m}{% \begingroup\gradbars@comparetrue \def\gradbars@reference{#2}% \gradbar[shape=bar,#1]{#3}% \endgroup} \NewDocumentCommand\gradrange{O{} m m}{% \begingroup\gradbars@rangemodetrue \def\gradbars@rangelo{#2}\def\gradbars@rangehi{#3}% \gradbar[shape=bar,#1]{#3}% \endgroup} \ExplSyntaxOn \cs_new_eq:NN \gradbarsValidateBeforeShapes \gradbarsValidateExtras \cs_set_protected:Npn \gradbarsValidateExtras { \gradbarsValidateBeforeShapes \clist_map_inline:nn {markersize,stemwidth,outlinewidth} {\dim_compare:nNnF {\use:c {gradbars@##1}} > {0pt} {\gradbarsFail{Marker~and~line~sizes~must~be~positive}}} \dim_compare:nNnT {\gradbars@rowpadding} < {0pt} {\gradbarsFail{Row~padding~must~be~nonnegative}} \ifgradbars@stack \str_if_eq:eeF {\gradbars@shape}{bar}{\gradbarsFail{Stacked~bars~require~shape=bar}} \fi \ifgradbars@compare \str_case_e:nnF {\gradbars@shape}{{bar}{}{dumbbell}{}} {\gradbarsFail{Comparison~requires~shape=bar~or~dumbbell}} \gradbarsCheckNumber{\gradbars@compareratio}{compare~ratio} \gradbars@referencemissingfalse \tl_set:Nx \l_tmpa_tl {\gradbars@reference}\tl_trim_spaces:N \l_tmpa_tl \tl_if_empty:NT \l_tmpa_tl {\gradbars@referencemissingtrue} \str_if_eq:VnT \l_tmpa_tl {NA}{\gradbars@referencemissingtrue} \ifgradbars@referencemissing\else\gradbarsCheckNumber{\gradbars@reference}{reference}\fi \ifgradbars@valid \fp_compare:nF {0<\gradbars@compareratio<1}{\gradbarsFail{Compare~ratio~must~lie~strictly~between~0~and~1}} \ifgradbars@referencemissing\else \fp_compare:nNnT {\gradbars@min} = {0} {\fp_compare:nNnT {\gradbars@reference} < {0} {\gradbarsFail{Negative~reference~requires~a~negative~min}}} \gradbarsRange{Reference}{\gradbars@reference} \fi \fi \fi \ifgradbars@rangemode \str_if_eq:eeF {\gradbars@shape}{bar}{\gradbarsFail{Range~requires~shape=bar}} \ifgradbars@error\gradbarsFail{Range~bars~do~not~accept~error~whiskers}\fi \clist_if_empty:NF \l__gradbars_thresholds_clist {\gradbarsFail{Range~bars~do~not~accept~thresholds}} \gradbars@rangemissingfalse \tl_set:Nx \l_tmpa_tl {\gradbars@rangelo}\tl_trim_spaces:N \l_tmpa_tl \tl_if_empty:NT \l_tmpa_tl {\gradbars@rangemissingtrue} \str_if_eq:VnT \l_tmpa_tl {NA}{\gradbars@rangemissingtrue} \ifgradbars@rangemissing \ifgradbars@missing\else\gradbarsFail{Both~range~endpoints~must~be~present~or~missing}\fi \else \ifgradbars@missing\gradbarsFail{Both~range~endpoints~must~be~present~or~missing}\fi \gradbarsCheckNumber{\gradbars@rangelo}{range~lower~endpoint} \fi \tl_if_empty:oF {\gradbars@rangepoint}{\gradbarsCheckNumber{\gradbars@rangepoint}{range~point}} \ifgradbars@valid \ifgradbars@missing \tl_if_empty:oF {\gradbars@rangepoint}{\gradbarsFail{Missing~range~cannot~have~a~point}} \else \fp_compare:nNnT {\gradbars@rangelo} > {\gradbars@rangehi} {\gradbarsFail{Range~lower~endpoint~must~not~exceed~upper}} \fp_compare:nNnT {\gradbars@min} = {0} {\fp_compare:nNnT {\gradbars@rangelo} < {0} {\gradbarsFail{Negative~range~requires~a~negative~min}}} \gradbarsRange{Range~lower~endpoint}{\gradbars@rangelo} \tl_if_empty:oF {\gradbars@rangepoint} {\fp_compare:nF {\gradbars@rangelo<=\gradbars@rangepoint<=\gradbars@rangehi} {\gradbarsFail{Range~point~must~lie~between~endpoints}}} \cs_set:Npx \gradbars@start {\gradbarsPosition{\gradbars@rangelo}} \cs_set:Npx \gradbars@stop {\gradbarsPosition{\gradbars@rangehi}} \fi \fi \else \tl_if_empty:oF {\gradbars@rangepoint}{\gradbarsFail{Range~point~requires~gradrange}} \fi } % Format each endpoint independently using the ordinary number formatter. \cs_new_eq:NN \gradbarsSingleLabel \gradbars@labelcontent \cs_new_protected:Npn \gradbarsFormatEndpoint #1 {\group_begin:\gradbars@missingfalse\def\gradbars@text{} \cs_set:Npx \gradbars@number {\fp_eval:n {#1}} \str_if_eq:eeT {\gradbars@format}{percent} {\cs_set:Npx \gradbars@number {\fp_eval:n {100*(#1)/\gradbars@max}}} \gradbarsSingleLabel\group_end:} \cs_set_protected:Npn \gradbars@labelcontent { \tl_if_empty:oTF {\gradbars@text} {\ifgradbars@compare \gradbarsSingleLabel\,/\, \ifgradbars@referencemissing\gradbars@missingtext \else\gradbarsFormatEndpoint{\gradbars@reference}\fi \else\ifgradbars@rangemode \ifgradbars@missing\gradbars@missingtext \else[\gradbarsFormatEndpoint{\gradbars@rangelo},\, \gradbarsFormatEndpoint{\gradbars@rangehi}]\fi \else\gradbarsSingleLabel\fi\fi} {\gradbars@text} } \cs_new_protected:Npn \gradbarsDrawTrack { \str_if_eq:eeTF {\gradbars@shape}{lollipop} {\draw[draw=\gradbars@track,line~width=\gradbars@stemwidth] (0,.5*\gradbars@height)--(\gradbars@width,.5*\gradbars@height);} {\ifgradbars@outline \path[rounded~corners=\gradbars@radius,fill=\gradbars@track, draw=gradbarsInk!35,line~width=\gradbars@outlinewidth] (0,0) rectangle (\gradbars@width,\gradbars@height); \else \path[rounded~corners=\gradbars@radius,fill=\gradbars@track,draw=none] (0,0) rectangle (\gradbars@width,\gradbars@height); \fi} } \cs_new_protected:Npn \gradbarsDrawDot #1 { \pgfmathsetlengthmacro\gradbars@dotradius{min(\gradbars@markersize,.5*\gradbars@height)} \ifgradbars@outline \path[fill=white,draw=\gradbars@left,line~width=\gradbars@stemwidth] (#1,.5*\gradbars@height) circle[radius=\gradbars@dotradius]; \else \path[fill=\gradbars@left,draw=none] (#1,.5*\gradbars@height) circle[radius=\gradbars@dotradius]; \fi } \cs_new_protected:Npn \gradbarsDrawShape { \str_if_eq:eeTF {\gradbars@shape}{lollipop} {\ifgradbars@missing\else \draw[draw=\gradbars@left,line~width=\gradbars@stemwidth] (\gradbars@xzero,.5*\gradbars@height)--(\gradbars@xend,.5*\gradbars@height); \gradbarsDrawDot{\gradbars@xend} \fi} { \ifgradbars@compare \ifgradbars@referencemissing\else \pgfmathsetlengthmacro\gradbars@xref{\gradbarsPosition{\gradbars@reference}*(\gradbars@width)} \ifgradbars@outline \draw[draw=\gradbars@comparecolor,line~width=\gradbars@outlinewidth] (\gradbars@xzero,0) rectangle (\gradbars@xref,\gradbars@height); \else \path[rounded~corners=\gradbars@radius,fill=\gradbars@comparecolor,draw=none] (\gradbars@xzero,0) rectangle (\gradbars@xref,\gradbars@height); \fi \fi \begin{scope}[yshift={.5*(1-\gradbars@compareratio)*\gradbars@height}] \pgfmathsetlengthmacro\gradbars@height{\gradbars@compareratio*\gradbars@height} \pgfmathsetlengthmacro\gradbars@radius{min(\gradbars@radius,.5*\gradbars@height)} \gradbarsDrawBarBody \end{scope} \else \gradbarsDrawBarBody \ifgradbars@rangemode\ifgradbars@missing\else \draw[draw=\gradbars@left,line~width=\gradbars@stemwidth] (\gradbars@xstart,0)--(\gradbars@xstart,\gradbars@height) (\gradbars@xstop,0)--(\gradbars@xstop,\gradbars@height); \tl_if_empty:oF {\gradbars@rangepoint} {\pgfmathsetlengthmacro\gradbars@xpoint{\gradbarsPosition{\gradbars@rangepoint}*(\gradbars@width)} \pgfmathsetlengthmacro\gradbars@dotradius{min(\gradbars@markersize,.5*\gradbars@height)} \gradbarsDrawMarker{\gradbars@xpoint}{.5*\gradbars@height}{gradbarsInk}{hollow}} \fi\fi \fi } } \ExplSyntaxOff \def\gradbarsDrawBarBody{% \ifdim\gradbars@xstop>\gradbars@xstart\relax \pgfmathsetlengthmacro\gradbars@fillradius{min(\gradbars@radius,.5*(\gradbars@xstop-\gradbars@xstart))}% \begin{scope} \clip[rounded corners=\gradbars@radius] (0,0) rectangle (\gradbars@width,\gradbars@height); \ifgradbars@stack \clip[rounded corners=\gradbars@fillradius] (\gradbars@xstart,0) rectangle (\gradbars@xstop,\gradbars@height); \gradbarsDrawStack \else\ifgradbars@outline \draw[rounded corners=\gradbars@fillradius,draw=\gradbars@left,line width=\gradbars@outlinewidth] (\gradbars@xstart,0) rectangle (\gradbars@xstop,\gradbars@height); \else\ifgradbars@gradient \path[rounded corners=\gradbars@fillradius,shade, left color=\gradbars@left,right color=\gradbars@right] (\gradbars@xstart,0) rectangle (\gradbars@xstop,\gradbars@height); \else \path[rounded corners=\gradbars@fillradius,fill=\gradbars@left,draw=none] (\gradbars@xstart,0) rectangle (\gradbars@xstop,\gradbars@height); \fi\fi\fi \ifgradbars@stack\else\ifgradbars@outline\else \clip[rounded corners=\gradbars@fillradius] (\gradbars@xstart,0) rectangle (\gradbars@xstop,\gradbars@height); \gradbarsPatternRect{0}{\gradbars@xstart}{0}{\gradbars@xstop}{\gradbars@height} \fi \fi \end{scope} \fi } % v0.0.3: comparison, signed compositions, series and semantic palettes. \definecolor{gradbarsOrange}{HTML}{D55E00} \definecolor{gradbarsPurple}{HTML}{AA4499} \definecolor{gradbarsCyan}{HTML}{56B4E9} \definecolor{gradbarsGreen}{HTML}{009E73} \def\gradbars@comparelabel{values} \def\gradbars@stacktotals{net} \def\gradbars@qualitytarget{} \def\gradbars@qualityrange{} \def\gradbars@sparkrange{auto} \def\gradbars@sparkpoints{extrema} \def\gradbars@sparkhigh{gradbarsTeal} \def\gradbars@sparklow{gradbarsOrange} \newif\ifgradbars@spark \pgfkeys{/gradbars, shape/dumbbell/.code=\def\gradbars@shape{dumbbell}, shape/sparkline/.code=\def\gradbars@shape{sparkline}, compare label/.is choice, compare label/values/.code=\def\gradbars@comparelabel{values}, compare label/delta/.code=\def\gradbars@comparelabel{delta}, stack totals/.is choice, stack totals/net/.code=\def\gradbars@stacktotals{net}, stack totals/separate/.code=\def\gradbars@stacktotals{separate}, better/target/.code=\def\gradbars@better{target}, better/interval/.code=\def\gradbars@better{interval}, quality target/.store in=\gradbars@qualitytarget, quality range/.store in=\gradbars@qualityrange, spark range/.is choice, spark range/auto/.code=\def\gradbars@sparkrange{auto}, spark range/fixed/.code=\def\gradbars@sparkrange{fixed}, spark points/.is choice, spark points/extrema/.code=\def\gradbars@sparkpoints{extrema}, spark points/all/.code=\def\gradbars@sparkpoints{all}, spark points/last/.code=\def\gradbars@sparkpoints{last}, spark points/none/.code=\def\gradbars@sparkpoints{none}, spark high color/.store in=\gradbars@sparkhigh, spark low color/.store in=\gradbars@sparklow, palette/.is choice, palette/categorical/.style={stack colors={gradbarsBlue,gradbarsOrange,gradbarsGreen,gradbarsPurple,gradbarsCyan,gold}, stack patterns={none},compare color=gradbarsOrange,negative color=gradbarsOrange}, palette/sequential/.style={stack colors={gradbarsBlue!20,gradbarsBlue!40,gradbarsBlue!60,gradbarsBlue!80,gradbarsBlue}, stack patterns={none}}, palette/diverging/.style={stack colors={gradbarsOrange!85,gradbarsOrange!40,black!12,gradbarsTeal!40,gradbarsTeal!85}, threshold colors={gradbarsOrange,gold,gradbarsTeal},negative color=gradbarsOrange, compare color=gradbarsOrange,left color=gradbarsTeal,right color=gradbarsTeal!35,stack patterns={none}}, palette/mono/.style={print,stack colors={white,black!10,black!20}, stack patterns={diagonal,dots,crosshatch},compare color=black!45, spark high color=black,spark low color=black}, } \NewDocumentCommand\graddumbbell{O{} m m}{% \gradcompare[#1,shape=dumbbell]{#2}{#3}} \ExplSyntaxOn \fp_new:N \l__gradbars_positive_fp \fp_new:N \l__gradbars_negative_fp \cs_new_protected:Npn \gradbarsStackReset {\fp_zero:N \l__gradbars_positive_fp\fp_zero:N \l__gradbars_negative_fp} \cs_new_protected:Npn \gradbarsStackStep #1 { \fp_compare:nNnTF {#1} < {0} {\fp_set_eq:NN \l__gradbars_sum_fp \l__gradbars_negative_fp \fp_add:Nn \l__gradbars_negative_fp {#1} \fp_set_eq:NN \l__gradbars_before_fp \l__gradbars_negative_fp} {\fp_set_eq:NN \l__gradbars_before_fp \l__gradbars_positive_fp \fp_add:Nn \l__gradbars_positive_fp {#1} \fp_set_eq:NN \l__gradbars_sum_fp \l__gradbars_positive_fp} } % Category identity is scoped and keyed by literal names, independent of order. \prop_new:N \l__gradbars_category_colors_prop \prop_new:N \l__gradbars_category_patterns_prop \NewDocumentCommand\gradbarscategory{m m m} { \tl_if_blank:nTF {#1}{\gradbarsFail{Category~name~must~not~be~empty}} {\prop_if_in:NnTF \c__gradbars_patterns_prop {#3} {\prop_put:Nnn \l__gradbars_category_colors_prop {#1}{#2} \prop_put:Nnn \l__gradbars_category_patterns_prop {#1}{#3}} {\gradbarsFail{Unknown~category~pattern}}} } \cs_new_protected:Npn \gradbarsCategoryColor #1 { \cs_set:Npx \gradbars@segmentcolor {\clist_item:Nn \l__gradbars_stackcolors_clist {1+\int_mod:nn {#1-1}{\clist_count:N \l__gradbars_stackcolors_clist}}} \tl_set:Nx \l_tmpa_tl {\clist_item:Nn \l__gradbars_names_clist {#1}} \ifgradbars@print\else \prop_get:NVNT \l__gradbars_category_colors_prop \l_tmpa_tl \l_tmpb_tl {\cs_set:Npx \gradbars@segmentcolor {\exp_not:V \l_tmpb_tl}} \fi } \cs_new_protected:Npn \gradbarsCategoryPattern #1 { \int_compare:nNnT {#1} > {0} {\tl_set:Nx \l_tmpa_tl {\clist_item:Nn \l__gradbars_names_clist {#1}} \prop_get:NVNT \l__gradbars_category_patterns_prop \l_tmpa_tl \l_tmpb_tl {\tl_set_eq:NN \l__gradbars_pattern_tl \l_tmpb_tl}} } \fp_new:N \l__gradbars_distance_fp \clist_new:N \l__gradbars_quality_clist \cs_new_protected:Npn \gradbarsQuality { \str_case_e:nn {\gradbars@better} {{target}{\gradbarsCheckNumber{\gradbars@qualitytarget}{quality~target}} {interval}{\clist_set:Nx \l__gradbars_quality_clist {\gradbars@qualityrange} \tl_set:Nx \l_tmpa_tl {\gradbars@qualityrange} \regex_match:nVT {\A\s*,|,\s*,|,\s*\Z} \l_tmpa_tl {\gradbarsFail{Quality~range~requires~two~endpoints}} \int_compare:nNnF {\clist_count:N \l__gradbars_quality_clist} = {2} {\gradbarsFail{Quality~range~requires~two~endpoints}} \clist_map_inline:Nn \l__gradbars_quality_clist {\gradbarsCheckNumber{##1}{quality~endpoint}}}} \clist_if_empty:NT \l__gradbars_thresholds_clist {\gradbarsFail{Target~and~interval~quality~require~distance~thresholds}} \ifgradbars@stack\gradbarsFail{Stack~does~not~support~quality~evaluation}\fi \ifgradbars@rangemode\gradbarsFail{Range~does~not~support~quality~evaluation}\fi \ifgradbars@valid \fp_compare:nNnT {\clist_item:Nn \l__gradbars_thresholds_clist {1}} < {0} {\gradbarsFail{Distance~thresholds~must~be~nonnegative}} \str_if_eq:eeTF {\gradbars@better}{target} {\fp_set:Nn \l__gradbars_distance_fp {abs(\gradbars@value-\gradbars@qualitytarget)}} {\fp_compare:nNnT {\clist_item:Nn \l__gradbars_quality_clist {1}} > {\clist_item:Nn \l__gradbars_quality_clist {2}} {\gradbarsFail{Quality~range~must~be~ordered}} \fp_set:Nn \l__gradbars_distance_fp {max(0,\clist_item:Nn \l__gradbars_quality_clist {1}-\gradbars@value, \gradbars@value-\clist_item:Nn \l__gradbars_quality_clist {2})}} \int_set:Nn \l_tmpa_int {1} \fp_compare:nT {\l__gradbars_distance_fp <= \clist_item:Nn \l__gradbars_thresholds_clist {2}} {\int_set:Nn \l_tmpa_int {2}} \fp_compare:nT {\l__gradbars_distance_fp <= \clist_item:Nn \l__gradbars_thresholds_clist {1}} {\int_set:Nn \l_tmpa_int {3}} \cs_set:Npx \gradbars@left {\clist_item:Nn \l__gradbars_colors_clist {\l_tmpa_int}} \gradbars@gradientfalse \fi } \cs_new_eq:NN \gradbarsValidateBeforeThree \gradbarsValidateExtras \cs_set_protected:Npn \gradbarsValidateExtras { \gradbarsValidateBeforeThree \str_case_e:nn {\gradbars@better}{{target}{\gradbarsQuality}{interval}{\gradbarsQuality}} \str_if_eq:eeT {\gradbars@shape}{dumbbell} {\ifgradbars@compare\else\gradbarsFail{Dumbbell~requires~graddumbbell}\fi} \str_if_eq:eeT {\gradbars@shape}{sparkline} {\ifgradbars@spark\else\gradbarsFail{Sparkline~requires~gradspark}\fi} \ifgradbars@spark \str_if_eq:eeF {\gradbars@shape}{sparkline}{\gradbarsFail{Spark~requires~shape=sparkline}} \ifgradbars@error\gradbarsFail{Spark~does~not~support~error~whiskers}\fi \tl_if_empty:oF {\gradbars@target}{\gradbarsFail{Spark~does~not~support~bar~targets}} \tl_if_empty:oF {\gradbars@band}{\gradbarsFail{Spark~does~not~support~bar~bands}} \tl_if_empty:oF {\gradbars@thresholds}{\gradbarsFail{Spark~does~not~support~thresholds}} \gradbarsValidateSpark \fi } \cs_new_eq:NN \gradbarsLabelBeforeThree \gradbars@labelcontent \cs_set_protected:Npn \gradbars@labelcontent { \tl_if_empty:oTF {\gradbars@text} {\ifgradbars@compare \str_if_eq:eeTF {\gradbars@comparelabel}{delta} {\ifgradbars@missing\gradbars@missingtext\else \ifgradbars@referencemissing\gradbars@missingtext\else $\Delta$\,\gradbarsFormatEndpoint{\gradbars@value-\gradbars@reference}\fi\fi} {\gradbarsLabelBeforeThree} \else\ifgradbars@stack \str_if_eq:eeTF {\gradbars@stacktotals}{separate} {+\gradbarsFormatEndpoint{\gradbars@positive}\,/\,\gradbarsFormatEndpoint{\gradbars@negative}} {\gradbarsLabelBeforeThree} \else\gradbarsLabelBeforeThree\fi\fi} {\gradbars@text} } \cs_new_eq:NN \gradbarsShapeBeforeThree \gradbarsDrawShape \cs_set_protected:Npn \gradbarsDrawShape { \str_case_e:nnF {\gradbars@shape} {{dumbbell}{\gradbarsDrawDumbbell}{sparkline}{\gradbarsDrawSpark}} {\gradbarsShapeBeforeThree} } \cs_new_protected:Npn \gradbarsDrawDumbbell { \gradbarsMarkerBounds \ifgradbars@referencemissing\else \pgfmathsetlengthmacro\gradbars@xref{\gradbarsPosition{\gradbars@reference}*\gradbars@width} \ifgradbars@missing\else \draw[draw=\gradbars@left,line~width=\gradbars@stemwidth] (\gradbars@xref,.5*\gradbars@height)--(\gradbars@xend,.5*\gradbars@height); \fi \group_begin:\let\gradbars@left\gradbars@comparecolor \gradbars@outlinetrue\gradbarsDrawDot{\gradbars@xref}\group_end: \fi \ifgradbars@missing\else\gradbarsDrawDot{\gradbars@xend}\fi } \seq_new:N \l__gradbars_series_seq \seq_new:N \l__gradbars_series_clean_seq \fp_new:N \l__gradbars_series_min_fp \fp_new:N \l__gradbars_series_max_fp \fp_new:N \l__gradbars_series_low_fp \fp_new:N \l__gradbars_series_high_fp \bool_new:N \l__gradbars_series_any_bool \bool_new:N \l__gradbars_series_prev_bool \bool_new:N \l__gradbars_series_mark_bool \int_new:N \l__gradbars_series_index_int \cs_new_protected:Npn \gradbarsParseSpark #1 { \fp_zero:N \l__gradbars_series_min_fp \fp_zero:N \l__gradbars_series_max_fp \seq_set_split:Nnn \l__gradbars_series_seq {,}{#1} \seq_clear:N \l__gradbars_series_clean_seq \bool_set_false:N \l__gradbars_series_any_bool \seq_map_inline:Nn \l__gradbars_series_seq {\tl_set:Nx \l_tmpa_tl {##1}\tl_trim_spaces:N \l_tmpa_tl \tl_if_empty:NT \l_tmpa_tl {\tl_set:Nn \l_tmpa_tl {NA}} \str_if_eq:VnF \l_tmpa_tl {NA} {\gradbarsCheckNumber{\l_tmpa_tl}{spark~observation} \ifgradbars@valid \bool_if:NTF \l__gradbars_series_any_bool {\fp_set:Nn \l__gradbars_series_min_fp {min(\l__gradbars_series_min_fp,\l_tmpa_tl)} \fp_set:Nn \l__gradbars_series_max_fp {max(\l__gradbars_series_max_fp,\l_tmpa_tl)}} {\fp_set:Nn \l__gradbars_series_min_fp {\l_tmpa_tl} \fp_set:Nn \l__gradbars_series_max_fp {\l_tmpa_tl} \bool_set_true:N \l__gradbars_series_any_bool} \fi} \seq_put_right:NV \l__gradbars_series_clean_seq \l_tmpa_tl} \seq_set_eq:NN \l__gradbars_series_seq \l__gradbars_series_clean_seq \cs_set:Npx \gradbars@sparklast {\seq_item:Nn \l__gradbars_series_seq {-1}} } \NewDocumentCommand\gradspark{O{} m} {\group_begin:\gradbars@validtrue\gradbarsParseSpark{#2} \ifgradbars@valid \gradbars@sparktrue \gradbar[height=4ex,#1,shape=sparkline]{\gradbars@sparklast} \fi\group_end:} \cs_new_protected:Npn \gradbarsValidateSpark { \str_if_eq:eeTF {\gradbars@sparkrange}{fixed} {\fp_set:Nn \l__gradbars_series_low_fp {\gradbars@min} \fp_set:Nn \l__gradbars_series_high_fp {\gradbars@max} \seq_map_inline:Nn \l__gradbars_series_seq {\str_if_eq:nnF {##1}{NA}{\gradbarsRange{Spark~observation}{##1}}}} {\fp_set_eq:NN \l__gradbars_series_low_fp \l__gradbars_series_min_fp \fp_set_eq:NN \l__gradbars_series_high_fp \l__gradbars_series_max_fp} } \cs_new_protected:Npn \gradbarsDrawSpark { \gradbarsMarkerBounds \bool_set_false:N \l__gradbars_series_prev_bool \int_zero:N \l__gradbars_series_index_int \seq_map_inline:Nn \l__gradbars_series_seq {\int_incr:N \l__gradbars_series_index_int \str_if_eq:nnTF {##1}{NA} {\bool_set_false:N \l__gradbars_series_prev_bool} {\pgfmathsetlengthmacro\gradbars@sparkx {\fp_eval:n {\seq_count:N \l__gradbars_series_seq=1 ? .5 : (\l__gradbars_series_index_int-1)/max(1,\seq_count:N \l__gradbars_series_seq-1)}*\gradbars@width} \fp_compare:nNnTF {\l__gradbars_series_low_fp} = {\l__gradbars_series_high_fp} {\pgfmathsetlengthmacro\gradbars@sparky{.5*\gradbars@height}} {\pgfmathsetlengthmacro\gradbars@sparky {\fp_eval:n {max(0,min(1,(##1-\l__gradbars_series_low_fp)/ (\l__gradbars_series_high_fp-\l__gradbars_series_low_fp)))}*\gradbars@height}} \bool_if:NT \l__gradbars_series_prev_bool {\draw[draw=\gradbars@left,line~width=\gradbars@stemwidth] (\gradbars@sparkprevx,\gradbars@sparkprevy)--(\gradbars@sparkx,\gradbars@sparky);} \bool_set_false:N \l__gradbars_series_mark_bool \let\gradbars@pointcolor\gradbars@left \str_case_e:nn {\gradbars@sparkpoints} {{all}{\bool_set_true:N \l__gradbars_series_mark_bool} {extrema}{\fp_compare:nNnT {##1} = {\l__gradbars_series_min_fp} {\bool_set_true:N \l__gradbars_series_mark_bool\let\gradbars@pointcolor\gradbars@sparklow} \fp_compare:nNnT {##1} = {\l__gradbars_series_max_fp} {\bool_set_true:N \l__gradbars_series_mark_bool\let\gradbars@pointcolor\gradbars@sparkhigh}}} \str_if_eq:eeF {\gradbars@sparkpoints}{none} {\int_compare:nNnT {\l__gradbars_series_index_int} = {\seq_count:N \l__gradbars_series_seq} {\bool_set_true:N \l__gradbars_series_mark_bool}} \bool_if:NT \l__gradbars_series_mark_bool {\gradbarsDrawMarker{\gradbars@sparkx}{\gradbars@sparky} {\gradbars@pointcolor}{\gradbars@markerfill}} \let\gradbars@sparkprevx\gradbars@sparkx\let\gradbars@sparkprevy\gradbars@sparky \bool_set_true:N \l__gradbars_series_prev_bool}} } % Auto series scaling applies to the y axis; it must not inherit bar clipping. \cs_new_eq:NN \gradbarsValidateBeforeSpark \gradbarsValidate \cs_set_protected:Npn \gradbarsValidate { \ifgradbars@spark \str_if_eq:eeT {\gradbars@sparkrange}{auto} {\cs_set:Npx \gradbars@min {\fp_eval:n {min(0,\l__gradbars_series_min_fp)}} \cs_set:Npx \gradbars@max {\fp_eval:n {max(1,\l__gradbars_series_max_fp)}} \str_if_eq:eeT {\gradbars@format}{percent} {\gradbarsFail{Auto~spark~range~does~not~support~percent~format}}} \str_if_eq:eeF {\gradbars@label}{none}{\def\gradbars@label{outside}} \fi \let\gradbars@sparkbasecolor\gradbars@left \gradbarsValidateBeforeSpark \ifgradbars@spark\let\gradbars@left\gradbars@sparkbasecolor\fi } \cs_new_protected:Npn \gradbarsMarkerBounds {\path (-\gradbars@markersize,-\gradbars@markersize) rectangle ([xshift=\gradbars@markersize,yshift=\gradbars@markersize]\gradbars@width,\gradbars@height);} \cs_new_eq:NN \gradbarsTrackBeforeThree \gradbarsDrawTrack \cs_set_protected:Npn \gradbarsDrawTrack {\group_begin: \str_if_eq:eeT {\gradbars@shape}{dumbbell}{\def\gradbars@shape{lollipop}} \gradbarsTrackBeforeThree\group_end:} \ExplSyntaxOff % Reference records: {value/color/line style/name}, names may be empty. \def\gradbars@references{} \def\gradbars@bulletbands{} \newif\ifgradbars@bullet \pgfkeys{/gradbars/.cd, references/.store in=\gradbars@references, bullet bands/.store in=\gradbars@bulletbands} \NewDocumentCommand\gradbullet{O{} m}{% \begingroup\gradbars@bullettrue \gradbar[height=12pt,fill=solid,label=outside,#1,shape=bar]{#2}% \endgroup} \ExplSyntaxOn \seq_new:N \l__gradbars_record_seq \clist_new:N \l__gradbars_refs_clist \clist_new:N \l__gradbars_bands_clist \fp_new:N \l__gradbars_band_start_fp \tl_new:N \l__gradbars_record_color_tl \tl_new:N \l__gradbars_record_style_tl \tl_new:N \l__gradbars_record_name_tl \cs_new_protected:Npn \gradbarsRecord #1#2 {\seq_set_split:Nnn \l__gradbars_record_seq {/}{#1} \int_compare:nNnF {\seq_count:N \l__gradbars_record_seq} = {#2} {\gradbarsFail{Wrong~number~of~fields~in~reference,~band~or~interval~record}}} \cs_new_eq:NN \gradbarsValidateBeforeReferences \gradbarsValidateExtras \cs_set_protected:Npn \gradbarsValidateExtras { \gradbarsValidateBeforeReferences \clist_set:No \l__gradbars_refs_clist {\gradbars@references} \clist_set:No \l__gradbars_bands_clist {\gradbars@bulletbands} \ifgradbars@spark \clist_if_empty:NF \l__gradbars_refs_clist {\gradbarsFail{Spark~does~not~support~references}} \fi \clist_map_inline:Nn \l__gradbars_refs_clist {\gradbarsRecord{##1}{4} \ifgradbars@valid \gradbarsCheckNumber{\seq_item:Nn \l__gradbars_record_seq {1}}{reference} \ifgradbars@valid \fp_compare:nT {\seq_item:Nn \l__gradbars_record_seq {1}<\gradbars@min || \seq_item:Nn \l__gradbars_record_seq {1}>\gradbars@max} {\gradbarsFail{Reference~must~lie~within~range}} \tl_set:Nx \l_tmpa_tl {\seq_item:Nn \l__gradbars_record_seq {3}} \exp_args:NnV \clist_if_in:nnF {solid,dashed,dotted} \l_tmpa_tl {\gradbarsFail{Reference~line~style~must~be~solid,~dashed~or~dotted}} \fi \fi} \ifgradbars@bullet \clist_if_empty:NT \l__gradbars_bands_clist {\gradbarsFail{Bullet~requires~explicit~bullet~bands}} \else \clist_if_empty:NF \l__gradbars_bands_clist {\gradbarsFail{Bullet~bands~require~gradbullet}} \fi \ifgradbars@valid \fp_set:Nn \l__gradbars_band_start_fp {\gradbars@min} \clist_map_inline:Nn \l__gradbars_bands_clist {\gradbarsRecord{##1}{2} \ifgradbars@valid \gradbarsCheckNumber{\seq_item:Nn \l__gradbars_record_seq {1}}{band~endpoint} \ifgradbars@valid \fp_compare:nT {\seq_item:Nn \l__gradbars_record_seq {1}<=\l__gradbars_band_start_fp || \seq_item:Nn \l__gradbars_record_seq {1}>\gradbars@max} {\gradbarsFail{Bullet~endpoints~must~increase~within~range}} \fp_set:Nn \l__gradbars_band_start_fp {\seq_item:Nn \l__gradbars_record_seq {1}} \fi \fi} \ifgradbars@bullet\ifgradbars@valid \fp_compare:nNnF {\l__gradbars_band_start_fp} = {\gradbars@max} {\gradbarsFail{Last~bullet~endpoint~must~equal~max}} \fi\fi \fi } \cs_new_protected:Npn \gradbarsDrawReferences {\int_zero:N \l_tmpa_int \clist_map_inline:Nn \l__gradbars_refs_clist {\seq_set_split:Nnn \l__gradbars_record_seq {/}{##1} \tl_set:Nx \l__gradbars_record_color_tl {\seq_item:Nn \l__gradbars_record_seq {2}} \tl_set:Nx \l__gradbars_record_style_tl {\seq_item:Nn \l__gradbars_record_seq {3}} \tl_set:Nx \l__gradbars_record_name_tl {\seq_item:Nn \l__gradbars_record_seq {4}} \pgfmathsetlengthmacro\gradbars@rx {\gradbarsPosition{\seq_item:Nn \l__gradbars_record_seq {1}}*(\gradbars@width)} \draw[draw=\l__gradbars_record_color_tl,line~width=.6pt, \l__gradbars_record_style_tl] (\gradbars@rx,-1pt)--(\gradbars@rx,{\gradbars@height+1pt}); \tl_if_blank:VF \l__gradbars_record_name_tl {\node[anchor=south,inner~sep=1pt,font=\scriptsize, text=\l__gradbars_record_color_tl] at (\gradbars@rx,{\gradbars@height+2pt+10pt*\int_mod:nn{\l_tmpa_int}{2}}) {\l__gradbars_record_name_tl};} \int_incr:N \l_tmpa_int}} \cs_new_eq:NN \gradbarsBandBeforeBullet \gradbarsDrawBand \cs_set_protected:Npn \gradbarsDrawBand {\ifgradbars@bullet \fp_set:Nn \l__gradbars_band_start_fp {\gradbars@min} \clist_map_inline:Nn \l__gradbars_bands_clist {\seq_set_split:Nnn \l__gradbars_record_seq {/}{##1} \tl_set:Nx \l__gradbars_record_color_tl {\seq_item:Nn \l__gradbars_record_seq {2}} \pgfmathsetlengthmacro\gradbars@bx {\gradbarsPosition{\l__gradbars_band_start_fp}*(\gradbars@width)} \pgfmathsetlengthmacro\gradbars@ex {\gradbarsPosition{\seq_item:Nn \l__gradbars_record_seq {1}}*(\gradbars@width)} \path[fill=\l__gradbars_record_color_tl,draw=none] (\gradbars@bx,0) rectangle (\gradbars@ex,\gradbars@height); \fp_set:Nn \l__gradbars_band_start_fp {\seq_item:Nn \l__gradbars_record_seq {1}}} \fi\gradbarsBandBeforeBullet} \cs_new_eq:NN \gradbarsShapeBeforeBullet \gradbarsDrawShape \cs_set_protected:Npn \gradbarsDrawShape {\ifgradbars@bullet \begin{scope}[yshift=.3*\gradbars@height,yscale=.4] \gradbarsShapeBeforeBullet \end{scope} \else\gradbarsShapeBeforeBullet\fi} % Each interval record has name / lower / point (or NA) / upper / color. \tl_new:N \l__gradbars_interval_rows_tl \cs_new_protected:Npn \gradbarsIntervalRow #1#2#3#4#5 {#1 & \gradrange[color=#5,range~point=#3]{#2}{#4}\\} \NewDocumentCommand\gradintervals{O{} m} {\group_begin: \pgfkeys{/gradbars,#1} \gradbars@validtrue \tl_clear:N \l__gradbars_interval_rows_tl \clist_if_empty:nT {#2}{\gradbarsFail{Interval~comparison~requires~records}} \clist_map_inline:nn {#2} {\gradbarsRecord{##1}{5} \ifgradbars@valid \tl_set:Nx \l__gradbars_record_name_tl {\seq_item:Nn \l__gradbars_record_seq {1}} \tl_set:Nx \l_tmpa_tl {\seq_item:Nn \l__gradbars_record_seq {3}} \str_if_eq:VnT \l_tmpa_tl {NA}{\tl_clear:N \l_tmpa_tl} \tl_put_right:Nx \l__gradbars_interval_rows_tl {\exp_not:N \gradbarsIntervalRow {\exp_not:V \l__gradbars_record_name_tl} {\seq_item:Nn \l__gradbars_record_seq {2}} {\exp_not:V \l_tmpa_tl} {\seq_item:Nn \l__gradbars_record_seq {4}} {\seq_item:Nn \l__gradbars_record_seq {5}}} \fi} \ifgradbars@valid \begin{tabular}{@{}l@{\hspace{.7em}}l@{}} \l__gradbars_interval_rows_tl \end{tabular} \fi\group_end:} \ExplSyntaxOff % v0.0.4: overflow indicators, comparison annotations and marker shapes. \def\gradbars@overflowmark{none} \def\gradbars@markershape{circle} \def\gradbars@markerfill{solid} \def\gradbars@change{none} \pgfkeys{/gradbars/.cd, overflow mark/.is choice, overflow mark/none/.code=\def\gradbars@overflowmark{none}, overflow mark/arrow/.code=\def\gradbars@overflowmark{arrow}, overflow mark/slash/.code=\def\gradbars@overflowmark{slash}, marker shape/.is choice, marker shape/circle/.code=\def\gradbars@markershape{circle}, marker shape/square/.code=\def\gradbars@markershape{square}, marker shape/diamond/.code=\def\gradbars@markershape{diamond}, marker shape/triangle/.code=\def\gradbars@markershape{triangle}, marker fill/.is choice, marker fill/solid/.code=\def\gradbars@markerfill{solid}, marker fill/hollow/.code=\def\gradbars@markerfill{hollow}, compare annotation/.is choice, compare annotation/none/.code=\def\gradbars@change{none}, compare annotation/arrow/.code=\def\gradbars@change{arrow}, compare annotation/bracket/.code=\def\gradbars@change{bracket}, compare label/percent/.code=\def\gradbars@comparelabel{percent}} \ExplSyntaxOn \cs_new_protected:Npn \gradbarsDrawMarker #1#2#3#4 {\group_begin: \tl_set:Nn \l_tmpa_tl {#3} \str_if_eq:eeT {#4}{hollow}{\tl_set:Nn \l_tmpa_tl {white}} \begin{scope}[shift={(#1,#2)}] \tikzset{gradbars~mark/.style={draw=#3,fill=\l_tmpa_tl,line~width=\gradbars@stemwidth}} \str_case_e:nn {\gradbars@markershape} {{circle}{\path[gradbars~mark] (0,0) circle[radius=\gradbars@markersize];} {square}{\path[gradbars~mark] (-\gradbars@markersize,-\gradbars@markersize) rectangle (\gradbars@markersize,\gradbars@markersize);} {diamond}{\path[gradbars~mark] (0,\gradbars@markersize)--(\gradbars@markersize,0) --(0,-\gradbars@markersize)--(-\gradbars@markersize,0)--cycle;} {triangle}{\path[gradbars~mark] (0,\gradbars@markersize) --(\gradbars@markersize,-\gradbars@markersize)--(-\gradbars@markersize,-\gradbars@markersize)--cycle;}} \end{scope}\group_end:} \cs_set_protected:Npn \gradbarsDrawDot #1 {\ifgradbars@outline \gradbarsDrawMarker{#1}{.5*\gradbars@height}{\gradbars@left}{hollow} \else\gradbarsDrawMarker{#1}{.5*\gradbars@height}{\gradbars@left}{\gradbars@markerfill}\fi} \fp_new:N \l__gradbars_raw_low_fp \fp_new:N \l__gradbars_raw_high_fp \bool_new:N \l__gradbars_overflow_known_bool \cs_new_protected:Npn \gradbarsOverflowSide #1#2 {\begin{scope}[shift={(#1,.5*\gradbars@height)},xscale=#2] \str_if_eq:eeTF {\gradbars@overflowmark}{arrow} {\draw[draw=gradbarsInk,line~width=.7pt](-2pt,-2pt)--(1pt,0)--(-2pt,2pt);} {\draw[draw=gradbarsInk,line~width=.7pt](-2pt,-2pt)--(0,2pt) (0,-2pt)--(2pt,2pt);} \end{scope}} \cs_new_protected:Npn \gradbarsDrawOverflow {\str_if_eq:eeF {\gradbars@overflowmark}{none} {\bool_set_true:N \l__gradbars_overflow_known_bool \ifgradbars@missing\bool_set_false:N \l__gradbars_overflow_known_bool\fi \ifgradbars@compare\ifgradbars@referencemissing\else \bool_set_true:N \l__gradbars_overflow_known_bool\fi\fi \ifgradbars@spark\bool_set_eq:NN \l__gradbars_overflow_known_bool \l__gradbars_series_any_bool\fi \bool_if:NT \l__gradbars_overflow_known_bool { \fp_set:Nn \l__gradbars_raw_low_fp {\gradbars@value} \fp_set_eq:NN \l__gradbars_raw_high_fp \l__gradbars_raw_low_fp \ifgradbars@stack \fp_set:Nn \l__gradbars_raw_low_fp {\gradbars@negative} \fp_set:Nn \l__gradbars_raw_high_fp {\gradbars@positive} \fi \ifgradbars@rangemode \fp_set:Nn \l__gradbars_raw_low_fp {\gradbars@rangelo} \fp_set:Nn \l__gradbars_raw_high_fp {\gradbars@rangehi} \fi \ifgradbars@compare\ifgradbars@referencemissing\else \fp_set:Nn \l__gradbars_raw_low_fp {min(\gradbars@value,\gradbars@reference)} \fp_set:Nn \l__gradbars_raw_high_fp {max(\gradbars@value,\gradbars@reference)} \ifgradbars@missing \fp_set:Nn \l__gradbars_raw_low_fp {\gradbars@reference} \fp_set_eq:NN \l__gradbars_raw_high_fp \l__gradbars_raw_low_fp \fi \fi\fi \ifgradbars@error \fp_set:Nn \l__gradbars_raw_low_fp {min(\l__gradbars_raw_low_fp,\gradbars@value-\gradbars@errorminus)} \fp_set:Nn \l__gradbars_raw_high_fp {max(\l__gradbars_raw_high_fp,\gradbars@value+\gradbars@errorplus)} \fi \ifgradbars@spark \fp_set_eq:NN \l__gradbars_raw_low_fp \l__gradbars_series_min_fp \fp_set_eq:NN \l__gradbars_raw_high_fp \l__gradbars_series_max_fp \fi \fp_compare:nNnT {\l__gradbars_raw_low_fp} < {\gradbars@min}{\gradbarsOverflowSide{0pt}{-1}} \fp_compare:nNnT {\l__gradbars_raw_high_fp} > {\gradbars@max}{\gradbarsOverflowSide{\gradbars@width}{1}} }}} \cs_new_protected:Npn \gradbarsChangeLabel {\group_begin: \ifgradbars@missing\gradbars@missingtext\else \ifgradbars@referencemissing\gradbars@missingtext\else \str_if_eq:eeTF {\gradbars@comparelabel}{percent} {\fp_compare:nNnTF {\gradbars@reference} = {0} {\gradbars@missingtext} {\def\gradbars@format{value}\def\gradbars@unit{\%} \fp_compare:nNnT {\gradbars@value-\gradbars@reference} > {0}{+} \gradbarsFormatEndpoint{100*(\gradbars@value-\gradbars@reference)/abs(\gradbars@reference)}}} {$\Delta$\,\def\gradbars@format{value} \fp_compare:nNnT {\gradbars@value-\gradbars@reference} > {0}{+} \gradbarsFormatEndpoint{\gradbars@value-\gradbars@reference}} \fi\fi\group_end:} \cs_new_eq:NN \gradbarsLabelBeforeFour \gradbars@labelcontent \cs_set_protected:Npn \gradbars@labelcontent {\ifgradbars@compare \tl_if_empty:oTF {\gradbars@text} {\str_if_eq:eeTF {\gradbars@comparelabel}{percent} {\gradbarsChangeLabel}{\gradbarsLabelBeforeFour}} {\gradbarsLabelBeforeFour} \else\gradbarsLabelBeforeFour\fi} \cs_new_protected:Npn \gradbarsDrawChange {\ifgradbars@compare\ifgradbars@missing\else\ifgradbars@referencemissing\else \str_if_eq:eeF {\gradbars@change}{none} {\pgfmathsetlengthmacro\gradbars@cx{\gradbarsPosition{\gradbars@reference}*\gradbars@width} \begin{scope}[yshift={\gradbars@height+5pt}] \str_if_eq:eeTF {\gradbars@change}{arrow} {\dim_compare:nNnF {\gradbars@xend} = {\gradbars@cx} {\draw[->,draw=gradbarsInk,line~width=.5pt](\gradbars@cx,0)--(\gradbars@xend,0);}} {\draw[draw=gradbarsInk,line~width=.5pt] (\gradbars@cx,-2pt)--(\gradbars@cx,0)--(\gradbars@xend,0)--(\gradbars@xend,-2pt);} \node[anchor=south,inner~sep=1pt,font=\scriptsize,text=gradbarsInk] at ({.5*(\gradbars@cx+\gradbars@xend)},1pt){\gradbarsChangeLabel}; \end{scope}} \fi\fi\fi} \ExplSyntaxOff % gradtable buffers declarations and rows; no alignment tokens in user data. \ExplSyntaxOn \seq_new:N \l__gradtable_columns_seq \seq_new:N \l__gradtable_rows_seq \prop_new:N \l__gradtable_titles_prop \prop_new:N \l__gradtable_types_prop \prop_new:N \l__gradtable_options_prop \prop_new:N \l__gradtable_widths_prop \prop_new:N \l__gradtable_align_prop \prop_new:N \l__gradtable_headalign_prop \prop_new:N \l__gradtable_valign_prop \prop_new:N \l__gradtable_colwidth_prop \tl_new:N \l__gradtable_align_tl \tl_new:N \l__gradtable_headalign_tl \tl_new:N \l__gradtable_valign_tl \tl_new:N \l__gradtable_default_align_tl \tl_new:N \l__gradtable_default_headalign_tl \tl_new:N \l__gradtable_default_valign_tl \tl_new:N \l__gradtable_rules_tl \tl_new:N \l__gradtable_stretch_tl \tl_new:N \l__gradtable_header_spec_tl \tl_new:N \l__gradtable_header_color_tl \tl_new:N \l__gradtable_rule_color_tl \dim_new:N \l__gradtable_colwidth_dim \dim_new:N \l__gradtable_sep_dim \dim_new:N \l__gradtable_padding_dim \tl_new:N \l__gradtable_preset_tl \tl_new:N \l__gradtable_type_tl \tl_new:N \l__gradtable_options_tl \tl_new:N \l__gradtable_id_tl \tl_new:N \l__gradtable_preamble_tl \tl_new:N \l__gradtable_body_tl \clist_new:N \l__gradtable_cells_clist \seq_new:N \l__gradtable_interval_seq \dim_new:N \l__gradtable_graphic_dim \dim_new:N \l__gradtable_text_dim \dim_new:N \l__gradtable_label_dim \dim_new:N \g__gradtable_measured_dim \box_new:N \l__gradtable_measure_box \int_new:N \l__gradtable_row_int \int_new:N \l__gradtable_col_int \bool_new:N \l__gradtable_valid_bool \bool_new:N \l__gradtable_started_bool \keys_define:nn {gradbars/table} {preset .choice:, preset / paper .code:n = \tl_set:Nn \l__gradtable_preset_tl {paper}, preset / report .code:n = \tl_set:Nn \l__gradtable_preset_tl {report}, preset / mono .code:n = \tl_set:Nn \l__gradtable_preset_tl {mono}, graphic~width .dim_set:N = \l__gradtable_graphic_dim, label~width .dim_set:N = \l__gradtable_label_dim, text~width .dim_set:N = \l__gradtable_text_dim, align .choices:nn = {auto,l,c,r}{\tl_set_eq:NN\l__gradtable_default_align_tl\l_keys_choice_tl}, header~align .choices:nn = {auto,l,c,r}{\tl_set_eq:NN\l__gradtable_default_headalign_tl\l_keys_choice_tl}, valign .choices:nn = {t,c,b}{\tl_set_eq:NN\l__gradtable_default_valign_tl\l_keys_choice_tl}, rules .choices:nn = {booktabs,rows,grid,none}{\tl_set_eq:NN\l__gradtable_rules_tl\l_keys_choice_tl}, row~stretch .tl_set:N = \l__gradtable_stretch_tl, column~sep .dim_set:N = \l__gradtable_sep_dim, row~padding .dim_set:N = \l__gradtable_padding_dim, header~color .tl_set:N = \l__gradtable_header_color_tl, rule~color .tl_set:N = \l__gradtable_rule_color_tl} \keys_define:nn {gradbars/table/column} {type .choices:nn = {text,number,bar,bullet,interval,compare,dumbbell,stack,spark} {\tl_set_eq:NN \l__gradtable_type_tl \l_keys_choice_tl}, options .tl_set:N = \l__gradtable_options_tl, align .choices:nn = {auto,l,c,r}{\tl_set_eq:NN\l__gradtable_align_tl\l_keys_choice_tl}, header~align .choices:nn = {auto,l,c,r}{\tl_set_eq:NN\l__gradtable_headalign_tl\l_keys_choice_tl}, valign .choices:nn = {t,c,b}{\tl_set_eq:NN\l__gradtable_valign_tl\l_keys_choice_tl}, width .dim_set:N = \l__gradtable_colwidth_dim} \cs_new_protected:Npn \gradtableError #1 {\bool_set_false:N \l__gradtable_valid_bool \PackageError{gradbars}{Table~row~\int_use:N\l__gradtable_row_int, ~column~\tl_use:N\l__gradtable_id_tl :~#1} {Check~column~declarations~and~comma-separated~row~data.}} \NewDocumentCommand\gradcolumn{O{} m m} {\PackageError{gradbars}{gradcolumn~requires~gradtable}{Place~column~declarations~inside~gradtable.}} \NewDocumentCommand\gradrow{m} {\PackageError{gradbars}{gradrow~requires~gradtable}{Place~rows~inside~gradtable.}} \cs_new_protected:Npn \gradtableColumn #1#2#3 {\bool_if:NT \l__gradtable_started_bool {\gradtableError{Declare~columns~before~rows}} \seq_if_empty:NF\l__gradtable_headers_seq{\gradtableError{Declare~columns~before~headers}} \tl_set:Nn \l__gradtable_id_tl {#2} \tl_if_blank:nT {#2}{\gradtableError{Column~identifier~must~not~be~empty}} \prop_if_in:NnT \l__gradtable_types_prop {#2}{\gradtableError{Duplicate~column~identifier}} \tl_set:Nn \l__gradtable_type_tl {text} \tl_clear:N \l__gradtable_options_tl \tl_set_eq:NN\l__gradtable_align_tl\l__gradtable_default_align_tl \tl_set_eq:NN\l__gradtable_headalign_tl\l__gradtable_default_headalign_tl \tl_set_eq:NN\l__gradtable_valign_tl\l__gradtable_default_valign_tl \dim_zero:N\l__gradtable_colwidth_dim \fp_set:Nn\l__gradtable_weight_fp{1} \tl_set:Nn\l__gradtable_mark_tl{none} \keys_set:nn {gradbars/table/column}{#1} \dim_compare:nNnT{\l__gradtable_colwidth_dim}<{0pt}{\gradtableError{Column~width~must~be~nonnegative}} \prop_put:Nnx\l__gradtable_fixed_prop{#2}{\dim_use:N\l__gradtable_colwidth_dim} \prop_put:Nnx\l__gradtable_weights_prop{#2}{\fp_use:N\l__gradtable_weight_fp} \str_if_eq:VnT\l__gradtable_align_tl{auto} {\tl_set:Nn\l__gradtable_align_tl{l} \str_if_eq:VnT\l__gradtable_type_tl{number}{\tl_set:Nn\l__gradtable_align_tl{r}}} \str_if_eq:VnT\l__gradtable_headalign_tl{auto}{\tl_set_eq:NN\l__gradtable_headalign_tl\l__gradtable_align_tl} \str_if_eq:VnT\l__gradtable_type_tl{text} {\dim_compare:nNnT{\l__gradtable_colwidth_dim}={0pt}{\dim_set_eq:NN\l__gradtable_colwidth_dim\l__gradtable_text_dim}} \prop_put:NnV\l__gradtable_marks_prop{#2}\l__gradtable_mark_tl \str_if_eq:VnF\l__gradtable_mark_tl{none} {\str_case:VnF\l__gradtable_type_tl{{number}{}{bar}{}{bullet}{}} {\gradtableError{Mark~requires~number,~bar~or~bullet~column}}} \seq_put_right:Nn \l__gradtable_columns_seq {#2} \prop_put:Nnn \l__gradtable_titles_prop {#2}{#3} \prop_put:NnV \l__gradtable_types_prop {#2}\l__gradtable_type_tl \prop_put:NnV \l__gradtable_options_prop {#2}\l__gradtable_options_tl \prop_put:NnV\l__gradtable_align_prop{#2}\l__gradtable_align_tl \prop_put:NnV\l__gradtable_headalign_prop{#2}\l__gradtable_headalign_tl \prop_put:NnV\l__gradtable_valign_prop{#2}\l__gradtable_valign_tl \prop_put:Nnx\l__gradtable_colwidth_prop{#2}{\dim_use:N\l__gradtable_colwidth_dim} \prop_put:Nnx \l__gradtable_widths_prop {#2}{\dim_use:N\l__gradtable_label_dim}} \cs_new_protected:Npn \gradtableRow #1 {\bool_set_true:N \l__gradtable_started_bool \int_incr:N \l__gradtable_row_int \clist_set:Nn \l__gradtable_cells_clist {#1} \int_compare:nNnTF {\clist_count:N\l__gradtable_cells_clist} = {\seq_count:N\l__gradtable_columns_seq} {\seq_put_right:Nn \l__gradtable_rows_seq {#1}} {\gradtableError{Wrong~number~of~cells;~use~NA~for~missing~data}}} \cs_new_protected:Npn \gradtableConfigure #1 {\prop_get:NnN \l__gradtable_types_prop {#1}\l__gradtable_type_tl \prop_get:NnN \l__gradtable_options_prop {#1}\l__gradtable_options_tl \pgfkeys{/gradbars,preset=paper,fill=solid,precision=1,overflow~mark=arrow} \str_case:Vn \l__gradtable_preset_tl {{report}{\pgfkeys{/gradbars,preset=report}} {mono}{\pgfkeys{/gradbars,theme=gray,print}}} \pgfkeys{/gradbars,width=\l__gradtable_graphic_dim} \exp_args:NV \gradbarssetup \l__gradtable_options_tl \prop_get:NnNT\l__gradtable_plots_prop{#1}\l_tmpa_tl {\pgfkeys{/gradbars/width/.expand~once=\l_tmpa_tl}} \pgfkeys{/gradbars,label=outside,label~width=\prop_item:Nn\l__gradtable_widths_prop{#1}}} \cs_new_protected:Npn \gradtableNumber #1 {\tl_set:Nn \l_tmpa_tl {#1}\tl_trim_spaces:N \l_tmpa_tl \str_if_eq:VnTF \l_tmpa_tl {NA} {\gradbars@missingtext} {\gradbars@validtrue\gradbarsCheckNumber{#1}{table~number} \tl_set:Nx \l_tmpa_tl {\gradbars@precision} \regex_match:nVTF {\A [0-6] \Z} \l_tmpa_tl {} {\gradbarsFail{Precision~must~be~an~integer~from~0~to~6}} \str_if_eq:eeT {\gradbars@format}{percent} {\gradbarsCheckNumber{\gradbars@max}{max} \ifgradbars@valid\fp_compare:nNnF {\gradbars@max}>{0} {\gradbarsFail{Percent~format~requires~positive~max}}\fi} \ifgradbars@valid \gradbars@missingfalse\def\gradbars@value{#1} \gradbarsFormatEndpoint{#1} \fi}} \cs_new_protected:Npn \gradtableContent #1 {\str_case:Vn \l__gradtable_type_tl {{text}{#1} {number}{\gradtableNumber{#1}} {bar}{\gradbar{#1}} {bullet}{\gradbullet{#1}} {compare}{\gradtablePair{\gradcompare}{#1}} {dumbbell}{\gradtablePair{\graddumbbell}{#1}} {stack}{\str_if_eq:nnTF{#1}{NA}{\gradbar{NA}}{\gradstack{#1}}} {spark}{\gradspark{#1}} {interval}{\str_if_eq:nnTF {#1}{NA} {\gradrange{NA}{NA}} {\seq_set_split:Nnn \l__gradtable_interval_seq {/}{#1} \int_compare:nNnTF {\seq_count:N\l__gradtable_interval_seq} = {3} {\tl_set:Nx \l_tmpa_tl {\seq_item:Nn\l__gradtable_interval_seq{2}} \str_if_eq:VnT \l_tmpa_tl {NA}{\tl_clear:N\l_tmpa_tl} \pgfkeys{/gradbars/range~point/.expand~once=\l_tmpa_tl} \exp_args:Nee \gradrange {\seq_item:Nn\l__gradtable_interval_seq{1}} {\seq_item:Nn\l__gradtable_interval_seq{3}}} {\gradbarsFail{Interval~requires~lower/point/upper}}}}}} \cs_new_protected:Npn \gradtableMeasure #1#2 {\group_begin: \gradbarsSuspendMeasurementTagging \tl_set:Nn \l__gradtable_id_tl {#1} \gradtableConfigure{#1} \gradtableHighlight{#1}{#2} \cs_set_eq:NN \gradtableSavedPackageError \PackageError \cs_set_protected:Npn \PackageError ##1##2##3 {\gradtableSavedPackageError{##1} {Table~row~\int_use:N\l__gradtable_row_int,~column~#1:~##2}{##3}} \dim_gset:Nn \g__gradtable_measured_dim {\prop_item:Nn\l__gradtable_widths_prop{#1}} \cs_set_eq:NN \gradtableSavedLabel \gradbarsDrawMainLabel \cs_set_protected:Npn \gradbarsDrawMainLabel {\gradbarsMeasure\gradbars@labelbox\gradbars@font{\gradbars@labelcontent} \dim_gset:Nn \g__gradtable_measured_dim {\dim_max:nn{\g__gradtable_measured_dim}{\wd\gradbars@labelbox}} \gradtableSavedLabel} \hbox_set:Nn \l__gradtable_measure_box {\gradtableContent{#2}} \str_if_eq:VnT \l__gradtable_type_tl {number} {\dim_gset:Nn \g__gradtable_measured_dim {\dim_max:nn{\g__gradtable_measured_dim}{\box_wd:N\l__gradtable_measure_box}}} \gradbarsResumeMeasurementTagging \group_end: \prop_put:Nnx \l__gradtable_widths_prop {#1}{\dim_use:N\g__gradtable_measured_dim}} \cs_new_protected:Npn \gradtableCell #1#2 {\group_begin:\tl_set:Nn\l__gradtable_id_tl{#1}\gradtableConfigure{#1} \gradtableHighlight{#1}{#2} \str_if_eq:VnTF \l__gradtable_type_tl {number} {\makebox[\dim_max:nn{\prop_item:Nn\l__gradtable_widths_prop{#1}}{\prop_item:Nn\l__gradtable_colwidth_prop{#1}}] [\prop_item:Nn\l__gradtable_align_prop{#1}]{\gradtableContent{#2}}} {\str_if_eq:VnTF\l__gradtable_type_tl{text}{\gradtableContent{#2}} {\hbox_set:Nn\l__gradtable_measure_box{\gradtableContent{#2}} \dim_compare:nNnT{\l__gradtable_total_dim}>{0pt} {\dim_compare:nNnT{\box_wd:N\l__gradtable_measure_box} >{\prop_item:Nn\l__gradtable_colwidth_prop{#1}+.2pt} {\gradtableError{Graphic~exceeds~allocated~column;~increase~width~or~simplify~labels}}} \makebox[\dim_max:nn{\box_wd:N\l__gradtable_measure_box}{\prop_item:Nn\l__gradtable_colwidth_prop{#1}}] [\prop_item:Nn\l__gradtable_align_prop{#1}]{\box_use:N\l__gradtable_measure_box}}} \group_end:} \cs_new:Npn\gradtableAlignCode #1 {\str_case:nn{#1}{{l}{\raggedright}{c}{\centering}{r}{\raggedleft}}} \cs_new:Npn\gradtableVerticalCode #1 {\str_case:nn{#1}{{t}{p}{c}{m}{b}{b}}} \cs_new_protected:Npn \gradtableRender {\gradtableRank \gradtableScan \dim_compare:nNnT{\l__gradtable_total_dim}>{0pt}{\gradtableAllocate} \tl_set:Nn\l__gradtable_preamble_tl{@{}} \tl_clear:N\l__gradtable_body_tl \str_case:Vn\l__gradtable_rules_tl {{booktabs}{\tl_set:Nn\l__gradtable_body_tl{\toprule}} {rows}{\tl_set:Nn\l__gradtable_body_tl{\toprule}} {grid}{\tl_set:Nn\l__gradtable_body_tl{\hline}\tl_set:Nn\l__gradtable_preamble_tl{|}}} \gradtableBuildHeaders \int_zero:N\l__gradtable_col_int \seq_map_inline:Nn \l__gradtable_columns_seq {\int_incr:N\l__gradtable_col_int \int_compare:nNnT{\l__gradtable_col_int}>{1}{\tl_put_right:Nn\l__gradtable_body_tl{&}} \bool_if:nTF{\dim_compare_p:nNn{\l__gradtable_total_dim}>{0pt} || \str_if_eq_p:ee{\prop_item:Nn\l__gradtable_types_prop{##1}}{text}} {\tl_put_right:Nx\l__gradtable_preamble_tl {>{\exp_not:N\gradtableAlignCode{\prop_item:Nn\l__gradtable_align_prop{##1}}\exp_not:N\arraybackslash} \str_if_eq:eeTF{\prop_item:Nn\l__gradtable_types_prop{##1}}{text} {\exp_args:Ne\gradtableVerticalCode{\prop_item:Nn\l__gradtable_valign_prop{##1}}}{p} {\prop_item:Nn\l__gradtable_colwidth_prop{##1}}}} {\tl_put_right:Nx\l__gradtable_preamble_tl{\prop_item:Nn\l__gradtable_align_prop{##1}}} \str_if_eq:VnT\l__gradtable_rules_tl{grid}{\tl_put_right:Nn\l__gradtable_preamble_tl{|}} \tl_clear:N\l__gradtable_header_spec_tl \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\int_compare:nNnT{\l__gradtable_col_int}={1}{\tl_put_right:Nn\l__gradtable_header_spec_tl{|}}} {\int_compare:nNnT{\l__gradtable_col_int}={1}{\tl_put_right:Nn\l__gradtable_header_spec_tl{@{}}}} \tl_if_empty:NF\l__gradtable_header_color_tl {\dim_set_eq:NN\l_tmpa_dim\l__gradtable_sep_dim \dim_set_eq:NN\l_tmpb_dim\l__gradtable_sep_dim \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\dim_set:Nn\l_tmpa_dim{\dim_max:nn{0pt}{\l_tmpa_dim-\arrayrulewidth}} \dim_set_eq:NN\l_tmpb_dim\l_tmpa_dim} {\int_compare:nNnT{\l__gradtable_col_int}={1}{\dim_zero:N\l_tmpa_dim} \int_compare:nNnT{\l__gradtable_col_int}={\seq_count:N\l__gradtable_columns_seq}{\dim_zero:N\l_tmpb_dim}} \tl_put_right:Nx\l__gradtable_header_spec_tl {>{\exp_not:N\columncolor{\exp_not:V\l__gradtable_header_color_tl} [\dim_use:N\l_tmpa_dim][\dim_use:N\l_tmpb_dim]}}} \bool_if:nTF{\dim_compare_p:nNn{\l__gradtable_total_dim}>{0pt} || \str_if_eq_p:ee{\prop_item:Nn\l__gradtable_types_prop{##1}}{text}} {\tl_put_right:Nx\l__gradtable_header_spec_tl {>{\exp_not:N\gradtableAlignCode{\prop_item:Nn\l__gradtable_headalign_prop{##1}}\exp_not:N\arraybackslash} p{\prop_item:Nn\l__gradtable_colwidth_prop{##1}}}} {\tl_put_right:Nx\l__gradtable_header_spec_tl{\prop_item:Nn\l__gradtable_headalign_prop{##1}}} \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\tl_put_right:Nn\l__gradtable_header_spec_tl{|}} {\int_compare:nNnT{\l__gradtable_col_int}={\seq_count:N\l__gradtable_columns_seq} {\tl_put_right:Nn\l__gradtable_header_spec_tl{@{}}}} \tl_put_right:Nx\l__gradtable_body_tl {\exp_not:N\multicolumn{1}{\exp_not:V\l__gradtable_header_spec_tl} {\exp_not:N\gradtableHeader{##1}}}} \str_if_eq:VnF\l__gradtable_rules_tl{grid}{\tl_put_right:Nn\l__gradtable_preamble_tl{@{}}} \tl_put_right:Nn\l__gradtable_body_tl{\\} \str_case:Vn\l__gradtable_rules_tl {{booktabs}{\tl_put_right:Nn\l__gradtable_body_tl{\midrule}} {rows}{\tl_put_right:Nn\l__gradtable_body_tl{\midrule}} {grid}{\tl_put_right:Nn\l__gradtable_body_tl{\hline}}} \tl_set_eq:NN\l__gradtable_head_tl\l__gradtable_body_tl \tl_clear:N\l__gradtable_body_tl \int_zero:N\l__gradtable_row_int \seq_map_inline:Nn\l__gradtable_rows_seq {\int_incr:N\l__gradtable_row_int \gradtableInsertGroup \clist_set:Nn\l__gradtable_cells_clist{##1} \int_zero:N\l__gradtable_col_int \clist_map_inline:Nn\l__gradtable_cells_clist {\int_incr:N\l__gradtable_col_int \tl_set:Nx\l__gradtable_id_tl{\seq_item:Nn\l__gradtable_columns_seq{\l__gradtable_col_int}} \int_compare:nNnT{\l__gradtable_col_int}>{1}{\tl_put_right:Nn\l__gradtable_body_tl{&}} \tl_put_right:Nx\l__gradtable_body_tl {\exp_not:N\gradtableCell{\exp_not:V\l__gradtable_id_tl}{\exp_not:n{####1}}}} \tl_put_right:Nn\l__gradtable_body_tl{\\} \str_if_eq:VnT\l__gradtable_rules_tl{grid}{\tl_put_right:Nn\l__gradtable_body_tl{\hline}} \str_if_eq:VnT\l__gradtable_rules_tl{rows} {\int_compare:nNnT{\l__gradtable_row_int}<{\seq_count:N\l__gradtable_rows_seq} {\tl_put_right:Nn\l__gradtable_body_tl{\midrule}}}} \cs_set:Npx\arraystretch{\l__gradtable_stretch_tl} \setlength\tabcolsep{\l__gradtable_sep_dim} \setlength\extrarowheight{\l__gradtable_padding_dim} \exp_args:NV\arrayrulecolor\l__gradtable_rule_color_tl \bool_if:NTF\l__gradtable_long_bool{\gradtableLong} {\exp_args:NV\tabular\l__gradtable_preamble_tl \l__gradtable_head_tl\l__gradtable_body_tl\gradtableBottom \endtabular}} \cs_new_protected:Npn\gradtableHeader #1 {\textbf{\prop_item:Nn\l__gradtable_titles_prop{#1}}} \NewDocumentEnvironment{gradtable}{O{} +b} {\group_begin: \prop_clear:N\l__gradtable_fixed_prop \prop_clear:N\l__gradtable_weights_prop \prop_clear:N\l__gradtable_plots_prop \seq_clear:N\l__gradtable_headers_seq \prop_clear:N\l__gradtable_groups_prop \prop_clear:N\l__gradtable_marks_prop \seq_clear:N\l__gradtable_style_stack_seq \seq_clear:N\l__gradtable_schema_stack_seq \cs_set_eq:NN\gradtableSavedRuleColor\CT@arc@ \seq_clear:N\l__gradtable_columns_seq\seq_clear:N\l__gradtable_rows_seq \prop_clear:N\l__gradtable_titles_prop\prop_clear:N\l__gradtable_types_prop \prop_clear:N\l__gradtable_options_prop\prop_clear:N\l__gradtable_widths_prop \prop_clear:N\l__gradtable_align_prop\prop_clear:N\l__gradtable_headalign_prop \prop_clear:N\l__gradtable_valign_prop\prop_clear:N\l__gradtable_colwidth_prop \int_zero:N\l__gradtable_row_int\tl_clear:N\l__gradtable_id_tl \bool_set_true:N\l__gradtable_valid_bool\bool_set_false:N\l__gradtable_started_bool \keys_set:nn{gradbars/table}{preset=paper,graphic~width=32mm,text~width=22mm,label~width=18mm, align=auto,header~align=auto,valign=t,rules=booktabs,row~stretch=auto, column~sep=6pt,row~padding=0pt,header~color=auto,rule~color=black,group~color=gradbarsTrack,group~sep=4pt,width=0pt,min~text~width=12mm,min~graphic~width=12mm, long=false,caption={},label={},continued~text={(continued)},#1} \str_if_eq:VnT\l__gradtable_stretch_tl{auto} {\tl_set:Nn\l__gradtable_stretch_tl{1.2} \str_if_eq:VnT\l__gradtable_preset_tl{report}{\tl_set:Nn\l__gradtable_stretch_tl{1.5}}} \regex_match:nVTF{\A\d+(\.\d+)?\Z}\l__gradtable_stretch_tl {\fp_compare:nNnF{\l__gradtable_stretch_tl}>{0}{\gradtableError{Row~stretch~must~be~positive}}} {\gradtableError{Row~stretch~must~be~a~positive~decimal}} \dim_compare:nNnT{\l__gradtable_sep_dim}<{0pt}{\gradtableError{Column~sep~must~be~nonnegative}} \dim_compare:nNnT{\l__gradtable_padding_dim}<{0pt}{\gradtableError{Row~padding~must~be~nonnegative}} \str_if_eq:VnT\l__gradtable_header_color_tl{auto} {\tl_clear:N\l__gradtable_header_color_tl \str_if_eq:VnT\l__gradtable_preset_tl{report}{\tl_set:Nn\l__gradtable_header_color_tl{gradbarsTrack}}} \dim_compare:nNnF{\l__gradtable_graphic_dim}>{0pt}{\gradtableError{Graphic~width~must~be~positive}} \dim_compare:nNnF{\l__gradtable_text_dim}>{0pt}{\gradtableError{Text~width~must~be~positive}} \dim_compare:nNnT{\l__gradtable_label_dim}<{0pt}{\gradtableError{Label~width~must~be~nonnegative}} \gradtableValidateLayout \RenewDocumentCommand\gradheader{+m}{\gradtableAddHeader{##1}} \RenewDocumentCommand\gradcolumn{O{} m m}{\gradtableColumn{##1}{##2}{##3}} \RenewDocumentCommand\gradrow{m}{\gradtableRow{##1}} \RenewDocumentCommand\gradgroup{m}{\gradtableGroup{##1}} \RenewDocumentCommand\graduseschema{m}{\gradtableUseSchema{##1}} #2 \prop_if_in:NxT\l__gradtable_groups_prop{\int_eval:n{\l__gradtable_row_int+1}} {\gradtableError{Group~requires~at~least~one~data~row}} \seq_if_empty:NT\l__gradtable_columns_seq{\gradtableError{Table~requires~columns}} \bool_if:NT\l__gradtable_valid_bool{\gradtableRender} \cs_gset_eq:NN\CT@arc@\gradtableSavedRuleColor \group_end:}{} \ExplSyntaxOff % Reusable table definitions, group headings and column extrema. \ExplSyntaxOn \prop_new:N\g__gradtable_styles_prop \prop_new:N\g__gradtable_schemas_prop \prop_new:N\l__gradtable_groups_prop \prop_new:N\l__gradtable_marks_prop \prop_new:N\l__gradtable_best_prop \prop_new:N\l__gradtable_second_prop \seq_new:N\l__gradtable_style_stack_seq \seq_new:N\l__gradtable_schema_stack_seq \seq_new:N\l__gradtable_rank_seq \tl_new:N\l__gradtable_mark_tl \tl_new:N\l__gradtable_group_color_tl \tl_new:N\g__gradtable_rank_direction_tl \tl_new:N\l__gradtable_rank_direction_tl \tl_new:N\l__gradtable_rank_value_tl \dim_new:N\l__gradtable_group_sep_dim \int_new:N\l__gradtable_rank_col_int \cs_generate_variant:Nn\prop_if_in:NnT{NxT} \cs_generate_variant:Nn\prop_get:NnNT{NxNT} \keys_define:nn{gradbars/table} {style .code:n=\gradtableUseStyle{#1}, group~color .tl_set:N=\l__gradtable_group_color_tl, group~sep .code:n={\dim_set:Nn\l__gradtable_group_sep_dim{#1} \dim_compare:nNnT{\l__gradtable_group_sep_dim}<{0pt} {\gradtableError{Group~sep~must~be~nonnegative}}}} \keys_define:nn{gradbars/table/column} {mark .choices:nn={none,best,both}{\tl_set_eq:NN\l__gradtable_mark_tl\l_keys_choice_tl}} \NewDocumentCommand\gradtablestyle{m m} {\tl_if_blank:nTF{#1}{\PackageError{gradbars}{Empty~table~style~name}{Supply~a~name.}} {\prop_gput:Nnn\g__gradtable_styles_prop{#1}{#2}}} \NewDocumentCommand\gradtableschema{m +m} {\tl_if_blank:nTF{#1}{\PackageError{gradbars}{Empty~table~schema~name}{Supply~a~name.}} {\prop_gput:Nnn\g__gradtable_schemas_prop{#1}{#2}}} \cs_new_protected:Npn\gradtableUseStyle #1 {\seq_if_in:NnTF\l__gradtable_style_stack_seq{#1} {\gradtableError{Recursive~table~style~#1}} {\prop_get:NnNTF\g__gradtable_styles_prop{#1}\l_tmpa_tl {\seq_put_right:Nn\l__gradtable_style_stack_seq{#1} \exp_args:NnV\keys_set:nn{gradbars/table}\l_tmpa_tl \seq_pop_right:NN\l__gradtable_style_stack_seq\l_tmpa_tl} {\gradtableError{Unknown~table~style~#1}}}} \NewDocumentCommand\graduseschema{m} {\PackageError{gradbars}{graduseschema~requires~gradtable}{Use~inside~gradtable.}} \cs_new_protected:Npn\gradtableUseSchema #1 {\seq_if_in:NnTF\l__gradtable_schema_stack_seq{#1} {\gradtableError{Recursive~table~schema~#1}} {\prop_get:NnNTF\g__gradtable_schemas_prop{#1}\l_tmpa_tl {\seq_put_right:Nn\l__gradtable_schema_stack_seq{#1} \tl_use:N\l_tmpa_tl \seq_pop_right:NN\l__gradtable_schema_stack_seq\l_tmpa_tl} {\gradtableError{Unknown~table~schema~#1}}}} \NewDocumentCommand\gradgroup{m} {\PackageError{gradbars}{gradgroup~requires~gradtable}{Use~inside~gradtable.}} \cs_new_protected:Npn\gradtableGroup #1 {\bool_set_true:N\l__gradtable_started_bool \seq_if_empty:NT\l__gradtable_columns_seq{\gradtableError{Declare~columns~before~groups}} \tl_if_blank:nT{#1}{\gradtableError{Group~title~must~not~be~empty}} \prop_if_in:NxT\l__gradtable_groups_prop{\int_eval:n{\l__gradtable_row_int+1}} {\gradtableError{Group~requires~at~least~one~data~row}} \prop_put:Nxn\l__gradtable_groups_prop{\int_eval:n{\l__gradtable_row_int+1}}{#1}} \cs_new_protected:Npn\gradtableInsertGroup {\prop_get:NxNT\l__gradtable_groups_prop{\int_use:N\l__gradtable_row_int}\l_tmpa_tl {\str_if_eq:VnF\l__gradtable_rules_tl{grid} {\tl_put_right:Nx\l__gradtable_body_tl {\exp_not:N\noalign{\exp_not:N\vskip\dim_use:N\l__gradtable_group_sep_dim}}} \tl_set:Nn\l_tmpb_tl{@{}} \dim_zero:N\l_tmpa_dim \str_if_eq:VnT\l__gradtable_rules_tl{grid} {\tl_set:Nn\l_tmpb_tl{|} \dim_set:Nn\l_tmpa_dim{\dim_max:nn{0pt}{\l__gradtable_sep_dim-\arrayrulewidth}}} \tl_if_empty:NF\l__gradtable_group_color_tl {\tl_put_right:Nx\l_tmpb_tl {>{\exp_not:N\columncolor{\exp_not:V\l__gradtable_group_color_tl} [\dim_use:N\l_tmpa_dim][\dim_use:N\l_tmpa_dim]}}} \dim_compare:nNnTF{\l__gradtable_total_dim}>{0pt} {\dim_set_eq:NN\l__gradtable_span_dim\l__gradtable_total_dim \str_if_eq:VnT\l__gradtable_rules_tl{grid} {\dim_sub:Nn\l__gradtable_span_dim{2\l__gradtable_sep_dim+2\arrayrulewidth}} \tl_put_right:Nx\l_tmpb_tl {>{\exp_not:N\raggedright\exp_not:N\arraybackslash}p{\dim_use:N\l__gradtable_span_dim}}} {\tl_put_right:Nn\l_tmpb_tl{l}} \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\tl_put_right:Nn\l_tmpb_tl{|}}{\tl_put_right:Nn\l_tmpb_tl{@{}}} \tl_put_right:Nx\l__gradtable_body_tl {\exp_not:N\multicolumn{\seq_count:N\l__gradtable_columns_seq}{\exp_not:V\l_tmpb_tl} {\exp_not:N\gradtableGroupTitle{\exp_not:V\l_tmpa_tl}}\exp_not:N\\*} \str_if_eq:VnT\l__gradtable_rules_tl{grid} {\tl_put_right:Nn\l__gradtable_body_tl{\gradtableGroupRule}}}} \cs_new:Npn\gradtableGroupRule {\noalign{\nobreak{\CT@arc@\hrule height\arrayrulewidth}\nobreak}} \cs_new_protected:Npn\gradtableGroupTitle #1 {\rule{0pt}{\dim_eval:n{\ht\strutbox+\l__gradtable_group_sep_dim}}\textbf{#1}} \cs_new_protected:Npn\gradtablePair #1#2 {\str_if_eq:nnTF{#2}{NA}{#1{NA}{NA}} {\seq_set_split:Nnn\l__gradtable_interval_seq{/}{#2} \int_compare:nNnTF{\seq_count:N\l__gradtable_interval_seq}={2} {\exp_args:Nee#1{\seq_item:Nn\l__gradtable_interval_seq{1}} {\seq_item:Nn\l__gradtable_interval_seq{2}}} {\gradbarsFail{Comparison~requires~reference/current}}}} \cs_new_protected:Npn\gradtableRank {\prop_clear:N\l__gradtable_best_prop\prop_clear:N\l__gradtable_second_prop \int_zero:N\l__gradtable_rank_col_int \seq_map_inline:Nn\l__gradtable_columns_seq {\int_incr:N\l__gradtable_rank_col_int \str_if_eq:eeF{\prop_item:Nn\l__gradtable_marks_prop{##1}}{none} {\group_begin:\gradtableConfigure{##1} \tl_gset:Nx\g__gradtable_rank_direction_tl{\gradbars@better}\group_end: \tl_set_eq:NN\l__gradtable_rank_direction_tl\g__gradtable_rank_direction_tl \str_case:VnF\l__gradtable_rank_direction_tl{{higher}{}{lower}{}} {\gradtableError{Mark~requires~better=higher~or~lower}} \seq_clear:N\l__gradtable_rank_seq \seq_map_inline:Nn\l__gradtable_rows_seq {\clist_set:Nn\l__gradtable_cells_clist{####1} \tl_set:Nx\l__gradtable_rank_value_tl {\clist_item:Nn\l__gradtable_cells_clist{\l__gradtable_rank_col_int}} \tl_trim_spaces:N\l__gradtable_rank_value_tl \regex_match:nVT{\A[+\-]?(\d+(\.\d*)?|\.\d+)\Z}\l__gradtable_rank_value_tl {\seq_put_right:Nx\l__gradtable_rank_seq{\fp_eval:n{\l__gradtable_rank_value_tl}}}} \seq_remove_duplicates:N\l__gradtable_rank_seq \seq_sort:Nn\l__gradtable_rank_seq {\str_if_eq:VnTF\l__gradtable_rank_direction_tl{higher} {\fp_compare:nNnTF{####1}<{####2}{\sort_return_swapped:}{\sort_return_same:}} {\fp_compare:nNnTF{####1}>{####2}{\sort_return_swapped:}{\sort_return_same:}}} \seq_if_empty:NF\l__gradtable_rank_seq {\prop_put:Nnx\l__gradtable_best_prop{##1}{\seq_item:Nn\l__gradtable_rank_seq{1}}} \int_compare:nNnT{\seq_count:N\l__gradtable_rank_seq}>{1} {\prop_put:Nnx\l__gradtable_second_prop{##1}{\seq_item:Nn\l__gradtable_rank_seq{2}}}}}} \cs_new_protected:Npn\gradtableBest #1{{\bfseries\boldmath #1}} \cs_new_protected:Npn\gradtableHighlight #1#2 {\cs_set_eq:NN\gradtableEmphasis\use:n \tl_set:Nn\l_tmpa_tl{#2}\tl_trim_spaces:N\l_tmpa_tl \regex_match:nVT{\A[+\-]?(\d+(\.\d*)?|\.\d+)\Z}\l_tmpa_tl {\prop_get:NnNT\l__gradtable_best_prop{#1}\l_tmpb_tl {\fp_compare:nNnT{#2}={\l_tmpb_tl}{\cs_set_eq:NN\gradtableEmphasis\gradtableBest}} \str_if_eq:eeT{\prop_item:Nn\l__gradtable_marks_prop{#1}}{both} {\prop_get:NnNT\l__gradtable_second_prop{#1}\l_tmpb_tl {\fp_compare:nNnT{#2}={\l_tmpb_tl}{\cs_set_eq:NN\gradtableEmphasis\underline}}}} \str_if_eq:VnTF\l__gradtable_type_tl{number} {\cs_set_eq:NN\gradtableOriginalNumber\gradtableNumber \cs_set_protected:Npn\gradtableNumber##1{\gradtableEmphasis{\gradtableOriginalNumber{##1}}}} {\cs_set_eq:NN\gradtableOriginalLabel\gradbars@labelcontent \cs_set_protected:Npn\gradbars@labelcontent{\gradtableEmphasis{\gradtableOriginalLabel}}}} \ExplSyntaxOff % v0.0.4: column-spanning headers, constrained widths and long tables. \ExplSyntaxOn \seq_new:N\l__gradtable_headers_seq \tl_new:N\l__gradtable_head_tl \tl_new:N\l__gradtable_caption_tl \tl_new:N\l__gradtable_label_tl \tl_new:N\l__gradtable_continued_tl \tl_new:N\l__gradtable_span_id_tl \bool_new:N\l__gradtable_long_bool \dim_new:N\l__gradtable_total_dim \dim_new:N\l__gradtable_min_text_dim \dim_new:N\l__gradtable_min_graphic_dim \dim_new:N\l__gradtable_remaining_dim \dim_new:N\l__gradtable_base_dim \dim_new:N\l__gradtable_span_dim \dim_new:N\g__gradtable_extent_dim \fp_new:N\l__gradtable_weight_fp \fp_new:N\l__gradtable_weight_sum_fp \prop_new:N\l__gradtable_fixed_prop \prop_new:N\l__gradtable_weights_prop \prop_new:N\l__gradtable_flex_prop \prop_new:N\l__gradtable_plots_prop \prop_new:N\l__gradtable_overheads_prop \int_new:N\l__gradtable_span_start_int \int_new:N\l__gradtable_span_count_int \keys_define:nn{gradbars/table} {width .dim_set:N=\l__gradtable_total_dim, min~text~width .dim_set:N=\l__gradtable_min_text_dim, min~graphic~width .dim_set:N=\l__gradtable_min_graphic_dim, long .bool_set:N=\l__gradtable_long_bool, caption .tl_set:N=\l__gradtable_caption_tl, label .tl_set:N=\l__gradtable_label_tl, continued~text .tl_set:N=\l__gradtable_continued_tl} \keys_define:nn{gradbars/table/column} {weight .code:n={\regex_match:nnTF{\A\d+(\.\d+)?\Z}{#1} {\fp_set:Nn\l__gradtable_weight_fp{#1} \fp_compare:nNnF{#1}>{0}{\gradtableError{Column~weight~must~be~positive}}} {\gradtableError{Column~weight~must~be~a~positive~decimal}}}} \cs_new_protected:Npn\gradtableValidateLayout {\dim_compare:nNnT{\l__gradtable_total_dim}<{0pt}{\gradtableError{Table~width~must~be~nonnegative}} \dim_compare:nNnF{\l__gradtable_min_text_dim}>{0pt}{\gradtableError{Min~text~width~must~be~positive}} \dim_compare:nNnF{\l__gradtable_min_graphic_dim}>{0pt}{\gradtableError{Min~graphic~width~must~be~positive}} \bool_if:NTF\l__gradtable_long_bool {\ifinner\gradtableError{Long~table~requires~outer~paragraph~mode}\fi \if@twocolumn\gradtableError{Long~table~requires~one-column~mode}\fi \tl_if_empty:NF\l__gradtable_label_tl {\tl_if_empty:NT\l__gradtable_caption_tl{\gradtableError{Table~label~requires~caption}}}} {\tl_if_empty:NF\l__gradtable_caption_tl{\gradtableError{Caption~option~requires~long=true}} \tl_if_empty:NF\l__gradtable_label_tl{\gradtableError{Label~option~requires~long=true}}}} \NewDocumentCommand\gradheader{+m} {\PackageError{gradbars}{gradheader~requires~gradtable}{Declare~headers~inside~gradtable.}} \NewDocumentCommand\gradspan{m m} {\PackageError{gradbars}{gradspan~requires~gradheader}{Place~spans~inside~gradheader.}} \cs_new_protected:Npn\gradtableAddHeader #1 {\bool_if:NT\l__gradtable_started_bool{\gradtableError{Declare~headers~before~rows}} \int_zero:N\l__gradtable_span_count_int \cs_set_eq:NN\gradtableSavedSpan\gradspan \RenewDocumentCommand\gradspan{m m} {\regex_match:nnTF{\A[1-9]\d*\Z}{##1} {\int_add:Nn\l__gradtable_span_count_int{##1}} {\gradtableError{Header~span~must~be~a~positive~integer}}} #1 \cs_set_eq:NN\gradspan\gradtableSavedSpan \int_compare:nNnF{\l__gradtable_span_count_int}={\seq_count:N\l__gradtable_columns_seq} {\gradtableError{Header~spans~must~cover~all~columns~exactly}} \seq_put_right:Nn\l__gradtable_headers_seq{#1}} \cs_new_protected:Npn\gradtableBuildHeaders {\seq_map_inline:Nn\l__gradtable_headers_seq {\int_set:Nn\l__gradtable_span_start_int{1} \cs_set_eq:NN\gradtableSavedSpan\gradspan \RenewDocumentCommand\gradspan{m m}{\gradtableBuildSpan{####1}{####2}} ##1 \cs_set_eq:NN\gradspan\gradtableSavedSpan \tl_put_right:Nn\l__gradtable_body_tl{\\} \str_case:Vn\l__gradtable_rules_tl {{grid}{\tl_put_right:Nn\l__gradtable_body_tl{\hline}} {booktabs}{\tl_put_right:Nn\l__gradtable_body_tl{\midrule}} {rows}{\tl_put_right:Nn\l__gradtable_body_tl{\midrule}}}}} \cs_new_protected:Npn\gradtableBuildSpan #1#2 {\int_compare:nNnT{\l__gradtable_span_start_int}>{1}{\tl_put_right:Nn\l__gradtable_body_tl{&}} \tl_clear:N\l__gradtable_header_spec_tl \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\int_compare:nNnT{\l__gradtable_span_start_int}={1}{\tl_put_right:Nn\l__gradtable_header_spec_tl{|}}} {\int_compare:nNnT{\l__gradtable_span_start_int}={1}{\tl_put_right:Nn\l__gradtable_header_spec_tl{@{}}}} \tl_if_empty:NF\l__gradtable_header_color_tl {\dim_set_eq:NN\l_tmpa_dim\l__gradtable_sep_dim \dim_set_eq:NN\l_tmpb_dim\l__gradtable_sep_dim \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\dim_set:Nn\l_tmpa_dim{\dim_max:nn{0pt}{\l_tmpa_dim-\arrayrulewidth}} \dim_set_eq:NN\l_tmpb_dim\l_tmpa_dim} {\int_compare:nNnT{\l__gradtable_span_start_int}={1}{\dim_zero:N\l_tmpa_dim} \int_compare:nNnT{\l__gradtable_span_start_int+#1-1}={\seq_count:N\l__gradtable_columns_seq} {\dim_zero:N\l_tmpb_dim}} \tl_put_right:Nx\l__gradtable_header_spec_tl {>{\exp_not:N\columncolor{\exp_not:V\l__gradtable_header_color_tl} [\dim_use:N\l_tmpa_dim][\dim_use:N\l_tmpb_dim]}}} \dim_compare:nNnTF{\l__gradtable_total_dim}>{0pt} {\dim_set:Nn\l__gradtable_span_dim{2\l__gradtable_sep_dim*(#1-1)} \str_if_eq:VnT\l__gradtable_rules_tl{grid} {\dim_add:Nn\l__gradtable_span_dim{\arrayrulewidth*(#1-1)}} \int_step_inline:nnnn{\l__gradtable_span_start_int}{1}{\l__gradtable_span_start_int+#1-1} {\tl_set:Nx\l__gradtable_span_id_tl{\seq_item:Nn\l__gradtable_columns_seq{##1}} \dim_add:Nn\l__gradtable_span_dim{\prop_item:NV\l__gradtable_colwidth_prop\l__gradtable_span_id_tl}} \tl_put_right:Nx\l__gradtable_header_spec_tl {>{\exp_not:N\centering\exp_not:N\arraybackslash}p{\dim_use:N\l__gradtable_span_dim}}} {\tl_put_right:Nn\l__gradtable_header_spec_tl{c}} \str_if_eq:VnTF\l__gradtable_rules_tl{grid} {\tl_put_right:Nn\l__gradtable_header_spec_tl{|}} {\int_compare:nNnT{\l__gradtable_span_start_int+#1-1}={\seq_count:N\l__gradtable_columns_seq} {\tl_put_right:Nn\l__gradtable_header_spec_tl{@{}}}} \tl_put_right:Nx\l__gradtable_body_tl {\exp_not:N\multicolumn{#1}{\exp_not:V\l__gradtable_header_spec_tl}{\exp_not:N\textbf{\exp_not:n{#2}}}} \int_add:Nn\l__gradtable_span_start_int{#1}} \cs_new_protected:Npn\gradtableScan {\int_zero:N\l__gradtable_row_int \seq_map_inline:Nn\l__gradtable_rows_seq {\int_incr:N\l__gradtable_row_int \clist_set:Nn\l__gradtable_cells_clist{##1} \int_zero:N\l__gradtable_col_int \clist_map_inline:Nn\l__gradtable_cells_clist {\int_incr:N\l__gradtable_col_int \tl_set:Nx\l__gradtable_id_tl{\seq_item:Nn\l__gradtable_columns_seq{\l__gradtable_col_int}} \exp_args:NV\gradtableMeasure\l__gradtable_id_tl{####1}}}} \cs_new_protected:Npn\gradtableExtent #1#2 {\group_begin:\gradtableConfigure{#1}\gradtableHighlight{#1}{#2} \gradbarsSuspendMeasurementTagging \dim_gset:Nn\g__gradtable_extent_dim{\prop_item:Nn\l__gradtable_overheads_prop{#1}} \str_case:VnF\l__gradtable_type_tl{{text}{}{number}{}} {\hbox_set:Nn\l__gradtable_measure_box{\gradtableContent{#2}} \dim_gset:Nn\g__gradtable_extent_dim {\dim_max:nn{\prop_item:Nn\l__gradtable_overheads_prop{#1}} {\box_wd:N\l__gradtable_measure_box-\gradbars@width}}} \gradbarsResumeMeasurementTagging \group_end: \prop_put:Nnx\l__gradtable_overheads_prop{#1}{\dim_use:N\g__gradtable_extent_dim}} \cs_new_protected:Npn\gradtableAllocate {\prop_clear:N\l__gradtable_overheads_prop\prop_clear:N\l__gradtable_flex_prop \seq_map_inline:Nn\l__gradtable_columns_seq {\group_begin:\gradtableConfigure{##1} \dim_gset:Nn\g__gradtable_extent_dim {\prop_item:Nn\l__gradtable_widths_prop{##1}+\gradbars@gap+2pt}\group_end: \prop_put:Nnx\l__gradtable_overheads_prop{##1}{\dim_use:N\g__gradtable_extent_dim}} \seq_map_inline:Nn\l__gradtable_rows_seq {\clist_set:Nn\l__gradtable_cells_clist{##1}\int_zero:N\l__gradtable_col_int \clist_map_inline:Nn\l__gradtable_cells_clist {\int_incr:N\l__gradtable_col_int \tl_set:Nx\l__gradtable_id_tl{\seq_item:Nn\l__gradtable_columns_seq{\l__gradtable_col_int}} \exp_args:NV\gradtableExtent\l__gradtable_id_tl{####1}}} \dim_set:Nn\l__gradtable_remaining_dim {\l__gradtable_total_dim-2\l__gradtable_sep_dim*(\seq_count:N\l__gradtable_columns_seq-1)} \str_if_eq:VnT\l__gradtable_rules_tl{grid} {\dim_sub:Nn\l__gradtable_remaining_dim {2\l__gradtable_sep_dim+\arrayrulewidth*(\seq_count:N\l__gradtable_columns_seq+1)}} \fp_zero:N\l__gradtable_weight_sum_fp \seq_map_inline:Nn\l__gradtable_columns_seq {\tl_set:Nn\l__gradtable_id_tl{##1} \tl_set:Nx\l__gradtable_type_tl{\prop_item:Nn\l__gradtable_types_prop{##1}} \dim_set:Nn\l__gradtable_base_dim{\prop_item:Nn\l__gradtable_fixed_prop{##1}} \fp_zero:N\l__gradtable_weight_fp \str_if_eq:VnTF\l__gradtable_type_tl{number} {\dim_set:Nn\l__gradtable_base_dim {\dim_max:nn{\l__gradtable_base_dim}{\prop_item:Nn\l__gradtable_widths_prop{##1}}}} {\dim_compare:nNnTF{\l__gradtable_base_dim}>{0pt} {\str_if_eq:VnF\l__gradtable_type_tl{text} {\dim_compare:nNnT{\l__gradtable_base_dim} <{\prop_item:Nn\l__gradtable_overheads_prop{##1}+\l__gradtable_min_graphic_dim} {\gradtableError{Fixed~column~too~narrow~for~labels~and~graphic}}}} {\fp_set:Nn\l__gradtable_weight_fp{\prop_item:Nn\l__gradtable_weights_prop{##1}} \str_if_eq:VnTF\l__gradtable_type_tl{text} {\dim_set_eq:NN\l__gradtable_base_dim\l__gradtable_min_text_dim} {\dim_set:Nn\l__gradtable_base_dim {\prop_item:Nn\l__gradtable_overheads_prop{##1}+\l__gradtable_min_graphic_dim}}}} \prop_put:Nnx\l__gradtable_colwidth_prop{##1}{\dim_use:N\l__gradtable_base_dim} \prop_put:Nnx\l__gradtable_flex_prop{##1}{\fp_use:N\l__gradtable_weight_fp} \fp_add:Nn\l__gradtable_weight_sum_fp{\l__gradtable_weight_fp} \dim_sub:Nn\l__gradtable_remaining_dim{\l__gradtable_base_dim}} \dim_compare:nNnT{\l__gradtable_remaining_dim}<{0pt} {\gradtableError{Table~width~too~small;~increase~width~or~reduce~minimum~widths~and~spacing}} \fp_compare:nNnT{\l__gradtable_weight_sum_fp}={0} {\dim_compare:nNnT{\l__gradtable_remaining_dim}>{.1pt} {\gradtableError{Table~width~requires~a~flexible~text~or~graphic~column}}} \seq_map_inline:Nn\l__gradtable_columns_seq {\fp_set:Nn\l__gradtable_weight_fp{\prop_item:Nn\l__gradtable_flex_prop{##1}} \fp_compare:nNnT{\l__gradtable_weight_fp}>{0} {\dim_set:Nn\l_tmpa_dim{\fp_to_dim:n {\dim_to_fp:n{\l__gradtable_remaining_dim}*\l__gradtable_weight_fp/\l__gradtable_weight_sum_fp}} \prop_put:Nnx\l__gradtable_colwidth_prop{##1} {\dim_eval:n{\prop_item:Nn\l__gradtable_colwidth_prop{##1}+\l_tmpa_dim}} \dim_sub:Nn\l__gradtable_remaining_dim{\l_tmpa_dim} \fp_sub:Nn\l__gradtable_weight_sum_fp{\l__gradtable_weight_fp}} \str_case_e:nnF{\prop_item:Nn\l__gradtable_types_prop{##1}}{{text}{}{number}{}} {\prop_put:Nnx\l__gradtable_plots_prop{##1} {\dim_eval:n{\prop_item:Nn\l__gradtable_colwidth_prop{##1}-\prop_item:Nn\l__gradtable_overheads_prop{##1}}}}}} \cs_new:Npn\gradtableBottom {\str_case:Vn\l__gradtable_rules_tl{{booktabs}{\bottomrule}{rows}{\bottomrule}}} \cs_new_protected:Npn\gradtableLong {\par\setlength\LTleft{0pt}\setlength\LTright{\fill} \dim_compare:nNnT{\l__gradtable_total_dim}>{0pt}{\setlength\LTcapwidth{\l__gradtable_total_dim}} \exp_args:NV\longtable\l__gradtable_preamble_tl \tl_if_empty:NF\l__gradtable_caption_tl {\caption{\l__gradtable_caption_tl} \tl_if_empty:NF\l__gradtable_label_tl{\exp_args:NV\label\l__gradtable_label_tl}\\} \l__gradtable_head_tl\endfirsthead \tl_if_empty:NTF\l__gradtable_caption_tl {\tl_if_empty:NF\l__gradtable_continued_tl {\multicolumn{\seq_count:N\l__gradtable_columns_seq}{c}{\l__gradtable_continued_tl}\\}} {\caption[]{\l__gradtable_caption_tl\space\l__gradtable_continued_tl}\\} \l__gradtable_head_tl\endhead \gradtableBottom \tl_if_empty:NF\l__gradtable_continued_tl {\multicolumn{\seq_count:N\l__gradtable_columns_seq}{r}{\footnotesize\l__gradtable_continued_tl}\\} \endfoot \gradtableBottom\endlastfoot \l__gradtable_body_tl \endlongtable} \ExplSyntaxOff % Accessible descriptions use the supported TikZ tagging interface. No tagging % is activated by this package; ordinary documents keep their existing output. \def\gradbarsCaptureTikzAlt{% % Capture explicit /tikz/alt options locally, without changing the global key. \pgfkeysifdefined{/tikz/alt/.@cmd}{% \pgfkeys{/tikz/alt/.append code={\ifgradbars@capturealt\def\gradbars@alt{##1}\fi}}% }{\pgfkeys{/tikz/alt/.code={\def\gradbars@alt{##1}}}}% } \ExplSyntaxOn \tl_new:N \l__gradbars_alt_tl \seq_new:N \l__gradbars_alt_fields_seq \int_new:N \l__gradbars_alt_index_int \cs_new_protected:Npn \gradbarsAltValue #1 { \tl_set:Nx \l_tmpa_tl {#1} \tl_trim_spaces:N \l_tmpa_tl \tl_if_empty:NTF \l_tmpa_tl {\tl_put_right:Nn \l__gradbars_alt_tl {missing}} {\str_if_eq:VnTF \l_tmpa_tl {NA} {\tl_put_right:Nn \l__gradbars_alt_tl {missing}} {\tl_put_right:Nx \l__gradbars_alt_tl {\fp_eval:n {\l_tmpa_tl}}}} } \cs_new_protected:Npn \gradbarsBuildAlt { \tl_clear:N \l__gradbars_alt_tl \ifgradbars@spark \tl_put_right:Nn \l__gradbars_alt_tl {Equally~spaced~series:~} \int_zero:N \l__gradbars_alt_index_int \seq_map_inline:Nn \l__gradbars_series_seq {\int_incr:N \l__gradbars_alt_index_int \int_compare:nNnT {\l__gradbars_alt_index_int}>{1} {\tl_put_right:Nn \l__gradbars_alt_tl {;~}} \tl_put_right:Nx \l__gradbars_alt_tl {observation~\int_use:N\l__gradbars_alt_index_int :~} \gradbarsAltValue{##1}} \tl_put_right:Nn \l__gradbars_alt_tl {.~Final~observation:~} \gradbarsAltValue{\gradbars@sparklast} \tl_put_right:Nx \l__gradbars_alt_tl {.~Vertical~range:~\fp_use:N\l__gradbars_series_low_fp\c_space_tl to~\fp_use:N\l__gradbars_series_high_fp.} \else\ifgradbars@stack \tl_put_right:Nn \l__gradbars_alt_tl {Stacked~contributions:~} \int_zero:N \l__gradbars_alt_index_int \clist_map_inline:Nn \l__gradbars_stack_clist {\int_incr:N \l__gradbars_alt_index_int \int_compare:nNnT {\l__gradbars_alt_index_int}>{1} {\tl_put_right:Nn \l__gradbars_alt_tl {;~}} \clist_if_empty:NTF \l__gradbars_names_clist {\tl_put_right:Nx \l__gradbars_alt_tl {segment~\int_use:N\l__gradbars_alt_index_int}} {\tl_put_right:Nx \l__gradbars_alt_tl {\clist_item:Nn\l__gradbars_names_clist{\l__gradbars_alt_index_int}}} \tl_put_right:Nn \l__gradbars_alt_tl {:~}\gradbarsAltValue{##1}} \tl_put_right:Nx \l__gradbars_alt_tl {.~Net:~\gradbars@total.~Positive~subtotal:~\gradbars@positive.\c_space_tl Negative~subtotal:~\gradbars@negative.} \else\ifgradbars@compare \tl_put_right:Nn \l__gradbars_alt_tl {Reference:~} \ifgradbars@referencemissing \tl_put_right:Nn \l__gradbars_alt_tl {missing} \else\gradbarsAltValue{\gradbars@reference}\fi \tl_put_right:Nn \l__gradbars_alt_tl {.~Current:~} \ifgradbars@missing\tl_put_right:Nn \l__gradbars_alt_tl {missing} \else\gradbarsAltValue{\gradbars@value}\fi \tl_put_right:Nn \l__gradbars_alt_tl {.~Change:~} \ifgradbars@missing\tl_put_right:Nn \l__gradbars_alt_tl {missing} \else\ifgradbars@referencemissing\tl_put_right:Nn \l__gradbars_alt_tl {missing} \else\gradbarsAltValue{\gradbars@value-\gradbars@reference}\fi\fi \str_if_eq:eeT {\gradbars@comparelabel}{percent} {\tl_put_right:Nn \l__gradbars_alt_tl {.~Relative~change:~} \ifgradbars@missing\tl_put_right:Nn \l__gradbars_alt_tl {missing} \else\ifgradbars@referencemissing\tl_put_right:Nn \l__gradbars_alt_tl {missing} \else\fp_compare:nNnTF {\gradbars@reference}={0} {\tl_put_right:Nn \l__gradbars_alt_tl {undefined~for~a~zero~reference}} {\gradbarsAltValue{100*(\gradbars@value-\gradbars@reference)/abs(\gradbars@reference)} \tl_put_right:Nn \l__gradbars_alt_tl {~percent}}\fi\fi} \tl_put_right:Nn \l__gradbars_alt_tl {.} \else\ifgradbars@rangemode \tl_put_right:Nn \l__gradbars_alt_tl {Interval:~} \ifgradbars@rangemissing\tl_put_right:Nn \l__gradbars_alt_tl {missing.} \else \gradbarsAltValue{\gradbars@rangelo} \tl_put_right:Nn \l__gradbars_alt_tl {~to~}\gradbarsAltValue{\gradbars@rangehi} \tl_put_right:Nn \l__gradbars_alt_tl {.} \tl_if_empty:oF {\gradbars@rangepoint} {\tl_put_right:Nn \l__gradbars_alt_tl {~Point~estimate:~} \gradbarsAltValue{\gradbars@rangepoint}\tl_put_right:Nn \l__gradbars_alt_tl {.}} \fi \else \tl_put_right:Nn \l__gradbars_alt_tl {Value:~} \ifgradbars@missing\tl_put_right:Nn \l__gradbars_alt_tl {missing.} \else\gradbarsAltValue{\gradbars@value}\tl_put_right:Nn \l__gradbars_alt_tl {.}\fi \fi\fi\fi\fi \tl_if_empty:oF {\gradbars@unit} {\tl_put_right:Nx \l__gradbars_alt_tl {~Unit:~\exp_not:o{\gradbars@unit}.}} \ifgradbars@spark\else \tl_put_right:Nx \l__gradbars_alt_tl {~Scale:~\fp_eval:n{\gradbars@min}~to~\fp_eval:n{\gradbars@max}.} \ifgradbars@error \tl_put_right:Nx \l__gradbars_alt_tl {~Error~distances:~minus~\gradbars@errorminus,~plus~\gradbars@errorplus.} \fi \tl_if_empty:oF {\gradbars@target} {\tl_put_right:Nx \l__gradbars_alt_tl {~Target:~\gradbars@target.}} \clist_map_inline:Nn \l__gradbars_refs_clist {\seq_set_split:Nnn\l__gradbars_alt_fields_seq{/}{##1} \tl_put_right:Nx\l__gradbars_alt_tl {~Reference~\seq_item:Nn\l__gradbars_alt_fields_seq{4}:\c_space_tl \seq_item:Nn\l__gradbars_alt_fields_seq{1}.}} \tl_if_empty:oF {\gradbars@band} {\tl_put_right:Nx\l__gradbars_alt_tl {~Reference~band:~\gradbars@band.}} \ifgradbars@bullet \tl_put_right:Nn\l__gradbars_alt_tl {~Background~grade~upper~bounds:~} \clist_map_inline:Nn\l__gradbars_bands_clist {\seq_set_split:Nnn\l__gradbars_alt_fields_seq{/}{##1} \tl_put_right:Nx\l__gradbars_alt_tl {\seq_item:Nn\l__gradbars_alt_fields_seq{1};~}} \fi \fi } \cs_new_protected:Npn \gradbarsApplyAlt { \cs_if_exist:NT \tag_if_active:T {\tag_if_active:T {\pgfkeysifdefined{/tikz/alt/.@cmd} {\str_case_e:nn {\gradbars@accessibility} {{auto}{\tl_if_empty:oF{\gradbars@alt} {\tl_set:No\l__gradbars_alt_tl{\gradbars@alt}} \tikzset{alt={\l__gradbars_alt_tl}}} {artifact}{\tikzset{artifact}}}} {}}} } \cs_new_protected:Npn \gradbarsPrepareAlt {\cs_if_exist:NT\tag_if_active:T {\tag_if_active:T{\gradbarsBuildAlt\gradbarsApplyAlt}}} \cs_new_protected:Npn \gradbarsPrepareLegendAlt {\cs_if_exist:NT\tag_if_active:T {\tag_if_active:T {\tl_set:Nx\l__gradbars_alt_tl {Legend~categories:~\clist_use:Nn\l__gradbars_names_clist{;~}.} \gradbarsApplyAlt}}} \cs_new_protected:Npn \gradbarsSuspendMeasurementTagging {\cs_if_exist:NT\tag_suspend:n{\tag_suspend:n{gradbars-measurement}}} \cs_new_protected:Npn \gradbarsResumeMeasurementTagging {\cs_if_exist:NT\tag_resume:n{\tag_resume:n{gradbars-measurement}}} \ExplSyntaxOff \endinput