diff options
-rwxr-xr-x | Build/tools/tpm-ctan-check | 3 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/datatool/README | 97 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/datatool/doc/CHANGES | 1 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf | bin | 0 -> 888470 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/datatool/source/datatool.dtx | 12428 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/datatool/source/datatool.ins | 25 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc | 1 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/datatool.tlpsrc | 2 |
8 files changed, 12556 insertions, 1 deletions
diff --git a/Build/tools/tpm-ctan-check b/Build/tools/tpm-ctan-check index 74d3167a3a8..8a63062466e 100755 --- a/Build/tools/tpm-ctan-check +++ b/Build/tools/tpm-ctan-check @@ -32,7 +32,8 @@ my @WorkingTPM = qw( crop crossreference csquotes csvtools ctable cursolatex cursor cuisine currvita curve curve2e curves custom-bib cyrillic - dancers dashbox dateiliste datetime dcpic decimal delimtxt digiconfigs + dancers dashbox datatool + dateiliste datetime dcpic decimal delimtxt digiconfigs dinat dingbat directory disser dk-bib dlfltxb doi doipubmed dottex doublestroke dpfloat draftwatermark dramatist dtxtut dvdcoll dvipsconfig dyntree diff --git a/Master/texmf-dist/doc/latex/datatool/README b/Master/texmf-dist/doc/latex/datatool/README new file mode 100644 index 00000000000..34e1b34558a --- /dev/null +++ b/Master/texmf-dist/doc/latex/datatool/README @@ -0,0 +1,97 @@ +LaTeX Bundle : datatool v1.0 (datatool.sty, datapie.sty, dataplot.sty, databar.sty) + +Last Modified : 23 July 2007 + +Author : Nicola Talbot + +datatool.sty: + + Databases can be created using LaTeX commands or loaded + from external ASCII files, such as comma or tab separated + variable files. + + Databases can be sorted numerically or alphabetically + (descending or ascending.) + + Repetitive operations can be performed on each row of + data in a database (such as mail merging.) Conditions + can be imposed to exclude rows. + + Commands are provided to determine if an argument is + an integer, a real number, currency or a string. + (Scientific notation is currently not supported.) + + Locale dependent number settings are supported + (such as a comma as a decimal character and full stop as + a number group character.) + + Commands are provided to convert between locale dependent + numbers/currency and the standard decimal format required + by the fp package enabling fixed point arithmetic to be + performed on elements of the database. + + Strings can be tested to determine if they are all upper + or all lower case. + + Names can be converted to initials using \DTLinitials. + +datapie.sty: + + A database defined by datatool.sty can be converted into a + pie chart. + + Segments can be separated from the rest of the chart to make + them stand out. + + Colour/grey scale options. + + Predefined segment colours can be changed. + + Hooks provided to annotate chart. + +dataplot.sty: + + A database defined by datatool.sty may be plotted as a 2D + scatter or line plot + + Settings provided to govern the appearance of the chart. + (e.g. show/hide axes, legend, grid, major/minor tick marks.) + + Hooks provided to add extra information to the plot + +databar.sty: + + A database defined by datatool.sty can be converted into a + bar chart. + + Colour/grey scale options. + + Predefined bar colours can be changed. + + Horizontal or vertical formats provided. + + Hooks provided to annotate chart. + +*The datatool bundle replaces the csvtools bundle which is now obsolete.* + +The datatool.sty package requires the following packages/files: + +xkeyval +xfor +fp +substr +compare.tex + +The datapie.sty, dataplot.sty and databar.sty packages requires +the tikz/pgf package. + +*Remember to refresh TeX's database* + +The package and documentation source code is also supplied as a +dtx and ins file located in texmf/source. + +This material is subject to the LaTeX Project Public License. +See http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html for the details of that license. + +http://theoval.cmp.uea.ac.uk/~nlct/ + diff --git a/Master/texmf-dist/doc/latex/datatool/doc/CHANGES b/Master/texmf-dist/doc/latex/datatool/doc/CHANGES new file mode 100644 index 00000000000..11c7fa0086c --- /dev/null +++ b/Master/texmf-dist/doc/latex/datatool/doc/CHANGES @@ -0,0 +1 @@ +v1.0 (2007/07/23) : Initial Release diff --git a/Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf b/Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf Binary files differnew file mode 100644 index 00000000000..7a2784f1ee0 --- /dev/null +++ b/Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf diff --git a/Master/texmf-dist/doc/latex/datatool/source/datatool.dtx b/Master/texmf-dist/doc/latex/datatool/source/datatool.dtx new file mode 100644 index 00000000000..a7363848b5a --- /dev/null +++ b/Master/texmf-dist/doc/latex/datatool/source/datatool.dtx @@ -0,0 +1,12428 @@ +%\iffalse +% datatool.dtx generated using makedtx version 0.93b (c) Nicola Talbot +% Command line args: +% -src "datatool.sty=>datatool.sty" +% -src "datapie.sty=>datapie.sty" +% -src "dataplot.sty=>dataplot.sty" +% -src "databar.sty=>databar.sty" +% -doc "manual.tex" +% -author "Nicola Talbot" +% -codetitle "datatool.sty" +% -dir "source" +% datatool +% Created on 2007/7/23 22:53 +%\fi +%\iffalse +%<*package> +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%</package> +%\fi +% \iffalse +% Doc-Source file to use with LaTeX2e +% Copyright (C) 2007 Nicola Talbot, all rights reserved. +% \fi +% \iffalse +%<*driver> +\documentclass[a4paper]{ltxdoc} +\usepackage{ifthen} +\usepackage{alltt} +\usepackage[verbose=false]{datatool} +\usepackage{datapie,databar} +\usepackage{textcomp} +\usepackage{graphicx} +\usepackage{colortbl} +\usepackage[colorlinks, + bookmarks, + hyperindex=false, + pdfauthor={Nicola L.C. Talbot}, + pdftitle={datatool: Databases and data manipulation}, + pdfkeywords={LaTeX,package,database,data,chart,plot}]{hyperref} +\usetikzlibrary{snakes} + + %hyperindex conflicts with doc + %(end up with |usage|hyperpage in indexentry) + %This unfortunately means that the changes section doesn't + %have active links, but at least it will keep makeindex happy. + +\renewcommand{\usage}[1]{\textit{\hyperpage{#1}}} +\renewcommand{\main}[1]{\hyperpage{#1}} +\newcommand{\see}[2]{\emph{see} #1} +\makeatletter +\def\index@prologue{\section*{Index}} + + % commands are too wide for a 3 column index + \def\theindex{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi + \columnseprule \z@ \columnsep 35\p@ + \twocolumn[\index@prologue]% + \IndexParms \let\item\@idxitem \ignorespaces} + \def\endtheindex{\if@restonecol\onecolumn\else\clearpage\fi} +\makeatother +\RecordChanges +\PageIndex +\CheckSum{8992} +\CodelineNumbered + +\newcommand*{\sty}[1]{\textsf{#1}} +\newcommand*{\env}[1]{\textsf{#1}} +\definecolor{defbackground}{rgb}{0.8,1,1} + +\makeatletter +\newcommand*{\setting}[2]{\textsf{#2}\relax +\@for\thiscmd:=#1\do{% +\edef\doindex{\noexpand\index +{\thiscmd\space settings=\noexpand\cs{\thiscmd} settings>#2=\noexpand +\textsf{#2}|hyperpage}}\doindex +}} +\makeatother + +\newcommand*{\counterfmt}[1]{\texttt{#1}\index +{#1 counter=\texttt{#1} counter|hyperpage}} + +\newcommand*{\ics}[1]{\cs{#1}\SpecialMainIndex{#1}} + +\newsavebox\defsbox +\newenvironment{definition}{% +\begin{lrbox}{\defsbox}% +\begin{minipage}{\linewidth} +}{% +\end{minipage} +\end{lrbox}% +\vskip10pt +\noindent +{\setlength{\fboxsep}{4pt}\setlength{\fboxrule}{1.25pt}% +\fcolorbox{black}{defbackground}{\usebox\defsbox}% +}\vskip10pt +} + +\newcommand*{\pkgopt}[2][datatool]{\textsf{#2}\index +{#1 package options=\textsf{#1} package options>#2=\textsf{#2}|hyperpage}} + +\newcounter{example} +\newcommand*{\examplename}{example} +\makeatletter +\newenvironment{example}[2]{\refstepcounter{example}\label{#2}% +\par\vskip10pt\noindent +\textbf{\large Example \theexample\ (#1)}% +\addcontentsline{loe}{section}{\protect\numberline{\theexample}#1}% +\nopagebreak\par\vskip10pt\nopagebreak +}% +{\begin{center}\rule{2in}{1pt}\end{center}} + +\newcommand*{\listofexamples}{\section*{List of Examples}% +\@starttoc{loe}} +\makeatother + + +\begin{document} +\DocInput{datatool.dtx} +\end{document} +%</driver> +%\fi +%\MakeShortVerb{"} +%\DeleteShortVerb{\|} +% +% \title{datatool v 1.0: Databases and data manipulation} +% \author{Nicola L.C. Talbot\\[10pt] +%School of Computing Sciences\\ +%University of East Anglia\\ +%Norwich. Norfolk\\ +%NR4 7TJ. United Kingdom.\\ +%\url{http://theoval.cmp.uea.ac.uk/~nlct/}} +% +% \date{23rd July 2007} +% \maketitle +%\tableofcontents +%\listofexamples +% +% \section{Introduction} +% +% \changes{1.0}{2007 July 22}{Initial version} +%The \sty{datatool} bundle consists of the following +%packages: \sty{datatool}, \sty{datapie}, \sty{dataplot} and +%\sty{databar}. +% +%The \sty{datatool} package can be used to: +%\begin{itemize} +%\item Create or load databases. +%\item Sort rows of a database (either numerically or alphabetically, +%ascending or descending.) +%\item Perform repetitive operations on each row of a database +%(e.g.\ mail merging.) Conditions may be imposed to exclude rows. +%\item Determine where an argument is an integer, a real number, +%currency or a string. (Scientific notation is currently not +%supported.) Locale dependent number settings are supported (such +%as a comma as a decimal character and a full stop as a number +%group character.) +%\item Convert locale dependent numbers/currency to the decimal +%format required by the \sty{fp} package, enabling fixed point +%arithmetic to be performed on elements of the database. +%\item Names can be converted to initials. +%\item Strings can be tested to determine if they are all +%upper or lower case. +%\end{itemize} +% +%The \sty{datapie} package can be used to convert a database into +%a pie chart: +%\begin{itemize} +%\item Segments can be separated from the rest of the chart to make +%them stand out. +%\item Colour/grey scale options. +%\item Predefined segment colours can be changed. +%\item Hooks provided to add extra information to the chart +%\end{itemize} +% +%The \sty{databar} package can be used to convert a database into +%a bar chart: +%\begin{itemize} +%\item Colour/grey scale options. +%\item Predefined bar colours can be changed. +%\item Hooks provided to add extra information to the chart +%\end{itemize} +% +%(The \sty{datapie} and \sty{databar} packages do not support the +%creation of 3D charts, and I have no plans to implement them at any +%later date. The use of 3D charts should be discouraged. They may look +%pretty, but the purpose of a chart is to be informative. Three +%dimensional graphics cause distortion, which can result in misleading +%impressions.) +% +%The \sty{dataplot} package can be used to convert a database into +%a two dimensional plot using markers and/or lines. Three dimensional +%plots are currently not supported. +% +%\textbf{This package replaces the \sty{csvtools} package which is now +%obsolete.} +% +%\section{Data Types} +%\label{sec:datatypes} +% +%The \sty{datatool} package recognises four data types: integers, +%real numbers, currency and strings. +% +%\begin{description} +%\item[Integers] An integer is a sequence of digits, optionally +%groups of three digits may be separated by the number group character. +%The default number group character is a comma (,) but may be +%changed using \cs{DTLsetnumberchars} (see below.) +% +%\item[Real Numbers] A real number is an integer followed by the +%decimal character followed by one or more digits. The decimal +%character is a full stop (.) by default. The number group +%and decimal characters may be changed using +%\DescribeMacro{\DTLsetnumberchars} +%\begin{definition} +%\cs{DTLsetnumberchars}\marg{number group character}\marg{decimal character} +%\end{definition} +%Note that scientific notation is not supported, and the number group +%character may not be used after the decimal character. +% +%\item[Currency] A currency symbol followed by an integer or +%real number is considered to be the currency data type. +%There are two predefined currency symbols, "\$" and \cs{pounds}. +%In addition, if any of the following commands are defined at the +%start of the document, they are also considered to be a currency +%symbol: \cs{texteuro}, \cs{textdollar}, \cs{textstirling}, +%\cs{textyen}, \cs{textwon}, \cs{textcurrency}, \cs{euro} +%and \cs{yen}. Additional currency symbols can be defined using +%\DescribeMacro{\DTLnewcurrencysymbol} +%\begin{definition} +%\cs{DTLnewcurrencysymbol}\marg{symbol} +%\end{definition} +% +%\item[Strings] Anything that doesn't belong to the above three +%types is considered to be a string. +% +%\end{description} +% +%\subsection{Conditionals} +%\label{sec:ifconditions} +% +%The following conditionals are provided by the \sty{datatool} +%package: +% +%\DescribeMacro{\DTLifint} +%\begin{definition} +%\cs{DTLifint}\marg{text}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{text} is an integer then do \meta{true part}, otherwise +%do \meta{false part}. For example +%\begin{verbatim} +%\DTLifint{2536}{integer}{not an integer} +%\end{verbatim} +%produces: +%\DTLifint{2536}{integer}{not an integer}. +% +%The number group character may appear in the number, for example: +%\begin{verbatim} +%\DTLifint{2,536}{integer}{not an integer} +%\end{verbatim} +%produces: +%\DTLifint{2,536}{integer}{not an integer}. +%However, the number group character may only be followed by a group +%of three digits. For example: +%\begin{verbatim} +%\DTLifint{2,5,3,6}{integer}{not an integer} +%\end{verbatim} +%produces: +%\DTLifint{2,5,3,6}{integer}{not an integer}. +%The number group character may be changed. For example: +%\begin{verbatim} +%\DTLsetnumberchars{.}{,}% +%\DTLifint{2,536}{integer}{not an integer} +%\end{verbatim} +%this now produces: +%\DTLsetnumberchars{.}{,}\relax +%\DTLifint{2,536}{integer}{not an integer}, since 2,536 is now +%a real number. +% +%Note that nothing else can be appended or prepended to the +%number. For example: +%\begin{verbatim} +%\DTLsetnumberchars{,}{.}% +%\DTLifint{2,536m}{integer}{not an integer} +%\end{verbatim} +%produces: +%\DTLsetnumberchars{,}{.}\relax +%\DTLifint{2,536m}{integer}{not an integer}. +% +%\DescribeMacro{\DTLifreal} +%\begin{definition} +%\cs{DTLifreal}\marg{text}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{text} is a real number then do \meta{true part}, otherwise +%do \meta{false part}. For example +%\begin{verbatim} +%\DTLifreal{1000.0}{real}{not real} +%\end{verbatim} +%produces: +%\DTLifreal{1000.0}{real}{not real}. +% +%Note that an integer is not a real number: +%\begin{verbatim} +%\DTLifreal{1,000}{real}{not real} +%\end{verbatim} +%produces: +%\DTLifreal{1,000}{real}{not real}. +% +%Whereas +%\begin{verbatim} +%\DTLifreal{1,000.0}{real}{not real} +%\end{verbatim} +%produces: +%\DTLifreal{1,000.0}{real}{not real}. +% +%However +%\begin{verbatim} +%\DTLsetnumberchars{.}{,}% +%\DTLifreal{1,000}{real}{not real} +%\end{verbatim} +%produces: +%\DTLsetnumberchars{.}{,}\relax +%\DTLifreal{1,000}{real}{not real} since the comma is now +%the decimal character. +% +%Currency is not considered to be real: +%\begin{verbatim} +%\DTLsetnumberchars{,}{.}% +%\DTLifreal{\$1.00}{real}{not real} +%\end{verbatim} +%produces: +%\DTLsetnumberchars{,}{.}\relax +%\DTLifreal{\$1.00}{real}{not real}. +% +%\DescribeMacro{\DTLifcurrency} +%\begin{definition} +%\cs{DTLifcurrency}\marg{text}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{text} is currency, then do \meta{true part}, otherwise +%do false part. For example: +%\begin{verbatim} +%\DTLifcurrency{\$5.99}{currency}{not currency} +%\end{verbatim} +%produces: +%\DTLifcurrency{\$5.99}{currency}{not currency}. Similarly: +%\begin{verbatim} +%\DTLifcurrency{\pounds5.99}{currency}{not currency} +%\end{verbatim} +%produces: +%\DTLifcurrency{\pounds5.99}{currency}{not currency}. +%Note, however, that +%\begin{verbatim} +%\DTLifcurrency{US\$5.99}{currency}{not currency} +%\end{verbatim} +%produces: +%\DTLifcurrency{US\$5.99}{currency}{not currency}. If you want +%this to be considered currency, you will have to add the +%sequence "US\$" to the set of currency symbols: +%\begin{verbatim} +%\DTLnewcurrencysymbol{US\$}% +%\DTLifcurrency{US\$5.99}{currency}{not currency} +%\end{verbatim} +%this now produces: +%\DTLnewcurrencysymbol{US\$}\relax +%\DTLifcurrency{US\$5.99}{currency}{not currency}. +% +%This document has used the \sty{textcomp} package which defines +%\cs{texteuro}, so this is also considered to be currency. For +%example: +%\begin{verbatim} +%\DTLifcurrency{\texteuro5.99}{currency}{not currency} +%\end{verbatim} +%produces: +%\DTLifcurrency{\texteuro5.99}{currency}{not currency}. +% +%The preferred method is to display the euro symbol in a sans-serif +%font, but +%\begin{verbatim} +%\DTLifcurrency{\textsf{\texteuro}5.99}{currency}{not currency} +%\end{verbatim} +%will produce: +%\DTLifcurrency{\textsf{\texteuro}5.99}{currency}{not currency}. +% +%It is better to define a new command, for example: +%\begin{verbatim} +%\DeclareRobustCommand*{\euro}{\textsf{\texteuro}} +%\end{verbatim} +%and add that command to the list of currency symbols. In fact, +%in this case, if you define the command \cs{euro} in the +%preamble, it will automatically be added to the list of known +%currency symbols. If however you define \cs{euro} in the document, +%you will have to add it using \ics{DTLnewcurrencysymbol}. For +%example: +%\begin{verbatim} +%\newcommand*{\euro}{\textsf{\texteuro}}% +%\DTLnewcurrencysymbol{\euro}% +%\DTLifcurrency{\euro5.99}{currency}{not currency} +%\end{verbatim} +%produces: +%\DeclareRobustCommand*{\euro}{\textsf{\texteuro}}\relax +%\DTLnewcurrencysymbol{\euro}\relax +%\DTLifcurrency{\euro5.99}{currency}{not currency}. +% +%\DescribeMacro{\DTLifcurrencyunit} +%\begin{definition} +%\cs{DTLifcurrencyunit}\marg{text}\marg{symbol}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{text} is currency, and uses \meta{symbol} as the unit of +%currency, then do \meta{true part} otherwise do \meta{false part}. +%For example: +%\begin{verbatim} +%\DTLifcurrencyunit{\$6.99}{\$}{dollars}{not dollars} +%\end{verbatim} +%produces: +%\DTLifcurrencyunit{\$6.99}{\$}{dollars}{not dollars}. +%Another example: +%\begin{verbatim} +%\def\cost{\euro10.50}% +%\DTLifcurrencyunit{\cost}{\euro}{euros}{not euros} +%\end{verbatim} +%produces: +%\def\cost{\euro10.50}\relax +%\DTLifcurrencyunit{\cost}{\euro}{euros}{not euros}. +% +%\DescribeMacro{\DTLifnumerical} +%\begin{definition} +%\cs{DTLifnumerical}\marg{text}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{text} is numerical (either an integer, real number or +%currency) then do \meta{true part} otherwise do +%\meta{false part}. +%For example: +%\begin{verbatim} +%\DTLifnumerical{1,000.0}{number}{string}. +%\end{verbatim} +%produces: \DTLifnumerical{1,000.0}{number}{string}. +%Whereas +%\begin{verbatim} +%\DTLsetnumberchars{.}{,}% +%\DTLifnumerical{1,000.0}{number}{string}. +%\end{verbatim} +%produces: +%\DTLsetnumberchars{.}{,}\relax +%\DTLifnumerical{1,000.0}{number}{string}. +%Since the number group character is now a full stop, and the +%decimal character is now a comma. (The number group character +%may only appear before the decimal character, not after it.) +% +%Currency is also considered to be numerical: +%\begin{verbatim} +%\DTLsetnumberchars{,}{.}% +%\DTLifnumerical{\$1,000.0}{number}{string}. +%\end{verbatim} +%produces: +%\DTLsetnumberchars{,}{.}\relax +%\DTLifnumerical{\$1,000.0}{number}{string}. +% +%\DescribeMacro{\DTLifstring} +%\begin{definition} +%\cs{DTLifstring}\marg{text}\marg{true part}\marg{false part} +%\end{definition} +%This is the opposite of \cs{DTLifnumerical}. If \meta{text} is +%not numerical, do \meta{true part}, otherwise do \meta{false part}. +% +%\DescribeMacro{\DTLifcasedatatype} +%\begin{definition} +%\cs{DTLifcasedatatype}\marg{text}\marg{string case}\marg{int case}\marg{real case}\marg{currency case} +%\end{definition} +%If \meta{text} is a string do \meta{string case}, if \meta{text} +%is an integer do \meta{int case}, if \meta{text} is a real number +%do \meta{real case}, if \meta{text} is currency do +%\meta{currency case}. For example: +%\begin{verbatim} +%\DTLifcasedatatype{1,000}{string}{integer}{real}{currency} +%\end{verbatim} +%produces: +%\DTLifcasedatatype{1,000}{string}{integer}{real}{currency}. +% +%\DescribeMacro{\DTLifnumlt} +%\begin{definition} +%\cs{DTLifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{num1} is less than \meta{num2}, then do \meta{true part}, +%otherwise do \meta{false part}. Note that both \meta{num1} and +%\meta{num2} must be numerical (either integers, real numbers or +%currency.) +% +%\DescribeMacro{\DTLifstringlt} +%\begin{definition} +%\cs{DTLifstringlt}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{string1} is alphabetically less than \meta{string2}, then do +%\meta{true part}, otherwise do \meta{false part}. +%For example: +%\begin{verbatim} +%\DTLifstringlt{aardvark}{zebra}{less}{not less} +%\end{verbatim} +%produces: +%\DTLifstringlt{aardvark}{zebra}{less}{not less}. +% +%Note that both \meta{string1} and \meta{string2} are considered to be +%strings, so for example: +%\begin{verbatim} +%\DTLifstringlt{2}{10}{less}{not less} +%\end{verbatim} +%produces: +%\DTLifstringlt{2}{10}{less}{not less}, since the string "2" +%comes after the string "10" when arranged alphabetically. +% +%\DescribeMacro{\DTLiflt} +%\begin{definition} +%\cs{DTLiflt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{arg1} and \meta{arg2} are both numerical, then this +%is equivalent to \cs{DTLifnumlt}, otherwise it is equivalent +%to \cs{DTLstringlt}. +% +%\DescribeMacro{\DTLifnumgt} +%\begin{definition} +%\cs{DTLifnumgt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{num1} is greater than \meta{num2}, then do \meta{true part}, +%otherwise do \meta{false part}. Note that both \meta{num1} and +%\meta{num2} must be numerical (either integers, real numbers or +%currency.) +% +%\DescribeMacro{\DTLifstringgt} +%\begin{definition} +%\cs{DTLifstringgt}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{string1} is alphabetically greater than \meta{string2}, then +%do \meta{true part}, otherwise do \meta{false part}. For example: +%\begin{verbatim} +%\DTLifstringgt{aardvark}{zebra}{greater}{not greater} +%\end{verbatim} +%produces: +%\DTLifstringgt{aardvark}{zebra}{greater}{not greater}. +% +%Note that both \meta{string1} and \meta{string2} are considered to be +%strings, so for example: +%\begin{verbatim} +%\DTLifstringgt{2}{10}{greater}{not greater} +%\end{verbatim} +%produces: +%\DTLifstringgt{2}{10}{greater}{not greater}, since the string "2" +%comes after the string "10" when arranged alphabetically. +% +%\DescribeMacro{\DTLifgt} +%\begin{definition} +%\cs{DTLifgt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{arg1} and \meta{arg2} are both numerical, then this +%is equivalent to \cs{DTLifnumgt}, otherwise it is equivalent +%to \cs{DTLstringgt}. +% +%\DescribeMacro{\DTLifnumeq} +%\begin{definition} +%\cs{DTLifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{num1} is equal to \meta{num2}, then do \meta{true part}, +%otherwise do \meta{false part}. Note that both \meta{num1} and +%\meta{num2} must be numerical (either integers, real numbers or +%currency.) The currency symbol is ignored when determining +%equality. For example +%\begin{verbatim} +%\DTLifnumeq{\pounds10.50}{10.5}{true}{false} +%\end{verbatim} +%produces: +%\DTLifnumeq{\pounds10.50}{10.5}{true}{false}, since they are +%considered to be numerically equivalent. Likewise: +%\begin{verbatim} +%\DTLifnumeq{\pounds10.50}{\$10.50}{true}{false} +%\end{verbatim} +%produces: +%\DTLifnumeq{\pounds10.50}{\$10.50}{true}{false}. +% +%\DescribeMacro{\DTLifstringeq} +%\begin{definition} +%\cs{DTLifstringeq}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{string1} and \meta{string2} are identical, then do +%\meta{true part}, otherwise do \meta{false part}. Again, both +%\meta{string1} and \meta{string2} are considered to be strings, +%so for example: +%\begin{verbatim} +%\DTLifstringeq{10.50}{10.5}{true}{false} +%\end{verbatim} +%produces: +%\DTLifstringeq{10.50}{10.5}{true}{false}. +% +%Note that the comparison is case sensitive, so for example: +%\begin{verbatim} +%\DTLifstringeq{Text}{text}{true}{false} +%\end{verbatim} +%produces: +%\DTLifstringeq{Text}{text}{true}{false}. +% +%\DescribeMacro{\DTLifeq} +%\begin{definition} +%\cs{DTLifeq}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +%\end{definition} +%If both \meta{arg1} and \meta{arg2} are numerical, then this is +%equivalent to \cs{DTLifnumeq}, otherwise it is equivalent to +%\cs{DTLifstringeq}. +% +%\DescribeMacro{\DTLifnumclosedbetween} +%\begin{definition} +%\cs{DTLifnumclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{min} $\leq$ \meta{num} $\leq$ \meta{max} then do \meta{true part}, +%otherwise do \meta{false part}. Note that \meta{num}, \meta{min} and +%\meta{max} must be numerical (either integers, real numbers or +%currency.) The currency symbol is ignored when determining +%equality. For example: +%\begin{verbatim} +%\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside} +%\end{verbatim} +%produces: +%\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside}. +%Note that the closed range includes end points: +%\begin{verbatim} +%\DTLifnumclosedbetween{5}{5}{7}{inside}{outside} +%\end{verbatim} +%produces: +%\DTLifnumclosedbetween{5}{5}{7}{inside}{outside}. +% +%\DescribeMacro{\DTLifstringclosedbetween} +%\begin{definition} +%\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%This determines if \meta{string} is between \meta{min} and +%\meta{max} in the alphabetical sense, or is equal to either +%\meta{min} or \meta{max}. +% +%\DescribeMacro{\DTLifclosedbetween} +%\begin{definition} +%\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{arg}, \meta{min} and \meta{max} are numerical, then this is +%equivalent to \cs{DTLifnumclosedbetween}, otherwise it is equivalent to +%\cs{DTLifstringclosedbetween}. +% +%\DescribeMacro{\DTLifnumopenbetween} +%\begin{definition} +%\cs{DTLifnumopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{min} $<$ \meta{num} $<$ \meta{max} then do \meta{true part}, +%otherwise do \meta{false part}. Note that \meta{num}, \meta{min} and +%\meta{max} must be numerical (either integers, real numbers or +%currency.) Again, the currency symbol is ignored when determining +%equality. For example: +%\begin{verbatim} +%\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside} +%\end{verbatim} +%produces: +%\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside}. +%Note that end points are not included. For example: +%\begin{verbatim} +%\DTLifnumclosedbetween{5}{5}{7}{inside}{outside} +%\end{verbatim} +%produces: +%\DTLifnumclosedbetween{5}{5}{7}{inside}{outside}. +% +%\DescribeMacro{\DTLifstringclosedbetween} +%\begin{definition} +%\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%This determines if \meta{string} is between \meta{min} and +%\meta{max} in the alphabetical sense, or is equal to either +%\meta{min} or \meta{max}. +% +%\DescribeMacro{\DTLifclosedbetween} +%\begin{definition} +%\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{arg}, \meta{min} and \meta{max} are numerical, then this is +%equivalent to \cs{DTLifnumclosedbetween}, otherwise it is equivalent to +%\cs{DTLifstringclosedbetween}. +% +%\DescribeMacro{\DTLifFPclosedbetween} +%\begin{definition} +%\cs{DTLifFPclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{min} $\leq$ \meta{num} $\leq$ \meta{max} then do \meta{true part}, +%otherwise do \meta{false part} where \meta{num}, \meta{min} +%and \meta{max} are all in standard fixed point notation (i.e.\ +%no number group separator, no currency symbols and a full stop as +%a decimal point.) +% +%\DescribeMacro{\DTLifFPopenbetween} +%\begin{definition} +%\cs{DTLifFPopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +%If \meta{min} $<$ \meta{num} $<$ \meta{max} then do \meta{true part}, +%otherwise do \meta{false part} where \meta{num}, \meta{min} +%and \meta{max} are all in standard fixed point notation (i.e.\ +%no number group separator, no currency symbols and a full stop as +%a decimal point.) +% +%\DescribeMacro{\DTLifAllUpperCase} +%\begin{definition} +%\cs{DTLifAllUpperCase}\marg{string}\marg{true part}\marg{false part} +%\end{definition} +%Tests if \meta{string} is all upper case. For example: +%\begin{verbatim} +%\DTLifAllUpperCase{WORD}{all upper}{not all upper} +%\end{verbatim} +%produces: +%\DTLifAllUpperCase{WORD}{all upper}{not all upper}, +%whereas +%\begin{verbatim} +%\DTLifAllUpperCase{Word}{all upper}{not all upper} +%\end{verbatim} +%produces: +%\DTLifAllUpperCase{Word}{all upper}{not all upper}. +%Note also that: +%\begin{verbatim} +%\DTLifAllUpperCase{\MakeUppercase{word}}{all upper}{not all upper} +%\end{verbatim} +%also produces: +%\DTLifAllUpperCase{\MakeUppercase{word}}{all upper}{not all upper}. +%\cs{MakeTextUppercase} (defined in David Carlisle's \sty{textcase} +%package) and \cs{uppercase} are also detected, otherwise, if +%a command is encountered, the case of the command is considered. +%For example: +%\begin{verbatim} +%\DTLifAllUpperCase{MAN{\OE}UVRE}{all upper}{not all upper} +%\end{verbatim} +%produces: +%\DTLifAllUpperCase{MAN{\OE}UVRE}{all upper}{not all upper}. +% +%\DescribeMacro{\DTLifAllLowerCase} +%\begin{definition} +%\cs{DTLifAllLowerCase}\marg{string}\marg{true part}\marg{false part} +%\end{definition} +%Tests if \meta{string} is all lower case. For example: +%\begin{verbatim} +%\DTLifAllLowerCase{word}{all lower}{not all lower} +%\end{verbatim} +%produces: +%\DTLifAllLowerCase{word}{all lower}{not all lower}, +%whereas +%\begin{verbatim} +%\DTLifAllLowerCase{Word}{all lower}{not all lower} +%\end{verbatim} +%produces: +%\DTLifAllLowerCase{Word}{all lower}{not all lower}. +%Note also that: +%\begin{verbatim} +%\DTLifAllLowerCase{\MakeLowercase{WORD}}{all lower}{not all lower} +%\end{verbatim} +%also produces: +%\DTLifAllLowerCase{\MakeLowercase{WORD}}{all lower}{not all lower}. +%\cs{MakeTextLowercase} (defined in David Carlisle's \sty{textcase} +%package) and \cs{lowercase} are also detected, otherwise, if +%a command is encountered, the case of the command is considered. +%For example: +%\begin{verbatim} +%\DTLifAllLowerCase{man{\oe}uvre}{all lower}{not all lower} +%\end{verbatim} +%produces: +%\DTLifAllLowerCase{man{\oe}uvre}{all lower}{not all lower}. +% +%\subsection{\texorpdfstring{\sty{ifthen}}{ifthen} conditionals} +%\label{sec:ifthen} +% +%The commands described in the previous section can not be +%used as the conditional part of the \cs{ifthenelse} or +%\cs{whiledo} commands provided by the \sty{ifthen} package. +%This section describes analogous commands which may only be +%used in the conditional argument of \cs{ifthenelse} and +%\cs{whiledo}. +% +%\DescribeMacro{\DTLisstring} +%\begin{definition} +%\cs{DTLisstring}\marg{text} +%\end{definition} +%Tests if \meta{text} is a string. For example: +%\begin{verbatim} +%\ifthenelse{\DTLisstring{some text}}{string}{not a string} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLisstring{some text}}{string}{not a string}. +% +%\DescribeMacro{\DTLisnumerical} +%\begin{definition} +%\cs{DTLisnumerical}\marg{text} +%\end{definition} +%Tests if \meta{text} is numerical (i.e.\ not a string.) For example: +%\begin{verbatim} +%\ifthenelse{\DTLisnumerical{\$10.95}}{numerical}{not numerical} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLisnumerical{\$10.95}}{numerical}{not numerical}. +% +%Note however that \cs{DTLisnumerical} requires more care than +%\cs{DTLifnumerical} when used with some of the other currency +%symbols. Consider: +%\begin{verbatim} +%\DTLifnumerical{\pounds10.95}{numerical}{not numerical} +%\end{verbatim} +%This produces: +%\DTLifnumerical{\pounds10.95}{numerical}{not numerical}. +%However +%\begin{verbatim} +%\ifthenelse{\DTLisnumerical{\pounds10.95}}{numerical}{not numerical} +%\end{verbatim} +%produces +%\ifthenelse{\DTLisnumerical{\pounds10.95}}{numerical}{not numerical}. +%This is due to the expansion that occurs within \cs{ifthenelse}. +%This can be prevented using \cs{noexpand}, for example: +%\begin{verbatim} +%\ifthenelse{\DTLisnumerical{\noexpand\pounds10.95}}{numerical}{not numerical} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLisnumerical{\noexpand\pounds10.95}}{numerical}{not numerical}. +% +%Likewise: +%\begin{verbatim} +%\def\cost{\pounds10.95}% +%\ifthenelse{\DTLisnumerical{\noexpand\cost}}{numerical}{not numerical} +%\end{verbatim} +%produces +%\def\cost{\pounds10.95}\relax +%\ifthenelse{\DTLisnumerical{\noexpand\cost}}{numerical}{not numerical}. +% +%\DescribeMacro{\DTLiscurrency} +%\begin{definition} +%\cs{DTLiscurrency}\marg{text} +%\end{definition} +%Tests if \meta{text} is currency. For example: +%\begin{verbatim} +%\ifthenelse{\DTLiscurrency{\$10.95}}{currency}{not currency} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLiscurrency{\$10.95}}{currency}{not currency}. +% +%The same warning given above for \cs{DTLisnumerical} also applies +%here. +% +%\DescribeMacro{\DTLiscurrencyunit} +%\begin{definition} +%\cs{DTLiscurrencyunit}\marg{text}\marg{symbol} +%\end{definition} +%Tests if \meta{text} is currency, and uses \meta{symbol} as the unit +%of currency. +%For example: +%\begin{verbatim} +%\ifthenelse{\DTLiscurrencyunit{\$6.99}{\$}}{dollars}{not dollars} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLiscurrencyunit{\$6.99}{\$}}{dollars}{not dollars} +%Another example: +%\begin{verbatim} +%\def\cost{\euro10.50}% +%\ifthenelse{\DTLiscurrencyunit{\noexpand\cost}{\noexpand\euro}}% +%{euros}{not euros} +%\end{verbatim} +%produces: +%\def\cost{\euro10.50}\relax +%\ifthenelse{\DTLiscurrencyunit{\noexpand\cost}{\noexpand\euro}}% +%{euros}{not euros}. Again note the use of \cs{noexpand}. +% +%\DescribeMacro{\DTLisreal} +%\begin{definition} +%\cs{DTLisreal}\marg{text} +%\end{definition} +%Tests if \meta{text} is a fixed point number (again, an integer is +%not considered to be a fixed point number.) For example: +%\begin{verbatim} +%\ifthenelse{\DTLisreal{1.5}}{real}{not real} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLisreal{1.5}}{real}{not real}. +% +%\DescribeMacro{\DTLisint} +%\begin{definition} +%\cs{DTLisint}\marg{text} +%\end{definition} +%Tests if \meta{text} is an integer. For example: +%\begin{verbatim} +%\ifthenelse{\DTLisint{153}}{integer}{not an integer} +%\end{verbatim} +%produces: +%\ifthenelse{\DTLisint{153}}{integer}{not an integer}. +% +%\DescribeMacro{\DTLislt} +%\begin{definition} +%\cs{DTLislt}\marg{arg1}\marg{arg2} +%\end{definition} +%This checks if \meta{arg1} is less than \meta{arg2}. As with +%\cs{DTLiflt}, if \meta{arg1} and \meta{arg2} are numerical, +%a numerical comparison is used, otherwise an alphabetical +%comparison is used. +% +%\DescribeMacro{\DTLisgt} +%\begin{definition} +%\cs{DTLisgt}\marg{arg1}\marg{arg2} +%\end{definition} +%This checks if \meta{arg1} is greater than \meta{arg2}. As with +%\cs{DTLifgt}, if \meta{arg1} and \meta{arg2} are numerical, +%a numerical comparison is used, otherwise an alphabetical +%comparison is used. +% +%\DescribeMacro{\DTLiseq} +%\begin{definition} +%\cs{DTLiseq}\marg{arg1}\marg{arg2} +%\end{definition} +%This checks if \meta{arg1} is equal to \meta{arg2}. As with +%\cs{DTLifeq}, if \meta{arg1} and \meta{arg2} are numerical, +%a numerical comparison is used, otherwise an alphabetical +%comparison is used. +% +%\DescribeMacro{\DTLisclosedbetween} +%\begin{definition} +%\cs{DTLisclosedbetween}\marg{arg}\marg{min}\marg{max} +%\end{definition} +%This checks if \meta{arg} lies between \meta{min} and +%\meta{max} (end points included.) As with +%\cs{DTLifclosedbetween}, if the arguments are numerical, +%a numerical comparison is used, otherwise an alphabetical +%comparison is used. +% +%\DescribeMacro{\DTLisopenbetween} +%\begin{definition} +%\cs{DTLisopenbetween}\marg{arg}\marg{min}\marg{max} +%\end{definition} +%This checks if \meta{arg} lies between \meta{min} and +%\meta{max} (end points excluded.) As with +%\cs{DTLifopenbetween}, if the arguments are numerical, +%a numerical comparison is used, otherwise an alphabetical +%comparison is used. +% +%\DescribeMacro{\DTLisFPlt} +%\begin{definition} +%\cs{DTLisFPlt}\marg{num1}\marg{num2} +%\end{definition} +%This checks if \meta{num1} is less than \meta{num2}, where both +%numbers are in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\DescribeMacro{\DTLisFPlteq} +%\begin{definition} +%\cs{DTLisFPlteq}\marg{num1}\marg{num2} +%\end{definition} +%This checks if \meta{num1} is less than or equal to \meta{num2}, where both +%numbers are in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\DescribeMacro{\DTLisFPgt} +%\begin{definition} +%\cs{DTLisFPgt}\marg{num1}\marg{num2} +%\end{definition} +%This checks if \meta{num1} is greater than \meta{num2}, where both +%numbers are in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\DescribeMacro{\DTLisFPgteq} +%\begin{definition} +%\cs{DTLisFPgteq}\marg{num1}\marg{num2} +%\end{definition} +%This checks if \meta{num1} is greater than or equal to \meta{num2}, where both +%numbers are in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\DescribeMacro{\DTLisFPeq} +%\begin{definition} +%\cs{DTLisFPeq}\marg{num1}\marg{num2} +%\end{definition} +%This checks if \meta{num1} is equal to \meta{num2}, where both +%numbers are in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\DescribeMacro{\DTLisFPclosedbetween} +%\begin{definition} +%\cs{DTLisFPclosedbetween}\marg{num}\marg{min}\marg{max} +%\end{definition} +%This checks if \meta{num} lies between \meta{min} and +%\meta{max} (end points included.) All arguments must be +%numbers in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\DescribeMacro{\DTLisFPopenbetween} +%\begin{definition} +%\cs{DTLisFPopenbetween}\marg{num}\marg{min}\marg{max} +%\end{definition} +%This checks if \meta{num} lies between \meta{min} and +%\meta{max} (end points excluded.) All arguments must be +%numbers in standard fixed point format (i.e.\ no number group +%separators, no currency and a full stop as a decimal point.) +% +%\section{Fixed Point Arithmetic} +%\label{sec:fp} +% +%The \sty{datatool} package uses the \sty{fp} package to perform +%fixed point arithmetic, however all numbers must be converted +%from the locale dependent format into the format required by the +%\sty{fp} package. A numerical value (i.e.\ an integer, a real +%or currency) can be converted into a plain decimal number using +%\DescribeMacro{\DTLconverttodecimal} +%\begin{definition} +%\cs{DTLconverttodecimal}\marg{num}\marg{cmd} +%\end{definition} +%The decimal number will be stored in \meta{cmd} which must be +%a control sequence. For example: +%\begin{verbatim} +%\DTLconverttodecimal{1,563.54}{\mynum} +%\end{verbatim} +%\DTLconverttodecimal{1,563.54}{\mynum}\relax +%will define \cs{mynum} to be \texttt{\mynum}. The command +%can then be used in any of the arithmetic macros provided by the +%\sty{fp} package. There are two commands provided to perform +%the reverse: +%\DescribeMacro{\DTLdecimaltolocale} +%\begin{definition} +%\cs{DTLdecimaltolocale}\marg{number}\marg{cmd} +%\end{definition} +%This converts a plain decimal number \meta{number} (that uses a full +%stop as the decimal character and has no number group characters) +%into a locale dependent format. The resulting number is stored +%in \meta{cmd}, which must be a control sequence. For example: +%\begin{verbatim} +%\DTLdecimaltolocale{6795.3}{\mynum} +%\end{verbatim} +%\DTLdecimaltolocale{6795.3}{\mynum} +%will define \cs{mynum} to be \texttt{\mynum}. +% +%\DescribeMacro{\DTLdecimaltocurrency} +%\begin{definition} +%\cs{DTLdecimaltocurrency}\marg{number}\marg{cmd} +%\end{definition} +%This will convert a plain decimal number \meta{number} into a +%locale dependent currency format. For example: +%\begin{verbatim} +%\DTLdecimaltocurrency{267.5}{\price}\price +%\end{verbatim} +%will produce: +%\DTLdecimaltocurrency{267.5}{\price}\price. +% +%The currency symbol used by \cs{DTLdecimaltocurrency} is +%initially "\$", but will use the currency last encountered. +%So, for example +%\begin{verbatim} +%\DTLifcurrency{\texteuro45.00}{}{}% +%\DTLdecimaltocurrency{267.5}{\price}\price +%\end{verbatim} +%will produce: +%\DTLifcurrency{\texteuro45.00}{}{}\relax +%\DTLdecimaltocurrency{267.5}{\price}\price. This is because +%the last currency symbol to be encountered was \cs{texteuro}. +%You can reset the currency symbol using the command: +%\DescribeMacro{\DTLsetdefaultcurrency} +%\begin{definition} +%\cs{DTLsetdefaultcurrency}\marg{symbol} +%\end{definition} +%For example: +%\begin{verbatim} +%\DTLsetdefaultcurrency{\textyen}% +%\DTLdecimaltocurrency{267.5}{\price}\price +%\end{verbatim} +%will produce: +%\DTLsetdefaultcurrency{\textyen}\relax +%\DTLdecimaltocurrency{267.5}{\price}\price +% +%The \sty{datatool} package provides convenience commands which +%use \cs{DTLconverttodecimal}, and then use the basic macros provided +%by the \sty{fp} package. The resulting value is then converted +%back into the locale format using +%\cs{DTLdecimaltolocale} or \cs{DTLdecimaltocurrency}. +% +%\DescribeMacro{\DTLadd} +%\begin{definition} +%\cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%\DescribeMacro{\DTLgadd} +%\begin{definition} +%\cs{DTLgadd}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%This sets the control sequence \meta{cmd} to \meta{num1}+\meta{num2}. +%\cs{DLTadd} sets \meta{cmd} locally, while \cs{DTLgadd} sets +%\meta{cmd} globally. +% +%For example: +%\begin{verbatim} +%\DTLadd{\result}{3,562.65}{412.2}\result +%\end{verbatim} +%will produce: +%\DTLadd{\result}{3,562.65}{412.2}\result. Since +%\cs{DTLconverttodecimal} can also convert currency, you can +%also add prices. For example: +%\begin{verbatim} +%\DTLadd{\result}{\pounds3,562.65}{\pounds452.2}\result +%\end{verbatim} +%produces: +%\DTLadd{\result}{\pounds3,562.65}{\pounds452.2}\result. +% +%Note that \sty{datatool} isn't aware of exchange rates! If you +%use different currency symbols, the last symbol will be used. +%For example +%\begin{verbatim} +%\DTLadd{\result}{\pounds3,562.65}{\euro452.2}\result +%\end{verbatim} +%produces: +%\DTLadd{\result}{\pounds3,562.65}{\euro452.2}\result. +% +%Likewise, if one value is a number and the other is a currency, +%the type of the last value, \meta{num2}, will be used for the +%result. For example: +%\begin{verbatim} +%\DTLadd{\result}{3,562.65}{\$452.2}\result +%\end{verbatim} +%produces: +%\DTLadd{\result}{3,562.65}{\$452.2}\result. +% +%\DescribeMacro{\DTLaddall} +%\begin{definition} +%\cs{DTLaddall}\marg{cmd}\marg{number list} +%\end{definition} +%\DescribeMacro{\DTLgaddall} +%\begin{definition} +%\cs{DTLgaddall}\marg{cmd}\marg{number list} +%\end{definition} +%This sets the control sequence \meta{cmd} to the sum of all +%the numbers in \meta{number list}. +%\cs{DLTaddall} sets \meta{cmd} locally, while \cs{DTLgaddall} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLaddall{\total}{25.1,45.2,35.6}\total +%\end{verbatim} +%produces: +%\DTLaddall{\total}{25.1,45.2,35.6}\total. +%Note that if any of the numbers in \meta{number list} contain +%a comma, you must group the number. Example: +%\begin{verbatim} +%\DTLaddall{\total}{{1,525},{2,340},500}\total +%\end{verbatim} +%produces: +%\DTLaddall{\total}{{1,525},{2,340},500}\total. +% +%\DescribeMacro{\DTLsub} +%\begin{definition} +%\cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%\DescribeMacro{\DTLgsub} +%\begin{definition} +%\cs{DTLgsub}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%This sets the control sequence \meta{cmd} to +%\meta{num1}$-$\meta{num2}. +%\cs{DLTsub} sets \meta{cmd} locally, while \cs{DTLgsub} sets +%\meta{cmd} globally. +% +%For example: +%\begin{verbatim} +%\DTLsub{\result}{3,562.65}{412.2}\result +%\end{verbatim} +%will produce: +%\DTLsub{\result}{3,562.65}{412.2}\result. As with \cs{DTLadd}, +%\meta{num1} and \meta{num2} may be currency. +% +%\DescribeMacro{\DTLmul} +%\begin{definition} +%\cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%\DescribeMacro{\DTLgmul} +%\begin{definition} +%\cs{DTLgmul}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%This sets the control sequence \meta{cmd} to +%\meta{num1}$\times$\meta{num2}. +%\cs{DLTmul} sets \meta{cmd} locally, while \cs{DTLgmul} sets +%\meta{cmd} globally. +% +%For example: +%\begin{verbatim} +%\DTLmul{\result}{568.95}{2}\result +%\end{verbatim} +%will produce: +%\DTLmul{\result}{568.95}{2}\result. Again, \meta{num1} or +%\meta{num2} may be currency, but unlike \cs{DTLadd} and \cs{DTLsub}, +%currency overrides integer/real. For example: +%\begin{verbatim} +%\DTLmul{\result}{\pounds568.95}{2}\result +%\end{verbatim} +%will produce: +%\DTLmul{\result}{\pounds568.95}{2}\result. Likewise, +%\begin{verbatim} +%\DTLmul{\result}{2}{\pounds568.95}\result +%\end{verbatim} +%will produce: +%\DTLmul{\result}{2}{\pounds568.95}\result. Although it doesn't make +%sense to multiply two currencies, \sty{datatool} will allow +%\begin{verbatim} +%\DTLmul{\result}{\$2}{\pounds568.95}\result +%\end{verbatim} +%which will produce: +%\DTLmul{\result}{\$2}{\pounds568.95}\result. +% +%\DescribeMacro{\DTLdiv} +%\begin{definition} +%\cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%\DescribeMacro{\DTLgdiv} +%\begin{definition} +%\cs{DTLgdiv}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%This sets the control sequence \meta{cmd} to +%\meta{num1}$\div$\meta{num2}. +%\cs{DLTdiv} sets \meta{cmd} locally, while \cs{DTLgdiv} sets +%\meta{cmd} globally. +% +%For example: +%\begin{verbatim} +%\DTLdiv{\result}{501}{2}\result +%\end{verbatim} +%will produce: +%\DTLdiv{\result}{501}{2}\result. Again, \meta{num1} or \meta{num2} +%may be currency, but the resulting type will be not be a currency +%if both \meta{num1} and \meta{num2} use the same currency symbol. +%For example: +%\begin{verbatim} +%\DTLdiv{\result}{\$501}{\$2}\result +%\end{verbatim} +%will produce: +%\DTLdiv{\result}{\$501}{\$2}\result. Whereas +%\begin{verbatim} +%\DTLdiv{\result}{\$501}{2}\result +%\end{verbatim} +%will produce: +%\DTLdiv{\result}{\$501}{2}\result. +% +%\DescribeMacro{\DTLabs} +%\begin{definition} +%\cs{DTLabs}\marg{cmd}\marg{num} +%\end{definition} +%\DescribeMacro{\DTLgabs} +%\begin{definition} +%\cs{DTLgabs}\marg{cmd}\marg{num} +%\end{definition} +%This sets \meta{cmd} to the absolute value of \meta{num}. +%\cs{DLTabs} sets \meta{cmd} locally, while \cs{DTLgabs} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLabs{\result}{-\pounds2.50}\result +%\end{verbatim} +%produces: +%\DTLabs{\result}{-\pounds2.50}\result. +% +%\DescribeMacro{\DTLneg} +%\begin{definition} +%\cs{DTLneg}\marg{cmd}\marg{num} +%\end{definition} +%\DescribeMacro{\DTLgneg} +%\begin{definition} +%\cs{DTLgneg}\marg{cmd}\marg{num} +%\end{definition} +%This sets \meta{cmd} to the negative of \meta{num}. +%\cs{DLTneg} sets \meta{cmd} locally, while \cs{DTLgneg} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLneg{\result}{\pounds2.50}\result +%\end{verbatim} +%produces: +%\DTLneg{\result}{\pounds2.50}\result. +% +%\DescribeMacro{\DTLsqrt} +%\begin{definition} +%\cs{DTLsqrt}\marg{cmd}\marg{num} +%\end{definition} +%\DescribeMacro{\DTLgsqrt} +%\begin{definition} +%\cs{DTLgsqrt}\marg{cmd}\marg{num} +%\end{definition} +%This sets \meta{cmd} to the sqrt root of \meta{num}. +%\cs{DLTsqrt} sets \meta{cmd} locally, while \cs{DTLgsqrt} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLsqrt{\result}{2}\result +%\end{verbatim} +%produces: +%\DTLsqrt{\result}{2}\result. +% +%\DescribeMacro{\DTLmin} +%\begin{definition} +%\cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%\DescribeMacro{\DTLgmin} +%\begin{definition} +%\cs{DTLgmin}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%This sets the control sequence \meta{cmd} to the minimum of +%\meta{num1} and \meta{num2}. +%\cs{DLTmin} sets \meta{cmd} locally, while \cs{DTLgmin} sets +%\meta{cmd} globally. For example: +%\begin{verbatim} +%\DTLmin{\result}{256}{32}\result +%\end{verbatim} +%produces: +%\DTLmin{\result}{256}{32}\result. +%Again, \meta{num1} and \meta{num2} may +%be currency. For example: +%\begin{verbatim} +%\DTLmin{\result}{256}{\pounds32}\result +%\end{verbatim} +%produces: +%\DTLmin{\result}{256}{\pounds32}\result, whereas +%\begin{verbatim} +%\DTLmin{\result}{\pounds256}{32}\result +%\end{verbatim} +%produces: +%\DTLmin{\result}{\pounds256}{32}\result. As mentioned above, +%\sty{datatool} doesn't know about exchange rates, so be careful +%about mixing currencies. For example: +%\begin{verbatim} +%\DTLmin{\result}{\pounds5}{\$6}\result +%\end{verbatim} +%produces: +%\DTLmin{\result}{\pounds5}{\$6}\result, which may not necessarily +%be true! +% +%\DescribeMacro{\DTLminall} +%\begin{definition} +%\cs{DTLminall}\marg{cmd}\marg{number list} +%\end{definition} +%\DescribeMacro{\DTLgminall} +%\begin{definition} +%\cs{DTLgminall}\marg{cmd}\marg{number list} +%\end{definition} +%This sets the control sequence \meta{cmd} to the minimum of all +%the numbers in \meta{number list}. +%\cs{DLTminall} sets \meta{cmd} locally, while \cs{DTLgminall} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLminall{\theMin}{25.1,45.2,35.6}\theMin +%\end{verbatim} +%produces: +%\DTLminall{\theMin}{25.1,45.2,35.6}\theMin. +%Note that if any of the numbers in \meta{number list} contain +%a comma, you must group the number. Example: +%\begin{verbatim} +%\DTLminall{\theMin}{{1,525},{2,340},500}\theMin +%\end{verbatim} +%produces: +%\DTLminall{\theMin}{{1,525},{2,340},500}\theMin. +% +%\DescribeMacro{\DTLmax} +%\begin{definition} +%\cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%\DescribeMacro{\DTLgmax} +%\begin{definition} +%\cs{DTLgmax}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +%This sets the control sequence \meta{cmd} to the maximum of +%\meta{num1} and \meta{num2}. +%\cs{DLTmax} sets \meta{cmd} locally, while \cs{DTLgmax} sets +%\meta{cmd} globally. For example: +%\begin{verbatim} +%\DTLmax{\result}{256}{32}\result +%\end{verbatim} +%produces: +%\DTLmax{\result}{256}{32}\result. +%Again, \meta{num1} and \meta{num2} may +%be currency, but the same warnings for \cs{DTLmin} apply. +% +%\DescribeMacro{\DTLmaxall} +%\begin{definition} +%\cs{DTLmaxall}\marg{cmd}\marg{number list} +%\end{definition} +%\DescribeMacro{\DTLgmaxall} +%\begin{definition} +%\cs{DTLgmaxall}\marg{cmd}\marg{number list} +%\end{definition} +%This sets the control sequence \meta{cmd} to the maximum of all +%the numbers in \meta{number list}. +%\cs{DLTmaxall} sets \meta{cmd} locally, while \cs{DTLgmaxall} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLmaxall{\theMax}{25.1,45.2,35.6}\theMax +%\end{verbatim} +%produces: +%\DTLmaxall{\theMax}{25.1,45.2,35.6}\theMax. +%Note that if any of the numbers in \meta{number list} contain +%a comma, you must group the number. Example: +%\begin{verbatim} +%\DTLmaxall{\theMax}{{1,525},{2,340},500}\theMax +%\end{verbatim} +%produces: +%\DTLmaxall{\theMax}{{1,525},{2,340},500}\theMax. +% +%\DescribeMacro{\DTLmeanforall} +%\begin{definition} +%\cs{DTLmeanforall}\marg{cmd}\marg{number list} +%\end{definition} +%\DescribeMacro{\DTLgmeanall} +%\begin{definition} +%\cs{DTLgmeanforall}\marg{cmd}\marg{number list} +%\end{definition} +%This sets the control sequence \meta{cmd} to the arithmetic mean of all +%the numbers in \meta{number list}. +%\cs{DLTmeanforall} sets \meta{cmd} locally, while \cs{DTLgmeanforall} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLmeanforall{\theMean}{25.1,45.2,35.6}\theMean +%\end{verbatim} +%produces: +%\DTLmeanforall{\theMean}{25.1,45.2,35.6}\theMean. +%Note that if any of the numbers in \meta{number list} contain +%a comma, you must group the number. Example: +%\begin{verbatim} +%\DTLmeanforall{\theMean}{{1,525},{2,340},500}\theMean +%\end{verbatim} +%produces: +%\DTLmeanforall{\theMean}{{1,525},{2,340},500}\theMean. +% +%\DescribeMacro{\DTLvarianceforall} +%\begin{definition} +%\cs{DTLvarianceforall}\marg{cmd}\marg{number list} +%\end{definition} +%\DescribeMacro{\DTLgvarianceforall} +%\begin{definition} +%\cs{DTLgvarianceforall}\marg{cmd}\marg{number list} +%\end{definition} +%This sets the control sequence \meta{cmd} to the variance of all +%the numbers in \meta{number list}. +%\cs{DLTvarianceforall} sets \meta{cmd} locally, while \cs{DTLgvarianceforall} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLvarianceforall{\theVar}{25.1,45.2,35.6}\theVar +%\end{verbatim} +%produces: +%\DTLvarianceforall{\theVar}{25.1,45.2,35.6}\theVar. +%Again note that if any of the numbers in \meta{number list} +%contain a comma, you must group the number. +% +%\DescribeMacro{\DTLsdforall} +%\begin{definition} +%\cs{DTLsdforall}\marg{cmd}\marg{number list} +%\end{definition} +%\DescribeMacro{\DTLgsdforall} +%\begin{definition} +%\cs{DTLgsdforall}\marg{cmd}\marg{number list} +%\end{definition} +%This sets the control sequence \meta{cmd} to the standard deviation of all +%the numbers in \meta{number list}. +%\cs{DLTsdforall} sets \meta{cmd} locally, while \cs{DTLgsdforall} sets +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLsdforall{\theSD}{25.1,45.2,35.6}\theSD +%\end{verbatim} +%produces: +%\DTLsdforall{\theSD}{25.1,45.2,35.6}\theSD. +%Note that if any of the numbers in \meta{number list} contain +%a comma, you must group the number. Example: +%\begin{verbatim} +%\DTLsdforall{\theSD}{{1,525},{2,340},500}\theSD +%\end{verbatim} +%produces: +%\DTLsdforall{\theSD}{{1,525},{2,340},500}\theSD. +% +%\DescribeMacro{\DTLround} +%\begin{definition} +%\cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +%\DescribeMacro{\DTLground} +%\begin{definition} +%\cs{DTLground}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +%This sets \meta{cmd} to \meta{num} rounded to \meta{num digits} +%after the decimal character. +%\cs{DLTround} sets \meta{cmd} locally, while \cs{DTLground} sets +%\meta{cmd} globally. +% +%\DescribeMacro{\DTLtrunc} +%\begin{definition} +%\cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +%\DescribeMacro{\DTLgtrunc} +%\begin{definition} +%\cs{DTLgtrunc}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +%This sets \meta{cmd} to \meta{num} truncated to \meta{num digits} +%after the decimal character. +%\cs{DLTtrunc} sets \meta{cmd} locally, while \cs{DTLgtrunc} sets +%\meta{cmd} globally. +% +%\DescribeMacro{\DTLclip} +%\begin{definition} +%\cs{DTLclip}\marg{cmd}\marg{num} +%\end{definition} +%\DescribeMacro{\DTLgclip} +%\begin{definition} +%\cs{DTLgclip}\marg{cmd}\marg{num} +%\end{definition} +%This sets \meta{cmd} to \meta{num} with all unnecessary 0's +%removed. +%\cs{DLTclip} sets \meta{cmd} locally, while \cs{DTLgclip} sets +%\meta{cmd} globally. +% +%\section{Strings} +% +%Strings are considered to be anything non-numerical. The +%\sty{datatool} package loads the \sty{substr} package, so +%you can use the commands defined in that package to determine +%if one string is contained in another string. In addition, +%the \sty{datatool} provides the following macros: +% +%\DescribeMacro{\DTLinitials} +%\begin{definition} +%\cs{DTLinitials}\marg{string} +%\end{definition} +%This converts \meta{string} (typically a name) into initials. +%For example: +%\begin{verbatim} +%\DTLinitials{Mary Ann} +%\end{verbatim} +%produces: +%\DTLinitials{Mary Ann}. Note that +%\begin{verbatim} +%\DTLinitials{Mary-Ann} +%\end{verbatim} +%produces: +%\DTLinitials{Mary-Ann}. +% +%\DescribeMacro{\DTLstoreinitials} +%\begin{definition} +%\cs{DTLstoreinitials}\marg{string}\marg{cmd} +%\end{definition} +%This converts \meta{string} into initials and stores the +%result in \meta{cmd}. +% +%The above commands rely on the following to format the +%initials: +%\DescribeMacro{\DTLafterinitials} +%\begin{definition} +%\cs{DTLafterinitials} +%\end{definition} +%This indicates what to do at the end of the initials. This +%simply does a full stop by default. +% +%\DescribeMacro{\DTLbetweeninitials} +%\begin{definition} +%\cs{DTLbetweeninitials} +%\end{definition} +%This indicates what to do between initials. This does a +%full stop followed by a space by default. +% +%\DescribeMacro{\DTLafterinitialbeforehyphen} +%\begin{definition} +%\cs{DTLafterinitialbeforehyphen} +%\end{definition} +%This indicates what to do between an initial and a hyphen. +%This simply does a full stop by default. +% +%\section{Databases} +%\label{sec:databases} +% +%The \sty{datatool} package provides a means of creating and +%loading databases. Once a database has been created (or loaded), +%it is possible to iterate through each row of data, to make it +%easier to perform repetitive actions, such as mail merging. +% +%\subsection{Creating a New Database} +%\label{sec:newdb} +% +%\DescribeMacro{\DTLnewdb} +%\begin{definition} +%\cs{DTLnewdb}\marg{db name} +%\end{definition} +%This command creates a new empty database called \meta{db name}. You +%can test if a database is empty using: +%\DescribeMacro{\DTLifdbempty} +%\begin{definition} +%\cs{DTLifdbempty}\marg{db name}\marg{true part}\marg{false part} +%\end{definition} +%If the database called \meta{db name} is empty, do \meta{true part}, +%otherwise do \meta{false part}. +% +%\DescribeMacro{\DTLrowcount} +%\begin{definition} +%\cs{DTLrowcount}\marg{db name} +%\end{definition} +%This command displays the number of rows in the database called +%\meta{db name}. +% +%\DescribeMacro{\DTLnewrow} +%\begin{definition} +%\cs{DTLnewrow}\marg{db name} +%\end{definition} +%This command starts a new row in the database called \meta{db name}. +%This new row becomes the current row when adding new entries. +% +%For example, the following creates an empty database called +%\texttt{mydata}: +%\begin{verbatim} +%\DTLnewdb{mydata} +%\end{verbatim} +%\DTLnewdb{mydata}\relax +%The following tests if the database is empty: +%\begin{verbatim} +%\DTLifdbempty{mydata}{empty}{not empty}! +%\end{verbatim} +%This produces: +%\DTLifdbempty{mydata}{empty}{not empty}! +% +%The following adds an empty row to the database, this is the +%first row of the database: +%\begin{verbatim} +%\DTLnewrow{mydata} +%\end{verbatim} +%\DTLnewrow{mydata}\relax +%Note that even though the only row in the database is currently +%empty, the database is no longer considered to be empty: +%\begin{verbatim} +%\DTLifdbempty{mydata}{empty}{not empty}! +%\end{verbatim} +%This now produces: +%\DTLifdbempty{mydata}{empty}{not empty}! The row count is +%given by +%\begin{verbatim} +%\DTLrowcount{mydata} +%\end{verbatim} +%which produces: +%\DTLrowcount{mydata}. +% +%\DescribeMacro{\DTLnewdbentry} +%\begin{definition} +%\cs{DTLnewdbentry}\marg{db name}\marg{key}\marg{value} +%\end{definition} +%This creates a new entry with the identifier \meta{key} whose value +%is \meta{value} and adds it to the current row of the database +%called \meta{db name}. For example: +%\begin{verbatim} +%\DTLnewdbentry{mydata}{Surname}{Smith} +%\DTLnewdbentry{mydata}{FirstName}{John} +%\end{verbatim} +%Adds an entry with identifier \texttt{Surname} and value +%\texttt{Smith} to the current row of the database named +%\texttt{mydata}, and then adds an entry with identifier +%\texttt{FirstName} and value \texttt{John}. +% +%Note that database entries can't contain paragraph breaks as +%many of the macros used by \sty{datatool} are short commands. +%If you do need a paragraph break in an entry, you can instead +%use the command: +%\DescribeMacro{\DTLpar} +%\begin{definition} +%\cs{DTLpar} +%\end{definition} +% +%\subsection{Loading a Database from an External ASCII File} +%\label{sec:loaddb} +% +%Instead of using the commands described in \autoref{sec:newdb} +%to create a new database, you can load a database from an +%external ASCII file using: +%\DescribeMacro{\DTLloaddb} +%\begin{definition} +%\cs{DTLloaddb}\marg{db name}\marg{filename} +%\end{definition} +%This creates a new database called \meta{db name}, and fills +%it with the entries given in the file \meta{filename}. +%The filename must have a header row at the start of the file, +%which provides the \meta{key} when creating a new database entry +%using \ics{DTLnewdbentry}. By default, the entries in the database +%must be separated by a comma, and optionally delimited by the +%double quote character (\verb|"|). The separator can be changed +%to a tab separator using the command: +%\DescribeMacro{\DTLsettabseparator} +%\begin{definition} +%\cs{DTLsettabseparator} +%\end{definition} +%To set the separator to a character other than a tab, you need to use +%\DescribeMacro{\DTLsetseparator} +%\begin{definition} +%\cs{DTLsetseparator}\marg{character} +%\end{definition} +%The delimiter can be changed using +%\DescribeMacro{\DTLsetdelimiter} +%\begin{definition} +%\cs{DTLsetdelimiter}\marg{character} +%\end{definition} +% +%For example, suppose you have a file called \texttt{mydata.csv} +%which contains the following: +%\begin{verbatim} +%FirstName,Surname,Score +%John,"Smith, Jr",68 +%Jane,Brown,75 +%Andy,Brown,42 +%Z\"oe,Adams,52 +%\end{verbatim} +%then +%\begin{verbatim} +%\DTLloaddb{mydata}{mydata.csv} +%\end{verbatim} +%is equivalent to: +%\begin{verbatim} +%\DTLnewdb{mydata} +%\DTLnewrow{mydata}% +%\DTLnewdbentry{mydata}{FirstName}{John}% +%\DTLnewdbentry{mydata}{Surname}{Smith, Jr}% +%\DTLnewdbentry{mydata}{Score}{68}% +%\DTLnewrow{mydata}% +%\DTLnewdbentry{mydata}{FirstName}{Jane}% +%\DTLnewdbentry{mydata}{Surname}{Brown}% +%\DTLnewdbentry{mydata}{Score}{75}% +%\DTLnewrow{mydata}% +%\DTLnewdbentry{mydata}{FirstName}{Andy}% +%\DTLnewdbentry{mydata}{Surname}{Brown}% +%\DTLnewdbentry{mydata}{Score}{42}% +%\DTLnewrow{mydata}% +%\DTLnewdbentry{mydata}{FirstName}{Z\"oe}% +%\DTLnewdbentry{mydata}{Score}{52}% +%\DTLnewdbentry{mydata}{Surname}{Adams}% +%\end{verbatim} +%Note that the entry \texttt{Smith, Jr} had to be delimited in +%\texttt{mydata.csv} using the double quote character since it +%contained a comma which is used as the separator. +% +%The file used in the above example contained a \LaTeX\ command, +%namely \verb|\"|. When using \ics{DTLloaddb} all the special +%characters that appear in the command retain their \LaTeX\ meaning +%when the file is loaded. It is likely however that the data file +%may have been created by another application that is not \TeX-aware, +%for example a spreadsheet application. For example, suppose you +%have a file called, say, \texttt{products.csv} which looks +%like: +%\begin{verbatim} +%Product,Cost +%Fruit & Veg,$1.25 +%Stationary,$0.80 +%\end{verbatim} +%This file contains two of \TeX's special characters, namely +%"&" and \verb|$|. In this case, if you try to load the file +%using \ics{DTLloaddb}, you will encounter errors. Instead you +%can use: +%\DescribeMacro{\DTLloadrawdb} +%\begin{definition} +%\cs{DTLloadrawdb}\marg{db name}\marg{filename} +%\end{definition} +%This is the same as \ics{DTLloaddb} except that it maps nine of +%the ten special characters onto commands that produce that +%symbol. The only character that retains its active state is the +%backslash character, so you will still need to check the file +%for backslash characters. The mappings used are listed in +%\autoref{tab:rawmappings}. So using the file \texttt{products.csv}, +%as described above, +%\begin{verbatim} +%\DTLloadrawdb{mydata}{products.csv} +%\end{verbatim} +%is equivalent to: +%\begin{verbatim} +%\DTLnewdb{mydata} +%\DTLnewrow{mydata}% +%\DTLnewdbentry{mydata}{Product}{Fruit \& Veg}% +%\DTLnewdbentry{mydata}{Cost}{\$1.25}% +%\DTLnewrow{mydata}% +%\DTLnewdbentry{mydata}{Product}{Stationary}% +%\DTLnewdbentry{mydata}{Cost}{\$0.80}% +%\end{verbatim} +% +%\begin{table}[htbp] +%\caption{Special character mappings used by \cs{DTLloadrawdb} +%(note that the backslash retains its active state)} +%\label{tab:rawmappings} +%\begin{center} +%\begin{tabular}{ll} +%Character & Mapping\\ +%\verb|%| & \verb|\%|\\ +%\verb|$| & \verb|\$|\\ +%\verb|&| & \verb|\&|\\ +%\verb|#| & \verb|\#|\\ +%\verb|_| & \verb|\_|\\ +%\verb|{| & \verb|\{|\\ +%\verb|}| & \verb|\}|\\ +%\verb|~| & \cs{textasciitilde}\\ +%\verb|^| & \cs{textasciicircum} +%\end{tabular} +%\end{center} +%\end{table} +% +%It may be that there are other characters that require mapping. +%For example, the file \texttt{products.csv} may instead look like:\par +%\vskip\baselineskip +%\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} +%Product,Cost +%Fruit \& Veg,\pounds1.25 +%Stationary,\pounds0.80 +%\end{ttfamily} +%\vskip\baselineskip +%The pound character is not an internationally standard keyboard +%character, and does not achieve the desired effect when used +%in a \LaTeX\ document. It will therefore be necessary to convert +%this symbol to an appropriate control sequence. This can be done +%using the command: +%\DescribeMacro{\DTLrawmap} +%\begin{definition} +%\cs{DTLrawmap}\marg{string}\marg{replacement} +%\end{definition} +%For example:\par +%\vskip\baselineskip +%\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} +%\cs{DTLrawmap}\char`\{\pounds\char`\}\char`\{\cs{pounds}\char`\} +%\end{ttfamily} +%\vskip\baselineskip\noindent +%will convert all occurrences\footnote{in the \LaTeX\ database, not +%in the data file itself!} of \texttt{\pounds} with \cs{pounds}. +% +%Note that the warning in the previous section about no paragraph +%breaks in an entry also applies to entries loaded from a database. +%If you do need a paragraph break, use \ics{DTLpar} instead of +%\cs{par}, but remember that each row of data in an external data file +%must not have a line break. +% +%\subsection{Iterating Through a Database} +%\label{sec:dbforeach} +% +%Once you have created a database, either loading it from an +%external file, as described in \autoref{sec:loaddb}, or using the +%commands described in \autoref{sec:newdb}, you can then iterate +%through each row of the database and access elements in that row. +% +%\DescribeMacro{\DTLforeach} +%\begin{definition} +%\cs{DTLforeach}\oarg{condition}\marg{db name}\marg{values}\marg{text} +%\end{definition} +%This will iterate through each row of the database called +%\meta{db name}, applying \meta{text} to each row of the database +%where \meta{condition} is met. The argument \meta{values} is a +%comma separated list of \meta{cmd}"="\meta{key} pairs. At the +%start of each row, each command \meta{cmd} in the \meta{values} +%list will be set to the value of the entry given by \meta{key}. +%These commands may then be used in \meta{text}. +%Note that this assignment is done globally to ensure that +%\cs{DLTforeach} works correctly in a \env{tabular} environment. +%Since you may want to use the same set of commands in a later +%\cs{DTLforeach}, the commands are not checked to determine if they +%already exist. It is therefore important that you check you +%are not using an existing command whose value should not be changed. +% +%The optional argument \meta{condition} is a condition in the +%form allowed by \cs{ifthenelse}. This includes the commands +%provided by the \sty{ifthen} package, as well as the commands +%described in \autoref{sec:ifthen}. The default value of +%\meta{condition} is "\boolean{true}". +% +%\begin{example}{Student scores}{ex:scores} +%Suppose you have a data file called \texttt{studentscores.csv} that +%contains the following: +%\begin{verbatim} +%FirstName,Surname,StudentNo,Score +%John,"Smith, Jr",102689,68 +%Jane,Brown,102647,75 +%Andy,Brown,103569,42 +%Z\"oe,Adams,105987,52 +%Roger,Brady,106872,58 +%Clare,Verdon,104356,45 +%\end{verbatim} +%\DTLnewdb{scores}\relax +%\DTLnewrow{scores}\relax +%\DTLnewdbentry{scores}{FirstName}{John}\relax +%\DTLnewdbentry{scores}{Surname}{Smith, Jr}\relax +%\DTLnewdbentry{scores}{StudentNo}{102689}\relax +%\DTLnewdbentry{scores}{Score}{68}\relax +%\DTLnewrow{scores}\relax +%\DTLnewdbentry{scores}{FirstName}{Jane}\relax +%\DTLnewdbentry{scores}{Surname}{Brown}\relax +%\DTLnewdbentry{scores}{StudentNo}{102647}\relax +%\DTLnewdbentry{scores}{Score}{75}\relax +%\DTLnewrow{scores}\relax +%\DTLnewdbentry{scores}{FirstName}{Andy}\relax +%\DTLnewdbentry{scores}{Surname}{Brown}\relax +%\DTLnewdbentry{scores}{StudentNo}{103569}\relax +%\DTLnewdbentry{scores}{Score}{42}\relax +%\DTLnewrow{scores}\relax +%\DTLnewdbentry{scores}{FirstName}{Z\"oe}\relax +%\DTLnewdbentry{scores}{Score}{52}\relax +%\DTLnewdbentry{scores}{StudentNo}{105987}\relax +%\DTLnewdbentry{scores}{Surname}{Adams}\relax +%\DTLnewrow{scores}\relax +%\DTLnewdbentry{scores}{FirstName}{Roger}\relax +%\DTLnewdbentry{scores}{Score}{58}\relax +%\DTLnewdbentry{scores}{StudentNo}{106872}\relax +%\DTLnewdbentry{scores}{Surname}{Brady}\relax +%\DTLnewrow{scores}\relax +%\DTLnewdbentry{scores}{FirstName}{Clare}\relax +%\DTLnewdbentry{scores}{Score}{45}\relax +%\DTLnewdbentry{scores}{StudentNo}{104356}\relax +%\DTLnewdbentry{scores}{Surname}{Verdon}\relax +%and you load the data into a database called "scores" using: +%\begin{verbatim} +%\DTLloaddb{scores}{studentscores.csv} +%\end{verbatim} +%you can then display the database in a table as follows: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores}\label{tab:scores} +%\centering +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\ +%\firstname & \surname & \score} +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:scores}. (Note that since I didn't +%need the student registration number, I didn't bother to +%assign a command to the key "StudentNo".) +% +%\begin{table}[htbp] +%\caption{Student Scores}\label{tab:scores} +%\centering +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\ +%\firstname & \surname & \score} +%\end{tabular} +%\end{table} +%\end{example} +% +%The macro \ics{DTLforeach} may be nested up to three times. Each +%level uses the corresponding counters: +%\counterfmt{DTLrowi}, +%\counterfmt{DTLrowii} and +%\counterfmt{DTLrowiii} that keep track of +%the current row. Note that these counters are only incremented +%when \meta{condition} is satisfied. These counters are incremented +%using \cs{refstepcounter} before the start of \meta{text}, so they +%may be referenced using \cs{label}, however remember that \cs{label} +%references the last counter to be incremented using +%\cs{refstepcounter} \emph{in the current scope}. The \cs{label} +%should therefore be the first command in \meta{text} to ensure +%that it references the current row counter. +% +%\DescribeMacro{\DTLcurrentindex} +%\begin{definition} +%\cs{DTLcurrentindex} +%\end{definition} +%At the start of each iteration, \cs{DTLcurrentindex} is set +%to the arabic value of the current row counter. +% +%\begin{example}{Student Scores---Labelling}{ex:label} +%In the previous example, the student scores, stored in the +%database "scores" were placed in a table. In this example the +%table will be modified slightly to number each student according +%to the row. Suppose I also want to identify which row Jane Brown +%is in, and reference it in the text. The easiest way to do this +%is to construct a label on each row which uniquely identifies +%that student. The label can't simply be constructed from the +%surname, as there are two students with the same surname. In order +%to create a unique label, I can either construct a label from +%both the surname and the first name, or I can use the student's +%registration number, or I can use the student's score, since all +%the scores are unique. The former method will cause a problem since +%one of the names (Z\"oe) contains an accent command. Although +%the registration numbers are all unique, they are not particularly +%memorable, so I shall instead use the scores. +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores}\label{tab:scoreslab} +%\centering +%\begin{tabular}{cllc} +%\bfseries Row & +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\label{row:\score}\\\theDTLrowi & +%\firstname & \surname & \score}% +%\end{tabular} +%\end{table} +% +%Jane Brown scored the highest (75\%), her score can be seen on +%row~\ref{row:75}. +%\end{verbatim} +%This produces \autoref{tab:scoreslab} and the following text: +%Jane Brown scored the highest (75\%), her score can be seen on +%row~\ref*{row:75}. +% +%\textbf{Note:} the \cs{label} command is placed before +%"\\" to ensure that it is in the same scope as the command +%"\refstepcounter{DTLrowi}". +% +%\begin{table}[htbp] +%\caption{Student Scores}\label{tab:scoreslab} +%\centering +%\begin{tabular}{cllc} +%\bfseries Row & +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\label{row:\score}\\\theDTLrowi & +%\firstname & \surname & \score}\relax +%\end{tabular} +%\end{table} +%\end{example} +% +%\DescribeMacro{\DTLsavelastrowcount} +%\begin{definition} +%\cs{DTLsavelastrowcount}\marg{cmd} +%\end{definition} +%This command will store the value of the row counter used in +%the last occurrence of \ics{DTLforeach} in the control sequence +%\meta{cmd}. +% +%\begin{example}{Filtering Rows}{ex:filter} +%As mentioned earlier, the optional argument \meta{condition} of +%\ics{DTLforeach} provides a means to exclude certain rows. +%This example uses the database defined in \autoref{ex:scores}, +%but only displays the information for students whose marks are +%above 60. At the end of the table, \cs{DTLsavelastrowcount} +%is used to store the number of rows in the table. (Note that +%\cs{DTLsavelastrowcount} is outside of \ics{DTLforeach}.) +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Top Student Scores}\label{tab:topscores} +%\centering +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach[\DTLisgt{\score}{60}]{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\ +%\firstname & \surname & \score} +%\end{tabular} +% +%\DTLsavelastrowcount{\n}% +%\n\ students scored above 60\%. +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:topscores}. Note that in this example, +%I could have specified the condition as "\score>60" since all +%the scores are integers, however, as it's possible that an entry +%may feasibly have a decimal score I have used \ics{DTLisgt} instead. +% +%\begin{table}[htbp] +%\caption{Top Student Scores}\label{tab:topscores} +%\centering +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach[\DTLisgt{\score}{60}]{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\ +%\firstname & \surname & \score} +%\end{tabular} +% +%\DTLsavelastrowcount{\n}\relax +%\n\ students scored above 60\%. +%\end{table} +% +%Suppose now, I only want to display the scores for students whose +%surname begins with `B'. I can do this as follows: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores (B)}\label{tab:Bscores} +%\centering +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach[\DTLisgt{\surname}{B}\and\DTLislt{\surname}{C}]{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\ +%\firstname & \surname & \score} +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:Bscores}. +% +%\begin{table}[htbp] +%\caption{Student Scores (B)}\label{tab:Bscores} +%\centering +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach[\DTLisgt{\surname}{B}\and\DTLislt{\surname}{C}]{scores} +%{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\ +%\firstname & \surname & \score} +%\end{tabular} +%\end{table} +% +%\end{example} +% +%Within the body of \ics{DTLforeach} (i.e.\ within \meta{text}) +%the following conditionals may be used: +%\DescribeMacro{\DTLiffirstrow} +%\begin{definition} +%\cs{DTLiffirstrow}\marg{true part}\marg{false part} +%\end{definition} +%If the current row is the first row, then do \meta{true part}, +%otherwise do \meta{false part}. +% +%\DescribeMacro{\DTLiflastrow} +%\begin{definition} +%\cs{DTLiflastrow}\marg{true part}\marg{false part} +%\end{definition} +%If the current row is the last row, then do \meta{true part}, +%otherwise do \meta{false part}. +% +%\DescribeMacro{\DTLifoddrow} +%\begin{definition} +%\cs{DTLifoddrow}\marg{true part}\marg{false part} +%\end{definition} +%If the current row number is an odd number, then do \meta{true part}, +%otherwise do \meta{false part}. +% +%\begin{example}{Stripy Tables}{ex:stripy} +%This example uses the same database as in the previous examples. +%It requires the \sty{colortbl} package, which provides the +%command \cs{rowcolor}. The command \cs{DTLifoddrow} is used +%to produce a striped table. +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{A Stripy Table}\label{tab:stripy} +%\centering +%\begin{tabular}{llc} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\\DTLifoddrow{\rowcolor{blue}}{\rowcolor{green}}% +%\firstname & \surname & \score}% +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:stripy}. +% +%\begin{table}[htbp] +%\caption{A Stripy Table}\label{tab:stripy} +%\centering +%\begin{tabular}{llc} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\\DTLifoddrow{\rowcolor{blue}}{\rowcolor{green}}\relax +%\firstname & \surname & \score}\relax +%\end{tabular} +%\end{table} +%\end{example} +% +%\begin{example}{Two Database Rows per Tabular Row}{ex:2rows} +%In order to save space, you may want two database rows per +%tabular row, when displaying a database in a \env{tabular} +%environment. This can be accomplished using \ics{DTLifoddrow}. +%For example +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Two Database Rows per Tabular Row}\label{tab:2rows} +%\centering +%\begin{tabular}{llcllc} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%) & +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\DTLifoddrow{\\}{&}\relax +%\firstname & \surname & \score}\relax +%\end{tabular} +%\end{table} +%\end{verbatim} +%produces \autoref{tab:2rows} +% +%\begin{table}[htbp] +%\caption{Two Database Rows per Tabular Row}\label{tab:2rows} +%\centering +%\begin{tabular}{llcllc} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%) & +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\DTLifoddrow{\\}{&}\relax +%\firstname & \surname & \score}\relax +%\end{tabular} +%\end{table} +%\end{example} +% +%\begin{example}{Nested \cs{DTLforeach}}{ex:nested} +%In this example I have a CSV file called "index.csv" which +%contains: +%\begin{verbatim} +%File,Temperature,NaCl,pH +%exp25a.csv,25,4.7,0.5 +%exp25b.csv,25,4.8,1.5 +%exp30a.csv,30,5.12,4.5 +%\end{verbatim} +%\DTLnewdb{index}\relax +%\DTLnewrow{index}\relax +%\DTLnewdbentry{index}{File}{exp25a.csv}\relax +%\DTLnewdbentry{index}{Temperature}{25}\relax +%\DTLnewdbentry{index}{NaCl}{4.7}\relax +%\DTLnewdbentry{index}{pH}{0.5}\relax +%\DTLnewrow{index}\relax +%\DTLnewdbentry{index}{File}{exp25b.csv}\relax +%\DTLnewdbentry{index}{Temperature}{25}\relax +%\DTLnewdbentry{index}{NaCl}{4.8}\relax +%\DTLnewdbentry{index}{pH}{1.5}\relax +%\DTLnewrow{index}\relax +%\DTLnewdbentry{index}{File}{exp30a.csv}\relax +%\DTLnewdbentry{index}{Temperature}{30}\relax +%\DTLnewdbentry{index}{NaCl}{5.12}\relax +%\DTLnewdbentry{index}{pH}{4.5}\relax +%The first column of this file contains the name of another +%CSV file which has the results of a time to growth experiment +%performed at the given incubation temperature, salt concentration +%and pH. The file "exp25a.csv" contains the following: +%\begin{verbatim} +%Time,Log Count +%0,3.75 +%23,3.9 +%45,4.0 +%\end{verbatim} +%\DTLnewdb{exp25a.csv}\relax +%\DTLnewrow{exp25a.csv}\relax +%\DTLnewdbentry{exp25a.csv}{Time}{0}\relax +%\DTLnewdbentry{exp25a.csv}{Log Count}{3.75}\relax +%\DTLnewrow{exp25a.csv}\relax +%\DTLnewdbentry{exp25a.csv}{Time}{23}\relax +%\DTLnewdbentry{exp25a.csv}{Log Count}{3.9}\relax +%\DTLnewrow{exp25a.csv}\relax +%\DTLnewdbentry{exp25a.csv}{Time}{45}\relax +%\DTLnewdbentry{exp25a.csv}{Log Count}{4.0}\relax +%The file "exp25b.csv" contains the following: +%\begin{verbatim} +%Time,Log Count +%0,3.6 +%60,3.8 +%120,4.0 +%\end{verbatim} +%\DTLnewdb{exp25b.csv}\relax +%\DTLnewrow{exp25b.csv}\relax +%\DTLnewdbentry{exp25b.csv}{Time}{0}\relax +%\DTLnewdbentry{exp25b.csv}{Log Count}{3.6}\relax +%\DTLnewrow{exp25b.csv}\relax +%\DTLnewdbentry{exp25b.csv}{Time}{60}\relax +%\DTLnewdbentry{exp25b.csv}{Log Count}{3.8}\relax +%\DTLnewrow{exp25b.csv}\relax +%\DTLnewdbentry{exp25b.csv}{Time}{120}\relax +%\DTLnewdbentry{exp25b.csv}{Log Count}{4.0}\relax +%The file "exp30a.csv" contains the following: +%\begin{verbatim} +%Time,Log Count +%0,3.73 +%23,3.67 +%60,4.9 +%\end{verbatim} +%\DTLnewdb{exp30a.csv}\relax +%\DTLnewrow{exp30a.csv}\relax +%\DTLnewdbentry{exp30a.csv}{Time}{0}\relax +%\DTLnewdbentry{exp30a.csv}{Log Count}{3.73}\relax +%\DTLnewrow{exp30a.csv}\relax +%\DTLnewdbentry{exp30a.csv}{Time}{23}\relax +%\DTLnewdbentry{exp30a.csv}{Log Count}{3.67}\relax +%\DTLnewrow{exp30a.csv}\relax +%\DTLnewdbentry{exp30a.csv}{Time}{60}\relax +%\DTLnewdbentry{exp30a.csv}{Log Count}{4.9}\relax +%Suppose I now want to iterate through "index.csv", load the given +%file, and create a table for that data. I can do this using +%nested \ics{DTLforeach} as follows: +%\begin{verbatim} +%% load index data file +%\DTLloaddb{index}{index.csv} +% +%% iterate through index database +%\DTLforeach{index}{\theFile=File,\theTemp=Temperature,% +%\theNaCl=NaCl,\thepH=pH}{% +%% load results file into database of the same name +%\DTLloaddb{\theFile}{\theFile}% +%% Create a table +%\begin{table}[htbp] +%\caption{Temperature = \theTemp, NaCl = \theNaCl, +%pH = \thepH}\label{tab:\theFile} +%\centering +%\begin{tabular}{rl} +%\bfseries Time & \bfseries Log Count +%\DTLforeach{\theFile}{\theTime=Time,\theLogCount=Log Count}{% +%\\\theTime & \theLogCount}% +%\end{tabular} +%\end{table} +%} +%\end{verbatim} +%This creates \autoref{tab:exp25a.csv} to \autoref{tab:exp30a.csv}. +%(Note that each table is given a label that is based on the +%database name, to ensure that it is unique.) +% +%\DTLforeach{index}{\theFile=File,\theTemp=Temperature,\theNaCl +%=NaCl,\thepH=pH}{ +%\begin{table}[htbp] +%\caption{Temperature = \theTemp, NaCl = \theNaCl, +%pH = \thepH}\label{tab:\theFile} +%\centering +%\begin{tabular}{rl} +%\bfseries Time & \bfseries Log Count +%\DTLforeach{\theFile}{\theTime=Time,\theLogCount=Log Count}{ +%\\\theTime & \theLogCount}% +%\end{tabular} +%\end{table} +%} +%\end{example} +% +%\subsection{Editing Database Rows} +% +%In the body of the \ics{DTLforeach} loop, you can use the following +%to edit the current row: +%\DescribeMacro{\DTLappendtorow} +%\begin{definition} +%\cs{DTLappendtorow}\marg{key}\marg{value} +%\end{definition} +%This appends a new entry with the given \meta{key} and \meta{value} +%to the current row. +% +%\DescribeMacro{\DTLreplaceentryforrow} +%\begin{definition} +%\cs{DTLreplaceentryforrow}\marg{key}\marg{value} +%\end{definition} +%This replaces the entry for \meta{key} with \meta{value}. +% +%\DescribeMacro{\DTLremoveentryfromrow} +%\begin{definition} +%\cs{DTLremoveentryfromrow}\marg{key} +%\end{definition} +%This the entry for \meta{key} from the current row. +% +%\DescribeMacro{\DTLremovecurrentrow} +%\begin{definition} +%\cs{DTLremovecurrentrow} +%\end{definition} +%This removes the current row from the database. +% +%\DescribeMacro{\DTLforeachkeyinrow} +%\begin{definition} +%\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +%\end{definition} +%This iterates through each key in the current row, assigns +%\meta{cmd} to the value of that key, and does \meta{text}. +%(\meta{cmd} must be a control sequence.) +% +%\begin{example}{Editing Database Rows}{ex:editdb} +%In this example I have a CSV file called "marks.csv" that contains +%student marks for three assignments: +%\DTLnewdb{marks}\relax +%\DTLnewrow{marks}\relax +%\DTLnewdbentry{marks}{FirstName}{John}\relax +%\DTLnewdbentry{marks}{Surname}{Smith, Jr}\relax +%\DTLnewdbentry{marks}{StudentNo}{102689}\relax +%\DTLnewdbentry{marks}{Assignment 1}{68}\relax +%\DTLnewdbentry{marks}{Assignment 2}{57}\relax +%\DTLnewdbentry{marks}{Assignment 3}{72}\relax +%\DTLnewrow{marks}\relax +%\DTLnewdbentry{marks}{FirstName}{Jane}\relax +%\DTLnewdbentry{marks}{Surname}{Brown}\relax +%\DTLnewdbentry{marks}{StudentNo}{102647}\relax +%\DTLnewdbentry{marks}{Assignment 1}{75}\relax +%\DTLnewdbentry{marks}{Assignment 2}{84}\relax +%\DTLnewdbentry{marks}{Assignment 3}{80}\relax +%\DTLnewrow{marks}\relax +%\DTLnewdbentry{marks}{FirstName}{Andy}\relax +%\DTLnewdbentry{marks}{Surname}{Brown}\relax +%\DTLnewdbentry{marks}{StudentNo}{103569}\relax +%\DTLnewdbentry{marks}{Assignment 1}{42}\relax +%\DTLnewdbentry{marks}{Assignment 2}{52}\relax +%\DTLnewdbentry{marks}{Assignment 3}{54}\relax +%\DTLnewrow{marks}\relax +%\DTLnewdbentry{marks}{FirstName}{Z\"oe}\relax +%\DTLnewdbentry{marks}{Surname}{Adams}\relax +%\DTLnewdbentry{marks}{StudentNo}{105987}\relax +%\DTLnewdbentry{marks}{Assignment 1}{52}\relax +%\DTLnewdbentry{marks}{Assignment 2}{48}\relax +%\DTLnewdbentry{marks}{Assignment 3}{57}\relax +%\DTLnewrow{marks}\relax +%\DTLnewdbentry{marks}{FirstName}{Roger}\relax +%\DTLnewdbentry{marks}{Surname}{Brady}\relax +%\DTLnewdbentry{marks}{StudentNo}{106872}\relax +%\DTLnewdbentry{marks}{Assignment 1}{58}\relax +%\DTLnewdbentry{marks}{Assignment 2}{60}\relax +%\DTLnewdbentry{marks}{Assignment 3}{62}\relax +%\DTLnewrow{marks}\relax +%\DTLnewdbentry{marks}{FirstName}{Clare}\relax +%\DTLnewdbentry{marks}{Surname}{Verdon}\relax +%\DTLnewdbentry{marks}{StudentNo}{104356}\relax +%\DTLnewdbentry{marks}{Assignment 1}{45}\relax +%\DTLnewdbentry{marks}{Assignment 2}{50}\relax +%\DTLnewdbentry{marks}{Assignment 3}{48}\relax +%\begin{ttfamily}\setlength{\parindent}{0pt}\par +%Surname,FirstName,StudentNo,Assignment 1,Assignment 2,Assignment 3 +% +%\DTLforeach{marks}{\surname=Surname,\firstname=FirstName,\regNo +%=StudentNo,\assignI=Assignment 1,\assignII +%=Assignment 2,\assignIII=Assignment 3}{\relax +%\surname,\firstname,\regNo,\assignI,\assignII\assignIII\par +%} +%\end{ttfamily}\par\noindent +%First load this into a database called "marks": +%\begin{verbatim} +%\DTLloaddb{marks}{marks.csv} +%\end{verbatim} +%Suppose now I want to compute the average mark for each +%student, and append this to the database. I can do this as +%follows: +%\begin{verbatim} +%\DTLforeach{marks}{% +%\assignI=Assignment 1,% +%\assignII=Assignment 2,% +%\assignIII=Assignment 3}{% +%\DTLmeanforall{\theMean}{\assignI,\assignII,\assignIII}% +%\DTLappendtorow{Average}{\theMean}} +%\end{verbatim} +%\DTLforeach{marks}{\assignI=Assignment 1,\assignII +%=Assignment 2,\assignIII=Assignment 3}{\relax +%\DTLmeanforall{\theMean}{\assignI,\assignII,\assignIII}% +%\DTLappendtorow{Average}{\theMean}}\relax +%For each row in the "marks" database, I now have an extra key +%called "Average" that contains the average mark over all three +%assignments for a given student. I can now put this data into +%a table: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Marks} +%\centering +%\begin{tabular}{llrrrr} +%\bfseries Surname & \bfseries First Name & +%\bfseries Assign 1 & +%\bfseries Assign 2 & +%\bfseries Assign 3 & +%\bfseries Average Mark% +%\DTLforeach{marks}{\surname=Surname,\firstname=FirstName,\average +%=Average,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII +%=Assignment 3}{\\\surname +%& \firstname & \assignI & \assignII & \assignIII & +%\DTLround{\average}{\average}{2}\average}\relax +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:meanmarks}. +% +%Note that if I only wanted the averages for the table and nothing +%else, I could simply have computed the average in each row of the +%table and displayed it without adding the information to the +%database, however I am going to reuse this information in +%\autoref{ex:multibar}, so adding it to the database means that +%I don't need to recompute the mean. +% +%\begin{table}[htbp] +%\caption{Student Marks}\label{tab:meanmarks} +%\centering +%\begin{tabular}{llrrrr} +%\bfseries Surname & \bfseries First Name & +%\bfseries Assign 1 & +%\bfseries Assign 2 & +%\bfseries Assign 3 & +%\bfseries Average Mark\relax +%\DTLforeach{marks}{\surname=Surname,\firstname=FirstName,\average +%=Average,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII +%=Assignment 3}{\\\surname +%& \firstname & \assignI & \assignII & \assignIII & +%\DTLround{\average}{\average}{2}\average}\relax +%\end{tabular} +%\end{table} +% +%\end{example} +% +%\subsection{Arithmetical Computations on Database Entries} +% +%The commands used in \autoref{sec:fp} can be used on database +%entries. You can, of course, directly use the commands provided +%by the \sty{fp} package if you know that the values are in the +%correct format (i.e.\ no currency symbols, no number group +%separators and a full stop as the decimal point) but if this may +%not be the case, then you should use the commands described in +%\autoref{sec:fp}. If you want to use a command provided by the +%\sty{fp} package, that does not have a wrapper function in +%\sty{datatool}, then you will need to convert the value using +%\ics{DTLconverttodecimal}, and convert it back using either +%\ics{DTLdecimaltolocale} or \ics{DTLdecimaltocurrency}. +% +%\begin{example}{Arithmetical Computations}{ex:mean} +%In this example, I am going to produce a table similar to +%\autoref{tab:scores}, except that I want to add an extra row at the +%end which contains the average score. +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores (Including Average)}\label{tab:mean} +%\centering +%\def\total{0}% +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\ +%\firstname & \surname & +%\DTLgadd{\total}{\score}{\total}% +%\score +%}\\ +%\multicolumn{2}{l}{\bfseries Average Score} & +%\DTLsavelastrowcount{\n}% +%\DTLdiv{\average}{\total}{\n}% +%\DTLround{\average}{\average}{2}% +%\average +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:mean}. +%\textbf{Notes:} +%\begin{itemize} +%\item I had to use \ics{DTLgadd} rather than \ics{DTLadd} since it +%occurs within a \env{tabular} environment which puts each entry +%in a local scope. +% +%\item I used \ics{DTLsavelastrowcount} to store the number of +%rows produced by \ics{DTLforeach} in the control sequence \cs{n}. +% +%\item I used \ics{DTLround} to round the average score to 2 decimal +%places. +%\end{itemize} +% +%\begin{table}[htbp] +%\caption{Student Scores (Including Average)}\label{tab:mean} +%\centering +%\def\total{0}\relax +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\ +%\firstname & \surname & +%\DTLgadd{\total}{\score}{\total}\relax +%\score +%}\\ +%\multicolumn{2}{l}{\bfseries Average Score} & +%\DTLsavelastrowcount{\n}\relax +%\DTLdiv{\average}{\total}{\n}\relax +%\DTLround{\average}{\average}{2}\relax +%\average +%\end{tabular} +%\end{table} +%\end{example} +% +%\DescribeMacro{\DTLsumforkeys} +%\begin{definition} +%\cs{DTLsumforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command sums all the entries over all the databases listed in +%the comma separated list of database names \meta{db list} for each key in +%\meta{key list} where the condition given by +%\meta{condition} is true. The result is stored in \meta{cmd} +%which must be a control sequence. For example: +%\begin{verbatim} +%\DTLsumforkeys{scores}{Score}{\total} +%\end{verbatim} +%sets \cs{total} to the sum of all the scores in the database +%called "scores". +% +%\DescribeMacro{\DTLmeanforkeys} +%\begin{definition} +%\cs{DTLmeanforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command computes the arithmetic mean of all the entries over +%all the databases listed in \meta{db list} for all keys in \meta{key list} where +%the condition +%given by \meta{condition} is true. The result is stored in \meta{cmd} +%which must be a control sequence. For example: +%\begin{verbatim} +%\DTLmeanforkeys{scores}{Score}{\average} +%\end{verbatim} +%sets \cs{average} to the mean of all the scores in the database +%called "scores". +% +%\DescribeMacro{\DTLvarianceforkeys} +%\begin{definition} +%\cs{DTLvarianceforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command computes the variance of all the entries over +%all the databases listed in \meta{db list} for all keys in \meta{key list} where +%the condition +%given by \meta{condition} is true. The result is stored in \meta{cmd} +%which must be a control sequence. +% +%\DescribeMacro{\DTLsdforkeys} +%\begin{definition} +%\cs{DTLsdforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command computes the standard deviation of all the entries over +%all the databases listed in \meta{db list} for all keys in \meta{key list} where +%the condition +%given by \meta{condition} is true. The result is stored in \meta{cmd} +%which must be a control sequence. +% +%\DescribeMacro{\DTLminforkeys} +%\begin{definition} +%\cs{DTLminforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command determines the minimum value over all entries +%for all keys in \meta{key list} over all the databases listed in \meta{db list} +%and stores +%in \meta{cmd}, which must be a control sequence. For example +%\begin{verbatim} +%\DTLminforkeys{scores}{Score}{\theMin} +%\end{verbatim} +%sets \cs{theMin} to the minimum score in the database. +% +%\DescribeMacro{\DTLmaxforkeys} +%\begin{definition} +%\cs{DTLmaxforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command determines the maximum value over all entries +%for all keys in \meta{key list} over all the databases listed in \meta{db list} +%and stores +%in \meta{cmd}, which must be a control sequence. For example +%\begin{verbatim} +%\DTLminforkeys{scores}{Score}{\theMax} +%\end{verbatim} +%sets \cs{theMax} to the minimum score in the database. +% +%\DescribeMacro{\DTLcomputebounds} +%\begin{definition} +%\cs{DTLcomputebounds}\marg{condition}\marg{db list}\marg{x key}\marg{y key}\marg{minX cmd}\marg{minY cmd}\marg{maxX cmd}\marg{maxY cmd} +%\end{definition} +%Computes the maximum and minimum $x$ and $y$ values over all +%the databases listed in \meta{db list} where the $x$ value +%is given by \meta{x key} and the $y$ value is given by +%\meta{y key}. The results are stored in \meta{minX cmd}, +%\meta{minY cmd}, \meta{maxX cmd} and \meta{maxY cmd}. +% +%\begin{example}{Mail Merging}{ex:mailmerging} +%This example uses the database given in \autoref{ex:scores} and +%uses \ics{DTLmeanforkey} to determine the average score. A letter +%is then created for each student to inform them of their score +%and the class average. +% +%\begin{verbatim} +%\documentclass{letter} +% +%\usepackage{datatool} +% +%\begin{document} +%% load database +%\DTLloaddb{scores}{studentscores.csv} +%% compute arithmetic mean for key `Score' +%\DTLmeanforkey{scores}{Score}{\average} +%% Round the average to 2 decimal places +%\DTLround{\average}{\average}{2} +%% Save the highest score in \maxscore +%\DTLmaxforkey{scores}{Score}{\maxscore} +% +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,% +%\score=Score}{% +%\begin{letter}{} +%\opening{Dear \firstname\ \surname} +% +%\DTLifnumgt{\score}{60}{Congratulations you}{You} achieved a score +%of \score\% which was \DTLifnumgt{\score}{\average}{above}{below} +%the average of \average\%. \DTLifnumeq{\score}{\maxscore}{You +%achieved the highest score}{The top score was \maxscore}. +% +%\closing{Yours Sincerely} +%\end{letter} +%} +%\end{document} +%\end{verbatim} +%\end{example} +% +%\subsection{Sorting a Database} +%\label{sec:sort} +% +%\DescribeMacro{\DTLsort} +%\begin{definition} +%\cs{DTLsort}\marg{sort criteria}\marg{db name} +%\end{definition} +%This will sort the database called \meta{db name} according to +%the criteria given by \meta{sort criteria}, which must be a +%comma separated list of keys and optionally "="\meta{order}, where +%\meta{order} is either "ascending" or "descending". If the order +%is omitted, "ascending" is assumed. The database keeps track of +%the data type for a given key, and uses this to determine whether +%an alphabetical or numerical sort is required. +% +%\begin{example}{Sorting a Database}{ex:sort} +%This example uses the database called "scores" defined in +%\autoref{ex:scores}. First, I am going to sort the database +%according to the student scores in descending order (highest to +%lowest) and display the database in a table +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores (Sorted by Score)}\label{tab:sortscores} +%\centering +%\DTLsort{Score=descending}{scores}% +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)% +%\DTLforeach{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\ +%\firstname & \surname & \score} +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:sortscores}. +% +%\begin{table}[htbp] +%\caption{Student Scores (Sorted by Score)}\label{tab:sortscores} +%\centering +%\DTLsort{Score=descending}{scores}\relax +%\begin{tabular}{llr} +%\bfseries First Name & +%\bfseries Surname & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\ +%\firstname & \surname & \score} +%\end{tabular} +%\end{table} +% +%Now I am going to sort the database according to +%surname and then first name, and display it in a table. Note that +%since I want to sort in ascending order, I can omit the +%"=ascending" part of the sort criteria. I have also decided to +%reverse the first and second columns, so that the surname is +%in the first column. +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores (Sorted by Name)}\label{tab:sortname} +%\centering +%\DTLsort{Surname,FirstName}{scores}% +%\begin{tabular}{llr} +%\bfseries Surname & +%\bfseries First Name & +%\bfseries Score (\%)% +%\DTLforeach{scores}{% +%\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\ +%\surname & \firstname & \score} +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:sortname}. +%\begin{table}[htbp] +%\caption{Student Scores (Sorted by Name)}\label{tab:sortname} +%\centering +%\DTLsort{Surname,FirstName}{scores}\relax +%\begin{tabular}{llr} +%\bfseries Surname & +%\bfseries First Name & +%\bfseries Score (\%)\relax +%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\\ +%\surname & \firstname & \score} +%\end{tabular} +%\end{table} +% +%\end{example} +% +%\subsection{Saving a Database to an External File} +%\label{sec:savedb} +% +%\DescribeMacro{\DTLsavedb} +%\begin{definition} +%\cs{DTLsavedb}\marg{db name}\marg{filename} +%\end{definition} +%This writes the database called \meta{db name} to a file called +%\meta{filename}. The separator and delimiter characters used +%are as given by \ics{DTLsetseparator} (or \ics{DTLsettabseparator}) +%and \ics{DTLsetdelimiter}. For example: +%\begin{verbatim} +%\DTLsettabdelimiter +%\DTLsavedb{scores}{scores.txt} +%\end{verbatim} +% +%\DescribeMacro{\DTLsavetexdb} +%\begin{definition} +%\cs{DTLsavetexdb}\marg{db name}\marg{filename} +%\end{definition} +%This writes the database called \meta{db name} to a \LaTeX\ file +%called \meta{filename}, where the database is stored as +%a combination of \ics{DTLnewdb}, \ics{DTLnewrow} and \ics{DTLnewdbentry} commands. +% +%\section{Pie Charts (\texorpdfstring{\sty{datapie}}{datapie} package)} +% +%The \sty{datapie} package is not loaded by the \sty{datatool} package, +%so you need to load \sty{datapie} if you want to use any of the +%commands defined in this section. You will need to have the +%\sty{pgf}/\sty{tikz} packages installed. The \sty{datapie} package +%may be given the following options: +%\begin{description} +%\item[{\pkgopt[datapie]{color}}] Colour option (default.) +%\item[{\pkgopt[datapie]{monochrome}}] Monochrome option. +%\item[{\pkgopt[datapie]{rotateinner}}] +%Rotate inner labels so that they are aligned +%with the pie chart radial axis. +%\item[{\pkgopt[datapie]{norotateinner}}] +%Don't rotate inner labels (default.) +%\item[{\pkgopt[datapie]{rotateouter}}] +%Rotate outer labels so that they are aligned +%with the pie chart radial axis. +%\item[{\pkgopt[datapie]{norotateouter}}] +%Don't rotate outer labels (default.) +%\end{description} +% +%Numerical information contained in a database created by the +%\sty{datatool} package can be converted into a pie chart using +%\DescribeMacro{\DTLpiechart} +%\begin{definition} +%\cs{DTLpiechart}\oarg{condition}\marg{settings list}\marg{db name}\marg{values} +%\end{definition}\noindent +%where \meta{db name} is the name of the database, and +%\meta{condition} has the same form as the optional argument +%to \ics{DTLforeach} described in \autoref{sec:dbforeach}. If +%\meta{condition} is false, that information is omitted from the +%construction of the pie chart. The argument \meta{values} is a +%comma separated list of \meta{cmd}"="\meta{key} pairs, the same +%as that required by the penultimate argument of \ics{DTLforeach}. +%The \meta{settings list} is a comma separated list of +%\meta{setting}=\meta{value} pairs, where \meta{setting} can be any of +%the following: +%\begin{description} +%\item[\setting{DTLpiechart}{variable}] +%This specifies the control sequence to use that +%contains the value used to construct the pie chart. The control +%sequence must be one of the control sequences to appear in +%the assignment list \meta{values}. This setting is required. +% +%\item[\setting{DTLpiechart}{start}] +%This is the starting angle of the first segment. The +%value is 0 by default. +% +%\item[\setting{DTLpiechart}{radius}] +%This is the radius of the pie chart. The default value +%is 2cm. +% +%\item[\setting{DTLpiechart}{innerratio}] +%The distance from the centre of the +%pie chart to the point where the inner labels are placed is given +%by this value multiplied by the ratio. The default value is 0.5. +% +%\item[\setting{DTLpiechart}{outerratio}] +%The distance from the centre of the +%pie chart to the point where the outer labels are placed is given +%by this value multiplied by the ratio. The default value is 1.25. +% +%\item[\setting{DTLpiechart}{cutawayratio}] +%The distance from the centre of the pie chart +%to the point of cutaway segments is given by this value multiplied +%by the ratio. The default value is 0.2. +% +%\item[\setting{DTLpiechart}{inneroffset}] +%This is the absolute distance from the centre +%of the pie chart to the point where the inner labels are placed. +%You should use only one or other of \setting{DTLpiechart}{innerratio} +%and \setting{DTLpiechart}{inneroffset}, not both. If you also want to +%specify the radius, you must use \setting{DTLpiechart}{ratio} +%before \setting{DTLpiechart}{inneroffset}. If omitted, the inner +%offset is obtained from the ratio multiplied by the +%\setting{DTLpiechart}{innerratio} value. +% +%\item[\setting{DTLpiechart}{outeroffset}] +%This is the absolute distance from the centre +%of the pie chart to the point where the outer labels are placed. +%You should use only one or other of \setting{DTLpiechart}{outerratio} +%and \setting{DTLpiechart}{outeroffset}, not both. If you also want to +%specify the radius, you must use \setting{DTLpiechart}{ratio} +%before \setting{DTLpiechart}{outeroffset}. If omitted, the outer +%offset is obtained from the ratio multiplied by the +%\setting{DTLpiechart}{outerratio} value. +% +%\item[\setting{DTLpiechart}{cutawayoffset}] +%This is the absolute distance from the centre of +%the pie chart to the point of the cutaway segments. You should use +%only one or other of \setting{DTLpiechart}{cutawayratio} and +%\setting{DTLpiechart}{cutawayoffset}, not both. If +%you also want to specify the radius, you must use +%\setting{DTLpiechart}{ratio} before +%\setting{DTLpiechart}{cutawayoffset}. If omitted, the cutaway offset +%is obtained from the ratio multiplied by the +%\setting{DTLpiechart}{cutawayratio} value. +% +%\item[\setting{DTLpiechart}{cutaway}] +%This is a list of cutaway segments. This should be +%a comma separated list of individual numbers, or number ranges +%(separated by a dash.) For example "cutaway={1,3}" will separate +%the first and third segments from the rest of the pie chart, offset +%by the value of the \setting{DTLpiechart}{cutawayoffset} setting, +%whereas "cutaway={1-3}" will separate the +%first three segments from the rest of the pie chart. If omitted, +%the pie chart will be whole. +% +%\item[\setting{DTLpiechart}{innerlabel}] +%The value of this is positioned in the middle of each segment at a +%distance of \setting{DTLpiechart}{inneroffset} from the centre +%of the pie chart. The default is the same as the value of +%\setting{DTLpiechart}{variable}. +% +%\item[\setting{DTLpiechart}{outerlabel}] +%The value of this is positioned at a distance of +%\setting{DTLpiechart}{outeroffset} from the centre of the pie chart. +%The default is empty. +% +%\item[\setting{DTLpiechart}{rotateinner}] This is a boolean setting, +%so it can only take the values "true" and "false". If the value is +%omitted "true" is assumed. If true, the inner labels are rotated +%along the spokes of the pie chart, otherwise the inner labels are not +%rotated. There are analogous package options +%\pkgopt[datapie]{rotateinner} and \pkgopt[datapie]{norotateinner}. +% +%\item[\setting{DTLpiechart}{rotateouter}] +%This is a boolean setting, so it can only take +%the values "true" and "false". If the value is omitted "true" is +%assumed. If true, the outer labels are rotated along the spokes of +%the pie chart, otherwise the outer labels are not rotated. +%There are analogous package options +%\pkgopt[datapie]{rotateouter} and \pkgopt[datapie]{norotateouter}. +% +%\end{description} +% +%\begin{example}{A Pie Chart}{ex:piechart} +%This example loads data from a file called "fruit.csv" which contains +%the following: +%\begin{verbatim} +%Name,Quantity +%"Apples",30 +%"Pears",25 +%"Lemons,Limes",40.5 +%"Peaches",34.5 +%"Cherries",20 +%\end{verbatim} +%First load the data: +%\begin{verbatim} +%\DTLloaddb{fruit}{fruit.csv} +%\end{verbatim} +%\DTLnewdb{fruit}\relax +%\DTLnewrow{fruit}\relax +%\DTLnewdbentry{fruit}{Name}{Apples}\relax +%\DTLnewdbentry{fruit}{Quantity}{30}\relax +%\DTLnewrow{fruit}\relax +%\DTLnewdbentry{fruit}{Name}{Pears}\relax +%\DTLnewdbentry{fruit}{Quantity}{25}\relax +%\DTLnewrow{fruit}\relax +%\DTLnewdbentry{fruit}{Name}{Lemons,Limes}\relax +%\DTLnewdbentry{fruit}{Quantity}{40.5}\relax +%\DTLnewrow{fruit}\relax +%\DTLnewdbentry{fruit}{Name}{Peaches}\relax +%\DTLnewdbentry{fruit}{Quantity}{34.5}\relax +%\DTLnewrow{fruit}\relax +%\DTLnewdbentry{fruit}{Name}{Cherries}\relax +%\DTLnewdbentry{fruit}{Quantity}{20}\relax +%Now create a pie chart in a figure: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity}{fruit}{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart} +%\end{figure} +%\end{verbatim} +%This creates \autoref{fig:piechart}. +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity}{fruit}{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart} +%\label{fig:piechart} +%\end{figure} +% +%There are no outer labels by default, but they can be set +%using the \setting{DTLpiechart}{outerlabel} setting. +%The following sets the outer label to the value of the "Name" key: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Outer labels set)} +%\end{figure} +%\end{verbatim} +%This creates \autoref{fig:piechartouter}. +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name}{fruit} +%{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Outer labels set)} +%\label{fig:piechartouter} +%\end{figure} +% +%You may prefer the labels to be rotated. The following +%switches on the rotation for the inner and outer labels: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name,% +%rotateinner,rotateouter}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Rotation enabled)} +%\end{figure} +%\end{verbatim} +%This creates \autoref{fig:piechartrot}. +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name +%,rotateinner,rotateouter}{fruit} +%{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Rotation enabled)} +%\label{fig:piechartrot} +%\end{figure} +%\end{example} +% +%\begin{example}{Separating Segments from the Pie Chart}{ex:cutaway} +%You may want to separate one or more segments from the pie chart, +%perhaps to emphasize them. You can do this using the +%\setting{DTLpiechart}{cutaway} +%setting. The following separates the first and third segments +%from the pie chart: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name,% +%cutaway={1,3}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart with Cutaway Segments} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:piecutaway}. +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name +%,cutaway={1,3}}{fruit}{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart with Cutaway Segments} +%\label{fig:piecutaway} +%\end{figure} +% +%Alternatively I can specify a range of segments. The following +%separates the first two segments: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name,% +%cutaway={1-2}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart with Cutaway Segments (\texttt{cutaway=\{1-2\}})} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:piecutaway2}. +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name +%,cutaway={1-2}}{fruit}{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart with Cutaway Segments (\texttt{cutaway=\{1-2\}})} +%\label{fig:piecutaway2} +%\end{figure} +% +%Notice the difference between \autoref{fig:piecutaway2} and +%\autoref{fig:piecutaway3} which was produced using: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name,% +%cutaway={1,2}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart with Cutaway Segments (\texttt{cutaway=\{1,2\}})} +%\end{figure} +%\end{verbatim} +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,outerlabel=\name +%,cutaway={1,2}}{fruit}{\name=Name,\quantity=Quantity} +%\caption{A Pie Chart with Cutaway Segments (\texttt{cutaway=\{1,2\}})} +%\label{fig:piecutaway3} +%\end{figure} +% +%\end{example} +% +%\subsection{Pie Chart Variables} +% +%\DescribeMacro{\DTLpievariable} +%\begin{definition} +%\cs{DTLpievariable} +%\end{definition} +%This command is set to the variable given by the +%\setting{DTLpiechart}{variable} setting in the \meta{settings list} +%argument of \cs{DTLpiechart}. The \setting{DTLpiechart}{innerlabel} +%is set to \cs{DTLpievariable} by default. +% +%\DescribeMacro{\DTLpiepercent} +%\begin{definition} +%\cs{DTLpiepercent} +%\end{definition} +%This command is set to the percentage value of \cs{DTLpievariable}. +%The percentage value is rounded to \meta{n} digits, where \meta{n} +%is the value of the \LaTeX\ counter +%\counterfmt{DTLpieroundvar}. +% +%\begin{example}{Changing the Inner and Outer Labels}{ex:pielabels} +%This example uses the database defined in \autoref{ex:piechart}. +%The inner label is now set to the percentage value, rather than +%the actual value, and the outer label is set to the name with +%the actual value in parentheses. +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,% +%innerlabel={\DTLpiepercent\%},% +%outerlabel={\name\ (\DTLpievariable)}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Changing the labels)} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:piechartlabels}. +% +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent +%\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Changing the labels)} +%\label{fig:piechartlabels} +%\end{figure} +%\end{example} +% +%\subsection{Pie Chart Label Formatting} +% +%\DescribeMacro{\DTLdisplayinnerlabel} +%\begin{definition} +%\cs{DTLdisplayinnerlabel}\marg{text} +%\end{definition} +%This governs how the inner label is formatted, where \meta{text} +%is the text of the inner label. The default is to just do \meta{text}. +% +%\DescribeMacro{\DTLdisplayouterlabel} +%\begin{definition} +%\cs{DTLdisplayouterlabel}\marg{text} +%\end{definition} +%This governs how the outer label is formatted, where \meta{text} +%is the text of the outer label. The default is to just do \meta{text}. +% +%\begin{example}{Changing the Inner and Outer Label +%Format}{ex:pielabelformat} +%This example extends \autoref{ex:pielabels}. +%The inner and outer labels are now both typeset in a sans-serif +%font: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} +%\renewcommand*{\DTLdisplayouterlabel}[1]{\textsf{#1}} +%\DTLpiechart{variable=\quantity,% +%innerlabel={\DTLpiepercent\%},% +%outerlabel={\name\ (\DTLpievariable)}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Changing the label format)} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:piechartlabelformat}. +% +%\begin{figure}[htbp] +%\centering +%\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} +%\renewcommand*{\DTLdisplayouterlabel}[1]{\textsf{#1}} +%\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent +%\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{A Pie Chart (Changing the label format)} +%\label{fig:piechartlabelformat} +%\end{figure} +%\end{example} +% +%\subsection{Pie Chart Colours} +% +%The \sty{datapie} package predefines colours for the first +%eight segments of the pie chart. If you require more than +%eight segments, you will need to use +%\DescribeMacro{\DTLsetpiesegmentcolor} +%\begin{definition} +%\cs{DTLsetpiesegmentcolor}\marg{n}\marg{color} +%\end{definition}\noindent +%to set the colours for any additional segments, or you can use +%it to change the default colours. The first argument \meta{n} +%is the segment index (starting from 1), and the second argument +%\meta{color} is a colour specifier as used in commands such as +%\cs{color}. +% +%\DescribeMacro{\DTLdopiesegmentcolor} +%\begin{definition} +%\cs{DTLdopiesegmentcolor}\meta{n} +%\end{definition} +%This sets the current text colour to that of the \meta{n}th +%segment. +% +%\DescribeMacro{\DTLdocurrentpiesegmentcolor} +%\begin{definition} +%\cs{DTLdocurrentpiesegmentcolor} +%\end{definition} +%This sets the current text colour to that of the current pie +%segment. This command may only be used within a pie chart, or +%within the body of \ics{DTLforeach}. +% +%\DescribeMacro{\DTLpieoutlinecolor} +%\begin{definition} +%\cs{DTLpieoutlinecolor} +%\end{definition} +%This sets the outline colour for the pie chart. The default is +%black. +% +%\DescribeMacro{\DTLpieoutlinewidth} +%\begin{definition} +%\cs{DTLpieoutlinewidth} +%\end{definition} +%This is a length that governs the line width of the outline. The +%default value is 0pt, but can be changed using \cs{setlength}. +%The outline is only drawn if \cs{DTLpieoutlinewidth} is greater +%than 0pt. +% +%\begin{example}{Pie Segment Colours}{ex:piecolours} +%This example extends \autoref{ex:pielabelformat}. +%It sets the outline thickness to 2pt, and +%the outer label is now set in the same colour as the fill colour +%of the segment to which it belongs. +%In addition, a legend is created using +%\ics{DTLforeach}. +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\setlength{\DTLpieoutlinewidth}{2pt} +%\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} +%\renewcommand*{\DTLdisplayouterlabel}[1]{% +%\DTLdocurrentpiesegmentcolor +%\textsf{\shortstack{#1}}} +%\DTLpiechart{variable=\quantity,% +%innerlabel={\DTLpiepercent\%},% +%outerlabel={\name\\(\DTLpievariable)}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\begin{tabular}[b]{ll} +%\DTLforeach{fruit}{\name=Name}{\DTLiffirstrow{}{\\}% +%\DTLdocurrentpiesegmentcolor\rule{10pt}{10pt} & +%\name +%} +%\end{tabular} +%\caption{A Pie Chart (Using Segment Colours and Outline)} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:piesegcolour}. (The format of the +%outer label has been changed to use \cs{shortstack} to +%prevent the outer labels from taking up so much horizontal +%space. The \setting{DTLpiechart}{outerlabel} setting has also been +%modified to use "\\" after the name to move the percentage value onto +%the next row.) +% +%\begin{figure}[htbp] +%\centering +%\setlength{\DTLpieoutlinewidth}{2pt} +%\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} +%\renewcommand*{\DTLdisplayouterlabel}[1]{\relax +%\DTLdocurrentpiesegmentcolor +%\textsf{\shortstack{#1}}} +%\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent +%\%},outerlabel={\name\\(\DTLpievariable)}}{fruit}{% +%\name=Name,\quantity=Quantity} +%\begin{tabular}[b]{ll} +%\DTLforeach{fruit}{\name=Name}{\DTLiffirstrow{}{\\}\relax +%\DTLdocurrentpiesegmentcolor\rule{10pt}{10pt} & +%\name +%} +%\end{tabular} +%\caption{A Pie Chart (Using Segment Colours and Outline)} +%\label{fig:piesegcolour} +%\end{figure} +%\end{example} +% +%\subsection{Adding Extra Commands Before and After the Pie Chart} +% +%The pie charts created using \ics{DTLpiechart} are placed inside +%a \env{tikzpicture} environment (defined by the \sty{tikz} package.) +% +%\DescribeMacro{\DTLpieatbegintikz} +%\begin{definition} +%\cs{DTLpieatbegintikz} +%\end{definition} +%The macro \cs{DTLpieatbegintikz} is called at the start of the +%\env{tikzpicture} environment, allowing you to change the +%\env{tikzpicture} settings. By default \cs{DTLpieatbegintikz} +%does nothing, but you can redefine it to, say, scale the pie +%chart. +% +%\DescribeMacro{\DTLpieatendtikz} +%\begin{definition} +%\cs{DTLpieatendtikz} +%\end{definition} +%The macro \cs{DTLpieatendtikz} is called at the end of the +%\env{tikzpicture} environment, allowing you add additional +%graphics to the pie chart. This does nothing by default. +% +%\begin{example}{Adding Information to the Pie Chart}{ex:piescale} +%This example modifies \autoref{ex:piechart}. It redefines +%\cs{DTLpieatendtikz} to add an annotated arrow. +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLpiechart{variable=\quantity}{fruit}{% +%\name=Name,\quantity=Quantity} +%\caption{An Annotated Pie Chart} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:pieannote}. (Note that the centre +%of the pie chart is the origin of the TikZ picture.) +% +%\begin{figure}[htbp] +%\centering +%\renewcommand*{\DTLpieatendtikz}{% +%\draw[<-] (45:1.5cm) -- (40:2.5cm)node[right]{Apples};} +%\DTLpiechart{variable=\quantity}{fruit}{\name=Name,\quantity=Quantity} +%\caption{An Annotated Pie Chart} +%\label{fig:pieannote} +%\end{figure} +%\end{example} +% +%\section{Scatter and Line Plots (\texorpdfstring{\sty{dataplot}}{dataplot} +%package)} +% +%The \sty{dataplot} package provides commands for creating +%scatter or line plots from databases. It uses the pgf/TikZ plot +%handler library to create the plots. See the \sty{pgf} manual for +%more detail on pgf streams and plot handles. The \sty{dataplot} +%package is not loaded by \sty{datatool} so if you want to use +%it you need to load it explicitly using "\usepackage{dataplot}". +% +%\DescribeMacro{\DTLplot} +%\begin{definition} +%\cs{DTLplot}\oarg{condition}\marg{db list}\marg{settings} +%\end{definition} +%This command creates a plot (inside a \env{tikzpicture} environment) +%of all the data given in the databases listed in \meta{db list}, +%which should be a comma separated list of database names. +%The optional argument \meta{condition} is the same as that for +%\ics{DTLforeach}. The \meta{settings} argument is a comma separated +%list of \meta{setting}"="\meta{value} pairs. There are two settings +%that must be specified \setting{DTLplot}{x} and \setting{DTLplot}{y}. +%The other settings are optional. Note that any value that contains +%a comma, must be enclosed in braces. For example +%"colors={red,cyan,blue}". Note where any setting requires +%a number, or list of numbers (such as \setting{DTLplot}{bounds}) +%the number must be supplied in standard decimal notation (i.e.\ +%no currency, no number groups, and a full stop as the decimal +%point.) Available settings are as follows: +%\begin{description} +%\item[\setting{DTLplot}{x}] The database key +%that specifies the $x$ co-ordinates. This setting is required. +% +%\item[\setting{DTLplot}{y}] The database key that specifies +%the $y$ co-ordinates. This setting is required. +% +%\item[\setting{DTLplot}{markcolors}] A comma separated list of colour +%names for the markers. An empty value will use the current colour. +% +%\item[\setting{DTLplot}{linecolors}] A comma separated list of colour +%names for the plot lines. An empty value will use the current colour. +% +%\item[\setting{DTLplot}{colors}] A comma separated list of colour +%names for the lines and markers. +% +%\item[\setting{DTLplot}{marks}] A comma separated list of +%code to generate plot marks. (This should typically be a list +%of \cs{pgfuseplotmark} commands, see the \sty{pgf} manual for +%further details.) You may use \cs{relax} as an element +%of the list to suppress markers for the corresponding plot. +%For example: "marks={\pgfuseplotmark{o},\relax}" will use an +%open circle marker for the first database, and no markers for the +%second database listed in \meta{db list}. +% +%\item[\setting{DTLplot}{lines}] A comma separated list of +%line style settings. (This should typically be a list of +%\cs{pgfsetdash} commands, see the \sty{pgf} manual for +%further details on how to set the line style.) An empty value +%will use the current line style. +%You may use \cs{relax} as an element +%of the list to suppress line for the corresponding plot. +%For example: "lines={\relax,\pgfsetdash{}{0pt}}" +%will have no lines for the first database, and a solid line +%for the second database listed in \meta{db list}. +% +%\item[\setting{DTLplot}{width}] The width of the plot. This must +%be a length. The plot width does not include outer tick marks or +%labels. +% +%\item[\setting{DTLplot}{height}] The height of the plot. This must +%be a length. The plot height does not include outer tick marks +%or labels. +% +%\item[\setting{DTLplot}{style}] This setting governs whether +%to use lines or markers in the plot, and may take one of +%the following values: "both" (lines and markers), +%"lines" (only lines) or "markers" (only markers.) The default is +%"markers". +% +%\item[\setting{DTLplot}{axes}] This setting governs whether +%to display the axes, and may take one of +%the following values: "both", "x", "y" or "none". If no value +%is specified, "both" is assumed. +% +%\item[\setting{DTLplot}{box}] This setting governs whether +%or not to surround the plot in a box. It is a boolean setting, +%taking only the values "true" and "false". If no value is +%specified, "true" is assumed. +% +%\item[\setting{DTLplot}{xtics}] This setting governs whether +%or not to display the $x$ tick marks. It is a boolean setting, +%taking only the values "true" and "false". If no value is +%specified "true" is assumed. If the \setting{DTLplot}{axes} +%setting is set to "both" or "x", this value will automatically +%be set to "true", otherwise it will be set to "false". +% +%\item[\setting{DTLplot}{ytics}] This setting governs whether +%or not to display the $y$ ticks. It is a boolean setting, +%taking only the values "true" and "false". If no value is +%specified "true" is assumed. If the \setting{DTLplot}{axes} +%setting is set to "both" or "y", this value will automatically +%be set to "true", otherwise it will be set to "false". +% +% +%\item[\setting{DTLplot}{xminortics}] This setting governs whether +%or not to display the $x$ minor tick marks. It is a boolean +%setting, taking only the values "true" and "false". If no value is +%specified "true" is assumed. This setting also sets the +%$x$ major tick marks on if the value is "true". +% +%\item[\setting{DTLplot}{yminortics}] This setting governs whether +%or not to display the $y$ minor tick marks. It is a boolean +%setting, taking only the values "true" and "false". If no value is +%specified "true" is assumed. This setting also sets the +%$y$ major tick marks on if the value is "true". +% +%\item[\setting{DTLplot}{xticdir}] This sets the $x$ tick direction, +%and may only take the values "in" or "out". +% +%\item[\setting{DTLplot}{yticdir}] This sets the $y$ tick direction, +%and may only take the values "in" or "out". +% +%\item[\setting{DTLplot}{ticdir}] This sets the $x$ and $y$ tick +%direction, and may only take the values "in" or "out". +% +%\item[\setting{DTLplot}{bounds}] The value must be in the form +%\meta{min x}","\meta{min y}","\meta{max x}","\meta{max y}. This +%sets the graph bounds to the given values. If omitted the +%bounds are computed from the maximum and minimum values of the +%data. For example +%\begin{verbatim} +%\DTLplot{data1,data2}{x=Height,y=Weight,bounds={0,0,10,20}} +%\end{verbatim} +%Note that the \setting{DTLplot}{bounds} setting overrides +%the \setting{DTLplot}{minx}, \setting{DTLplot}{maxx}, +%\setting{DTLplot}{miny} and \setting{DTLplot}{maxy} settings. +% +%\item[\setting{DTLplot}{minx}] The value is the minimum value +%of the $x$ axis. +% +%\item[\setting{DTLplot}{miny}] The value is the minimum value +%of the $y$ axis. +% +%\item[\setting{DTLplot}{maxx}] The value is the maximum value +%of the $x$ axis. +% +%\item[\setting{DTLplot}{maxy}] The value is the maximum value +%of the $y$ axis. +% +%\item[\setting{DTLplot}{xticpoints}] The value must be a comma +%separated list of decimal numbers indicating where to put the +%$x$ tick marks. If omitted, the $x$ tick marks are placed at +%equal intervals along the $x$ axis such that each interval is +%not less than the length given by \ics{DTLmintickgap}. +%This setting overrides \setting{DTLplot}{xticgap}. +% +%\item[\setting{DTLplot}{xticgap}] This value specifies the +%gap between the $x$ tick marks. +% +%\item[\setting{DTLplot}{yticpoints}] The value must be a comma +%separated list of decimal numbers indicating where to put the +%$y$ tick marks. If omitted, the $y$ tick marks are placed at +%equal intervals along the $y$ axis such that each interval is +%not less than the length given by \ics{DTLmintickgap}. +%This setting overrides \setting{DTLplot}{yticgap}. +% +%\item[\setting{DTLplot}{yticgap}] This value specifies the +%gap between the $y$ tick marks. +% +%\item[\setting{DTLplot}{grid}] This is a boolean value that +%specifies whether or not to display the grid. If no value +%is given, "true" is assumed. The minor grid lines are only +%displayed if the minor tick marks are set. +% +%\item[\setting{DTLplot}{xticlabels}] The value must be a comma +%separated list of labels for each $x$ tick mark. If omitted, +%the labels are the value of the $x$ tick position, rounded +%\meta{n} digits after the decimal point, where \meta{n} is +%given by the value of the counter \counterfmt{DTLplotroundXvar}. +% +%\item[\setting{DTLplot}{yticlabels}] The value must be a comma +%separated list of labels for each $y$ tick mark. If omitted, +%the labels are the value of the $y$ tick position, rounded +%\meta{n} digits after the decimal point, where \meta{n} is +%given by the value of the counter \counterfmt{DTLplotroundYvar}. +% +%\item[\setting{DTLplot}{xlabel}] The value is the label for +%the $x$ axis. If omitted, the axis has no label. +% +%\item[\setting{DTLplot}{ylabel}] The value is the label for +%the $y$ axis. If omitted, the axis has no label. +% +%\item[\setting{DTLplot}{legend}] This setting governs whether +%or not to display the legend, and where it should be displayed. +%It may take one of the following values "none" (don't display +%the legend), "north", "northeast", "east", "southeast", "south", +%"southwest", "west" or "northwest". If the value is omitted, +%"northeast" is assumed. +% +%\item[\setting{DTLplot}{legendlabels}] The value must be a comma +%separated list of labels for the legend. If omitted, the database +%names are used. +% +%\end{description} +% +%\begin{example}{A Basic Graph}{ex:basicplot} +%Suppose you have a file called "groupa.csv" that contains the +%following: +%\DTLnewdb{groupa}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.55}\relax +%\DTLnewdbentry{groupa}{Weight}{45.4}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.54}\relax +%\DTLnewdbentry{groupa}{Weight}{48.0}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.56}\relax +%\DTLnewdbentry{groupa}{Weight}{58.0}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.56}\relax +%\DTLnewdbentry{groupa}{Weight}{50.2}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.57}\relax +%\DTLnewdbentry{groupa}{Weight}{46.0}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.58}\relax +%\DTLnewdbentry{groupa}{Weight}{48.3}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.59}\relax +%\DTLnewdbentry{groupa}{Weight}{56.5}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.59}\relax +%\DTLnewdbentry{groupa}{Weight}{58.1}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.60}\relax +%\DTLnewdbentry{groupa}{Weight}{60.9}\relax +%\DTLnewrow{groupa}\relax +%\DTLnewdbentry{groupa}{Height}{1.62}\relax +%\DTLnewdbentry{groupa}{Weight}{56.3}\relax +%\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} +%Height,Weight +%\DTLforeach{groupa}{\x=Height,\y=Weight}{\x,\y +%}\end{ttfamily}\par\noindent +%First load this into a database called "groupa": +%\begin{verbatim} +%\DTLloaddb{groupa}{groupa.csv} +%\end{verbatim} +%The data can now be converted into a scatter plot as follows: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa}{x=Height,y=Weight} +%\caption{A Scatter Plot} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:basicplot}. +% +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa}{x=Height,y=Weight} +%\caption{A Scatter Plot} +%\label{fig:basicplot} +%\end{figure} +% +%Alternatively, you can use the \setting{DTLplot}{style} setting +%to change it into a line plot: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa}{x=Height,y=Weight,style=lines} +%\caption{A Line Plot} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:basiclineplot}. +% +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa}{x=Height,y=Weight,style=lines} +%\caption{A Line Plot} +%\label{fig:basiclineplot} +%\end{figure} +%\end{example} +% +%\begin{example}{Plotting Multiple Data Sets}{ex:2db} +%In this example, I shall use the database called "groupa" defined +%in \autoref{ex:basicplot}, and another database called "groupb" +%which is loaded from the file "groupb.csv" which contains the +%following: +%\DTLnewdb{groupb} +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.54}\relax +%\DTLnewdbentry{groupb}{Weight}{48.4}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.54}\relax +%\DTLnewdbentry{groupb}{Weight}{42.0}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.55}\relax +%\DTLnewdbentry{groupb}{Weight}{64.0}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.56}\relax +%\DTLnewdbentry{groupb}{Weight}{58.2}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.56}\relax +%\DTLnewdbentry{groupb}{Weight}{49.0}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.57}\relax +%\DTLnewdbentry{groupb}{Weight}{40.3}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.58}\relax +%\DTLnewdbentry{groupb}{Weight}{51.5}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.58}\relax +%\DTLnewdbentry{groupb}{Weight}{63.1}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.59}\relax +%\DTLnewdbentry{groupb}{Weight}{74.9}\relax +%\DTLnewrow{groupb}\relax +%\DTLnewdbentry{groupb}{Height}{1.59}\relax +%\DTLnewdbentry{groupb}{Weight}{59.3}\relax +%\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} +%Height,Weight +%\DTLforeach{groupb}{\x=Height,\y=Weight}{\x,\y +%}\end{ttfamily}\par\noindent +%First load this into a database called "groupb": +%\begin{verbatim} +%\DTLloaddb{groupb}{groupb.csv} +%\end{verbatim} +%I can now plot both groups in the same graph, but I want a smaller +%graph than \autoref{fig:basicplot} and \autoref{fig:basiclineplot}, +%so I am going to set the plot width and height to 3in: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa,groupb}{x=Height,y=Weight,width=3in,height=3in} +%\caption{A Scatter Plot} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:2db}. +% +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa,groupb}{x=Height,y=Weight,width=3in,height=3in} +%\caption{A Scatter Plot} +%\end{figure} +%\label{fig:2db} +% +%Now let's add a legend using the \setting{DTLplot}{legend} setting, +%with the legend labels "Group A" and "Group B", +%and set the $x$ tick intervals using \setting{DTLplot}{xticpoints} +%setting. I am also going to set the $x$ axis label to +%"Height (m)" and the $y$ axis label to "Weight (kg)", and place +%a box around the plot. +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa,groupb}{x=Height,y=Weight, +%width=3in,height=3in,legend,legendlabels={Group A,Group B}, +%xlabel={Height (m)},ylabel={Weight (kg)},box, +%xticpoints={1.54,1.55,1.56,1.57,1.58,1.59,1.60,1.61,1.62}} +%\caption{A Scatter Plot} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:legend}. +% +%\begin{figure}[htbp] +%\centering +%\DTLplot{groupa,groupb}{x=Height,y=Weight,legend, +%width=3in,height=3in,legendlabels={Group A,Group B}, +%xlabel={Height (m)},ylabel={Weight (kg)},box, +%xticpoints={1.54,1.55,1.56,1.57,1.58,1.59,1.60,1.61,1.62}} +%\caption{A Scatter Plot} +%\label{fig:legend} +%\end{figure} +%\end{example} +% +%\subsection{Adding Information to the Plot} +% +%The \sty{datatool} package provides two hooks used at the beginning +%and end of the \env{tikzpicture} environment: +%\DescribeMacro{\DTLplotatbegintikz} +%\begin{definition} +%\cs{DTLplotatbegintikz} +%\end{definition}\noindent +%and +%\DescribeMacro{\DTLplotatendtikz} +%\begin{definition} +%\cs{DTLplotatendtikz} +%\end{definition} +%They are both defined to do nothing by default, but can be redefined +%to add commands to the image. The unit vectors are set prior to +%using these hooks, so you can use the same co-ordinates as those +%in the data sets. +% +%\DescribeMacro{\DTLaddtoplotlegend} +%\begin{definition} +%\cs{DTLaddtoplotlegend}\marg{marker}\marg{line style}\marg{text} +%\end{definition} +%This adds a new row to the plot legend where \meta{marker} is +%code to produce the marker, \meta{line style} is code to set +%the line style and \meta{text} is a textual label. You can +%use \cs{relax} to suppress the marker or line. For example: +%\begin{verbatim} +%\DTLaddtoplotlegend{\pgfuseplotmark{x}}{\relax}{Some Data} +%\end{verbatim} +%Note that the legend is plotted before \cs{DTLplotatendtikz}, +%so if you want to add information to the legend you will need +%to do the in \cs{DTLplotatstarttikz}. +% +%\begin{example}{Adding Information to a Plot}{ex:addtoplot} +%Returning to the plots created in \autoref{ex:2db}, suppose +%I now want to annotate the plot, say I want to draw your notice +%to a particular point, say the point (1.58,48.3), then I can +%redefine \cs{DTLplotatendtikz} to draw an annotated arrow to +%that point: +%\begin{verbatim} +%\renewcommand*{\DTLplotatendtikz}{% +%\draw[<-,line width=1pt] (1.58,48.3) -- (1.6,43) +% node[below]{interesting point}; +%} +%\end{verbatim} +%So \autoref{fig:legend} now looks like \autoref{fig:annote}. +% +%\begin{figure}[htbp] +%\renewcommand*{\DTLplotatendtikz}{% +%\draw[<-,line width=1pt] (1.58,48.3) -- (1.6,43) +% node[below]{interesting point}; +%} +%\centering +%\DTLplot{groupa,groupb}{x=Height,y=Weight,legend, +%width=3in,height=3in,legendlabels={Group A,Group B},box, +%xlabel={Height (m)},ylabel={Weight (kg)}, +%xticpoints={1.54,1.55,1.56,1.57,1.58,1.59,1.60,1.61,1.62}} +%\caption{A Scatter Plot} +%\label{fig:annote} +%\end{figure} +%\end{example} +% +%\subsection{Global Plot Settings} +% +%\subsubsection{Lengths} +%This section describes the lengths that govern the appearance of +%the plot created using \ics{DTLplot}. These lengths can be +%changed using \cs{setlength}. +% +%\DescribeMacro{\DTLplotwidth} +%\begin{definition} +%\cs{DTLplotwidth} +%\end{definition} +%This length governs the length of the $x$ axis. Note that the plot +%width does not include any outer tick marks or labels. The default +%value is 4in. +% +%\DescribeMacro{\DTLplotheight} +%\begin{definition} +%\cs{DTLplotheight} +%\end{definition} +%This length governs the length of the $y$ axis. Note that the plot +%height does not include any outer tick marks or labels. The default +%value is 4in +% +%\DescribeMacro{\DTLticklength} +%\begin{definition} +%\cs{DTLticklength} +%\end{definition} +%This governs the length of the tick marks. The default value is +%5pt. +% +%\DescribeMacro{\DTLminorticklength} +%\begin{definition} +%\cs{DTLminorticklength} +%\end{definition} +%This governs the length of the minor tick marks. The default value is +%2pt. +% +%\DescribeMacro{\DTLticklabeloffset} +%\begin{definition} +%\cs{DTLticklabeloffset} +%\end{definition} +%This governs the distance from the axis to the tick labels. The +%default value is 8pt. +% +%\DescribeMacro{\DTLmintickgap} +%\begin{definition} +%\cs{DTLmintickgap} +%\end{definition} +%This is the minimum distance allowed between tick marks. If the +%plot width or height is less than this distance there will only +%be tick marks at either end of the axis. The default value is +%20pt. +% +%\DescribeMacro{\DTLlegendxoffset} +%\begin{definition} +%\cs{DTLlegendxoffset} +%\end{definition} +%This is the horizontal distance from the border of the plot to the +%outer border of the legend. The default value is 10pt. +% +%\DescribeMacro{\DTLlegendyoffset} +%\begin{definition} +%\cs{DTLlegendyoffset} +%\end{definition} +%This is the vertical distance from the border of the plot to the +%outer border of the legend. The default value is 10pt. +% +%\subsubsection{Counters} +%These counters govern the appearance of plots +%created using \ics{DTLplot}. The value of the counters can be +%changed using \cs{setcounter}. +% +%\begin{definition} +%\counterfmt{DTLplotroundXvar} +%\end{definition} +%Unless you specify your own tick labels, the $x$ tick labels will +%be given by the tick points rounded to \meta{n} digits after the +%decimal point, where \meta{n} is the value of the counter +%\counterfmt{DTLplotroundXvar}. +% +%\begin{definition} +%\counterfmt{DTLplotroundYvar} +%\end{definition} +%Unless you specify your own tick labels, the $y$ tick labels will +%be given by the tick points rounded to \meta{n} digits after the +%decimal point, where \meta{n} is the value of the counter +%\counterfmt{DTLplotroundYvar}. +% +%\subsubsection{Macros} +%These macros govern the appearance of plots created using +%\ics{DTLplot}. They can be changed using \cs{renewcommand}. +% +%\DescribeMacro{\DTLplotmarks} +%\begin{definition} +%\cs{DTLplotmarks} +%\end{definition} +%This must be a comma separated list of \sty{pgf} code to create the +%plot marks. \ics{DTLplot} cycles through this list for each +%database listed. The \sty{pgf} package provides convenient commands +%for generating plots using \cs{pgfuseplotmark}. See the \sty{pgf} +%manual for more details. +% +%\DescribeMacro{\DTLplotmarkcolors} +%\begin{definition} +%\cs{DTLplotmarkcolors} +%\end{definition} +%This must be a comma separated list of defined colours to apply to the +%plot marks. \ics{DTLplot} cycles through this list for each database +%listed. If this macro is set to empty, the current colour will +%be used instead. +% +%\DescribeMacro{\DTLplotlines} +%\begin{definition} +%\cs{DTLplotlines} +%\end{definition} +%This must be a comma separated list of \sty{pgf} code to set the +%style of the plot lines. \ics{DTLplot} cycles through this list for +%each database listed. Dash patterns can be set using \cs{pgfsetdash}, +%see the \sty{pgf} manual for more details. If \cs{DTLplotlines} is +%set to empty the current line style will be used instead. +% +%\DescribeMacro{\DTLplotlinecolors} +%\begin{definition} +%\cs{DTLplotlinecolors} +%\end{definition} +%This must be a comma separated list of defined colours to apply to the +%plot lines. \cs{DTLplot} cycles through this list for each database +%listed. If this macro is set to empty, the current colour will +%be used instead. The default is the same as \cs{DTLplotmarkcolors}. +% +%\DescribeMacro{\DTLXAxisStyle} +%\begin{definition} +%\cs{DTLxaxisstyle} +%\end{definition} +%This governs the style of the $x$ axis. It is passed as the optional +%argument to the TikZ \cs{draw} command. By default it is just "-" +%which is a solid line style with no start or end arrows. The $x$ +%axis line starts from the bottom left corner of the plot and extends +%to the bottom right corner of the plot. So if you want the $x$ axis +%to have an arrow head at the right end, you can do: +%\begin{verbatim} +%\renewcommand*{\DTLXAxisStyle}{->} +%\end{verbatim} +% +%\DescribeMacro{\DTLYAxisStyle} +%\begin{definition} +%\cs{DTLyaxisstyle} +%\end{definition} +%This governs the style of the $y$ axis. It is analogous to +%\cs{DTLxaxisstyle} described above. +% +%\DescribeMacro{\DTLmajorgridstyle} +%\begin{definition} +%\cs{DTLmajorgridstyle} +%\end{definition} +%This specifies the format of the major grid lines. +%It may be set to any TikZ setting that you can pass to the +%optional argument of \cs{draw}. The default value is +%"color=gray,-" which indicates a grey solid line. +% +%\DescribeMacro{\DTLminorgridstyle} +%\begin{definition} +%\cs{DTLminorgridstyle} +%\end{definition} +%This specifies the format of the minor grid lines. +%It may be set to any TikZ setting that you can pass to the +%optional argument of \cs{draw}. The default value is +%"color=gray,loosely dotted" which indicates a grey dotted line. +% +%\DescribeMacro{\DTLformatlegend} +%\begin{definition} +%\cs{DTLformatlegend}\marg{legend} +%\end{definition} +%This formats the entire legend, which is passed as the argument. +%The default is to set the legend with +%a white background, a black frame. +% +%\subsection{Adding to a Plot Stream} +%\DescribeMacro{\DTLplotstream} +%\begin{definition} +%\cs{DTLplotstream}\oarg{condition}\marg{db name}\marg{x key}\marg{y key} +%\end{definition} +%This adds points to a stream from the database called \meta{db name} +%where the $x$ co-ordinates are given by the key \meta{x key} +%and the $y$ co-ordinates are given by the key \meta{y key}. +%(\ics{DTLconverttodecimal} is used to convert locale dependent +%values to a standard decimal that is recognised by the +%\sty{pgf} package.) +%The optional argument \meta{condition} is the same as that +%for \ics{DTLforeach}. +% +%\begin{example}{Adding to a Plot Stream}{ex:plotstream} +%Suppose you have a CSV file called "data.csv" containing the +%following: +%\begin{verbatim} +%x,y +%0,0 +%1,1 +%2,0.5 +%1.5,0.3 +%\end{verbatim} +%\DTLnewdb{data}\relax +%\DTLnewrow{data}\relax +%\DTLnewdbentry{data}{x}{0}\relax +%\DTLnewdbentry{data}{y}{0}\relax +%\DTLnewrow{data}\relax +%\DTLnewdbentry{data}{x}{1}\relax +%\DTLnewdbentry{data}{y}{1}\relax +%\DTLnewrow{data}\relax +%\DTLnewdbentry{data}{x}{2}\relax +%\DTLnewdbentry{data}{y}{0.5}\relax +%\DTLnewrow{data}\relax +%\DTLnewdbentry{data}{x}{1.5}\relax +%\DTLnewdbentry{data}{y}{0.3}\relax +%First load the file into a database called "data": +%\begin{verbatim} +%\DTLloaddb{data}{data.csv} +%\end{verbatim} +%Now create a figure containing this data: +%\begin{verbatim} +%\begin{figure}[tbhp] +%\centering +%\begin{tikzpicture} +%\pgfplothandlermark{\pgfuseplotmark{o}} +%\pgfplotstreamstart +%\DTLplotstream{data}{x}{y}% +%\pgfplotstreamend +%\pgfusepath{stroke} +%\end{tikzpicture} +%\caption{Adding to a Plot Stream} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:plotstream}. +% +%\begin{figure}[tbhp] +%\centering +%\begin{tikzpicture} +%\pgfplothandlermark{\pgfuseplotmark{o}} +%\pgfplotstreamstart +%\DTLplotstream{data}{x}{y}% +%\pgfplotstreamend +%\pgfusepath{stroke} +%\end{tikzpicture} +%\caption{Adding to a Plot Stream} +%\label{fig:plotstream} +%\end{figure} +%\end{example} +% +%\begin{example}{Plotting Multiple Keys in the Same +%Database}{ex:multikey} +%Suppose I have conducted two time to growth experiments. For each +%experiment, I have recorded the log count at set times, and I have +%recorded this information in the same data file called, say, +%"growth.csv" which contains the following: +%\begin{verbatim} +%Time,Experiment 1,Experiment 2 +%0,3.73,3.6 +%23,3.67,3.7 +%60,4.9,3.8 +%\end{verbatim} +%\DTLnewdb{growth}\DTLnewrow{growth}\relax +%\DTLnewdbentry{growth}{Time}{0}\relax +%\DTLnewdbentry{growth}{Experiment 1}{3.73}\relax +%\DTLnewdbentry{growth}{Experiment 2}{3.6}\relax +%\DTLnewrow{growth}\relax +%\DTLnewdbentry{growth}{Time}{23}\relax +%\DTLnewdbentry{growth}{Experiment 1}{3.67}\relax +%\DTLnewdbentry{growth}{Experiment 2}{3.7}\relax +%\DTLnewrow{growth}\relax +%\DTLnewdbentry{growth}{Time}{60}\relax +%\DTLnewdbentry{growth}{Experiment 1}{4.9}\relax +%\DTLnewdbentry{growth}{Experiment 2}{3.8}\relax +%I can load the data into a database using: +%\begin{verbatim} +%\DTLloaddb{growth}{growth.csv} +%\end{verbatim} +%However, I'd like to plot both results on the same graph. Since they +%are contained in the same database, I can't use the method I used +%in \autoref{ex:2db}. Instead I can use a combination of +%\ics{DTLplot} and \ics{DTLplotstream}: +%\begin{verbatim} +%\begin{figure}[tbhp] +%\centering +%% computer bounds +%\DTLminforkeys{growth}{Time}{\minX} +%\DTLminforkeys{growth}{Experiment 1,Experiment 2}{\minY} +%\DTLmaxforkeys{growth}{Time}{\maxX} +%\DTLmaxforkeys{growth}{Experiment 1,Experiment 2}{\maxY} +%% round x tick labels +%\setcounter{DTLplotroundXvar}{0} +%% redefine \DTLplotatbegintikz to plot the data for Experiment 1 +%\renewcommand*{\DTLplotatbegintikz}{% +%% set plot mark +%\pgfplothandlermark{\color{green}\pgfuseplotmark{x}} +%% start plot stream +%\pgfplotstreamstart +%% add data from Experiment 1 to plot stream +%\DTLplotstream{growth}{Time}{Experiment 1}% +%% end plot stream +%\pgfplotstreamend +%% stroke path +%\pgfusepath{stroke} +%% add information to legend (no line is require so use \relax) +%\DTLaddtoplotlegend{\color{green}% +%\pgfuseplotmark{x}}{\relax}{Experiment 1} +%} +%% now plot the data for Experiment 2 +%\DTLplot{growth}{x=Time,y=Experiment 2,legend, +%width=3in,height=3in,bounds={\minX,\minY,\maxX,\maxY}, +%xlabel={Time},ylabel={Log Count}, +%legendlabels={Experiment 2}} +%\caption{Time to Growth Data} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:multikey}. +%Notes: +%\begin{itemize} +%\item I redefined \ics{DTLplotatbegintikz} in order to add +%the new plot to the legend, since \ics{DTLplotatendtikz} is +%used after the legend is plotted. The $x$ and $y$ unit vectors +%are set before \ics{DTLplotatbegintikz} so I don't need to +%worry about the co-ordinates. +%\item I set the counter \counterfmt{DTLplotroundXvar} to zero +%otherwise the $x$ axis would have looked too cluttered. +%\item I have used \ics{DTLminforkeys} and \ics{DTLmaxforkeys} to +%determine the bounds since \ics{DTLplot} won't take the data +%for Experiment 1 into account when computing the bounds. +%\end{itemize} +% +%\begin{figure}[htbp] +%\DTLminforkeys{growth}{Time}{\minX} +%\DTLminforkeys{growth}{Experiment 1,Experiment 2}{\minY} +%\DTLmaxforkeys{growth}{Time}{\maxX} +%\DTLmaxforkeys{growth}{Experiment 1,Experiment 2}{\maxY} +%\setcounter{DTLplotroundXvar}{0} +%\renewcommand*{\DTLplotatbegintikz}{% +%\pgfplothandlermark{\color{green}\pgfuseplotmark{x}} +%\pgfplotstreamstart +%\DTLplotstream{growth}{Time}{Experiment 1}% +%\pgfplotstreamend +%\pgfusepath{stroke} +%\DTLaddtoplotlegend{\color{green}\pgfuseplotmark{x}}{\relax}{Experiment 1} +%} +%\centering +%\DTLplot{growth}{x=Time,y=Experiment 2,legend, +%width=3in,height=3in,bounds={\minX,\minY,\maxX,\maxY}, +%xlabel={Time},ylabel={Log Count}, +%legendlabels={Experiment 2}} +%\caption{Time to Growth Data} +%\label{fig:multikey} +%\end{figure} +%\end{example} +% +%\section{Bar Charts (\texorpdfstring{databar}{databar} package)} +% +%The \sty{databar} package provides commands for creating bar charts. +%It is not loaded by the \sty{datatool} package, so if you want to +%use it you will need to load it explicitly using +%"\usepackage{databar}". +% +%Bar charts can either be vertical or horizontal, the default is +%vertical. In this section the $x$ axis refers to the horizontal +%axis when plotting a vertical bar chart and to the vertical axis +%when plotting a horizontal bar chart. The $x$ axis units are in +%increments of one bar. The $y$ axis refers to the vertical axis +%when plotting a vertical bar chart and to the horizontal axis when +%plotting a horizontal bar chart. The $y$ axis uses the same +%co-ordinates as the data. The bars may have an upper and lower +%label. In a vertical bar chart, the lower label is placed below +%the $x$ axis and the upper label is placed above the top of the bar. +%In a horizontal bar chart, the lower label is placed to the left of +%the $x$ axis and the upper label is placed to the right of the +%end of the bar. (This is actually a misnomer as it is possible +%for the ``upper'' label to be below the ``lower'' label if a +%bar has a negative value, however the bars are considered to +%be anchored on the $x$ axis, and the other end of the bar is +%considered to be the ``upper'' end, regardless of its +%direction.) +% +%The \sty{databar} package options are as follows: +%\begin{description} +%\item[{\pkgopt[databar]{color}}] Created coloured bar charts +%(default.) +% +%\item[{\pkgopt[databar]{gray}}] Created grey scale bar charts. +% +%\item[{\pkgopt[databar]{vertical}}] Created vertical bar charts +%(default.) +% +%\item[{\pkgopt[databar]{horizontal}}] Created horizontal bar charts. +%\end{description} +% +% +%\DescribeMacro{\DTLbarchart} +%\begin{definition} +%\cs{DTLbarchart}\oarg{condition}\marg{db name}\marg{settings}\marg{values} +%\end{definition} +%\DescribeMacro{\DTLmultibarchart} +%\begin{definition} +%\cs{DTLmultibarchart}\oarg{condition}\marg{db name}\marg{settings}\marg{values} +%\end{definition} +%These commands both create a bar chart from the information in +%the database \meta{db name}, where \meta{condition} is the same +%as the optional argument for \ics{DTLforeach} described in +%\autoref{sec:dbforeach}, and \meta{values} is the same as the +%penultimate argument of \ics{DTLforeach}. The \meta{settings} +%argument is a \meta{setting}"="\meta{value} list of settings. The +%first command, \cs{DLTbarchart}, will draw a bar chart for a +%given column of data in the database, whereas the second command, +%\cs{DTLmultibarchart}, will draw a bar chart that is divided into +%groups of bars where each bar within a group represents data from +%several columns of a given row in the database. +% +%The \setting{DTLbarchart}{variable} setting is +%required for \cs{DTLbarchart} and the +%\setting{DTLmultibarchart}{variables}, the other settings are +%optional (though some may only be used for one of +%\cs{DTLbarchart} and \cs{DLTmultibarchart}), and are as follows: +% +%\begin{description} +%\item[\setting{DTLbarchart}{variable}] +%This specifies the control sequence to use that +%contains the value used to construct the bar chart. The control +%sequence must be one of the control sequences to appear in +%the assignment list \meta{values}. This setting is required +%for \cs{DTLbarchart}, and is unavailable for \cs{DTLmultibarchart}. +% +%\item[\setting{DTLmultibarchart}{variables}] +%This specifies a list of control sequences to use which +%contain the values used to construct the bar chart. Each control +%sequence must be one of the control sequences to appear in +%the assignment list \meta{values}. This setting is required +%for \cs{DTLmultibarchart}, and is unavailable for +%\cs{DTLbarchart}. +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{max}] +%This specifies the maximum value on the $y$ axis. (This should +%be a standard decimal value.) +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{length}] +%This specifies the overall length of the $y$ axis, and must +%be a dimension. +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{maxdepth}] +%This must be a zero or negative number. It specifies the maximum +%depth of the $y$ axis. (This should be a standard decimal value.) +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{axes}] +%This setting specifies which axes to display. This may take one +%of the following values: "both", "x", "y" or "none". +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{barlabel}] +%This setting specifies the lower bar label. When used with +%\cs{DTLmultibarchart} it indicates the group label. +% +%\item[\setting{DTLmultibarchart}{multibarlabels}] +%This setting should contain a comma separated list of labels +%for each bar within a group for \cs{DTLmultibarchart}. This +%setting is not available for \cs{DTLbarchart}. +% +%\item[\setting{DTLbarchart}{upperbarlabel}] +%This setting specifies the upper bar label. This setting +%is not available for \cs{DTLmultibarchart}. +% +%\item[\setting{DTLmultibarchart}{uppermultibarlabels}] +%This setting must be a comma separated list of upper bar +%labels for each bar within a group. This setting is not +%available for \cs{DTLbarchart}. +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{yticpoints}] +%This must be a comma separated list of tick locations for the +%$y$ axis. (These should be standard decimal values.) +%This setting overrides \setting{DTLbarchart}{yticgap}. +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{yticgap}] +%This specifies the gap between the $y$ tick marks. (This should +%be a standard decimal value.) +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{yticlabels}] +%This must be a comma separated list of tick labels for the +%$y$ axis. +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{ylabel}] +%This specifies the label for the $y$ axis. +% +%\item[\setting{DTLmultibarchart}{groupgap}] This specifies +%the gap between groups when using \cs{DTLmultibarchart}. +%This value is given as a multiple of the bar width. The +%default value is 1, which indicates a gap of one bar width. +%This setting is not available for \cs{DTLbarchart}. +% +%\item[\setting{DTLbarchart,DTLmultibarchart}{verticalbars}] +%This is a boolean setting, so it can only take the values +%"true" (do a vertical bar chart) or "false" (do a horizontal +%bar chart.) If the value is omitted, "true" is assumed. +%\end{description} +% +%\begin{example}{A Basic Bar Chart}{ex:barchart} +%Recall \autoref{ex:piechart} defined a database called "fruit". +%This example will be using that database to plot a bar chart. +%The following plots a basic vertical bar chart: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLbarchart{variable=\theQuantity}{fruit}{\theQuantity=Quantity} +%\caption{A Basic Bar Chart} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:barchart}. +% +%\begin{figure}[htbp] +%\centering +%\DTLbarchart{variable=\theQuantity}{fruit}{\theQuantity=Quantity} +%\caption{A Basic Bar Chart} +%\label{fig:barchart} +%\end{figure} +%\end{example} +% +%\subsection{Changing the Appearance of a Bar Chart} +% +%\DescribeMacro{\DTLbarchartlength} +%\begin{definition} +%\cs{DTLbarchartlength} +%\end{definition} +%This specifies the total length of the $y$ axis. You must use +%\cs{setlength} to change this value. The default value is 3in. +% +%\DescribeMacro{\DTLbarwidth} +%\begin{definition} +%\cs{DTLbarwidth} +%\end{definition} +%This specifies the width of each bar. You must use \cs{setlength} +%to change this value. The default value is 1cm. +% +%\DescribeMacro{\DTLbarlabeloffset} +%\begin{definition} +%\cs{DTLbarlabeloffset} +%\end{definition} +%This specifies the distance from the $x$ axis to the lower bar label. +%You must use \cs{setlength} to change this value. The default value +%is 10pt. +% +%\begin{definition} +%\counterfmt{DTLbarroundvar} +%\end{definition} +%The $y$ tick labels are rounded to \meta{n} digits after the +%decimal point, where \meta{n} is given by the value of the +%counter \counterfmt{DTLbarroundvar}. You must use \cs{setcounter} +%to change this value. +% +%\DescribeMacro{\DTLsetbarcolor} +%\begin{definition} +%\cs{DTLsetbarcolor}\marg{n}\marg{color} +%\end{definition} +%This sets the \meta{n}th bar colour to \meta{color}. +%Only the first eight bars have a colour defined by default. If you +%need more than eight bars, you will need to define more bar colours. +% +%\DescribeMacro{\DTLdobarcolor} +%\begin{definition} +%\cs{DTLdobarcolor}\marg{n} +%\end{definition} +%This sets the current colour to the colour of the \meta{n}th bar. +% +%\DescribeMacro{\DTLbaroutlinecolor} +%\begin{definition} +%\cs{DTLbaroutlinecolor} +%\end{definition} +%This macro contains the colour of the bar outlines. This defaults +%to "black". +% +%\DescribeMacro{\DTLbaroutlinewidth} +%\begin{definition} +%\cs{DTLbaroutlinewidth} +%\end{definition} +%This length specifies the line width for the bar outlines. If it +%is 0pt, the outline is not drawn. The default value is 0pt. +% +%\DescribeMacro{\DTLbaratbegintikz} +%\begin{definition} +%\cs{DTLbaratbegintikz} +%\end{definition} +%This specifies any additional commands to add to the start of +%the plot. It defaults to nothing, and is called after the +%unit vectors are set. +% +%\DescribeMacro{\DTLbaratendtikz} +%\begin{definition} +%\cs{DTLbaratendtikz} +%\end{definition} +%This specifies any additional commands to add to the end of +%the plot. It defaults to nothing. +% +%\DescribeMacro{\ifDTLverticalbars} +%\begin{definition} +%\cs{ifDTLverticalbars} +%\end{definition} +%This conditional governs whether the chart uses vertical or +%horizontal bars. +% +%\DescribeMacro{\DTLbarXlabelalign} +%\begin{definition} +%\cs{DTLbarXlabelalign} +%\end{definition} +%This specifies the text alignment of the lower bar labels. This +%defaults to "left,rotate=-90" if you use the \pkgopt[databar]{vertical} +%package option or the \setting{DTLbarchart}{verticalbars} setting, +%and defaults to "right" if you use the \pkgopt[databar]{horizontal} +%package option or the \setting{DTLbarchart}{verticalbars}"=false" +%setting. +% +%\DescribeMacro{\DTLbarYticklabelalign} +%\begin{definition} +%\cs{DTLbarYlabelalign} +%\end{definition} +%This specifies the text alignment of the $y$ axis labels. This +%defaults to "right" for vertical bar charts and "center" for +%horizontal bar charts. +% +%\DescribeMacro{\DTLbardisplayYticklabel} +%\begin{definition} +%\cs{DTLbardisplayYticklabel}\marg{text} +%\end{definition} +%This specifies how to display the $y$ tick label. The argument +%is the tick label. +% +%\DescribeMacro{\DTLdisplaylowerbarlabel} +%\begin{definition} +%\cs{DTLdisplaylowerbarlabel}\marg{text} +%\end{definition} +%This specifies how to display the lower bar label for +%\cs{DTLbarchart} and the lower bar group label for +%\cs{DTLmultibarchart}. The argument is the label. +% +%\DescribeMacro{\DTLdisplaylowermultibarlabel} +%\begin{definition} +%\cs{DTLdisplaylowermultibarlabel}\marg{text} +%\end{definition} +%This specifies how to display the lower bar label for +%\cs{DTLmultibarchart}. The argument is the label. This +%command is ignored by \cs{DTLbarchart}. +% +%\DescribeMacro{\DTLdisplayupperbarlabel} +%\begin{definition} +%\cs{DTLdisplayupperbarlabel}\marg{text} +%\end{definition} +%This specifies how to display the upper bar label for +%\cs{DTLbarchart} and the upper bar group label for +%\cs{DTLmultibarchart}. The argument is the label. +% +%\DescribeMacro{\DTLdisplayuppermultibarlabel} +%\begin{definition} +%\cs{DTLdisplayuppermultibarlabel}\marg{text} +%\end{definition} +%This specifies how to display the upper bar label for +%\cs{DTLmultibarchart}. The argument is the label. This +%command is ignored by \cs{DTLbarchart}. +% +%\begin{example}{An Labelled Bar Chart}{ex:annotebarchart} +%This example extends \autoref{ex:barchart} so that the chart is +%a bit more informative (which is after all the whole point of +%a chart.) This chart now has a label below each bar, as well +%as a label above the bar. The lower label uses the value of the +%"Name" key, and the upper label uses the quantity. I have also +%set the outline width so each bar has a border. +%\begin{verbatim} +%\begin{figure}[htbp] +%\setlength{\DTLbaroutlinewidth}{1pt} +%\centering +%\DTLbarchart{variable=\theQuantity,barlabel=\theName,% +%upperbarlabel=\theQuantity}{fruit}{% +%\theQuantity=Quantity,\theName=Name} +%\caption{A Basic Bar Chart} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:annotebarchart}. +% +%\begin{figure}[htbp] +%\centering +%\setlength{\DTLbaroutlinewidth}{1pt} +%\DTLbarchart{variable=\theQuantity,barlabel=\theName, +%upperbarlabel=\theQuantity}{fruit}{% +%\theQuantity=Quantity,\theName=Name} +%\caption{A Bar Chart} +%\label{fig:annotebarchart} +%\end{figure} +%\end{example} +% +%\begin{example}{Profit/Loss Bar Chart}{ex:profit} +%Suppose I have a file called "profits.csv" that looks like: +%\DTLnewdb{profits} +%\DTLnewrow{profits} +%\DTLnewdbentry{profits}{Year}{2000}\relax +%\DTLnewdbentry{profits}{Profit}{\protect\pounds2,525}\relax +%\DTLnewrow{profits} +%\DTLnewdbentry{profits}{Year}{2001}\relax +%\DTLnewdbentry{profits}{Profit}{\protect\pounds3,752}\relax +%\DTLnewrow{profits} +%\DTLnewdbentry{profits}{Year}{2002}\relax +%\DTLnewdbentry{profits}{Profit}{-\protect\pounds1,520}\relax +%\DTLnewrow{profits} +%\DTLnewdbentry{profits}{Year}{2003}\relax +%\DTLnewdbentry{profits}{Profit}{\protect\pounds1,270}\relax +%\begin{verbatim} +%Year,Profit +%2000,\pounds2,535 +%2001,\pounds3,752 +%2002,-\pounds1,520 +%2003,\pounds1,270 +%\end{verbatim} +%First I can load this file into a database called "profits": +%\begin{verbatim} +%\DTLloaddb{profits}{profits.csv} +%\end{verbatim} +%Now I can plot the data as a bar chart: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%% Set the width of each bar to 10pt +%\setlength{\DTLbarwidth}{10pt} +%% Set the outline width to 1pt +%\setlength{\DTLbaroutlinewidth}{1pt} +%% Round the $y$ tick labels to integers +%\setcounter{DTLbarroundvar}{0} +%% Adjust the tick label offset +%\setlength{\DTLticklabeloffset}{20pt} +%% Change the y tick label alignment +%\renewcommand*{\DTLbarYticklabelalign}{left} +%% Rotate the y tick labels +%\renewcommand*{\DTLbardisplayYticklabel}[1]{\rotatebox{-45}{#1}} +%% Set the bar colours depending on the value of \theProfit +%\DTLforeach{profits}{\theProfit=Profit}{% +%\ifthenelse{\DTLislt{\theProfit}{0}} +%{\DTLsetbarcolor{\DTLcurrentindex}{red}} +%{\DTLsetbarcolor{\DTLcurrentindex}{blue}}} +%% Do the bar chart +%\DTLbarchart{variable=\theProfit,upperbarlabel=\theYear, +%ylabel={Profit/Loss (\pounds)},verticalbars=false, +%maxdepth=-2000,max=4000}{profits} +%{\theProfit=Profit,\theYear=Year} +%\caption{Profits for 2000--2003} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:profits}. Notes: +%\begin{enumerate} +%\item This example uses \cs{rotatebox}, so the \sty{graphics} +%or \sty{graphicx} package is required. +%\item The $y$ tick labels are too wide to fit horizontally +%so they have been rotated to avoid overlapping with their +%neighbour. +%\item Rotating the $y$ tick labels puts them too close to +%the $y$ axis, so \ics{DTLticklabeloffset} is made larger to +%compensate. +%\item Remember not to use \cs{year} as an assignment command +%as this command already exists! +%\item Before the bar chart is created I have iterated through +%the database, setting the bar colour to red or blue +%depending on the value of \cs{theProfit}. +%\end{enumerate} +% +%Both \cs{DTLbarchart} and \cs{DTLmultibarchart} set the following +%macros, which may be used in \cs{DTLbaratbegintikz} and +%\cs{DTLbaratendtikz}: +%\DescribeMacro{\DTLbarchartwidth} +%\begin{definition} +%\cs{DTLbarchartwidth} +%\end{definition} +%This is the overall width of the bar chart. In the case of +%\cs{DTLbarchart} this is just the number of bars. In the case +%of \cs{DTLmultibarchart} it is computed as: +%\begin{displaymath} +%m \times n + (m-1)\times g +%\end{displaymath} +%where $m$ is the number of bar groups (i.e.\ the number of rows +%of data), $n$ is the number of bars within a group (i.e.\ +%the number of commands listed in the +%\setting{DTLmultibarchart}{variables}) setting and $g$ is the +%group gap (as specified by the \setting{DTLmultibarchart}{groupgap} setting.) +% +%\DescribeMacro{\DTLnegextent} +%\begin{definition} +%\cs{DTLnegextent} +%\end{definition} +%This is set to the negative extent of the bar chart. (This value +%may either be zero or negative, and corresponds to the +%\setting{DTLbarchart,DTLmultibarchart}{maxdepth} setting.) +% +%\DescribeMacro{\DTLbarmax} +%\begin{definition} +%\cs{DTLbarmax} +%\end{definition} +%This is set to the maximum extent of the bar chart. (This value +%corresponds to the +%\setting{DTLbarchart,DTLmultibarchart}{max} setting.) +% +%\begin{figure}[htbp] +%\centering +%\setlength{\DTLbarwidth}{10pt} +%\setlength{\DTLbaroutlinewidth}{1pt} +%\setlength{\DTLticklabeloffset}{20pt} +%\setcounter{DTLbarroundvar}{0} +%\renewcommand*{\DTLbarYticklabelalign}{left} +%\renewcommand*{\DTLbardisplayYticklabel}[1]{\rotatebox{-45}{#1}} +%\DTLforeach{profits}{\theProfit=Profit}{\relax +%\ifthenelse{\DTLislt{\theProfit}{0}} +%{\DTLsetbarcolor{\DTLcurrentindex}{red}} +%{\DTLsetbarcolor{\DTLcurrentindex}{blue}}} +%\DTLbarchart{variable=\theProfit,upperbarlabel=\theYear, +%ylabel={Profit/Loss (\pounds)},verticalbars=false, +%maxdepth=-2000,max=4000 +%}{profits} +%{\theProfit=Profit,\theYear=Year} +%\caption{Profits for 2000--2003} +%\label{fig:profits} +%\end{figure} +% +%\end{example} +% +%\begin{example}{A Multi-Bar Chart}{ex:multibar} +%This example uses the "marks" database described in +%\autoref{ex:editdb}. +%Recall that this database stores student marks for three +%assignments. The keys for the assignment marks are +%\texttt{Assignment 1}, \texttt{Assignment 2} and +%\texttt{Assignment 3}, respectively. I can convert this +%data into a bar chart using the following: +%\begin{verbatim} +%\begin{figure}[htbp] +%\centering +%\DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, +%barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, +%barlabel={\firstname\ \surname}}{marks}{% +%\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,% +%\assignII=Assignment 2,\assignIII=Assignment 3} +%\caption{Student Marks} +%\end{figure} +%\end{verbatim} +%This produces \autoref{fig:multibar}. Notes: +%\begin{enumerate} +%\item I used "variables={\assignI,\assignII,\assignIII}" to +%set the variable to use for each bar within a group. This means +%that there will be three bars in each group. +%\item I have set the bar width to 10pt, otherwise the chart +%will be too wide. +%\item I used "uppermultibarlabels={\assignI,\assignII,\assignIII}" +%to set the upper labels for each bar within a group. This +%will print the assignment mark above the relevant bar. +%\item I used "barlabel={\firstname\ \surname}" to place the +%student's name below the group corresponding to that student. +%\end{enumerate} +% +%\begin{figure}[htbp] +%\centering +%\DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, +%barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, +%barlabel={\firstname\ \surname}}{marks} +%{\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII=Assignment 3} +%\caption{Student Marks}\label{fig:multibar} +%\end{figure} +% +%Recall that \autoref{ex:editdb} computed the average score over +%for each student, and saved it with the key "Average". This +%information can be added to the bar chart. It might also be +%useful to compute the average over all students and add this +%information to the chart. This is done as follows: +%\begin{verbatim} +%\end{verbatim} +%which produces \autoref{fig:multibarmean}. Notes: +%\begin{enumerate} +%\item I've used the TikZ snake library to create a brace, so +%I need to put +%\begin{verbatim} +%\usetikzlibrary{snakes} +%\end{verbatim} +%in the preamble. See the \sty{pgf} manual for more details on +%how to use this library. +% +%\item I used \ics{DTLbargroupwidth} to indicate the width of +%each bar group. +% +%\item I used \ics{DTLbarchartwidth} to indicate the width of the +%entire bar chart +%\end{enumerate} +% +%\begin{figure}[htbp] +%\centering +%\DTLmeanforkeys{marks}{Average}{\overallmean} +%\DTLround{\overallmean}{\overallmean}{2} +%\renewcommand*{\DTLbaratendtikz}{\draw[lightgray,loosely dotted] (0,\overallmean) -- +%(\DTLbarchartwidth,\overallmean) node[right,black]{Average (\overallmean)};} +%\renewcommand*{\DTLdisplaylowerbarlabel}[1]{\relax +%\tikz[baseline=(current bounding box.center)]{ +%\draw[snake=brace,rotate=-90](0,0) -- (\DTLbargroupwidth,0);} +%\DTLround{\theMean}{\theMean}{2}\relax +%\shortstack{#1\\(Average: \theMean)}} +%\DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, +%barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, +%barlabel={\firstname\ \surname}}{marks} +%{\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII=Assignment 3,\theMean=Average} +%\caption{Student Marks (with average scores)} +%\label{fig:multibarmean} +%\end{figure} +%\end{example} +% +% \StopEventually{\clearpage\phantomsection +%\addcontentsline{toc}{section}{Index}\PrintIndex} +% +% +% +%\section{datatool.sty} +%\iffalse +% \begin{macrocode} +%<*datatool.sty> +% \end{macrocode} +%\fi +%\subsection{Package Declaration} +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datatool}[2007/07/23 v1.0 (NLCT)] +% \end{macrocode} +% Load required packages: +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{ifthen} +\RequirePackage{xfor} +\RequirePackage{fp} +\RequirePackage{substr} +% \end{macrocode} +% +%\subsection{Package Options} +% Define macro to store data separator character (comma by default) +% This is the separator used in external data files, not in the +% \LaTeX\ code, which always uses a comma separator. +%\begin{macro}{\@dtl@separator} +% \begin{macrocode} +\newcommand*{\@dtl@separator}{,} +% \end{macrocode} +%\end{macro} +% Provide a command for setting the data separator. This sets +% \cs{@dtl@separator}, and constructs the relevent macros that +% require this character to be hardcoded into their definition. +%\begin{macro}{\DTLsetseparator} +% \begin{macrocode} +\newcommand*{\DTLsetseparator}[1]{% +\renewcommand*{\@dtl@separator}{#1}% +\@dtl@construct@lopoffs +} +% \end{macrocode} +%\end{macro} +% Make it easier to set a tab separator +%\begin{macro}{\DTLsettabseparator} +\begingroup +\catcode`\ 12 +\gdef\DTLsettabseparator{% + \catcode`\ 12 + \DTLsetseparator{ }% +} +\endgroup +%\end{macro} +% +% Define a macro to store data delimiter character (double quote +% by default.) This is used in external data files, not in the +% \LaTeX\ code. +%\begin{macro}{\@dtl@delimiter} +% \begin{macrocode} +\begingroup +\catcode`\"12\relax +\gdef\@dtl@delimiter{"} +\endgroup +% \end{macrocode} +%\end{macro} +% Define a macro that sets the delimiter. +%\begin{macro}{\DTLsetdelimiter} +% \begin{macrocode} +\newcommand*\DTLsetdelimiter[1]{% +\renewcommand*{\@dtl@delimiter}{#1}% +\@dtl@construct@lopoffs} +% \end{macrocode} +%\end{macro} +% \cs{@dtl@construct@lopoff}\meta{separator char}\meta{delimiter char} +% defines +% \cs{@dtl@lopoff}\meta{first element}\meta{sep}\meta{rest of list}\cs{to}\meta{cmd1}\meta{cmd2} +% for the current separator and delimiter. +%\begin{macro}{\@dtl@construct@lopoff} +% \begin{macrocode} +\edef\@dtl@construct@lopoff#1#2{% +\noexpand\long\noexpand\def\noexpand\@dtl@lopoff#1##1##2\noexpand +\to##3##4{% +\noexpand\ifx#2##1\noexpand\relax +\noexpand\@dtl@qlopoff#1##1##2\noexpand\to##3##4\relax +\noexpand\else +\noexpand\@dtl@lop@ff#1##1##2\noexpand\to##3##4\relax +\noexpand\fi +}} +% \end{macrocode} +%\end{macro} +% Define command to construct macro \cs{@dtl@qlopoff} to be used +% when the entry is surrounded by the current delimiter value. +% Syntax: +%\begin{definition} +% \cs{@dtl@construct@qlopoff}\meta{separator char}\meta{delimiter char} +%\end{definition} +%\begin{macro}{\@dtl@construct@qlopoff} +% \begin{macrocode} +\edef\@dtl@construct@qlopoff#1#2{% +\noexpand\long\noexpand\def\noexpand\@dtl@qlopoff#1#2##1#2#1##2\noexpand +\to##3##4{% +\noexpand\def##4{##1}\noexpand\def##3{#1##2}% +}} +% \end{macrocode} +%\end{macro} +% Define command to construct macro \cs{@dtl@lop@ff} to be used when +% the entry isn't surrouded by the delimiter. +%Syntax: +%\begin{definition} +% \cs{@dtl@construct@lop@ff}\meta{separator char} +%\end{definition} +%\begin{macro}{\@dtl@construct@lop@ff} +% \begin{macrocode} +\edef\@dtl@construct@lop@ff#1{% +\noexpand\long\noexpand\def\noexpand\@dtl@lop@ff#1##1#1##2\noexpand +\to##3##4{% +\noexpand\def##4{##1}\noexpand\def##3{#1##2}% +}} +% \end{macrocode} +%\end{macro} +% Construct all the lopoff macros. +%\begin{macro}{\@dtl@construct@lopoffs} +% \begin{macrocode} +\newcommand{\@dtl@construct@lopoffs}{% +\edef\@dtl@chars{{\@dtl@separator}{\@dtl@delimiter}}% +\expandafter\@dtl@construct@lopoff\@dtl@chars +\expandafter\@dtl@construct@qlopoff\@dtl@chars +\expandafter\@dtl@construct@lop@ff\expandafter{\@dtl@separator}% +} +% \end{macrocode} +%\end{macro} +% Define the decimal character +%\begin{macro}{\@dtl@decimal} +% \begin{macrocode} +\newcommand*{\@dtl@decimal}{.} +% \end{macrocode} +%\end{macro} +%Define the number group character +%\begin{macro}{\@dtl@numbergroupchar} +% \begin{macrocode} +\newcommand*{\@dtl@numbergroupchar}{,} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLsetnumberchars}\marg{number group char}\marg{decimal char} +%\end{definition} +% Sets the decimal character and number group +% characters. +%\begin{macro}{\DTLsetnumberchars} +% \begin{macrocode} +\newcommand*{\DTLsetnumberchars}[2]{% +\renewcommand*{\@dtl@numbergroupchar}{#1}% +\renewcommand*{\@dtl@decimal}{#2}% +\@dtl@construct@getnums +\@dtl@construct@stripnumgrpchar{#1}} +% \end{macrocode} +%\end{macro} +% +% Construct macros for extracting integer and +% fractional parts from a real number using the decimal character +% given by "#1". +% +%\begin{definition} +% \cs{DTLconverttodecimal}\marg{num}\marg{cmd} +%\end{definition} +% \cs{DTLconverttodecimal} will convert locale dependent \meta{num} +% a decimal number in a form that can be used in the +% macros defined in the \sty{fp} package. The resulting +% number is stored in \meta{cmd}. This command has to be redefined +% whenever the decimal and number group characters are changed +% as they form part of the command definitions. +% +%\begin{macro}{\@dtl@construct@getintfrac} +% \begin{macrocode} +\edef\@dtl@construct@getintfrac#1{% +\noexpand\def\noexpand\@dtl@getintfrac##1#1##2\noexpand\relax{% +\noexpand\@dtl@get@intpart{##1}% +\noexpand\def\noexpand\@dtl@fracpart{##2}% +\noexpand\ifx\noexpand\@empty\noexpand\@dtl@fracpart + \noexpand\def\noexpand\@dtl@fracpart{0}% +\noexpand\else + \noexpand\@dtl@getfracpart##2\noexpand\relax + \noexpand\@dtl@choptrailingzeroes{\noexpand\@dtl@fracpart}% +\noexpand\fi +}% +\noexpand\def\noexpand\@dtl@getfracpart##1#1\noexpand\relax{% +\noexpand\def\noexpand\@dtl@fracpart{##1}% +}% +\noexpand\def\noexpand\DTLconverttodecimal##1##2{% +\noexpand\dtl@ifsingle{##1}% +{\noexpand\expandafter\noexpand\toks@\noexpand\expandafter{##1}% +\noexpand\edef\noexpand\@dtl@tmp{\noexpand\the\noexpand\toks@}}% +{\noexpand\def\noexpand\@dtl@tmp{##1}}% + \noexpand\@dtl@standardize@currency\noexpand\@dtl@tmp + \noexpand\ifx\noexpand\@dtl@org@currency\noexpand\@empty + \noexpand\else + \noexpand\let\noexpand\@dtl@currency\noexpand\@dtl@org@currency + \noexpand\fi +\noexpand\expandafter +\noexpand\@dtl@getintfrac\noexpand\@dtl@tmp#1\noexpand\relax +\noexpand\edef##2{\noexpand\@dtl@intpart.\noexpand\@dtl@fracpart}}% +} +% \end{macrocode} +%\end{macro} +% Define command to call the above with the relevant decimal +% character: +%\begin{macro}{\@dtl@construct@getnums} +% \begin{macrocode} +\newcommand*{\@dtl@construct@getnums}{% +\expandafter\@dtl@construct@getintfrac\expandafter{\@dtl@decimal}} +% \end{macrocode} +%\end{macro} +% Get the integer (adjusting for repeating +/- signs if neccessary) +% Sets \cs{@dtl@intpart}. +%\begin{macro}{\@dtl@get@intpart} +% \begin{macrocode} +\newcommand*{\@dtl@get@intpart}[1]{% +\@dtl@tmpcount=1\relax +\def\@dtl@intpart{#1}% +\ifx\@dtl@intpart\@empty + \def\@dtl@intpart{0}% +\else + \def\@dtl@intpart{}% + \@dtl@get@int@part#1.\relax% +\fi +\ifnum\@dtl@tmpcount<0\relax + \edef\@dtl@intpart{-\@dtl@intpart}% +\fi +\@dtl@strip@numgrpchar{\@dtl@intpart}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@get@int@part} +% \begin{macrocode} +\def\@dtl@get@int@part#1#2\relax{% +\def\@dtl@argi{#1}% +\def\@dtl@argii{#2}% +\ifx\protect#1\relax% + \let\@dtl@get@nextintpart=\@dtl@get@int@part +\else + \expandafter\ifx\@dtl@argi\$% + \let\@dtl@get@nextintpart=\@dtl@get@int@part + \else + \ifx-#1% + \multiply\@dtl@tmpcount by -1\relax + \let\@dtl@get@nextintpart=\@dtl@get@int@part + \else + \if\@dtl@argi+% + \let\@dtl@get@nextintpart=\@dtl@get@int@part + \else + \def\@dtl@intpart{#1}% + \ifx.\@dtl@argii + \let\@dtl@get@nextintpart=\@gobble + \else + \let\@dtl@get@nextintpart=\@dtl@get@next@intpart + \fi + \fi + \fi + \fi +\fi +\@dtl@get@nextintpart#2\relax +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@get@next@intpart} +% \begin{macrocode} +\def\@dtl@get@next@intpart#1.\relax{% +\edef\@dtl@intpart{\@dtl@intpart#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{@dtl@choptrailingzeroes}\marg{cmd} +%\end{definition} +% Chop trailing zeroes from number given by \meta{cmd}. +%\begin{macro}{\@dtl@choptrailingzeroes} +% \begin{macrocode} +\newcommand*{\@dtl@choptrailingzeroes}[1]{% +\def\@dtl@tmpcpz{}% +\expandafter\@dtl@chop@trailingzeroes#1\@nil% +\let#1=\@dtl@tmpcpz +} +% \end{macrocode} +%\end{macro} +% +% Trailing zeroes are chopped using a recursive algorithm. +% \cs{@dtl@tmpcpz} needs to be set before using this. (The chopped +% number is put in this control sequence.) +%\begin{macro}{\@dtl@chop@trailingzeroes} +% \begin{macrocode} +\def\@dtl@chop@trailingzeroes#1#2\@nil{% +\FPifeq{#2}{0}% + \edef\@dtl@tmpcpz{\@dtl@tmpcpz#1}% + \let\@dtl@chopzeroesnext=\@dtl@chop@trailingzeroesnoop +\else + \edef\@dtl@tmpcpz{\@dtl@tmpcpz#1}% + \let\@dtl@chopzeroesnext=\@dtl@chop@trailingzeroes +\fi +\@dtl@chopzeroesnext#2\@nil +} +% \end{macrocode} +%\end{macro} +% No-op macro to end recursion +%\begin{macro}{\@dtl@chop@trailingzeroesnoop} +% \begin{macrocode} +\def\@dtl@chop@trailingzeroesnoop#1\@nil{} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@truncatedecimal}\meta{cmd} +%\end{definition} +%Truncates decimal given by \meta{cmd} to an integer (assumes in +% decimal format with full stop as decimal point) +%\begin{macro}{\dtl@truncatedecimal} +% \begin{macrocode} +\newcommand*{\dtl@truncatedecimal}[1]{% +\expandafter\@dtl@truncatedecimal#1.\@nil#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@truncatedecimal} +% \begin{macrocode} +\def\@dtl@truncatedecimal#1.#2\@nil#3{% +\def#3{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{@dtl@strip@numgrpchar}\marg{cmd} +%\end{definition} +% Strip the number group character from the number given by +% \meta{cmd}. +%\begin{macro}{\@dtl@strip@numgrpchar} +% \begin{macrocode} +\newcommand*{\@dtl@strip@numgrpchar}[1]{% +\def\@dtl@stripped{}% +\edef\@dtl@do@stripnumgrpchar{% +\noexpand\@@dtl@strip@numgrpchar#1\@dtl@numbergroupchar +\noexpand\relax}% +\@dtl@do@stripnumgrpchar +\let#1=\@dtl@stripped +} +% \end{macrocode} +%\end{macro} +% +% Define command to construct macro \cs{@@dtl@strip@numgrpchar} +%\begin{macro}{\@dtl@construct@stripnumgrpchar} +% \begin{macrocode} +\edef\@dtl@construct@stripnumgrpchar#1{% +\noexpand\def\noexpand\@@dtl@strip@numgrpchar##1#1##2\noexpand\relax{% +\noexpand\expandafter\noexpand\toks@\noexpand\expandafter +{\noexpand\@dtl@stripped}% +\noexpand\edef\noexpand\@dtl@stripped{\noexpand\the\noexpand\toks@ +##1}% +\noexpand\def\noexpand\@dtl@tmp{##2}% +\noexpand\ifx\noexpand\@dtl@tmp\noexpand\@empty + \noexpand\let\noexpand\@dtl@next=\noexpand\relax +\noexpand\else + \noexpand\let\noexpand\@dtl@next=\noexpand\@@dtl@strip@numgrpchar +\noexpand\fi +\noexpand\@dtl@next##2\noexpand\relax +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLdecimaltolocale}\marg{number}\marg{cmd} +%\end{definition} +% Define command to convert a decimal number into the locale +% dependent format. Stores result in \meta{cmd} which must be +% a control sequence. +%\begin{macro}{\DTLdecimaltolocale} +% \begin{macrocode} +\newcommand*{\DTLdecimaltolocale}[2]{% +\edef\@dtl@tmpdtl{#1}% +\expandafter\@dtl@decimaltolocale\@dtl@tmpdtl.\relax +\FPifeq{\@dtl@fracpart}{0}% + \edef#2{\@dtl@intpart}% +\else + \edef#2{\@dtl@intpart\@dtl@decimal\@dtl@fracpart}% +\fi +} +% \end{macrocode} +%\end{macro} +% Convert the integer part (store in \cs{@dtl@intpart}) +%\begin{macro}{\@dtl@decimaltolocale} +% \begin{macrocode} +\def\@dtl@decimaltolocale#1.#2\relax{% +\@dtl@decimaltolocaleint{#1}% +\def\@dtl@fracpart{#2}% +\ifx\@dtl@fracpart\@empty + \def\@dtl@fracpart{0}% +\else + \@dtl@decimaltolocalefrac#2\relax +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@decimaltolocaleint} +% \begin{macrocode} +\def\@dtl@decimaltolocaleint#1{% +\@dtl@tmpcount=0\relax +\@dtl@countdigits#1.\relax +\@dtl@numgrpsepcount=\@dtl@tmpcount\relax +\divide\@dtl@numgrpsepcount by 3\relax +\multiply\@dtl@numgrpsepcount by 3\relax +\advance\@dtl@numgrpsepcount by -\@dtl@tmpcount\relax +\ifnum\@dtl@numgrpsepcount<0\relax + \advance\@dtl@numgrpsepcount by 3\relax +\fi +\def\@dtl@intpart{}% +\@dtl@decimal@to@localeint#1.\relax +} +% \end{macrocode} +%\end{macro} +% Counts the number of digits until "#2" is a full stop. +% (increments \cs{@dtl@tmpcount}.) +%\begin{macro}{\@dtl@countdigits} +% \begin{macrocode} +\def\@dtl@countdigits#1#2\relax{% +\advance\@dtl@tmpcount by 1\relax +\ifx.#2\relax + \let\@dtl@countnext=\@gobble +\else + \let\@dtl@countnext=\@dtl@countdigits +\fi +\@dtl@countnext#2\relax +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@decimal@to@localeint} +% \begin{macrocode} +\def\@dtl@decimal@to@localeint#1#2\relax{% +\advance\@dtl@numgrpsepcount by 1\relax +\ifx.#2\relax + \edef\@dtl@intpart{\@dtl@intpart#1}% + \let\@dtl@localeintnext=\@gobble +\else + \ifnum\@dtl@numgrpsepcount=3\relax + \edef\@dtl@intpart{\@dtl@intpart#1\@dtl@numbergroupchar}% + \@dtl@numgrpsepcount=0\relax + \else + \ifnum\@dtl@numgrpsepcount>3\relax + \@dtl@numgrpsepcount=0\relax + \fi + \edef\@dtl@intpart{\@dtl@intpart#1}% + \fi + \let\@dtl@localeintnext=\@dtl@decimal@to@localeint +\fi +\@dtl@localeintnext#2\relax +} +% \end{macrocode} +%\end{macro} +% +% Convert the fractional part (store in \cs{@dtl@fracpart}) +%\begin{macro}{\@dtl@decimaltolocalefrac} +% \begin{macrocode} +% \end{macrocode} +\def\@dtl@decimaltolocalefrac#1.\relax{% +\def\@dtl@fracpart{#1}% +\@dtl@choptrailingzeroes{\@dtl@fracpart}% +} +%\end{macro} +% +%\begin{definition} +% \cs{DTLdecimaltocurrency}\marg{number}\marg{cmd} +%\end{definition} +% Define command to convert a decimal number into the locale +% dependent currency format. Stores result in \meta{cmd} which must be +% a control sequence. +%\begin{macro}{\DTLdecimaltocurrency} +% \begin{macrocode} +\newcommand*{\DTLdecimaltocurrency}[2]{% +\edef\@dtl@tmpdtl{#1}% +\expandafter\@dtl@decimaltolocale\@dtl@tmpdtl.\relax +\dtl@truncatedecimal\@dtl@tmpdtl +\@dtl@tmpcount=\@dtl@tmpdtl\relax +\expandafter\@dtl@toks\expandafter{\@dtl@currency}% +\FPifeq{\@dtl@fracpart}{0}% + \ifnum\@dtl@tmpcount<0\relax + \@dtl@tmpcount = -\@dtl@tmpcount\relax + \edef#2{-\the\@dtl@toks\the\@dtl@tmpcount\@dtl@decimal00}% + \else + \edef#2{\the\@dtl@toks\@dtl@intpart\@dtl@decimal00}% + \fi +\else + \ifnum\@dtl@tmpcount<0\relax + \@dtl@tmpcount = -\@dtl@tmpcount\relax + \ifnum\@dtl@fracpart<10\relax + \edef#2{-\the\@dtl@toks\number\@dtl@tmpcount + \@dtl@decimal\@dtl@fracpart0}% + \else + \edef#2{-\the\@dtl@toks\number\@dtl@tmpcount + \@dtl@decimal\@dtl@fracpart}% + \fi + \else + \ifnum\@dtl@fracpart<10\relax + \edef#2{\the\@dtl@toks\@dtl@intpart\@dtl@decimal\@dtl@fracpart0}% + \else + \edef#2{\the\@dtl@toks\@dtl@intpart\@dtl@decimal\@dtl@fracpart}% + \fi + \fi +\fi +} +% \end{macrocode} +%\end{macro} +% +% Set the defaults: +% \begin{macrocode} +\@dtl@construct@lopoffs +\@dtl@construct@getnums +\expandafter\@dtl@construct@stripnumgrpchar\expandafter +{\@dtl@numbergroupchar} +% \end{macrocode} +% Define key for package option \pkgopt{separator}. +% \begin{macrocode} +\define@key{datatool.sty}{separator}{% +\DTLsetseparator{#1}} +% \end{macrocode} +% Define key for package option \pkgopt{delimiter}. +% \begin{macrocode} +\define@key{datatool.sty}{delimiter}{% +\DTLsetdelimiter{#1}} +% \end{macrocode} +% Define key for package option \pkgopt{verbose}. (This also +% switches the \sty{fp} messages on/off) +% \begin{macrocode} +\define@boolkey{datatool.sty}[dtl]{verbose}[true]{% +\ifdtlverbose \FPmessagestrue\else \FPmessagesfalse\fi} +% \end{macrocode} +% Display message only if verbose option set: +% \begin{macrocode} +\newcommand*{\dtl@message}[1]{% +\ifdtlverbose \typeout{#1}\fi} +% \end{macrocode} +% Process package options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +% Requires \texttt{compare.tex}, unless \cs{compare} has already +% been defined. If paragraph breaks are allowed, these commands +% need to be defined to be long. +% \begin{macrocode} +\@ifundefined{compare}{\input{compare}}{} +% \end{macrocode} +% +% Many of the commands used by this package are short commands +% (such as \cs{compare}.) This means that you can't use \cs{par} +% in the data. To get around this, define the robust command +% \cs{DTLpar} to use instead. +%\begin{macro}{\DTLpar} +% \begin{macrocode} +\DeclareRobustCommand\DTLpar{\@par} +% \end{macrocode} +%\end{macro} +% +% \subsection{Determining Data Types} +% The control sequence \cs{@dtl@checknumerical} checks the data +% type of its argument, and sets \cs{@dtl@datatype} to 0 if +% the argument is a string, 1 if the argument is an integer +% or 2 if the argument is a real number. First define +% \cs{@dtl@datatype}: +%\begin{macro}{\@dtl@datatype} +% \begin{macrocode} +\newcount\@dtl@datatype +% \end{macrocode} +%\end{macro} +% Define temporary count register +%\begin{macro}{\@dtl@tmpcount} +% \begin{macrocode} +\newcount\@dtl@tmpcount +% \end{macrocode} +%\end{macro} +% Define count register to count the digits between the number +% group separator. +%\begin{macro}{\@dtl@numgrpsepcount} +% \begin{macrocode} +\newcount\@dtl@numgrpsepcount +% \end{macrocode} +%\end{macro} +% +% Define a macro that checks if the argument is numerical +% (includes decimal numbers, but not scientific notation.) +% Sets \cs{@dtl@datatype}, as described above. +%\begin{macro}{\@dtl@checknumerical} +% \begin{macrocode} +\newcommand{\@dtl@checknumerical}[1]{% +\@dtl@numgrpsepfalse +\def\@dtl@tmp{#1}% +\ifx\@empty#1\@empty + \@dtl@datatype=0\relax +\else + \dtl@ifsingle{#1}% + {\expandafter\toks@\expandafter{#1}% + \edef\@dtl@tmp{\the\toks@}}% + {\def\@dtl@tmp{#1}}% + \@dtl@tmpcount=0\relax + \@dtl@datatype=0\relax + \@dtl@numgrpsepcount=2\relax + \@dtl@standardize@currency\@dtl@tmp + \ifx\@dtl@org@currency\@empty + \else + \let\@dtl@currency\@dtl@org@currency + \fi + \expandafter\@dtl@checknumericalstart\@dtl@tmp\@nil\@nil +\fi +\ifnum\@dtl@numgrpsepcount>-1\relax + \if@dtl@numgrpsep + \ifnum\@dtl@numgrpsepcount=3\relax + \else + \@dtl@datatype=0\relax + \fi + \fi +\fi +} +% \end{macrocode} +%\end{macro} +% Check first character for checknumerical process to see if +% it's a plus or minus sign. +%\begin{macro}{\@dtl@checknumericalstart} +% \begin{macrocode} +\def\@dtl@checknumericalstart#1#2\@nil\@nil{% +\ifx#1\protect + \@dtl@checknumericalstart#2\@nil\@nil\relax +\else + \if-#1\relax + \def\@dtl@tmp{#2}% + \ifx\@empty\@dtl@tmp + \@dtl@datatype=0\relax + \else + \ifnum\@dtl@datatype=0\relax + \@dtl@datatype=1\relax + \fi + \@dtl@checknumericalstart#2\@nil\@nil\relax + \fi + \else + \if+#1\relax + \def\@dtl@tmp{#2}% + \ifx\@empty\@dtl@tmp + \@dtl@datatype=0\relax + \else + \ifnum\@dtl@datatype=0\relax + \@dtl@datatype=1\relax + \fi + \@dtl@checknumericalstart#2\@nil\@nil\relax + \fi + \else + \def\@dtl@tmp{#1}% + \ifx#1\$\relax + \@dtl@datatype=3\relax + \@dtl@checknumericalstart#2\@nil\@nil\relax + \else + \ifx\@empty\@dtl@tmp + \@dtl@datatype=0\relax + \else + \ifnum\@dtl@datatype=0\relax + \@dtl@datatype=1\relax + \fi + \@dtl@checknumericalloop#1#2\@nil\@nil\relax + \fi + \fi + \fi + \fi +\fi +} +% \end{macrocode} +%\end{macro} +% The conditional \cs{if@dtl@numgrpsep} is set the first time +% \cs{@dtl@checknumericalloop} encounters the number group +% separator. +%\begin{macro}{\if@dtl@numgrpsep} +% \begin{macrocode} +\newif\if@dtl@numgrpsep +% \end{macrocode} +%\end{macro} +% Check numerical loop. This iterates through each character +% until \cs{@nil} is reached, or invalid character found. +% Increments \cs{@dtl@tmpcount} each time it encounters a +% decimal character. +%\begin{macro}{\@dtl@checknumericalloop} +% \begin{macrocode} +\def\@dtl@checknumericalloop#1#2\@nil{% +\def\@dtl@tmp{#1}% +\ifx\@nnil\@dtl@tmp\relax + \let\@dtl@chcknumnext=\@dtl@checknumericalnoop% +\else + \ifthenelse{\equal{#1}{0}\or + \equal{#1}{1}\or + \equal{#1}{2}\or + \equal{#1}{3}\or + \equal{#1}{4}\or + \equal{#1}{5}\or + \equal{#1}{6}\or + \equal{#1}{7}\or + \equal{#1}{8}\or + \equal{#1}{9}\or + \equal{#1}{\@dtl@decimal}}{% + \let\@dtl@chcknumnext=\@dtl@checknumericalloop% + \ifthenelse{\equal{#1}{\@dtl@decimal}}{% + \if@dtl@numgrpsep + \ifnum\@dtl@numgrpsepcount=3\relax + \@dtl@numgrpsepcount=-1\relax + \else + \@dtl@datatype=0\relax + \let\@dtl@chcknumnext=\@dtl@checknumericalnoop + \fi + \else + \@dtl@numgrpsepcount=-1\relax + \fi + }{% + \ifnum\@dtl@numgrpsepcount=-1\relax + \else + \advance\@dtl@numgrpsepcount by 1\relax + \fi}% +}{\ifthenelse{\equal{#1}{\@dtl@numbergroupchar}}{% + \@dtl@numgrpseptrue + \ifnum\@dtl@numgrpsepcount<3\relax + \@dtl@datatype=0\relax + \let\@dtl@chcknumnext=\@dtl@checknumericalnoop + \else + \@dtl@numgrpsepcount=0\relax + \fi}{% + \@dtl@datatype=0\relax + \let\@dtl@chcknumnext=\@dtl@checknumericalnoop +}}% + \ifx\@dtl@decimal\@dtl@tmp\relax + \ifnum\@dtl@datatype<3\relax + \@dtl@datatype=2\relax + \fi + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount>1\relax + \@dtl@datatype=0\relax + \let\@dtl@chcknumnext=\@dtl@checknumericalnoop% + \fi + \fi +\fi +\@dtl@chcknumnext#2\@nil +} +% \end{macrocode} +%\end{macro} +% End loop +%\begin{macro}{\@dtl@checknumericalnoop} +% \begin{macrocode} +\def\@dtl@checknumericalnoop#1\@nil#2{} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifnumerical} which tests the first argument, if +% its numerical do second argument, otherwise do third argument. +%\begin{macro}{\DTLifnumerical} +% \begin{macrocode} +\newcommand{\DTLifnumerical}[3]{% +\@dtl@checknumerical{#1}% +\ifnum\@dtl@datatype=0\relax#3\else#2\fi +} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifreal} which tests the first argument, if +% it's a real number (not an integer) do second argument, +% otherwise do third argument. +%\begin{macro}{\DTLifreal} +% \begin{macrocode} +\newcommand{\DTLifreal}[3]{% +\@dtl@checknumerical{#1}% +\ifnum\@dtl@datatype=2\relax #2\else #3\fi +} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifint} which tests the first argument, if +% it's an integer do second argument, +% otherwise do third argument. +%\begin{macro}{\DTLifint} +% \begin{macrocode} +\newcommand{\DTLifint}[3]{% +\@dtl@checknumerical{#1}% +\ifnum\@dtl@datatype=1\relax #2\else #3\fi +} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifstring} which tests the first argument, if +% it's a string do second argument, +% otherwise do third argument. +%\begin{macro}{\DTLifstring} +% \begin{macrocode} +\newcommand{\DTLifstring}[3]{% +\@dtl@checknumerical{#1}% +\ifnum\@dtl@datatype=0\relax #2\else #3\fi +} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifcurrency} which tests the first argument, if +% it starts with the currency symbol do second argument, +% otherwise do third argument. +%\begin{macro}{\DTLifcurrency} +% \begin{macrocode} +\newcommand{\DTLifcurrency}[3]{% +\@dtl@checknumerical{#1}% +\ifnum\@dtl@datatype=3\relax #2\else #3\fi +} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifcurrencyunit} which tests if the first argument +% is currency, and uses the currency unit given by the +% second argument. If true do third argument, otherwise +% do fourth argument. +%\begin{macro}{\DTLifcurrencyunit} +% \begin{macrocode} +\newcommand*{\DTLifcurrencyunit}[4]{% +\@dtl@checknumerical{#1}% +\ifnum\@dtl@datatype=3\relax + \ifthenelse{\equal{\@dtl@org@currency}{#2}}{#3}{#4}% +\else + #4% +\fi +} +% \end{macrocode} +%\end{macro} +% +% Define \cs{DTLifcasedatatype} which tests the first argument. +% If it is a string, do second argument, if it is an integer +% do third argument, if it is a real number, do fourth argument, +% if it is currency, do fifth argument. +%\begin{macro}{\DTLifcasedatatype} +% \begin{macrocode} +\newcommand{\DTLifcasedatatype}[5]{% +\@dtl@checknumerical{#1}% +\ifcase\@dtl@datatype + #2% string +\or + #3% integer +\or + #4% number +\or + #5% currency +\fi +} +% \end{macrocode} +%\end{macro} +% +% Test if both arguments are numerical. This sets +% the conditional \cs{if@dtl@condition} +%\begin{macro}{\dtl@testbothnumerical} +% \begin{macrocode} +\newcommand*{\dtl@testbothnumerical}[2]{% +\dtl@ifsingle{#1}{% + \edef\@dtl@tmp{#1}}{% + \def\@dtl@tmp{#1}}% +\expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% +\edef\@dtl@firsttype{\number\@dtl@datatype}% +\dtl@ifsingle{#2}{% + \edef\@dtl@tmp{#2}}{% + \def\@dtl@tmp{#2}}% +\expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% +\multiply\@dtl@datatype by \@dtl@firsttype\relax +\ifnum\@dtl@datatype>0\relax + \@dtl@conditiontrue +\else + \@dtl@conditionfalse +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \marg{num1} < \marg{num2}. Both numbers +% need to have the decimal separator changed to a dot +% to ensure that it works with \cs{FPiflt} +%\begin{macro}{\DTLifnumlt} +% \begin{macrocode} +\newcommand*{\DTLifnumlt}[4]{% + \DTLconverttodecimal{#1}{\@dtl@numi}% + \DTLconverttodecimal{#2}{\@dtl@numii}% + \FPiflt{\@dtl@numi}{\@dtl@numii}% + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifstringlt}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +%\end{definition} +% String comparison +%\begin{macro}{\DTLifstringlt} +% \begin{macrocode} +\newcommand*{\DTLifstringlt}[4]{% +\protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#2}}% + \expandafter\ifnum\@dtl@tmpcmp<0\relax + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLiflt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +%\end{definition} +% Do \cs{DTLifnumlt} if both \meta{arg1} and \meta{arg2} are +% numerical, otherwise do \cs{DTifstringlt}. +%\begin{macro}{\DTLiflt} +% \begin{macrocode} +\newcommand*{\DTLiflt}[4]{% +\dtl@testbothnumerical{#1}{#2}% +\if@dtl@condition + \DTLifnumlt{#1}{#2}{#3}{#4}% +\else + \DTLifstringlt{#1}{#2}{#3}{#4}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifnumgt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \marg{num1} > \marg{num2}. Both numbers +% need to have the decimal separator changed to a dot +% to ensure that it works with \cs{FPifgt} +%\begin{macro}{\DTLifnumgt} +% \begin{macrocode} +\newcommand*{\DTLifnumgt}[4]{% + \DTLconverttodecimal{#1}{\@dtl@numi}% + \DTLconverttodecimal{#2}{\@dtl@numii}% + \FPifgt{\@dtl@numi}{\@dtl@numii}% + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifstringgt}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +%\end{definition} +% String comparison +%\begin{macro}{\DTLifstringgt} +% \begin{macrocode} +\newcommand*{\DTLifstringgt}[4]{% +\protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#2}}% + \expandafter\ifnum\@dtl@tmpcmp>0\relax + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifgt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +%\end{definition} +% Do \cs{DTLifnumgt} if both \meta{arg1} and \meta{arg2} are +% numerical, otherwise do \cs{DTifstringgt}. +%\begin{macro}{\DTLifgt} +% \begin{macrocode} +\newcommand*{\DTLifgt}[4]{% +\dtl@testbothnumerical{#1}{#2}% +\if@dtl@condition + \DTLifnumgt{#1}{#2}{#3}{#4}% +\else + \DTLifstringgt{#1}{#2}{#3}{#4}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \marg{num1} = \marg{num2}. Both numbers +% need to have the decimal separator changed to a dot +% to ensure that it works with \cs{FPifeq} +%\begin{macro}{\DTLifnumeq} +% \begin{macrocode} +\newcommand*{\DTLifnumeq}[4]{% + \DTLconverttodecimal{#1}{\@dtl@numi}% + \DTLconverttodecimal{#2}{\@dtl@numii}% + \FPifeq{\@dtl@numi}{\@dtl@numii}% + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifstringeq}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +%\end{definition} +% String comparison +%\begin{macro}{\DTLifstringeq} +% \begin{macrocode} +\newcommand*{\DTLifstringeq}[4]{% +\protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#2}}% + \expandafter\ifnum\@dtl@tmpcmp=0\relax + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifeq}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +%\end{definition} +% Do \cs{DTLifnumeq} if both \meta{arg1} and \meta{arg2} are +% numerical, otherwise do \cs{DTifstringeq}. +%\begin{macro}{\DTLifeq} +% \begin{macrocode} +\newcommand*{\DTLifeq}[4]{% +\dtl@testbothnumerical{#1}{#2}% +\if@dtl@condition + \DTLifnumeq{#1}{#2}{#3}{#4}% +\else + \DTLifstringeq{#1}{#2}{#3}{#4}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifnumclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \meta{min} $\leq$ \meta{num} $\leq$ \meta{max}. +%\begin{macro}{\DTLifnumclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLifnumclosedbetween}[5]{% +\DTLconverttodecimal{#1}{\@dtl@numi}% +\DTLconverttodecimal{#2}{\@dtl@numii}% +\DTLconverttodecimal{#3}{\@dtl@numiii}% +\DTLifFPclosedbetween{\@dtl@numi}{\@dtl@numii}{\@dtl@numiii}{#4}{#5}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% String comparison +%\begin{macro}{\DTLifstringclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLifstringclosedbetween}[5]{% +\protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#2}}% +\let\@dtl@dovalue\relax +\expandafter\ifnum\@dtl@tmpcmp<0\relax + \def\@dtl@dovalue{#5}% +\fi +\ifx\@dtl@dovalue\relax + \protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#3}}% + \expandafter\ifnum\@dtl@tmpcmp>0\relax + \def\@dtl@dovalue{#5}% + \else + \def\@dtl@dovalue{#4}% + \fi +\fi +\@dtl@dovalue +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% Do \cs{DTLifnumclosedbetween} if \marg{arg}, \meta{min} and \meta{max} are +% numerical, otherwise do \cs{DTifstringclosedbetween}. +%\begin{macro}{\DTLifclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLifclosedbetween}[5]{% +\dtl@testbothnumerical{#2}{#3}% +\if@dtl@condition + \dtl@ifsingle{#1}{% + \edef\@dtl@tmp{#1}}{% + \def\@dtl@tmp{#1}}% + \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% + \ifnum\@dtl@datatype>0\relax + \DTLifnumclosedbetween{#1}{#2}{#3}{#4}{#5}% + \else + \DTLifstringclosedbetween{#1}{#2}{#3}{#4}{#5}% + \fi +\else + \DTLifstringclosedbetween{#1}{#2}{#3}{#4}{#5}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifnumopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \meta{min} $<$ \meta{num} $<$ \meta{max}. +%\begin{macro}{\DTLifnumopenbetween} +% \begin{macrocode} +\newcommand*{\DTLifnumopenbetween}[5]{% +\DTLconverttodecimal{#1}{\@dtl@numi}% +\DTLconverttodecimal{#2}{\@dtl@numii}% +\DTLconverttodecimal{#3}{\@dtl@numiii}% +\DTLifFPopenbetween{\@dtl@numi}{\@dtl@numii}{\@dtl@numiii}{#4}{#5}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifstringopenbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% String comparison +%\begin{macro}{\DTLifstringopenbetween} +% \begin{macrocode} +\newcommand*{\DTLifstringopenbetween}[5]{% +\protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#2}}% +\let\@dtl@dovalue\relax +\expandafter\ifnum\@dtl@tmpcmp>0\relax +\else + \def\@dtl@dovalue{#5}% +\fi +\ifx\@dtl@dovalue\relax + \protected@edef\@dtl@tmpcmp{\noexpand\compare{#1}{#3}}% + \expandafter\ifnum\@dtl@tmpcmp<0\relax + \def\@dtl@dovalue{#4}% + \else + \def\@dtl@dovalue{#5}% + \fi +\fi +\@dtl@dovalue +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifopenbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% Do \cs{DTLifnumopenbetween} if \marg{arg}, \meta{min} and \meta{max} are +% numerical, otherwise do \cs{DTifstringopenbetween}. +%\begin{macro}{\DTLifopenbetween} +% \begin{macrocode} +\newcommand*{\DTLifopenbetween}[5]{% +\dtl@testbothnumerical{#2}{#3}% +\if@dtl@condition + \dtl@ifsingle{#1}{% + \edef\@dtl@tmp{#1}}{% + \def\@dtl@tmp{#1}}% + \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% + \ifnum\@dtl@datatype>0\relax + \DTLifnumopenbetween{#1}{#2}{#3}{#4}{#5}% + \else + \DTLifstringopenbetween{#1}{#2}{#3}{#4}{#5}% + \fi +\else + \DTLifstringopenbetween{#1}{#2}{#3}{#4}{#5}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifFPopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \meta{min} $<$ \meta{num} $<$ \meta{max} where +% all arguments are in standard fixed point notation. +%\begin{macro}{\DTLifFPopenbetween} +% \begin{macrocode} +\newcommand*{\DTLifFPopenbetween}[5]{% + \let\@dtl@dovalue\relax + \FPifgt{#1}{#2}% + \else + \def\@dtl@dovalue{#5}% + \fi + \FPiflt{#1}{#3}% + \ifx\@dtl@dovalue\relax + \def\@dtl@dovalue{#4}% + \fi + \else + \def\@dtl@dovalue{#5}% + \fi +\@dtl@dovalue +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifFPclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} +%\end{definition} +% Determine if \meta{min} $\leq$ \meta{num} $\leq$ \meta{max}. +%\begin{macro}{\DTLifFPclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLifFPclosedbetween}[5]{% + \let\@dtl@dovalue\relax + \FPifgt{#1}{#3}% + \def\@dtl@dovalue{#5}% + \fi + \FPiflt{#1}{#2}% + \ifx\@dtl@dovalue\relax + \def\@dtl@dovalue{#5}% + \fi + \else + \def\@dtl@dovalue{#4}% + \fi +\@dtl@dovalue +} +% \end{macrocode} +%\end{macro} +% +% The following conditionals are only meant to be used within +% \cs{DTLforeach} as they depend on the counter +% \texttt{DTLrow}\meta{n}. +% +%\begin{definition} +%\cs{DTLiffirstrow}\marg{true part}\marg{false part} +%\end{definition} +%\begin{macro}{\DTLiffirstrow} +% \begin{macrocode} +\newcommand{\DTLiffirstrow}[2]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLiffirstrow\space can only + be used inside \string\DTLforeach}{}% +\else +\expandafter\ifnum\csname c@DTLrow\romannumeral +\dtlforeachlevel\endcsname +=1\relax#1\else#2\fi +\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLiflastrow}\marg{true part}\marg{false part} +%\end{definition} +%\begin{macro}{\DTLiflastrow} +% \begin{macrocode} +\newcommand{\DTLiflastrow}[2]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLiflastrow\space can only + be used inside \string\DTLforeach}{}% +\else +\expandafter\ifnum\csname c@DTLrow\romannumeral +\dtlforeachlevel\endcsname= +\value{DTLrow\romannumeral\dtlforeachlevel}% +#1\else #2\fi +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLifoddrow}\marg{true part}\marg{false part} +%\end{definition} +%\begin{macro}{\DTLifoddrow} +% \begin{macrocode} +\newcommand{\DTLifoddrow}[2]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLifoddrow\space can only + be used inside \string\DTLforeach}{}% +\else +\expandafter\ifodd\csname c@DTLrow\romannumeral +\dtlforeachlevel\endcsname +#1\else #2\fi +\fi +} +% \end{macrocode} +%\end{macro} +% +% \subsection{ifthen Conditionals} +% The following commands provide conditionals \cs{DTLis}\ldots\ +% that can be used in \cs{ifthenelse}. First need to define +% a new conditional: +%\begin{macro}{\if@dtl@condition} +% \begin{macrocode} +\newif\if@dtl@condition +% \end{macrocode} +%\end{macro} +% +% Command to test if first argument is less than second argument. +% If either argument is a string, a string comparison is used +% instead. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testlt} +% \begin{macrocode} +\newcommand*{\dtl@testlt}[2]{% +\DTLiflt{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLislt} +% \begin{macrocode} +\newcommand*{\DTLislt}[2]{% +\TE@throw\noexpand\dtl@testlt{#1}{#2}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number is greater than second number. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testgt} +% \begin{macrocode} +\newcommand*{\dtl@testgt}[2]{% +\DTLifgt{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisgt} +% \begin{macrocode} +\newcommand*{\DTLisgt}[2]{% +\TE@throw\noexpand\dtl@testgt{#1}{#2}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number is equal to the second number. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testeq} +% \begin{macrocode} +\newcommand*{\dtl@testeq}[2]{% +\DTLifeq{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLiseq} +% \begin{macrocode} +\newcommand*{\DTLiseq}[2]{% +\TE@throw\noexpand\dtl@testeq{#1}{#2}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number lies between second and third +% numbers. (End points included.) This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testclosedbetween} +% \begin{macrocode} +\newcommand*{\dtl@testclosedbetween}[3]{% +\DTLifclosedbetween{#1}{#2}{#3}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLisclosedbetween}[3]{% +\TE@throw\noexpand\dtl@testclosedbetween{#1}{#2}{#3}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number lies between second and third +% numbers. (End points excluded.) This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testopenbetween} +% \begin{macrocode} +\newcommand*{\dtl@testopenbetween}[3]{% +\DTLifopenbetween{#1}{#2}{#3}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisopenbetween} +% \begin{macrocode} +\newcommand*{\DTLisopenbetween}[3]{% +\TE@throw\noexpand\dtl@testopenbetween{#1}{#2}{#3}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number lies between second and third +% numbers. (End points included, all arguments are fixed point +% numbers in standard format.) This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testclosedbetween} +% \begin{macrocode} +\newcommand*{\dtl@testFPclosedbetween}[3]{% +\DTLifFPclosedbetween{#1}{#2}{#3}% +{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLisFPclosedbetween}[3]{% +\TE@throw\noexpand\dtl@testFPclosedbetween{#1}{#2}{#3}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number lies between second and third +% numbers. (End points excluded, all arguments are fixed point +% numbers in standard format.) This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testopenbetween} +% \begin{macrocode} +\newcommand*{\dtl@testFPopenbetween}[3]{% +\DTLifFPopenbetween{#1}{#2}{#3}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPopenbetween} +% \begin{macrocode} +\newcommand*{\DTLisFPopenbetween}[3]{% +\TE@throw\noexpand\dtl@testFPopenbetween{#1}{#2}{#3}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number is less than second +% number where both numbers are in standard format. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testFPislt} +% \begin{macrocode} +\newcommand*{\dtl@testFPislt}[2]{% +\FPiflt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPlt} +% \begin{macrocode} +\newcommand*{\DTLisFPlt}[2]{% +\TE@throw\noexpand\dtl@testFPislt{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number is greater than second +% number where both numbers are in standard format. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testFPisgt} +% \begin{macrocode} +\newcommand*{\dtl@testFPisgt}[2]{% +\FPifgt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPgt} +% \begin{macrocode} +\newcommand*{\DTLisFPgt}[2]{% +\TE@throw\noexpand\dtl@testFPisgt{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if two numbers are equal, where both numbers +% are in standard decimal format +%\begin{macro}{\dtl@testFPiseq} +% \begin{macrocode} +\newcommand*{\dtl@testFPiseq}[2]{% +\FPifeq{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPeq} +% \begin{macrocode} +\newcommand*{\DTLisFPeq}[2]{% +\TE@throw\noexpand\dtl@testFPiseq{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number is less than or equal to second +% number where both numbers are in standard format. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testFPislteq} +% \begin{macrocode} +\newcommand*{\dtl@testFPislteq}[2]{% +\FPiflt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi +\if@dtl@condition +\else + \dtl@testFPiseq{#1}{#2}% +\fi +} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPlteq} +% \begin{macrocode} +\newcommand*{\DTLisFPlteq}[2]{% +\TE@throw\noexpand\dtl@testFPislteq{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if first number is greater than or equal to second +% number where both numbers are in standard format. +% This sets \cs{if@dtl@condition}. +%\begin{macro}{\dtl@testFPisgteq} +% \begin{macrocode} +\newcommand*{\dtl@testFPisgteq}[2]{% +\FPifgt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi +\if@dtl@condition +\else + \dtl@testFPiseq{#1}{#2}% +\fi +} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisFPgteq} +% \begin{macrocode} +\newcommand*{\DTLisFPgteq}[2]{% +\TE@throw\noexpand\dtl@testFPisgteq{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% +% Command to test if argument is a string. This sets +% \cs{if@dtl@condition} +%\begin{macro}{\dtl@teststring} +% \begin{macrocode} +\newcommand*{\dtl@teststring}[1]{% +\DTLifstring{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisstring} +% \begin{macrocode} +\newcommand*{\DTLisstring}[1]{% +\TE@throw\noexpand\dtl@teststring{#1}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if argument is a numerical. This sets +% \cs{if@dtl@condition} +%\begin{macro}{\dtl@testnumerical} +% \begin{macrocode} +\newcommand*{\dtl@testnumerical}[1]{% +\DTLifnumerical{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisnumerical} +% \begin{macrocode} +\newcommand*{\DTLisnumerical}[1]{% +\TE@throw\noexpand\dtl@testnumerical{#1}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if argument is an integer. This sets +% \cs{if@dtl@condition} +%\begin{macro}{\dtl@testint} +% \begin{macrocode} +\newcommand*{\dtl@testint}[1]{% +\DTLifint{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisint} +% \begin{macrocode} +\newcommand*{\DTLisint}[1]{% +\TE@throw\noexpand\dtl@testint{#1}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if argument is a real. This sets +% \cs{if@dtl@condition} +%\begin{macro}{\dtl@testreal} +% \begin{macrocode} +\newcommand*{\dtl@testreal}[1]{% +\DTLifreal{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisreal} +% \begin{macrocode} +\newcommand*{\DTLisreal}[1]{% +\TE@throw\noexpand\dtl@testreal{#1}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if argument is a currency. This sets +% \cs{if@dtl@condition} +%\begin{macro}{\dtl@testcurrency} +% \begin{macrocode} +\newcommand*{\dtl@testcurrency}[1]{% +\DTLifcurrency{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLiscurrency} +% \begin{macrocode} +\newcommand*{\DTLiscurrency}[1]{% +\TE@throw\noexpand\dtl@testcurrency{#1}\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% Command to test if argument is a currency with given unit. This sets +% \cs{if@dtl@condition} +%\begin{macro}{\dtl@testcurrencyunit} +% \begin{macrocode} +\newcommand*{\dtl@testcurrencyunit}[2]{% +\DTLifcurrencyunit{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLiscurrencyunit} +% \begin{macrocode} +\newcommand*{\DTLiscurrencyunit}[2]{% +\TE@throw\noexpand\dtl@testcurrencyunit{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +% +% \subsection{Defining New Databases} +% A database is stored internally as a list of lists, where each list +% is a row of data. The data is stored as a comma separated list of +% \marg{id}\marg{value} pairs, where \meta{id} is an +% identifier +% and \meta{value} is the value. \cs{DTLnewdb}\marg{name} +% initialises a database called \meta{name}. The keys associated +% with this database are stored in \cs{dtlkeys@}\meta{name} +% A new count register \cs{dtlrows@}\meta{db name} is created. +% This stores the total number of rows in the data base. +%\begin{macro}{\DTLnewdb} +% \begin{macrocode} +\newcommand*{\DTLnewdb}[1]{% +\DTLifdbexists{#1}{% +\PackageError{datatool}{Database `#1' already exists}{}}{% +\dtl@message{Creating database `#1'}% +\expandafter\gdef\csname dtldb@#1\endcsname{}% +\expandafter\gdef\csname dtlkeys@#1\endcsname{}% +\expandafter\global\expandafter\newcount\csname dtlrows@#1\endcsname}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLrowcount}\marg{db name} +%\end{definition} +% Number of rows in \meta{db name} +%\begin{macro}{\DTLrowcount} +% \begin{macrocode} +\newcommand*{\DTLrowcount}[1]{% +\expandafter\number\csname dtlrows@#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLifempty}\marg{name}\marg{true part}\marg{false part} +%\end{definition} +% Check if named database is empty (i.e.\ no rows have been added.) +%\begin{macro}{\DTLifdbempty} +% \begin{macrocode} +\newcommand{\DTLifdbempty}[3]{% +\DTLifdbexists{#1}{% +\expandafter\ifx\csname dtldb@#1\endcsname\@empty + #2% +\else + #3% +\fi}{% +\PackageError{Database `#1' doesn't exist}{}{}}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLnewrow}\marg{db name} +%\end{definition} +% Add a new row to named database. +%\begin{macro}{\DTLnewrow} +% \begin{macrocode} +\newcommand*{\DTLnewrow}[1]{% +\DTLifdbempty{#1}{% + \expandafter\gdef\csname dtldb@#1\endcsname{{}}% + \expandafter\global\expandafter\advance + \csname dtlrows@#1\endcsname by 1\relax + \dtl@message{New row added to database `#1'}% +}{% + \expandafter\let\expandafter\@dtl@olddb\csname dtldb@#1\endcsname% + \expandafter\toks@\expandafter{\@dtl@olddb,{}}% + \expandafter\xdef\csname dtldb@#1\endcsname{\the\toks@}% + \expandafter\global\expandafter\advance + \csname dtlrows@#1\endcsname by 1\relax + \dtl@message{New row added to database `#1'}% +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLnewdbentry}\marg{db name}\marg{id}\marg{value}. +%\end{definition} +% Add an entry to the last row (adds new row if database is empty.) +% +% When a new entry is added, the control sequence +% \cs{@dtl@idtype@}\meta{db name}\texttt{@}\meta{id} is checked. +% This keeps track of the type of all the entries with the given ID +% for the given database. If this control +% sequence doesn't exist, a new one is created, and set to the +% relevant type: 0 (string), 1 (int) or 2 (real). If it exists, +% then it is set as follows: if has a value of 0 (string), it +% remains unchanged. If it has another value, then it is set to +% 2 (real) if it was either 1 or 2 and \meta{value} is 2, it is +% set to 1 if \meta{value} is 1, otherwise it remains unchanged. +%\begin{macro}{\DTLnewdbentry} +% \begin{macrocode} +\newcommand{\DTLnewdbentry}[3]{% +% \end{macrocode} +% Set \cs{@dtl@dbvalue} to the value of this entry +% \begin{macrocode} +\expandafter\@dtl@toks\expandafter{#3}% +\edef\@dtl@dbvalue{\the\@dtl@toks}% +% \end{macrocode} +% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow +% for the ID to be stored in a control sequence. +% \begin{macrocode} +\edef\@dtl@dbid{#2}% +% \end{macrocode} +% Set up the correct entry format: +% \begin{macrocode} +\long\edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% +% \end{macrocode} +% If database is empty, add new row. +% \begin{macrocode} +\DTLifdbempty{#1}{\DTLnewrow{#1}}{}% +% \end{macrocode} +% Add the entry to the last row of the database: +% Split the database into the last row +% (\cs{@dtl@dblastrow}), and everything except the last row +% (\cs{@dtl@dbrest}.) +% \begin{macrocode} +\expandafter\dtl@choplast\expandafter{% +\csname dtldb@#1\endcsname}{\@dtl@dbrest}{\@dtl@dblastrow}% +% \end{macrocode} +% Check if the last row already contains an entry with this ID. +% If so, generate an error, otherwise append this entry to the +% row, and reconstruct database list. +% \begin{macrocode} +\dtl@ifrowcontains{#2}{\@dtl@dblastrow}{% +\PackageError{datatool}{Can't add entry with ID `#2' to current +row of database `#1'}{There is already an entry with this ID on +the current row}}{% +% \end{macrocode} +% Append entry to last row +% \begin{macrocode} +\expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% +\ifthenelse{\equal{}{\@dtl@dblastrow}}{% + \edef\@dtl@dblastrow{\the\@dtl@toks}% +}{% + \expandafter\toks@\expandafter{\@dtl@dblastrow}% + \edef\@dtl@dblastrow{\the\toks@,\the\@dtl@toks}% +}% +% \end{macrocode} +% Reconstruct list. +% \begin{macrocode} +\expandafter\@dtl@toks\expandafter{\@dtl@dblastrow}% +\ifthenelse{\equal{}{\@dtl@dbrest}}{% + \expandafter\long\expandafter\xdef\csname dtldb@#1\endcsname{% + {\the\@dtl@toks}}% +}{% + \expandafter\toks@\expandafter{\@dtl@dbrest}% + \expandafter\long\expandafter\xdef\csname dtldb@#1\endcsname{% + \the\toks@,{\the\@dtl@toks}}% +}% +% \end{macrocode} +% Set the keys +% \begin{macrocode} +\@dtl@setidtype{#1}{#2}{#3}% +\expandafter\@dtl@setkeys\expandafter{#2}{#1}% +}% +\dtl@message{Added #2\space -> #3\space to database `#1'}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{@dtl@setidtype}\marg{db name}\marg{id}\marg{value} +%\end{definition} +% Set the type for \meta{id} according to \meta{value}. +% If \meta{value} is empty, leave \cs{@dtl@idtype}\meta{id} +% unchanged (if defined) or define as empty if not defined. +%\begin{macro}{\@dtl@setidtype} +% \begin{macrocode} +\newcommand{\@dtl@setidtype}[3]{% +\@dtl@checknumerical{#3}% +\def\@dtl@value{#3}% +\@ifundefined{@dtl@idtype@#1@#2}{% +\ifx\@dtl@value\@empty + \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{}% +\else + \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% + \the\@dtl@datatype}% +\fi +}{% +\ifx\@dtl@value\@empty +\else + \expandafter\ifx\csname @dtl@idtype@#1@#2\endcsname\@empty + \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% + \the\@dtl@datatype}% + \else + \expandafter\@dtl@tmpcount\expandafter= + \csname @dtl@idtype@#1@#2\endcsname + \ifcase\@dtl@tmpcount + % string, leave as it is + \or + % int, set to whatever \@dtl@datatype is + \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% + \the\@dtl@datatype}% + \or + % real, set to real unless <value> is a string + \ifnum\@dtl@datatype=0\relax + \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{0}% + \else + \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{2}% + \fi + \fi + \fi +\fi +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{@dtl@setkeys}\marg{key}\marg{db name} +%\end{definition} +% Adds \marg{key} to \cs{dtlkeys@}\meta{db name} if not already +% in it. +%\begin{macro}{\@dtl@setkeys} +% \begin{macrocode} +\newcommand*{\@dtl@setkeys}[2]{% +\edef\@dtl@tmp{\csname dtlkeys@#2\endcsname}% +\expandafter\@dtl@toks\expandafter{\@dtl@tmp}% +\expandafter\ifx\csname dtlkeys@#2\endcsname\@empty + \expandafter\gdef\csname dtlkeys@#2\endcsname{#1}% +\else + \@for\dtl@key:=\@dtl@tmp\do{% + \ifthenelse{\equal{\dtl@key}{#1}}{\@endfortrue}{}% + }% + \if@endfor + \else + \expandafter\xdef\csname dtlkeys@#2\endcsname{\the\@dtl@toks,#1}% + \fi +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{@dtl@getidtype}\marg{db name}\marg{id} +%\end{definition} +% Get the data type for \meta{id} in given database. +%\begin{macro}{\@dtl@getidtype} +% \begin{macrocode} +\newcommand*{\@dtl@getidtype}[2]{% +\csname @dtl@idtype@#1@#2\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLifdbexists}\marg{db name}\marg{true part}\marg{false part} +%\end{definition} +% Check if a data base with the given name exists: +%\begin{macro}{\DTLifdbexists} +% \begin{macrocode} +\newcommand{\DTLifdbexists}[3]{% +\@ifundefined{dtldb@#1}{#3}{#2}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{dtl@ifrowcontains}\meta{id}\meta{cmd}\meta{true part}\meta{false +%part} +%\end{definition} +% Check to see if the row given by \meta{cmd} contains an +% entry with ID given by \meta{id}. If true, do \meta{true part}, +% otherwise do \meta{false part}. +%\begin{macro}{\dtl@ifrowcontains} +% \begin{macrocode} +\newcommand{\dtl@ifrowcontains}[4]{% +\@for\@dtl@element:=#2\do{% +\dtl@getentryid{\@dtl@element}{\@dtl@entryid}% +\ifthenelse{\equal{#1}{\@dtl@entryid}}{\@endfortrue}{}% +}% +\if@endfor #3\else #4\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{dtl@getentryid}\meta{entry cmd}\meta{id cmd} +%\end{definition} +% Get the ID for an entry given by \meta{entry cmd}, and stores in +% in \meta{id cmd}. +%\begin{macro}{\dtl@getentryid} +% \begin{macrocode} +\newcommand*{\dtl@getentryid}[2]{\expandafter\@dtl@getentryid#1#2} +\long\def\@dtl@getentryid#1#2#3{\def#3{#1}} +% \end{macrocode} +%\end{macro} +%\begin{definition} +% \cs{dtl@getentryvalue}\meta{entry cmd}\meta{cmd} +%\end{definition} +% Stores the entry value in \meta{cmd} for +% entry given by \meta{entry cmd}. +%\begin{macro}{\dtl@getentryvalue} +% \begin{macrocode} +\newcommand*{\dtl@getentryvalue}[2]{% +\expandafter\@dtl@getentryvalue#1#2} +\long\def\@dtl@getentryvalue#1#2#3{\gdef#3{#2}} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLforeach} can only be nested up to three levels. +% \cs{dtlforeachlevel} keeps track of the current level. +%\begin{macro}{\dtlforeachlevel} +% \begin{macrocode} +\global\newcount\dtlforeachlevel +% \end{macrocode} +%\end{macro} +% +% The counter DTLrow\meta{n} keeps track of each row of data during +% the \meta{n} nested \cs{DTLforeach}. It is only incremented in the +% conditions (given by the optional argument) are met. +% \begin{macrocode} +\newcounter{DTLrowi} +\newcounter{DTLrowii} +\newcounter{DTLrowiii} +% \end{macrocode} +% Keep \sty{hyperref} happy +% \begin{macrocode} +\newcounter{DTLrow} +\newcommand*{\theHDTLrow}{\arabic{DTLrow}} +\newcommand*{\theHDTLrowi}{\theHDTLrow.\arabic{DTLrowi}} +\newcommand*{\theHDTLrowii}{\theHDTLrowi.\arabic{DTLrowii}} +\newcommand*{\theHDTLrowiii}{\theHDTLrowii.\arabic{DTLrowiii}} +% \end{macrocode} +% +%\begin{definition} +%\cs{DTLsavelastrowcount}\marg{cmd} +%\end{definition} +% Stores the maximum row count for the last \cs{DTLforeach}. +%\begin{macro}{\DTLsaverowcount} +% \begin{macrocode} +\newcommand*{\DTLsavelastrowcount}[1]{% +\ifnum\dtlforeachlevel>2\relax + \def#1{0}% +\else + \ifnum\dtlforeachlevel<0\relax + \def#1{0}% + \else + \@dtl@tmpcount=\dtlforeachlevel + \advance\@dtl@tmpcount by 1\relax + \edef#1{\expandafter\number + \csname c@DTLrow\romannumeral\@dtl@tmpcount\endcsname}% + \fi +\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLforeach}\oarg{conditions}\marg{db name}\marg{values}\marg{text} +%\end{definition} +% For each row of data in the database given by \meta{db name}, +% do \meta{text}, if the specified conditions are satisfied. +% The argument \marg{values} is a comma separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. At the start of each row, +% each of the commands in this list are set to the value of the +% entry with the corresponding key \meta{key}. +% (\cs{gdef} is used to ensure \cs{DTLforeach} works in a tabular +% environment.) The database is reconstructed to allow for +% rows to be edited. +%\begin{macro}{\DTLforeach} +% \begin{macrocode} +\newcommand{\DTLforeach}[4][\boolean{true}]{% +% \end{macrocode} +% Check database exists +% \begin{macrocode} +\DTLifdbexists{#2}{% +% \end{macrocode} +% Keep \sty{hyperref} happy +% \begin{macrocode} +\refstepcounter{DTLrow}% +\global\c@DTLrow=\c@DTLrow +% \end{macrocode} +% Store database name +% \begin{macrocode} +\gdef\@dtl@dbname{#2}% +% \end{macrocode} +% Increment level and check not exceeded 3 +% \begin{macrocode} +\global\advance\dtlforeachlevel by 1\relax +\ifnum\dtlforeachlevel>3\relax + \PackageError{datatool}{\string\DTLforeach\space nested too +deeply}{}% +\else +% \end{macrocode} +% Set level dependent information (needs to be global to ensure +% it works in the \env{tabular} environment.) Row counter: +% \begin{macrocode} + \expandafter\global + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname = 0\relax +% \end{macrocode} +% Construct updated database: +% \begin{macrocode} + \expandafter\global\expandafter\let + \csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname + =\@empty +% \end{macrocode} +% Database name: +% \begin{macrocode} + \expandafter\global\expandafter\let + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + =\@dtl@dbname +% \end{macrocode} +% Iterate through each row +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@db\csname dtldb@#2\endcsname% + \@for\@dtl@currentrow:=\@dtl@db\do{% +% \end{macrocode} +% Set current row macro for this level +% \begin{macrocode} + \expandafter\global\expandafter + \let\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel + \endcsname=\@dtl@currentrow +% \end{macrocode} +% Assign commands to the required entries +% \begin{macrocode} + \ifx\relax#3\relax + \else + \@dtl@assign{#3}% + \fi +% \end{macrocode} +% Do the main body of text if condition is satisfied +% \begin{macrocode} + \ifthenelse{#1}{% + \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% + \expandafter\edef\expandafter\DTLcurrentindex\expandafter + {\arabic{DTLrow\romannumeral\dtlforeachlevel}}% + #4% + }{}% +% \end{macrocode} +% Reconstruct database +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thiscurrentrow + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Don't add this row if it is now empty +% \begin{macrocode} + \ifx\@dtl@thiscurrentrow\@empty + \else + \expandafter\@dtl@toks\expandafter{\@dtl@thiscurrentrow}% + \expandafter + \ifx + \csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname + \@empty + \expandafter + \xdef\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname{{\the\@dtl@toks}}% + \else + \expandafter\let\expandafter\@dtl@foreachrows\expandafter + =\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname + \expandafter\toks@\expandafter{\@dtl@foreachrows}% + \expandafter + \xdef\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname{\the\toks@,{\the\@dtl@toks}}% + \fi + \fi +\@endforfalse +}% + \expandafter\let\expandafter\@dtl@foreachrows\expandafter + =\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname +\expandafter\global + \expandafter\let\csname dtldb@#2\endcsname=\@dtl@foreachrows +\fi +\global\advance\dtlforeachlevel by -1\relax +}{% +\PackageError{datatool}{Database `#2' doesn't exist}{}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLappendtorow}\marg{key}\marg{value} +%\end{definition} +% Appends entry to current row. (The current row is given by +% \cs{@dtl@thiscurrentrow@}\meta{n} where \meta{n} is roman +% numeral value of \cs{dtlforeachlevel}. +%\begin{macro}{\DTLappendtorow} +% \begin{macrocode} +\newcommand*{\DTLappendtorow}[2]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLappendtorow\space can only + be used inside \string\DTLforeach}{}% +\else +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Set \cs{@dtl@dbvalue} to the value of this entry +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{#2}% + \edef\@dtl@dbvalue{\the\@dtl@toks}% +% \end{macrocode} +% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow +% for the ID to be stored in a control sequence. +% \begin{macrocode} + \edef\@dtl@dbid{#1}% +% \end{macrocode} +% Set up the correct entry format: +% \begin{macrocode} + \edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% +% \end{macrocode} +% Set \cs{@dtl@thisrow} to the current row. +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisrow + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check if there is already an entry with this key +% \begin{macrocode} + \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% + \PackageError{datatool}{Can't add entry with ID `#1' to current + row of database `\@dtl@thisdb'}{There is already an entry with + this ID on the current row}}{% +% \end{macrocode} +% Append entry to last row +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% + \ifx\@dtl@thisrow\@empty + \expandafter + \xdef\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname{\the\@dtl@toks}% + \else + \expandafter\toks@\expandafter{\@dtl@thisrow}% + \expandafter + \xdef\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname{\the\toks@,\the\@dtl@toks}% + \fi + } +% \end{macrocode} +% Update key list +% \begin{macrocode} + \@dtl@setidtype{\@dtl@thisdb}{#1}{#2}% + \expandafter\@dtl@setkeys\expandafter{#1}{\@dtl@thisdb}% +% \end{macrocode} +% end the \cs{ifnum} +% \begin{macrocode} +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLremoveentryfromrow}\marg{key} +%\end{definition} +% Removes entry given by \meta{key} from current row. +% (The current row is given by +% \cs{@dtl@thiscurrentrow@}\meta{n} where \meta{n} is roman +% numeral value of \cs{dtlforeachlevel}. +%\begin{macro}{\DTLremoveentryfromrow} +% \begin{macrocode} +\newcommand*{\DTLremoveentryfromrow}[1]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLremoveentryfromrow\space can only + be used inside \string\DTLforeach}{}% +\else +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Set \cs{@dtl@thisrow} to the current row. +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisrow + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check row contains an entry with this key +% \begin{macrocode} + \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% +% \end{macrocode} +% Split row list +% \begin{macrocode} + \let\@dtl@pre=\@empty + \@for\dtl@thisentry:=\@dtl@thisrow\do{% + \dtl@getentryid\dtl@thisentry\@dtl@id + \ifthenelse{\equal{\@dtl@id}{#1}}{% + }{% + \expandafter\@dtl@toks\expandafter{\dtl@thisentry}% + \ifx\@dtl@pre\@empty + \edef\@dtl@pre{{\the\@dtl@toks}}% + \else + \expandafter\toks@\expandafter{\@dtl@pre}% + \edef\@dtl@pre{\the\toks@,{\the\@dtl@toks}}% + \fi + } + }% + \expandafter\let + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname + =\@dtl@pre + }{% + \PackageError{datatool}{Can't remove entry given by key `#1' + from current row in database `\@dtl@thisdb', no such entry}{}% + }% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLreplaceentryforrow}\marg{key}\marg{value} +%\end{definition} +% Replaces entry given by \meta{key} in current row with +% \meta{value}. +% (The current row is given by +% \cs{@dtl@thiscurrentrow@}\meta{n} where \meta{n} is roman +% numeral value of \cs{dtlforeachlevel}. +%\begin{macro}{\DTLreplaceentryforrow} +% \begin{macrocode} +\newcommand*{\DTLreplaceentryforrow}[2]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLreplaceentryforrow\space can only + be used inside \string\DTLforeach}{}% +\else +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Set \cs{@dtl@dbvalue} to the value of this entry +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{#2}% + \edef\@dtl@dbvalue{\the\@dtl@toks}% +% \end{macrocode} +% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow +% for the ID to be stored in a control sequence. +% \begin{macrocode} + \edef\@dtl@dbid{#1}% +% \end{macrocode} +% Set up the correct entry format: +% \begin{macrocode} + \edef\dtl@newentry{{\@dtl@dbid}{\the\@dtl@toks}}% +% \end{macrocode} +% Set \cs{@dtl@thisrow} to the current row. +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisrow + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check row contains an entry with this key +% \begin{macrocode} + \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% +% \end{macrocode} +% Split row list +% \begin{macrocode} + \let\@dtl@pre=\@empty + \@for\dtl@thisentry:=\@dtl@thisrow\do{% + \dtl@getentryid\dtl@thisentry\@dtl@id + \ifthenelse{\equal{\@dtl@id}{#1}}{% + \expandafter\@dtl@toks\expandafter{\dtl@newentry}% + }{% + \expandafter\@dtl@toks\expandafter{\dtl@thisentry}% + } + \ifx\@dtl@pre\@empty + \edef\@dtl@pre{{\the\@dtl@toks}}% + \else + \expandafter\toks@\expandafter{\@dtl@pre}% + \edef\@dtl@pre{\the\toks@,{\the\@dtl@toks}}% + \fi + }% + \expandafter\let + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname + =\@dtl@pre + }{% + \PackageError{datatool}{Can't remove entry given by key `#1' + from current row in database `\@dtl@thisdb', no such entry}{}% + }% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLremovecurrentrow} +%\end{definition} +% Removes current row. This just sets the current row to empty +%\begin{macro}{\DTLremoveentryfromrow} +% \begin{macrocode} +\newcommand*{\DTLremovecurrentrow}[1]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLremovecurrentrow\space can only + be used inside \string\DTLforeach}{}% +\else +% \end{macrocode} +% Set current row to empty. +% \begin{macrocode} + \expandafter\let + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname + =\@empty +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +%\end{definition} +% Iterates through each key in the row, and does \meta{text}. +%\begin{macro}{\DTLforeachkeyinrow} +% \begin{macrocode} +\newcommand*{\DTLforeachkeyinrow}[2]{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLforeachkeyinrow\space can only + be used inside \string\DTLforeach}{}% +\else +% \end{macrocode} +% Set \cs{@dtl@thisrow} to the current row. +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisrow + \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Iterate through the row +% \begin{macrocode} + \@for\dtl@thisentry:=\@dtl@thisrow\do{% + \dtl@getentryvalue\dtl@thisentry{#1}% + #2% + }% +\fi +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{definition} +%\cs{DTLaddentryforrow}\marg{db name}\marg{assign list}\marg{condition}\marg{key}\marg{value} +%\end{definition} +%\begin{macro}{\DTLaddentryforrow} +% \begin{macrocode} +\newcommand{\DTLaddentryforrow}[5]{% +\gdef\@dtl@dbname{#1}% +\DTLifdbexists{#1}{% +% \end{macrocode} +% Set \cs{@dtl@dbvalue} to the value of this entry +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{#5}% + \edef\@dtl@dbvalue{\the\@dtl@toks}% +% \end{macrocode} +% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow +% for the ID to be stored in a control sequence. +% \begin{macrocode} + \edef\@dtl@dbid{#4}% +% \end{macrocode} +% Set up the correct entry format: +% \begin{macrocode} + \edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% +% \end{macrocode} +% Store the database in \cs{@dtl@db} +% \begin{macrocode} + \expandafter + \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% + \let\@dtl@prerow=\@empty +% \end{macrocode} +% Iterate through each row of the database +% \begin{macrocode} + \@for\@dtl@currentrow:=\@dtl@db\do{% + \@dtl@assign{#2}% + \ifthenelse{#3}{% + \expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% + \ifx\@dtl@currentrow\@empty + \edef\@dtl@currentrow{{\the\@dtl@toks}}% + \else + \expandafter\toks@\expandafter{\@dtl@currentrow}% + \edef\@dtl@currentrow{\the\toks@,{\the\@dtl@toks}}% + \fi + \@endfortrue + }{% + }% + \expandafter\@dtl@toks\expandafter{\@dtl@currentrow}% + \ifx\@dtl@prerow\@empty + \edef\@dtl@prerow{{\the\@dtl@toks}}% + \else + \expandafter\toks@\expandafter{\@dtl@prerow}% + \edef\@dtl@prerow{\the\toks@,{\the\@dtl@toks}}% + \fi +}% +\if@endfor + \expandafter\@dtl@toks\expandafter{\@forremainder}% + \expandafter\toks@\expandafter{\@dtl@prerow}% + \edef\@dtl@prerow{\the\toks@,{\the\@dtl@toks}}% + \expandafter\global\expandafter + \let\csname dtldb@\@dtl@dbname\endcsname=\@dtl@prerow +\else + \PackageError{datatool}{Unable to add `#5' for key `#4' - condition + not met for any row in database `#1'}{}% +\fi +\@endforfalse +}{% +\PackageError{datatool}{Database `#1' doesn't exist}{}}% +} +% \end{macrocode} +%\end{macro} +% +%\cs{@dtl@assign}\marg{values} assigns each command in +% \meta{values} (see above) to the value of the corresponding +% ID for the row given by \cs{@dtl@currentrow}. +%\begin{macro}{\@dtl@assign} +% \begin{macrocode} +\newcommand*{\@dtl@assign}[1]{% +\@dtl@assigncmd#1,\relax\@@ +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +% \cs{\@dtl@assigncmd}\meta{cmd}=\meta{id}\cs{@nil} +%\end{definition} +% Assign \meta{cmd} to value given by \meta{id} +%\begin{macro}{\@dtl@assigncmd} +% \begin{macrocode} +\def\@dtl@assigncmd#1=#2,#3\@@{% +\@for\@dtl@entry:=\@dtl@currentrow\do{% +\dtl@getentryid\@dtl@entry\@dtl@id +\ifthenelse{\equal{\@dtl@id}{#2}}{% +\dtl@getentryvalue\@dtl@entry#1% +\@endfortrue}{}% +}% +\if@endfor +\else + \@dtl@setnull{#1}{#2}% +\fi +\@endforfalse +\ifx\relax#3% + \let\@dtl@next=\@dtl@assigncmdnoop +\else + \let\@dtl@next=\@dtl@assigncmd +\fi +\@dtl@next#3\@@ +} +% \end{macrocode} +%\end{macro} +% End loop +%\begin{macro}{\@dtl@assigncmdnoop} +% \begin{macrocode} +\def\@dtl@assigncmdnoop#1\@@{} +% \end{macrocode} +%\end{macro} +%\cs{@dtl@setnull}\marg{cmd}\marg{id} sets \meta{cmd} to either +% NULL or 0 depending on the data type for \meta{id}. (Database +% name should be stored in \cs{@dtl@dbname} prior to use. +%\begin{macro}{\@dtl@setnull} +% \begin{macrocode} +\newcommand*{\@dtl@setnull}[2]{% +\@ifundefined{@dtl@idtype@\@dtl@dbname @#2}{% +\PackageError{datatool}{Key `#2' not defined in database +`\@dtl@dbname'}{}}{% +\edef\@dtl@tmp{0\@dtl@getidtype{\@dtl@dbname}{#2}}% +\expandafter\ifnum\@dtl@tmp=0\relax + \gdef#1{NULL}% +\else + \gdef#1{0}% +\fi +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@gathervalues}\marg{db name}\marg{row} +%\end{definition} +% Stores each element of \meta{row} in \meta{db name} into +% the command \cs{@dtl@key@}\meta{key}, where \meta{key} is the +% key for that element. +%\begin{macro}{\dtl@gathervalues} +% \begin{macrocode} +\newcommand{\dtl@gathervalues}[2]{% +\edef\@dtl@tmp{\csname dtlkeys@#1\endcsname}% +\def\@dtl@list{}% +\@for\dtl@key:=\@dtl@tmp\do{% + \expandafter\@dtl@setnull\expandafter{% + \csname @dtl@key@\dtl@key\endcsname}{\dtl@key}% + \@for\dtl@thiselement:=#2\do{% + \dtl@getentryid\dtl@thiselement\@dtl@id + \DTLifstringeq{\@dtl@id}{\dtl@key}{% + \dtl@getentryvalue\dtl@thiselement\@dtl@value% + \expandafter\protected@edef\csname @dtl@key@\dtl@key\endcsname{\@dtl@value}% + \@endfortrue}{}% + }% +\@endforfalse +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLsumforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Sums all entries for key \meta{key} over all databases listed +% in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. +%\begin{macro}{\DTLsumforkeys} +% \begin{macrocode} +\newcommand*{\DTLsumforkeys}[4][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% +\def#4{0}% +\@for\@dtl@dbname:=#2\do{% + \DTLifdbexists{\@dtl@dbname}{% + \expandafter + \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% + \@for\@dtl@currentrow:=\@dtl@db\do{% + \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% + \@for\@dtl@key:=#3\do{% + \protected@edef\DTLthisval{% + \csname @dtl@key@\@dtl@key\endcsname}% + \ifthenelse{#1}{\DTLadd{#4}{#4}{\DTLthisval}}{}% + }}% + }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% + }% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLmeanforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Computes the arithmetic mean of all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. +%\begin{macro}{\DTLmeanforkeys} +% \begin{macrocode} +\newcommand*{\DTLmeanforkeys}[4][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% +\def#4{0}% +\def\dtl@n{0}% +\@for\@dtl@dbname:=#2\do{% +\DTLifdbexists{\@dtl@dbname}{% + \expandafter + \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% + \@for\@dtl@currentrow:=\@dtl@db\do{% + \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% + \@for\@dtl@key:=#3\do{% + \protected@edef\DTLthisval{% + \csname @dtl@key@\@dtl@key\endcsname}% + \ifthenelse{#1}{% + \DTLadd{#4}{#4}{\DTLthisval}% + \DTLadd{\dtl@n}{\dtl@n}{1}% + }{}% + }}% +}{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}}}% +\ifnum\dtl@n=0\relax + \PackageError{datatool}{Can't compute mean, no data!}{}% +\else + \DTLdiv{#4}{#4}{\dtl@n}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLvarianceforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Computes the variance of all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. +%\begin{macro}{\DTLvarianceforkeys} +% \begin{macrocode} +\newcommand*{\DTLvarianceforkeys}[4][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% +\DTLmeanforkeys[#1]{#2}{#3}{\dtl@mean}% +\def#4{0}% +\@for\@dtl@dbname:=#2\do{% + \DTLifdbexists{\@dtl@dbname}{% + \expandafter + \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname + \@for\@dtl@currentrow:=\@dtl@db\do{% + \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% + \@for\@dtl@key:=#3\do{% + \protected@edef\DTLthisval{% + \csname @dtl@key@\@dtl@key\endcsname}% + \ifthenelse{#1}{% + \DTLsub{\dtl@diff}{\DTLthisval}{\dtl@mean}% + \DTLmul{\dtl@diff}{\dtl@diff}{\dtl@diff}% + \DTLadd{#4}{#4}{\dtl@diff}% + }{}% + }}% + }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% + }% +}% +\ifnum\dtl@n=0\relax + \PackageError{datatool}{Can't compute variance, no data!}{}% +\else + \DTLdiv{#4}{#4}{\dtl@n}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLsdforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Computes the standard deviation of all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. +%\begin{macro}{\DTLsdforkeys} +% \begin{macrocode} +\newcommand*{\DTLsdforkeys}[4][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% +\DTLvarianceforkeys[#1]{#2}{#3}{#4}% +\DTLsqrt{#4}{#4}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLminforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Determines the minimum over all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. +%\begin{macro}{\DTLminforkeys} +% \begin{macrocode} +\newcommand*{\DTLminforkeys}[4][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% +\def#4{}% +\@for\@dtl@dbname:=#2\do{% +\DTLifdbexists{\@dtl@dbname}{% + \expandafter + \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% + \@for\@dtl@currentrow:=\@dtl@db\do{% + \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% + \@for\@dtl@key:=#3\do{% + \protected@edef\DTLthisval{% + \csname @dtl@key@\@dtl@key\endcsname}% + \ifthenelse{#1}{% + \ifx#4\@empty + \let#4=\DTLthisval + \else + \DTLmin{#4}{#4}{\DTLthisval}% + \fi + }{}% +}}% + }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% + }% +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLmaxforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Determines the maximum over all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. +%\begin{macro}{\DTLmaxforkeys} +% \begin{macrocode} +\newcommand*{\DTLmaxforkeys}[4][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% +\def#4{}% +\@for\@dtl@dbname:=#2\do{% +\DTLifdbexists{\@dtl@dbname}{% + \expandafter + \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% + \@for\@dtl@currentrow:=\@dtl@db\do{% + \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% + \@for\@dtl@key:=#3\do{% + \protected@edef\DTLthisval{% + \csname @dtl@key@\@dtl@key\endcsname}% + \ifthenelse{#1}{% + \ifx#4\@empty + \let#4=\DTLthisval + \else + \DTLmax{#4}{#4}{\DTLthisval}% + \fi + }{}% +}}% + }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% + }% +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLcomputebounds}\oarg{condition}\marg{db list}\marg{x key}\marg{y key}\marg{minX cmd}\marg{minY cmd}\marg{maxX cmd}\marg{maxY cmd} +%\end{definition} +% Computes the maximum and minimum $x$ and $y$ values over all +% the databases listed in \meta{db list} where the $x$ value +% is given by \meta{x key} and the $y$ value is given by +% \meta{y key}. The results are stored in \meta{minX cmd}, +% \meta{minY cmd}, \meta{maxX cmd} and \meta{maxY cmd} in +% standard decimal format. +%\begin{macro}{\DTLcomputebounds} +% \begin{macrocode} +\newcommand*{\DTLcomputebounds}[8][\boolean{true}]{% +\let#5=\relax +\let#6=\relax +\let#7=\relax +\let#8=\relax +\@for\dtl@thisdb:=#2\do{% + \DTLforeach[#1]{\dtl@thisdb}{\DTLthisX=#3,\DTLthisY=#4}{% + \DTLconverttodecimal{\DTLthisX}{\dtl@decx}% + \DTLconverttodecimal{\DTLthisY}{\dtl@decy}% + \ifx#5\relax + \let#5=\dtl@decx + \let#6=\dtl@decy + \let#7=\dtl@decx + \let#8=\dtl@decy + \else + \FPmin{#5}{#5}{\dtl@decx}% + \FPmin{#6}{#6}{\dtl@decy}% + \FPmax{#7}{#7}{\dtl@decx}% + \FPmax{#8}{#8}{\dtl@decy}% + \fi + }% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLsort}\marg{sort criteria}\marg{db name} +%\end{definition} +% Sorts database \meta{db name} according to \marg{sort criteria}, +% which must be a comma separated list of keys, and optionally +% \texttt{=}\meta{order}, where \meta{order} is either +% "ascending" or "descending". +%\begin{macro}{\DTLsort} +% \begin{macrocode} +\newcommand*{\DTLsort}[2]{% +\edef\@dtl@sortorder{#1}% +\edef\@dtl@dbname{#2}% +\protected@edef\@dtl@list{\csname dtldb@#2\endcsname}% +\dtl@sortlist{\@dtl@list}{\@dtl@sortcriteria}% +\expandafter\global\expandafter + \let\csname dtldb@#2\endcsname=\@dtl@list} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{@dtl@sortcriteria}\marg{a}\marg{b} +%\end{definition} +% Sort criteria. \cs{@dtl@currentrow} and +% \cs{@dtl@sortorder} must be set before use. +%\begin{macro}{\@dtl@sortcriteria} +% \begin{macrocode} +\newcommand{\@dtl@sortcriteria}[2]{% +\@for\@dtl@level:=\@dtl@sortorder\do{% + \expandafter\@dtl@getsortdirection\@dtl@level=\relax% + \dtl@compare{\@dtl@key}{#1}{#2}% + \multiply\dtl@sortresult by \@dtl@sortdirection\relax + \ifnum\dtl@sortresult=0\relax + \else + \@endfortrue + \fi +}% +} +% \end{macrocode} +%\end{macro} +% Get the direction from either \meta{key} or +% \meta{key}=\meta{direction}. Sets \cs{@dtl@sortdirection} to +% either -1 (ascending) or 1 (descending). +%\begin{macro}{\@dtl@getsortdirection} +% \begin{macrocode} +\def\@dtl@getsortdirection#1=#2\relax{% +\def\@dtl@key{#1}% +\def\@dtl@sortdirection{#2}% +\ifx\@dtl@sortdirection\@empty + \def\@dtl@sortdirection{-1}% +\else + \@dtl@get@sortdirection#2% + \DTLifstringeq{\@dtl@sortdirection}{ascending}{% + \def\@dtl@sortdirection{-1}}{% + \DTLifstringeq{\@dtl@sortdirection}{descending}{% + \def\@dtl@sortdirection{1}}{% + \PackageError{datatool}{Invalid sort direction + `\@dtl@sortdirection'}{% + The sort direction can only be one of `ascending' or + `descending'}\def\@dtl@sortdirection{-1}}}% +\fi +} +% \end{macrocode} +%\end{macro} +% Get direction +%\begin{macro}{\@dtl@get@sortdirection} +% \begin{macrocode} +\def\@dtl@get@sortdirection#1={\def\@dtl@sortdirection{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@compare}\marg{key}\marg{a}\marg{b} +%\end{definition} +% Compare \meta{a} and \meta{b} according to \meta{key} of +% database given by \cs{@dtl@dbname}. Sets \cs{dtl@sortresult}. +%\begin{macro}{\dtl@compare} +% \begin{macrocode} +\newcommand{\dtl@compare}[3]{% +\protected@edef\dtl@arga{#2}\protected@edef\dtl@argb{#3}% +\dtl@gathervalues{\@dtl@dbname}{\dtl@arga}% +\protected@edef\@dtl@a{\csname @dtl@key@#1\endcsname}% +\dtl@gathervalues{\@dtl@dbname}{\dtl@argb}% +\protected@edef\@dtl@b{\csname @dtl@key@#1\endcsname}% +\expandafter\@dtl@datatype\expandafter= + \csname @dtl@idtype@\@dtl@dbname @#1\endcsname\relax +\ifnum\@dtl@datatype=0\relax + \edef\@dtl@result{\noexpand\compare{\@dtl@a}{\@dtl@b}}% + \expandafter\dtl@sortresult\expandafter=\@dtl@result\relax +\else + \DTLifnumlt{\@dtl@a}{\@dtl@b}{\dtl@sortresult=-1\relax}{% + \DTLifnumgt{\@dtl@a}{\@dtl@b}{\dtl@sortresult=1\relax}{% + \dtl@sortresult=0\relax}}% +\fi +\dtl@message{`\@dtl@a' <=> `\@dtl@b' = \number\dtl@sortresult}% +} +% \end{macrocode} +%\end{macro} +% +%\subsection{General List Utilities} +% +%\begin{definition} +% \cs{dtl@choplast}\marg{list}\marg{rest}\marg{last} +%\end{definition} +% Chop the last element off a comma separated list, putting the +% last element in the control sequence \meta{last} and putting +% the rest in the control sequence \meta{rest}. The control +% sequence \meta{list} is unchanged. If the list is empty, both +% \meta{last} and \meta{rest} will be empty. +%\begin{macro}{\dtl@choplast} +% \begin{macrocode} +\newcommand*{\dtl@choplast}[3]{% +% \end{macrocode} +% Set \meta{rest} to empty: +% \begin{macrocode} +\let#2\@empty +% \end{macrocode} +% Set \meta{last} to empty: +% \begin{macrocode} +\let#3\@empty +% \end{macrocode} +% Iterate through \meta{list}: +% \begin{macrocode} +\@for\@dtl@element:=#1\do{% +\ifx#3\@empty +% \end{macrocode} +% First iteration, don't set \meta{rest}. +% \begin{macrocode} +\else + \ifx#2\@empty +% \end{macrocode} +% Second iteration, set \meta{rest} to \meta{last} (which is +% currently set to the previous value: +% \begin{macrocode} + \expandafter\toks@\expandafter{#3}% + \edef#2{{\the\toks@}}% + \else +% \end{macrocode} +% Subsequent iterations, set \meta{rest} to \meta{rest},\meta{last} +% (\meta{last} is currently set to the previous value): +% \begin{macrocode} + \expandafter\toks@\expandafter{#3}% + \expandafter\@dtl@toks\expandafter{#2}% + \edef#2{\the\@dtl@toks,{\the\toks@}}% + \fi +\fi +% \end{macrocode} +% Now set \meta{last} to current element. +% \begin{macrocode} +\let#3=\@dtl@element% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{dtl@chopfirst}\marg{list}\marg{first}\marg{rest} +%\end{definition} +% Chop first element off \meta{list} and store in \meta{first}. +% The remainder of the list is stored in \meta{rest}. (\meta{list} +% remains unchanged.) +%\begin{macro}{\dtl@chopfirst} +% \begin{macrocode} +\newcommand*{\dtl@chopfirst}[3]{% +\let#2=\@empty +\let#3=\@empty +\@for\@dtl@element:=#1\do{% + \let#2=\@dtl@element + \@endfortrue +}% +\if@endfor + \let#3=\@forremainder +\fi +\@endforfalse +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{dtl@sortlist}\marg{list}\marg{criteria cmd} +%\end{definition} +% Performs an insertion sort on \meta{list}, where \meta{criteria cmd} +% is a macro which takes two arguments \meta{a} and \meta{b}. +% \meta{criteria cmd} must set the count register \cs{dtl@sortresult} +% to either -1 (\meta{a} less than \meta{b}), 0 (\meta{a} is +% equal to \meta{b}) or 1 (\meta{a} is greater than \meta{b}.) +%\begin{macro}{\dtl@sortlist} +% \begin{macrocode} +\newcommand{\dtl@sortlist}[2]{% +\def\@dtl@sortedlist{}% +\@for\@dtl@currentrow:=#1\do{% +\dtl@insertinto{\@dtl@currentrow}{\@dtl@sortedlist}{#2}% +\@endforfalse}% +\let#1=\@dtl@sortedlist +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{dtl@insertinto}\marg{element}\marg{sorted-list}\marg{criteria cmd} +%\end{definition} +% Inserts \meta{element} into the sorted list \meta{sorted-list} +% according to the criteria given by \meta{criteria cmd} (see above.) +%\begin{macro}{\dtl@insertinto} +% \begin{macrocode} +\newtoks\@dtl@toks +\newcommand{\dtl@insertinto}[3]{% +\def\@dtl@newsortedlist{}% +\@dtl@insertdonefalse +\@for\dtl@srtelement:=#2\do{% +\expandafter\toks@\expandafter{\@dtl@newsortedlist}% +\if@dtl@insertdone + \protected@edef\@dtl@newstuff{{\dtl@srtelement}}% +\else + \expandafter#3\expandafter{\dtl@srtelement}{#1}% + \ifnum\dtl@sortresult<0\relax + \protected@edef\@dtl@newstuff{{#1},{\dtl@srtelement}}% + \@dtl@insertdonetrue + \else + \protected@edef\@dtl@newstuff{{\dtl@srtelement}}% + \fi +\fi +\ifx\@dtl@newsortedlist\@empty + \protected@edef\@dtl@newsortedlist{\@dtl@newstuff}% +\else + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \protected@edef\@dtl@newsortedlist{\the\toks@,\@dtl@newstuff}% +\fi +\@endforfalse +}% + \ifx\@dtl@newsortedlist\@empty + \protected@edef\@dtl@newsortedlist{{#1}}% + \else + \if@dtl@insertdone + \else + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \protected@edef\@dtl@newsortedlist{\the\toks@,{#1}}% + \fi + \fi +\global\let#2=\@dtl@newsortedlist +} +% \end{macrocode} +%\end{macro} +% Define conditional to indicate whether the new entry has +% been inserted into the sorted list. +%\begin{macro}{\if@dtl@insertdone} +% \begin{macrocode} +\newif\if@dtl@insertdone +% \end{macrocode} +%\end{macro} +% Define \cs{dtl@sortresult} to be set by comparision macro. +%\begin{macro}{\dtl@sortresult} +% \begin{macrocode} +\newcount\dtl@sortresult +% \end{macrocode} +%\end{macro} +% +% \subsection{Floating Point Arithmetic} +% The commands defined in this section all use the equivalent +% commands provided by the \sty{fp} package, but first convert +% the decimal number into the required format. +% +%\begin{definition} +% \cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} + \meta{num2} +%\begin{macro}{\DTLadd} +% \begin{macrocode} +\newcommand*{\DTLadd}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPadd{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgadd} +% \begin{macrocode} +\newcommand*{\DTLgadd}[3]{% +\DTLadd{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLaddall}\marg{cmd}\marg{num list} +%\end{definition} +% Sums all the values in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\begin{macro}{\DTLaddall} +% \begin{macrocode} +\newcommand*{\DTLaddall}[2]{% +\def\@dtl@sum{0}% +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \FPadd{\@dtl@sum}{\@dtl@sum}{\@dtl@num}% +} +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@sum}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@sum}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLgaddall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +%\begin{macro}{\DTLgaddall} +% \begin{macrocode} +\newcommand*{\DTLgaddall}[2]{% +\DTLaddall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} - \meta{num2} +%\begin{macro}{\DTLsub} +% \begin{macrocode} +\newcommand*{\DTLsub}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPsub{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgsub} +% \begin{macrocode} +\newcommand*{\DTLgsub}[3]{% +\DTLsub{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} * \meta{num2} +%\begin{macro}{\DTLmul} +% \begin{macrocode} +\newcommand*{\DTLmul}[3]{% +\let\@dtl@thisreplaced=\@empty +\DTLconverttodecimal{#2}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty +\else + \let\@dtl@thisreplaced=\@dtl@replaced +\fi +\DTLconverttodecimal{#3}{\@dtl@numii}% +\ifx\@dtl@replaced\@empty +\else + \let\@dtl@thisreplaced=\@dtl@replaced +\fi +\FPmul{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@thisreplaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgmul} +% \begin{macrocode} +\newcommand*{\DTLgmul}[3]{% +\DTLmul{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} / \meta{num2} +%\begin{macro}{\DTLdiv} +% \begin{macrocode} +\newcommand*{\DTLdiv}[3]{% +\let\@dtl@thisreplaced=\@empty +\DTLconverttodecimal{#2}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty +\else + \let\@dtl@thisreplaced=\@dtl@replaced +\fi +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPdiv{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@thisreplaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \ifx\@dtl@thisreplaced\@dtl@replaced + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + \else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + \fi +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgdiv} +% \begin{macrocode} +\newcommand*{\DTLgdiv}[3]{% +\DTLdiv{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLabs}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = abs(\meta{num}) +%\begin{macro}{\DTLabs} +% \begin{macrocode} +\newcommand*{\DTLabs}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPabs{\@dtl@tmp}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgabs} +% \begin{macrocode} +\newcommand*{\DTLgabs}[2]{% +\DTLabs{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLneg}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = -\meta{num} +%\begin{macro}{\DTLneg} +% \begin{macrocode} +\newcommand*{\DTLneg}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPneg{\@dtl@tmp}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgneg} +% \begin{macrocode} +\newcommand*{\DTLgneg}[2]{% +\DTLneg{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLsqrt}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = sqrt(\meta{num}) +%\begin{macro}{\DTLsqrt} +% \begin{macrocode} +\newcommand*{\DTLsqrt}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FProot{\@dtl@tmpi}{\@dtl@numi}{2}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmpi}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmpi}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgsqrt} +% \begin{macrocode} +\newcommand*{\DTLgsqrt}[2]{% +\DTLsqrt{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = min(\meta{num1}, \meta{num2}) +%\begin{macro}{\DTLmin} +% \begin{macrocode} +\newcommand*{\DTLmin}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPiflt{\@dtl@numi}{\@dtl@numii}% + \dtl@ifsingle{#2}{% + \let#1=#2}{% + \def#1{#2}}% +\else + \dtl@ifsingle{#3}{% + \let#1=#3}{% + \def#1{#3}}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgmin} +% \begin{macrocode} +\newcommand*{\DTLgmin}[3]{% +\DTLmin{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLminall}\marg{cmd}\marg{num list} +%\end{definition} +% Finds the minimum value in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\begin{macro}{\DTLminall} +% \begin{macrocode} +\newcommand*{\DTLminall}[2]{% +\let\@dtl@min=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@min\@empty + \let\@dtl@min=\@dtl@num + \else + \FPmin{\@dtl@min}{\@dtl@min}{\@dtl@num}% + \fi +} +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@min}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@min}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLgminall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +%\begin{macro}{\DTLgminall} +% \begin{macrocode} +\newcommand*{\DTLgminall}[2]{% +\DTLminall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = max(\meta{num1}, \meta{num2}) +%\begin{macro}{\DTLmax} +% \begin{macrocode} +\newcommand*{\DTLmax}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPmax{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\FPifgt{\@dtl@numi}{\@dtl@numii}% + \dtl@ifsingle{#2}{% + \let#1=#2}{% + \def#1{#2}}% +\else + \dtl@ifsingle{#3}{% + \let#1=#3}{% + \def#1{#3}}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgmax} +% \begin{macrocode} +\newcommand*{\DTLgmax}[3]{% +\DTLmax{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLmaxall}\marg{cmd}\marg{num list} +%\end{definition} +% Finds the maximum value in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\begin{macro}{\DTLmaxall} +% \begin{macrocode} +\newcommand*{\DTLmaxall}[2]{% +\let\@dtl@max=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@max\@empty + \let\@dtl@max\@dtl@num + \else + \FPmax{\@dtl@max}{\@dtl@max}{\@dtl@num}% + \fi +} +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@max}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@max}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLgmaxall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +%\begin{macro}{\DTLgmaxall} +% \begin{macrocode} +\newcommand*{\DTLgmaxall}[2]{% +\DTLmaxall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLmeanforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the arithmetic mean of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\begin{macro}{\DTLmeanforall} +% \begin{macrocode} +\newcommand*{\DTLmeanforall}[2]{% +\def\@dtl@mean{0}% +\def\@dtl@n{0}% +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \FPadd{\@dtl@n}{\@dtl@n}{1}% +} +\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@mean}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@mean}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLgmeanforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +%\begin{macro}{\DTLgmeanforall} +% \begin{macrocode} +\newcommand*{\DTLgmeanforall}[2]{% +\DTLmeanforall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLvarianceforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the variance of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\begin{macro}{\DTLvarianceforall} +% \begin{macrocode} +\newcommand*{\DTLvarianceforall}[2]{% +\def\@dtl@mean{0}% +\def\@dtl@n{0}% +\let\@dtl@decvals=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@decvals\@empty + \let\@dtl@decvals=\@dtl@num + \else + \edef\@dtl@decvals{\@dtl@decvals,\@dtl@num}% + \fi + \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \FPadd{\@dtl@n}{\@dtl@n}{1}% +} +\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% +\def\@dtl@var{0}% +\@for\dtl@num:=\@dtl@decvals\do{% + \FPsub{\@dtl@diff}{\@dtl@var}{\@dtl@mean}% + \FPmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% + \FPadd{\@dtl@var}{\@dtl@var}{\@dtl@diff}% +} +\FPdiv{\@dtl@var}{\@dtl@var}{\@dtl@n}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@var}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@var}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLgvarianceforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +%\begin{macro}{\DTLgvarianceforall} +% \begin{macrocode} +\newcommand*{\DTLgvarianceforall}[2]{% +\DTLvarianceforall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLsdforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the standard deviation of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\begin{macro}{\DTLsdforall} +% \begin{macrocode} +\newcommand*{\DTLsdforall}[2]{% +\def\@dtl@mean{0}% +\def\@dtl@n{0}% +\let\@dtl@decvals=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@decvals\@empty + \let\@dtl@decvals=\@dtl@num + \else + \edef\@dtl@decvals{\@dtl@decvals,\@dtl@num}% + \fi + \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \FPadd{\@dtl@n}{\@dtl@n}{1}% +} +\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% +\def\@dtl@sd{0}% +\@for\dtl@num:=\@dtl@decvals\do{% + \FPsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% + \FPmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% + \FPadd{\@dtl@sd}{\@dtl@sd}{\@dtl@diff}% +} +\FPdiv{\@dtl@sd}{\@dtl@sd}{\@dtl@n}% +\FProot{\@dtl@sd}{\@dtl@sd}{2}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@sd}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@sd}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLgsdforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +%\begin{macro}{\DTLgsdforall} +% \begin{macrocode} +\newcommand*{\DTLgsdforall}[2]{% +\DTLsdforall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +% Sets \meta{cmd} to \meta{num} rounded to \meta{num digits} +% digits after the decimal character. +%\begin{macro}{\DTLround} +% \begin{macrocode} +\newcommand*{\DTLround}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPround{\@dtl@tmp}{\@dtl@numi}{#3}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLground} +% \begin{macrocode} +\newcommand*{\DTLground}[3]{% +\DTLround{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +% Sets \meta{cmd} to \meta{num} truncated to \meta{num digits} +% digits after the decimal character. +%\begin{macro}{\DTLtrunc} +% \begin{macrocode} +\newcommand*{\DTLtrunc}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPtrunc{\@dtl@tmp}{\@dtl@numi}{#3}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgtrunc} +% \begin{macrocode} +\newcommand*{\DTLgtrunc}[3]{% +\DTLtrunc{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLclip}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} to \meta{num} with all unnecessary 0's removed. +%\begin{macro}{\DTLclip} +% \begin{macrocode} +\newcommand*{\DTLclip}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPclip{\@dtl@tmp}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% Global version +%\begin{macro}{\DTLgclip} +% \begin{macrocode} +\newcommand*{\DTLgclip}[3]{% +\DTLclip{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\subsection{String Macros} +%\begin{definition} +%\cs{DTLinitials}\marg{string} +%\end{definition} +% Convert a string into initials. +%\begin{macro}{\DTLinitials} +% \begin{macrocode} +\newcommand*{\DTLinitials}[1]{% +\def\dtl@initialscmd{}% +\protected@edef\dtl@string{#1}% +\expandafter\dtl@initials\dtl@string{} \@nil +\dtl@initialscmd} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLstoreinitials}\marg{string}\marg{cmd} +%\end{definition} +% Convert a string into initials and store in \meta{cmd} +%\begin{macro}{\DTLstoreinitials} +% \begin{macrocode} +\newcommand*{\DTLstoreinitials}[2]{% +\def\dtl@initialscmd{}% +\protected@edef\dtl@string{#1}% +\expandafter\dtl@initials\dtl@string{} \@nil +\let#2=\dtl@initialscmd +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@initials} +% \begin{macrocode} +\def\dtl@initials#1#2 #3{% +\def\dtl@tmp{#3}% +\dtl@initialshyphen#2-{}\dtl@endhyp +\expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% +\toks@{#1}% +\ifx\dtl@inithyphen\@empty +\else + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@}% + \expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% + \expandafter\toks@\expandafter{\dtl@inithyphen}% +\fi +\ifx\@nnil\dtl@tmp + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLafterinitials}% + \let\dtl@initialsnext=\@gobble +\else + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLbetweeninitials}% + \let\dtl@initialsnext=\dtl@initials +\fi +\dtl@initialsnext#3} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@initialshyphen} +% \begin{macrocode} +\def\dtl@initialshyphen#1-#2#3\dtl@endhyp{% +\def\dtl@inithyphen{#2}% +\ifx\dtl@inithyphen\@empty +\else + \edef\dtl@inithyphen{\DTLafterinitialbeforehyphen-#2}% +\fi +} +% \end{macrocode} +%\end{macro} +% Define what to do after the final initial: +%\begin{macro}{\DTLafterinitials} +% \begin{macrocode} +\newcommand*{\DTLafterinitials}{.} +% \end{macrocode} +%\end{macro} +% Define what to do between initials: +%\begin{macro}{\DTLbetweeninitials} +% \begin{macrocode} +\newcommand*{\DTLbetweeninitials}{.} +% \end{macrocode} +%\end{macro} +% Define what to do before a hyphen: +%\begin{macro}{\DTLafterinitialbeforehyphen} +% \begin{macrocode} +\newcommand*{\DTLafterinitialbeforehyphen}{.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLifAllUpperCase} +% \begin{macrocode} +\newcommand*{\DTLifAllUpperCase}[3]{% +\protected@edef\dtl@tuc{#1}% +\expandafter\dtl@testifuppercase\dtl@tuc\@nil\relax +\if@dtl@condition#2\else#3\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifalluppercase} +% \begin{macrocode} +\def\dtl@testifuppercase#1#2{% +\def\dtl@argi{#1}% +\def\dtl@argii{#2}% +\def\dtl@tc@rest{}% +\ifx\dtl@argi\@nnil + \let\dtl@testifuppernext=\@nnil +\else + \ifx#1\protect + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \ifx\uppercase#1\relax + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + \else + \edef\dtl@tc@arg{\string#1}% + \expandafter\dtl@test@ifuppercase\dtl@tc@arg\end + \ifx\dtl@argii\@nnil + \let\dtl@testifuppernext=\dtl@testifcasenoop + \fi + \fi + \fi +\fi +\ifx\dtl@testifuppernext\relax + \edef\dtl@dotestifuppernext{% + \noexpand\dtl@testifuppercase}% +\else + \ifx\dtl@testifuppernext\@nnil + \edef\dtl@dotestifuppernext{#2}% + \else + \expandafter\toks@\expandafter{\dtl@tc@rest}% + \@dtl@toks{#2}% + \edef\dtl@dotestifuppernext{% + \noexpand\dtl@testifuppernext\the\toks@\the\@dtl@toks}% + \fi +\fi +\dtl@dotestifuppernext +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@test@ifalluppercase} +% \begin{macrocode} +\def\dtl@test@ifuppercase#1#2\end{% +\def\dtl@tc@rest{#2}% +\IfSubStringInString{\string\MakeUppercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax +}{% + \IfSubStringInString{\string\MakeTextUppercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + }{% + \edef\dtl@uccode{\the\uccode`#1}% + \edef\dtl@code{\number`#1}% + \ifnum\dtl@code=\dtl@uccode\relax + \@dtl@conditiontrue + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \ifnum\dtl@uccode=0\relax + \@dtl@conditiontrue + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \@dtl@conditionfalse + \let\dtl@testifuppernext=\dtl@testifcasenoop + \fi + \fi +}}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifcasenoop} +% \begin{macrocode} +\def\dtl@testifcasenoop#1\@nil{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLifAllLowerCase} +% \begin{macrocode} +\newcommand*{\DTLifAllLowerCase}[3]{% +\protected@edef\dtl@tlc{#1}% +\expandafter\dtl@testiflowercase\dtl@tlc\@nil\relax +\if@dtl@condition#2\else#3\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifalllowercase} +% \begin{macrocode} +\def\dtl@testiflowercase#1#2{% +\def\dtl@argi{#1}% +\def\dtl@argii{#2}% +\ifx\dtl@argi\@nnil + \let\dtl@testiflowernext=\@nnil +\else + \ifx#1\protect + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \ifx\lowercase#1\relax + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + \else + \edef\dtl@tc@arg{\string#1}% + \expandafter\dtl@test@iflowercase\dtl@tc@arg\end + \ifx\dtl@argii\@nnil + \let\dtl@testiflowernext=\dtl@testifcasenoop + \fi + \fi + \fi +\fi +\ifx\dtl@testiflowernext\relax + \edef\dtl@dotestiflowernext{% + \noexpand\dtl@testiflowercase}% +\else + \ifx\dtl@testiflowernext\@nnil + \edef\dtl@dotestiflowernext{#2}% + \else + \expandafter\toks@\expandafter{\dtl@tc@rest}% + \@dtl@toks{#2}% + \edef\dtl@dotestiflowernext{% + \noexpand\dtl@testiflowernext\the\toks@\the\@dtl@toks}% + \fi +\fi +\dtl@dotestiflowernext +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@test@ifalllowercase} +% \begin{macrocode} +\def\dtl@test@iflowercase#1#2\end{% +\def\dtl@tc@rest{#2}% +\IfSubStringInString{\string\MakeLowercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax +}{% + \IfSubStringInString{\string\MakeTextLowercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + }{% + \edef\dtl@lccode{\the\lccode`#1}% + \edef\dtl@code{\number`#1}% + \ifnum\dtl@code=\dtl@lccode\relax + \@dtl@conditiontrue + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \ifnum\dtl@lccode=0\relax + \@dtl@conditiontrue + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \@dtl@conditionfalse + \let\dtl@testiflowernext=\dtl@testifcasenoop + \fi + \fi +}}} +% \end{macrocode} +%\end{macro} +% +%\subsection{Saving a database to an external file} +% +%\begin{macro}{\@dtl@write} +% \begin{macrocode} +\newwrite\@dtl@write +% \end{macrocode} +%\end{macro} +%\begin{definition} +% \cs{DTLsavedb}\marg{db name}\marg{filename} +%\end{definition} +% Save a database as an ASCII data file using the separator +% and delimiter given by \cs{@dtl@separator} and \cs{@dtl@delimiter}. +%\begin{macro}{\DTLsavedb} +% \begin{macrocode} +\newcommand*{\DTLsavedb}[2]{% +\DTLifdbexists{#1}{% +\openout\@dtl@write=#2% +\edef\@dtl@keys{\csname dtlkeys@#1\endcsname}% +\def\@dtl@header{}% +\@for\@dtl@key:=\@dtl@keys\do{% +\expandafter\@dtl@toks\expandafter{\@dtl@header}% +\ifx\@dtl@header\@empty + \IfSubStringInString{\@dtl@separator}{\@dtl@key}{% + \protected@edef\@dtl@header{% + \@dtl@delimiter\@dtl@key\@dtl@delimiter}% + }{% + \protected@edef\@dtl@header{\@dtl@key}% + }% +\else + \IfSubStringInString{\@dtl@separator}{\@dtl@key}{% + \protected@edef\@dtl@header{\the\@dtl@toks\@dtl@separator + \@dtl@delimiter\@dtl@key\@dtl@delimiter}% + }{% + \protected@edef\@dtl@header{\the\@dtl@toks\@dtl@separator + \@dtl@key}% + }% +\fi +}% +\protected@write\@dtl@write{}{\@dtl@header}% +\expandafter\let\expandafter\@dtl@db\csname dtldb@#1\endcsname% +\@for\@dtl@currentrow:=\@dtl@db\do{% +\dtl@gathervalues{#1}{\@dtl@currentrow}% +\def\@dtl@outputrow{}% +\@for\@dtl@key:=\@dtl@keys\do{% +\protected@edef\@dtl@element{\csname @dtl@key@\@dtl@key\endcsname}% +\expandafter\@dtl@toks\expandafter{\@dtl@outputrow}% +\ifx\@dtl@outputrow\@empty + \IfSubStringInString{\@dtl@separator}{\@dtl@element}{% + \protected@edef\@dtl@outputrow{% + \@dtl@delimiter\@dtl@element\@dtl@delimiter}% + }{% + \protected@edef\@dtl@outputrow{\@dtl@element}% + }% +\else + \IfSubStringInString{\@dtl@separator}{\@dtl@element}{% + \protected@edef\@dtl@outputrow{\the\@dtl@toks\@dtl@separator + \@dtl@delimiter\@dtl@element\@dtl@delimiter}% + }{% + \protected@edef\@dtl@outputrow{\the\@dtl@toks\@dtl@separator + \@dtl@element}% + }% +\fi +}% +\protected@write\@dtl@write{}{\@dtl@outputrow}% +}% +\closeout\@dtl@write +}{% +\PackageError{datatool}{Database `#1' doesn't exist}{}% +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLsavetexdb}\marg{db name}\marg{filename} +%\end{definition} +% Save a database as a \LaTeX\ file. +%\begin{macro}{\DTLsavetexdb} +% \begin{macrocode} +\newcommand*{\DTLsavetexdb}[2]{% +\DTLifdbexists{#1}{% +\openout\@dtl@write=#2% +\edef\@dtl@keys{\csname dtlkeys@#1\endcsname}% +\protected@write\@dtl@write{}{\string\DTLnewdb{#1}}% +\expandafter\let\expandafter\@dtl@db\csname dtldb@#1\endcsname% +\@for\@dtl@currentrow:=\@dtl@db\do{% +\dtl@gathervalues{#1}{\@dtl@currentrow}% +\protected@write\@dtl@write{}{\string\DTLnewrow{#1}}% +\@for\@dtl@key:=\@dtl@keys\do{% +\protected@edef\@dtl@element{\csname @dtl@key@\@dtl@key\endcsname}% +\protected@write\@dtl@write{}{\string\DTLnewdbentry + {#1}{\@dtl@key}{\@dtl@element}}% +}% +}% +\closeout\@dtl@write +}{% +\PackageError{datatool}{Database `#1' doesn't exist}{}% +}} +% \end{macrocode} +%\end{macro} +% +%\subsection{Loading a database from an external file} +% +%\begin{macro}{\@dtl@read} +% \begin{macrocode} +\newread\@dtl@read +% \end{macrocode} +%\end{macro} +% Keep track of current column in data file +%\begin{macro}{\dtl@entrycr} +% \begin{macrocode} +\newcount\dtl@entrycr +% \end{macrocode} +%\end{macro} +%\begin{definition} +% \cs{DTLloaddb}\marg{db name}\marg{filename} +%\end{definition} +% Create a new database called \meta{db name}, and load the data in +% \meta{filename} into it. The separator and delimiter used in +% the file must match \cs{@dtl@separator} and \cs{@dtl@delimiter}. +%\begin{macro}{\DTLloaddb} +% \begin{macrocode} +\gdef\DTLloaddb#1#2{% +\IfFileExists{#2}{% +\begingroup +\catcode`\"12\relax +\openin\@dtl@read=#2% +\dtl@message{Reading `#2'}% +\DTLnewdb{#1}% +\ifeof\@dtl@read +\else + \loop + \@dtl@conditionfalse + \ifeof\@dtl@read + \else + \read\@dtl@read to \@dtl@line + \dtl@trim\@dtl@line + \if\@dtl@line\par + \@dtl@conditiontrue + \fi + \fi + \if@dtl@condition + \repeat + \ifeof\@dtl@read + \else + \protected@edef\@dtl@lin@{\@dtl@separator\@dtl@line\@dtl@separator}% + \@dtl@tmpcount=0\relax + \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% + \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key + \advance\@dtl@tmpcount by 1\relax + \expandafter\@dtl@toks\expandafter{\@dtl@key}% + \expandafter + \edef\csname @dtl@inky@\romannumeral\@dtl@tmpcount\endcsname{% + \the\@dtl@toks}% + }% + \ifeof\@dtl@read + \else + \@dtl@conditiontrue + \loop + \read\@dtl@read to \@dtl@line + \dtl@trim\@dtl@line + \ifthenelse{\equal{\@dtl@line}{}}{}% + {% + \DTLnewrow{#1}% + \expandafter\@dtl@toks\expandafter{\@dtl@line}% + \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks + \@dtl@separator}% + \dtl@entrycr=0\relax + \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% + \expandafter\@dtl@lopoff\@dtl@lin@\to + \@dtl@lin@\@dtl@thisentry + \advance\dtl@entrycr by 1\relax + \edef\@dtl@thiskey{% + \csname @dtl@inky@\romannumeral\dtl@entrycr\endcsname}% + \DTLnewdbentry{#1}{\@dtl@thiskey}{\@dtl@thisentry}% + }% + }% + \ifeof\@dtl@read \@dtl@conditionfalse\fi + \if@dtl@condition + \repeat + \fi + \fi +\fi +\closein\@dtl@read +\endgroup +}{% +\PackageError{datatool}{Can't load database `#1' (file `#2' +doesn't exist)}{}% +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@trim}\marg{line} +%\end{definition} +% Trims the trailing space from \meta{line}. +%\begin{macro}{\dtl@trim} +% \begin{macrocode} +\newcommand{\dtl@trim}[1]{% +\def\@dtl@trmstr{}% +\expandafter\@dtl@starttrim#1\@nil% +\let#1=\@dtl@trmstr +} +% \end{macrocode} +%\end{macro} +% Start trimming +%\begin{macro}{\@dtl@starttrim} +% \begin{macrocode} +\long\def\@dtl@starttrim#1#2{% +\ifx\par#1% + \def\@dtl@dotrim{\@dtl@trim{} #2}% +\else + \def\@dtl@dotrim{\@dtl@trim#1#2}% +\fi +\@dtl@dotrim% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@trim} +% \begin{macrocode} +\long\def\@dtl@trim#1 \@nil{\long\def\@dtl@trmstr{#1}} +% \end{macrocode} +%\end{macro} +% +% Load a raw database (substitutes "%" $\to$ "\%", +% "$" $\to$ "\$", "&" $\to$ "\&", "#" $\to$ "\#", +% "~" $\to$ "\textasciitilde", "_" $\to$ "\_" +% and "^" $\to$ "\textasciicircum".) +%\begin{macro}{\DTLloadrawdb} +% \begin{macrocode} +\gdef\DTLloadrawdb#1#2{% +\IfFileExists{#2}{% +\openin\@dtl@read=#2% +\dtl@message{Reading `#2'}% +\DTLnewdb{#1}% +\ifeof\@dtl@read +\else + \loop + \@dtl@conditionfalse + \ifeof\@dtl@read + \else + \@dtl@rawread\@dtl@read to\@dtl@line + \dtl@trim\@dtl@line + \if\@dtl@line\par + \@dtl@conditiontrue + \fi + \fi + \if@dtl@condition + \repeat + \ifeof\@dtl@read + \else + \dtl@domappings\@dtl@line + \protected@edef\@dtl@lin@{\@dtl@separator\@dtl@line\@dtl@separator}% + \@dtl@tmpcount=0\relax + \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% + \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key + \advance\@dtl@tmpcount by 1\relax + \expandafter\@dtl@toks\expandafter{\@dtl@key}% + \expandafter + \edef\csname @dtl@inky@\romannumeral\@dtl@tmpcount\endcsname{% + \the\@dtl@toks}% + }% + \ifeof\@dtl@read + \else + \@dtl@conditiontrue + \loop + \@dtl@rawread\@dtl@read to\@dtl@line + \dtl@trim\@dtl@line + \ifthenelse{\equal{\@dtl@line}{}}{}% + {% + \DTLnewrow{#1}% + \dtl@domappings\@dtl@line + \expandafter\@dtl@toks\expandafter{\@dtl@line}% + \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks + \@dtl@separator}% + \dtl@entrycr=0\relax + \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% + \expandafter\@dtl@lopoff\@dtl@lin@\to + \@dtl@lin@\@dtl@thisentry + \advance\dtl@entrycr by 1\relax + \edef\@dtl@thiskey{% + \csname @dtl@inky@\romannumeral\dtl@entrycr\endcsname}% + \DTLnewdbentry{#1}{\@dtl@thiskey}{\@dtl@thisentry}% + }% + }% + \ifeof\@dtl@read \@dtl@conditionfalse\fi + \if@dtl@condition + \repeat + \fi + \fi +\fi +\closein\@dtl@read +}{% +\PackageError{datatool}{Can't load database `#1' (file `#2' +doesn't exist)}{}% +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{@dtl@rawread}\meta{number}to\meta{cmd} +%\end{definition} +% Reads in a raw line from file given by \meta{number} +% converts special characters and stores in \meta{cmd} +%\begin{macro}{\@dtl@rawread} +% \begin{macrocode} +\begingroup +\catcode`\%=\active +\catcode`$=\active +\catcode`&=\active +\catcode`~=\active +\catcode`_=\active +\catcode`^=\active +\catcode`#=\active +\catcode`?=6\relax +\catcode`<=1\relax +\catcode`>=2\relax +\catcode`\{=\active +\catcode`\}=\active +\gdef\@dtl@rawread?1to?2<\relax +<<\catcode`\%=\active +\catcode`$=\active +\catcode`&=\active +\catcode`~=\active +\catcode`_=\active +\catcode`^=\active +\catcode`#=\active +\catcode`\{=\active +\catcode`\}=\active +\def%<\noexpand\%>\relax +\def$<\noexpand\$>\relax +\def&<\&>\relax +\def#<\#>\relax +\def~<\noexpand\textasciitilde>\relax +\def_<\noexpand\_>\relax +\def^<\noexpand\textasciicircum>\relax +\@dtl@activatebraces +\@dtl@doreadraw?1?2>>> +\gdef\@dtl@doreadraw?1?2<\relax +\read?1 to \tmp +\xdef?2<\tmp>\relax +> +\endgroup +% \end{macrocode} +%\end{macro} +% \cs{@dtl@activatebraces} resets braces for \cs{@dtl@rawread} +%\begin{macro}{\@dtl@activatebraces} +% \begin{macrocode} +\begingroup +\catcode`\{=\active +\catcode`\}=\active +\catcode`<=1\relax +\catcode`>=2\relax +\gdef\@dtl@activatebraces<% + \catcode`\{=\active + \catcode`\}=\active + \def{<\noexpand\{>% + \def}<\noexpand\}>% +>% +\endgroup +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLrawmap}\marg{string}\marg{replacement} +%\end{definition} +% Additional mappings to perform when reading a raw data file +%\begin{macro}{\DTLrawmap} +% \begin{macrocode} +\newcommand*{\DTLrawmap}[2]{% +\expandafter\@dtl@toks\expandafter{\@dtl@rawmappings}% +\ifx\@dtl@rawmappings\@empty + \def\@dtl@rawmappings{{#1}{#2}}% +\else + \def\@dtl@tmp{{#1}{#2}} + \protected@edef\@dtl@rawmappings{\the\@dtl@toks,\@dtl@tmp} +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@rawmappings} +% \begin{macrocode} +\newcommand*{\@dtl@rawmappings}{} +% \end{macrocode} +%\end{macro} +%\begin{definition} +% \cs{dtl@domappings}\marg{cmd} +%\end{definition} +% Do all mappings in string given by \meta{cmd}. +%\begin{macro}{\dtl@domappings} +% \begin{macrocode} +\newcommand*{\dtl@domappings}[1]{% +\@for\@dtl@map:=\@dtl@rawmappings\do{% + \expandafter\DTLsubstitute\expandafter#1\@dtl@map +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLsubstitute}\marg{cmd}\marg{original}\marg{replacement} +%\end{definition} +% Substitutes first occurence of \meta{original} with +% \marg{replacement} within the string given by \meta{cmd} +%\begin{macro}{\DTLsubstitute} +% \begin{macrocode} +\newcommand{\DTLsubstitute}[3]{% +\def\dtl@splitstr##1#2##2\@nil{% +\def\@dtl@beforepart{##1}% +\def\@dtl@afterpart{##2}% +\ifx\@dtl@afterpart\@empty + \let\@dtl@replaced=\@empty +\else + \def\@dtl@replaced{#2}% + \dtl@split@str##2\@nil +\fi +}% +\def\dtl@split@str##1#2\@nil{% +\def\@dtl@afterpart{##1}}% +\expandafter\dtl@splitstr#1#2\@nil +\ifx\@dtl@replaced\@empty +\else + \def#1{}% + \expandafter\@dtl@toks\expandafter{\@dtl@beforepart}% + \expandafter\toks@\expandafter{#1}% + \protected@edef#1{\the\toks@\the\@dtl@toks#3}% + \expandafter\@dtl@toks\expandafter{\@dtl@afterpart}% + \expandafter\toks@\expandafter{#1}% + \edef#1{\the\toks@\the\@dtl@toks}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLsubstituteall}\marg{cmd}\marg{original}\marg{replacement} +%\end{definition} +% Substitutes all occurences of \meta{original} with +% \marg{replacement} within the string given by \meta{cmd} +%\begin{macro}{\DTLsubstituteall} +% \begin{macrocode} +\newcommand{\DTLsubstituteall}[3]{% +\def\dtl@splitstr##1#2##2\@nil{% +\def\@dtl@beforepart{##1}\def\@dtl@afterpart{##2}}% +\let\@dtl@replaced=\@empty +\IfSubStringInString{#2}{#1}{% + \expandafter\dtl@splitstr#1\@nil + \expandafter\toks@\expandafter{#2}% + \edef\@dtl@replaced{\the\toks@}% + \def#1{}% + \@dtl@conditiontrue + \loop + \expandafter\@dtl@toks\expandafter{\@dtl@beforepart}% + \expandafter\toks@\expandafter{#1}% + \protected@edef#1{\the\toks@\the\@dtl@toks#3}% + \IfSubStringInString{#2}{\@dtl@afterpart}{% + \expandafter\dtl@splitstr\@dtl@afterpart\@nil + }{\@dtl@conditionfalse}% + \if@dtl@condition + \repeat + \expandafter\@dtl@toks\expandafter{\@dtl@afterpart}% + \expandafter\toks@\expandafter{#1}% + \edef#1{\the\toks@\the\@dtl@toks}% +}{}% +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Currencies} +% \cs{@dtl@currencies} stores all known currencies. +%\begin{macro}{\@dtl@currencies} +% \begin{macrocode} +\newcommand*{\@dtl@currencies}{\$,\pounds} +% \end{macrocode} +%\end{macro} +%\begin{definition} +% \cs{DTLaddcurrency}\marg{symbol} +%\end{definition} +% Adds \meta{symbol} to the list of known currencies +%\begin{macro}{\DTLnewcurrencysymbol} +% \begin{macrocode} +\newcommand*{\DTLnewcurrencysymbol}[1]{% +\expandafter\toks@\expandafter{\@dtl@currencies}% +\@dtl@toks{#1}% +\edef\@dtl@currencies{\the\@dtl@toks,\the\toks@}% +} +% \end{macrocode} +%\end{macro} +% If any of the following currency commands have been defined, +% add them to the list: +% \begin{macrocode} +\AtBeginDocument{% +\@ifundefined{texteuro}{}{\DTLnewcurrencysymbol{\texteuro}}% +\@ifundefined{textdollar}{}{\DTLnewcurrencysymbol{\textdollar}}% +\@ifundefined{textstirling}{}{\DTLnewcurrencysymbol{\textstirling}}% +\@ifundefined{textyen}{}{\DTLnewcurrencysymbol{\textyen}}% +\@ifundefined{textwon}{}{\DTLnewcurrencysymbol{\textwon}}% +\@ifundefined{textcurrency}{}{\DTLnewcurrencysymbol{\textcurrency}}% +\@ifundefined{euro}{}{\DTLnewcurrencysymbol{\euro}}% +\@ifundefined{yen}{}{\DTLnewcurrencysymbol{\yen}}% +} +% \end{macrocode} +%\begin{definition} +%\cs{@dtl@standardize@currency}\marg{cmd} +%\end{definition} +% Substitutes the first currency symbol found in \meta{cmd} +% with "\$". This is used when testing text to determine +% if it is currency. The original currency symbol is stored +% in \cs{@dtl@org@currency}, so that it can be replaced later. +% If no currency symbol is found, \cs{@dtl@org@currency} will +% be empty. +%\begin{macro}{\@dtl@standardize@currency} +% \begin{macrocode} +\newcommand{\@dtl@standardize@currency}[1]{% +\def\@dtl@org@currency{}% +\@for\@dtl@thiscurrency:=\@dtl@currencies\do{% + \expandafter\toks@\expandafter{\@dtl@thiscurrency}% + \edef\@dtl@dosubs{\noexpand\DTLsubstitute{\noexpand#1}% + {\the\toks@}{\noexpand\$}}% + \@dtl@dosubs + \ifx\@dtl@replaced\@empty + \else + \let\@dtl@org@currency=\@dtl@replaced + \@endfortrue + \fi +}% +\@endforfalse} +% \end{macrocode} +%\end{macro} +% +%\cs{@dtl@currency} is set by \cs{DTLlocaltodecimal} and +%\cs{@dtl@checknumerical}. It is used by \cs{DTLdecimaltocurrency}. +% Set to "\$" by default. +%\begin{macro}{\@dtl@currency} +% \begin{macrocode} +\newcommand*{\@dtl@currency}{\$} +% \end{macrocode} +%\end{macro} +%\cs{DTLsetdefaultcurrency}\marg{symbol} sets the default currency. +%\begin{macro}{\DTLsetdefaultcurrency} +% \begin{macrocode} +\newcommand*{\DTLsetdefaultcurrency}[1]{% +\renewcommand*{\@dtl@currency}{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@ifsingle}\marg{arg}\marg{true part}\marg{false part} +%\end{definition} +% If there is only one object in \meta{arg} (without expansion) +% do \meta{true part}, otherwise do false part. +%\begin{macro}{\dtl@ifsingle} +% \begin{macrocode} +\newcommand{\dtl@ifsingle}[3]{% +\@dtl@ifsingle#1\@nil{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@ifsingle} +% \begin{macrocode} +\def\@dtl@ifsingle#1#2\@nil#3#4{% +\def\dtl@sg@arg{#2}% +\ifx\dtl@sg@arg\@empty + #3% +\else + #4% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Debugging commands} +% These commands are provided to assist debugging +%\begin{definition} +%\cs{dtlshowdb}\marg{db name} +%\end{definition} +% Shows the database. +%\begin{macro}{\dtlshowdb} +% \begin{macrocode} +\newcommand*{\dtlshowdb}[1]{% +\expandafter\show\csname dtldb@#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtlshowdbkeys}\marg{db name} +%\end{definition} +% Shows the key list for the named database. +%\begin{macro}{\dtlshowdbkeys} +% \begin{macrocode} +\newcommand*{\dtlshowdbkeys}[1]{% +\expandafter\show\csname dtlkeys@#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtlshowtype}\marg{db name}\marg{key} +%\end{definition} +% Show the data type for given key in the named database. +% This should be an integer from 0 to 3. +%\begin{macro}{\dtlshowtype} +% \begin{macrocode} +\newcommand*{\dtlshowtype}[2]{% +\expandafter\show\csname @dtl@idtype@#1@#2\endcsname} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</datatool.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*datapie.sty> +% \end{macrocode} +%\fi +%\section{datapie.sty} +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datapie}[2007/07/23 v1.0 (NLCT)] +% \end{macrocode} +% Require \sty{xkeyval} package +% \begin{macrocode} +\RequirePackage{xkeyval} +% \end{macrocode} +% Define a conditional to determine whether to use colour or +% grey scale. +%\begin{macro}{\ifDTLcolorpiechart} +% \begin{macrocode} +\newif\ifDTLcolorpiechart +\DTLcolorpiecharttrue +% \end{macrocode} +%\end{macro} +% Package options to change the conditional: +% \begin{macrocode} +\DeclareOption{color}{\DTLcolorpiecharttrue} +\DeclareOption{gray}{\DTLcolorpiechartfalse} +% \end{macrocode} +% Define boolean keys to govern label rotations. +%\begin{macro}{\ifDTLrotateinner} +% \begin{macrocode} +\define@boolkey{datapie}[DTL]{rotateinner}[true]{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLrotateouter} +% \begin{macrocode} +\define@boolkey{datapie}[DTL]{rotateouter}[true]{} +% \end{macrocode} +%\end{macro} +% Set defaults: +% \begin{macrocode} +\DTLrotateinnerfalse +\DTLrotateouterfalse +% \end{macrocode} +% Package options to change \cs{DTLrotateinner} +% \begin{macrocode} +\DeclareOption{rotateinner}{\DTLrotateinnertrue} +\DeclareOption{norotateinner}{\DTLrotateinnerfalse} +% \end{macrocode} +% Package options to change \cs{DTLrotateouter} +% \begin{macrocode} +\DeclareOption{rotateouter}{\DTLrotateoutertrue} +\DeclareOption{norotateouter}{\DTLrotateouterfalse} +% \end{macrocode} +% Process options: +% \begin{macrocode} +\ProcessOptions +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{datatool} +\RequirePackage{tikz} +% \end{macrocode} +% Define some variables that govern the appearance of the pie +% chart. +% +% The radius of the pie chart: +%\begin{macro}{\DTLradius} +% \begin{macrocode} +\newlength\DTLradius +\DTLradius=2cm +% \end{macrocode} +%\end{macro} +% Inner label offset ratio +%\begin{macro}{\DTLinnerratio} +% \begin{macrocode} +\newcommand*{\DTLinnerratio}{0.5} +% \end{macrocode} +%\end{macro} +% Outer label offset ratio +%\begin{macro}{\DTLouterratio} +% \begin{macrocode} +\newcommand*{\DTLouterratio}{1.25} +% \end{macrocode} +%\end{macro} +% Cutaway offset ration +%\begin{macro}{\DTLcutawayratio} +% \begin{macrocode} +\newcommand*\DTLcutawayratio{0.2} +% \end{macrocode} +%\end{macro} +% The angle of the first segment +%\begin{macro}{\DTLstartangle} +% \begin{macrocode} +\newcommand*{\DTLstartangle}{0} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@inneroffset} +% \begin{macrocode} +\newlength\dtl@inneroffset +\dtl@inneroffset=\DTLinnerratio\DTLradius +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@outeroffset} +% \begin{macrocode} +\newlength\dtl@outeroffset +\dtl@outeroffset=\DTLouterratio\DTLradius +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@cutawayoffset} +% \begin{macrocode} +\newlength\dtl@cutawayoffset +\dtl@cutawayoffset=\DTLcutawayratio\DTLradius +% \end{macrocode} +%\end{macro} +% +% \cs{dtl@piecutaways} is a comma separated list of segments that +% need to be cut away from the pie chart. +%\begin{macro}{\dtl@piecutaways} +% \begin{macrocode} +\newcommand*{\dtl@piecutaways}{} +% \end{macrocode} +%\end{macro} +% \cs{dtl@innerlabel} specifies the label to appear inside +% the segment. By default this is the variable used to create +% the pie chart. +%\begin{macro}{\dtl@innerlabel} +% \begin{macrocode} +\def\dtl@innerlabel{\DTLpievariable}% +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@outerlabel} +% \begin{macrocode} +\def\dtl@outerlabel{}% +% \end{macrocode} +%\end{macro} +% \counterfmt{DTLpieroundvar} is a counter governing the number of digits +% to round to when using \cs{FPround}. +% \begin{macrocode} +\newcounter{DTLpieroundvar} +\setcounter{DTLpieroundvar}{1} +% \end{macrocode} +% +%\begin{definition} +%\cs{DTLdisplayinnerlabel}\marg{label} +%\end{definition} +% Command used to format the inner label. This just does the +% label by default. +%\begin{macro}{\DTLdisplayinnerlabel} +% \begin{macrocode} +\newcommand*{\DTLdisplayinnerlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLdisplayouterlabel}\marg{label} +%\end{definition} +% Command used to format the outer label. This just does the +% label by default. +%\begin{macro}{\DTLdisplayouterlabel} +% \begin{macrocode} +\newcommand*{\DTLdisplayouterlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLpiepercent} +% returns the percentage value of the current segment. +%\begin{macro}{\DTLpiepercent} +% \begin{macrocode} +\newcommand*{\DTLpiepercent}{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datapie}{Can't use + \string\DTLpiepercent\space outside + \string\DTLpiechart}{}% +\else + \csname dtl@piepercent@\romannumeral\@dtl@seg\endcsname +\fi} +% \end{macrocode} +%\end{macro} +% +% \cs{DTLpieatbegintikz} specifies any commands +% to apply at the start of the \env{tikzpicture} environment. +% By default it does nothing, but can be set +% to any of the \sty{pgf} package's transformation commands, e.g.\ +%\begin{verbatim} +%\renewcommand*{\DTLpieatbegintikz}{% +%\pgftransformcm{2}{0}{0}{1}{\pgforigin}} +%\end{verbatim} +%\begin{macro}{\DTLpieatbegintikz} +% \begin{macrocode} +\newcommand*{\DTLpieatbegintikz}{} +% \end{macrocode} +%\end{macro} +% +% \cs{DTLpieatendtikz} specifies any commands +% to apply at the end of the \env{tikzpicture} environment. +% By default it does nothing. +%\begin{macro}{\DTLpieatendtikz} +% \begin{macrocode} +\newcommand*{\DTLpieatendtikz}{} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLsetpiesegmentcolor}\marg{n}\marg{color} +%\end{definition} +% Assign colour name \meta{color} to the \meta{n}th segment. +%\begin{macro}{\DTLsetpiesegmentcolor} +% \begin{macrocode} +\newcommand*{\DTLsetpiesegmentcolor}[2]{% +\expandafter\def\csname dtlpie@segcol\romannumeral#1\endcsname{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLgetpiesegmentcolor}\marg{n} +%\end{definition} +% Get the colour specification for segment \meta{n} +%\begin{macro}{\DTLgetpiesegmentcolor} +% \begin{macrocode} +\newcommand*{\DTLgetpiesegmentcolor}[1]{% +\csname dtlpie@segcol\romannumeral#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLdopiesegmentcolor}\marg{n} +%\end{definition} +% Set the colour to that for segment \meta{n} +%\begin{macro}{\DTLdopiesegmentcolor} +% \begin{macrocode} +\newcommand*{\DTLdopiesegmentcolor}[1]{% +\expandafter\color\expandafter +{\csname dtlpie@segcol\romannumeral#1\endcsname}} +% \end{macrocode} +%\end{macro} +%\cs{DTLdocurrentpiesegmentcolor} +% sets the colour to that of the current segment. +%\begin{macro}{\DTLdocurrentpiesegmentcolor} +% \begin{macrocode} +\newcommand*{\DTLdocurrentpiesegmentcolor}{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datapie}{Can't use + \string\DTLdocurrentpiesegmentcolor\space outside + \string\DTLpiechart}{}% +\else + \expandafter\DTLdopiesegmentcolor\expandafter{% + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname}% +\fi} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLpieoutlinecolor} specifies what colour to draw the +% outline. +%\begin{macro}{\DTLpieoutlinecolor} +% \begin{macrocode} +\newcommand*{\DTLpieoutlinecolor}{black} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLpieoutlinewidth} specifies the line width of the outline: +% Outline is only drawn if the linewidth is greater than 0pt. +%\begin{macro}{\DTLpieoutlinewidth} +% \begin{macrocode} +\newlength\DTLpieoutlinewidth +\DTLpieoutlinewidth=0pt +% \end{macrocode} +%\end{macro} +% +% Set the default colours. If there are more than eight segments, +% more colours will need to be defined. +% \begin{macrocode} +\ifDTLcolorpiechart + \DTLsetpiesegmentcolor{1}{red} + \DTLsetpiesegmentcolor{2}{green} + \DTLsetpiesegmentcolor{3}{blue} + \DTLsetpiesegmentcolor{4}{yellow} + \DTLsetpiesegmentcolor{5}{magenta} + \DTLsetpiesegmentcolor{6}{cyan} + \DTLsetpiesegmentcolor{7}{orange} + \DTLsetpiesegmentcolor{8}{white} +\else + \DTLsetpiesegmentcolor{1}{black!15} + \DTLsetpiesegmentcolor{2}{black!25} + \DTLsetpiesegmentcolor{3}{black!35} + \DTLsetpiesegmentcolor{4}{black!45} + \DTLsetpiesegmentcolor{5}{black!55} + \DTLsetpiesegmentcolor{6}{black!65} + \DTLsetpiesegmentcolor{7}{black!75} + \DTLsetpiesegmentcolor{8}{black!85} +\fi +% \end{macrocode} +% Define keys for \cs{DTLpiechart} optional argument. +% Set the starting angle of the first segment. +% \begin{macrocode} +\define@key{datapie}{start}{\def\DTLstartangle{#1}} +% \end{macrocode} +% Set the radius of the pie chart (must be set prior to +% inneroffset and outeroffset keys.) +% \begin{macrocode} +\define@key{datapie}{radius}{\DTLradius=#1\relax +\dtl@inneroffset=\DTLinnerratio\DTLradius +\dtl@outeroffset=\DTLouterratio\DTLradius +\dtl@cutawayoffset=\DTLcutawayratio\DTLradius} +% \end{macrocode} +% Set the inner ratio. +% \begin{macrocode} +\define@key{datapie}{innerratio}{% +\def\DTLinnerratio{#1}% +\dtl@inneroffset=\DTLinnerratio\DTLradius} +% \end{macrocode} +% Set the outer ratio +% \begin{macrocode} +\define@key{datapie}{outerratio}{% +\def\DTLouterratio{#1}% +\dtl@outeroffset=\DTLouterratio\DTLradius} +% \end{macrocode} +% The cutaway offset ratio +% \begin{macrocode} +\define@key{datapie}{cutawayratio}{% +\def\DTLcutawayratio{#1}% +\dtl@cutawayoffset=\DTLcutawayratio\DTLradius} +% \end{macrocode} +% Set the inner offset as an absolute value (not dependent +% on the radius.) +% \begin{macrocode} +\define@key{datapie}{inneroffset}{% +\dtl@inneroffset=#1} +% \end{macrocode} +% Set the outer offset as an absolute value (not dependent +% on the radius.) +% \begin{macrocode} +\define@key{datapie}{outeroffset}{% +\dtl@outeroffset=#1} +% \end{macrocode} +% Set the cutaway offset as an absolute value (not dependent +% on the radius.) +% \begin{macrocode} +\define@key{datapie}{cutawayoffset}{% +\dtl@cutawayoffset=#1} +% \end{macrocode} +% List of cut away segments. +% \begin{macrocode} +\define@key{datapie}{cutaway}{% +\renewcommand*{\dtl@piecutaways}{#1}} +% \end{macrocode} +% Variable used to create the pie chart. (Must be a control +% sequence.) +% \begin{macrocode} +\define@key{datapie}{variable}{% +\def\DTLpievariable{#1}} +% \end{macrocode} +% Inner label +% \begin{macrocode} +\define@key{datapie}{innerlabel}{% +\def\dtl@innerlabel{#1}} +% \end{macrocode} +% Outer label +% \begin{macrocode} +\define@key{datapie}{outerlabel}{% +\def\dtl@outerlabel{#1}} +% \end{macrocode} +% +%\begin{definition} +% \cs{DTLpiechart}\oarg{conditions}\marg{option list}\marg{db name}\marg{assign list} +%\end{definition} +% Make a pie chart from data given in data base \meta{db name}, +% where \meta{assign list} is a comma-separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. \meta{option list} must +% include \texttt{variable}\texttt{=}\meta{cmd}, where \meta{cmd} +% is included in \meta{assign list}. The optional argument +% \meta{conditions} is the same as that for \cs{DTLforeach}. +%\begin{macro}{\DTLpiechart} +% \begin{macrocode} +\newcommand*{\DTLpiechart}[4][\boolean{true}]{% +{\let\DTLpievariable=\relax +\setkeys{datapie}{#2}% +\ifx\DTLpievariable\relax + \PackageError{datapie}{\string\DTLpiechart\space missing variable}{}% +\else +% \end{macrocode} +% Compute the total. +% \begin{macrocode} +\def\dtl@total{0}% +\DTLforeach[#1]{#3}{#4}{% +\let\dtl@oldtotal=\dtl@total +\expandafter\DTLconverttodecimal\expandafter + {\DTLpievariable}{\dtl@variable}% +\FPadd{\dtl@total}{\dtl@variable}{\dtl@total}% +}% +% \end{macrocode} +% Compute the angles +% \begin{macrocode} +\expandafter\DTLconverttodecimal\expandafter + {\DTLstartangle}{\@dtl@start}% +\DTLforeach[#1]{#3}{#4}{% +\expandafter\DTLconverttodecimal\expandafter + {\DTLpievariable}{\dtl@variable}% +\dtl@computeangles{% +\csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname}{% +\dtl@variable}% +\expandafter\@dtl@seg\expandafter= +\csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname% +\FPmul{\dtl@tmp}{\dtl@variable}{100}% +\let\dtl@old=\dtl@tmp +\FPdiv{\dtl@tmp}{\dtl@old}{\dtl@total}% +\expandafter\FPround +\csname dtl@piepercent@\romannumeral\@dtl@seg\endcsname\dtl@tmp +\c@DTLpieroundvar +}% +% \end{macrocode} +% Compute the offsets for each cut away segment +% \begin{macrocode} +\@for\dtl@row:=\dtl@piecutaways\do{% +\expandafter\@dtl@set@off\dtl@row-\relax +}% +% \end{macrocode} +% Set the starting angle +% \begin{macrocode} +\let\dtl@start=\DTLstartangle +% \end{macrocode} +% Do the pie chart +% \begin{macrocode} +\begin{tikzpicture} +\DTLpieatbegintikz +\DTLforeach[#1]{#3}{#4}{% +% \end{macrocode} +% Store the segment number in \cs{@dtl@seg} +% \begin{macrocode} +\expandafter\@dtl@seg\expandafter= +\csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname% +% \end{macrocode} +% Set the start angle. +% \begin{macrocode} +\edef\dtl@start{\csname dtl@sang@\romannumeral\@dtl@seg\endcsname}% +% \end{macrocode} +% Set the extent +% \begin{macrocode} +\edef\dtl@extent{\csname dtl@angle@\romannumeral\@dtl@seg\endcsname}% +% \end{macrocode} +% Compute the end angle +% \begin{macrocode} +\FPadd{\dtl@endangle}{\dtl@start}{\dtl@extent}% +% \end{macrocode} +% Compute the shift. +% \begin{macrocode} +\edef\dtl@angle{\csname dtl@cut@angle@\romannumeral\@dtl@seg\endcsname}% +\let\dtl@old=\dtl@angle +\dtl@truncatedecimal\dtl@angle +\ifnum\dtl@angle>180 + \FPsub{\dtl@angle}{\dtl@old}{360}% + \dtl@truncatedecimal\dtl@angle +\fi +\edef\dtl@cutlen{% +\csname dtl@cut@len@\romannumeral\@dtl@seg\endcsname} +\edef\@dtl@shift{(\dtl@angle:\dtl@cutlen)}% +% \end{macrocode} +% Compute the mid way angle. +% \begin{macrocode} +\FPmul{\dtl@angle}{\dtl@extent}{0.5}% +\FPadd{\dtl@midangle}{\dtl@angle}{\dtl@start}% +% \end{macrocode} +% Draw the segment. +% \begin{macrocode} +\begin{scope}[shift={\@dtl@shift}]% +\dtl@truncatedecimal\dtl@start +\dtl@truncatedecimal\dtl@endangle +\fill[color=\DTLgetpiesegmentcolor\@dtl@seg] (0,0) -- +(\dtl@start:\DTLradius) +arc (\dtl@start:\dtl@endangle:\DTLradius) -- cycle; +% \end{macrocode} +% Draw the outline if required: +% \begin{macrocode} +\ifdim\DTLpieoutlinewidth>0pt\relax +\draw[color=\DTLpieoutlinecolor,line width=\DTLpieoutlinewidth] +(0,0) -- (\dtl@start:\DTLradius) +arc (\dtl@start:\dtl@endangle:\DTLradius) -- cycle; +\fi +% \end{macrocode} +% Convert decimal to an integer +% \begin{macrocode} +\dtl@truncatedecimal\dtl@midangle +% \end{macrocode} +% Determine whether to rotate inner labels +% \begin{macrocode} +\ifDTLrotateinner +% \end{macrocode} +% If the mid way angle is between 90 and 270, the text will look +% upside-down, so adjust accordingly. +% \begin{macrocode} +\ifthenelse{\(\dtl@midangle > 90 \and \dtl@midangle < 270\) +\TE@or \dtl@midangle < -90}{% + \FPsub{\dtl@labelangle}{\dtl@midangle}{180}% + \dtl@truncatedecimal\dtl@labelangle + \edef\dtl@innernodeopt{anchor=east,rotate=\dtl@labelangle}% +}{% + \edef\dtl@innernodeopt{anchor=west,rotate=\dtl@midangle}% +}% +% \end{macrocode} +% Don't rotate inner labels +% \begin{macrocode} +\else + \edef\dtl@innernodeopt{anchor=center}% +\fi +% \end{macrocode} +% Determine whether to rotate outer labels +% \begin{macrocode} +\ifDTLrotateouter +% \end{macrocode} +% If the mid way angle is between 90 and 270, the text will look +% upside-down, so adjust accordingly. +% \begin{macrocode} +\ifthenelse{\(\dtl@midangle > 90 \and \dtl@midangle < 270\) +\TE@or \dtl@midangle < -90}{% + \FPsub{\dtl@labelangle}{\dtl@midangle}{180}% + \dtl@truncatedecimal\dtl@labelangle + \edef\dtl@outernodeopt{anchor=east,rotate=\dtl@labelangle}% +}{% + \edef\dtl@outernodeopt{anchor=west,rotate=\dtl@midangle}% +}% +% \end{macrocode} +% Don't rotate outer labels +% \begin{macrocode} +\else + \ifthenelse{\(\dtl@midangle<45\and\dtl@midangle>-45\) + \TE@or \dtl@midangle=45 + \TE@or \dtl@midangle>315}{% + % east quadrant + \edef\dtl@outernodeopt{anchor=west}% + }{% + \ifthenelse{\(\dtl@midangle<135\and\dtl@midangle>45\) + \TE@or \dtl@midangle=135}{% + % north quadrant + \edef\dtl@outernodeopt{anchor=south}% + }{% + \ifthenelse{\(\dtl@midangle<225\and\dtl@midangle>135\) + \TE@or \dtl@midangle=225 + \TE@or \dtl@midangle=-135 + \TE@or \dtl@midangle<-135}{% + % west quadrant + \edef\dtl@outernodeopt{anchor=east}% + }{% + \edef\dtl@outernodeopt{anchor=north}% + }% + } + } +\fi +% \end{macrocode} +% Draw inner and outer labels +% \begin{macrocode} +\edef\@dtl@dolabel{% +\noexpand\draw (\dtl@midangle:\the\dtl@inneroffset) +node[\dtl@innernodeopt]{% +\noexpand\DTLdisplayinnerlabel{\noexpand\dtl@innerlabel}};}% +\@dtl@dolabel +\edef\@dtl@dolabel{% +\noexpand\draw (\dtl@midangle:\the\dtl@outeroffset) +node[\dtl@outernodeopt]{% +\noexpand\DTLdisplayouterlabel{\noexpand\dtl@outerlabel}};}% +\@dtl@dolabel +\end{scope} +}% +\DTLpieatendtikz +\end{tikzpicture} +\fi +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@computeangles}\marg{n}\marg{variable} +%\end{definition} +% Compute the angles for segment \meta{n}. This sets +% \cs{dtl@sang@}\meta{n} (start angle), +% \cs{dtl@angle@}\meta{n} (extent angle), +% \cs{dtl@cut@angle@}\meta{n} (cut away angle) and +% \cs{dtl@cut@len@}\meta{n} (cut away length). +%\begin{macro}{\dtl@computeangles} +% \begin{macrocode} +\newcommand*{\dtl@computeangles}[2]{% +\FPifgt{\@dtl@start}{180}% +% if startangle > 180 + \let\dtl@old=\@dtl@start +% startangle = startangle - 360 + \FPsub{\@dtl@start}{\dtl@old}{360}% +\fi +\FPiflt{\@dtl@start}{-180}% +% if startangle < -180 + \let\dtl@old=\@dtl@start +% startangle = startangle + 360 + \FPadd{\@dtl@start}{\dtl@old}{360}% +\fi +\expandafter\edef\csname dtl@sang@\romannumeral#1\endcsname{% +\@dtl@start}% +\FPmul{\dtl@angle}{360}{#2}% +\let\dtl@old=\dtl@angle +\FPdiv{\dtl@angle}{\dtl@old}{\dtl@total}% +\expandafter\let\csname dtl@angle@\romannumeral#1\endcsname=\dtl@angle +\let\dtl@old=\@dtl@start +\FPadd{\@dtl@start}{\dtl@old}{\dtl@angle}% +\expandafter\def\csname dtl@cut@angle@\romannumeral#1\endcsname{0}% +\expandafter\def\csname dtl@cut@len@\romannumeral#1\endcsname{0cm}% +} +% \end{macrocode} +%\end{macro} +% +% Set the offset angles. +%\begin{macro}{\@dtl@set@off} +% \begin{macrocode} +\def\@dtl@set@off#1-#2\relax{% +\ifthenelse{\equal{#2}{}}{% +\@@dtl@set@off{#1}}{% +\@@dtl@set@offr#1-#2\relax}% +} +% \end{macrocode} +%\end{macro} +% Set offset for individual segment: +%\begin{macro}{\@@dtl@set@off} +% \begin{macrocode} +\newcommand*{\@@dtl@set@off}[1]{% +\edef\dtl@old{\csname dtl@angle@\romannumeral#1\endcsname}% +\FPmul{\dtl@angle}{\dtl@old}{0.5}% +\let\dtl@old=\dtl@angle +\edef\dtl@sang{\csname dtl@sang@\romannumeral#1\endcsname}% +\FPadd{\dtl@angle}{\dtl@old}{\dtl@sang}% +\expandafter\edef\csname dtl@cut@angle@\romannumeral#1\endcsname{% +\dtl@angle}% +\expandafter\edef\csname dtl@cut@len@\romannumeral#1\endcsname{% + \the\dtl@cutawayoffset} +} +% \end{macrocode} +%\end{macro} +% Define count register to keep track of segments +%\begin{macro}{\@dtl@seg} +% \begin{macrocode} +\newcount\@dtl@seg +% \end{macrocode} +%\end{macro} +% Set offset for a range of segments +%\begin{macro}{\@@dtl@setoffr} +% \begin{macrocode} +\def\@@dtl@set@offr#1-#2-\relax{% +\ifnum#1>#2\relax + \PackageError{datapie}{Segment ranges must go in ascending order}{% +Try #2-#1 instead of #1-#2}% +\else + \def\dtl@angle{0}% + \@dtl@seg=#1\relax + \whiledo{\not\(\@dtl@seg > #2\)}{% + \let\dtl@old=\dtl@angle + \edef\dtl@segang{\csname dtl@angle@\romannumeral\@dtl@seg\endcsname}% + \FPadd{\dtl@angle}{\dtl@old}{\dtl@segang}% + \advance\@dtl@seg by 1\relax + }% + \let\dtl@old=\dtl@angle + \FPmul{\dtl@angle}{\dtl@old}{0.5}% + \edef\dtl@sang{\csname dtl@sang@\romannumeral#1\endcsname}% + \let\dtl@old=\dtl@angle + \FPadd{\dtl@angle}{\dtl@old}{\dtl@sang}% + \@dtl@seg=#1\relax + \whiledo{\not\(\@dtl@seg > #2\)}{% + \expandafter + \let\csname dtl@cut@angle@\romannumeral\@dtl@seg\endcsname + =\dtl@angle + \expandafter + \edef\csname dtl@cut@len@\romannumeral\@dtl@seg\endcsname{% + \the\dtl@cutawayoffset} + \advance\@dtl@seg by 1\relax + }% +\fi +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</datapie.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*dataplot.sty> +% \end{macrocode} +%\fi +%\section{dataplot.sty} +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{dataplot}[2007/07/23 v1.0 (NLCT)] +% \end{macrocode} +% Required packages +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{tikz} +\RequirePackage{datatool} +% \end{macrocode} +% Load TikZ plot libraries +% \begin{macrocode} +\usetikzlibrary{plotmarks} +\usetikzlibrary{plothandlers} +% \end{macrocode} +%\begin{definition} +%\cs{DTLplotstream}\oarg{condition}\marg{db name}\marg{x key}\marg{y key} +%\end{definition} +% Add points to a stream from the database called \meta{db name} +% where the $x$ co-ordinates are given by the key \meta{x key} +% and the $y$ co-ordinates are given by the key \meta{y key}. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach} +%\begin{macro}{\DTLplotstream} +% \begin{macrocode} +\newcommand*{\DTLplotstream}[4][\boolean{true}]{% +\DTLforeach[#1]{#2}{\dtl@x=#3,\dtl@y=#4}{% +\DTLconverttodecimal{\dtl@x}{\dtl@decx}% +\DTLconverttodecimal{\dtl@y}{\dtl@decy}% +\pgfplotstreampoint{\pgfpointxy{\dtl@decx}{\dtl@decy}}}} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLplotmarks} contains a list of plot marks used by +%\cs{DTLplot}. +%\begin{macro}{\DTLplotmarks} +% \begin{macrocode} +\newcommand*{\DTLplotmarks}{% +\pgfuseplotmark{o},% +\pgfuseplotmark{x},% +\pgfuseplotmark{+},% +\pgfuseplotmark{square},% +\pgfuseplotmark{triangle},% +\pgfuseplotmark{diamond},% +\pgfuseplotmark{pentagon},% +\pgfuseplotmark{asterisk},% +\pgfuseplotmark{star}} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLplotmarkcolors} contains a list of the plot mark colours. +%\begin{macro}{\DTLplotmarkcolors} +% \begin{macrocode} +\newcommand*{\DTLplotmarkcolors}{% +red,% +green,% +blue,% +yellow,% +magenta,% +cyan,% +orange,% +black,% +gray} +% \end{macrocode} +%\end{macro} +%\cs{DTLplotlines} contains a list of dash patterns used by +%\cs{DLTplot}. +%\begin{macro}{\DTLplotlines} +% \begin{macrocode} +\newcommand*{\DTLplotlines}{% +\pgfsetdash{}{{0pt}},% solid line +\pgfsetdash{{10pt}{5pt}}{0pt},% +\pgfsetdash{{5pt}{5pt}}{0pt},% +\pgfsetdash{{1pt}{5pt}}{0pt},% +\pgfsetdash{{5pt}{5pt}{1pt}{5pt}}{0pt},% +\pgfsetdash{{1pt}{3pt}}{0pt},% +} +% \end{macrocode} +%\end{macro} +%\cs{DTLplotlinecolors} contains a list of the plot line colours. +%\begin{macro}{\DTLplotlinecolors} +% \begin{macrocode} +\newcommand*{\DTLplotlinecolors}{% +red,% +green,% +blue,% +yellow,% +magenta,% +cyan,% +orange,% +black,% +gray} +% \end{macrocode} +%\end{macro} +% +% The default total plot width is stored in the length +% \cs{dtlplotwidth} +%\begin{macro}{\DTLplotwidth} +% \begin{macrocode} +\newlength\DTLplotwidth +\setlength\DTLplotwidth{4in} +% \end{macrocode} +%\end{macro} +% +% The default total plot height is stored in the length +% \cs{dtlplotheight} +%\begin{macro}{\DTLplotheight} +% \begin{macrocode} +\newlength\DTLplotheight +\setlength\DTLplotheight{4in} +% \end{macrocode} +%\end{macro} +% +% The length of the tick marks is given by +%\begin{macro}{\DTLticklength} +% \begin{macrocode} +\newlength\DTLticklength +\setlength\DTLticklength{5pt} +% \end{macrocode} +%\end{macro} +% The length of the minor tick marks is given by +%\begin{macro}{\DTLminorticklength} +% \begin{macrocode} +\newlength\DTLminorticklength +\setlength\DTLminorticklength{2pt} +% \end{macrocode} +%\end{macro} +% The offset from the axis to the tick label is given by +%\begin{macro}{\DTLticklabeloffset} +% \begin{macrocode} +\newlength\DTLticklabeloffset +\setlength\DTLticklabeloffset{8pt} +% \end{macrocode} +%\end{macro} +% Length to store the height of the $x$ tick labels +%\begin{macro}{\dtl@xticlabelheight} +% \begin{macrocode} +\newlength\dtl@xticlabelheight +% \end{macrocode} +%\end{macro} +% Length to store the width of the $y$ tick labels +%\begin{macro}{\dtl@yticlabelwidth} +% \begin{macrocode} +\newlength\dtl@yticlabelwidth +% \end{macrocode} +%\end{macro} +% Suggested minimum distance between tick marks where the gap +% is not specified. +%\begin{macro}{\DTLmintickgap} +% \begin{macrocode} +\newlength\DTLmintickgap +\setlength\DTLmintickgap{20pt} +% \end{macrocode} +%\end{macro} +% Suggested minimum distance between minor tick marks where the gap +% is not specified. +%\begin{macro}{\DTLminminortickgap} +% \begin{macrocode} +\newlength\DTLminminortickgap +\setlength\DTLminminortickgap{5pt} +% \end{macrocode} +%\end{macro} +% Round $x$ tick labels to the number of digits given by +% the counter \counterfmt{DTLplotroundXvar}. +% \begin{macrocode} +\newcounter{DTLplotroundXvar} +\setcounter{DTLplotroundXvar}{2} +% \end{macrocode} +% Round $y$ tick labels to the number of digits given by +% the counter \counterfmt{DTLplotroundYvar}. +% \begin{macrocode} +\newcounter{DTLplotroundYvar} +\setcounter{DTLplotroundYvar}{2} +% \end{macrocode} +% Conditional to determine whether or not to display the $x$ axis +%\begin{macro}{\ifDTLxaxis} +% \begin{macrocode} +\newif\ifDTLxaxis +\DTLxaxistrue +% \end{macrocode} +%\end{macro} +% The style of the $x$ axis is just a solid line by default +%\begin{macro}{\DTLXAxisStyle} +% \begin{macrocode} +\newcommand*{\DTLXAxisStyle}{-} +% \end{macrocode} +%\end{macro} +% +% Conditional to determine whether or not to display the $y$ axis +%\begin{macro}{\ifDTLyaxis} +% \begin{macrocode} +\newif\ifDTLyaxis +\DTLyaxistrue +% \end{macrocode} +%\end{macro} +% The style of the $y$ axis is just a solid line by default +%\begin{macro}{\DTLYAxisStyle} +% \begin{macrocode} +\newcommand*{\DTLYAxisStyle}{-} +% \end{macrocode} +%\end{macro} +% The style of the major grid lines: +%\begin{macro}{\DTLmajorgridstyle} +% \begin{macrocode} +\newcommand*{\DTLmajorgridstyle}{color=gray,-} +% \end{macrocode} +%\end{macro} +% The style of the minor grid lines: +%\begin{macro}{\DTLminorgridstyle} +% \begin{macrocode} +\newcommand*{\DTLminorgridstyle}{color=gray,loosely dotted} +% \end{macrocode} +%\end{macro} +% +% Conditional to determine whether the $x$ tics should point in or +% out. +%\begin{macro}{\ifDTLxticsin} +% \begin{macrocode} +\newif\ifDTLxticsin +\DTLxticsintrue +% \end{macrocode} +%\end{macro} +% Conditional to determine whether the $y$ tics should point in or +% out. +%\begin{macro}{\ifDTLyticsin} +% \begin{macrocode} +\newif\ifDTLyticsin +\DTLyticsintrue +% \end{macrocode} +%\end{macro} +% Count register to determine the legend setting. +%\begin{macro}{\dtl@legendsetting} +% \begin{macrocode} +\newcount\dtl@legendsetting +% \end{macrocode} +%\end{macro} +% Gap between border of plot and legend is given by the +% lengths \cs{DTLlegendxoffset} and \cs{DTLlegendyoffset} +%\begin{macro}{\DTLlegendxoffset} +% \begin{macrocode} +\newlength\DTLlegendxoffset +\setlength\DTLlegendxoffset{10pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLlegendyoffset} +% \begin{macrocode} +\newlength\DTLlegendyoffset +\setlength\DTLlegendyoffset{10pt} +% \end{macrocode} +%\end{macro} +% Macro to display the legend: +%\begin{macro}{\DTLformatlegend} +% \begin{macrocode} +\newcommand*{\DTLformatlegend}[1]{% +\setlength{\fboxrule}{1.1pt}% +\fcolorbox{black}{white}{#1}} +% \end{macrocode} +%\end{macro} +% Conditional to specify whether or not to use markers +%\begin{macro}{\ifDTLshowmarkers} +% \begin{macrocode} +\newif\ifDTLshowmarkers +\DTLshowmarkerstrue +% \end{macrocode} +%\end{macro} +% Conditional to specify whether or not to use lines +%\begin{macro}{\ifDTLshowlines} +% \begin{macrocode} +\newif\ifDTLshowlines +\DTLshowlinesfalse +% \end{macrocode} +%\end{macro} +% Hook to insert stuff at the start of the \env{tikzpicture} +% environment (after the unit vectors have been set). +%\begin{macro}{\DTLplotatbegintikz} +% \begin{macrocode} +\newcommand*{\DTLplotatbegintikz}{} +% \end{macrocode} +%\end{macro} +% Hook to insert stuff at the end of the \env{tikzpicture} +% environment. +%\begin{macro}{\DTLplotatendtikz} +% \begin{macrocode} +\newcommand*{\DTLplotatendtikz}{} +% \end{macrocode} +%\end{macro} +% +% Plot settings. The database key for the $x$ value is +% given by the "x" setting: +% \begin{macrocode} +\define@key{dataplot}{x}{% +\def\dtl@xkey{#1}} +% \end{macrocode} +% The database key for the $y$ value is given by the "y" setting: +% \begin{macrocode} +\define@key{dataplot}{y}{% +\def\dtl@ykey{#1}} +% \end{macrocode} +% The list of plot mark colours is given by the "markcolors" setting. +% (This should be a comma separated list of colour names.) +% \begin{macrocode} +\define@key{dataplot}{markcolors}{% +\def\DTLplotmarkcolors{#1}} +% \end{macrocode} +% The list of plot line colours is given by the "linecolors" setting. +% (This should be a comma separated list of colour names.) +% \begin{macrocode} +\define@key{dataplot}{linecolors}{% +\def\DTLplotlinecolors{#1}} +% \end{macrocode} +% The list of plot mark and line colours is given by the "colors" +% setting. (This should be a comma separated list of colour names.) +% \begin{macrocode} +\define@key{dataplot}{colors}{% +\def\DTLplotmarkcolors{#1}% +\def\DTLplotlinecolors{#1}} +% \end{macrocode} +% The list of plot marks is given by the "marks" setting. (This +% should be a comma separated list of code that generates +% pgf plot marks.) +% \begin{macrocode} +\define@key{dataplot}{marks}{% +\def\DTLplotmarks{#1}} +% \end{macrocode} +% The list of plot line styles is given by the "lines" setting. (This +% should be a comma separated list of code that sets the line +% style.) An empty set will create solid lines. +% \begin{macrocode} +\define@key{dataplot}{lines}{% +\def\DTLplotlines{#1}} +% \end{macrocode} +% The total width of the plot is given by the "width" setting. +% \begin{macrocode} +\define@key{dataplot}{width}{% +\setlength\DTLplotwidth{#1}} +% \end{macrocode} +% The total height of the plot is given by the "height" setting. +% \begin{macrocode} +\define@key{dataplot}{height}{% +\setlength\DTLplotheight{#1}} +% \end{macrocode} +% Determine whether to show lines, markers or both +% \begin{macrocode} +\define@choicekey{dataplot}{style}[\val\nr]{both,lines,markers}{% +\ifcase\nr\relax + \DTLshowlinestrue + \DTLshowmarkerstrue +\or + \DTLshowlinestrue + \DTLshowmarkersfalse +\or + \DTLshowmarkerstrue + \DTLshowlinesfalse +\fi} +% \end{macrocode} +% Determine whether or not to display the axes +% \begin{macrocode} +\define@choicekey{dataplot}{axes}[\val\nr]{both,x,y,none}[both]{% +\ifcase\nr\relax + % both + \DTLxaxistrue + \DTLxticstrue + \DTLyaxistrue + \DTLyticstrue +\or % x + \DTLxaxistrue + \DTLxticstrue + \DTLyaxisfalse + \DTLyticsfalse +\or % y + \DTLxaxisfalse + \DTLxticsfalse + \DTLyaxistrue + \DTLyticstrue +\or % none + \DTLxaxisfalse + \DTLxticsfalse + \DTLyaxisfalse + \DTLyticsfalse +\fi +} +% \end{macrocode} +% Enclose plot in a box +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{box}[true]{} +\DTLboxfalse +% \end{macrocode} +% Condition to determine whether to show the $x$ tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{xtics}[true]{} +\DTLxticstrue +% \end{macrocode} +% Condition to determine whether to show the $y$ tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{ytics}[true]{} +\DTLyticstrue +% \end{macrocode} +% Condition to determine whether to show the $x$ minor tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{xminortics}[true]{% +\ifDTLxminortics \DTLxticstrue\fi} +\DTLxminorticsfalse +% \end{macrocode} +% Condition to determine whether to show the $y$ minor tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{yminortics}[true]{% +\ifDTLyminortics \DTLyticstrue\fi} +\DTLyminorticsfalse +% \end{macrocode} +% Determine whether to draw the grid +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{grid}[true]{} +% \end{macrocode} +% Determine whether the $x$ tick marks should point +% in or out +% \begin{macrocode} +\define@choicekey{dataplot}{xticdir}[\val\nr]{in,out}{% +\ifcase\nr\relax + \DTLxticsintrue +\or + \DTLxticsinfalse +\fi +} +% \end{macrocode} +% Determine whether the $y$ tick marks should point +% in or out +% \begin{macrocode} +\define@choicekey{dataplot}{yticdir}[\val\nr]{in,out}{% +\ifcase\nr\relax + \DTLyticsintrue +\or + \DTLyticsinfalse +\fi +} +% \end{macrocode} +% Determine whether the $x$ and $y$ tick marks should point +% in or out +% \begin{macrocode} +\define@choicekey{dataplot}{ticdir}[\val\nr]{in,out}{% +\ifcase\nr\relax + \DTLxticsintrue + \DTLyticsintrue +\or + \DTLxticsinfalse + \DTLyticsinfalse +\fi +} +% \end{macrocode} +% Set the bounds of the graph (value must be in the form +% \meta{min x}","\meta{min y}","\meta{max x}","\meta{max y} +% (bounds overrides minx, miny, maxx and maxy settings.) +% \begin{macrocode} +\define@key{dataplot}{bounds}{% +\def\dtl@bounds{#1}} +\let\dtl@bounds=\relax +% \end{macrocode} +% Set only the lower $x$ bound +% \begin{macrocode} +\define@key{dataplot}{minx}{% +\def\dtl@minx{#1}} +\let\dtl@minx=\relax +% \end{macrocode} +% Set only the upper $x$ bound: +% \begin{macrocode} +\define@key{dataplot}{maxx}{% +\def\dtl@maxx{#1}} +\let\dtl@maxx=\relax +% \end{macrocode} +% Set only the lower $y$ bound: +% \begin{macrocode} +\define@key{dataplot}{miny}{% +\def\dtl@miny{#1}} +\let\dtl@miny=\relax +% \end{macrocode} +% Set only the upper $y$ bound: +% \begin{macrocode} +\define@key{dataplot}{maxy}{% +\def\dtl@maxy{#1}} +\let\dtl@maxy=\relax +% \end{macrocode} +% Define list of points for $x$ ticks. (Must be a comma separated +% list of decimal numbers.) +% \begin{macrocode} +\define@key{dataplot}{xticpoints}{% +\def\dtl@xticlist{#1}\DTLxticstrue\DTLxaxistrue} +\let\dtl@xticlist=\relax +% \end{macrocode} +% Define list of points for $y$ ticks. (Must be a comma separated +% list of decimal numbers.) +% \begin{macrocode} +\define@key{dataplot}{yticpoints}{% +\def\dtl@yticlist{#1}\DTLyticstrue\DTLyaxistrue} +\let\dtl@yticlist=\relax +% \end{macrocode} +% Define a the gap between $x$ tick marks (xticpoints overrides +% xticgap) +% \begin{macrocode} +\define@key{dataplot}{xticgap}{\def\dtl@xticgap{#1}% +\DTLxticstrue\DTLxaxistrue} +\let\dtl@xticgap=\relax +% \end{macrocode} +% Define a the gap between $y$ tick marks (yticpoints overrides +% yticgap) +% \begin{macrocode} +\define@key{dataplot}{yticgap}{\def\dtl@yticgap{#1}% +\DTLyticstrue\DTLyaxistrue} +\let\dtl@yticgap=\relax +% \end{macrocode} +% Define comma separated list of labels for $x$ ticks. +% \begin{macrocode} +\define@key{dataplot}{xticlabels}{% +\def\dtl@xticlabels{#1}\DTLxticstrue\DTLxaxistrue} +\let\dtl@xticlabels=\relax +% \end{macrocode} +% Define comma separated list of labels for $y$ ticks. +% \begin{macrocode} +\define@key{dataplot}{yticlabels}{% +\def\dtl@yticlabels{#1}\DTLyticstrue\DTLyaxistrue} +\let\dtl@yticlabels=\relax +% \end{macrocode} +% Define $x$ axis label +% \begin{macrocode} +\define@key{dataplot}{xlabel}{% +\def\dtl@xlabel{#1}} +\let\dtl@xlabel=\relax +% \end{macrocode} +% Define $y$ axis label +% \begin{macrocode} +\define@key{dataplot}{ylabel}{% +\def\dtl@ylabel{#1}} +\let\dtl@ylabel=\relax +% \end{macrocode} +% The legend setting may be one of: "none" (don't show it), +% "north", "northeast", "east", "southeast", "south", "southwest", +% "west", or "northwest". These set the count register +% \cs{dtl@legendsetting}. +% \begin{macrocode} +\define@choicekey{dataplot}{legend}[\val\nr]{none,north,northeast,% +east,southeast,south,southwest,west,northwest}[northeast]{% +\dtl@legendsetting=\nr\relax +} +% \end{macrocode} +% Legend labels (comma separated list). If omitted, the database +% name is used. +% \begin{macrocode} +\define@key{dataplot}{legendlabels}{\def\dtl@legendlabels{#1}} +% \end{macrocode} +% +% Temporary length: +%\begin{macro}{\dtl@tmplength} +% \begin{macrocode} +\newlength\dtl@tmplength +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLplot}\oarg{condition}\marg{db list}\marg{settings} +%\end{definition} +% Creates a plot (inside a \env{tikzpicture} environment) of all +% the data given in the databases listed in \meta{db list}. +%\begin{macro}{\DTLplot} +% \begin{macrocode} +\newcommand*{\DTLplot}[3][\boolean{true}]{{% +\let\dtl@xkey=\relax +\let\dtl@ykey=\relax +\let\dtl@legendlabels=\relax +\setkeys{dataplot}{#3}% +\let\dtl@plotmarklist=\DTLplotmarks +\let\dtl@plotlinelist=\DTLplotlines +\let\dtl@plotmarkcolorlist=\DTLplotmarkcolors +\let\dtl@plotlinecolorlist=\DTLplotlinecolors +\def\dtl@legend{}% +\ifx\dtl@legendlabels\relax + \edef\dtl@legendlabels{#2}% +\fi +\ifx\dtl@xkey\relax + \PackageError{dataplot}{Missing x setting for + \string\DTLplot}{}% +\else + \ifx\dtl@ykey\relax + \PackageError{dataplot}{Missing y setting for + \string\DTLplot}{}% + \else +% \end{macrocode} +% If user didn't specified bounds, +% compute the maximum and minimum $x$ and $y$ values over +% all the databases listed. +% \begin{macrocode} + \ifx\dtl@bounds\relax + \DTLcomputebounds[#1]{#2}{\dtl@xkey}{\dtl@ykey} + {\DTLminX}{\DTLminY}{\DTLmaxX}{\DTLmaxY}% + \ifx\dtl@minx\relax + \else + \let\DTLminX=\dtl@minx + \fi + \ifx\dtl@maxx\relax + \else + \let\DTLmaxX=\dtl@maxx + \fi + \ifx\dtl@miny\relax + \else + \let\DTLminY=\dtl@miny + \fi + \ifx\dtl@maxy\relax + \else + \let\DTLmaxY=\dtl@maxy + \fi +% \end{macrocode} +% Otherwise extract information from \cs{dtl@bounds} +% \begin{macrocode} + \else + \expandafter\dtl@getbounds\dtl@bounds\@nil + \fi +% \end{macrocode} +% Determine scaling factors. +% \begin{macrocode} + \@dtl@tmpcount=\DTLplotwidth + \FPsub{\dtl@dx}{\DTLmaxX}{\DTLminX}% + \FPdiv{\dtl@unit@x}{\number\@dtl@tmpcount}{\dtl@dx}% + \@dtl@tmpcount=\DTLplotheight + \FPsub{\dtl@dy}{\DTLmaxY}{\DTLminY}% + \FPdiv{\dtl@unit@y}{\number\@dtl@tmpcount}{\dtl@dy}% +% \end{macrocode} +% If x tics specified, construct a list of x tic points if not +% already specified. +% \begin{macrocode} + \ifDTLxtics + \ifx\dtl@xticlist\relax + \ifx\dtl@xticgap\relax + \dtl@constructticklist\DTLminX\DTLmaxX + \dtl@unit@x\dtl@xticlist + \else + \DTLifFPopenbetween{0}{\DTLminX}{\DTLmaxX}{% + \dtl@constructticklistwithgapz + \DTLminX\DTLmaxX\dtl@xticlist\dtl@xticgap}{% + \dtl@constructticklistwithgap + \DTLminX\DTLmaxX\dtl@xticlist\dtl@xticgap}% + \fi + \fi +% \end{macrocode} +% Construct a list of $x$ minor tick points if required +% \begin{macrocode} + \let\dtl@xminorticlist\@empty + \ifDTLxminortics + \let\dtl@prevtick=\relax + \@for\dtl@nexttick:=\dtl@xticlist\do{% + \ifx\dtl@prevtick\relax + \else + \dtl@constructminorticklist + \dtl@prevtick\dtl@nexttick\dtl@unit@x\dtl@xminorticlist + \fi + \let\dtl@prevtick=\dtl@nexttick + }% + \fi +% \end{macrocode} +% Determine the height of the $x$ tick labels. +% \begin{macrocode} + \ifx\dtl@xticlabels\relax + \settoheight{\dtl@xticlabelheight}{\dtl@xticlist}% + \else + \settoheight{\dtl@xticlabelheight}{\dtl@xticlabels}% + \fi + \else + \setlength{\dtl@xticlabelheight}{0pt}% + \fi +% \end{macrocode} +% If y tics specified, construct a list of y tic points if not +% already specified. +% \begin{macrocode} + \setlength{\dtl@yticlabelwidth}{0pt}% + \ifDTLytics + \ifx\dtl@yticlist\relax + \ifx\dtl@yticgap\relax + \dtl@constructticklist\DTLminY\DTLmaxY + \dtl@unit@y\dtl@yticlist + \else + \DTLifFPopenbetween{0}{\DTLminY}{\DTLmaxY}{% + \dtl@constructticklistwithgapz + \DTLminY\DTLmaxY\dtl@yticlist\dtl@yticgap}{% + \dtl@constructticklistwithgap + \DTLminY\DTLmaxY\dtl@yticlist\dtl@yticgap}% + \fi + \fi +% \end{macrocode} +% Construct a list of $y$ minor tick points if required +% \begin{macrocode} + \let\dtl@yminorticlist\@empty + \ifDTLyminortics + \let\dtl@prevtick=\relax + \@for\dtl@nexttick:=\dtl@yticlist\do{% + \ifx\dtl@prevtick\relax + \else + \dtl@constructminorticklist + \dtl@prevtick\dtl@nexttick\dtl@unit@y\dtl@yminorticlist + \fi + \let\dtl@prevtick=\dtl@nexttick + }% + \fi +% \end{macrocode} +% Determine the width of the $y$ tick labels. +% \begin{macrocode} + \ifx\dtl@ylabel\relax + \else + \ifx\dtl@yticlabels\relax + \@for\dtl@thislabel:=\dtl@yticlist\do{% + \FPround{\dtl@thislabel}{\dtl@thislabel} + {\c@DTLplotroundYvar}% + \settowidth{\dtl@tmplength}{\dtl@thislabel}% + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \else + \@for\dtl@thislabel:=\dtl@yticlabels\do{% + \settowidth{\dtl@tmplength}{\dtl@thislabel}% + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \fi + \fi +% \end{macrocode} +% Start the picture. +% \begin{macrocode} + \begin{tikzpicture} +% \end{macrocode} +% Set the $x$ and $y$ unit vectors. +% \begin{macrocode} + \pgfsetxvec{\pgfpoint{\dtl@unit@x sp}{0pt}}% + \pgfsetyvec{\pgfpoint{0pt}{\dtl@unit@y sp}}% +% \end{macrocode} +% Add any extra information the user requires +% \begin{macrocode} + \DTLplotatbegintikz +% \end{macrocode} +% Determine whether to put a box around the plot +% \begin{macrocode} + \ifDTLbox + \draw (\DTLminX,\DTLminY) -- (\DTLmaxX,\DTLminY) -- + (\DTLmaxX,\DTLmaxY) -- (\DTLminX,\DTLmaxY) -- + cycle; + \else +% \end{macrocode} +% Plot $x$ axis if required. +% \begin{macrocode} + \ifDTLxaxis + \expandafter\draw\expandafter[\DTLXAxisStyle] + (\DTLminX,\DTLminY) -- (\DTLmaxX,\DTLminY); + \fi +% \end{macrocode} +% Plot $y$ axis if required. +% \begin{macrocode} + \ifDTLyaxis + \expandafter\draw\expandafter[\DTLYAxisStyle] + (\DTLminX,\DTLminY) -- (\DTLminX,\DTLmaxY); + \fi + \fi +% \end{macrocode} +% Plot grid if required +% \begin{macrocode} + \ifDTLgrid + \ifDTLxminortics + \@for\dtl@thistick:=\dtl@xminorticlist\do{% + \expandafter\draw\expandafter[\DTLminorgridstyle] + (\dtl@thistick,\DTLminY) -- (\dtl@thistick,\DTLmaxY); + }% + \fi + \ifDTLyminortics + \@for\dtl@thistick:=\dtl@yminorticlist\do{% + \expandafter\draw\expandafter[\DTLminorgridstyle] + (\DTLminX,\dtl@thistick) -- (\DTLmaxX,\dtl@thistick); + }% + \fi + \@for\dtl@thistick:=\dtl@xticlist\do{% + \expandafter\draw\expandafter[\DTLmajorgridstyle] + (\dtl@thistick,\DTLminY) -- (\dtl@thistick,\DTLmaxY); + }% + \@for\dtl@thistick:=\dtl@yticlist\do{% + \expandafter\draw\expandafter[\DTLmajorgridstyle] + (\DTLminX,\dtl@thistick) -- (\DTLmaxX,\dtl@thistick); + }% + \fi +% \end{macrocode} +% Plot $x$ tics if required. +% \begin{macrocode} + \ifDTLxtics + \addtolength\dtl@xticlabelheight{\DTLticklabeloffset}% + \@for\dtl@thistick:=\dtl@xticlist\do{% + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{\DTLminY}} + \ifDTLxticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLminY}} + {\pgfpoint{0pt}{\DTLticklength}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLminY}} + {\pgfpoint{0pt}{-\DTLticklength}}} + \fi + \ifDTLbox + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{\DTLmaxY}} + \ifDTLxticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLmaxY}} + {\pgfpoint{0pt}{-\DTLticklength}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLmaxY}} + {\pgfpoint{0pt}{\DTLticklength}}} + \fi + \fi + \pgfusepath{stroke}% +% \end{macrocode} +% Plot the tick labels +% \begin{macrocode} + \ifx\dtl@xticlabels\relax + \FPround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLplotroundXvar}% + \else + \dtl@chopfirst\dtl@xticlabels\dtl@thislabel\dtl@rest + \let\dtl@xticlabels=\dtl@rest + \fi + \pgftext[base,center,at={\pgfpointadd + {\pgfpointxy{\dtl@thistick}{\DTLminY}} + {\pgfpoint{0pt}{-\dtl@xticlabelheight}}}] + {\dtl@thislabel} + }% + \fi +% \end{macrocode} +% Plot $x$ label if required. +% \begin{macrocode} + \ifx\dtl@xlabel\relax + \else + \addtolength{\dtl@xticlabelheight}{\baselineskip}% + \setlength{\dtl@tmplength}{0.5\DTLplotwidth} + \pgftext[base,center,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLminY}}% + {\pgfpoint{\dtl@tmplength}{-\dtl@xticlabelheight}}}]{% + \dtl@xlabel} + \fi +% \end{macrocode} +% Plot the $x$ minor ticks if required +% \begin{macrocode} + \ifDTLxminortics + \@for\dtl@thistick:=\dtl@xminorticlist\do{% + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{\DTLminY}} + \ifDTLxticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLminY}} + {\pgfpoint{0pt}{\DTLminorticklength}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLminY}} + {\pgfpoint{0pt}{-\DTLminorticklength}}} + \fi + \ifDTLbox + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{\DTLmaxY}} + \ifDTLxticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLmaxY}} + {\pgfpoint{0pt}{-\DTLminorticklength}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{\DTLmaxY}} + {\pgfpoint{0pt}{\DTLminorticklength}}} + \fi + \fi + }% + \fi +% \end{macrocode} +% Plot $y$ tics if required. +% \begin{macrocode} + \ifDTLytics + \@for\dtl@thistick:=\dtl@yticlist\do{% + \pgfpathmoveto{\pgfpointxy{\DTLminX}{\dtl@thistick}} + \ifDTLyticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLminX}{\dtl@thistick}} + {\pgfpoint{\DTLticklength}{0pt}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLminX}{\dtl@thistick}} + {\pgfpoint{-\DTLticklength}{0pt}}} + \fi + \ifDTLbox + \pgfpathmoveto{\pgfpointxy{\DTLmaxX}{\dtl@thistick}} + \ifDTLyticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLmaxX}{\dtl@thistick}} + {\pgfpoint{-\DTLticklength}{0pt}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLmaxX}{\dtl@thistick}} + {\pgfpoint{\DTLticklength}{0pt}}} + \fi + \fi + \pgfusepath{stroke} +% \end{macrocode} +% Plot the $y$ tick labels if required +% \begin{macrocode} + \ifx\dtl@yticlabels\relax + \FPround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLplotroundYvar}% + \else + \dtl@chopfirst\dtl@yticlabels\dtl@thislabel\dtl@rest + \let\dtl@yticlabels=\dtl@rest + \fi + \pgftext[right,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\dtl@thistick}} + {\pgfpoint{-\DTLticklabeloffset}{0pt}}}] + {\dtl@thislabel} + }% + \fi +% \end{macrocode} +% Plot $y$ label if required. +% \begin{macrocode} + \ifx\dtl@ylabel\relax + \else + \addtolength{\dtl@yticlabelwidth}{\baselineskip}% + \setlength{\dtl@tmplength}{0.5\DTLplotheight} + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLminY}}% + {\pgfpoint{-\dtl@yticlabelwidth}{\dtl@tmplength}}}, + rotate=90]{% + \dtl@ylabel} + \fi +% \end{macrocode} +% Plot the $y$ minor ticks if required +% \begin{macrocode} + \ifDTLyminortics + \@for\dtl@thistick:=\dtl@yminorticlist\do{% + \pgfpathmoveto{\pgfpointxy{\DTLminX}{\dtl@thistick}} + \ifDTLyticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLminX}{\dtl@thistick}} + {\pgfpoint{\DTLminorticklength}{0pt}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLminX}{\dtl@thistick}} + {\pgfpoint{-\DTLminorticklength}{0pt}}} + \fi + \ifDTLbox + \pgfpathmoveto{\pgfpointxy{\DTLmaxX}{\dtl@thistick}} + \ifDTLyticsin + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLmaxX}{\dtl@thistick}} + {\pgfpoint{-\DTLminorticklength}{0pt}}} + \else + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\DTLmaxX}{\dtl@thistick}} + {\pgfpoint{\DTLminorticklength}{0pt}}} + \fi + \fi + \pgfusepath{stroke} + }% + \fi +% \end{macrocode} +% Iterate through each database +% \begin{macrocode} + \@for\dtl@thisdb:=#2\do{% +% \end{macrocode} +% Get the current plot mark colour. +% \begin{macrocode} + \ifx\dtl@plotmarkcolorlist\@empty + \let\dtl@plotmarkcolorlist=\DTLplotmarkcolors + \fi + \dtl@chopfirst\dtl@plotmarkcolorlist\dtl@thisplotmarkcolor + \dtl@remainder + \let\dtl@plotmarkcolorlist=\dtl@remainder +% \end{macrocode} +% Get the current plot mark, and store in \cs{dtl@mark} +% \begin{macrocode} + \ifDTLshowmarkers + \ifx\dtl@plotmarklist\@empty + \let\dtl@plotmarklist=\DTLplotmarks + \fi + \dtl@chopfirst\dtl@plotmarklist\dtl@thisplotmark + \dtl@remainder + \let\dtl@plotmarklist=\dtl@remainder + \ifx\dtl@thisplotmark\relax + \let\dtl@mark=\relax + \else + \expandafter\toks@\expandafter{\dtl@thisplotmark}% + \ifx\dtl@thisplotmarkcolor\@empty + \edef\dtl@mark{\the\toks@}% + \else + \edef\dtl@mark{% + \noexpand\color{\dtl@thisplotmarkcolor}% + \the\toks@}% + \fi + \fi + \else + \let\dtl@mark=\relax + \fi +% \end{macrocode} +% Get the current plot line colour. +% \begin{macrocode} + \ifx\dtl@plotlinecolorlist\@empty + \let\dtl@plotlinecolorlist=\DTLplotlinecolors + \fi + \dtl@chopfirst\dtl@plotlinecolorlist\dtl@thisplotlinecolor + \dtl@remainder + \let\dtl@plotlinecolorlist=\dtl@remainder +% \end{macrocode} +% Get the current line style, and store in \cs{dtl@linestyle} +% \begin{macrocode} + \ifDTLshowlines + \ifx\dtl@plotlinelist\@empty + \let\dtl@plotlinelist=\DTLplotlines + \fi + \dtl@chopfirst\dtl@plotlinelist\dtl@thisplotline + \dtl@remainder + \let\dtl@plotlinelist=\dtl@remainder + \expandafter\ifx\dtl@thisplotline\relax + \let\dtl@linestyle=\relax + \else + \expandafter\toks@\expandafter{\dtl@thisplotline}% + \ifx\dtl@thisplotlinecolor\@empty + \edef\dtl@linestyle{\the\toks@}% + \else + \edef\dtl@linestyle{% + \noexpand\color{\dtl@thisplotlinecolor}% + \the\toks@}% + \fi + \fi + \else + \let\dtl@linestyle=\relax + \fi +% \end{macrocode} +% Append this plot setting to the legend. +% \begin{macrocode} + \ifnum\dtl@legendsetting>0\relax + \dtl@chopfirst\dtl@legendlabels\dtl@thislabel\dtl@rest + \let\dtl@legendlabels=\dtl@rest + \expandafter\toks@\expandafter{\dtl@mark}% + \expandafter\@dtl@toks\expandafter{\dtl@linestyle}% + \edef\dtl@addtolegend{\noexpand\DTLaddtoplotlegend + {\the\toks@}{\the\@dtl@toks}{\dtl@thislabel}}% + \dtl@addtolegend + \fi +% \end{macrocode} +% Store stream in \cs{dtl@stream} +% \begin{macrocode} + \def\dtl@stream{\pgfplotstreamstart}% +% \end{macrocode} +% Only plot points that lie inside bounds. +% \begin{macrocode} + \DTLforeach[#1]{\dtl@thisdb}{\dtl@x=\dtl@xkey,% + \dtl@y=\dtl@ykey}{% + \DTLconverttodecimal{\dtl@x}{\dtl@decx}% + \DTLconverttodecimal{\dtl@y}{\dtl@decy}% + \ifthenelse{% + \DTLisclosedbetween{\dtl@x}{\DTLminX}{\DTLmaxX}% + \and + \DTLisclosedbetween{\dtl@y}{\DTLminY}{\DTLmaxY}% + }{% + \expandafter\toks@\expandafter{\dtl@stream}% + \edef\dtl@stream{\the\toks@ + \noexpand\pgfplotstreampoint + {\noexpand\pgfpointxy{\dtl@decx}{\dtl@decy}}}% + }{}% + }% + \expandafter\toks@\expandafter{\dtl@stream}% + \edef\dtl@stream{\the\toks@\noexpand\pgfplotstreamend}% +% \end{macrocode} +% End plot stream and draw path. +% \begin{macrocode} + \ifx\dtl@linestyle\relax + \else + \begin{scope} + \dtl@linestyle + \pgfplothandlerlineto + \dtl@stream + \pgfusepath{stroke} + \end{scope} + \fi + \ifx\dtl@mark\relax + \else + \begin{scope} + \pgfplothandlermark{\dtl@mark}% + \dtl@stream + \pgfusepath{stroke} + \end{scope} + \fi + }% +% \end{macrocode} +% Plot legend if required. +% \begin{macrocode} + \ifcase\dtl@legendsetting + % none + \or % north + \pgftext[top,center,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLmaxY}} + {\pgfpoint{0.5\DTLplotwidth}{-\DTLlegendyoffset}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % north east + \pgftext[top,right,at={\pgfpointadd + {\pgfpointxy{\DTLmaxX}{\DTLmaxY}} + {\pgfpoint{-\DTLlegendxoffset}{-\DTLlegendyoffset}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % east + \pgftext[center,right,at={\pgfpointadd + {\pgfpointxy{\DTLmaxX}{\DTLminY}} + {\pgfpoint{-\DTLlegendxoffset}{0.5\DTLplotheight}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % south east + \pgftext[bottom,right,at={\pgfpointadd + {\pgfpointxy{\DTLmaxX}{\DTLminY}} + {\pgfpoint{-\DTLlegendxoffset}{\DTLlegendyoffset}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % south + \pgftext[center,bottom,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLminY}} + {\pgfpoint{0.5\DTLplotwidth}{\DTLlegendyoffset}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % south west + \pgftext[bottom,left,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLminY}} + {\pgfpoint{\DTLlegendxoffset}{\DTLlegendyoffset}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % west + \pgftext[center,left,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLminY}} + {\pgfpoint{\DTLlegendxoffset}{0.5\DTLplotheight}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \or % north west + \pgftext[top,left,at={\pgfpointadd + {\pgfpointxy{\DTLminX}{\DTLmaxY}} + {\pgfpoint{\DTLlegendxoffset}{-\DTLlegendyoffset}}}] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}} + \fi + \DTLplotatendtikz + \end{tikzpicture} + \fi + \fi +\fi +}} +% \end{macrocode} +%\end{macro} +% +% Extract bounds: +%\begin{macro}{\dtl@getbounds} +% \begin{macrocode} +\def\dtl@getbounds#1,#2,#3,#4\@nil{% +\def\DTLminX{#1}% +\def\DTLminY{#2}% +\def\DTLmaxX{#3}% +\def\DTLmaxY{#4}% +\FPifgt{\DTLminX}{\DTLmaxX} + \PackageError{dataplot}{Min X > Max X in bounds #1,#2,#3,#4}{% + The bounds must be specified as minX,minY,maxX,maxY}% +\fi +\FPifgt{\DTLminY}{\DTLmaxY} + \PackageError{dataplot}{Min Y > Max Y in bounds #1,#2,#3,#4}{% + The bounds must be specified as minX,minY,maxX,maxY}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@constructticklist}\marg{min}\marg{max}\marg{scale factor}\marg{list} +%\end{definition} +% Construct a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence.) +%\begin{macro}{\dtl@constructticklist} +% \begin{macrocode} +\newcommand*{\dtl@constructticklist}[4]{% +\DTLifFPopenbetween{0}{#1}{#2}{% + \FPsub{\@dtl@width}{0}{#1}% + \FPmul{\@dtl@width}{\@dtl@width}{#3}% + \FPdiv{\@dtl@neggap}{\@dtl@width}{10}% + \setlength\dtl@tmplength{\@dtl@neggap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \FPdiv{\@dtl@neggap}{\@dtl@width}{4}% + \setlength\dtl@tmplength{\@dtl@neggap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \FPdiv{\@dtl@neggap}{\@dtl@width}{2}% + \setlength\dtl@tmplength{\@dtl@neggap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \let\@dtl@neggap=\@dtl@width + \fi + \fi + \fi + \FPmul{\@dtl@width}{#2}{#3}% + \FPdiv{\@dtl@posgap}{\@dtl@width}{10}% + \setlength\dtl@tmplength{\@dtl@posgap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \FPdiv{\@dtl@posgap}{\@dtl@width}{4}% + \setlength\dtl@tmplength{\@dtl@posgap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \FPdiv{\@dtl@posgap}{\@dtl@width}{2}% + \setlength\dtl@tmplength{\@dtl@posgap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \let\@dtl@posgap=\@dtl@width + \fi + \fi + \fi + \FPmax{\@dtl@gap}{\@dtl@neggap}{\@dtl@posgap}% + \FPdiv{\@dtl@gap}{\@dtl@gap}{#3}% + \dtl@constructticklistwithgapz{#1}{#2}{#4}{\@dtl@gap}% +}{% + \FPsub{\@dtl@width}{#2}{#1}% + \FPmul{\@dtl@width}{\@dtl@width}{#3}% + \FPdiv{\@dtl@gap}{\@dtl@width}{10}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \FPdiv{\@dtl@gap}{\@dtl@width}{4}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \FPdiv{\@dtl@gap}{\@dtl@width}{2}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLmintickgap + \let\@dtl@gap=\@dtl@width + \fi + \fi + \fi + \FPdiv{\@dtl@gap}{\@dtl@gap}{#3}% + \dtl@constructticklistwithgap{#1}{#2}{#4}{\@dtl@gap}% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@constructticklistwithgap}\marg{min}\marg{max}\marg{list}\marg{gap} +%\end{definition} +% Construct a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence) using the gap given +% by \meta{gap} where the gap is given in user co-ordinates. +%\begin{macro}{\dtl@constructticklistwithgap} +% \begin{macrocode} +\newcommand*{\dtl@constructticklistwithgap}[4]{% +\edef\@dtl@thistick{#1}% +\edef#3{#1}% +\FPadd{\@dtl@thistick}{\@dtl@thistick}{#4}% +\whiledo{\DTLisFPopenbetween{\@dtl@thistick}{#1}{#2}}{% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \edef#3{#3,\the\toks@}% + \FPadd{\@dtl@thistick}{\@dtl@thistick}{#4}% +}% +\expandafter\toks@\expandafter{#2}% +\edef#3{#3,\the\toks@}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@constructticklistwithgapz}\marg{min}\marg{max}\marg{list}\marg{gap} +%\end{definition} +% Construct a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence) using the gap given +% by \meta{gap} where the tick list straddles zero. +%\begin{macro}{\dtl@constructticklistwithgapz} +% \begin{macrocode} +\newcommand*{\dtl@constructticklistwithgapz}[4]{% +\edef\@dtl@thistick{0}% +\edef#3{0}% +\FPadd{\@dtl@thistick}{\@dtl@thistick}{#4}% +\whiledo{\DTLisFPopenbetween{\@dtl@thistick}{0}{#2}}{% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \edef#3{#3,\the\toks@}% + \FPadd{\@dtl@thistick}{\@dtl@thistick}{#4}% +}% +\expandafter\toks@\expandafter{#2}% +\edef#3{#3,\the\toks@}% +\FPifeq{#1}{0}% +\else +\edef\@dtl@thistick{0}% + \FPsub{\@dtl@thistick}{\@dtl@thistick}{#4}% + \whiledo{\DTLisFPopenbetween{\@dtl@thistick}{#1}{0}}{% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \edef#3{\the\toks@,#3}% + \FPsub{\@dtl@thistick}{\@dtl@thistick}{#4}% + }% + \expandafter\toks@\expandafter{#1}% + \edef#3{\the\toks@,#3}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@constructminorticklist}\marg{min}\marg{max}\marg{scale factor}\marg{list} +%\end{definition} +% Construct a list of minor tick points between \meta{min} and \meta{max} +% and append to \meta{list} (a control sequence.) +%\begin{macro}{\dtl@constructminorticklist} +% \begin{macrocode} +\newcommand*{\dtl@constructminorticklist}[4]{% + \FPsub{\@dtl@width}{#2}{#1}% + \FPmul{\@dtl@width}{\@dtl@width}{#3}% + \FPdiv{\@dtl@gap}{\@dtl@width}{10}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLminminortickgap + \FPdiv{\@dtl@gap}{\@dtl@width}{4}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLminminortickgap + \FPdiv{\@dtl@gap}{\@dtl@width}{2}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLminminortickgap + \let\@dtl@gap=\@dtl@width + \fi + \fi + \fi + \FPdiv{\@dtl@gap}{\@dtl@gap}{#3}% + \dtl@constructticklistwithgapex{#1}{#2}{\dtl@tmp}{\@dtl@gap}% + \ifx#4\@empty + \let#4=\dtl@tmp + \else + \expandafter\toks@\expandafter{#4}% + \edef#4{#4,\dtl@tmp}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{dtl@constructticklistwithgapex}\marg{min}\marg{max}\marg{list}\marg{gap} +%\end{definition} +% Construct a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence) using the gap given +% by \meta{gap} where the gap is given in user co-ordinates. +% The end points are excluded from the list. +%\begin{macro}{\dtl@constructticklistwithgapex} +% \begin{macrocode} +\newcommand*{\dtl@constructticklistwithgapex}[4]{% +\edef\@dtl@thistick{#1}% +\let#3=\@empty +\FPadd{\@dtl@thistick}{\@dtl@thistick}{#4}% +\whiledo{\DTLisFPopenbetween{\@dtl@thistick}{#1}{#2}}{% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \ifx#3\@empty + \edef#3{\the\toks@}% + \else + \edef#3{#3,\the\toks@}% + \fi + \FPadd{\@dtl@thistick}{\@dtl@thistick}{#4}% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLaddtoplotlegend}\marg{marker}\marg{line style}\marg{label} +%\end{definition} +% Add entry to legend. +%\begin{macro}{\DTLaddtoplotlegend} +% \begin{macrocode} +\newcommand*{\DTLaddtoplotlegend}[3]{% +\def\dtl@legendline{}% +\ifx\relax#2\relax +\else + \toks@{#2% + \pgfpathmoveto{\pgfpoint{-10pt}{0pt}}% + \pgfpathlineto{\pgfpoint{10pt}{0pt}}% + \pgfusepath{stroke}}% + \edef\dtl@legendline{\the\toks@}% +\fi +\ifx\relax#1\relax +\else + \toks@{#1}% + \expandafter\@dtl@toks\expandafter{\dtl@legendline}% + \edef\dtl@legendline{\the\@dtl@toks\the\toks@}% +\fi +\expandafter\toks@\expandafter{\dtl@legendline}% +\ifx\dtl@legend\@empty + \edef\dtl@legend{\noexpand\tikz\the\toks@; \noexpand& #3}% +\else + \expandafter\@dtl@toks\expandafter{\dtl@legend}% + \edef\dtl@legend{\the\@dtl@toks\noexpand\\% + \noexpand\tikz\the\toks@; \noexpand& #3}% +\fi +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</dataplot.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*databar.sty> +% \end{macrocode} +%\fi +%\section{databar.sty} +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{databar}[2007/07/23 v1.0 (NLCT)] +% \end{macrocode} +% Require \sty{xkeyval} package +% \begin{macrocode} +\RequirePackage{xkeyval} +% \end{macrocode} +% Require \sty{dataplot} package +% \begin{macrocode} +\RequirePackage{dataplot} +% \end{macrocode} +% Define a conditional to determine whether to use colour or +% grey scale. +%\begin{macro}{\ifDTLcolorbarchart} +% \begin{macrocode} +\newif\ifDTLcolorbarchart +\DTLcolorbarcharttrue +% \end{macrocode} +%\end{macro} +% Package options to change the conditional: +% \begin{macrocode} +\DeclareOption{color}{\DTLcolorbarcharttrue} +\DeclareOption{gray}{\DTLcolorbarchartfalse} +% \end{macrocode} +%\cs{DTLbarXlabelalign} specifies the alignment +% for the $x$ axis labels. +% \begin{macrocode} +\newcommand*{\DTLbarXlabelalign}{left,rotate=-90} +% \end{macrocode} +%\cs{DTLbarYticklabelalign} specifies the alignment +% for the $x$ axis labels. +% \begin{macrocode} +\newcommand*{\DTLbarYticklabelalign}{right} +% \end{macrocode} +% Define boolean keys to govern bar chart orientation. +%\begin{macro}{\ifDTLverticalbars} +% \begin{macrocode} +\define@boolkey{databar}[DTL]{verticalbars}[true]{% +\ifDTLverticalbars + \def\DTLbarXlabelalign{left,rotate=-90}% + \def\DTLbarYticklabelalign{right} +\else + \def\DTLbarXlabelalign{right}% + \def\DTLbarYticklabelalign{center} +\fi} +% \end{macrocode} +%\end{macro} +% Set defaults: +% \begin{macrocode} +\DTLverticalbarstrue +% \end{macrocode} +% Package options to change \cs{ifDTLverticalbars} +% \begin{macrocode} +\DeclareOption{vertical}{\DTLverticalbarstrue + \def\DTLbarXlabelalign{left,rotate=-90}% + \def\DTLbarYticklabelalign{right} +} +\DeclareOption{horizontal}{\DTLverticalbarsfalse + \def\DTLbarXlabelalign{right}% + \def\DTLbarYticklabelalign{center} +} +% \end{macrocode} +% Process options: +% \begin{macrocode} +\ProcessOptions +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{datatool} +\RequirePackage{tikz} +% \end{macrocode} +% Define some variables that govern the appearance of the bar +% chart. +% +% The total height of the bar chart +%\begin{macro}{\DTLbarchartlength} +% \begin{macrocode} +\newlength\DTLbarchartlength +\DTLbarchartlength=3in +% \end{macrocode} +%\end{macro} +% +% The width of each bar +%\begin{macro}{\DTLbarwidth} +% \begin{macrocode} +\newlength\DTLbarwidth +\DTLbarwidth=1cm +% \end{macrocode} +%\end{macro} +% +% The offset from the $x$ axis to the bar label +%\begin{macro}{\DTLbarlabeloffset} +% \begin{macrocode} +\newlength\DTLbarlabeloffset +\setlength\DTLbarlabeloffset{10pt} +% \end{macrocode} +%\end{macro} +% The style of the $x$ axis +%\begin{macro}{\DTLBarXAxisStyle} +% \begin{macrocode} +\newcommand*{\DTLBarXAxisStyle}{-} +% \end{macrocode} +%\end{macro} +% The style of the $y$ axis +%\begin{macro}{\DTLBarYAxisStyle} +% \begin{macrocode} +\newcommand*{\DTLBarYAxisStyle}{-} +% \end{macrocode} +%\end{macro} +% +% \counterfmt{DTLbarroundvar} is a counter governing the number of digits +% to round to when using \cs{FPround}. +% \begin{macrocode} +\newcounter{DTLbarroundvar} +\setcounter{DTLbarroundvar}{1} +% \end{macrocode} +% +%\cs{DTLbardisplayYticklabel} governs how the $y$ tick labels appear. +%\begin{macro}{\DTLbardisplayYticklabel} +% \begin{macrocode} +\newcommand*{\DTLbardisplayYticklabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\cs{DTLdisplaylowerbarlabel} governs how the lower bar labels appear. +%\begin{macro}{\DTLdisplaylowerbarlabel} +% \begin{macrocode} +\newcommand*{\DTLdisplaylowerbarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\cs{DTLdisplaylowermultibarlabel} governs how the lower multi bar labels appear. +%\begin{macro}{\DTLdisplaylowermultibarlabel} +% \begin{macrocode} +\newcommand*{\DTLdisplaylowermultibarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\cs{DTLdisplayupperbarlabel} governs how the upper bar labels +% appear. +%\begin{macro}{\DTLdisplayupperbarlabel} +% \begin{macrocode} +\newcommand*{\DTLdisplayupperbarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\cs{DTLdisplayuppermultibarlabel} governs how the upper multi bar +% labels appear. +%\begin{macro}{\DTLdisplayuppermultibarlabel} +% \begin{macrocode} +\newcommand*{\DTLdisplayuppermultibarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +% +% \cs{DTLbaratbegintikz} specifies any commands +% to apply at the start of the \env{tikzpicture} environment. +% By default it does nothing. +%\begin{macro}{\DTLbaratbegintikz} +% \begin{macrocode} +\newcommand*{\DTLbaratbegintikz}{} +% \end{macrocode} +%\end{macro} +% +% \cs{DTLbaratendtikz} specifies any commands +% to apply at the end of the \env{tikzpicture} environment. +% By default it does nothing. +%\begin{macro}{\DTLbaratendtikz} +% \begin{macrocode} +\newcommand*{\DTLbaratendtikz}{} +% \end{macrocode} +%\end{macro} +% +% Conditional to determine whether or not to display the $x$ +% axis +%\begin{macro}{\ifDTLbarxaxis} +% \begin{macrocode} +\newif\ifDTLbarxaxis +% \end{macrocode} +%\end{macro} +% Conditional to determine whether or not to display the $y$ +% axis +%\begin{macro}{\ifDTLbaryaxis} +% \begin{macrocode} +\newif\ifDTLbaryaxis +% \end{macrocode} +%\end{macro} +% Conditional to determine whether or not to display the $y$ +% tick marks +%\begin{macro}{\ifDTLbarytics} +% \begin{macrocode} +\newif\ifDTLbarytics +% \end{macrocode} +%\end{macro} +% +% Define count register to store the current bar index: +%\begin{macro}{\@dtl@barcount} +% \begin{macrocode} +\newcount\@dtl@barcount +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLsetbarcolor}\marg{n}\marg{color} +%\end{definition} +% Assign colour name \meta{color} to the \meta{n}th bar. +%\begin{macro}{\DTLsetbarcolor} +% \begin{macrocode} +\newcommand*{\DTLsetbarcolor}[2]{% +\expandafter\def\csname dtlbar@segcol\romannumeral#1\endcsname{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLgetbarcolor}\marg{n} +%\end{definition} +% Get the colour specification for the \meta{n}th bar +%\begin{macro}{\DTLgetbarcolor} +% \begin{macrocode} +\newcommand*{\DTLgetbarcolor}[1]{% +\csname dtlbar@segcol\romannumeral#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +%\cs{DTLdobarcolor}\marg{n} +%\end{definition} +% Set the colour to that for the \meta{n}th bar +%\begin{macro}{\DTLdobarcolor} +% \begin{macrocode} +\newcommand*{\DTLdobarcolor}[1]{% +\expandafter\color\expandafter +{\csname dtlbar@segcol\romannumeral#1\endcsname}} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLdocurrentbarcolor} +% sets the colour to that of the current bar. +%\begin{macro}{\DTLdocurrentbarcolor} +% \begin{macrocode} +\newcommand*{\DTLdocurrentbarcolor}{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{databar}{Can't use + \string\DTLdocurrentbarcolor\space outside + \string\DTLbarchart}{}% +\else + \expandafter\DTLdobarcolor\expandafter{% + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname}% +\fi} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLbaroutlinecolor} specifies what colour to draw the +% outline. +%\begin{macro}{\DTLbaroutlinecolor} +% \begin{macrocode} +\newcommand*{\DTLbaroutlinecolor}{black} +% \end{macrocode} +%\end{macro} +% +%\cs{DTLbaroutlinewidth} specifies the line width of the outline: +% Outline is only drawn if the linewidth is greater than 0pt. +%\begin{macro}{\DTLbaroutlinewidth} +% \begin{macrocode} +\newlength\DTLbaroutlinewidth +\DTLbaroutlinewidth=0pt +% \end{macrocode} +%\end{macro} +% +% Set the default colours. If there are more than eight bars, +% more colours will need to be defined. +% \begin{macrocode} +\ifDTLcolorbarchart + \DTLsetbarcolor{1}{red} + \DTLsetbarcolor{2}{green} + \DTLsetbarcolor{3}{blue} + \DTLsetbarcolor{4}{yellow} + \DTLsetbarcolor{5}{magenta} + \DTLsetbarcolor{6}{cyan} + \DTLsetbarcolor{7}{orange} + \DTLsetbarcolor{8}{white} +\else + \DTLsetbarcolor{1}{black!15} + \DTLsetbarcolor{2}{black!25} + \DTLsetbarcolor{3}{black!35} + \DTLsetbarcolor{4}{black!45} + \DTLsetbarcolor{5}{black!55} + \DTLsetbarcolor{6}{black!65} + \DTLsetbarcolor{7}{black!75} + \DTLsetbarcolor{8}{black!85} +\fi +% \end{macrocode} +% +% Define keys for \cs{DTLbarchart} optional argument. +% Set the maximum value of the $y$ axis. +% \begin{macrocode} +\define@key{databar}{max}{\def\DTLbarmax{#1}} +% \end{macrocode} +% Set the total length of the bar chart +% \begin{macrocode} +\define@key{databar}{length}{\DTLbarchartlength=#1\relax +} +% \end{macrocode} +% Set the maximum depth (negative extent) +% \begin{macrocode} +\define@key{databar}{maxdepth}{% +\ifnum#1>0\relax + \PackageError{databar}{depth must be zero or negative}{}% +\else + \def\DTLnegextent{#1}% +\fi} +% \end{macrocode} +% Determine which axes should be shown +% \begin{macrocode} +\define@choicekey{databar}{axes}[\var\nr]{both,x,y,none}{% +\ifcase\nr\relax + % both + \DTLbarxaxistrue + \DTLbaryaxistrue + \DTLbaryticstrue +\or + % x only + \DTLbarxaxistrue + \DTLbaryaxisfalse + \DTLbaryticsfalse +\or + % y only + \DTLbarxaxisfalse + \DTLbaryaxistrue + \DTLbaryticstrue +\or + % neither + \DTLbarxaxisfalse + \DTLbaryaxisfalse + \DTLbaryticsfalse +\fi +} +% \end{macrocode} +% Variable used to create the bar chart. (Must be a control +% sequence.) +% \begin{macrocode} +\define@key{databar}{variable}{% +\def\DTLbarvariable{#1}} +% \end{macrocode} +% Variables used to create the multi bar chart. (Must be a +% comma separated list of control sequences.) +% \begin{macrocode} +\define@key{databar}{variables}{% +\def\dtlbar@variables{#1}} +% \end{macrocode} +% Bar width +% \begin{macrocode} +\define@key{databar}{barwidth}{\setlength{\DTLbarwidth}{#1}} +% \end{macrocode} +% Lower bar labels +% \begin{macrocode} +\define@key{databar}{barlabel}{% +\def\dtl@barlabel{#1}} +\def\dtl@barlabel{} +% \end{macrocode} +% Lower bar labels for multi-bar charts +% \begin{macrocode} +\define@key{databar}{multibarlabels}{% +\def\dtl@multibarlabels{#1}} +\def\dtl@multibarlabels{} +% \end{macrocode} +% Gap between groups in multi-bar charts (This should be in $x$ units +% where 1 $x$ unit is the width of a bar.) +% \begin{macrocode} +\define@key{databar}{groupgap}{\def\dtlbar@groupgap{#1}} +\def\dtlbar@groupgap{1} +% \end{macrocode} +% Upper bar labels +% \begin{macrocode} +\define@key{databar}{upperbarlabel}{% +\def\dtl@upperbarlabel{#1}} +\def\dtl@upperbarlabel{} +% \end{macrocode} +% Upper bar labels for multi-bar charts +% \begin{macrocode} +\define@key{databar}{uppermultibarlabels}{% +\def\dtl@uppermultibarlabels{#1}} +\def\dtl@uppermultibarlabels{} +% \end{macrocode} +% Define list of points for $y$ tics. (Must be a comma separated list +% of decimal numbers.) +% \begin{macrocode} +\define@key{databar}{yticpoints}{% +\def\dtlbar@yticlist{#1}\DTLbaryticstrue\DTLbaryaxistrue} +\let\dtlbar@yticlist=\relax +% \end{macrocode} +% Set the $y$ tick gap: +% \begin{macrocode} +\define@key{databar}{yticgap}{% +\def\dtlbar@yticgap{#1}\DTLbaryticstrue\DTLbaryaxistrue} +\let\dtlbar@yticgap=\relax +% \end{macrocode} +% Define list of labels for $y$ tics. +% \begin{macrocode} +\define@key{databar}{yticlabels}{% +\def\dtlbar@yticlabels{#1}\DTLbaryticstrue\DTLbaryaxistrue} +\let\dtlbar@yticlabels=\relax +% \end{macrocode} +% Define $y$ axis label. +% \begin{macrocode} +\define@key{databar}{ylabel}{% +\def\dtlbar@ylabel{#1}} +\let\dtlbar@ylabel=\relax +% \end{macrocode} +% +%\begin{definition} +% \cs{DTLbarchart}\oarg{conditions}\marg{option list}\marg{db name}\marg{assign list} +%\end{definition} +% Make a bar chart from data given in data base \meta{db name}, +% where \meta{assign list} is a comma-separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. \meta{option list} must +% include \texttt{variable}\texttt{=}\meta{cmd}, where \meta{cmd} +% is included in \meta{assign list}. The optional argument +% \meta{conditions} is the same as that for \cs{DTLforeach}. +%\begin{macro}{\DTLbarchart} +% \begin{macrocode} +\newcommand*{\DTLbarchart}[4][\boolean{true}]{% +{\let\DTLbarvariable=\relax +\let\DTLbarmax=\relax +\let\DTLnegextent=\relax +\disable@keys{databar}{variables,multibarlabels,% +uppermultibarlabels,groupgap}% +\setkeys{databar}{#2}% +\ifx\DTLbarvariable\relax + \PackageError{databar}{\string\DTLbarchart\space missing variable}{}% +\else +% \end{macrocode} +% Compute the maximum bar height, unless \cs{DTLbarmax} has been +% set. +% \begin{macrocode} + \ifx\DTLbarmax\relax + \DTLforeach[#1]{#3}{#4}{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \ifx\DTLbarmax\relax + \let\DTLbarmax=\dtl@barvar + \else + \let\dtl@old=\DTLbarmax + \FPmax{\DTLbarmax}{\dtl@old}{\dtl@barvar}% + \fi + }% + \ifx\dtlbar@yticgap\relax + \else + \let\dtl@thistick=\dtlbar@yticgap% + \whiledo{\DTLisFPopenbetween{\dtl@thistick}{0}{\DTLbarmax}}{% + \FPadd{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLbarmax=\dtl@thistick + \fi + \fi +% \end{macrocode} +% Compute the bar depth, unless \cs{DTLnegextent} has been +% set. +% \begin{macrocode} + \ifx\DTLnegextent\relax + \def\DTLnegextent{0}% + \DTLforeach[#1]{#3}{#4}{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \let\dtl@old=\DTLnegextent + \DTLmin{\DTLnegextent}{\dtl@old}{\dtl@barvar}% + }% + \ifx\dtlbar@yticgap\relax + \else + \ifthenelse{\DTLisFPlt{\DTLnegextent}{0}}{% + \edef\dtl@thistick{0}% + \whiledo{\DTLisFPclosedbetween{\dtl@thistick}{\DTLnegextent}{0}}{% + \FPsub{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLnegextent=\dtl@thistick + }{}% + \fi + \fi +% \end{macrocode} +% Determine scaling factor +% \begin{macrocode} + \@dtl@tmpcount=\DTLbarchartlength + \FPsub{\dtl@extent}{\DTLbarmax}{\DTLnegextent}% + \FPdiv{\dtl@unit}{\number\@dtl@tmpcount}{\dtl@extent}% +% \end{macrocode} +% Construct $y$ tick list if required +% \begin{macrocode} + \setlength{\dtl@yticlabelwidth}{0pt}% + \ifDTLbarytics + \ifx\dtlbar@yticlist\relax + \ifx\dtlbar@yticgap\relax + \dtl@constructticklist\DTLnegextent\DTLbarmax + \dtl@unit\dtlbar@yticlist + \else + \dtl@constructticklistwithgapz + \DTLnegextent\DTLbarmax\dtlbar@yticlist\dtlbar@yticgap + \fi + \fi + \ifx\dtlbar@ylabel\relax + \else + \ifx\dtlbar@yticlabels\relax + \@for\dtl@thislabel:=\dtlbar@yticlist\do{% + \FPround{\dtl@thislabel}{\dtl@thislabel} + {\c@DTLbarroundvar}% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \else + \@for\dtl@thislabel:=\dtlbar@yticlabels\do{% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \fi + \fi + \fi +% \end{macrocode} +% Store the width of the bar chart in \cs{DTLbarchartwidth} +% \begin{macrocode} +\edef\DTLbarchartwidth{\expandafter\number\csname dtlrows@#3\endcsname} +% \end{macrocode} +% Do the bar chart +% \begin{macrocode} +\begin{tikzpicture} +% \end{macrocode} +% Set unit vectors +% \begin{macrocode} +\ifDTLverticalbars + \pgfsetyvec{\pgfpoint{0pt}{\dtl@unit sp}}% + \pgfsetxvec{\pgfpoint{\DTLbarwidth}{0pt}}% +\else + \pgfsetxvec{\pgfpoint{\dtl@unit sp}{0pt}}% + \pgfsetyvec{\pgfpoint{0pt}{\DTLbarwidth}}% +\fi +% \end{macrocode} +% Begin hook +% \begin{macrocode} +\DTLbaratbegintikz +% \end{macrocode} +% Initialise +% \begin{macrocode} +\def\@dtl@start{0}% +% \end{macrocode} +% Iterate through data +% \begin{macrocode} +\DTLforeach[#1]{#3}{#4}{% +% \end{macrocode} +% Store the bar number in \cs{@dtl@bar} +% \begin{macrocode} +\expandafter\let\expandafter\@dtl@bar + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname% +% \end{macrocode} +% Convert variable to decimal +% \begin{macrocode} +\expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@variable}% +% \end{macrocode} +% Draw bars +% \begin{macrocode} +\begin{scope} + \DTLdocurrentbarcolor + \ifDTLverticalbars + \fill (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@bar,\dtl@variable) -- (\@dtl@bar,0) -- cycle; + \else + \fill (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@bar) -- (0,\@dtl@bar) -- cycle; + \fi +\end{scope} +% \end{macrocode} +% Draw outline +% \begin{macrocode} +\begin{scope} +\ifdim\DTLbaroutlinewidth>0pt + \expandafter\color\expandafter{\DTLbaroutlinecolor} + \ifDTLverticalbars + \draw (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@bar,\dtl@variable) -- (\@dtl@bar,0) -- cycle; + \else + \draw (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@bar) -- (0,\@dtl@bar) -- cycle; + \fi +\fi +\end{scope} +% \end{macrocode} +% Draw lower $x$ labels +% \begin{macrocode} +\ifDTLverticalbars + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@start.5}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, + \DTLbarXlabelalign + }% +\else + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\@dtl@start.5}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, + \DTLbarXlabelalign + }% +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplaylowerbarlabel{\dtl@barlabel}} +% \end{macrocode} +% Draw upper $x$ labels +% \begin{macrocode} +\ifDTLverticalbars + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} + { + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}} + }% + }{% + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} + }% + } +\else + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} + { + \edef\dtl@textopt{right, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}} + }% + }{% + \edef\dtl@textopt{left, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}} + {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} + }% + } +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplayupperbarlabel{\dtl@upperbarlabel}} +% \end{macrocode} +% End of loop +% \begin{macrocode} + \edef\@dtl@start{\number\@dtl@bar}% +} +% \end{macrocode} +% Draw $x$ axis +% \begin{macrocode} +\ifDTLbarxaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (\DTLbarchartwidth,0); + \else + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (0,\DTLbarchartwidth); + \fi +\fi +% \end{macrocode} +% Draw $y$ axis +% \begin{macrocode} +\ifDTLbaryaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (0,\DTLnegextent) -- (0,\DTLbarmax); + \else + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (\DTLnegextent,0) -- (\DTLbarmax,0); + \fi +\fi +% \end{macrocode} +% Plot $y$ tick marks if required +% \begin{macrocode} +\ifx\dtlbar@yticlist\relax +\else + \@for\dtl@thistick:=\dtlbar@yticlist\do{% + \ifDTLverticalbars + \pgfpathmoveto{\pgfpointxy{0}{\dtl@thistick}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{0}{\dtl@thistick}} + {\pgfpoint{-\DTLticklength}{0pt}}} + \else + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{0}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{0}} + {\pgfpoint{0pt}{-\DTLticklength}}} + \fi + \pgfusepath{stroke} + \ifx\dtlbar@yticlabels\relax + \FPround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLbarroundvar}% + \else + \dtl@chopfirst\dtlbar@yticlabels\dtl@thislabel\dtl@rest + \let\dtlbar@yticlabels=\dtl@rest + \fi + \ifDTLverticalbars + \edef\dtl@textopt{\DTLbarYticklabelalign,% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\dtl@thistick}} + {\noexpand\pgfpoint{-\noexpand\DTLticklabeloffset}{0pt}}, + }}% + \else + \edef\dtl@textopt{\DTLbarYticklabelalign, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@thistick}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLticklabeloffset}} + }}% + \fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLbardisplayYticklabel{\dtl@thislabel}} + }% +\fi +% \end{macrocode} +% Plot the $y$ label if required +% \begin{macrocode} +\ifx\dtlbar@ylabel\relax +\else + \addtolength{\dtl@yticlabelwidth}{\baselineskip}% + \setlength{\dtl@tmplength}{0.5\DTLbarchartlength} + \ifDTLverticalbars + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{0}{\DTLnegextent}}% + {\pgfpoint{-\dtl@yticlabelwidth}{\dtl@tmplength}}}, + rotate=90]{% + \dtlbar@ylabel} + \else + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{\DTLnegextent}{0}}% + {\pgfpoint{\dtl@tmplength}{-\dtl@yticlabelwidth}}}]{% + \dtlbar@ylabel} + \fi +\fi +% \end{macrocode} +% Finish bar chart +% \begin{macrocode} +\DTLbaratendtikz +\end{tikzpicture} +\fi +}} +% \end{macrocode} +%\end{macro} +% +%\begin{definition} +% \cs{DTLmultibarchart}\oarg{conditions}\marg{option list}\marg{db name}\marg{assign list} +%\end{definition} +% Make a multi-bar chart from data given in data base \meta{db name}, +% where \meta{assign list} is a comma-separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. \meta{option list} must +% include the \texttt{variables} key which must be a comma separated +% list of commands, where each command +% is included in \meta{assign list}. The optional argument +% \meta{conditions} is the same as that for \cs{DTLforeach}. +%\begin{macro}{\DTLmultibarchart} +% \begin{macrocode} +\newcommand*{\DTLmultibarchart}[4][\boolean{true}]{% +{\let\dtlbar@variables=\relax +\let\DTLbarmax=\relax +\let\DTLnegextent=\relax +\disable@keys{databar}{variable,upperbarlabel}% +\setkeys{databar}{#2}% +\ifx\dtlbar@variables\relax + \PackageError{databar}{\string\DTLmultibarchart\space missing variables setting}{}% +\else +% \end{macrocode} +% Compute the maximum bar height, unless \cs{DTLbarmax} has been +% set. +% \begin{macrocode} + \ifx\DTLbarmax\relax + \DTLforeach[#1]{#3}{#4}{% + \@for\DTLbarvariable:=\dtlbar@variables\do{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \ifx\DTLbarmax\relax + \let\DTLbarmax=\dtl@barvar + \else + \let\dtl@old=\DTLbarmax + \FPmax{\DTLbarmax}{\dtl@old}{\dtl@barvar}% + \fi + }% + }% + \ifx\dtlbar@yticgap\relax + \else + \let\dtl@thistick=\dtlbar@yticgap% + \whiledo{\DTLisFPopenbetween{\dtl@thistick}{0}{\DTLbarmax}}{% + \FPadd{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLbarmax=\dtl@thistick + \fi + \fi +% \end{macrocode} +% Compute the bar depth, unless \cs{DTLnegextent} has been +% set. +% \begin{macrocode} + \ifx\DTLnegextent\relax + \def\DTLnegextent{0}% + \DTLforeach[#1]{#3}{#4}{% + \@for\DTLbarvariable:=\dtlbar@variables\do{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \let\dtl@old=\DTLnegextent + \DTLmin{\DTLnegextent}{\dtl@old}{\dtl@barvar}% + }% + }% + \ifx\dtlbar@yticgap\relax + \else + \ifthenelse{\DTLisFPlt{\DTLnegextent}{0}}{% + \edef\dtl@thistick{0}% + \whiledo{\DTLisFPclosedbetween{\dtl@thistick}{\DTLnegextent}{0}}{% + \FPsub{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLnegextent=\dtl@thistick + }{}% + \fi + \fi +% \end{macrocode} +% Determine scaling factor +% \begin{macrocode} + \@dtl@tmpcount=\DTLbarchartlength + \FPsub{\dtl@extent}{\DTLbarmax}{\DTLnegextent}% + \FPdiv{\dtl@unit}{\number\@dtl@tmpcount}{\dtl@extent}% +% \end{macrocode} +% Construct $y$ tick list if required +% \begin{macrocode} + \setlength{\dtl@yticlabelwidth}{0pt}% + \ifDTLbarytics + \ifx\dtlbar@yticlist\relax + \ifx\dtlbar@yticgap\relax + \dtl@constructticklist\DTLnegextent\DTLbarmax + \dtl@unit\dtlbar@yticlist + \else + \dtl@constructticklistwithgapz + \DTLnegextent\DTLbarmax\dtlbar@yticlist\dtlbar@yticgap + \fi + \fi + \ifx\dtlbar@ylabel\relax + \else + \ifx\dtlbar@yticlabels\relax + \@for\dtl@thislabel:=\dtlbar@yticlist\do{% + \FPround{\dtl@thislabel}{\dtl@thislabel} + {\c@DTLbarroundvar}% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \else + \@for\dtl@thislabel:=\dtlbar@yticlabels\do{% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \fi + \fi + \fi +% \end{macrocode} +% Calculate the offset for the lower label and number of labels +% \begin{macrocode} +\dtl@xticlabelheight=0pt\relax +\@dtl@tmpcount=0\relax +\@for\dtl@thislabel:=\dtl@multibarlabels\do{% + \advance\@dtl@tmpcount by 1\relax + \settoheight{\dtl@tmplength}{\tikz\expandafter\pgftext\expandafter + [\DTLbarXlabelalign]{\DTLdisplaylowerbarlabel{\dtl@thislabel}};}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{\tikz\expandafter\pgftext\expandafter + [\DTLbarXlabelalign]{\DTLdisplaylowerbarlabel{\dtl@thislabel}};}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \ifdim\dtl@tmplength>\dtl@xticlabelheight + \setlength{\dtl@xticlabelheight}{\dtl@tmplength}% + \fi +} +% \end{macrocode} +% Calculate number of bars per group +% \begin{macrocode} +\@dtl@tmpcount=0\relax +\@for\dtl@this:=\dtlbar@variables\do{% + \advance\@dtl@tmpcount by 1\relax +}% +\edef\DTLbargroupwidth{\number\@dtl@tmpcount}% +% \end{macrocode} +% Compute the total width of the bar chart (in terms of +% the $x$ unit vector.) +% \begin{macrocode} +\edef\dtl@n{\expandafter\number\csname dtlrows@#3\endcsname} +\FPmul{\dtl@tmpi}{\dtl@n}{\DTLbargroupwidth} +\FPsub{\dtl@tmpii}{\dtl@n}{1}% +\FPmul{\dtl@tmpii}{\dtl@tmpii}{\dtlbar@groupgap}% +\FPadd{\DTLbarchartwidth}{\dtl@tmpi}{\dtl@tmpii} +% \end{macrocode} +% Do the bar chart +% \begin{macrocode} +\begin{tikzpicture} +% \end{macrocode} +% Set unit vectors +% \begin{macrocode} +\ifDTLverticalbars + \pgfsetyvec{\pgfpoint{0pt}{\dtl@unit sp}}% + \pgfsetxvec{\pgfpoint{\DTLbarwidth}{0pt}}% +\else + \pgfsetxvec{\pgfpoint{\dtl@unit sp}{0pt}}% + \pgfsetyvec{\pgfpoint{0pt}{\DTLbarwidth}}% +\fi +% \end{macrocode} +% Begin hook +% \begin{macrocode} +\DTLbaratbegintikz +% \end{macrocode} +% Initialise +% \begin{macrocode} +\def\@dtl@start{0}% +% \end{macrocode} +% Iterate through data +% \begin{macrocode} +\DTLforeach[#1]{#3}{#4}{% +% \end{macrocode} +% Store the bar number in \cs{@dtl@bar} +% \begin{macrocode} +\@dtl@barcount = 1\relax +% \end{macrocode} +% Set the multibar label lists +% \begin{macrocode} +\let\dtl@multibar@labels=\dtl@multibarlabels +\let\dtl@uppermultibar@labels=\dtl@uppermultibarlabels +% \end{macrocode} +% Compute mid point over group +% \begin{macrocode} +\FPmul{\dtl@multimidpt}{\DTLbargroupwidth}{0.5}% +\FPadd{\dtl@multimidpt}{\dtl@multimidpt}{\@dtl@start}% +% \end{macrocode} +% Iterate through each variable +% \begin{macrocode} +\@for\DTLbarvariable:=\dtlbar@variables\do{% +% \end{macrocode} +% Set end point +% \begin{macrocode} +\FPadd{\@dtl@endpt}{\@dtl@start}{1}% +% \end{macrocode} +% Convert variable to decimal +% \begin{macrocode} +\expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@variable}% +% \end{macrocode} +% Get the current lower label: +% \begin{macrocode} +\dtl@chopfirst\dtl@multibar@labels\dtl@thisbarlabel\dtl@rest +\let\dtl@multibar@labels=\dtl@rest +% \end{macrocode} +% Get the current upper label: +% \begin{macrocode} +\dtl@chopfirst\dtl@uppermultibar@labels\dtl@thisupperbarlabel\dtl@rest +\let\dtl@uppermultibar@labels=\dtl@rest +% \end{macrocode} +% Draw bars +% \begin{macrocode} +\begin{scope} + \expandafter\color\expandafter{\DTLgetbarcolor{\@dtl@barcount}}% + \ifDTLverticalbars + \fill (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@endpt,\dtl@variable) -- (\@dtl@endpt,0) -- cycle; + \else + \fill (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@endpt) -- (0,\@dtl@endpt) -- cycle; + \fi +\end{scope} +% \end{macrocode} +% Draw outline +% \begin{macrocode} +\begin{scope} +\ifdim\DTLbaroutlinewidth>0pt + \expandafter\color\expandafter{\DTLbaroutlinecolor} + \ifDTLverticalbars + \draw (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@endpt,\dtl@variable) -- (\@dtl@endpt,0) -- cycle; + \else + \draw (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@endpt) -- (0,\@dtl@endpt) -- cycle; + \fi +\fi +\end{scope} +% \end{macrocode} +% Calculate mid point +% \begin{macrocode} +\FPadd{\@dtl@midpt}{\@dtl@start}{0.5}% +% \end{macrocode} +% Draw lower $x$ labels +% \begin{macrocode} +\ifDTLverticalbars + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@midpt}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, + \DTLbarXlabelalign + }% +\else + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\@dtl@midpt}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, + \DTLbarXlabelalign + }% +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplaylowermultibarlabel{\dtl@thisbarlabel}} +% \end{macrocode} +% Draw upper $x$ labels +% \begin{macrocode} +\ifDTLverticalbars + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} + { + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}} + }% + }{% + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} + }% + } +\else + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} + { + \edef\dtl@textopt{right, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}} + }% + }{% + \edef\dtl@textopt{left, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}} + {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} + }% + } +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplayuppermultibarlabel{\dtl@thisupperbarlabel}} +% \end{macrocode} +% End of loop increment loop variables +% \begin{macrocode} + \FPadd{\@dtl@start}{\@dtl@start}{1}% + \advance\@dtl@barcount by 1\relax +}% +% Draw lower group $x$ labels +% \begin{macrocode} +\setlength{\dtl@tmplength}{\DTLbarlabeloffset}% +\addtolength{\dtl@tmplength}{\dtl@xticlabelheight}% +\ifDTLverticalbars + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@multimidpt}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\dtl@tmplength}}}, + \DTLbarXlabelalign + }% +\else + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\dtl@multimidpt}} + {\noexpand\pgfpoint{-\noexpand\dtl@tmplength}{0pt}}}, + \DTLbarXlabelalign + }% +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplaylowerbarlabel{\dtl@barlabel}} +% \end{macrocode} +% Increment starting position by \cs{dtlbar@groupgap} +% \begin{macrocode} + \FPadd{\@dtl@start}{\@dtl@start}{\dtlbar@groupgap}% +} +% \end{macrocode} +% Draw $x$ axis +% \begin{macrocode} +\ifDTLbarxaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (\DTLbarchartwidth,0); + \else + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (0,\DTLbarchartwidth); + \fi +\fi +% \end{macrocode} +% Draw $y$ axis +% \begin{macrocode} +\ifDTLbaryaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (0,\DTLnegextent) -- (0,\DTLbarmax); + \else + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (\DTLnegextent,0) -- (\DTLbarmax,0); + \fi +\fi +% \end{macrocode} +% Plot $y$ tick marks if required +% \begin{macrocode} +\ifx\dtlbar@yticlist\relax +\else + \@for\dtl@thistick:=\dtlbar@yticlist\do{% + \ifDTLverticalbars + \pgfpathmoveto{\pgfpointxy{0}{\dtl@thistick}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{0}{\dtl@thistick}} + {\pgfpoint{-\DTLticklength}{0pt}}} + \else + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{0}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{0}} + {\pgfpoint{0pt}{-\DTLticklength}}} + \fi + \pgfusepath{stroke} + \ifx\dtlbar@yticlabels\relax + \FPround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLbarroundvar}% + \else + \dtl@chopfirst\dtlbar@yticlabels\dtl@thislabel\dtl@rest + \let\dtlbar@yticlabels=\dtl@rest + \fi + \ifDTLverticalbars + \edef\dtl@textopt{\DTLbarYticklabelalign,% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\dtl@thistick}} + {\noexpand\pgfpoint{-\noexpand\DTLticklabeloffset}{0pt}}, + }}% + \else + \edef\dtl@textopt{\DTLbarYticklabelalign, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@thistick}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLticklabeloffset}} + }}% + \fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLbardisplayYticklabel{\dtl@thislabel}} + }% +\fi +% \end{macrocode} +% Plot the $y$ label if required +% \begin{macrocode} +\ifx\dtlbar@ylabel\relax +\else + \addtolength{\dtl@yticlabelwidth}{\baselineskip}% + \setlength{\dtl@tmplength}{0.5\DTLbarchartlength} + \ifDTLverticalbars + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{0}{\DTLnegextent}}% + {\pgfpoint{-\dtl@yticlabelwidth}{\dtl@tmplength}}}, + rotate=90]{% + \dtlbar@ylabel} + \else + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{\DTLnegextent}{0}}% + {\pgfpoint{\dtl@tmplength}{-\dtl@yticlabelwidth}}}]{% + \dtlbar@ylabel} + \fi +\fi +% \end{macrocode} +% Finish bar chart +% \begin{macrocode} +\DTLbaratendtikz +\end{tikzpicture} +\fi +}} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</databar.sty> +% \end{macrocode} +%\fi +%\Finale +\endinput diff --git a/Master/texmf-dist/doc/latex/datatool/source/datatool.ins b/Master/texmf-dist/doc/latex/datatool/source/datatool.ins new file mode 100644 index 00000000000..8966a25bcbe --- /dev/null +++ b/Master/texmf-dist/doc/latex/datatool/source/datatool.ins @@ -0,0 +1,25 @@ +% datatool.ins generated using makedtx version 0.93b 2007/7/23 22:53 +\input docstrip + +\preamble +Copyright (C) 2007 Nicola Talbot, all rights reserved. +If you modify this file, you must change its name first. +You are NOT ALLOWED to distribute this file alone. You are NOT +ALLOWED to take money for the distribution or use of either this +file or a changed version, except for a nominal charge for copying +etc. +\endpreamble + +\askforoverwritefalse + +\generate{\file{datapie.sty}{\usepreamble\defaultpreamble +\usepostamble\defaultpostamble\from{datatool.dtx}{datapie.sty,package}} +\file{dataplot.sty}{\usepreamble\defaultpreamble +\usepostamble\defaultpostamble\from{datatool.dtx}{dataplot.sty,package}} +\file{datatool.sty}{\usepreamble\defaultpreamble +\usepostamble\defaultpostamble\from{datatool.dtx}{datatool.sty,package}} +\file{databar.sty}{\usepreamble\defaultpreamble +\usepostamble\defaultpostamble\from{datatool.dtx}{databar.sty,package}} +} + +\endbatchfile diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc index 2be884767e6..1c36367beb5 100644 --- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc @@ -90,6 +90,7 @@ depend Package/cv depend Package/cwpuzzle depend Package/dashbox depend Package/dashrule +depend Package/datatool depend Package/dateiliste depend Package/datenumber depend Package/datetime diff --git a/Master/tlpkg/tlpsrc/datatool.tlpsrc b/Master/tlpkg/tlpsrc/datatool.tlpsrc new file mode 100644 index 00000000000..2ab8067985c --- /dev/null +++ b/Master/tlpkg/tlpsrc/datatool.tlpsrc @@ -0,0 +1,2 @@ +name datatool +category Package |