14

One thing annoying in sparklines is its verbosity and dependence on external arithmetics. For example, to depict a three bar graph of 16%, 53%, 31%, one has to write:

\begin{sparkline}{4}
  \sparkspike .166 .302
  \sparkspike .500 1
  \sparkspike .834 .585 
\end{sparkline}

I would prefer:

\threesparkline{0.16}{0.53}{0.31}

So my main question is can I do basic arithmetic in LaTeX, like dividing and multiplying numbers, finding the max among three parameters, etc?

Alternatively, is there a better way of using sparklines that I've missed?

UPDATE:

After the sugestion of using the calc package, I'm stuck with the following attempt which yields an error in \real and \ratio:

\newcommand{\threespike}[3]{
    \newcounter{max}\setcounter{max}{\maxof{\maxof{\real{#1}}{\real{#2}}}{\real{#3}}}
    \newcounter{a}\setcounter{a}{\ratio{\real{#1}}{max}}
    \newcounter{b}\setcounter{b}{\ratio{\real{#2}}{max}}
    \newcounter{c}\setcounter{c}{\ratio{\real{#3}}{max}}    
    \begin{sparkline}{4}
      \sparkspike .166 a
      \sparkspike .500 b
      \sparkspike .834 c 
    \end{sparkline}
}

UPDATE2:

I eventually got to make \ratio work directly like this:

\newcommand{\ratiofivespark}[7]{
    \begin{sparkline}{6}
      \sparkspike .1 \ratio{#2}{#1}
      \sparkspike .3 \ratio{#3}{#1}
      \sparkspike .5 \ratio{#4}{#1}
      \sparkspike .7 \ratio{#5}{#1}
      \sparkspike .9 \ratio{#6}{#1} 
    \end{sparkline}
}

Where the first parameter passed establishes the full height of a bar. See the accepted answer for more powerful LaTeX-Fu!

7
  • How did you arrive at the numbers .166, .500, and .834? Why do you want the 53% to be the max height? Doesn't that make multiple bar graphs incomparable? Why do you want the 3 to be an optional argument? It seems like it would be required.
    – TH.
    Aug 26, 2010 at 23:02
  • (i) .166 .500 and .834 are the middle positions of a 5pt \sparkspikewidth with some padding (ii) in this particular case, the comparasion isn't among several bar graphs, but in the relative ratio among each bar (iii) true! 3 is a required argument. An even better solution would be \dosparkline{0.16, 0.53, 0.31}, but I believe latex doesn't support arrays? Aug 26, 2010 at 23:31
  • 1
    I guess what I was asking was what computation did you perform to arrive at those three numbers, but if you only ever want 3, then it's not really an issue. Counters only work with integers and I'm pretty sure that \ratio is expecting the ratio of two integers. You also need something like \arabic{foo} to use that counter, you can't just write foo. So, what you want requires a bit more work. As for arrays, there's no reason that that couldn't be parsed, but it'd require more work still.
    – TH.
    Aug 27, 2010 at 5:41
  • 1
    Just an extremely minor and excessively picky point: having never heard of "sparklines", I misread the first sentence as "One thing annoying in sparkliness" and was wondering about why I'd never thought of LaTeX as being "sparkly" before! It's useful to make package names stand out in some way, often we do this by making them look like code: sparklines. Aug 27, 2010 at 8:24
  • I too read it as sparkliness to begin with. You have to admit, it's catchy. =)
    – TH.
    Aug 27, 2010 at 8:58

2 Answers 2

5

You can certainly do basic arithmetic in LaTeX. You have several options. You can use the standard TeX \advance, \multiply, and \divide. You can use the calc package for a more natural way of doing arithmetic (although, I find I don't use it). You can also use the e-TeX extension \numexpr ... \relax.

Edit: Okay. I think I've got a solution for you.

\documentclass{article}
\usepackage{sparklines}
\usepackage{fp}
\newcount\slnum
\makeatletter
\newcommand\dosparkline[2][4]{%
        \FPset\slmax{0}%
        \FPset\slpos{0}%
        \slnum0
        \slparse#2,\relax
        \FPadd\sladvance{1}{\the\slnum}%
        \FPdiv\sladvance{1}\sladvance
        \count@\slnum
        \loop\ifnum\count@>0
                \advance\count@-1
                \FPdiv\sltemp{\csname sl@\the\count@\endcsname}\slmax
                \expandafter\let\csname sl@\the\count@\endcsname\sltemp
        \repeat
        \begin{sparkline}{#1}
                \count@0
                \loop\ifnum\count@<\slnum
                        \FPadd\slpos\slpos\sladvance
                        % The {} are necessary
                        \sparkspike \slpos{} \csname sl@\the\count@\endcsname{}
                        \advance\count@1
                \repeat
        \end{sparkline}
}
\def\slparse#1,#2\relax{%
        \FPset\sltemp{#1}%
        \FPmax\slmax\slmax\sltemp
        \expandafter\let\csname sl@\the\slnum\endcsname\sltemp
        \advance\slnum1
        \ifx\relax#2\relax\else
                \slparse#2\relax
        \fi
}
\makeatother
\begin{document}
\dosparkline[10]{16,53,31,25,10,45}

\dosparkline{.16,.53,.31}
\begin{sparkline}{4}
  \sparkspike .166 .302
  \sparkspike .500 1
  \sparkspike .834 .585 
\end{sparkline}

\end{document}

The first \dosparkline shows the optional argument which is the width (in ex of all things!). The second one shows what you asked for which you can compare without the output of yours. You'll note I didn't match your spacing. You can play around with that by changing how \sladvance is computed.

3
  • That was powerful! Have you considered contributing to the package? :-) Aug 27, 2010 at 14:37
  • Contributing to sparklines? I'd never heard of it until I read this question.
    – TH.
    Aug 27, 2010 at 19:39
  • This solution does not work any more.... (for me) Feb 17, 2016 at 21:15
5

For calculations using real numbers, take a look at the fp package. If you are using LuaTeX then escaping to Lua is going to be the best approach.

2
  • Oh, that is really excellent. I've lamented TeX's lack of floating point calculations.
    – TH.
    Aug 27, 2010 at 5:58
  • I'm currently writing a module for LaTeX3 based on the fp package (but using floating points). This is an effort, so I too regard the lack of floating point arithmetic as a pain :-)
    – Joseph Wright
    Aug 27, 2010 at 7:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.