15

I'm using booktabs to display some profiling data. I would like to add bars to each row to visually indicate the quantities in one column.

I would like to use a table instead of a barchart since there are additional columns that don't require visualisation.

Screenshot

Screenshot from vtune illustrating what I am looking for.

Could I maybe draw inside a cell using tikz? Or do I need to abandon the table and wrangle a pgfplots barchart to look like a table?

John
  • 579

4 Answers4

17

How about something like this:

\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{array}
\usepackage{xcolor}
\def\mybar#1{%%
  #1s & {\color{red}\rule{#1cm}{8pt}}}

\pagestyle{empty}
\begin{document}

\begin{tabular}{>{$\rhd$ }lrl}
Loop at line 151 in divergence  & \mybar{3.420}\\
Loop at line 1071 in radiation  & \mybar{3.270}\\
scalar face value               & \mybar{3.090}\\
Loop at line 102 in get         & \mybar{1.700}\\
get sensible enthalpy           & \mybar{1.250}\\
\end{tabular}

\end{document}

enter image description here

A.Ellett
  • 50,533
13

Example using TikZ:

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage{lmodern}

\usepackage{url}
\DeclareUrlCommand\function{\urlstyle{sf}}

\usepackage{xcolor}
\usepackage{tikz}
\usepackage{booktabs}
\usepackage{array}
\usepackage{multirow}
\usepackage{siunitx}

\definecolor{chart Idle}{gray}{.6}
\definecolor{chart Poor}{RGB}{242,28,28}
\definecolor{chart Ok}{RGB}{248,172,37}
\definecolor{chart Ideal}{RGB}{1,151,0}
\definecolor{chart Over}{RGB}{0,125,234}

\newdimen\tempdim
\newcommand*{\Triangle}{%
  \settoheight{\tempdim}{L}%
  \tikz[x=\tempdim, y=\tempdim]\draw(0,0) -- (.5,.5) -- (0,1) --cycle;%
}
\newcommand*{\ChartLegend}[1]{%
  \ifdim\lastkern=1sp %
    \hspace{1em}%
  \fi
  \ChartBox{0.75em}{#1}%
  \,#1%
  \kern-1sp\kern1sp\ignorespaces
}
\newcommand*{\ChartBox}[2]{%
  \begingroup
    \settoheight{\tempdim}{L}%
    \edef\tempheight{\the\tempdim}%
    \settodepth{\tempdim}{g}%
    \edef\tempdepth{\the\tempdim}%
    \tikz[
      baseline=0pt,
      inner sep=0pt,
    ]
    \node[
      fill={chart #2},
      draw,
      rounded corners=1pt,
      anchor=base,
    ]{%
      \vphantom{g\"A}%
      \pgfmathsetlength{\tempdim}{#1}%
      \kern\tempdim\relax
    };%
  \endgroup
}

\begin{document}
\sffamily
\renewcommand*{\arraystretch}{1.2}
\newcommand*{\chart}[2]{%
  #1 & \ChartBox{55mm/3.420*#1}{#2}%
}
\noindent
\begin{tabular}{>{\Triangle\,}lS[mode=text,detect-family,table-format=1.3]@{\,s~}l}
\toprule
\multicolumn{1}{c}{%
  \multirow{2}{*}{Source Function\,/\,Function\,/\,Call Stack}%
}&
  \multicolumn{2}{c}{CPU Time by Utilization}\\
\multicolumn{1}{c}{}& \multicolumn{2}{l}{%
  \ChartLegend{Idle}
  \ChartLegend{Poor}
  \ChartLegend{Ok}
  \ChartLegend{Ideal}
  \ChartLegend{Over}
}\\
\midrule
\relax[Loop at line 151 in \function{divergence_part_1}] &
  \chart{3.420}{Poor} \\
\relax[Loop at line 1071 in \function{radiation_fvm}] &
  \chart{3.270}{Poor} \\
\function{scalar_face_value} &
  \chart{3.090}{Poor} \\
\relax[Loop at line 102 in \function{get_match}] &
  \chart{1.700}{Poor} \\
\function{get_sensible_enthalpy_diff} &
  \chart{1.250}{Poor} \\
\function{compare_vec3} &
  \chart{1.140}{Poor} \\
\bottomrule
\end{tabular}
\end{document}

Result

Heiko Oberdiek
  • 271,626
  • I am utterly amazed at this faithful and beautiful reproduction. But I'm accepting the simpler solution. – John Apr 25 '14 at 14:10
8

Example using PGFPlots (adapted from Pgfplots: plot graph inside table) , which takes care of the scaling and lets you generate the table and graph from a datafile:

\documentclass{article}
\usepackage{booktabs}
\usepackage{multirow}
\usepackage{pgfplotstable}
\usepackage{filecontents}

% The data file
% In a real application, this would be a text file in your file system
\begin{filecontents}{data.txt}
function,cpu time
Loop at line 151,3.42
Loop at line 107,3.27
Scalar face value,3.09
Loop at line 102,1.7
Get sensible enthalpy,1.25
Compare vec3,1.14
\end{filecontents}


\pgfplotstableread[col sep=comma]{data.txt}\data

% Define the command for the plot
\newcommand{\errplot}{%
\begin{tikzpicture}[trim axis right]
\begin{axis}[y=-\baselineskip,
  scale only axis,
  width=5cm,
  enlarge y limits={abs=0.5},
  axis y line*=middle,
  ytick=\empty,
  axis x line*=bottom,
  xbar,
  bar width=1.5ex,
  xmin=0,
  visualization depends on=x \as \rawx,
  nodes near coords,
  every node near coord/.style={
    anchor=east,
    shift={(axis direction cs:-\rawx,0)}
  }
 ]
% 

\addplot [draw=black, fill=red]
table [x=cpu time,y expr=\coordindex]{\data};
\end{axis}
\end{tikzpicture}%
}

\begin{document}

% Get number of rows in datafile
\pgfplotstablegetrowsof{\data}
\let\numberofrows=\pgfplotsretval

% Print the table
\pgfplotstabletypeset[columns={function, cpu time},
  % Booktabs rules
  every head row/.style={before row=\toprule,after row=\midrule},
  every last row/.style={after row=[3ex]\bottomrule},
  % Set header name
  columns/function/.style={string type,column type=l,column name=Function},
  columns/cpu time/.style={
    column name={CPU Time},
    assign cell content/.code={% use \multirow for Z column:
    \ifnum\pgfplotstablerow=0
    \pgfkeyssetvalue{/pgfplots/table/@cell content}
    {\multirow{\numberofrows}{6.5cm}{\errplot}}%
    \else
    \pgfkeyssetvalue{/pgfplots/table/@cell content}{}%
    \fi
    }
  },
]{\data}
%Done!
\end{document}
Jake
  • 232,450
1

Inspired by answers above, here is an way to do with with floating point computation provided by xfp. The overleaf project is https://www.overleaf.com/read/ppjpzgcssddt .

This way lets you define a max scale for each bar, e.g. 100% or 90 degrees and a max bar width. The the bar width in cm is computed for you by \fpeval

table chart with xfp

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{booktabs}
\usepackage{xfp} % https://tex.stackexchange.com/questions/115558/simple-way-to-multiply-two-values/629838?noredirect=1#comment1570645_629838
\usepackage{color}
\pagestyle{empty}

\begin{document}

\def\pcb#1{%% percent bar {\color{red}\rule{\fpeval{#1/\percentscale\barwidth} cm}{\barheight}} #1 } \def\pcbb#1{%% best value percent {\color{blue}\rule{\fpeval{#1/\percentscale\barwidth} cm}{\barheight}} #1 } \def\db#1{%% degrees bar {\color{red}\rule{\fpeval{#1/\degscale\barwidth} cm}{\barheight}} #1 } \def\dbb#1{%% best degree value {\color{blue}\rule{\fpeval{#1/\degscale\barwidth} cm}{\barheight}} #1 }

\newcommand{\barwidth}{5} % cm max bar widths \newcommand{\barheight}{4pt} % height of each bar \newcommand{\percentscale}{100} % max scale for percent bars \newcommand{\degscale}{90} % max scale for degree bars

\begin{table*}[t] \centering \caption{My table}

\begin{tabular}{@{}ll@{}}

\toprule percent & degrees \ \midrule \pcb{76.54} & \db{49.09} \ \pcb{20.52} & \db{6.38} \ \pcb{9.91} & \db{18} \ \pcb{8.57} & \db{56} \ \pcbb{7.69} & \dbb{3} \ \end{tabular}

\end{table*}

\end{document}