28

In a plot, I have several vertically distributed nodes containing numbers with different numbers of digits before and after the decimal separator, and a trailing percent sign.

I would like to align these nodes horizontally along the decimal separator, similar to what can be done using the S column type in tables using the siunitx package. However, I do not want to use a table for the alignment, since the nodes are unevenly spaced vertically.

How can I align these nodes properly? I thought about somehow adding space before the numbers depending on the number of digits, but couldn't think of an elegant way of doing that without lots of manual work.

Here's a MWE:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\begin{document}
What I have:

\begin{tikzpicture}
\begin{axis}[
    ymode=log,
    height=4cm, width=8cm,
    domain=1:10,
    axis lines=left,
    clip=false
]
\pgfplotsinvokeforeach{0.01, 0.1, 1, 10, 100}{
    \addplot [black] {#1*x} node [anchor=west] {#1\,\%};
}
\end{axis}
\end{tikzpicture}

What I want:

\begin{tikzpicture}
\begin{axis}[
    ymode=log,
    domain=1:10,
    height=4cm, width=8cm,
    axis lines=left,
    clip=false
]
\addplot [black] {x*0.01} node [anchor=west] {\hphantom{10}0.01\,\%};
\addplot [black] {x*0.1} node [anchor=west] {\hphantom{10}0.1\,\%};
\addplot [black] {x*1} node [anchor=west] {\hphantom{00}1\,\%};
\addplot [black] {x*10} node [anchor=west] {\hphantom{0}10\,\%};
\addplot [black] {x*100} node [anchor=west] {100\,\%};
\end{axis}
\end{tikzpicture}
\end{document}
1
  • 1
    The siunitx package provides a macro for table-like output of numbers: \tablenum[table-format=3.2]{#1}\,\% However, this also aligns the % sign. Commented Jan 2, 2013 at 3:03

2 Answers 2

21

You can insert a padding command such as the following:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\makeatletter
\def\pad#1{\xpad#1.\relax#1\,\%}

\def\xpad#1.#2\relax{%
\ifnum0#1<10 \phantom{0}\fi
\ifnum0#1<100 \phantom{0}\fi
}

\makeatother

\begin{document}
What I have:

\begin{tikzpicture}
\begin{axis}[
    ymode=log,
    height=4cm, width=8cm,
    domain=1:10,
    axis lines=left,
    clip=false
]
\pgfplotsinvokeforeach{0.01, 0.1, 1, 10, 100}{
    \addplot [black] {#1*x} node [anchor=west] {\pad{#1}};
}
\end{axis}
\end{tikzpicture}

\end{document}

or this version which takes a parameter for the number of digits to pad:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\makeatletter
\def\pad#1#2{\xpad#1#2.\relax#2\,\%}

\def\xpad#1#2.#3\relax{%
\count@#1\relax
\@tempcnta\@ne\relax
\loop
\ifnum\count@>\z@
\advance\count@\m@ne
\multiply\@tempcnta 10\relax
\ifnum0#2<\@tempcnta \phantom{0}\fi
\repeat
}

\makeatother

\begin{document}
What I have:

\begin{tikzpicture}
\begin{axis}[
    ymode=log,
    height=4cm, width=8cm,
    domain=1:10,
    axis lines=left,
    clip=false
]
\pgfplotsinvokeforeach{0.01, 0.1, 1, 10, 100}{
    \addplot [black] {#1*x} node [anchor=west] {\pad{2}{#1}};
}
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[
    ymode=log,
    height=4cm, width=8cm,
    domain=1:10,
    axis lines=left,
    clip=false
]
\pgfplotsinvokeforeach{0.01, 0.1, 1, 10, 100}{
    \addplot [black] {#1*x} node [anchor=west] {\pad{3}{#1}};
}
\end{axis}
\end{tikzpicture}

\end{document}
3
  • Ah yes, that looks pretty good, thank you! Is there a way of making this a bit more flexible regarding the number of digits to be added? What if I decide to add another plot with a label of 10000, for example?
    – Jake
    Commented Jan 1, 2013 at 23:52
  • @Jake you can also count the digits with David's wizardry or say, via xstring's \Strlen
    – percusse
    Commented Jan 1, 2013 at 23:54
  • well yes you just need an input parameter that gives the number of digits that you are padding (so 2 in the MWE) give me a minute... Commented Jan 1, 2013 at 23:55
18

Here's a solution with LaTeX3:

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\pad}{O{3} >{\SplitArgument{1}{.}}m }
 {
  \leavevmode % because of `\hphantom`
  \jake_pad:nnn {#1} #2
 }
\cs_new_protected:Npn \jake_pad:nnn #1 #2 #3
 {
  \int_step_inline:nnnn { #1 - 1 } { -1 } { 1 }
   { \int_compare:nT { #2 < 1 \prg_replicate:nn { ##1 } { * 10 } } { \hphantom{0} } }
  #2\IfValueT{#3}{.#3}
 }
\ExplSyntaxOff

You use it as

\pad{10}\,\%

for padding to three digits, or

\pad[5]{1234}

for padding to five digits.

Example:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\pad}{O{3} >{\SplitArgument{1}{.}}m }
 {
  \leavevmode % for \hphantom
  \jake_pad:nnn {#1} #2
 }
\cs_new_protected:Npn \jake_pad:nnn #1 #2 #3
 {
  \int_step_inline:nnnn { #1 - 1 } { -1 } { 1 }
   { \int_compare:nT { #2 < 1 \prg_replicate:nn { ##1 } { * 10 } } { \hphantom{0} } }
  #2\IfValueT{#3}{.#3}
 }
\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\begin{axis}[
    ymode=log,
    height=4cm, width=8cm,
    domain=1:10,
    axis lines=left,
    clip=false
]
\pgfplotsinvokeforeach{0.01, 0.1, 1, 10, 100}{
    \addplot [black] {#1*x} node [anchor=west] {\pad{#1}\,\%};
}
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

1
  • The maximum number of digits for the integer part is 10.
    – egreg
    Commented Jan 2, 2013 at 0:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .