pgfplotstable
allows you to typeset a table in LaTeX without really typing out
the table. The following is a simple example, that converts a CSV into a table:
\documentclass{article}
\usepackage{pgfplotstable,booktabs}
\usepackage{filecontents} % <-- To create files on the fly
\begin{filecontents*}{data.csv}
,M23,F231,M36,F44,F63,M70
M23,1.00,0.81,0.88,0.83,0.41,0.82
F231,,1.00,0.52,0.56,0.25,0.94
M36,,,1.00,0.62,0.94,0.96
F44,,,,1.00,0.43,0.23
F63,,,,,1.00,0.22
M70,,,,,,1.00
\end{filecontents*}
\begin{document}
\pgfplotstabletypeset[
col sep = comma,
string replace*={_}{\textsubscript},
every head row/.style={before row=\toprule,after row=\midrule},
every last row/.style={after row=\bottomrule},
display columns/0/.style={string type,column name={}}
]
{data.csv}
\end{document}
Above, we use the package filecontents
to save the inline data into file
system. This is just a convenient way to present the CSV data in the same LaTeX
code, which normally it should be generated by a separate process. We also note
that, in case of CSV column headers, we often contains underscore which is
a special character in LaTeX. Therefore, we do a string replace on the data. The
rest are just simple table formatting.
More elaborated command to present a table with more formatting:
\usepackage{pgfplotstable}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{colortbl}
\pgfplotsset{compat=1.16}
\setlength\LTleft{0in}
\setlength\LTright{1.25in}
\setlength\LTpre{0cm}
\setlength\LTpost{0in}
\setcounter{LTchunksize}{100}
\pgfplotstabletypeset[
col sep=comma,
outfile=debug.tex,
string replace*={_}{\textsubscript},
begin table=\begin{longtable},
end table=\end{longtable},
font=\footnotesize,
%1000 sep={,},
every head row/.style={
before row={
\caption{My data table} \\
\toprule
&&&&&&&\multicolumn{8}{c|}{FOOs}
&\multicolumn{4}{c|}{BARs}&
\\
},
after row={
\midrule\endhead
\bottomrule\endfoot
},
},
every last row/.style={after row=\bottomrule},
empty cells with={-},
columns/lorem/.style={string type, column type/.add={|}{|}},
columns/ipsum/.style={string type, column type/.add={}{|}},
columns/dolor/.style={string type, column type/.add={}{|}},
columns/sit/.style={string type, column type/.add={}{|}},
columns/amet/.style={string type, column type/.add={}{|}},
columns/FOO-1/.style={fixed, fixed zerofill, dec sep align={|c}, precision=2, column name=$T$, column type/.add={}{}}
columns/FOO-2/.style={fixed, fixed zerofill, dec sep align, precision=2, column name=$T-1$},
columns/FOO-3/.style={fixed, fixed zerofill, dec sep align, precision=2, column name=$T-7$},
columns/FOO-4/.style={fixed, fixed zerofill, dec sep align, precision=2, column name=$T-30$, column type/.add={}{|}},
columns/BAR-1/.style={fixed, fixed zerofill, dec sep align={|c}, precision=4, column name=$T$},
columns/BAR-2/.style={fixed, fixed zerofill, dec sep align, precision=4, column name=$T-30$, column type/.add={}{|}},
columns/Date/.style={string type, column type/.add={}{|}},
]
{data.csv}
Note:
- data is read from file in CSV format by specifying the column separator
col sep=comma
- To save the output of
pgfplotstable
command, we provideoutfile=debug.tex
, this helps debugging the generated table code - Table is created with begin and end command of environment
\begin{longtable}\end{longtable}
- Table font is overridden
- There are two rows of headers: The grouping header is defined manually
- Each column has its type specified (otherwise
pgfplotstable
tend to expect a number), and column type specified to add vertical lines. Column-specific settings are addressed using the column name as defined in the CSV file - Numeric types are presented in fixed point numbers with specified precision.
They are also aligned at the decimal point with
dec sep align
option. In case the column header needs a special type other thanc
, it is specified asdec sep align={|c}
- Data column type (which is different from header in case of
dec sep align
) is overridden withcolumn type/.add={}{|}
We can further add coloring to header rows:
\usepackage[table]{xcolor}
\definecolor{mycolor}{HTML}{D9F8C7}
\pgfplotstabletypeset[
every head row/.style={
before row={
\caption{My data table} \\
\hline
\rowcolor{mycolor}
&&&&&&&\multicolumn{8}{c|}{\textbf{Foos}}
&\multicolumn{4}{c|}{\textbf{BARs}}&
\\
\rowcolor{mycolor}
},
after row={
\hline\endhead
\hline\endfoot
\showrowcolors
},
},
columns={Lorem, ipsum, dolor, sit, amet, FOO-1, FOO-2, ...}
]{...}
Above we use the xcolor
package with table
option to introduce commands
like \rowcolor
and \cellcolor
. We also use columns={...}
to select only a
subset of columns to print instead of everything from the input CSV.
When we use the pgfplotstable
for slightly more complicated table, we will
find that the dec sep align
can be problematic to use because this will
convert into two adjacent columns for the integer part and decimal part of a
numeric column. For example, if we want to color a column, it will not be easy
to get both columns right, not the mention that when we have multicolumn (such
as a group header), we have to count each column as two. Alternative to
dec sep align
is to make the column in fixed precision and right-aligned:
columns/FOO/.style = {fixed, fixed zerofill, precision=2, column name=$FOO_1$, column type={r}},
For column color, sometimes it is more convenient to define a new column type:
\newcolumntype{x}{>{\columncolor{myColor}}r}
...
columns/BAR/.style = {fixed, fixed zerofill, precision=2, column name=$BAR^1$, column type={x}},
Heat map on table
A greater challenge in using pgfplotstable
is to color the table cells with
heat map. First, this is how to get value of another cell on the same row,
which will make LaTeX slow:
\pgfplotstablegetelem{\pgfplotstablerow}{AnotherColumn}\of\mytable
The table \mytable
have to be registered first. The heat map is
defined as a spectrum of color and interpolated using a number between
a pair of predefined min and max value:
\pgfplotsset{
colormap={redgreen}{
rgb255=(223,101,128) % red
rgb255=(255,255,255) % white
rgb255=(217,240,163) % green
}
}
Then we can color the cell with \cellcolor
. Below is a full example, with the
special tweak to put a dash on an empty cell:
\documentclass[8pt]{extarticle}
% page formatting packages
\usepackage{geometry}
\usepackage{fancyhdr}
\geometry{letterpaper, landscape, top=1in, bottom=1in, right=0.3in, left=0.3in}
\fancypagestyle{front}{
\fancyhf{}
\lhead{\today}
\chead{Example}
\rhead{}
\renewcommand{\headrulewidth}{0pt}
}
\pagestyle{front}
\usepackage[table]{xcolor}
\definecolor{headerShade}{HTML}{D9F0D3}
\definecolor{columnGray}{gray}{0.90}
% table typesetting packages
\usepackage{pgfplotstable}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{colortbl}
\usepackage{array}
\pgfplotsset{compat=1.16}
\setlength\LTleft{0in}
\setlength\LTright{1.25in}
\setlength\LTpre{0cm}
\setlength\LTpost{0in}
\setcounter{LTchunksize}{100}
\newcolumntype{x}{>{\columncolor{columnGray}}r}
\newcolumntype{y}{>{\columncolor{columnGray}}c}
\newcolumntype{?}{!{\vrule width 1pt}}
% color map -- please use ColorBrewer to pick a more appealing color
\pgfplotsset{
colormap={redgreen}{
rgb255=(223,101,128) % red
rgb255=(255,255,255) % white
rgb255=(217,240,163) % green
}
}
% font spec
%\usepackage{fontspec}
%\defaultfontfeatures{Mapping=tex-text}
%\setmainfont[Ligatures=TeX]{Inconsolata}
\usepackage{mathspec}
\setallmainfonts(Digits,Latin){Inconsolata}
\setlength{\parindent}{0pt}
\setlength{\parskip}{1em}
\begin{document}
\pgfplotstableread[col sep=comma]{data.csv}\mytable
\pgfplotstabletypeset[
col sep=comma,
outfile=debug.tex,
string replace*={_}{\textsubscript},
begin table=\begin{longtable},
end table=\end{longtable},
font=\footnotesize,
every head row/.style={
before row={
\caption{Everything} \\
\rowcolor{headerShade}
&&&&&&\multicolumn{2}{c?}{\textbf{FOO}}&
\\
\rowcolor{headerShade}
},
after row={
\endhead
\hline\endfoot
\showrowcolors
},
},
every last row/.style={after row=\hline},
empty cells with={-},
columns={
lorem, ipsum, dolor, sit, consectetur, adipiscing, FOO1, FOO2, Date
},
columns/lorem/.style={string type, column type={c}},
columns/ipsum/.style={string type, column type={y}},
columns/dolor/.style={string type, column type={c}},
columns/sit/.style={string type, column type={y}},
columns/consectetur/.style={fixed, fixed zerofill, precision=2, column type={x},
column type/.add={?}{},
postproc cell content/.code={%
\begingroup
% read the relval
\pgfplotstablegetelem{\pgfplotstablerow}{heatConsectetur}\of\mytable%
\let\value=\pgfplotsretval%
\ifx\value\empty%
\pgfmathfloatparsenumber{0.5}%
\pgfmathfloattofixed{\pgfmathresult}%
\let\value=\pgfmathresult
\fi%
% map that value: \pgfmathresult then contains {<R>,<G>,<B>}
\pgfplotscolormapaccess[0.0:1.0]{\value}{redgreen}%
% acquire the display value AFTER any preprocessor or typesetter
\pgfkeysgetvalue{/pgfplots/table/@cell content}\typesetvalue
% tex-expansion control
\toks0=\expandafter{\typesetvalue}%
\xdef\temp{%
\noexpand\pgfkeysalso{%
@cell content={%
\noexpand\cellcolor[rgb]{\pgfmathresult}%
\the\toks0 %
}%
}%
}%
\endgroup
\temp
}%
},
columns/adipiscing/.style={fixed, fixed zerofill, precision=2, column type={x},
column type/.add={}{?},
postproc cell content/.code={%
\begingroup
% read the relval
\pgfplotstablegetelem{\pgfplotstablerow}{heatAdipiscing}\of\mytable%
\let\value=\pgfplotsretval%
\ifx\value\empty%
\pgfmathfloatparsenumber{0.5}%
\pgfmathfloattofixed{\pgfmathresult}%
\let\value=\pgfmathresult
\fi%
% map that value: \pgfmathresult then contains {<R>,<G>,<B>}
\pgfplotscolormapaccess[0.0:1.0]{\value}{redgreen}%
% acquire the display value AFTER any preprocessor or typesetter
\pgfkeysgetvalue{/pgfplots/table/@cell content}\typesetvalue
% tex-expansion control
\toks0=\expandafter{\typesetvalue}%
\xdef\temp{%
\noexpand\pgfkeysalso{%
@cell content={%
\noexpand\cellcolor[rgb]{\pgfmathresult}%
\the\toks0 %
}%
}%
}%
\endgroup
\temp
}%
},
columns/FOO1/.style={fixed, fixed zerofill, precision=4, column name=$T$, column type={x},
postproc cell content/.code={%
\begingroup
% read the relval
\pgfplotstablegetelem{\pgfplotstablerow}{heatFOO1}\of\mytable%
\let\value=\pgfplotsretval%
\ifx\value\empty%
\pgfmathfloatparsenumber{0.5}%
\pgfmathfloattofixed{\pgfmathresult}%
\let\value=\pgfmathresult
\fi%
% map that value: \pgfmathresult then contains {<R>,<G>,<B>}
\pgfplotscolormapaccess[0.0:1.0]{\value}{redgreen}%
% acquire the display value AFTER any preprocessor or typesetter
\pgfkeysgetvalue{/pgfplots/table/@cell content}\typesetvalue
% tex-expansion control
\toks0=\expandafter{\typesetvalue}%
\xdef\temp{%
\noexpand\pgfkeysalso{%
@cell content={%
\noexpand\cellcolor[rgb]{\pgfmathresult}%
\the\toks0 %
}%
}%
}%
\endgroup
\temp
}%
},
columns/FOO2/.style ={fixed, fixed zerofill, precision=4, column name=$T^2$, column type={x},
column type/.add={}{?},
postproc cell content/.code={%
\begingroup
% read the relval
\pgfplotstablegetelem{\pgfplotstablerow}{rvWAS-30}\of\mytable%
\let\value=\pgfplotsretval%
\ifx\value\empty%
\pgfmathfloatparsenumber{0.5}%
\pgfmathfloattofixed{\pgfmathresult}%
\let\value=\pgfmathresult
\fi%
% map that value: \pgfmathresult then contains {<R>,<G>,<B>}
\pgfplotscolormapaccess[0.0:1.0]{\value}{redgreen}%
% acquire the display value AFTER any preprocessor or typesetter
\pgfkeysgetvalue{/pgfplots/table/@cell content}\typesetvalue
% tex-expansion control
\toks0=\expandafter{\typesetvalue}%
\xdef\temp{%
\noexpand\pgfkeysalso{%
@cell content={%
\noexpand\cellcolor[rgb]{\pgfmathresult}%
\the\toks0 %
}%
}%
}%
\endgroup
\temp
}%
},
columns/Date/.style={string type, column type={c}},
]\mytable
\end{document}