45

I have recently started using the tufte-latex package for various science writing and, while I love the package generally, am dismayed that it does not include the ability to produce graphics (charts, sparklines, etc.) in the style of Tufte. While his typesetting is wonderful, it seems to me that the plots are the primary focus of his work.

Is there a readily available package that allows for easy production of Tufte-style plots? Perhaps using pgfplots or sageTeX?

2
  • 7
    The sparkline package is addressed to producing spark lines. :)
    – egreg
    Sep 23, 2011 at 15:56
  • @egreg: Maybe that should be an ansewr. :)
    – bcat
    Sep 23, 2011 at 18:48

3 Answers 3

49

The pgfplots package can do a lot of plotting stuff.

In contrast to the simpler sparkline package, it supports arbitrary input data - which might be given by some math expressions or table data (which might be interesting for statistical applications). It also comes with pgfplotstable which allows some automatic rounding of such tables.

In fact, I believe that I came across a solution by someone who produced pretty sparklines side-by-side using pgfplots and some table solution (looked pretty cool). If someone happens to know what I saw, this might be an interesting solution approach here (but I do not know where it is).

From my point of view, a usable solution for sparklines with pgfplots would need:

  • some styles adjustments
  • a little bit code to place start- and end nodes (together with their coordinate values)
  • a little bit math to compute min and max.

Here is the the output of an experiment this evening:

enter image description here

The source code is

% This is an experiment with a sparkline implementation based on
% pgfplots.
%
\documentclass[a4paper]{article}

\usepackage{pgfplots}


% BEGIN OF STYLE DEFINITION FOR sparkline:
\makeatletter
\usetikzlibrary{positioning}
\colorlet{sparkcolor}{red!80!black}
\colorlet{minmaxcolor}{blue!80!black}
\pgfplotsset{
    every spark line/.style={
        hide axis,
        clip=false,
        bar width=2pt,
        cycle list={blue,mark=none\\},
        height=0.8\baselineskip,
        anchor=south west,
        width=5\baselineskip,
        scale only axis,
        filter point/.code={%
            \xdef\sparklinex{\pgfkeysvalueof{/data point/x}}%
            \xdef\sparkliney{\pgfkeysvalueof{/data point/y}}%
            \pgfplotscoordmath{default}{parsenumber}{\sparklinex}%
            \let\sparklinex@=\pgfmathresult
            \pgfplotscoordmath{default}{parsenumber}{\sparkliney}%
            \let\sparkliney@=\pgfmathresult
            \ifnum\coordindex=0
                \global\let\sparklineSTARTx\sparklinex
                \global\let\sparklineSTARTy\sparkliney
                \global\let\sparklineMINx\sparklinex
                \global\let\sparklineMINy\sparkliney
                \global\let\sparklineMINy@\sparkliney@
                %
                \global\let\sparklineMAXx\sparklinex
                \global\let\sparklineMAXy\sparkliney
                \global\let\sparklineMAXy@\sparkliney@
            \else
                \pgfplotscoordmath{default}{if less than}{\sparkliney@}{\sparklineMINy@}{%
                    \global\let\sparklineMINx\sparklinex
                    \global\let\sparklineMINy\sparkliney
                    \global\let\sparklineMINy@\sparkliney@
                }{}%
                \pgfplotscoordmath{default}{if less than}{\sparklineMAXy@}{\sparkliney@}{%
                    \global\let\sparklineMAXx\sparklinex
                    \global\let\sparklineMAXy\sparkliney
                    \global\let\sparklineMAXy@\sparkliney@
                }{}%
            \fi
            \global\let\sparklineENDx\sparklinex
            \global\let\sparklineENDy\sparkliney
        },
        extra description/.code={%
            \node[begin node description]  {\pgfkeysvalueof{/pgfplots/begin node text}};
            \node[end node description]    {\pgfkeysvalueof{/pgfplots/end node text}};
        },
    },
    spark std max/.initial=,
    spark std min/.initial=,
    /tikz/spark std region/.style={fill=gray!10},
    begin node text/.initial=\pgfmathprintnumber{\sparklineSTARTy},
    end node text/.initial=  \pgfmathprintnumber{\sparklineENDy},
    /tikz/begin node description/.style={
        text width=3em,align=right,
        base left,sparkcolor,
        /pgf/number format/fixed,
        /pgf/number format/fixed zerofill,
        /pgf/number format/showpos,
        at={(current axis.south west)},
    },
    /tikz/end node description/.style={
        base right,sparkcolor,
        /pgf/number format/fixed,
        /pgf/number format/fixed zerofill,
        /pgf/number format/showpos,
        at={(current axis.south east)},
    },
    sparkline nodes/.initial={%
        node[begin node] at (axis cs:\sparklineSTARTx,\sparklineSTARTy) {}
        node[end node]   at (axis cs:\sparklineENDx,\sparklineENDy) {}
        node[min node]   at (axis cs:\sparklineMINx,\sparklineMINy) {}
        node[max node]   at (axis cs:\sparklineMAXx,\sparklineMAXy) {}
    },
    /tikz/spark marker/.style={
        circle,
        inner sep=1pt,
    },
    /tikz/begin node/.style={
        spark marker,
        fill=sparkcolor,
    },
    /tikz/end node/.style={
        spark marker,
        fill=sparkcolor,
    },
    /tikz/min node/.style={
        spark marker,
        fill=minmaxcolor,
    },
    /tikz/max node/.style={
        spark marker,
        fill=minmaxcolor,
    },
}

\def\sparkline{\pgfutil@ifnextchar[{\sparkline@opt}{\sparkline@opt[]}}%
\long\def\sparkline@opt[#1]#2;{%
    \begin{tikzpicture}[baseline]
    \begin{axis}[every spark line,#1]
        \begin{scope}[yshift=-0.2\baselineskip]
        \pgfplotsextra{
            \pgfkeysgetvalue{/pgfplots/spark std min}\sparkstdmin
            \pgfkeysgetvalue{/pgfplots/spark std max}\sparkstdmax
            \ifx\sparkstdmin\empty
            \else
                \ifx\sparkstdmax\empty
                \else
                    \fill[spark std region]
                         (axis cs:\sparklineSTARTx,\sparkstdmax) rectangle (axis cs:\sparklineENDx,\sparkstdmin);
                \fi
            \fi
        }
        \addplot #2 \pgfkeysvalueof{/pgfplots/sparkline nodes};
        \end{scope}
    \end{axis}
    \end{tikzpicture}%
}

\makeatother
% END OF STYLE DEFINITIONS

\begin{document}

\thispagestyle{empty}

\pgfplotsset{
    spark std min=-0.5,
    spark std max=0.5,
    /pgf/number format/fixed,
    /pgf/number format/fixed zerofill,
    /pgf/number format/showpos,
}

Stock A \sparkline {rand} ; 
min = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMINy}, max = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMAXy}

Stock B \sparkline {rand} ;
min = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMINy}, max = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMAXy}

Stock C \sparkline table[row sep=\\] {
x y\\
0 0\\
0.1 0.1\\
0.2 0.6\\
0.3 -0.3\\
0.4 -1.5\\
0.5 -0.4\\
0.6 0\\
};
min = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMINy}, max = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMAXy}

Stock D \sparkline[ybar,samples=15] {rand} ; 
min = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMINy}, max = \textcolor{minmaxcolor}{\pgfmathprintnumber\sparklineMAXy}
\end{document}

My idea is to define a macro \sparkline <coordinate input> ; which expects one of the different <coordinate input>s of pgfplots, as \addplot {rand}; or \addplot table (which are used above). I should note that in my case above, the space between {rand} and ; is mandatory (due to some expansion issue).

My idea is to use \baselineskip to determine the sparkline's dimensions (which, however, appears to cause problems inside of tabular!?).

The rest of the user interface is given by the options spark std min and spark std max which configure the gray background area.

Within this solution, all other things could be configured by means of styles.

See also http://pgfplots.sourceforge.net/pgfplots.pdf

10
  • Great answer! Since there's examples of bar diagrams in the sparklines manual it might make sense that you included some in your answer too.
    – N.N.
    Sep 23, 2011 at 19:26
  • I have added an example using bar plots. I also fixed a couple of bugs (like using fixed zerofill instead of fixed,fixed zerofill and showing the same start-and end coordinate in the texts). Sep 23, 2011 at 19:39
  • Very interesting and useful, thanks. I might make use of some of that but I am still a bit disappointed that there isn't a coherent package with set defaults so I could just type something like \binary_plot{[x_1,x_2,x_3]} and get the plot he suggests for sports scores. I actually implemented this plot in a sage script, which can easily be incorporated with sageTeX, but I am not good enough at programing to make a serious go at a comprehensive package. Sep 23, 2011 at 19:56
  • Perhaps there is some kind of "coherent package with set defaults" around which does the job correctly. You may want to wait before you accept the answer. Perhaps someone wrote one with pstricks? I am aware of the fact that my answer is more a starting point than a fully satisfactory solution (and, of course, only for sparklines). Sep 23, 2011 at 20:11
  • Hi, I tried this today. The plotting works great and I look forward to use it in practice. Only the background gray bars seem off to me; or I don't understand how they are supposed to work. We set std min / max = 0.5 / -0.5. However the rectangle seems to start at 0 on the lower end. I experimented a bit and it appears that it has to do with negative numbers somehow. Do you have an idea? Nov 2, 2014 at 20:25
14

I'd suggest you go with Christian Feuersänger answer but I'd also like to note that there's the path egreg mentioned in a comment.

There's the package called sparklines.

\documentclass{tufte-handout}

\usepackage{sparklines}

\begin{document}

A sparkline
\begin{sparkline}{10}
\sparkrectangle 0.3 0.8
\sparkdot 0.5 0.62 blue
\sparkdot 1 0.2 red
\spark 0.1 0.95
0.6 0.7
0.2 0.8 0.3 0.3 0.4 0.52 0.5 0.62
0.7 0.5 0.8 0.4 0.9 0.25 1 0.2 /
\end{sparkline}.
and another
\begin{sparkline}{4}
\sparkspike .083 .18
\sparkspike .25 .55
\sparkspike .417 1
\sparkspike .583 .62
\sparkspike .75 .42
\sparkspike .917 .5
\end{sparkline}.

\end{document}

Two sparklines

2
  • Yeah, that is nice too, though I'd really love to see things like the rug plots and such. I'm better acquainted with sage than with pgfplots and I might implement a few of his plots. If they get good enough, I might post them somewhere. Sep 24, 2011 at 12:24
  • 1
    @AdamRedwine If it were me I would make my plots in another software (R does rugplots nicely) and just includegraphics. After all, TeX doesn't specialise in graphics. Sep 25, 2013 at 5:54
5

Although it appears that there aren't any readymade packages specifically for LaTeX, depending on which math/graphics package you use, there might be alternatives.

For example, the sagemath program provides a ready interface to LaTeX through it's sageTeX module and renders 2D plots with the Matplotlib library. Options passed on to plots that do not have meaning in Sage will be passed to Matplotlib so it is then possible to use packages like etframes to get tufte style plots. Though I only recently came across this package, I'll add more if I find them as I do research.

You must log in to answer this question.

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