update This update has code which discovers on the fly the possible values. These values must be numeric but need not be integers. The incompatibility mentioned earlier with Beamer was only due to the fact that with Beamer it appears impossible (if not using tricks perhaps which I did not try to discover) to use tokens such as #1
or #2
in a frame; in particular it is impossible to define a command in a frame.
Any way the update does it with Beamer nevertheless. See bottom half of answer.
First answer
In this answer I implement a \Percentile
macro. The possible values of the data (from 0
to 7
) is however hard-coded in the macro.
I use \numexpr
when convenient, else I use xintfrac
(mainly because I didn't want to rewrite a rounding to fixed point routine, but at the level here everything could be done with \numexpr
). For convenience of coding I use \xintFor
of package xinttools
.
I briefly mentioned that this made me discover:
- I can not use a naked
\xintFor
in a Beamer frame, somehow the Beamer parsing does not like seeing the #
character,
1a. This has nothing to do whatsoever with \xintFor
: with Beamer it is impossible to define a command (which will use #1
, or #2
, etc...) inside a frame !!! As \xintFor
per its nature works with #1
etc.. tokens, its use is impossible in a beamer frame. Naturally a macro can use it internally.
- I can not use either
\xintFor
in a tabular with an S
column from siunitx
.
I dropped Beamer and for the tabular with siunitx
I used expandable macros as a replacement (but even then I discovered I could not use them in the generality I expected, when siunitx
is used).
As for the code, it uses internal macros to store individual data, for efficiency of data retrieval.
%\documentclass{beamer}
% Beamer is **incompatible** with non hidden \xintFor in a frame !!!
% NO (unhidden) \xintFor in a Beamer frame !!
% Also for some reason latex+dvipng raises an error here
% This is dvipng (dvipng (TeX Live)) 1.14 Copyright 2002-2010 Jan-Ake Larsson
% [1 <raw PostScriptdvipng warning: No image output from inclusion of raw PostScript >]
% must go via pdflatex
\documentclass[varwidth, border=6pt, ignorerest=false]{standalone}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{booktabs}
\usepackage{siunitx}
% siunitx is incompatible with use of \xintFor in a tabular !!
%
% \usepackage{xparse}
\usepackage{xintfrac, xinttools}
% xintfrac mainly for \xintRound because everything else can be emulated with
% \numexpr or \dimexpr in this context
% xinttools for the convenience of \xintFor
\newcommand*\SvendData
{{{A}{6}}%
{{B}{0}}%
{{C}{0}}%
{{D}{3}}%
{{E}{0}}%
{{F}{2}}%
{{G}{1}}%
{{H}{1}}%
{{I}{1}}%
{{J}{5}}%
{{K}{0}}%
{{L}{3}}%
{{M}{7}}%
{{N}{3}}%
{{O}{1}}%
{{P}{1}}%
{{Q}{0}}%
{{R}{0}}%
{{S}{0}}%
{{T}{2}}%
{{U}{1}}%
{{V}{2}}%
{{W}{0}}%
{{X}{2}}%
{{Y}{1}}%
{{Z}{1}}%
{{Aa}{4}}%
{{Ab}{6}}%
{{Ac}{1}}%
{{Ad}{1}}%
{{Ae}{6}}%
{{Af}{2}}%
{{Ag}{0}}%
{{Ah}{3}}%
{{Ai}{2}}%
{{Aj}{1}}%
{{Ak}{0}}%
{{Al}{0}}%
{{Am}{0}}%
{{An}{0}}%
{{Ao}{0}}%
{{Ap}{4}}}
% Utility to add Data
% e.g \AddToData \SvendData{WW}{5}
% \newcommand*\AddToData [3]{\odef #1{#1{{#2}{#3}}}}
% But would be better utility to update the private \Svend@Values@..,
% \Svend@Counts@.., \Svend@Cuml@.. macros
\makeatletter
% Possible values 0, 1, 2, 3, 4, 5, 6, 7 hard coded here, we associate to each
% a macro to hold the number of its occurrences
\newcommand*\ResetCounts {%
\xintFor ##1 in {0, 1, 2, 3, 4, 5, 6, 7}\do {\@namedef{Svend@Counts@##1}{0}}%
}
% \odef does \def with one expansion of replacement text
\newcommand*\ParseData [1]{%
% Defines the private macros underlying \elev and \HowMany
\xintFor* ##1 in {#1}\do {%
\expandafter\odef\csname Svend@Values@\@firstoftwo ##1\endcsname {\@secondoftwo ##1}%
\edef\Svend@tmp {Svend@Counts@\@secondoftwo ##1}%
\expandafter\odef\csname\Svend@tmp\endcsname
{\the\numexpr\csname\Svend@tmp\endcsname + \@ne}%
}%
}%
\newcommand*\ComputeCumu {%
% Computes and stores iteratively cumulative counts
% Again the possible values 0, 1, 2, 3, 4, 5, 6, 7 hard coded in this approach
\xintFor ##1 in {0, 1, 2, 3, 4, 5, 6, 7}\do {%
\xintifForFirst {\odef\Svend@tmp{\romannumeral-`0\HowMany{0}}}
{\odef\Svend@tmp{\the\numexpr\Svend@tmp+\HowMany{##1}}}%
\expandafter\let\csname Svend@Cumul@##1\endcsname \Svend@tmp
\xintifForLast {\let\HowManyTotale\Svend@tmp }{}%
}%
}
% Percentiles:
% I understand there are various definitions, I used this one :
%
% P(x) (x=0,1,..,100) is the smallest value V such as the frequency of
% event {v<= V} is at least x\%. Thus P(100) is the largest V and P(0) is the
% smallest V.
% cf http://en.wikipedia.org/wiki/Percentile
% first (expandable) method:
% \xintiLt {a}{b}{DO THIS IF a<b}{DO THIS IF a>=b}
% \newcommand*\Percentile [1]{%
% \xintifLt {\HowManyCumu {0}/\HowManyTotale}{#1/100}{% percentile at least 1
% \xintifLt {\HowManyCumu {1}/\HowManyTotale}{#1/100}{% percentile at least 2
% \xintifLt {\HowManyCumu {2}/\HowManyTotale}{#1/100}{% percentile at least 3
% \xintifLt {\HowManyCumu {3}/\HowManyTotale}{#1/100}{% percentile at least 4
% \xintifLt {\HowManyCumu {4}/\HowManyTotale}{#1/100}{% percentile at least 5
% \xintifLt {\HowManyCumu {5}/\HowManyTotale}{#1/100}{% percentile at least 6
% \xintifLt {\HowManyCumu {6}/\HowManyTotale}{#1/100}{7%
% }{6}%
% }{5}%
% }{4}%
% }{3}%
% }{2}%
% }{1}%
% }{0}%
% }
% Possibly faster expandable method, does three comparisons:
% (based on a binary tree of the possible values)
% The other method above does between 1 and 7 comparisons depending on the input
% Speed gain would show only for larger range of values, for example from 0 to
% 127 rather than from 0 to 7
\newcommand*\Percentile [1]{%
\xintifLt {\HowManyCumu {3}/\HowManyTotale}{#1/100}
{% percentile at least 4
\xintifLt {\HowManyCumu {5}/\HowManyTotale}{#1/100}
{\xintifLt {\HowManyCumu {6}/\HowManyTotale}{#1/100}{7}{6}}
{\xintifLt {\HowManyCumu {4}/\HowManyTotale}{#1/100}{5}{4}}%
}
{% percentile at most 3
\xintifLt {\HowManyCumu {1}/\HowManyTotale}{#1/100}
{\xintifLt {\HowManyCumu {2}/\HowManyTotale}{#1/100}{3}{2}}
{\xintifLt {\HowManyCumu {0}/\HowManyTotale}{#1/100}{1}{0}}%
}%
}%
\newcommand*\elev [1]{\csname Svend@Values@#1\endcsname }
\newcommand*\HowMany [1]{\csname Svend@Counts@#1\endcsname }
\newcommand*\HowManyCumu [1]{\csname Svend@Cumul@#1\endcsname }
\makeatother
\ResetCounts
\ParseData\SvendData
\ComputeCumu
\begin{document}
\centering
\begin{tabular}{*{14}{c}}
\toprule
\elev{A} & \elev{B} & \elev{C} & \elev{D} & \elev{E} & \elev{F} & \elev{G} &
\elev{H} & \elev{I} & \elev{J} & \elev{K} & \elev{L} & \elev{M} & \elev{N} \\[0.5ex]
\elev{O} & \elev{P} & \elev{Q} & \elev{R} & \elev{S} & \elev{T} & \elev{U} &
\elev{V} & \elev{W} & \elev{X} & \elev{Y} & \elev{Z} & \elev{Aa} & \elev{Ab} \\[0.5ex]
\elev{Ac} & \elev{Ad} & \elev{Ae} & \elev{Af} & \elev{Ag} & \elev{Ah} & \elev{Ai} &
\elev{Aj} & \elev{Ak} & \elev{Al} & \elev{Am} & \elev{An} & \elev{Ao} & \elev{Ap} \\
\bottomrule
\end{tabular}
\bigskip
% THIS WOULD BE OK:
% \begin{tabular}{*{8}{c}}
% \toprule
% \xintFor #1 in {0, 1, 2, 3, 4, 5, 6}\do {{$F(#1)$}&}{$F(7)$}\\
% \xintFor #1 in {0, 1, 2, 3, 4, 5, 6}\do
% {\xintRound{1}{\HowManyCumu{#1}/\HowManyTotale [2]}&}100\\
% \bottomrule
% \end{tabular}
% BUT THE SAME WITH
% \begin{tabular}{*{7}{S[table-format = 2.1]}S[table-format = 3]}
% DOESN'T WORK: ON NE PEUT PAS UTILISER \xintFor DANS UN TABULAR AVEC siunitx !!
% We can use expandable macros with siunitx
\def\RowA #1{{$F(#1)$}}% EXTRA BRACES NEEDED FOR SIUNITX !!
\def\RowB #1{\xintRound{1}{\HowManyCumu{#1}/\HowManyTotale [2]}}
\begin{tabular}{*{7}{S[table-format = 2.1]}S[table-format = 3]}
\toprule
% PURELY EXPANDABLE MACROS: those work with siunitx ...
% ... BUT don't try to define a macro with parameter here :((
\xintListWithSep {&}{\xintApply\RowA {{0}{1}{2}{3}{4}{5}{6}{7}}}\\
\xintListWithSep {&}{\xintApply\RowB {{0}{1}{2}{3}{4}{5}{6}}}&100\\
\bottomrule
\end{tabular}
\bigskip
\begin{tabular}{*{9}{c}}
\toprule
% strange standalone problem with too long line from
% \xintFor #1 in {0, 10, 25, 33, 50, 66, 75, 90} \do {\textit{Pe}$(#1)$&}\textit{Pe}$(100)$\\
\xintFor #1 in {0, 10, 25, 33, 50, 66, 75, 90} \do {$q(#1)$&}$q(100)$\\
\xintFor #1 in {0, 10, 25, 33, 50, 66, 75, 90} \do {$\Percentile{#1}$&}$7$\\
\bottomrule
\end{tabular}
\end{document}
I also got into trouble with standalone
(as indicated near the bottom of the code) and even dvipng
joined the comedy of complaints, for reasons unbeknownst to me.
Second Answer
\documentclass[10pt]{beamer}
%\usepackage[paperwidth=25cm]{geometry}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{booktabs}
\usepackage{siunitx}
\usepackage{xintfrac, xinttools}
% EXTENDED DATA
\newcommand*\SvendData
{{{A}{6}}%
{{B}{0}}%
{{C}{0}}%
{{D}{3}}%
{{E}{0}}%
{{F}{2}}%
{{G}{1}}%
{{H}{1}}%
{{I}{1}}%
{{J}{5}}%
{{K}{0}}%
{{L}{3}}%
{{M}{7}}%
{{N}{3}}%
{{O}{1}}%
{{P}{1}}%
{{Q}{0}}%
{{R}{0}}%
{{S}{0}}%
{{T}{2}}%
{{U}{1}}%
{{V}{2}}%
{{W}{0}}%
{{X}{2}}%
{{Y}{1}}%
{{Z}{1}}%
{{Aa}{4}}%
{{Ab}{6}}%
{{Ac}{1}}%
{{Ad}{1}}%
{{Ae}{6}}%
{{Af}{2}}%
{{Ag}{0}}%
{{Ah}{3}}%
{{Ai}{2}}%
{{Aj}{1}}%
{{Ak}{0}}%
{{Al}{0}}%
{{Am}{0}}%
{{An}{0}}%
{{Ao}{0}}%
{{Ap}{4}}%
{{NA}{6.5}}%
{{NB}{0.5}}%
{{NC}{0.5}}%
{{ND}{3.5}}%
{{NE}{0.5}}%
{{NF}{2.5}}%
{{NG}{1.5}}%
{{NH}{1.5}}%
{{NI}{1.5}}%
{{NJ}{5.5}}%
{{NK}{0.5}}%
{{NL}{3.5}}%
{{NM}{7.5}}%
{{NN}{3.5}}%
{{NO}{1.5}}%
{{NP}{1.5}}%
{{NQ}{0.5}}%
{{NR}{0.5}}%
{{NS}{0.5}}%
{{NT}{2.5}}%
{{NU}{1.5}}%
{{NV}{2.5}}%
{{NW}{0.5}}%
{{NX}{2.5}}%
{{NY}{1.5}}%
{{NZ}{1.5}}%
{{NAa}{4.5}}%
{{NAb}{6.5}}%
{{NAc}{1.5}}%
{{NAd}{1.5}}%
{{NAe}{6.5}}%
{{NAf}{2.5}}%
{{NAg}{0.5}}%
{{NAh}{3.5}}%
{{NAi}{2.5}}%
{{NAj}{1.5}}%
{{NAk}{0.5}}%
{{NAl}{0.5}}%
{{NAm}{0.5}}%
{{NAn}{0.5}}%
{{NAo}{0.5}}%
{{NAp}{4.5}}}
\makeatletter
% \odef does \def with one expansion of replacement text
\newcommand*\SvendValues {}
\newcommand*\SvendNumValues {}
\newcommand*\ParseData [1]{%
% Defines the private macros underlying \elev and \HowMany
% This version creates \SvendValues ordered list of values.
%
% For inner efficiency this \SvendValues is with braces, not commas
% (to be used with \xintFor* not \xintFor)
%
% The values do not have to be integers. But they must be numeric quantities
% as understood by xintfrac.
%
\def\SvendValues {}%
\def\SvendNumValues {0}%
\xintFor* ##1 in {#1}\do
{%
% get the possibly new value
\odef\Svend@tmpD {\@firstoftwo ##1}%
\odef\Svend@tmpV {\@secondoftwo ##1}%
% and insert it at the correct location in \SvendValues
% (the better would be to manage some kind of heap tree but I have not
% invested the needed time)
%
\def\SvendValues@Tmp {}%
\def\Svend@tmpflag {0}%
% 0 = initial state,
% 1 = inserted, finish,
% 2 = was already there
\xintifForFirst
{\odef\SvendValues {\expandafter{\Svend@tmpV}}%
\def\SvendNumValues{1}%
\expandafter\odef\csname Svend@Counts@\Svend@tmpV\endcsname {0}}% will be increased below
{\xintFor* ##2 in {\SvendValues}\do
{%
\if0\Svend@tmpflag\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\xintifCmp {\Svend@tmpV}{##2}
{\def\Svend@tmpflag{1}%
\oodef\SvendValues@Tmp
{\expandafter\SvendValues@Tmp \expandafter{\Svend@tmpV}{##2}}}% new < old
{\def\Svend@tmpflag{2}\odef\SvendValues@Tmp {\SvendValues@Tmp {##2}}}% old = new
{\odef\SvendValues@Tmp {\SvendValues@Tmp {##2}}}% new > old
}
{\odef\SvendValues@Tmp{\SvendValues@Tmp {##2}}}%
}%
\if0\Svend@tmpflag
\oodef\SvendValues@Tmp{\expandafter\SvendValues@Tmp\expandafter {\Svend@tmpV}}%
\fi
\let\SvendValues\SvendValues@Tmp
%\typeout{\SvendValues}% debugging
\if2\Svend@tmpflag
\else
% new value
\expandafter\odef\csname Svend@Counts@\Svend@tmpV\endcsname {0}% will be increased below
\odef\SvendNumValues {\the\numexpr\SvendNumValues+\@ne}\fi
}%
% continued as in earlier code
\expandafter\odef\csname Svend@Values@\Svend@tmpD\endcsname {\Svend@tmpV}%
\expandafter\odef\csname Svend@Counts@\Svend@tmpV\endcsname
{\the\numexpr\csname Svend@Counts@\Svend@tmpV\endcsname + \@ne}%
}% end of external \xintFor loop
}%
\newcommand*\ComputeCumu {%
% Computes and stores iteratively cumulative counts
% THIS VERSION USES \SvendValues
\xintFor* ##1 in {\SvendValues}\do {%
\xintifForFirst {\odef\Svend@tmp{\romannumeral-`0\HowMany{##1}}}
{\odef\Svend@tmp{\the\numexpr\Svend@tmp+\HowMany{##1}}}%
\expandafter\let\csname Svend@Cumul@##1\endcsname \Svend@tmp
\xintifForLast {\let\HowManyTotale\Svend@tmp }{}%
}%
}
% Percentiles:
%
% P(x) (x=0,1,..,100) is the smallest value V such as the frequency of
% event {v<= V} is at least x\%. Thus P(100) is the largest V and P(0) is the
% smallest V.
%
% THIS VERSION USES \SvendValues
% It has nothing hardcoded.
\catcode`_ 11
\def\Percentile@helper #1#2% space below is to stop premature expansion
{ \if1\xintifLt {\HowManyCumu {#2}/\HowManyTotale}{#1/100}{0}{1}\xint_dothis{#2}\fi}
\newcommand*\Percentile [1]{% expandable !
\xintApplyUnbraced{\Percentile@helper {#1}}\SvendValues\xint_orthat {}%
}
\catcode`_ 8
\newcommand*\elev [1]{\csname Svend@Values@#1\endcsname }
\newcommand*\HowMany [1]{\csname Svend@Counts@#1\endcsname }
\newcommand*\HowManyCumu [1]{\csname Svend@Cumul@#1\endcsname }
\let\firstoftwo\@firstoftwo
\let\secondoftwo\@secondoftwo
\makeatother
\ParseData\SvendData
\ComputeCumu
%\typeout{\meaning\SvendValues}
% for first tabular
% WITH BEAMER I CAN NOT DEFINE THIS IN THE FRAME !!!!!!
% ANY \newcommand MUST BE IN THE PREAMBLE WITH BEAMER !!!!!!
\newcommand*\Row [1]{\stepcounter{rowcount}%
\elev{\firstoftwo #1}%
\ifnum\value{rowcount}<14
\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{&}{\setcounter{rowcount}{0}\\[0.5ex]}}
% for middle data (not a tabular, would be too wide)
\newcommand*\ShowCumu [1]{$F(#1)=\xintRound{1}{\HowManyCumu{#1}/\HowManyTotale [2]}$}
% for third tabular
\newcommand*\RowA [1]{$q(#1)$}%
\newcommand*\RowB [1]{$\Percentile{#1}$}
\newcounter{rowcount}
\begin{document}\small
% DEBUGGING (not possible with Beamer! because of #1...)
% \HowMany{0}
% \xintFor*#1 in \SvendValues\do {[#1,\HowMany{#1}], }
% \SvendNumValues
% \xintNthElt{0}{\SvendData}
% \HowManyTotale
\begin{frame}
\centering
\setcounter{rowcount}{0}%
\begin{tabular}{*{14}{c}}
\toprule
\xintApplyUnbraced \Row\SvendData
\bottomrule
\end{tabular}
\bigskip
% (This is too wide hence would make letters in my png appear too small)
% DEFINITIONS LIKE THIS MUST BE MOVED TO PREAMBLE IF BEAMER CLASS !!
% \def\RowA #1{{$F(#1)$}}% EXTRA BRACES NEEDED FOR SIUNITX !!
% \def\RowB #1{\xintRound{1}{\HowManyCumu{#1}/\HowManyTotale [2]}}
% \centerline{\begin{tabular}{*{\SvendNumValues}{S[table-format = 2.1]}}
% \toprule
% \xintListWithSep {&}{\xintApply\RowA \SvendValues}\\
% \xintListWithSep {&}{\xintApply\RowB \SvendValues}\\
% \bottomrule
% \end{tabular}}
\xintListWithSep{,\quad }{\xintApply\ShowCumu \SvendValues}
\bigskip
\begin{tabular}{*{10}{c}}
\toprule
\xintListWithSep {&}{\xintApply\RowA {{0}{10}{25}{33}{50}{66}{75}{90}{100}}}\\
\xintListWithSep {&}{\xintApply\RowB {{0}{10}{25}{33}{50}{66}{75}{90}{100}}}\\
\bottomrule
\end{tabular}
\end{frame}
\end{document}
:)