diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/datatool/datatool-user.tex |
Initial commit
Diffstat (limited to 'macros/latex/contrib/datatool/datatool-user.tex')
-rw-r--r-- | macros/latex/contrib/datatool/datatool-user.tex | 11443 |
1 files changed, 11443 insertions, 0 deletions
diff --git a/macros/latex/contrib/datatool/datatool-user.tex b/macros/latex/contrib/datatool/datatool-user.tex new file mode 100644 index 0000000000..08f01e258f --- /dev/null +++ b/macros/latex/contrib/datatool/datatool-user.tex @@ -0,0 +1,11443 @@ +\documentclass[report,widecs]{nlctdoc} + +\DeleteShortVerb{\|} + +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{ifthen} +\usepackage[verbose=false]{datatool} +\usepackage{mfirstuc}[2017/11/10] +\usepackage{datapie,databar,databib,person,datagidx} +\usepackage{textcomp} +\usepackage{graphicx} +\usepackage{colortbl} +\usepackage{booktabs} +\usepackage{metalogo} +\usepackage{cmap} +\usepackage{alltt} +\ifpdf +\usepackage{mathpazo} +\usepackage[scaled=.88]{helvet} +\usepackage{courier} +\fi +\usepackage{caption} +\usepackage[colorlinks, + bookmarks, + hyperindex=false, + pdfauthor={Nicola L.C. Talbot}, + pdftitle={datatool: Databases and data manipulation}, + pdfkeywords={LaTeX,package,database,data,chart,plot}]{hyperref} +\usepackage{xr-hyper} +\usetikzlibrary{snakes} + +\PageIndex +\IndexPrologue{\chapter*{Index}} +\setcounter{IndexColumns}{2} + +\ifpdf + \externaldocument{datatool-code} +\fi + +\doxitem{Counter}{counter}{counters} +\doxitem{Option}{option}{package options} + +\newcommand*{\desctr}[1]{\DescribeCounter{#1}\ctrfmt{#1}} + +\newrobustcmd{\dbs}{\texttt{\string\\}} + +\newcommand{\idbs}{% + \dbs\index{\string\\\actualchar\dbs\encapchar usage}% +} + +\setlength\marginparwidth{70pt} + + + %bibliography database +\DTLnewdb{docbib} +\DTLnewrow{docbib} +\DTLnewdbentry{docbib}{CiteKey}{Goossens} +\DTLnewdbentry{docbib}{EntryType}{book} +\DTLnewdbentry{docbib}{Author}{{}{Goossens}{}{Michel},{}{Mittelbach}{}{Frank},{}{Samarin}{}{Alexander}} +\DTLnewdbentry{docbib}{Title}{The \LaTeX\ Companion} +\DTLnewdbentry{docbib}{Publisher}{Addison-Wesley} +\DTLnewdbentry{docbib}{Year}{1994} + + % datagidx index example database + +\newgidx{gidx-index}{Index}% define a database for the index + +\DTLgidxSetDefaultDB{gidx-index}% set this as the default + +\newterm{mac\'edoine} +\newterm{macram\'e} +\newterm[label=elite]{{\'e}lite} +\newterm{reptile} +\newterm[seealso={reptile}]{crocodylian} + +\newterm + [% + parent=crocodylian + ] + {crocodile} + +\newterm + [% + parent=crocodylian + ] + {alligator} + +\newterm + [% + parent=crocodylian, + description={(also cayman)} + ] + {caiman} + +\newterm[see={caiman}]{cayman} + +\begin{document} +% Some of the commands are too long to produce nicely formatted +% paragraphs so use ragged-right: +\raggedright +\setlength{\parindent}{1em}% + +\MakeShortVerb{"} + + \title{User Manual for datatool bundle version~2.31} + \author{Nicola L.C. Talbot\\ +\url{http://www.dickimaw-books.com/}} + + \date{2018-12-07} + \maketitle + +\pagenumbering{roman} + +\noindent +The \styfmt{datatool} bundle comes with the following documentation: +\begin{description} + \item[datatool-user.pdf] + This document is the main user guide for the \styfmt{datatool} + bundle. + + \item[\url{datatool-code.pdf}] + Advanced users wishing to know more about the inner workings of + all the packages provided in the \styfmt{datatool} bundle should + read \qt{Documented Code for datatool v2.31} + + \item[INSTALL] Installation instructions. + + \item[CHANGES] Change log. + + \item[README] Package summary. +\end{description} + +\begin{important} +There's an old adage, ``use the right tool for the right job.'' +A carpenter's fine chisel is the right tool for delicate carving, +but if you try to use it to hack off a tree branch it will take a +long time. That doesn't mean there's something wrong with the +chisel. It just means you're using the wrong tool for the job. + +The \styfmt{datatool} bundle is provided to help perform repetitive +commands, such as mail merging, but since \TeX\ is designed as a +typesetting language, don't expect this bundle to perform as +efficiently as custom database systems or a dedicated mathematical +or scripting language. \textbf{If the provided packages take a frustratingly +long time to compile your document, use another language to perform +your calculations or data manipulation and save the results in a +file that can be input into your document.} For large amounts of +data that need to be sorted or filtered or joined, consider storing your data +in an~SQL database and use +\app{datatooltk}\footnote{\url{http://www.dickimaw-books.com/software/datatooltk/}} to import the data, +using SQL syntax to filter, sort and otherwise +manipulate the values. +\end{important} + +This bundle consists of the following packages: +\begin{description} +\item[\sty{datatool}] Main package providing database support. +Automatically loads \sty{datatool-base}. + +\item[\sty{datatool-base}] Provides the main library code for +numerical and string functions. Automatically +loads \sty{datatool-fp} or \sty{datatool-pgfmath} depending on +package options. + +\item[\sty{datagidx}] Package for generating indexes and glossaries. +Automatically loads \sty{datatool}. + +\item[\sty{databar}] Package for drawing bar charts. +Automatically loads \sty{datatool}. + +\item[\sty{datapie}] Package for drawing pie charts. +Automatically loads \sty{datatool}. + +\item[\sty{dataplot}] Package for drawing simple line graphs. +Automatically loads \sty{datatool}. + +\item[\sty{databib}] Package for loading a bibliography into a +database. Automatically loads \sty{datatool}. + +\item[\sty{person}] Package for referencing people by the +appropriate gender pronouns. Automatically loads \sty{datatool}. + +\end{description} + +In addition, there are two mutually exclusive packages +\sty{datatool-fp} and \sty{datatool-pgfmath} that provide +mathematical related commands that are just wrapper functions for +\sty{fp} or \sty{pgfmath} commands. These can be loaded individually +without loading \sty{datatool}. For example, the following documents +produce the same results, but the first uses the \sty{fp} package +and the second uses the \sty{pgfmath} package: + +\begin{enumerate} +\item Using \sty{fp} macros: +\begin{verbatim} +\documentclass{article} +\usepackage{datatool-fp} +\begin{document} +1=2: \dtlifnumeq{1}{2}{true}{false}. +\end{document} +\end{verbatim} + +\item Using \sty{pgfmath} macros: +\begin{verbatim} +\documentclass{article} +\usepackage{datatool-pgfmath} +\begin{document} +1=2: \dtlifnumeq{1}{2}{true}{false}. +\end{document} +\end{verbatim} + +\end{enumerate} + +\begin{important} +Both \sty{fp} and \sty{pgfmath} have some limitations. These limitations +will therefore also be present in the various packages provided +with \sty{datatool}, according to the underlying package used. +\end{important} + +\cleardoublepage +\pdfbookmark[0]{Contents}{contents} +\tableofcontents +\cleardoublepage +\pdfbookmark[0]{List of Examples}{examples} +\listofexamples +\cleardoublepage +\pdfbookmark[0]{List of Figures}{figures} +\listoffigures +\cleardoublepage +\pdfbookmark[0]{List of Tables}{tables} +\listoftables + +\pagenumbering{arabic} +\chapter{Introduction} + + \changes{1.0}{2007 July 22}{Initial version} +The \sty{datatool} bundle consists of the following +packages: \sty{datatool} (which loads \sty{datatool-base} and either +\sty{datatool-fp} or \sty{datatool-pgfmath}), \sty{datagidx}, \sty{datapie}, \sty{dataplot}, +\sty{databar}, \sty{databib} and \sty{person}. + +\begin{itemize} +\item 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. +\end{itemize} +Package Options: + \begin{description} + \item[\pkgopt{utf8}] Boolean key. May be used to switch off the UTF-8 + support described on \pageref{utf8support} in \sectionref{sec:sort}. + If you both load \sty{inputenc} with UTF-8 + support and you use accent commands like \cs{'} or \cs{c} then make + sure you have at least version 2.05 of \sty{mfirstuc} + if you want to use commands like \ics{makefirstuc}. + \item[\pkgopt{verbose}] Boolean key. If + \pkgoptval{true}{verbose}, prints informational messages in + transcript. + \item[\pkgopt{math}] May take one of two values: + \pkgoptval{fp}{math} (load \sty{datatool-fp}) or + \pkgoptval{pgfmath}{math} (load \sty{datatool-pgfmath}). Default is: + \pkgoptval{fp}{math}. + \item[\pkgopt{delimiter}] Delimiter used in CSV files. + Default is a double quote (\texttt{\string"}). + \item[\pkgopt{separator}] Delimiter used in CSV files. + Default is a comma (\texttt{,}). + \end{description} + +\item The \sty{datatool-base} package can be used to: +\begin{itemize} +\item Determine whether 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} or \sty{pgfmath} packages, enabling fixed point +arithmetic to be performed on elements of the database. +\item Names can be converted to initials. +\item Determine if strings are all upper or lower case. +\item Perform string comparisons (both case sensitive and case insensitive). +\end{itemize} +Package Options: + \begin{description} + \item[\pkgopt{verbose}] Boolean key. If + \pkgoptval{true}{verbose}, prints informational messages in + transcript. + \item[\pkgopt{math}] May take one of two values: + \pkgoptval{fp}{math} (load \sty{datatool-fp}) or + \pkgoptval{pgfmath}{math} (load \sty{datatool-pgfmath}). Default is: + \pkgoptval{fp}{math}. + \end{description} + +\item The \sty{datagidx} package (see \autoref{sec:datagidx}) can be used +to generate indexes or glossaries as an alternative to packages +such as \sty{glossaries}. + +\item The \sty{datapie} package (see \autoref{sec:datapie}) 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} + +\item The \sty{databar} package (see \autoref{sec:databar}) 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{pgf} manual provides a more in-depth +discussion on the matter.) + +\item The \sty{dataplot} package (see \autoref{sec:dataplot}) can be used to convert a database into +a two dimensional plot using markers and/or lines. Three dimensional +plots are currently not supported. + +\item The \sty{databib} package (see \autoref{sec:databib}) can be used to convert a \BibTeX\ database +into a \sty{datatool} database. + +\item The \sty{person} package (see \autoref{sec:person}) can be +used for gender-specific mail-merging and similar uses to avoid the +cumbersome use of the impersonal \qt{he\slash she}. + +\end{itemize} + +\chapter{Data Types} +\label{sec:datatypes} + +The \sty{datatool-base} 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 +\begin{definition}[\DescribeMacro{\DTLsetnumberchars}]% +\cs{DTLsetnumberchars}\marg{number group character}\marg{decimal character} +\end{definition} +\begin{important} +Note that scientific notation is not supported, and the number group +character may not be used after the decimal character. +\end{important} + +\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 +\begin{definition}[\DescribeMacro{\DTLnewcurrencysymbol}]% +\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} + +\section{Conditionals} +\label{sec:ifconditions} + +The following conditionals are provided by the \sty{datatool-base} +package: +\begin{definition}[\DescribeMacro{\DTLifint}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifreal}]% +\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 considered 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}. + +\begin{definition}[\DescribeMacro{\DTLifcurrency}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifcurrencyunit}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifnumerical}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifstring}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifcasedatatype}]% +\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}. + +\begin{definition}[\DescribeMacro{\dtlifnumeq}]% +\cs{dtlifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false +paty} +\end{definition} +If \meta{num1} is equal to \meta{num2}, then do \meta{true part}, +otherwise to \meta{false part} where \meta{num1} and \meta{num2} +are plain numbers using a full stop as the decimal point and no +number group separator. For currency or locale dependent numbers use +\cs{DTLifnumeq}. + +\begin{definition}[\DescribeMacro{\DTLifnumeq}]% +\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}. + +\pagebreak +\begin{definition}[\DescribeMacro{\DTLifstringeq}]% +\cs{DTLifstringeq}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifstringeq*}]% +\cs{DTLifstringeq*}\marg{string1}\marg{string2}\marg{true part}\marg{false part} +\end{definition} +If \meta{string1} and \meta{string2} are the same, then do +\meta{true part}, otherwise do \meta{false part}. The starred +version ignores the case, the unstarred version is case +sensitive. 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 +\begin{verbatim} +\DTLifstringeq{Text}{text}{true}{false} +\end{verbatim} +produces: +\DTLifstringeq{Text}{text}{true}{false}, whereas +\begin{verbatim} +\DTLifstringeq*{Text}{text}{true}{false} +\end{verbatim} +produces: +\DTLifstringeq*{Text}{text}{true}{false}, however it should also be +noted that many commands will be ignored, so: +\begin{verbatim} +\DTLifstringeq{\uppercase{t}ext}{text}{true}{false} +\end{verbatim} +produces: +\DTLifstringeq{\uppercase{t}ext}{text}{true}{false}. + +Spaces are considered to be equivalent to \cs{space} and "~". For +example: +\begin{verbatim} +\DTLifstringeq{an apple}{an~apple}{true}{false} +\end{verbatim} +produces: +\DTLifstringeq{an apple}{an~apple}{true}{false}. Consecutive spaces +are treated as the same, for example: +\begin{verbatim} +\DTLifstringeq{an apple}{an apple}{true}{false} +\end{verbatim} +produces: +\DTLifstringeq{an apple}{an apple}{true}{false}. + +\begin{definition}[\DescribeMacro{\DTLifeq}]% +\cs{DTLifeq}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifeq*}]% +\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} (when using \cs{DTLifeq}) or \cs{DTLifstringeq*} +(when using \cs{DTLifeq*}). + +\begin{definition}[\DescribeMacro{\dtlifnumlt}]% +\cs{dtlifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false +paty} +\end{definition} +If \meta{num1} is less than \meta{num2}, then do \meta{true part}, +otherwise to \meta{false part} where \meta{num1} and \meta{num2} +are plain numbers using a full stop as the decimal point and no +number group separator. For currency or locale dependent numbers use +\cs{DTLifnumlt}. + +\begin{definition}[\DescribeMacro{\DTLifnumlt}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLifstringlt}]% +\cs{DTLifstringlt}\marg{string1}\marg{string2}\marg{true +part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifstringlt*}]% +\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}. The starred +version ignores the case, the unstarred version is case +sensitive. +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. + +The case sensitive (unstarred) version considers uppercase characters +to be less than lowercase characters, so +\begin{verbatim} +\DTLifstringlt{B}{a}{less}{not less} +\end{verbatim} +produces: +\DTLifstringlt{B}{a}{less}{not less}, whereas +\begin{verbatim} +\DTLifstringlt*{B}{a}{less}{not less} +\end{verbatim} +produces: +\DTLifstringlt*{B}{a}{less}{not less}. + +\begin{definition}[\DescribeMacro{\DTLiflt}]% +\cs{DTLiflt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLiflt*}]% +\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} (when using \cs{DTLiflt}) or +\cs{DTLstringlt*} (when using \cs{DTLiflt*}). + +\begin{definition}[\DescribeMacro{\DTLifnumgt}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLifstringgt}]% +\cs{DTLifstringgt}\marg{string1}\marg{string2}\marg{true +part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifstringgt*}]% +\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}. The +starred version ignores the case, the unstarred version is +case sensitive. 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. + +As with \cs{DTLifstringlt}, uppercase characters are considered +to be less than lower case characters when performing a +case sensitive comparison so: +\begin{verbatim} +\DTLifstringgt{B}{a}{greater}{not greater} +\end{verbatim} +produces: +\DTLifstringgt{B}{a}{greater}{not greater}, whereas +\begin{verbatim} +\DTLifstringgt*{B}{a}{greater}{not greater} +\end{verbatim} +produces: +\DTLifstringgt*{B}{a}{greater}{not greater}. + +\begin{definition}[\DescribeMacro{\DTLifgt}]% +\cs{DTLifgt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifgt*}]% +\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} (when using \cs{DTLifgt}) or +\cs{DTLstringgt*} (when using \cs{DTLifgt*}). + +\begin{definition}[\DescribeMacro{\DTLifnumclosedbetween}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifstringclosedbetween}]% +\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifstringclosedbetween*}]% +\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}. The starred version ignores the case, +the unstarred version is case sensitive. + +\begin{definition}[\DescribeMacro{\DTLifclosedbetween}]% +\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifclosedbetween*}]% +\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\newline +\cs{DTLifnumclosedbetween}\newline +otherwise it is equivalent to\newline +\cs{DTLifstringclosedbetween}\newline +(when using \cs{DTLifclosedbetween}) or\newline +\cs{DTLifstringclosedbetween*}\newline +(when using \cs{DTLifclosedbetween*}). + +\begin{definition}[\DescribeMacro{\DTLifnumopenbetween}]% +\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} +\DTLifnumopenbetween{5.4}{5}{7}{inside}{outside} +\end{verbatim} +produces: +\DTLifnumopenbetween{5.4}{5}{7}{inside}{outside}. +Note that end points are not included. For example: +\begin{verbatim} +\DTLifnumopenbetween{5}{5}{7}{inside}{outside} +\end{verbatim} +produces: +\DTLifnumopenbetween{5}{5}{7}{inside}{outside}. + +\begin{definition}[\DescribeMacro{\DTLifstringopenbetween}]% +\cs{DTLifstringopenbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifstringopenbetween*}]% +\cs{DTLifstringopenbetween*}\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. +The starred version ignores the case, +the unstarred version is case sensitive. + +\begin{definition}[\DescribeMacro{\DTLifopenbetween}]% +\cs{DTLifopenbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLifopenbetween*}]% +\cs{DTLifopenbetween*}\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{DTLifnumopenbetween} +otherwise it is equivalent to +\cs{DTLifstringopenbetween} +(when using \cs{DTLifopenbetween}) or +\cs{DTLifstringopenbetween*} +(when using \cs{DTLifopenbetween*}). + +\begin{definition}[\DescribeMacro{\DTLifFPclosedbetween}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLifFPopenbetween}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLifAllUpperCase}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifAllLowerCase}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifSubString}]% +\cs{DTLifSubString}\marg{string}\marg{substring}\marg{true +part}\marg{false part} +\end{definition} +This tests if \meta{substring} is a sub-string of \meta{string}. +This command performs a case sensitive match. For example: +\begin{verbatim} +\DTLifSubString{An apple}{app}{is substring}{isn't substring} +\end{verbatim} +produces: +\DTLifSubString{An apple}{app}{is substring}{isn't substring}. +Note that spaces are considered to be equivalent to \cs{space} +or "~", so +\begin{verbatim} +\DTLifSubString{An apple}{n~a}{is substring}{isn't substring} +\end{verbatim} +produces: +\DTLifSubString{An apple}{n~a}{is substring}{isn't substring}, +but other commands are skipped, so +\begin{verbatim} +\DTLifSubString{An \uppercase{a}pple}{app}{is substring}{isn't +substring} +\end{verbatim} +produces: +\DTLifSubString{An \uppercase{a}pple}{app}{is substring}{isn't +substring}, since the \cs{uppercase} command is ignored. Note also +that grouping is ignored, so: +\begin{verbatim} +\DTLifSubString{An {ap}ple}{app}{is substring}{isn't substring} +\end{verbatim} +produces: +\DTLifSubString{An {ap}ple}{app}{is substring}{isn't substring}. + +\cs{DTLifSubString} is case sensitive, so: +\begin{verbatim} +\DTLifSubString{An Apple}{app}{is substring}{isn't substring} +\end{verbatim} +produces: +\DTLifSubString{An Apple}{app}{is substring}{isn't substring}. + +\begin{definition}[\DescribeMacro{\DTLifStartsWith}]% +\cs{DTLifStartsWith}\marg{string}\marg{substring}\marg{true +part}\marg{false part} +\end{definition} +This is like \cs{DTLifSubString}, except that \meta{substring} must +occur at the start of \meta{string}. This command performs a case +sensitive match. For example, +\begin{verbatim} +\DTLifStartsWith{An apple}{app}{prefix}{not a prefix} +\end{verbatim} +produces: +\DTLifStartsWith{An apple}{app}{prefix}{not a prefix}. All the +above remarks for \cs{DTLifSubString} also applies to +\cs{DTLifStartsWith}. For example: +\begin{verbatim} +\DTLifStartsWith{\uppercase{a}n apple}{an~}{prefix}{not a prefix} +\end{verbatim} +produces: +\DTLifStartsWith{\uppercase{a}n apple}{an~}{prefix}{not a prefix}, +since \cs{uppercase} is ignored, and "~" is considered to be the +same as a space, whereas +\begin{verbatim} +\DTLifStartsWith{An apple}{an~}{prefix}{not a prefix} +\end{verbatim} +produces: +\DTLifStartsWith{An apple}{an~}{prefix}{not a prefix}. + +\section{\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}. These may be used with the boolean operations +\cs{not}, \cs{and} and \cs{or} provided by the \sty{ifthen} package. +See the \sty{ifthen} documentation for further details. + +\begin{definition}[\DescribeMacro{\DTLisstring}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLisnumerical}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLiscurrency}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLiscurrencyunit}]% +\cs{DTLiscurrencyunit}\marg{text}\marg{symbol} +\end{definition} +Tests if \meta{text} is currency and that currency 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}. + +\begin{definition}[\DescribeMacro{\DTLisreal}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLisint}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLislt}]% +\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 a case sensitive +alphabetical comparison is used. (Note that there is no starred +version of this command, but you can instead use \cs{DTLisilt} +to ignore the case.) + +\begin{definition}[\DescribeMacro{\DTLisilt}]% +\cs{DTLisilt}\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 a case insensitive +alphabetical comparison is used. + +\begin{definition}[\DescribeMacro{\DTLisgt}]% +\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 a case sensitive +alphabetical comparison is used. (Note that there is no starred +version of this command, instead use \cs{DTLisigt} to +ignore the case.) + +\begin{definition}[\DescribeMacro{\DTLisigt}]% +\cs{DTLisigt}\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 a case insensitive +alphabetical comparison is used. + +\begin{definition}[\DescribeMacro{\DTLiseq}]% +\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 a case sensitive +alphabetical comparison is used. (Note that there is no starred +version of this command, instead use \cs{DTLisieq}.) + +\begin{definition}[\DescribeMacro{\DTLisieq}]% +\cs{DTLisieq}\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 a case insensitive +alphabetical comparison is used. + +\begin{definition}[\DescribeMacro{\DTLisclosedbetween}]% +\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 a case sensitive +alphabetical comparison is used. (Note that there is no starred +version of this command, instead use \cs{DTLisiclosedbetween}.) + +\begin{definition}[\DescribeMacro{\DTLisiclosedbetween}]% +\cs{DTLisiclosedbetween}\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 a case insensitive +alphabetical comparison is used. + +\begin{definition}[\DescribeMacro{\DTLisopenbetween}]% +\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 a case sensitive +alphabetical comparison is used. (Note that there is no starred +version of this command, instead use \cs{DTLisiopenbetween}.) + +\begin{definition}[\DescribeMacro{\DTLisiopenbetween}]% +\cs{DTLisiopenbetween}\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 a case insensitive +alphabetical comparison is used. + +\begin{definition}[\DescribeMacro{\DTLisFPlt}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisFPlteq}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisFPgt}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisFPgteq}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisFPeq}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisFPclosedbetween}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisFPopenbetween}]% +\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). + +\begin{definition}[\DescribeMacro{\DTLisSubString}]% +\cs{DTLisSubString}\marg{string}\marg{substring} +\end{definition} +This checks if \meta{substring} is contained in \meta{string}. +The remarks about \cs{DTLifSubString} also apply to +\cs{DTLisSubString}. This command performs a case sensitive +match. + +\begin{definition}[\DescribeMacro{\DTLisPrefix}]% +\cs{DTLisPrefix}\marg{string}\marg{prefix} +\end{definition} +This checks if \meta{string} starts with \meta{prefix}. +The remarks about \cs{DTLifStartsWith} also apply to +\cs{DTLisPrefix}. This command performs a case sensitive +match. + +\begin{definition}[\DescribeMacro{\DTLisinlist}]% +\cs{DTLisinlist}\marg{element}\marg{list} +\end{definition} +This checks if \meta{element} is in \meta{list}. (Internally uses +\cs{DTLifinlist}.) + +\chapter{Fixed Point Arithmetic} +\label{sec:fp} + +\begin{important} +The \sty{datatool} bundle doesn't support scientific +notation. +\end{important} + +The \sty{datatool-base} package uses either the \sty{fp} or the \sty{pgfmath} 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} or \sty{pgfmath} packages. A numerical value (i.e.\ an integer, a real +or currency) can be converted into a plain decimal number using +\begin{definition}[\DescribeMacro{\DTLconverttodecimal}]% +\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 \cs{mynum} +can then be used in any of the arithmetic macros provided by the +\sty{fp} or \sty{pgfmath} packages. + +\begin{important} +The arguments to \cs{DTLconverttodecimal} don't get fully expanded +so, for example, +\begin{verbatim} +\def\myval{1.23} +\DTLconverttodecimal{\myval}{\mynum} +\end{verbatim} +will work, but the following \emph{\bfseries won't} work: +\begin{verbatim} +\def\myval{1.23} +\def\myotherval{\myval} +\DTLconverttodecimal{\myotherval}{\mynum} +\end{verbatim} +Nor will the following work: +\begin{verbatim} +\def\myval{9} +\DTLconverttodecimal{\myval 9}{\mynum} +\end{verbatim} +\end{important} +There are two commands provided to perform +the reverse: +\begin{definition}[\DescribeMacro{\DTLdecimaltolocale}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLdecimaltocurrency}]% +\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 it 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: +\begin{definition}[\DescribeMacro{\DTLsetdefaultcurrency}]% +\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-base} package provides convenience commands which +use \cs{DTLconverttodecimal}, and then use the basic macros provided +by the \sty{fp}\slash\sty{pgfmath} package. The resulting value is then converted +back into the locale format using +\cs{DTLdecimaltolocale} or \cs{DTLdecimaltocurrency}. +Note that since these commands use \cs{DTLconverttodecimal} the +caveat above regarding expansion also applies to all the commands. + +\begin{important} +If you don't require currency or locale conversion, you can reduce +the package overheads by using the commands defined in the +\sty{datatool-fp} or \sty{datatool-pgfmath} packages which provide +interface commands to \sty{fp} or \sty{pgfmath}, respectively. +(See sections~\ref*{sec:code:datatool-fp} +and~\ref*{sec:code:datatool-pgfmath} of the documented code, +\texttt{datatool-code.pdf}.) +Alternatively, you can just use the \sty{fp} or \sty{pgfmath} +commands explicitly. (See the \sty{fp} or \sty{pgf} manuals for +further details.) +\end{important} + + +\begin{definition}[\DescribeMacro{\DTLadd}]% +\cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgadd}]% +\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 convert currency to a real +number, 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. + +\begin{definition}[\DescribeMacro{\DTLaddall}]% +\cs{DTLaddall}\marg{cmd}\marg{number list} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgaddall}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLsub}]% +\cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgsub}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLmul}]% +\cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgmul}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLdiv}]% +\cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgdiv}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLabs}]% +\cs{DTLabs}\marg{cmd}\marg{num} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgabs}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLneg}]% +\cs{DTLneg}\marg{cmd}\marg{num} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgneg}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLsqrt}]% +\cs{DTLsqrt}\marg{cmd}\marg{num} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgsqrt}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLmin}]% +\cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgmin}]% +\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! + +\begin{definition}[\DescribeMacro{\DTLminall}]% +\cs{DTLminall}\marg{cmd}\marg{number list} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgminall}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLmax}]% +\cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgmax}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLmaxall}]% +\cs{DTLmaxall}\marg{cmd}\marg{number list} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgmaxall}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLmeanforall}]% +\cs{DTLmeanforall}\marg{cmd}\marg{number list} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgmeanall}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLvarianceforall}]% +\cs{DTLvarianceforall}\marg{cmd}\marg{number list} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgvarianceforall}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLsdforall}]% +\cs{DTLsdforall}\marg{cmd}\marg{number list} +\end{definition} +\pagebreak +\begin{definition}[\DescribeMacro{\DTLgsdforall}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLround}]% +\cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLground}]% +\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. Example: +\begin{verbatim} +\DTLround{\result}{3.135276}{2}\result +\end{verbatim} +produces: \DTLround{\result}{3.135276}{2}\result. + +\begin{definition}[\DescribeMacro{\DTLtrunc}]% +\cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgtrunc}]% +\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. Example: +\begin{verbatim} +\DTLtrunc{\result}{3.135276}{2}\result +\end{verbatim} +produces: \DTLtrunc{\result}{3.135276}{2}\result. + +\pagebreak +\begin{definition}[\DescribeMacro{\DTLclip}]% +\cs{DTLclip}\marg{cmd}\marg{num} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgclip}]% +\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. + +\chapter{Strings} +\label{sec: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: + +\begin{definition}[\DescribeMacro{\DTLsubstitute}]% +\cs{DTLsubstitute}\marg{cmd}\marg{original}\marg{replacement} +\end{definition} +This replaces the first occurrence of \meta{original} in +\meta{cmd} with \meta{replacement}. Note that \meta{cmd} must +be the name of a command. For example: +\begin{verbatim} +\def\mystr{abcdce}\DTLsubstitute{\mystr}{c}{z}\mystr +\end{verbatim} +produces: +\def\mystr{abcdce}\DTLsubstitute{\mystr}{c}{z}\mystr. + +\begin{definition}[\DescribeMacro{\DTLsubstituteall}]% +\cs{DTLsubstituteall}\marg{cmd}\marg{original}\marg{replacement} +\end{definition} +This replaces all occurrences of \meta{original} in +\meta{cmd} with \meta{replacement}, where again, \meta{cmd} must +be the name of a command. For example: +\begin{verbatim} +\def\mystr{abcdce}\DTLsubstituteall{\mystr}{c}{z}\mystr +\end{verbatim} +produces: +\def\mystr{abcdce}\DTLsubstituteall{\mystr}{c}{z}\mystr. + +\begin{definition}[\DescribeMacro{\DTLsplitstring}]% +\cs{DTLsplitstring}\marg{string}\marg{split text}\marg{before +cmd}\marg{after cmd} +\end{definition} +This splits \meta{string} at the first occurrence of \meta{split text} +and stores the before part in the command \meta{before cmd} and +the after part in the command \meta{after cmd}. For example: +\begin{verbatim} +\DTLsplitstring{abcdce}{c}{\beforepart}{\afterpart}% +Before part: ``\beforepart''. After part: ``\afterpart'' +\end{verbatim} +produces: +\DTLsplitstring{abcdce}{c}{\beforepart}{\afterpart}\relax +Before part: ``\beforepart''. After part: ``\afterpart''. +Note that for \cs{DTLsplitstring}, \meta{string} is not +expanded, so +\begin{verbatim} +\def\mystr{abcdce}% +\DTLsplitstring{\mystr}{c}{\beforepart}{\afterpart}% +Before part: ``\beforepart''. After part: ``\afterpart'' +\end{verbatim} +produces: +\def\mystr{abcdce}\relax +\DTLsplitstring{\mystr}{c}{\beforepart}{\afterpart}% +Before part: ``\beforepart''. After part: ``\afterpart''. If you +want the string expanded, you will need to use \cs{expandafter}: +\begin{verbatim} +\def\mystr{abcdce}% +\expandafter\DTLsplitstring\expandafter +{\mystr}{c}{\beforepart}{\afterpart}% +Before part: ``\beforepart''. After part: ``\afterpart'' +\end{verbatim} +which produces: +\def\mystr{abcdce}\relax +\expandafter\DTLsplitstring\expandafter +{\mystr}{c}{\beforepart}{\afterpart}\relax +Before part: ``\beforepart''. After part: ``\afterpart''. + +\begin{definition}[\DescribeMacro{\DTLinitials}]% +\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} (including the final full stop). Note that +\begin{verbatim} +\DTLinitials{Mary-Ann} +\end{verbatim} +produces: +\DTLinitials{Mary-Ann} (including the final full stop). +Be careful if the initial letter has an +accent. The accented letter needs to be placed in a group, if +you want the initial to also have an accent, otherwise the +accent command will be ignored. For example: +\begin{verbatim} +\DTLinitials{{\'E}lise Adams} +\end{verbatim} +produces: +\DTLinitials{{\'E}lise Adams}, whereas +\begin{verbatim} +\DTLinitials{\'Elise Adams} +\end{verbatim} +produces: +\DTLinitials{\'Elise Adams} In fact, any command which appears +at the start of the name that is not enclosed in a group will +be ignored. For example: +\begin{verbatim} +\DTLinitials{\MakeUppercase{m}ary ann} +\end{verbatim} +produces: +\DTLinitials{\MakeUppercase{m}ary ann}, whereas +\begin{verbatim} +\DTLinitials{{\MakeUppercase{m}}ary ann} +\end{verbatim} +produces: +\DTLinitials{{\MakeUppercase{m}}ary ann}, but note that +\begin{verbatim} +\DTLinitials{\MakeUppercase{mary ann}} +\end{verbatim} +produces: +\DTLinitials{\MakeUppercase{mary ann}} + +\begin{definition}[\DescribeMacro{\DTLstoreinitials}]% +\cs{DTLstoreinitials}\marg{string}\marg{cmd} +\end{definition} +This converts \meta{string} into initials and stores the +result in \meta{cmd} which must be a command name. The remarks +about \cs{DTLinitials} also relate to \cs{DTLstoreinitials}. +For example +\begin{verbatim} +\DTLstoreinitials{Marie-{\'E}lise del~Rosario}{\theInitials}\theInitials +\end{verbatim} +produces: +\DTLstoreinitials{Marie-{\'E}lise del~Rosario}{\theInitials}\theInitials + +Both the above commands rely on the following to format the +initials: +\begin{definition}[\DescribeMacro{\DTLafterinitials}]% +\cs{DTLafterinitials} +\end{definition} +This indicates what to do at the end of the initials. This +simply does a full stop by default. + +\begin{definition}[\DescribeMacro{\DTLbetweeninitials}]% +\cs{DTLbetweeninitials} +\end{definition} +This indicates what to do between initials. This does a +full stop by default. + +\begin{definition}[\DescribeMacro{\DTLinitialhyphen}]% +\cs{DTLinitialhyphen} +\end{definition} +This indicates what to do at a hyphen. This simply does a hyphen +by default, but can be redefined to do nothing to prevent the +hyphen appearing in the initials. + +\begin{definition}[\DescribeMacro{\DTLafterinitialbeforehyphen}]% +\cs{DTLafterinitialbeforehyphen} +\end{definition} +This indicates what to do between an initial and a hyphen. +This simply does a full stop by default. + +For example +\begin{verbatim} +\renewcommand*{\DTLafterinitialbeforehyphen}{}% +\DTLinitials{Marie-{\'E}lise del~Rosario} +\end{verbatim} +produces: +{\renewcommand*{\DTLafterinitialbeforehyphen}{}\relax +\DTLinitials{Marie-{\'E}lise del~Rosario}} +whereas +\begin{verbatim} +\renewcommand*{\DTLafterinitialbeforehyphen}{}% +\renewcommand*{\DTLafterinitials}{}% +\renewcommand*{\DTLbetweeninitials}{}% +\renewcommand*{\DTLinitialhyphen}{}% +\DTLinitials{Marie-{\'E}lise del~Rosario} +\end{verbatim} +produces: +{\renewcommand*{\DTLafterinitialbeforehyphen}{}\relax +\renewcommand*{\DTLafterinitials}{}\relax +\renewcommand*{\DTLbetweeninitials}{}\relax +\renewcommand*{\DTLinitialhyphen}{}\relax +\DTLinitials{Marie-{\'E}lise del~Rosario}} + +\chapter{Comma-Separated Lists} +\label{sec:csvlists} + +The \styfmt{datatool-base} package automatically loads the +\sty{etoolbox} package, so you can use any of the list +commands provided by that package, or you can use +the internal command \cs{@for} provided by the \LaTeX\ kernel +(and modified by the \sty{xfor} package, which is also loaded +by \styfmt{datatool-base}). + +In addition to those commands, \styfmt{datatool-base} +provides some commands that deal with comma-separated lists. +Note that this just refers to a control sequence that stores +a list of elements separated by commas, for example: +\begin{verbatim} +\newcommand{\mylist}{elephant,ant,zebra,duck} +\end{verbatim} +This isn't the same as comma-separated files, which is dealt +with in \sectionref{sec:databases}. + +\begin{definition}[\DescribeMacro{\DTLformatlist}] +\cs{DTLformatlist}\marg{list} +\end{definition} +Formats the comma-separated list. The unstarred version scopes +the internal operation. The starred form doesn't. +The \meta{list} may either be an explicit comma-separated list or +a control sequence whose replacement +text is a comma-separated list. If the list contains empty +elements then \cs{DTLformatlist} will either include or +skip the empty element according to the conditional: +\begin{definition}[\DescribeMacro{\ifDTLlistskipempty}] +\cs{ifDTLlistskipempty} +\end{definition} +For example: +\begin{verbatim} +\newcommand{\mylist}{elephant,,ant,zebra,duck}% +\DTLlistskipemptytrue +\DTLformatlist{\mylist}\par +\DTLlistskipemptyfalse +\DTLformatlist{\mylist} +\end{verbatim} +which produces: +\begin{display} +\newcommand{\mylist}{elephant,,ant,zebra,duck}% +\DTLlistskipemptytrue +\DTLformatlist{\mylist}\par +\DTLlistskipemptyfalse +\DTLformatlist{\mylist} +\end{display} +The default setting is +\begin{verbatim} +\DTLlistskipemptytrue +\end{verbatim} +Note that this may cause a difference when upgrading to v2.31 +as in previous versions \cs{DTLformatlist} didn't skip empty +elements. To restore the original behaviour use: +\begin{verbatim} +\DTLlistskipemptyfalse +\end{verbatim} +before \cs{DTLformatlist}. + +The list formatting command inserts +\begin{definition}[\DescribeMacro\DTLlistformatsep] +\cs{DTLlistformatsep} +\end{definition} +between each item, except for the last pair which uses: +\begin{definition}[\DescribeMacro\DTLlistformatlastsep] +\cs{DTLlistformatlastsep} +\end{definition} +if there are only two items in the list or +\begin{definition}[\DescribeMacro\DTLlistformatoxford] +\cs{DTLlistformatoxford}\cs{DTLlistformatlastsep} +\end{definition} +if there are three or more items in the list. +\cs{DTLlistformatlastsep} uses +\begin{definition}[\DescribeMacro\DTLandname] +\cs{DTLandname} +\end{definition} +Each item in the list is formatted according to +\begin{definition}[\DescribeMacro\DTLlistformatitem] +\cs{DTLlistformatitem}\marg{item} +\end{definition} + +The default definitions are: +\begin{itemize} +\item \cs{DTLlistformatitem}\marg{item}: just does \meta{item}; +\item \cs{DTLlistformatsep}: \verb*|, | (comma followed by a space); +\item \cs{DTLandname}: if \ics{andname} is +defined this is defined as \cs{andname} +otherwise it's defined as \verb|\&|; +\item \cs{DTLlistformatlastsep}: does \verb*| \DTLandname\space|; +\item \cs{DTLlistformatoxford}: does nothing (so if you want an +Oxford comma you need to redefine this). +\end{itemize} +For example +\begin{verbatim} +\renewcommand{\DTLlistformatitem}[1]{\emph{#1}}% +\renewcommand{\DTLlistformatoxford}{,}% +\renewcommand{\DTLandname}{and}% +One: \DTLformatlist{elephant}. + +Two: \DTLformatlist{elephant,ant}. + +Three: \DTLformatlist{elephant,ant,zebra}. + +Four: \DTLformatlist{elephant,ant,zebra,duck}. +\end{verbatim} +produces: +\begin{display} +\renewcommand{\DTLlistformatitem}[1]{\emph{#1}}% +\renewcommand{\DTLlistformatoxford}{,}% +\renewcommand{\DTLandname}{and}% +One: \DTLformatlist{elephant}. + +Two: \DTLformatlist{elephant,ant}. + +Three: \DTLformatlist{elephant,ant,zebra}. + +Four: \DTLformatlist{elephant,ant,zebra,duck}. +\end{display} + +You can test if an element is contained in a comma-separated list +using: +\begin{definition}[\DescribeMacro{\DTLifinlist}] +\cs{DTLifinlist}\marg{element}\marg{list}\marg{true part}\marg{false part} +\end{definition} +If \meta{element} is contained in the comma-separated list given +by \meta{list}, then this does \meta{true part} otherwise it does false +part. (Does a one level expansion on \meta{list}, but no +expansion on \meta{element}.) + +\begin{definition}[\DescribeMacro{\DTLnumitemsinlist}] +\cs{DTLnumitemsinlist}\marg{list}\marg{cmd} +\end{definition} +Counts the number of elements in \meta{list} and stores the +result in \meta{cmd}, which must be a control sequence. +As from v2.31, this obeys the conditional \cs{ifDTLlistskipempty} +to determine if empty elements should be skipped. For example: +\begin{verbatim} +\newcommand{\mylist}{foo,,bar,baz,wibble} +Number of non-empty elements: +\DTLnumitemsinlist{\mylist}{\listnum}\listnum.\par +\DTLlistskipemptyfalse +Number of elements (including empty): +\DTLnumitemsinlist{\mylist}{\listnum}\listnum. +\end{verbatim} +This produces: +\begin{display} +\newcommand{\mylist}{foo,,bar,baz,wibble} +Number of non-empty elements: \DTLnumitemsinlist{\mylist}{\listnum}\listnum.\par +\DTLlistskipemptyfalse +Number of elements (including empty): \DTLnumitemsinlist{\mylist}{\listnum}\listnum. +\end{display} + +\begin{definition}[\DescribeMacro{\DTLlistelement}] +\cs{DTLlistelement}\marg{list}\marg{index} +\end{definition} +Does the \meta{index}th element of the list (starting at 1 for +the first element) or generates a warning if the index is out +of range. This obeys the conditional \cs{ifDTLlistskipempty} +to determine if empty elements should be skipped. +For example: +\begin{verbatim} +\newcommand{\mylist}{foo,,bar,baz,wibble} +3rd item in list (skip empty): \DTLlistelement{\mylist}{3}.\par +\ifDTLlistskipempty +3rd item in list (include empty): \DTLlistelement{\mylist}{3}. +\end{verbatim} +This produces: +\begin{display} +\newcommand{\mylist}{foo,,bar,baz,wibble} +3rd item in list (skip empty): \DTLlistelement{\mylist}{3}.\par +\ifDTLlistskipempty +3rd item in list (include empty): \DTLlistelement{\mylist}{3}. +\end{display} + +\begin{definition}[\DescribeMacro{\DTLfetchlistelement}] +\cs{DTLfetchlistelement}\marg{list}\marg{index}\marg{cs} +\end{definition} +Like \cs{DTLlistelement} but it stores the \meta{index}th +element in the command given by \meta{cs}. + +\begin{definition}[\DescribeMacro\dtlsortlist] +\cs{dtlsortlist}\marg{list cs}\marg{criteria cs} +\end{definition} +This sorts the comma-separated list stored in the command +\meta{list cs} according to the criteria command +\meta{criteria cs}. The criteria command must take three arguments: +a count register in which to store the result, element \meta{A} and +element \meta{B}. If \meta{A} is considered less that \meta{B}, the +count register should be set to $-1$, if \meta{A} and \meta{B} are +considered the same then the count register should be set to 0, +and if \meta{A} is considered greater than \meta{B}, then the count +register should be set to 1. +\begin{important} +It's inefficient to use \TeX\ to sort and comparisons are only +made according to the character codes and so are inappropriate +for extended Latin or non-Latin alphabets. It's better to use +an external tool where possible. +\end{important} + +The \styfmt{datatool-base} package provides some predefined +criteria commands: +\begin{definition}[\DescribeMacro\dtlcompare] +\cs{dtlcompare}\marg{register}\marg{A}\marg{B} +\end{definition} +A case-sensitive comparison. +\begin{definition}[\DescribeMacro\dtlicompare] +\cs{dtlicompare}\marg{register}\marg{A}\marg{B} +\end{definition} +A case-insensitive comparison. +\begin{definition}[\DescribeMacro\dtlwordindexcompare] +\cs{dtlwordindexcompare}\marg{register}\marg{A}\marg{B} +\end{definition} +English word-ordering comparison for indexes, as described by +the Oxford Style Manual. +\begin{definition}[\DescribeMacro\dtlletterindexcompare] +\cs{dtlletterindexcompare}\marg{register}\marg{A}\marg{B} +\end{definition} +English letter-ordering comparison for indexes. +Those last two commands are described in more detail in +\sectionref{sec:sort}. + +For example: +\begin{verbatim} +\newcommand{\mylist}{elephant,ant,zebra,duck} +\dtlsortlist{\mylist}{\dtlcompare} + +\mylist. +\end{verbatim} +produces: +\begin{display} +\newcommand{\mylist}{elephant,ant,zebra,duck} +\dtlsortlist{\mylist}{\dtlcompare} + +\mylist. +\end{display} + +If you are building up a list, you may prefer to use: +\begin{definition}[\DescribeMacro\dtlinsertinto] +\cs{dtlinsertinto}\marg{element}\marg{list cs}\marg{criteria cs} +\end{definition} +which inserts \meta{element} into the list stored in the +command \meta{list cs} according to the criteria command +\meta{criteria cs}. This is more efficient than first building the +list and then sorting it. + +For example: +\begin{verbatim} +\newcommand{\mylist}{} +\dtlinsertinto{elephant}{\mylist}{\dtlcompare} +\dtlinsertinto{ant}{\mylist}{\dtlcompare} +\dtlinsertinto{zebra}{\mylist}{\dtlcompare} +\dtlinsertinto{duck}{\mylist}{\dtlcompare} + +\mylist. +\end{verbatim} +produces: +\begin{display} +\newcommand{\mylist}{} +\dtlinsertinto{elephant}{\mylist}{\dtlcompare} +\dtlinsertinto{ant}{\mylist}{\dtlcompare} +\dtlinsertinto{zebra}{\mylist}{\dtlcompare} +\dtlinsertinto{duck}{\mylist}{\dtlcompare} + +\mylist. +\end{display} + +Note that \cs{dtlinsertinto} doesn't expand \meta{element}. +If the element is stored in a command, you need to +expand it first. For example: +\begin{verbatim} +\newcommand*{\element}{ant} +\expandafter\dtlinsertinto\expandafter{\element}{\mylist}{\dtlcompare} +\end{verbatim} + +To ensure that the element is first fully expanded, you can +use: +\begin{definition}[\DescribeMacro\edtlinsertinto] +\cs{edtlinsertinto}\marg{element}\marg{list cs}\marg{criteria cs} +\end{definition} +This will fully expand \meta{element} using \cs{protected@edef} +and then use \cs{dtlinsertinto}. + +\chapter{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. + +\begin{important} +Whilst \TeX\ is an excellent typesetting language, +it is not designed as a database management system, and +attempting to use it as such is like trying to fasten a screw +with a knife instead of a screwdriver: it can be done, but requires +great care and is more time consuming. Version 2.0 of the +\sty{datatool} package uses a completely different method of storing +the data to previous versions.\footnote{Many thanks to Morten H\o gholm +for providing the new code.} As a result, the code is much more efficient, +however, large databases and complex operations will still slow the +time taken to process your document. Therefore, if you can, it is +better to do the complex operations using whatever system created +the data in the first place. +\end{important} + +Some advanced commands for accessing database information are +described in \autoref{sec:advanced}, but using \TeX\ is nowhere near +as efficient as, say, using a SQL database, so don't expect too much +from this package. + +\label{datatooltk}% +I've written a Java helper application to accompany \sty{datatool} +called \app{datatooltk}. The installer is available +on CTAN at +\url{http://mirrors.ctan.org/support/datatooltk/datatooltk-installer.jar}. The application will allow you to edit +files saved using \ics{DTLsaverawdb} or \ics{DTLprotectedsaverawdb} in a~graphical interface or +import data from a~SQL database, a~CSV file or a~\sty{probsoln} +dataset. + +Each database has the data stored internally in a token register and +the header information is stored in an internal control sequence. +In general you don't need to worry about the way it's stored, except +that row indexes start from 1 (the first row of data) and column +indexes also start from 1. Columns may be referenced by a label +but rows can only be referenced by the row index. Once the internal +commands and registers have been set, \styfmt{datatool} doesn't keep +a record of how or where the information came from (such as a CSV +file or through a file created by \app{datatooltk}). Changes to the +data only modify the internal commands and are lost at the end of +the \LaTeX\ run unless you save the data. + +\section{Creating a New Database} +\label{sec:newdb} + +\begin{definition}[\DescribeMacro{\DTLnewdb}]% +\cs{DTLnewdb}\marg{db name} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgnewdb}]% +\cs{DTLgnewdb}\marg{db name} +\end{definition} +This command creates a new empty database called \meta{db name}. The +second form is for global definitions. You +can test if a database is empty using: +\begin{definition}[\DescribeMacro{\DTLifdbempty}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLrowcount}]% +\cs{DTLrowcount}\marg{db name} +\end{definition} +This command displays the number of rows in the database called +\meta{db name}. + +\begin{definition}[\DescribeMacro{\DTLcolumncount}]% +\cs{DTLcolumncount}\marg{db name} +\end{definition} +This command displays the number of columns (or keys) in the +database called \meta{db name}. + +\begin{definition}[\DescribeMacro{\DTLnewrow}]% +\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}. The column count is given by +\begin{verbatim} +\DTLcolumncount{mydata} +\end{verbatim} +which produces: \DTLcolumncount{mydata}. + +\begin{definition}[\DescribeMacro{\DTLnewdbentry}]% +\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 last 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 last row of the database named +\texttt{mydata}, and then adds an entry with identifier +\texttt{FirstName} and value \texttt{John}. Note that the +key should not contain any fragile commands. It is generally +best to only use non-active characters in the key. + +The value isn't expanded by default, but you can change this +using the declaration: +\begin{definition}[\DescribeMacro{\dtlexpandnewvalue}] +\cs{dtlexpandnewvalue} +\end{definition} +This can be localised by placing it in a group, or you can +switch back using: +\begin{definition}[\DescribeMacro{\dtlnoexpandnewvalue}] +\cs{dtlnoexpandnewvalue} +\end{definition} + +\importantpar +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: +\begin{definition}[\DescribeMacro{\DTLpar}]% +\cs{DTLpar} +\end{definition} +For example: +\begin{verbatim} +\DTLnewdbentry{mydata}{Description}{First paragraph.\DTLpar +Second paragraph.} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLaddentryforrow}]% +\cs{DTLaddentryforrow}\marg{db}\marg{assign list}% +\marg{condition}\marg{key}\allowbreak\marg{value} +\end{definition} +This adds the entry with the key given by \meta{key} and value +given by \meta{value} to the first row in the database +\meta{db} which satisfies the condition given by +\meta{condition}. The \meta{assign list} argument is the same +as for \cs{DTLforeach} (described in \autoref{sec:dbforeach}) +and may be used to set the values which are to be tested in +\meta{condition} (where, again, \meta{condition} is the same +as for \cs{DTLforeach}). For example: +\begin{verbatim} +\DTLaddentryforrow{mydata}{\firstname=FirstName,\surname=Surname}% +{\DTLiseq{\firstname}{John}\and\DTLiseq{\surname}{Smith}}% +{Score}{75} +\end{verbatim} +Note that unlike \cs{DTLnewdbentry}, the value is always expanded +when adding an entry using \cs{DTLaddentryforrow}. + +\begin{definition}[\DescribeMacro{\DTLsetheader}]% +\cs{DTLsetheader}\marg{db}\marg{key}\marg{header} +\end{definition} +This assigns a header for a given key in the database named +\meta{db}. This is used by \cs{DTLdisplaydb} and +\cs{DTLdisplaylongdb} in the header row (see +\autoref{sec:displaydb}). If you don't assign +a header, the header will be given by the key. +For example: +\begin{verbatim} +\DTLsetheader{mydata}{Price}{Price (\$)} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLaddcolumn}] +\cs{DTLaddcolumn}\marg{db}\marg{key} +\end{definition} +Adds a new column with the given key to the database \meta{db}. This +doesn't add any data to the column, just identifies it as an +available column. The starred version doesn't check if the database +exists. + +\section{Loading a Database from an External ASCII File} +\label{sec:loaddb} + +\begin{important} +\cs{DTLloaddb} and \cs{DTLloadrawdb}, described in this section, can't +parse files that have newline characters within entries. The +\app{datatooltk} application (see page~\pageref{datatooltk}) can +parse them, so if you have multilined entries in a CSV file, you +can convert it to \sty{datatool}'s internal database format using +\app{datatooltk} and the input it using \ics{input} or \ics{DTLloaddbtex}. See the +\app{datatooltk} documentation for further details. +\end{important} +Remember that row numbers in \sty{datatool} refer to the row index +of the internal data not to line numbers in the CSV file. + +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: +\begin{definition}[\DescribeMacro{\DTLloaddb}]% +\cs{DTLloaddb}\oarg{options}\marg{db name}\marg{filename} +\end{definition} + +\begin{important} +Make sure your document uses the same encoding as \meta{filename}. +For example, if \meta{filename} is UTF-8, then include the following +in your document: +\begin{verbatim} +\usepackage[utf8]{inputenc} +\end{verbatim} +\end{important} +By default, \cs{DTLloaddb} creates a new database called \meta{db +name} before it loads the data given in the file \meta{filename}. +If you want to append the data, use +\begin{definition}[\DTLnewdbonloadfalse] +\cs{DTLnewdbonloadfalse} +\end{definition} +before you use \cs{DTLloaddb}. You can reverse this using +\begin{definition}[\DTLnewdbonloadtrue] +\cs{DTLnewdbonloadtrue} +\end{definition} +The file (\meta{filename}) may have a header row at the start of the file, +which provides the \meta{key} when creating a new database entry +using \ics{DTLnewdbentry}. +The optional argument \meta{options} +is a \meta{key}=\meta{value} list of options. +\begin{important} +Some of the keys may take a comma-separated list as a value. +Note that spaces count in the default \TeX\ way within these lists. +Remember that \TeX\ considers an end-of-line character as a space. +If you have a long list, consider using the comment character (\%) +to suppress unwanted space caused by line breaks in the code. +\end{important} +Available options are: +\begin{description} +\item[\csopt{DTLloaddb}{noheader}] This is a boolean value and +indicates if the file does not contain a header. If no value is +supplied, "true" is assumed (i.e.\ the file doesn't contain a header +row). If this option is omitted, it is assumed that the file +contains a header row. + +\item[\csopt{DTLloaddb}{keys}] This is a comma-separated list of +keys to use, where the keys are listed in the same order as the +columns. If the file has a header, these keys will override the +values given in the header row. If the file has no header row and no +keys are supplied in \meta{options}, then the keys will be given by +\cs{dtldefaultkey}\meta{n}, where \meta{n} is the column number and +\DescribeMacro{\dtldefaultkey}\cs{dtldefaultkey} defaults to +``\dtldefaultkey''. Note that the list of keys must be delimited by +braces since they contain commas. +For example: +\begin{verbatim} +\DTLloaddb[noheader,keys={Temperature,Time,T2G}]{data}{data.csv} +\end{verbatim} + +\item[\csopt{DTLloaddb}{autokeys}] This is a boolean option that +will automatically assign default keys (\cs{dtldefaultkey}\meta{n}, +as above) for all columns, regardless of whether the file has a +header row. If true, this option overrides the +\csopt{DTLloaddb}{keys} option. You may want to use this if you have +a header row with many fields containing active characters but you +only want to use commands like \cs{DTLdisplaydb}. (In which case, +you may want to consider using \cs{DTLloadrawdb} to load the data.) + +\item[\csopt{DTLloaddb}{headers}] This is a comma-separated list of +headers. If not supplied, the header will be the same as that given +in the header row, or the key if there is no header row. Note that +the list of headers must be delimited by braces since they contain +commas. For example: +\begin{verbatim} +\DTLloaddb[noheader,keys={Temperature,Time,T2G},% +headers={\shortstack{Incubation\\Temperature},% +\shortstack{Incubation\\Time},% +\shortstack{Time to\\Growth}}]{data}{data.csv} +\end{verbatim} + +\item[\csopt{DTLloaddb}{omitlines}] +This should be a non-negative integer that specifies how many rows +to skip at the start of the file. +\end{description} + +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: +\begin{definition}[\DescribeMacro{\DTLsettabseparator}]% +\cs{DTLsettabseparator} +\end{definition} +Note that this command changes the category code of the tab +character to~12 (other). If, after you have loaded your data, you want to +reset the tab category code to~10 (space), you can use: +\begin{definition}[\DescribeMacro{\DTLmaketabspace}]% +\cs{DTLmaketabspace} +\end{definition} +Don't use this command before you load any tab-separated data. + +To set the separator to a character other than a tab, you need to use +\begin{definition}[\DescribeMacro{\DTLsetseparator}]% +\cs{DTLsetseparator}\marg{character} +\end{definition} +The delimiter can be changed using +\begin{definition}[\DescribeMacro{\DTLsetdelimiter}]% +\cs{DTLsetdelimiter}\marg{character} +\end{definition} +\begin{important} +Note that spaces count in the usual \TeX\ manner and won't be +trimmed from either side of the separators. +\end{important} + +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 percent symbol \% can be used as a comment character within the +file. + +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, +such as 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: +\begin{definition}[\DescribeMacro{\DTLloadrawdb}]% +\cs{DTLloadrawdb}\oarg{options}\marg{db name}\marg{filename} +\end{definition} +This is similar to \ics{DTLloaddb} except that it maps nine of +the ten special characters onto commands which 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} +As with \ics{DTLloaddb}, you can govern whether or not a new +database should be created with \ics{DTLnewdbonloadtrue} and +\ics{DTLnewdbonloadfalse}. + +Note that \cs{DTLloadrawdb} is not recommended for CSV files that +contain commands. Any active characters occurring within the +file must be mapped. The mapping is done through +expansion. Version 2.28 now uses \cs{xdef} rather than +\cs{protected@xdef}, but \cs{DTLloadrawdb} isn't intended for files +containing \LaTeX\ code, but rather for files generated by a +non-\TeX\ aware method that doesn't guard against \LaTeX\ special +characters. + +If you have UTF-8 data, it's best to use an engine that natively +supports Unicode. Remember that there's no point using +\cs{DTLloadrawdb} (instead of \cs{DTLloaddb}) if your file doesn't +contain any special characters that require mapping. It's less +efficient to load if each row has to be converted, particularly for +large files. + +\begin{table}[htbp] +\caption[Special character mappings used by +\cs{DTLloadrawdb}]{Special character mappings used by +\cs{DTLloadrawdb} (note that the backslash retains its active state)} +\label{tab:rawmappings} +\centering +\begin{tabular}{cl} +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{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 generally achieve the desired effect when used +in a \LaTeX\ document. It may therefore be necessary to convert +this symbol to an appropriate control sequence. This can be done +using the command: +\begin{definition}[\DescribeMacro{\DTLrawmap}]% +\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 replace all occurrences\footnote{when it is loaded into the +\LaTeX\ database, it does not modify the data file!}\ of +\texttt{\pounds} with \cs{pounds}. Naturally, the mappings must be +set \emph{prior} to loading the data with \cs{DTLloadrawdb}. + +\begin{important} +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. +\end{important} + +\section{Displaying the Contents of a Database} +\label{sec:displaydb} + +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 display the +entire database in a \env{tabular} or \env{longtable} +environment. + +\begin{definition}[\DescribeMacro{\DTLdisplaydb}]% +\cs{DTLdisplaydb}\oarg{omit list}\marg{db} +\end{definition} +This displays the database given by \meta{db} in a \env{tabular} +environment. The first row displays the headers for the database +in bold, the subsequent rows display the values for each key +in each row of the database. The optional argument \meta{omit list} +is a comma-separated list of column keys to omit. (All columns displayed by default.) + +\begin{definition}[\DescribeMacro{\DTLdisplaylongdb}]% +\cs{DTLdisplaylongdb}\oarg{options}\marg{db} +\end{definition} +This is like \cs{DTLdisplaydb} except that it uses the +\env{longtable} environment instead of the \env{tabular} +environment. Note that if you use this command, you must load the +\sty{longtable} package, as it is not loaded by \sty{datatool}. +The optional argument \meta{options} is a comma-separated list +of key=value pairs. The following keys are available: +\begin{description} +\item[caption] The caption for the \env{longtable}. + +\item[contcaption] The continuation caption. + +\item[shortcaption] The caption to be used in the list of tables. + +\item[label] The label for this table. + +\item[omit] Comma-separated list of column keys to omit. + +\item[foot] The \env{longtable}'s foot. + +\item[lastfoot] The foot for the last page of the \env{longtable}. +\end{description} +For example, suppose I have a database called "iris", then I can +display the contents in a \env{longtable} using: +\begin{verbatim} +\DTLdisplaylongdb[% +caption={Iris Data},% +label={tab:iris},% +contcaption={Iris Data (continued)},% +foot={\em Continued overleaf},% +lastfoot={}% +]{iris} +\end{verbatim} +I can then reference the table using \verb|\ref{tab:iris}|. + +See the \sty{longtable} documentation for details on how to +change the \env{longtable} settings, such as how to change the +table so that it is left aligned instead of centred on the page. + +Note that if you want more control over the way the data is +displayed, for example, you want to filter rows or columns, you will +need to use \cs{DTLforeach}, described in \autoref{sec:dbforeach}. + +\begin{example}{Displaying the Contents of a Database}{ex:displaydb} +Suppose I have a file called \texttt{t2g.csv} that contains the +following: +\begin{verbatim} +40,120,40 +40,90,60 +35,180,20 +55,190,40 +\end{verbatim} +This represents time to growth data, where the first column +is the incubation temperature, the second column is the incubation +time and the third column is the time to growth. This file has no +header row, so when it is loaded, the \csopt{DTLloaddb}{noheaders} +option is required. Note that \cs{DTLdisplaydb} only puts the data +in a \env{tabular} environment, so \cs{DTLdisplaydb} needs to be +put in a \env{table} environment with a caption to make it a float. + +First load the data base, setting the keys and headers: +\begin{verbatim} +\DTLloaddb[noheader,% +keys={Temperature,Time,T2G},% +headers={\shortstack{Incubation\\Temperature},% +\shortstack{Incubation\\Time},\shortstack{Time to\\Growth}}% +]{t2g}{t2g.csv} +\end{verbatim} +\DTLnewdb{t2g}\relax +\DTLnewrow*{t2g}\relax +\DTLnewdbentry*{t2g}{Temperature}{40}\relax +\DTLnewdbentry*{t2g}{Time}{120}\relax +\DTLnewdbentry*{t2g}{T2G}{40}\relax +\DTLnewrow*{t2g}\relax +\DTLnewdbentry*{t2g}{Temperature}{40}\relax +\DTLnewdbentry*{t2g}{Time}{90}\relax +\DTLnewdbentry*{t2g}{T2G}{60}\relax +\DTLnewrow*{t2g}\relax +\DTLnewdbentry*{t2g}{Temperature}{35}\relax +\DTLnewdbentry*{t2g}{Time}{180}\relax +\DTLnewdbentry*{t2g}{T2G}{20}\relax +\DTLnewrow*{t2g}\relax +\DTLnewdbentry*{t2g}{Temperature}{55}\relax +\DTLnewdbentry*{t2g}{Time}{190}\relax +\DTLnewdbentry*{t2g}{T2G}{40}\relax +\DTLsetheader*{t2g}{Temperature}{\shortstack{Incubation\\Temperature}}\relax +\DTLsetheader*{t2g}{Time}{\shortstack {Incubation\\Time}}\relax +\DTLsetheader*{t2g}{T2G}{\shortstack {Time to\\Growth}}\relax + +Now display the data in a table: +\begin{verbatim} +\begin{table}[htbp] +\caption{Time to Growth Data} +\centering +\DTLdisplaydb{t2g} +\end{table} +\end{verbatim} +The result is shown in \autoref{tab:t2g}. +\begin{table}[htbp] +\caption{Time to Growth Data} +\label{tab:t2g} +\centering +\DTLdisplaydb{t2g} +\end{table} +\end{example} + +Each column in the database has an associated data type which +indicates what type of data is in that column. This may be one +of: string, integer, real number or currency. If a column contains +more than one type, the data type is determined as follows: +\begin{itemize} +\item If the column contains at least one string, then the column +data type is string. + +\item If the column doesn't contain a string, but contains at least +one currency, then the column data type is currency. + +\item If the column contains only real numbers and integers, the +column data type is real number. + +\item The column data type is integer if the column only +contains integers. +\end{itemize} +The column data type is updated whenever a new entry is added +to the database. Note that the column data type is not adjusted +when an entry is removed from the database. + +The column alignments used by \cs{DTLdisplaydb} are given by: +\begin{definition}[\DescribeMacro{\dtlstringalign}]% +\cs{dtlstringalign} +\end{definition}\noindent +The string alignment defaults to \texttt{l} (left aligned). + +\begin{definition}[\DescribeMacro{\dtlintalign}]% +\cs{dtlintalign} +\end{definition}\noindent +The integer alignment defaults to \texttt{r} (right aligned). + +\begin{definition}[\DescribeMacro{\dtlrealalign}]% +\cs{dtlrealalign} +\end{definition}\noindent +The alignment for real numbers defaults to \texttt{r} (right +aligned). + +\begin{definition}[\DescribeMacro{\dtlcurrencyalign}]% +\cs{dtlcurrencyalign} +\end{definition}\noindent +The currency alignment defaults to \texttt{r} (right aligned). + +You can redefine these to change the column alignments. For +example, if you want columns containing strings to have the +alignment "p{2in}", then you can redefine \cs{dtlstringalign} as +follows: +\begin{verbatim} +\renewcommand{\dtlstringalign}{p{2in}} +\end{verbatim} + +\begin{important} +You can't use \sty{siunitx}'s "S" column alignment +with either \cs{DTLdisplaydb} or \cs{DTLdisplaylongdb}. Instead, you +will need to use \cs{DTLforeach}. The \sty{siunitx} documentation +provides an example. +\end{important} + +In addition to the \cs{dtl}\meta{type}"align" commands above, you +can also modify the \env{tabular} column styles by redefining the +following three commands: +\begin{definition}[\DescribeMacro{\dtlbeforecols}] +\cs{dtlbeforecols} +\end{definition} +(before the first column) +\begin{definition}[\DescribeMacro{\dtlbetweencols}] +\cs{dtlbetweencols} +\end{definition} +(between each column) and +\begin{definition}[\DescribeMacro{\dtlaftercols}] +\cs{dtlaftercols} +\end{definition} +(after the last column). + +For example, to +place a vertical line before the start of the first column and +after the last column, do: +\begin{verbatim} +\renewcommand{\dtlbeforecols}{|} +\renewcommand{\dtlaftercols}{|} +\end{verbatim} +If you additionally want vertical lines between columns, do: +\begin{verbatim} +\renewcommand{\dtlbetweencols}{|} +\end{verbatim} + +Limited modifications can be made to the way the data is displayed +with \cs{DTLdisplaydb} and \cs{DTLdisplaylongdb}. +The commands controlling the formatting are described below. +If a more complicated layout is required, you will need to use +\cs{DTLforeach} described in \autoref{sec:dbforeach}. + +\begin{definition}[\DescribeMacro{\dtlheaderformat}]% +\cs{dtlheaderformat}\marg{header} +\end{definition} +This indicates how to format a column header, where the header is +given by \meta{header}. This defaults to +\cs{null}\cs{hfil}\cs{textbf}\marg{header}\cs{hfil}\cs{null}. + +\begin{definition}[\DescribeMacro{\dtlstringformat}]% +\cs{dtlstringformat}\marg{text} +\end{definition} +This specifies how to format each entry in the columns that contain +strings. This defaults to just displaying \meta{text}. + +\begin{definition}[\DescribeMacro{\dtlintformat}]% +\cs{dtlintformat}\marg{text} +\end{definition} +This specifies how to format each entry in the columns that contain +only integers. This defaults to just displaying \meta{text}. + +\begin{definition}[\DescribeMacro{\dtlrealformat}]% +\cs{dtlrealformat}\marg{text} +\end{definition} +This specifies how to format each entry in the columns that contain +only real numbers or a mixture of real numbers and integers. This +defaults to just displaying \meta{text}. + +\begin{definition}[\DescribeMacro{\dtlcurrencyformat}]% +\cs{dtlcurrencyformat}\marg{text} +\end{definition} +This specifies how to format each entry in the columns that contain +only currency or currency mixed with real numbers and/or integers. +This defaults to just displaying \meta{text}. + +\begin{definition}[\DescribeMacro{\dtldisplayvalign}] +\cs{dtldisplayvalign} +\end{definition} +Specifies the vertical alignment of the \env{tabular} environment +used by \cs{DTLdisplaydb}. Defaults to \texttt{c} (centred). May be redefined +to \texttt{t} (top) or \texttt{b} (bottom). + +\begin{definition}[\DescribeMacro{\dtldisplaycr}] +\cs{dtldisplaycr} +\end{definition} +Specifies how to separate rows. Defaults to just +\ics{tabularnewline}. + +\begin{definition}[\DescribeMacro{\dtldisplaystarttab}]% +\cs{dtldisplaystarttab} +\end{definition} +This is a hook to add something at the beginning of the +\env{tabular} environment. This defaults to nothing. +In the case of \cs{DTLdisplaylongdb}, this hook is done before the +header row on each page of the \env{longtable}. + +\begin{definition}[\DescribeMacro{\dtldisplayendtab}]% +\cs{dtldisplayendtab} +\end{definition} +This is a hook to add something at the end of the +\env{tabular} environment. This defaults to nothing. +In the case of \cs{DTLdisplaylongdb}, this hook is only done on the +\emph{last} page of the \env{longtable}. You have to use the +\texttt{foot} option to specify some code to do at the end of each page. + +\begin{definition}[\DescribeMacro{\dtldisplayafterhead}]% +\cs{dtldisplayafterhead} +\end{definition} +This is a hook to add something after the header row, before +the first row of data. This defaults to nothing. +In the case of \cs{DTLdisplaylongdb}, this hook is done after the +header row on each page of the \env{longtable}. + +\begin{definition}[\DescribeMacro{\dtldisplaystartrow}]% +\cs{dtldisplaystartrow} +\end{definition} +This is a hook to add something at the start of each row, but +not including the header row or the first row of data. This +defaults to nothing. + +If you want to use the \sty{booktabs} package, you can redefine the +above three commands to use \ics{toprule}, \ics{midrule} and +\ics{bottomrule}: +\begin{verbatim} +\renewcommand{\dtldisplaystarttab}{\toprule} +\renewcommand{\dtldisplayafterhead}{\midrule} +\renewcommand{\dtldisplayendtab}{\\\bottomrule} +\end{verbatim} + +\begin{example}{Balance Sheet}{ex:balance} +Suppose you have a file called "balance.csv" that contains +the following: +\begin{verbatim} +Description,In,Out,Balance +Travel expenses,,230,-230 +Conference fees,,400,-630 +Grant,700,,70 +Train fare,,70,0 +\end{verbatim} +\DTLnewdb{balance}\relax +\DTLnewrow{balance}\relax +\DTLnewdbentry{balance}{Description}{Travel expenses}\relax +\DTLnewdbentry{balance}{In}{}\relax +\DTLnewdbentry{balance}{Out}{230.00}\relax +\DTLnewdbentry{balance}{Balance}{-230.00}\relax +\DTLnewrow{balance}\relax +\DTLnewdbentry{balance}{Description}{Conference fees}\relax +\DTLnewdbentry{balance}{In}{}\relax +\DTLnewdbentry{balance}{Out}{400.00}\relax +\DTLnewdbentry{balance}{Balance}{-630.00}\relax +\DTLnewrow{balance}\relax +\DTLnewdbentry{balance}{Description}{Grant}\relax +\DTLnewdbentry{balance}{In}{700.00}\relax +\DTLnewdbentry{balance}{Out}{}\relax +\DTLnewdbentry{balance}{Balance}{70.00}\relax +\DTLnewrow{balance}\relax +\DTLnewdbentry{balance}{Description}{Train Fare}\relax +\DTLnewdbentry{balance}{In}{}\relax +\DTLnewdbentry{balance}{Out}{70.00}\relax +\DTLnewdbentry{balance}{Balance}{0.00}\relax +\DTLsetheader{balance}{In}{In (\pounds)}\relax +\DTLsetheader{balance}{Out}{Out (\pounds)}\relax +\DTLsetheader{balance}{Balance}{Balance (\pounds)}\relax +The data can be loaded using: +\begin{verbatim} +\DTLloaddb[headers={Description,In (\pounds),Out (\pounds),Balance +(\pounds)}]{balance}{balance.csv} +\end{verbatim} + +Suppose I want negative numbers to be displayed in red. I can do +this by redefining \cs{dtlrealformat} to check if the entry +is negative. For example: +\begin{verbatim} +\begin{table}[htbp] +\caption{Balance Sheet} +\renewcommand*{\dtlrealformat}[1]{\DTLiflt{#1}{0}{\color{red}}{}#1} +\centering +\DTLdisplaydb{balance} +\end{table} +\end{verbatim} +This produces \autoref{tab:balance}. +\begin{table}[htbp] +\caption{Balance Sheet} +\label{tab:balance} +\renewcommand*{\dtlrealformat}[1]{\DTLiflt{#1}{0}{\color{red}}{}#1} +\centering +\DTLdisplaydb{balance} +\end{table} +\end{example} + +\section{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. + +\begin{important} +The \cs{DTLforeach} command is provided as a convenient way of +iterating through databases with the option to filter rows, +cross-reference rows or have nested loops, but for large databases it can be +\emph{extremely slow}, especially if the unstarred version is used. +If you have a large database, consider pre-processing the data using +an external script. See also \sectionref{sec:advancediter}. +\end{important} + +\begin{definition}[\DescribeMacro{\DTLforeach}]% +\cs{DTLforeach}\oarg{condition}\marg{db name}\marg{assign list}\marg{text} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLforeach*}]% +\cs{DTLforeach*}\oarg{condition}\marg{db name}\marg{assign list}\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{assign list} is a +comma separated list of \meta{cmd}"="\meta{key} pairs. At the +start of each row, each command \meta{cmd} in \meta{assign list} +will be set to the value of the entry given by \meta{key}. +These commands may then be used in \meta{text}. + +\begin{important} +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. +\end{important} + +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 (such as \cs{not}, \cs{and}, +\cs{or}), as well as the commands +described in \autoref{sec:ifthen}. The default value of +\meta{condition} is "\boolean{true}". + +The starred version \cs{DTLforeach*} is a read-only version. +If you want to modify the database using any of the commands +described in \autoref{sec:editdb}, you must use the unstarred +version. The starred version is faster. + +\begin{important} +As is generally the case with command arguments, verbatim (for +example, using \cs{verb} or the \env{verbatim} environment) can't be used in any of +the arguments of \cs{DTLforeach}, specifically verbatim can't be +used in \meta{text}. +\end{important} + +There are also environment alternatives: +\begin{definition}[\DescribeEnv{DTLenvforeach}]% +\cs{begin}\{DTLenvforeach\}\oarg{condition}\marg{db name}\marg{assign list} +\end{definition} +\begin{definition}[\DescribeEnv{DTLenvforeach*}]% +\cs{begin}\{DTLenvforeach*\}\oarg{condition}\marg{db name}\marg{assign list} +\end{definition} +However, note that since these environments gather the contents of +their body, they also suffer from the above limitation. +\begin{important} +Verbatim can't be used in the body of \env{DTLenvforeach} or +\env{DTLenvforeach*}. +\end{important} + +\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} +\centering +\begin{tabular}{llr} +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%)% +\DTLforeach{scores}{% +\firstname=FirstName,\surname=Surname,\score=Score}{% +\\% start new row +\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{important} +Note that the new row command \idbs\ has been placed at the +start of the final argument in the above example. This is necessary +as placing it at the end of the argument will cause an unwanted row +at the end of the table. This is a feature of the loop mechanism. +\end{important} + +\begin{table}[htbp] +\caption[Student scores (displaying a database in a +table)]{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: +\desctr{DTLrowi}, +\desctr{DTLrowii} and +\desctr{DTLrowiii} which keep track of +the current row. + +\begin{important} +Note that these counters are only incremented when +\meta{condition} is satisfied, therefore they will not have the +correct value in \meta{condition}. 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. +\end{important} + +\begin{definition}[\DescribeMacro{\DTLcurrentindex}]% +\cs{DTLcurrentindex} +\end{definition} +At the start of each iteration in \cs{DTLforeach}, +\cs{DTLcurrentindex} is set to the arabic value of the current row +counter. Note that this is only set after the condition is tested, +so it should only be used in the body of \cs{DTLforeach} not in +the condition. It is also only set locally, so if you use it in +a tabular environment, it can only be used before the first instance +of \verb|\\| or \verb|&| in the current iteration. + +Within the body of \ics{DTLforeach} (i.e.\ within \meta{text}) +the following conditionals may be used: +\begin{definition}[\DescribeMacro{\DTLiffirstrow}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLiflastrow}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLifoddrow}]% +\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{definition}[\DescribeMacro{\DTLsavelastrowcount}]% +\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{definition}[\DescribeMacro{\DTLforeachkeyinrow}]% +\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +\end{definition} +This iterates through each key in the current row, (globally) assigns +\meta{cmd} to the value of that key, and does \meta{text} +(\meta{cmd} must be a control sequence and may be used in +\meta{text}). This command may only be used in the body of +\cs{DTLforeach}. At each iteration, \cs{DTLforeachkeyinrow} sets +\cs{dtlkey} to the current key, \cs{dtlcol} to the current column +index, \cs{dtltype} to the data type for the current column, +and \cs{dtlheader} to the header for the current column. Note that +\cs{dtltype} corresponds to the column type but if the entries in +the column have mixed types, it may not correspond to the type +of the current entry. + +\begin{definition}[\DescribeMacro{\dtlbreak}]% +\cs{dtlbreak} +\end{definition} +You can break out of most of the loops provided by \sty{datatool} +using \cs{dtlbreak}. Note, however, that it doesn't break the loop +until the end of the current iteration. There is no provision for +a "next" or "continue" style command. + +Additional loop commands provided by \sty{datatool} are +described in the documented code (datatool-code.pdf). + +\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} +\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}. + +Notes: +\begin{itemize} +\item the \cs{label} command is placed before +"\\" to ensure that it is in the same scope as the command +"\refstepcounter{DTLrowi}". + +\item To avoid unwanted spaces the end of line characters are +commented out with the percent (\texttt{\%}) symbol. +\end{itemize} + +\begin{table}[htbp] +\caption[Student scores (labelling rows)]{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} + +\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} +\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 (filtering rows using +\cs{DTLisgt})]{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)} +\centering +\begin{tabular}{llr} +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%)% +\DTLforeach*[\DTLisopenbetween{\surname}{B}{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) --- filtering rows using \newline +\cs{DTLisopenbetween}]{Student scores (B)}\label{tab:Bscores} +\centering +\begin{tabular}{llr} +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%)\relax +\DTLforeach*[\DTLisopenbetween{\surname}{B}{C}]{scores} +{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +\\ +\firstname & \surname & \score} +\end{tabular} +\end{table} + +\end{example} + +\begin{example}{Checking for the First Row (booktabs)}{ex:iffirst} +Suppose I want to use the \sty{booktabs} package and I want to use +\ics{midrule} after the header row. I can use \ics{DTLiffirstrow} to +check if the loop is on the first row of the iteration. (Remember +that you need to load the \sty{booktabs} package in the preamble +with \cs{usepackage}.) Using the same database as before: +\begin{verbatim} +\begin{table}[htbp] +\caption{Student scores (booktabs)} +\centering +\begin{tabular}{llc} +\toprule +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%)% +\DTLforeach*{scores}% + {\firstname=FirstName,\surname=Surname,\score=Score}% + {% + \DTLiffirstrow{\\\midrule}{\\}% + \firstname & \surname & \score + }% end of loop + \\\bottomrule +\end{tabular}% +\end{table} +\end{verbatim} +(The commands \ics{toprule}, \ics{midrule} and \ics{bottomrule} are +all provided by \sty{booktabs}.) This produces +\autoref{tab:iffirst}. + +\begin{table}[htbp] +\caption{Student scores (booktabs)} +\label{tab:iffirst} +\centering +\begin{tabular}{llc} +\toprule +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%)% +\DTLforeach*{scores}{% +\firstname=FirstName,\surname=Surname,\score=Score}{% +\DTLiffirstrow{\\\midrule}{\\}% +\firstname & \surname & \score}% +\\\bottomrule +\end{tabular}% +\end{table} + +\end{example} + +\begin{example}{Breaking Out of a Loop}{ex:dtlbreak} +Suppose I only want to display the first three rows of a database. +I could do:\footnote{Recall that \ctr{DTLrowi} is incremented +after the condition is tested, so it will be out by 1 when the +condition is tested which is why \texttt{<3} is used instead of +\texttt{<4}.} +\begin{verbatim} +\DTLforeach*[\value{DTLrowi}<3]{scores}% +{\firstname=FirstName,\surname=Surname,\score=Score}{% +\\\firstname & \surname & \score +} +\end{verbatim} +However, this isn't very efficient, as it still has to iterate +through the entire database, checking if the condition is met. If +the database has over 100 entries, this will slow the time taken +to create the table. It would therefore be much more efficient +to break out of the loop when row count exceeds 3: +\begin{verbatim} +\begin{table}[htbp] +\caption{First Three Rows} +\centering +\begin{tabular}{llr} +\bfseries First Name & \bfseries Surname & \bfseries Score (\%)% +\DTLforeach*{scores}% +{\firstname=FirstName,\surname=Surname,\score=Score}{% +\ifthenelse{\DTLcurrentindex=3}{\dtlbreak}{}% +\\\firstname & \surname & \score +}% +\end{tabular} +\end{table} +\end{verbatim} +This produces \autoref{tab:dtlbreak}. Note that the loop is not +broken until the end of the current iteration, so even though +\cs{dtlbreak} occurs at the start of the third row, the loop isn't +finished until the third row is completed. (Recall that +\cs{DTLcurrentindex} must be used before the first instance of +\verb|\\| or \verb|&|.) Alternatively, you can use +\ctr{DTLrowi} instead: +\begin{verbatim} +\DTLforeach{scores}% +{\firstname=FirstName,\surname=Surname,\score=Score}{% +\\\firstname & \surname & \score +\ifthenelse{\value{DTLrowi}=3}{\dtlbreak}{}% +}% +\end{verbatim} + +\begin{table}[htbp] +\caption{First Three Rows} +\label{tab:dtlbreak}% +\centering +\begin{tabular}{llr} +\bfseries First Name & \bfseries Surname & \bfseries Score (\%)\relax +\DTLforeach*{scores}% +{\firstname=FirstName,\surname=Surname,\score=Score}{% +\ifthenelse{\DTLcurrentindex=3}{\dtlbreak}{}\relax +\\\firstname & \surname & \score +}% +\end{tabular} +\end{table} +\end{example} + +\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 (illustrating the use of +\cs{DTLifoddrow})]{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} +\centering +\begin{tabular}{llcllc} +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%) & +\bfseries First Name & +\bfseries Surname & +\bfseries Score (\%)% +\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{% +\DTLifoddrow{\\}{&}% +\firstname & \surname & \score}% +\end{tabular} +\end{table} +\end{verbatim} +produces \autoref{tab:2rows} + +\begin{table}[htbp] +\caption[Two database rows per tabular row (illustrating the +use of\newline \cs{DTLifoddrow})]{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} + +(To order column-wise, instead of row-wise, see +\autoref{ex:twoblocks}.) +\end{example} + +\begin{example}{Iterating Through Keys in a Row}{ex:foreachkey} +Suppose you have lots of columns in your database, and you +want to display them all without having to set a variable for +each column. You can leave the assignment list in \cs{DTLforeach} +blank, and iterate through the keys using \cs{DTLforeachkeyinrow}. +For example: +\begin{verbatim} +\begin{table}[htbp] +\caption{Student Scores (Iterating Through Keys)} +\centering +\begin{tabular}{llll} +\bfseries First Name & \bfseries Surname & +\bfseries Registration No. & +\bfseries Score (\%)% +\DTLforeach*{scores}{}{% +\\\gdef\doamp{\gdef\doamp{&}}% +\DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}% +\end{tabular} +\end{table} +\end{verbatim} +This produces \autoref{tab:foreachkey}. +\begin{table}[htbp] +\caption{Student Scores (Iterating Through Keys)} +\label{tab:foreachkey} +\centering +\begin{tabular}{llll} +\bfseries First Name & \bfseries Surname & +\bfseries Registration No. & +\bfseries Score (\%)\relax +\DTLforeach*{scores}{}{% +\\\gdef\doamp{\gdef\doamp{&}}\relax +\DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}\relax +\end{tabular} +\end{table} + +Note that the "&" must be between columns, so I have defined +a command called \cs{doamp} that on first use redefines +itself to do "&". So, for each row, at the start of +the key iteration, \cs{doamp} does nothing, and on subsequent +iterations it does "&". This ensures that the correct number of +"&"s are used. Since each cell in the \env{tabular} environment +is scoped, \cs{gdef} is needed instead of \cs{def}. + +In the above, I needed to know how many columns are in the +database, and the order that the headings should appear. If you +are unsure, you can use \cs{dtlforeachkey} to determine the +number of columns and to display the header row. For example: +\begin{verbatim} + \begin{table}[htbp] + \caption{Student Scores} + \centering + % Work out the column alignments. + \def\colalign{}% + \dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do + {\edef\colalign{\colalign l}}% + % Begin the tabular environment. + \edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}% + \dobegintabular + % Do the header row. + \gdef\doamp{\gdef\doamp{&}}% + \dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do + {\doamp\bfseries \theHead}% + % Iterate through the data. + \DTLforeach*{scores}{}{% + \\\gdef\doamp{\gdef\doamp{&}}% + \DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}% + \end{tabular} + \end{table} +\end{verbatim} + +\begin{table}[htbp] +\caption[Student Scores (Using \cs{dtlforeachkey} and \newline +\cs{DTLforeachkeyinrow})]{Student Scores (Using \cs{dtlforeachkey} and +\cs{DTLforeachkeyinrow})} +\label{tab:foreachkey2} +\centering +\def\colalign{}% +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\edef\colalign{\colalign l}}% +\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}\relax +\dobegintabular +\gdef\doamp{\gdef\doamp{&}}\relax +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\doamp\bfseries \theHead}\relax +\DTLforeach*{scores}{}{% +\\\gdef\doamp{\gdef\doamp{&}}\relax +\DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}\relax +\end{tabular} +\end{table} + +Notes: +\begin{itemize} +\item In order to determine the column alignment for the +\env{tabular} environment, I first define \cs{colalign} to +nothing, and then I iterate through the keys appending +\texttt{l} to \cs{colalign}. Since \cs{colalign} only contains +alphabetical characters, I can just use \cs{edef} for this. I +could modify this to check the data type and, say, use \texttt{l} +(left alignment) for columns containing strings and \texttt{c} +(centred) for the other columns: +\begin{verbatim} +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\ifnum\theType=0\relax + \edef\colalign{\colalign l}% column contains strings + \else + \edef\colalign{\colalign c}% column contains numerical values + \fi +}% +\end{verbatim} + +\item To ensure \cs{colalign} gets correct expanded when passed +to the \env{tabular} environment I temporarily define +\cs{dobegintabular} to the code required to start the +\env{tabular} environment: +\begin{verbatim} +\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}% +\end{verbatim} +This sets \cs{dobegintabular} to \verb|\begin{tabular}{llll}|. +After defining \cs{dobegintabular}, I then need to use it. + +\item As before, I use \cs{doamp} to put the ampersands between +columns. + +\item Recall that I can set the headers using \cs{DTLsetheader} +or using the \csopt{DTLloaddb}{headers} key when loading the data +from an external file. For example: +\begin{verbatim} +\DTLsetheaders{scores}{FirstName}{First Name} +\DTLsetheaders{scores}{Score}{Score (\%)} +\end{verbatim} +\end{itemize} + +Recall that \cs{DTLforeachkeyinrow} sets \cs{dtlkey} to the +current key. This can be used to filter out columns. Alternatively, +if you know the column index, you can test \cs{dtlcol} instead. +The following code modifies the above example so that it filters +out the column whose key is \texttt{StudentNo}: +\begin{verbatim} +\begin{table}[htbp] +\caption{Student Scores (Filtering Out a Column)} +\centering +\def\colalign{}% +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\DTLifeq{\theKey}{StudentNo}{}{\edef\colalign{\colalign l}}}% +\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}% +\dobegintabular +\gdef\doamp{\gdef\doamp{&}}% +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\DTLifeq{\theKey}{StudentNo}{}{\doamp\bfseries \theHead}}% +\DTLforeach*{scores}{}{% +\\\gdef\doamp{\gdef\doamp{&}}% +\DTLforeachkeyinrow{\thisValue}{% + \DTLifeq{\dtlkey}{StudentNo}{}{\doamp\thisValue}}}% +\end{tabular} +\end{table} +\end{verbatim} +The result is shown in \autoref{tab:foreachkey3}. + +\begin{table}[htbp] +\caption{Student Scores (Filtering Out a Column)} +\label{tab:foreachkey3} +\centering +\def\colalign{}% +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\DTLifeq{\theKey}{StudentNo}{}{\edef\colalign{\colalign l}}}% +\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}\relax +\dobegintabular +\gdef\doamp{\gdef\doamp{&}}\relax +\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +{\DTLifeq{\theKey}{StudentNo}{}{\doamp\bfseries \theHead}}\relax +\DTLforeach*{scores}{}{% +\\\gdef\doamp{\gdef\doamp{&}}\relax +\DTLforeachkeyinrow{\thisValue}{\relax +\DTLifeq{\dtlkey}{StudentNo}{}{\doamp\thisValue}}}\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\space (illustrating nested +\cs{DTLforeach})]{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} + +\begin{example}{Dynamically Allocating Field Name}{ex:dyn} +(This example was suggested by Bill~Hobbs.) Suppose you have a +directory containing members of multiple clubs. The CSV file +(say, \texttt{clubs.csv}) may look something like: +\begin{verbatim} +First Name,Surname,Rockin,Single +John,"Smith, Jr",member, +Jane,Brown,,friend +Andy,Brown,friend,member +Z\"oe,Adams,member,member +Roger,Brady,friend,friend +Clare,Verdon,member, +\end{verbatim} +\DTLnewdb{clubs}\relax +\DTLnewrow{clubs}\relax +\DTLnewdbentry{clubs}{First Name}{John}\relax +\DTLnewdbentry{clubs}{Surname}{Smith, Jr}\relax +\DTLnewdbentry{clubs}{Rockin}{member}\relax +\DTLnewdbentry{clubs}{Single}{}\relax +\DTLnewrow{clubs}\relax +\DTLnewdbentry{clubs}{First Name}{Jane}\relax +\DTLnewdbentry{clubs}{Surname}{Brown}\relax +\DTLnewdbentry{clubs}{Rockin}{}\relax +\DTLnewdbentry{clubs}{Single}{friend}\relax +\DTLnewrow{clubs}\relax +\DTLnewdbentry{clubs}{First Name}{Andy}\relax +\DTLnewdbentry{clubs}{Surname}{Brown}\relax +\DTLnewdbentry{clubs}{Rockin}{friend}\relax +\DTLnewdbentry{clubs}{Single}{member}\relax +\DTLnewrow{clubs}\relax +\DTLnewdbentry{clubs}{First Name}{Z\"oe}\relax +\DTLnewdbentry{clubs}{Surname}{Adams}\relax +\DTLnewdbentry{clubs}{Rockin}{member}\relax +\DTLnewdbentry{clubs}{Single}{member}\relax +\DTLnewrow{clubs}\relax +\DTLnewdbentry{clubs}{First Name}{Roger}\relax +\DTLnewdbentry{clubs}{Surname}{Brady}\relax +\DTLnewdbentry{clubs}{Rockin}{friend}\relax +\DTLnewdbentry{clubs}{Single}{friend}\relax +\DTLnewrow{clubs}\relax +\DTLnewdbentry{clubs}{First Name}{Clare}\relax +\DTLnewdbentry{clubs}{Surname}{Verdon}\relax +\DTLnewdbentry{clubs}{Rockin}{member}\relax +\DTLnewdbentry{clubs}{Single}{}\relax +(Blank entries indicate that the person is not a member of that +club.) The data can be loaded as follows: +\begin{verbatim} +\DTLloaddb{clubs}{clubs.csv} +\end{verbatim} +Suppose at the beginning of your document you have specified +which club you are interested in ("Rockin" or "Single") and +store it in \cs{DIdent}: +\begin{verbatim} +\newcommand{\DIdent}{Rockin} +\end{verbatim} +\newcommand{\DIdent}{Rockin}\relax +You can now display the members for this particular club as +follows: +\begin{verbatim} +\begin{table}[htbp] +\caption{Club Membership} +\centering +\begin{tabular}{lll} +\bfseries First Name & \bfseries Surname & \bfseries Status +\DTLforeach*[\not\DTLiseq{\status}{}]{clubs} +{\firstname=First Name,\surname=Surname,\status=\DIdent}{% +\\\firstname & \surname & \status +}% +\end{tabular} +\end{table} +\end{verbatim} +The result is shown in \autoref{tab:dyn}. + +\begin{table}[htbp] +\caption{Club Membership} +\label{tab:dyn} +\centering +\begin{tabular}{lll} +\bfseries First Name & \bfseries Surname & \bfseries Status +\DTLforeach*[\not\DTLiseq{\status}{}]{clubs} +{\firstname=First Name,\surname=Surname,\status=\DIdent}{\relax +\\\firstname & \surname & \status +}\relax +\end{tabular} +\end{table} +\end{example} + +\section{Null Values} +\begin{important} +Note that a null value is not the same as an empty value. Empty +values can be tested using \sty{etoolbox}'s \ics{ifdefempty} or +similar. +\end{important} + +If a database is created using \cs{DTLnewdb}, \cs{DTLnewrow} +and \cs{DTLnewdbentry} (rather than loading it from an ASCII +file), it is possible for some of the entries to have null values +when a value is not assigned to a given key for a given row. +It's also possible for data fetched from a~SQL database using +\app{datatooltk} to contain null values, and you can use +the \app{datatooltk} GUI to assign null values, but data loaded using +\cs{DTLloaddb} (or \cs{DTLloadrawdb}) will have empty not null +values for any \emph{blank} cells. However, you will get null values when +loading a CSV file if cells are missing (rather than empty). For +example: +\begin{verbatim} +Column 1,Column 2,Column 3 +Foo,Bar +Foo,,Baz +Foo,Bar,Baz +\end{verbatim} +This has an empty cell (the second column in \texttt{Foo,,Baz}) and +a null cell (the third column in \texttt{Foo,Bar}). If the first +row of data was instead +\begin{verbatim} +Foo,Bar, +\end{verbatim} +then the third column is now empty, not null. + +When you iterate through the database using \cs{DTLforeach} +(described in \autoref{sec:dbforeach}), +if an entry is missing for a given row, the associated command given +in the \meta{values} argument will be set to a null value. This +value depends on the data type associated with the given key. + +\begin{definition}[\DescribeMacro{\DTLstringnull}]% +\cs{DTLstringnull} +\end{definition} +This is the null value for a string. + +\begin{definition}[\DescribeMacro{\DTLnumbernull}]% +\cs{DTLnumbernull} +\end{definition} +This is the null value for a number. + +\begin{definition}[\DescribeMacro{\DTLifnull}]% +\cs{DTLifnull}\marg{cmd}\marg{true part}\marg{false part} +\end{definition} +This checks if \meta{cmd} is null where \meta{cmd} is a control +sequence, if it is, then \meta{true part} +is done, otherwise \meta{false part} is done. This macro is +illustrated in \autoref{ex:null} below. + +\begin{definition}[\DescribeMacro{\DTLifnullorempty}] +\cs{DTLifnullorempty}\marg{cmd}\marg{true part}\marg{false part} +\end{definition} +This checks if \meta{cmd} is null or empty, where \meta{cmd} is a +control sequence. If it is it does \meta{true part}, otherwise +\meta{false part}. + +\begin{example}{Null vs Empty Values}{ex:null} +Consider the following (which creates a database called "emailDB"): +\begin{verbatim} +\DTLnewdb{emailDB} +\DTLnewrow{emailDB} +\DTLnewdbentry{emailDB}{Surname}{Jones} +\DTLnewdbentry{emailDB}{FirstName}{Mary} +\DTLnewdbentry{emailDB}{Email1}{mj@my.uni.ac.uk} +\DTLnewdbentry{emailDB}{Email2}{mj@somewhere.com} +\DTLnewrow{emailDB} +\DTLnewdbentry{emailDB}{Surname}{Smith} +\DTLnewdbentry{emailDB}{FirstName}{Adam} +\DTLnewdbentry{emailDB}{Email1}{as@my.uni.ac.uk} +\DTLnewdbentry{emailDB}{RegNum}{12345} +\end{verbatim} +\DTLnewdb{emailDB}\relax +\DTLnewrow{emailDB}\relax +\DTLnewdbentry{emailDB}{Surname}{Jones}\relax +\DTLnewdbentry{emailDB}{FirstName}{Mary}\relax +\DTLnewdbentry{emailDB}{Email1}{mj@my.uni.ac.uk}\relax +\DTLnewdbentry{emailDB}{Email2}{mj@somewhere.com}\relax +\DTLnewrow{emailDB}\relax +\DTLnewdbentry{emailDB}{Surname}{Smith}\relax +\DTLnewdbentry{emailDB}{FirstName}{Adam}\relax +\DTLnewdbentry{emailDB}{Email1}{as@my.uni.ac.uk}\relax +\DTLnewdbentry{emailDB}{RegNum}{12345}\relax +In the above example, the first row of the database contains +an entry with the key "Email2", but the second row doesn't. +Whereas the second row contains an entry with the key "RegNum", +but the first row doesn't. That is, this database has two null (not +empty) values. + +The following code puts the information in a \env{tabular} +environment: +\begin{verbatim} +\begin{tabular}{lllll} +\bfseries First Name & +\bfseries Surname & +\bfseries Email 1 & +\bfseries Email 2 & +\bfseries Reg Num% +\DTLforeach*{emailDB}{\firstname=FirstName,\surname=Surname,% +\emailI=Email1,\emailII=Email2,\regnum=RegNum}{% +\\\firstname & \surname & \emailI & \emailII & \regnum}% +\end{tabular} +\end{verbatim} +This produces the following:\par\vskip\baselineskip\noindent +\begin{tabular}{lllll} +\bfseries First Name & +\bfseries Surname & +\bfseries Email 1 & +\bfseries Email 2 & +\bfseries Reg Num\relax +\DTLforeach*{emailDB}{\firstname=FirstName,\surname +=Surname,\emailI=Email1,\emailII=Email2,\regnum=RegNum}{\relax +\\\firstname & \surname & \emailI & \emailII & \regnum}\relax +\end{tabular} +\par\vskip\baselineskip +Note that on the first row of data, the registration number appears as +0, while on the next row, the second email address appears as +NULL. The \sty{datatool} package has identified the key "RegNum" +for this database as a numerical key, since all elements in the +database with that key are numerical, whereas it has +identified the key "Email2" as a string, since there is at least +one element in this database with that key that is a string. Null +numerical values are set to \cs{DTLnumbernull} (\DTLnumbernull), and +null strings are set to \cs{DTLstringnull} (\DTLstringnull). + +The following code checks each value to determine whether it +is null using \cs{DTLifnull}. If it is, the text \emph{Missing} +is inserted, otherwise the value itself is used: +\begin{verbatim} +\begin{tabular}{lllll} +\bfseries First Name & +\bfseries Surname & +\bfseries Email 1 & +\bfseries Email 2 & +\bfseries Reg Num% +\DTLforeach{emailDB}{\firstname=FirstName,\surname=Surname,% +\emailI=Email1,\emailII=Email2,\regnum=RegNum}{% +\\\DTLifnull{\firstname}{\emph{Missing}}{\firstname} & +\DTLifnull{\surname}{\emph{Missing}}{\surname} & +\DTLifnull{\emailI}{\emph{Missing}}{\emailI} & +\DTLifnull{\emailII}{\emph{Missing}}{\emailII} & +\DTLifnull{\regnum}{\emph{Missing}}{\regnum}}% +\end{tabular} +\end{verbatim} +This produces the following:\par\vskip\baselineskip\noindent +\begin{tabular}{lllll} +\bfseries First Name & +\bfseries Surname & +\bfseries Email 1 & +\bfseries Email 2 & +\bfseries Reg Num\relax +\DTLforeach{emailDB}{\firstname=FirstName,\surname +=Surname,\emailI=Email1,\emailII=Email2,\regnum=RegNum}{\relax +\\\DTLifnull{\firstname}{\emph{Missing}}{\firstname} & +\DTLifnull{\surname}{\emph{Missing}}{\surname} & +\DTLifnull{\emailI}{\emph{Missing}}{\emailI} & +\DTLifnull{\emailII}{\emph{Missing}}{\emailII} & +\DTLifnull{\regnum}{\emph{Missing}}{\regnum}}\relax +\end{tabular} +\par\vskip\baselineskip\noindent +If you want to do this, you may find it easier to define a +convenience command that will display some appropriate text +if an entry is missing, for example: +\begin{verbatim} +\newcommand*{\checkmissing}[1]{\DTLifnull{#1}{---}{#1}} +\end{verbatim} +Then instead of typing, say, +\begin{verbatim} +\DTLifnull{\regnum}{---}{\regnum} +\end{verbatim} +you can instead type: +\begin{verbatim} +\checkmissing{\regnum} +\end{verbatim} + +Now suppose that instead of defining the database using \cs{DTLnewdb}, +\cs{DTLnewrow} and \cs{DTLnewdbentry}, you have a file with the +contents: +\begin{ttfamily}\setlength{\parindent}{0pt}\par\vskip\baselineskip +Surname,FirstName,RegNum,Email1,Email2 + +\DTLforeach{emailDB}{\surname=Surname,\firstname=FirstName,\regNo +=RegNum,\emailI=Email1,\emailII +=Email2}{\relax +\surname,\firstname,\DTLifnull{\regNo}{}{\regNo},\emailI,\DTLifnull{\emailII}{}{\emailII}\par +} +\end{ttfamily}\par\vskip\baselineskip\noindent +and you load the data from this file using \cs{DTLloaddb} +(defined in \autoref{sec:loaddb}). Now the +database has \emph{no null values}, but has an \emph{empty} value for the +key "RegNum" on the first row of the database, and an empty +value for the key "Email2" on the second row of the database. +Now, the following code +\begin{verbatim} +\begin{tabular}{lllll} +\bfseries First Name & +\bfseries Surname & +\bfseries Email 1 & +\bfseries Email 2 & +\bfseries Reg Number% +\DTLforeach{emailDB}{\firstname=FirstName,\surname=Surname,% +\emailI=Email1,\emailII=Email2,\regnum=RegNum}{% +\\\DTLifnull{\firstname}{\emph{Missing}}{\firstname} & +\DTLifnull{\surname}{\emph{Missing}}{\surname} & +\DTLifnull{\emailI}{\emph{Missing}}{\emailI} & +\DTLifnull{\emailII}{\emph{Missing}}{\emailII} & +\DTLifnull{\regnum}{\emph{Missing}}{\regnum}}% +\end{tabular} +\end{verbatim} +produces:\par\vskip\baselineskip\noindent +\begin{tabular}{lllll} +\bfseries First Name & +\bfseries Surname & +\bfseries Email 1 & +\bfseries Email 2 & +\bfseries Reg Number\relax +\DTLforeach{emailDB}{\firstname=FirstName,\surname +=Surname,\emailI=Email1,\emailII=Email2,\regnum=RegNum}{\relax +\\\firstname & \surname & \emailI & \DTLifnull{\emailII}{}{\emailII} & \DTLifnull{\regnum}{}{\regnum}}\relax +\end{tabular} + +\medskip + +Now the missing entries are simply blank instead of containing +\emph{Missing}. This is because they're empty not null. In this +case, you may prefer to use \cs{DTLifnullorempty} instead of +\cs{DTLifnull}. +\end{example} + +\section{Editing Database Rows} +\label{sec:editdb} + +A row can be removed from a data base using: +\begin{definition}[\DescribeMacro{\DTLremoverow}]% +\cs{DTLremoverow}\marg{db name}\marg{row index} +\end{definition} +where \meta{row index} is the index of the unwanted row. For +example: +\begin{verbatim} +\DTLremoverow{scores}{2} +\end{verbatim} +will delete the second row in the database labelled ``scores''. +There is also a starred version that doesn't check for the +existence of the database. Remember that the row index refers to the +internal data not to a reference in the external source if the data +has been input. + +The following commands may be used in the body of the +\ics{DTLforeach} loop,\footnote{Only the unstarred version of +\cs{DTLforeach}; the starred version is read-only.}\ to edit the +current row of the loop. (See also \autoref{sec:currentrow}.) + +\begin{definition}[\DescribeMacro{\DTLappendtorow}]% +\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. +(\meta{value} is expanded.) + +\begin{definition}[\DescribeMacro{\DTLreplaceentryforrow}]% +\cs{DTLreplaceentryforrow}\marg{key}\marg{value} +\end{definition} +This replaces the entry for \meta{key} with \meta{value}. +(\meta{value} is expanded.) + +\begin{definition}[\DescribeMacro{\DTLremoveentryfromrow}]% +\cs{DTLremoveentryfromrow}\marg{key} +\end{definition} +This removes the entry for \meta{key} from the current row. + +\begin{definition}[\DescribeMacro{\DTLremovecurrentrow}]% +\cs{DTLremovecurrentrow} +\end{definition} +This removes the current row from the database. + +\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 +\char`\"\surname\char`\",\DTLifstringeq{\firstname}{Zoe}{Z\string\"oe}{\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}{llcccc} +\bfseries Surname & \bfseries First Name & +\bfseries Assign 1 & +\bfseries Assign 2 & +\bfseries Assign 3 & +\bfseries Average Mark% +\DTLforeach{marks}% +{% assign variable + \surname=Surname,\firstname=FirstName,% + \average=Average,\assignI=Assignment 1,% + \assignII=Assignment 2,\assignIII=Assignment 3}% +{% start new row + \\\surname & \firstname & \assignI & \assignII & \assignIII & + \DTLround{\average}{\average}{2}% round to 2 dp + \DTLclip{\average}{average}%clip unnecessary 0s + \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 (with averages)]{Student +marks}\label{tab:meanmarks} +\centering +\begin{tabular}{llcccc} +\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}\DTLclip{\average}{\average}\average}\relax +\end{tabular} +\end{table} + +\end{example} + +\section{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 is +not 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}\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 (using arithmetic computations)]{Student +scores}\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} + +\begin{definition}[\DescribeMacro{\DTLsumforkeys}]% +\cs{DTLsumforkeys}\oarg{condition}\oarg{assign list}\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 second optional argument \meta{assign list} is the same +as the assignment list used by \ics{DTLforeach}, so that you can use +the information in \meta{condition}. 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". + +\begin{definition}[\DescribeMacro{\DTLsumcolumn}]% +\cs{DTLsumcolumn}\marg{db}\marg{key}\marg{cmd} +\end{definition} +This is a faster version of \cs{DTLsumforkeys} that only sums +the entries in a single column (specified by \meta{key}) for +a single database (specified by \meta{db}) and doesn't provide any +filtering. The result is stored in \meta{cmd} which must be +a control sequence. + +\begin{definition}[\DescribeMacro{\DTLmeanforkeys}]% +\cs{DTLmeanforkeys}\oarg{condition}\oarg{assign list}\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 +second optional argument \meta{assign list} is the same as the +assignment list used by \ics{DTLforeach}, so that you can use the +information in \meta{condition}. 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". + +\begin{definition}[\DescribeMacro{\DTLmeanforcolumn}]% +\cs{DTLmeanforcolumn}\marg{db}\marg{key}\marg{cmd} +\end{definition} +This is a faster version of \cs{DTLmeanforkeys} that only computes +the mean for a single column (specified by \meta{key}) for +a single database (specified by \meta{db}) and doesn't provide any +filtering. The result is stored in \meta{cmd} which must be +a control sequence. + +\begin{definition}[\DescribeMacro{\DTLvarianceforkeys}]% +\cs{DTLvarianceforkeys}\oarg{condition}\oarg{assign list}\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 second +optional argument \meta{assign list} is the same as the assignment +list used by \ics{DTLforeach}, so that you can use the information +in \meta{condition}. The result is stored in \meta{cmd} which must +be a control sequence. + +\begin{definition}[\DescribeMacro{\DTLvarianceforcolumn}]% +\cs{DTLvarianceforcolumn}\marg{db}\marg{key}\marg{cmd} +\end{definition} +This is a faster version of \cs{DTLvarianceforkeys} that only +computes the variance for a single column (specified by \meta{key}) +for a single database (specified by \meta{db}) and doesn't provide +any filtering. The result is stored in \meta{cmd} which must be a +control sequence. + +\begin{definition}[\DescribeMacro{\DTLsdforkeys}]% +\cs{DTLsdforkeys}\oarg{condition}\oarg{assign list}\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 +second optional argument \meta{assign list} is the same as the +assignment list used by \ics{DTLforeach}, so that you can use the +information in \meta{condition}. The result is stored in \meta{cmd} +which must be a control sequence. + +\begin{definition}[\DescribeMacro{\DTLsdforcolumn}]% +\cs{DTLsdforcolumn}\marg{db}\marg{key}\marg{cmd} +\end{definition} +This is a faster version of \cs{DTLsdforkeys} that only computes the +standard deviation for a single column (specified by \meta{key}) for +a single database (specified by \meta{db}) and doesn't provide any +filtering. The result is stored in \meta{cmd} which must be a +control sequence. + +\begin{definition}[\DescribeMacro{\DTLminforkeys}]% +\cs{DTLminforkeys}\oarg{condition}\oarg{assign list}\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} where \meta{condition} is true. The second optional argument +\meta{assign list} is the same as the assignment list used by +\ics{DTLforeach}, so that you can use the information in +\meta{condition}. The result is stored 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. + +\begin{definition}[\DescribeMacro{\DTLminforcolumn}]% +\cs{DTLminforcolumn}\marg{db}\marg{key}\marg{cmd} +\end{definition} +This is a faster version of \cs{DTLminforkeys} that only computes +the minimum for a single column (specified by \meta{key}) for +a single database (specified by \meta{db}) and doesn't provide any +filtering. The result is stored in \meta{cmd} which must be +a control sequence. + +\begin{definition}[\DescribeMacro{\DTLmaxforkeys}]% +\cs{DTLmaxforkeys}\oarg{condition}\oarg{assign list}\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} where \meta{condition} is true. The second optional argument +\meta{assign list} is the same as the assignment list used by +\ics{DTLforeach}, so that you can use the information in +\meta{condition}. The result is stored 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. + +\begin{definition}[\DescribeMacro{\DTLmaxforcolumn}]% +\cs{DTLmaxforcolumn}\marg{db}\marg{key}\marg{cmd} +\end{definition} +This is a faster version of \cs{DTLmaxforkeys} that only computes +the maximum for a single column (specified by \meta{key}) for +a single database (specified by \meta{db}) and doesn't provide any +filtering. The result is stored in \meta{cmd} which must be +a control sequence. + +\begin{definition}[\DescribeMacro{\DTLcomputebounds}]% +\cs{DTLcomputebounds}\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{DTLmeanforkeys} 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' +\DTLmeanforkeys{scores}{Score}{\average} + % Round the average to 2 decimal places +\DTLround{\average}{\average}{2} + % Save the highest score in \maxscore +\DTLmaxforkeys{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} + +To determine a person's gender when mail merging, see +\autoref{sec:person}. +\end{example} + +\section{Sorting a Database} +\label{sec:sort} + +The sort methods described here use \TeX\ to sort, which is very +inefficient. The comparison handlers use a character code comparison +rather than locale-sensitive alphabetic ordering. It's more +efficient to use \app{datatooltk} to import and sort at the same +time. + +\begin{definition}[\DescribeMacro{\dtlsort}]% +\cs{dtlsort}\oarg{replacement key list}\marg{sort criteria}\marg{db +name}\marg{handler} +\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. + +The final argument \meta{handler} is the command used for the +comparisons and is the same as the \meta{criteria cs} command +used by \cs{dtlsortlist} and \cs{dtlinsertinto}, described +in \sectionref{sec:csvlists}. The predefined handlers are: +\begin{description} +\item[\ics{dtlcompare}] A case-sensitive comparison. +\item[\ics{dtlicompare}] A case-insensitive comparison. +\item[\ics{dtlwordindexcompare}] English word-ordering comparison +for indexes, as described by the Oxford Style Manual. +\item[\ics{dtlletterindexcompare}] English letter-ordering +comparison for indexes. +\end{description} +The last two handlers, \cs{dtlwordindexcompare} and +\cs{dtlletterindexcompare}, assume that inversion commas are +indicated using one of the following commands: +\begin{itemize} +\item To indicate name inversion: +\begin{definition}[\DescribeMacro\datatoolpersoncomma] +\cs{datatoolpersoncomma} +\end{definition} +Example: \verb|Knuth\datatoolpersoncomma Donald E.| + +\item To indicate place inversion: +\begin{definition}[\DescribeMacro\datatoolplacecomma] +\cs{datatoolplacecomma} +\end{definition} +Example: +\verb|New York\datatoolplacecomma USA| + +\item To indicate subject inversion: +\begin{definition}[\DescribeMacro\datatoolsubjectcomma] +\cs{datatoolsubjectcomma} +\end{definition} +Example: \verb|New York\datatoolsubjectcomma population| +\end{itemize} +In addition, the start of parenthetical material should be indicated +with +\begin{definition}[\DescribeMacro\datatoolparenstart] +\cs{datatoolparenstart} +\end{definition} +Example: \verb|High Water\datatoolparenstart play| + +Following the guidelines of the Oxford Style Manual, when sorting +terms that have identical pre-inversion parts, the following +ordering is applied: people, places, subjects, no inversions and +parenthetical. + +\begin{example}{Sorting a Database---Dealing with +Inversions}{ex:sortinversion} +This uses the example given in Chapter~16 of the Oxford Style +Manual. Suppose I~define my database as follows: +\begin{verbatim} +\DTLnewdb{inversiondata} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York, New York} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York\datatoolsubjectcomma +population} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York\datatoolplacecomma +USA} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York\datatoolpersoncomma +Earl of} +\end{verbatim} +\DTLnewdb{inversiondata} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York, New York} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York\datatoolsubjectcomma +population} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York\datatoolplacecomma +USA} +\DTLnewrow{inversiondata} +\DTLnewdbentry{inversiondata}{Term}{New York\datatoolpersoncomma +Earl of} + +First of all, display the unsorted data: +\begin{verbatim} +\DTLdisplaydb{inversiondata} +\end{verbatim} +This produces: +\begin{display} +\DTLdisplaydb{inversiondata} +\end{display} + +Now sort the data using the \ics{dtlwordindexcompare} handler: +\begin{verbatim} +\dtlsort{Term}{inversiondata}{\dtlwordindexcompare} +\end{verbatim} +\dtlsort{Term}{inversiondata}{\dtlwordindexcompare}% +and display again: +\begin{verbatim} +\DTLdisplaydb{inversiondata} +\end{verbatim} +which now produces: +\begin{display} +\DTLdisplaydb{inversiondata} +\end{display} +There are three entries here with pre-inversion text that's simply +\texttt{New York}. Since each of these three entries has the same +pre-inversion text, they need to be sorted according to the type of +inversion: person, place, subject. The fourth entry (New York, New +York) doesn't have an inversion since the comma is part of the title +of the named work. It's therefore sorted according to \texttt{New +York, New York} rather than just \texttt{New York} and so comes +after all the \texttt{New York} entries. +\end{example} + +If you want to write your own comparison handler, see the documented +code for details on the syntax of the handler. (You may want to +consider uploading your handler as a separate package to CTAN if you +think it will be of general use.) + +\label{utf8support}% +As from version 2.24, the predefined handlers now have limited support for UTF-8 +characters. \emph{This is still experimental.} The support will +automatically be switched on if the \sty{inputenc} package is loaded +with the \pkgopt{utf8} option before loading \sty{datatool-base} +(which is automatically loaded by \sty{datatool}). If \sty{inputenc} +is loaded after \sty{datatool-base}, you can use the (boolean) \pkgopt{utf8} +option when you load \sty{datatool-base} to enable it. For example, +either: +\begin{verbatim} +\usepackage[utf8]{inputenc} +\usepackage{datatool-base} +\end{verbatim} +or +\begin{verbatim} +\usepackage[utf8]{datatool-base} +\usepackage[utf8]{inputenc} +\end{verbatim} +(As from version 2.28, you can now also pass the \pkgopt{utf8} +option to \sty{datatool} and \sty{datagidx}.) +You can also enable this option after \sty{datatool-base} has been loaded +using +\begin{definition}[\DescribeMacro\dtlenableUTFviii] +\cs{dtlenableUTFviii} +\end{definition} +or disable it with +\begin{definition}[\DescribeMacro\dtldisableUTFviii] +\cs{dtldisableUTFviii} +\end{definition} +For example: +\begin{verbatim} +\usepackage[utf8]{inputenc} +\usepackage{datatool} +\dtldisableUTFviii +\end{verbatim} +This option isn't required for \XeLaTeX, which treats each UTF-8 +character as an individual token. + +With regular (pdf)\LaTeX\ (as opposed to \XeLaTeX) each UTF-8 character is +actually treated as two tokens that represent the first and second +octet of the UTF-8 character. This means that it's not possible for +\TeX\ to obtain a character code using the usual backtick method, so +(with this option enabled) if a UTF-8 character is detected, the handlers +described above will pass both octet tokens to one of the following commands: +\begin{definition}[\DescribeMacro\dtlsetUTFviiicharcode] +\cs{dtlsetUTFviiicharcode}\marg{octet tokens}\marg{count} +\end{definition} +(for the case-sensitive handler \ics{dltcompare}) and +\begin{definition}[\DescribeMacro\dtlsetUTFviiilccharcode] +\cs{dtlsetUTFviiilccharcode}\marg{octet tokens}\marg{count} +\end{definition} +(for the case-insensitive handlers). + +By default the first simply does: +\begin{definition}[\DescribeMacro\dtlsetdefaultUTFviiicharcode] +\cs{dtlsetdefaultUTFviiicharcode}\marg{octet tokens}\marg{count} +\end{definition} +and the second does +\begin{definition}[\DescribeMacro\dtlsetdefaultUTFviiilccharcode] +\cs{dtlsetdefaultUTFviiilccharcode}\marg{octet tokens}\marg{count} +\end{definition} + +In all the above \meta{octet tokens} are the two octets forming the +UTF-8 character and \meta{count} is a count register in which to +store the relevant character code. + +The default commands simply set the character code for certain +common accented Latin characters (such as \'e) to the code for their +unaccented version (such as e). You can redefine +\cs{dtlsetUTFviiicharcode} and \cs{dtlsetUTFviiilccharcode} to test +for additional characters. For example, to add the Norwegian +characters \ae, \o\ and \aa\ to the end of the Latin alphabet, you +can do: +\begin{verbatim} +\renewcommand*{\dtlsetUTFviiicharcode}[2]{% + \ifstrequal{#1}{Æ}% + {% + #2=91\relax + }% + {% + \ifstrequal{#1}{Ø}% + {% + #2=92\relax + }% + {% + \ifstrequal{#1}{Å}% + {% + #2=93\relax + }% + {% + \ifstrequal{#1}{æ}% + {% + #2=123\relax + }% + {% + \ifstrequal{#1}{ø}% + {% + #2=124\relax + }% + {% + \ifstrequal{#1}{å}% + {% + #2=125\relax + }% + {% + \dtlsetdefaultUTFviiicharcode{#1}{#2}% + }% + }% + }% + }% + }% + }% +} + +\renewcommand*{\dtlsetUTFviiilccharcode}[2]{% + \ifstrequal{#1}{Æ}% + {% + #2=123\relax + }% + {% + \ifstrequal{#1}{Ø}% + {% + #2=124\relax + }% + {% + \ifstrequal{#1}{Å}% + {% + #2=125\relax + }% + {% + \ifstrequal{#1}{æ}% + {% + #2=123\relax + }% + {% + \ifstrequal{#1}{ø}% + {% + #2=124\relax + }% + {% + \ifstrequal{#1}{å}% + {% + #2=125\relax + }% + {% + \dtlsetdefaultUTFviiilccharcode{#1}{#2}% + }% + }% + }% + }% + }% + }% +} +\end{verbatim} + +In the case where a~character is a single token (for example, with +Latin-1 encoding), the code associated with that character is set +using +\begin{definition}[\DescribeMacro\dtlsetcharcode] +\cs{dtlsetcharcode}\marg{c}\marg{count register} +\end{definition} +(for case-sensitive comparison) and +\begin{definition}[\DescribeMacro\dtlsetlccharcode] +\cs{dtlsetlccharcode}\marg{c}\marg{count register} +\end{definition} +(for case-insensitive comparison), where \meta{c} is the character +and \meta{count register} is a count register. The default +definitions are: +\begin{verbatim} +\newcommand*{\dtlsetcharcode}[2]{#2=`#1\relax} +\newcommand*{\dtlsetlccharcode}[2]{#2=\lccode`#1\relax} +\end{verbatim} +So, for example, the letter \qt{e} has the code \number`e\ whereas +(with the Latin-1 encoding) the letter \qt{\'e} has the code 233. +This means that \qt{\'e} will be sorted after \qt{e}. It may be that +you want \qt{\'e} to be treated the same as \qt{e} when making the +comparison. In this case, you need to redefine \cs{dtlsetcharcode} +and \cs{dtlsetlccharcode}. For example, for the case-sensitive +comparisons: +\begin{verbatim} +\renewcommand*{\dtlsetcharcode}[2]{% + \ifstrequal{#1}{É}% + {% + #2=`E\relax + }% + {% + \ifstrequal{#1}{é}% + {% + #2=`e\relax + }% + {% + #2=`#1\relax + }% + }% +} +\end{verbatim} +and for the case-insensitive comparisons: +\begin{verbatim} +\renewcommand*{\dtlsetlccharcode}[2]{% + \ifboolexpr + {% + test {\ifstrequal{#1}{é}} + or test {\ifstrequal{#1}{É}} + }% + {% + #2=`e\relax + }% + {% + #2=\lccode`#1\relax + }% +} +\end{verbatim} +(Extra conditionals will need to be added for other diacritics. +Alternative conditionals, such as \cs{ifx} or \cs{ifnum}, may be more +efficient. In the above I've used the \sty{etoolbox} commands for +clarity.) + +There are two shortcut commands for \cs{dtlsort}: +\begin{definition}[\DescribeMacro{\DTLsort}]% +\cs{DTLsort}\oarg{replacement key list}\marg{sort criteria}\marg{db name} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLsort*}]% +\cs{DTLsort*}\oarg{replacement key list}\marg{sort criteria}\marg{db name} +\end{definition} +these use the \ics{dtlcompare} and \ics{dtlicompare} handlers, +respectively. + +The optional argument \meta{replacement key list} is a list of +keys to use if the current key given in \meta{sort criteria} +is null for a given entry. Null keys are unlikely to occur if +you have loaded the database from an external ASCII file, but +may occur if the database is created using \cs{DTLnewdb}, +\cs{DTLnewrow} and \cs{DTLnewdbentry}. For example: +\begin{verbatim} +\DTLsort[Editor,Organization]{Author}{mydata} +\end{verbatim} +will sort according to the "Author" key, but if that key is missing +for a given row of the database, the "Editor" key will be used, +and if the "Editor" key is missing, it will use the "Organization" +key. Note that this is not the same as: +\begin{verbatim} +\DTLsort{Author,Editor,Organization}{mydata} +\end{verbatim} +which will first compare the "Author" keys, but if the author names +are the same, it will then compare the "Editor" keys, and if the +editor names are also the same, it will then compare the +"Organization" keys. + +The unstarred version uses a case sensitive comparison for strings, +whereas the starred version ignores the case when comparing strings. +Note that the case sensitive comparison orders uppercase characters +before lowercase characters, so the letter B is considered to be +lower than the letter a. + +\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)} +\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)} +\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} + +Now suppose I add two new students to the database: +\begin{verbatim} +\DTLnewrow{scores}% +\DTLnewdbentry{scores}{Surname}{van der Mere}% +\DTLnewdbentry{scores}{FirstName}{Henk}% +\DTLnewdbentry{scores}{Score}{71}% +\DTLnewrow{scores}% +\DTLnewdbentry{scores}{Surname}{de la Mere}% +\DTLnewdbentry{scores}{FirstName}{Jos}% +\DTLnewdbentry{scores}{Score}{58}% +\end{verbatim} +\DTLnewrow{scores} +\DTLnewdbentry{scores}{Surname}{van der Mere}\relax +\DTLnewdbentry{scores}{FirstName}{Henk}\relax +\DTLnewdbentry{scores}{Score}{71}\relax +\DTLnewrow{scores}\relax +\DTLnewdbentry{scores}{Surname}{de la Mere}\relax +\DTLnewdbentry{scores}{FirstName}{Jos}\relax +\DTLnewdbentry{scores}{Score}{58}\relax +and again I try sorting the database, and displaying the contents +as a table: +\begin{verbatim} +\begin{table}[htbp] +\caption{Student scores (case sensitive sort)} +\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:sortname2}. Notice that the surnames +aren't correctly ordered. This is because a case-sensitive +sort was used. Changing \cs{DTLsort} to \cs{DTLsort*} in the +above code produces \autoref{tab:sortname3}. + +\begin{table}[htbp] +\caption{Student scores (case sensitive sort)}\label{tab:sortname2} +\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} + +\begin{table}[htbp] +\caption{Student scores (case ignored when +sorting)}\label{tab:sortname3} +\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} + +\begin{example}{Influencing the sort order}{ex:sortswitchargs} +Consider the data displayed in \autoref{tab:sortname3}, suppose that +you want the names ``van der Mere'' and ``de la Mere'' sorted +according to the actual surname ``Mere'' rather than by the ``von +part''. There are two ways you can do this: firstly, you could store +the von part in a separate field, and then sort by surname, then von +part, then first name, or you could define a command called, say, +\cs{switchargs}, as follows: +\begin{verbatim} +\newcommand*{\switchargs}[2]{#2#1} +\end{verbatim} +\newcommand*{\switchargs}[2]{#2#1}\relax +then store the data as: +\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 +Henk,\switchargs{Mere}{van der },106789,71 +Jos,\switchargs{Mere}{de la },104256,58 +\end{verbatim} +\DTLnewdb{scores2}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{FirstName}{John}\relax +\DTLnewdbentry{scores2}{Surname}{Smith, Jr}\relax +\DTLnewdbentry{scores2}{StudentNo}{102689}\relax +\DTLnewdbentry{scores2}{Score}{68}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{FirstName}{Jane}\relax +\DTLnewdbentry{scores2}{Surname}{Brown}\relax +\DTLnewdbentry{scores2}{StudentNo}{102647}\relax +\DTLnewdbentry{scores2}{Score}{75}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{FirstName}{Andy}\relax +\DTLnewdbentry{scores2}{Surname}{Brown}\relax +\DTLnewdbentry{scores2}{StudentNo}{103569}\relax +\DTLnewdbentry{scores2}{Score}{42}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{FirstName}{Z\"oe}\relax +\DTLnewdbentry{scores2}{Score}{52}\relax +\DTLnewdbentry{scores2}{StudentNo}{105987}\relax +\DTLnewdbentry{scores2}{Surname}{Adams}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{FirstName}{Roger}\relax +\DTLnewdbentry{scores2}{Score}{58}\relax +\DTLnewdbentry{scores2}{StudentNo}{106872}\relax +\DTLnewdbentry{scores2}{Surname}{Brady}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{FirstName}{Clare}\relax +\DTLnewdbentry{scores2}{Score}{45}\relax +\DTLnewdbentry{scores2}{StudentNo}{104356}\relax +\DTLnewdbentry{scores2}{Surname}{Verdon}\relax +\DTLnewrow{scores2} +\DTLnewdbentry{scores2}{Surname}{\switchargs{Mere}{van der }}\relax +\DTLnewdbentry{scores2}{FirstName}{Henk}\relax +\DTLnewdbentry{scores2}{Score}{71}\relax +\DTLnewrow{scores2}\relax +\DTLnewdbentry{scores2}{Surname}{\switchargs{Mere}{de la }}\relax +\DTLnewdbentry{scores2}{FirstName}{Jos}\relax +\DTLnewdbentry{scores2}{Score}{58}\relax +Now sort the data, and put it in table (this is the same code +as in the previous example: +\begin{verbatim} +\begin{table}[htbp] +\caption{Student scores (influencing the sort order)} +\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:influencesort}. + +\begin{table}[htbp] +\caption{Student scores (influencing the sort order)}\label{tab:influencesort} +\centering +\DTLsort*{Surname,FirstName}{scores2}\relax +\begin{tabular}{llr} +\bfseries Surname & +\bfseries First Name & +\bfseries Score (\%)\relax +\DTLforeach{scores2}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +\\ +\surname & \firstname & \score} +\end{tabular} +\end{table} + +\end{example} + +\section{Saving a Database to an External File} +\label{sec:savedb} + +\begin{definition}[\DescribeMacro{\DTLsavedb}]% +\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} +will create a file called "scores.txt" and will save the data in a +tab separated format. (The delimiters will only be used if a +given entry contains the separator character.) + +\begin{definition}[\DescribeMacro{\DTLsavetexdb}]% +\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. This means that the file is in a +user-friendly format, but may be so to load, particularly if the +database is large. If you are more concerned with speed rather than +readability you can use: +\begin{definition}[\DescribeMacro{\DTLsaverawdb}]% +\cs{DTLsaverawdb}\marg{db name}\marg{filename} +\end{definition} +This saves the database to \meta{filename} in its internal +representation, which makes it faster to load. Fragile commands +cause a~problem for \cs{DTLsaverawdb} so if your database contains +any use: +\begin{definition}[\DescribeMacro{\DTLprotectedsaverawdb}]% +\cs{DTLprotectedsaverawdb}\marg{db name}\marg{filename} +\end{definition} +instead. The \app{datatooltk} application +can read and write this raw format. To load a file in this format +you can just use \cs{input} or you can use: +\begin{definition} +\cs{DTLloaddbtex}\marg{cs}\marg{file} +\end{definition} +This checks for the file's existence and assigns the database name to the +control sequence \meta{cs}. + +Databases saved using \cs{DTLsavetexdb}, \cs{DTLsaverawdb} and +\cs{DTLprotectedsaverawdb} can be loaded using \LaTeX's standard +\ics{input} command. As from version 2.15, the last line of the +database file defines +\begin{definition}[\DescribeMacro{\dtllastloadeddb}] +\cs{dtllastloadeddb} +\end{definition} +to the name of the database, in case it's required. + +Databases saved using \cs{DTLsaverawdb} and +\cs{DTLprotectedsaverawdb} can also be loaded and edited by +\app{datatooltk} (see page~\pageref{datatooltk}). + +\section{Deleting or Clearing a Database}\label{sec:deletedb} + +A database can be cleared or deleted when its contents are no +longer required. +\begin{definition}[\DescribeMacro{\DTLcleardb}] +\cs{DTLcleardb}\marg{db name} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgcleardb}] +\cs{DTLgcleardb}\marg{db name} +\end{definition} +Clears the database given by \meta{db name}. The database is emptied +but remains defined. The second form is required if you want a +global effect. + +\begin{definition}[\DescribeMacro{\DTLdeletedb}] +\cs{DTLdeletedb}\marg{db name} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLgdeletedb}] +\cs{DTLgdeletedb}\marg{db name} +\end{definition} +Deletes (undefines) the database given by \meta{db name}. The second +form is required if you want a global effect. + +\begin{important} +Although \cs{DTLdeletedb} and \cs{DTLgdeletedb} undefine the macros +associated with the database, they don't unassign the registers +used. (\TeX\ doesn't provide a command that performs the reverse of +commands such as \cs{newcount}.) If you want to keep making +temporary databases, it's better to just define a single database +(called, say, \texttt{temp}) and then just clear it rather than +delete it and define a new database. For example, if you are +iterating through a loop and want to have a temporary database +on each iteration. In that case, define the database before the +start of the loop and clear it on each iteration. If you are loading +data from an external file, remember to use \ics{DTLnewdbonloadfalse} +before \ics{DTLloaddb} (or \ics{DTLloadrawdb}). +\end{important} + +\section{Advanced Database Commands} +\label{sec:advanced} + +This section describes more advanced commands. Further details +can be found in the documented code (datatool-code.pdf). + +\begin{definition}[\DescribeMacro{\DTLgetdatatype}] +\cs{DTLgetdatatype}\marg{cs}\marg{db}\marg{key} +\end{definition} +Gets the data type for the given key \meta{key} for the database +given by \meta{db}. The data type is stored in \meta{cs} which +must be a command name. The type will be one of: +\begin{itemize} +\item\DescribeMacro{\DTLunsettype}\cs{DTLunsettype} (not set), +\item\DescribeMacro{\DTLstringtype}\cs{DTLstringtype} (string), +\item\DescribeMacro{\DTLinttype}\cs{DTLinttype} (integer), +\item\DescribeMacro{\DTLrealtype}\cs{DTLrealtype} (real number) or +\item\DescribeMacro{\DTLcurrencytype}\cs{DTLcurrenttype} (currency). +\end{itemize} + +\begin{definition}[\DescribeMacro{\DTLifdbexists}] +\cs{DTLifdbexists}\marg{db name}\marg{true part}\marg{false part} +\end{definition} +Determines if the database given by \meta{db name} exists. + +\begin{definition}[\DescribeMacro{\DTLifhaskey}] +\cs{DTLifhaskey}\marg{db name}\marg{key}\marg{true part}\marg{false part} +\end{definition} +This determines if the database given by \meta{db name} has +any entries with the key given by \meta{key}. If so, it does +\meta{true part} otherwise it does \meta{false part}. + +Each key has an associated column index. This can be obtained +using: +\begin{definition}[\DescribeMacro{\DTLgetcolumnindex}] +\cs{DTLgetcolumnindex}\marg{cs}\marg{db}\marg{key} +\end{definition} +where \meta{cs} is a command name, \meta{db} is the database label +and \meta{key} is the key. The column index is stored in +\meta{cs}. + +You can also do the reverse and find the key associated with a +given column index: +\begin{definition}[\DescribeMacro{\DTLgetkeyforcolumn}] +\cs{DTLgetkeyforcolumn}\marg{key cs}\marg{db}\marg{column index} +\end{definition} +The key is stored in \meta{key cs} (which must be a command name). + +There is also a full expandable way of obtaining the column +index, but note that no check is performed to determine +if the database exists, or if it contains the given key: +\begin{definition}[\DescribeMacro{\dtlcolumnindex}] +\cs{dtlcolumnindex}\marg{db name}\marg{key} +\end{definition} + +\begin{definition}[\DescribeMacro{\DTLgetkeydata}] +\cs{DTLgetkeydata}\marg{key}\marg{db}\marg{col cs}\marg{type cs}\marg{header cs} +\end{definition} +Gets data for given key in database \meta{db}: the column index is +stored in \meta{col cs} (as \cs{DTLgetcolumnindex}), the type is +stored in \meta{type cs} (as \cs{DTLgetdatatype}) and the header +is stored in \meta{header cs}. + +\begin{definition}[\DescribeMacro{\DTLgetvalue}] +\cs{DTLgetvalue}\marg{cs}\marg{db}\marg{r}\marg{c} +\end{definition} +This gets the value for row given by index \meta{r} and column +given by \meta{c} for the database \meta{db} and stores it in +\meta{cs} which must be a command name. If you want to get the +value by key rather than column index you can use +\cs{dtlcolumnindex}. For example, the following gets the value +for row~3 with key \texttt{Surname} from the database +\texttt{data} and stores in \cs{myval}: +\begin{verbatim} +\DTLgetvalue{\myval}{data}{3}{\dtlcolumnindex{data}{Surname}} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLgetlocation}] +\cs{DTLgetlocation}\marg{row cs}\marg{column cs}\marg{database}% +\marg{value} +\end{definition} +Assigns \meta{row cs} and \meta{column cs} to the indices of the +first entry in \meta{database} that matches \meta{value}. + +\begin{definition}[\DescribeMacro{\DTLgetvalueforkey}] +\cs{DTLgetvalueforkey}\marg{cmd}\marg{key}\marg{db name}\marg{ref + key}\marg{ref value} +\end{definition} +This (globally) sets \meta{cmd} (a control sequence) to the +value of the key specified by \meta{key} in the first row +of the database called \meta{db name} which contains the key +\meta{ref key} which has the value \meta{value}. + +\begin{definition}[\DescribeMacro{\DTLfetch}] +\cs{DTLfetch}\marg{db name}\marg{column1 name}\marg{column1 +value}\marg{column2 name} +\end{definition} +This fetches and displays the value for \meta{column2 name} in the +first row where the value of \meta{column1 name} is \meta{column1 +value}. (Note that all arguments are expanded.) So, for example, if +you have a column labelled ``regnum'' and a column labelled +``tutor'', then to fetch and display the value of the tutor in the +row where ``regnum'' is ``12345'' from the database called +``students'' you can do: +\begin{verbatim} +\DTLfetch{students}{regnum}{12345}{tutor} +\end{verbatim} +See \autoref{ex:join} on page~\pageref{ex:join}. + +\begin{definition}[\DescribeMacro{\DTLassign}] +\cs{DTLassign}\marg{db name}\marg{row idx}\marg{assign list} +\end{definition} +This (globally) assigns the list of commands in \meta{assign list} +for row \meta{row idx} in database \meta{db name}, where +\meta{assign list} has the same format as in \ics{DTLforeach}. + +\begin{definition} +\cs{DTLassignfirstmatch}\marg{db name}\marg{col key}\marg{value}\marg{assign list} +\end{definition} +This is similar to \cs{DTLassign} except that it applies to the +first row in the given database where the column identified by the +label \meta{col key} has the given value. Note that no expansion is +performed in the match. The value must be an exact match. + +\begin{definition} +\cs{xDTLassignfirstmatch}\marg{db name}\marg{col key}\marg{value}\marg{assign list} +\end{definition} +This is like \cs{DTLassignfirstmatch} but performs a~\emph{one-level} +expansion on \meta{value}. + +Two rows can be swapped using: +\begin{definition}[\DescribeMacro{\DTLswaprows}]% +\cs{DTLswaprows}\marg{db name}\marg{row1 index}\marg{row2 index} +\end{definition} +where \meta{row1 index} and \meta{row2 index} are the indices +of the rows to be swapped. For example: +\begin{verbatim} +\DTLswaprows{scores}{3}{5} +\end{verbatim} +will swap the third and fifth rows. + +\begin{example}{Two Database Rows Per Tabular Row +(Column-Wise)}{ex:twoblocks} +This example adapts \autoref{ex:2rows} so that the list is ordered +vertically rather than horizontally. +\begin{verbatim} +\begin{table}[htbp] + \caption{Two database rows per tabular row (column-wise)} + \centering + % store half number of rows + \edef\maxrows{\DTLrowcount{scores}}% + \DTLdiv{\halfrowidx}{\maxrows}{2} + \begin{tabular}{llcllc} + \bfseries First Name & + \bfseries Surname & + \bfseries Score (\%) & + \bfseries First Name & + \bfseries Surname & + \bfseries Score (\%)% + \DTLforeach*[\value{DTLrowi}<\halfrowidx]{scores}% + {\firstname=FirstName,\surname=Surname,\score=Score}% + {% + \\% + \firstname & \surname & \score + & + \edef\currentrowidx{\arabic{DTLrowi}}% + \DTLadd{\rowidxII}{\halfrowidx}{\currentrowidx}% + \DTLassign{scores}{\rowidxII}% + {\firstnameII=FirstName,\surnameII=Surname,\scoreII=Score}% + \firstnameII & \surnameII & \scoreII + }% + \end{tabular} +\end{table} +\end{verbatim} + +This produces \autoref{tab:twoblocks}. + +\begin{table}[htbp] + \caption{Two database rows per tabular row (column-wise)} + \label{tab:twoblocks} + \centering + % store half number of rows + \edef\maxrows{\DTLrowcount{scores}}% + \DTLdiv{\halfrowidx}{\maxrows}{2} + \begin{tabular}{llcllc} + \bfseries First Name & + \bfseries Surname & + \bfseries Score (\%) & + \bfseries First Name & + \bfseries Surname & + \bfseries Score (\%)% + \DTLforeach*[\value{DTLrowi}<\halfrowidx]{scores}% + {\firstname=FirstName,\surname=Surname,\score=Score}% + {% + \\% + \firstname & \surname & \score + & + \edef\currentrowidx{\arabic{DTLrowi}}% + \DTLadd{\rowidxII}{\halfrowidx}{\currentrowidx}% + \DTLassign{scores}{\rowidxII}{\firstnameII=FirstName,\surnameII=Surname,\scoreII=Score}% + \firstnameII & \surnameII & \scoreII + }% + \end{tabular} +\end{table} +\end{example} + +\subsection{Operating on Current Row} +\label{sec:currentrow} + +If you want to select from or edit a particular row in a database without having +to iterate through the database using \cs{DTLforeach}, you can use +the commands described in this section. Remember that the row index +is a reference to the internal data and is unrelated to references +in the original source (such as line numbers in a CSV file). + +\begin{definition}[\DescribeMacro{\DTLgetrowindex}] +\cs{DTLgetrowindex}\marg{row cs}\marg{db name}\marg{col +idx}\marg{value} +\end{definition} +Gets the row index of the first row in database \meta{db name} where +the value for column \meta{col idx} matches \meta{value} and stores +the result in \meta{row cs}, which must be a control sequence. +An error message is given if not found. +\begin{definition}[\DescribeMacro{\dtlgetrowindex}] +\cs{dtlgetrowindex}\marg{row cs}\marg{db name}\marg{col +idx}\marg{value} +\end{definition} +Similar to \cs{DTLgetrowindex} but doesn't produce an error if no match is +found. You can test the result by using \cs{ifx}\meta{row +cs}\cs{dtlnovalue}. For example: +\begin{verbatim} +\dtlgetrowindex{\myrowidx}{data}{\dtlcolumnindex{data}{Surname}}{Smith} +\ifx\myrowidx\dtlnovalue + Not Found +\else + Found in row \myrowidx. +\fi +\end{verbatim} + +If you want \meta{value} to be fully expanded before testing +you can use +\begin{definition}[\DescribeMacro{\xdtlgetrowindex}] +\cs{xdtlgetrowindex}\marg{row cs}\marg{db name}\marg{col +idx}\marg{value} +\end{definition} +(The \sty{etoolbox} package provides \cs{expandonce} if you +only want one level of expansion. See the \sty{etoolbox} manual for +further details.) + +\begin{definition}[\DescribeMacro{\dtlgetrow}] +\cs{dtlgetrow}\marg{db name}\marg{row idx} +\end{definition} +Gets the row with index \meta{row idx} from the database \meta{db +name}. The required row is stored in the token register +\begin{definition}[\DescribeMacro{\dtlcurrentrow}] +\cs{dtlcurrentrow} +\end{definition} +the preceding rows are stored in the token register +\begin{definition}[\DescribeMacro{\dtlbeforerow}] +\cs{dtlbeforerow} +\end{definition} +the following rows are stored in the token register +\begin{definition}[\DescribeMacro{\dtlafterrow}] +\cs{dtlafterrow} +\end{definition} +the row index, \meta{row idx}, is stored in the register +\begin{definition}[\DescribeMacro{\dtlrownum}] +\cs{dtlrownum} +\end{definition} +and the database name is stored in the control sequence +\begin{definition}[\DescribeMacro{\dtldbname}] +\cs{dtldbname} +\end{definition} +\begin{important} +No check is made in \cs{dtlgetrow} to see +if the database exists or if the row index is valid. You will probably get a \qt{Missing \{ +inserted} error if you misspell the database name and a \qt{Runaway +argument} error if you specify a row index that is out of range. +\end{important} + +\begin{definition}[\DescribeMacro{\dtlgetrowforvalue}] +\cs{dtlgetrowforvalue}\marg{db name}\marg{column index}\marg{value} +\end{definition} +Like \cs{dtlgetrow}, but this gets the row where the entry in column +\meta{column index} matches \meta{value}. This command produces an +error if no match is found. \textbf{Note that no expansion is +performed when matching \meta{value}.} If you want \meta{value} +expanded before comparison, use: +\begin{definition}[\DescribeMacro{\edtlgetrowforvalue}] +\cs{edtlgetrowforvalue}\marg{db name}\marg{column index}\marg{value} +\end{definition} + +You can use the commands below to access or edit \cs{dtlcurrentrow}, but +they won't change the database. Instead, once you've finished +editing \cs{dtlcurrentrow}, you need to reconstruct the database +token by recombining \cs{dtlbeforerow}, \cs{dtlcurrentrow} and +\cs{dtlafterrow} using: +\begin{definition}[\DescribeMacro{\dtlrecombine}] +\cs{dtlrecombine} +\end{definition} +Alternatively, to recombine omitting the current row: +\begin{definition}[\DescribeMacro{\dtlrecombineomitcurrent}] +\cs{dtlrecombineomitcurrent} +\end{definition} +(This removes the current row from the database, shifting the row +indices in \cs{dtlafterrow}.) Note that these recombining commands +assume that you haven't altered \cs{dtlrownum}, \cs{dtldbname}, +\cs{dtlbeforerow} and \cs{dtlafterrow}. + +\begin{important} +\cs{dtlcurrentrow} stores the row information using \sty{datatool}'s +internal row syntax, described in the documented code (datatool-code.pdf). +Don't explicitly modify \cs{dtlcurrentrow} unless you have a good +understanding of the syntax. +\end{important} + +\begin{definition}[\DescribeMacro{\dtlgetentryfromcurrentrow}] +\cs{dtlgetentryfromcurrentrow}\marg{cs}\marg{col idx} +\end{definition} +Gets the value from \cs{dtlcurrentrow} for the column given by +\meta{col idx} (an integer) and stores in \meta{cs}, which must be a +control sequence. + +\begin{definition}[\DescribeMacro{\dtlreplaceentryincurrentrow}] +\cs{dtlreplaceentryincurrentrow}\marg{new value}\marg{col idx} +\end{definition} +Replaces the value in \cs{dtlcurrentrow} for the column given by +\meta{col idx} (an integer) with \meta{new value}. +\begin{important} +The new value doesn't get expanded. +\end{important} + +\begin{definition}[\DescribeMacro{\dtlremoveentryincurrentrow}] +\cs{dtlremoveentryincurrentrow}\marg{col idx} +\end{definition} +Removes the value in \cs{dtlcurrentrow} for the column given by +\meta{col idx}. + +\begin{definition}[\DescribeMacro{\dtlswapentriesincurrentrow}] +\cs{dtlswapentriesincurrentrow}\marg{col1 idx}\marg{col2 idx} +\end{definition} +Swaps entries in columns \meta{col1 idx} and \meta{col2 idx} in +\cs{dtlcurrentrow} (where \meta{col1 idx} and \meta{col2 idx} are +the column indices). + +\begin{definition}[\DescribeMacro{\dtlappendentrytocurrentrow}] +\cs{dtlappendentrytocurrentrow}\marg{key}\marg{value} +\end{definition} +Appends \meta{value} to the current row for column given by +\meta{key}. (Produces an error if there is already an entry for that +column in the current row.) + +\begin{definition}[\DescribeMacro{\dtlupdateentryincurrentrow}] +\cs{dtlupdateentryincurrentrow}\marg{key}\marg{value} +\end{definition} +Behaves like \cs{dtlappendentrytocurrentrow} if the current row +doesn't contain an entry for the column given by \meta{key}, +otherwise behaves like \cs{dtlreplaceentryincurrentrow}. + +\begin{example}{Joining Two Databases in a Single Table}{ex:join} +\DTLnewdb{cmp101}\DTLnewrow{cmp101}\relax +\DTLnewdbentry{cmp101}{regnum}{12345}\relax +\DTLnewdbentry{cmp101}{Autumn Marks}{80}\relax +\DTLnewdbentry{cmp101}{Spring Marks}{85}\relax +\DTLnewrow{cmp101}\relax +\DTLnewdbentry{cmp101}{regnum}{12346}\relax +\DTLnewdbentry{cmp101}{Autumn Marks}{70}\relax +\DTLnewdbentry{cmp101}{Spring Marks}{90}\relax +\DTLnewrow{cmp101}\relax +\DTLnewdbentry{cmp101}{regnum}{12347}\relax +\DTLnewdbentry{cmp101}{Autumn Marks}{75}\relax +\DTLnewdbentry{cmp101}{Spring Marks}{60}\relax +\DTLnewdb{students}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12344}\relax +\DTLnewdbentry{students}{name}{Mary Brown}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12345}\relax +\DTLnewdbentry{students}{name}{Joe Bloggs}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12346}\relax +\DTLnewdbentry{students}{name}{Jane Doe}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12347}\relax +\DTLnewdbentry{students}{name}{John Smith}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12348}\relax +\DTLnewdbentry{students}{name}{Alice Jones}\relax +Suppose a lecturer has a CSV file for a particular course that +contains student registration numbers and marks for the Autumn and +Spring semesters. The file is called, say, \texttt{cmp101.csv} and +contains the following: + +\vskip\baselineskip +\begin{ttfamily}\par +regnum,Autumn Marks,Spring Marks\par +\DTLforeach*{cmp101}{\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks} +{\RegNum,\Autumn,\Spring\par} +\end{ttfamily} +\vskip\baselineskip\noindent + +This only contains the student registration numbers, not their +names, but suppose there's another CSV file that contains the +registration numbers and names for all students at the department +(or university). This file called, say, \texttt{students.csv} may +look something like: + +\vskip\baselineskip +\begin{ttfamily}\par +regnum,name\par +\DTLforeach*{students}{\RegNum=regnum,\Name=name} +{\RegNum,\Name\par} +\end{ttfamily} +\vskip\baselineskip\noindent + +Now suppose the lecturer wants a table of all the students on course +CMP101 listing each student's name and marks. Here's the code: +\begin{verbatim} +\DTLloaddb{cmp101}{cmp101.csv}% load course data +\DTLloaddb{students}{students.csv}% load student data + +\begin{table}[htbp] + \caption{Student Marks (Joining Databases)} + \centering + \begin{tabular}{lrr} + \bfseries Name & \bfseries Autumn Marks & \bfseries Spring Marks% + \DTLforeach*{cmp101}% + {\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks}% + {\\\DTLfetch{students}{regnum}{\RegNum}{name} & \Autumn & \Spring}% + \end{tabular} +\end{table} +\end{verbatim} + +The result is shown in \autoref{tab:join}. + +\begin{table}[htbp] + \caption{Student Marks (Joining Databases)}\label{tab:join} + \centering + \begin{tabular}{lrr} + \bfseries Name & \bfseries Autumn Marks & \bfseries Spring Marks% + \DTLforeach*{cmp101}{\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks} + {\\\DTLfetch{students}{regnum}{\RegNum}{name} & \Autumn & \Spring}% + \end{tabular} +\end{table} + +Let's suppose now that the \texttt{students.csv} file has the first +name and surname in separate columns rather than single columns. So +the CSV file looks like: +\DTLcleardb{students}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12344}\relax +\DTLnewdbentry{students}{forename}{Mary}\relax +\DTLnewdbentry{students}{surname}{Brown}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12345}\relax +\DTLnewdbentry{students}{forename}{Joe}\relax +\DTLnewdbentry{students}{surname}{Bloggs}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12346}\relax +\DTLnewdbentry{students}{forename}{Jane}\relax +\DTLnewdbentry{students}{surname}{Doe}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12347}\relax +\DTLnewdbentry{students}{forename}{John}\relax +\DTLnewdbentry{students}{surname}{Smith}\relax +\DTLnewrow{students}\relax +\DTLnewdbentry{students}{regnum}{12348}\relax +\DTLnewdbentry{students}{forename}{Alice}\relax +\DTLnewdbentry{students}{surname}{Jones}\relax + +\vskip\baselineskip +\begin{ttfamily}\par +regnum,forename,surname\par +\DTLforeach*{students}{\RegNum=regnum,\Forename=forename,\Surname=surname} +{\RegNum,\Forename,\Surname\par} +\end{ttfamily} +\vskip\baselineskip\noindent + +You may be tempted to replace +\begin{verbatim} +\DTLfetch{students}{regnum}{\RegNum}{name} +\end{verbatim} +with +\begin{verbatim} +\DTLfetch{students}{regnum}{\RegNum}{forename}\space +\DTLfetch{students}{regnum}{\RegNum}{surname} +\end{verbatim} +in the above code, but this is inefficient as it requires two +searches for the same row. Instead, you can do: +\begin{verbatim} +\DTLfetch{students}{regnum}{\RegNum}{forename}\space +\dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% +\Surname +\end{verbatim} +This can be done because +\begin{verbatim} +\DTLfetch{students}{regnum}{\RegNum}{forename} +\end{verbatim} +is equivalent to +\begin{verbatim} +\edtlgetrowforvalue{students}{\dtlcolumnindex{students}{regnum}}{\RegNum}% +\dtlgetentryfromcurrentrow + {\dtlcurrentvalue}{\dtlcolumnindex{students}{forename}}% +\dtlcurrentvalue +\end{verbatim} +This means that \cs{dtlcurrentrow} has already been set by +\cs{DTLfetch} so we can just do another +\cs{dtlgetentryfromcurrentrow} for the surname field. +The new code for the table is now: + +\begin{verbatim} +\DTLloaddb{cmp101}{cmp101.csv}% load course data +\DTLloaddb{students}{students.csv}% load student data + +\begin{table}[htbp] + \caption{Student Marks (Joining Databases)} + \centering + \begin{tabular}{lrr} + \bfseries Name & \bfseries Autumn Marks & \bfseries Spring Marks% + \DTLforeach*{cmp101}% + {\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks}% + {\\% + \DTLfetch{students}{regnum}{\RegNum}{forename}\space + \dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% + \Surname + & \Autumn & \Spring}% + \end{tabular} +\end{table} +\end{verbatim} + +The result is shown in \autoref{tab:join2}. + +\begin{table}[htbp] + \caption{Student Marks (Joining Databases)}\label{tab:join2} + \centering + \begin{tabular}{lrr} + \bfseries Name & \bfseries Autumn Marks & \bfseries Spring Marks% + \DTLforeach*{cmp101}% + {\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks}% + {\\% + \DTLfetch{students}{regnum}{\RegNum}{forename}\space + \dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% + \Surname + & \Autumn & \Spring}% + \end{tabular} +\end{table} + +\textbf{Caveat:} be careful of scoping issues. Suppose you want the +first name and surname in separate columns, you may consider doing: +\begin{verbatim} + \DTLfetch{students}{regnum}{\RegNum}{forename}% + & + \dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% + \Surname +\end{verbatim} +(and adding an extra column to the \env{tabular} environment). +However this will result in undefined values for \cs{Surname} as +\cs{dtlcurrentrow} is only locally set. After the \verb|&| special +character \cs{dtlcurrentrow} has lost its value as it's no longer in the same +scope. You can fix this problem in a~number of ways. Firstly you can +make \cs{dtlcurrentrow} global after \cs{DTLfetch} via +\begin{verbatim} +\global\dtlcurrentrow=\dtlcurrentrow +\end{verbatim} +or you could move the column break to just before \cs{Surname} and +make \cs{Surname} global: +\begin{verbatim} + \DTLfetch{students}{regnum}{\RegNum}{forename}% + \dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% + \global\let\Surname\Surname + & + \Surname +\end{verbatim} +There are other possibilities as well, but the first method is +probably the best, especially if you have multiple columns you want +to fetch. + +Here's the updated code: +\begin{verbatim} +\begin{table}[htbp] + \caption{Student Marks (Joining Databases)} + \centering + \begin{tabular}{llrr} + \bfseries Forename & \bfseries Surname & + \bfseries Autumn Marks & \bfseries Spring Marks% + \DTLforeach*{cmp101}% + {\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks}% + {\\% + \DTLfetch{students}{regnum}{\RegNum}{forename}% + \global\dtlcurrentrow=\dtlcurrentrow + & + \dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% + \Surname + & \Autumn & \Spring}% + \end{tabular} +\end{table} +\end{verbatim} +The result is shown in \autoref{tab:join3}. + +\begin{table}[htbp] + \caption{Student Marks (Joining Databases)}\label{tab:join3} + \centering + \begin{tabular}{llrr} + \bfseries Forename & \bfseries Surname & + \bfseries Autumn Marks & \bfseries Spring Marks% + \DTLforeach*{cmp101}% + {\RegNum=regnum,\Autumn=Autumn Marks,\Spring=Spring Marks}% + {\\% + \DTLfetch{students}{regnum}{\RegNum}{forename}% + \global\dtlcurrentrow=\dtlcurrentrow + & + \dtlgetentryfromcurrentrow{\Surname}{\dtlcolumnindex{students}{surname}}% + \Surname + & \Autumn & \Spring}% + \end{tabular} +\end{table} +\end{example} + +\subsection{Advanced Iteration} +\label{sec:advancediter} + +The \ics{DTLforeach} command described in \sectionref{sec:dbforeach} +has some limitations, especially when trying to iterate through +large databases. This section describes lower-level user commands +that may be used for iteration instead of \cs{DTLforeach}. + +\begin{definition}[\DescribeMacro{\dtlforeachkey}]% +\cs{dtlforeachkey}(\meta{key cs},\meta{col cs},\meta{type +cs},\meta{header cs})\cs{in}\marg{db}\cs{do}\marg{body} +\end{definition} +This iterates through all the keys in the database given by +\meta{db}. In each iteration, \meta{key cs} is set to the key, +\meta{col cs} is set to the column index, \meta{type cs} is set to +the data type (as for \cs{DTLgetdatatype}), \meta{header cs} is set +to the header for that column, and then \meta{body} is done. Note +that \meta{key cs}, \meta{col cs}, \meta{type cs} and \meta{header +cs} must all be control sequences. No check is performed to +determine if that control sequence already exists, and the control +sequences are defined globally (since it's likely that +\cs{dtlforeachkey} may be used within a \env{tabular} environment), +so you need to make sure you don't override an existing command of +the same name. + +\begin{definition}[\DescribeMacro{\dtlforcolumn}]% +\cs{dtlforcolumn}\marg{cs}\marg{db}\marg{key}\marg{body} +\end{definition} +This iterates through the column given by \meta{key} in the +database given by \meta{db} and applies \meta{body}. In each +iteration, \meta{cs} (which must be a control sequence) is set to +the current element in the column and may be used in \meta{body}. +Alternatively, if you want to identify the column by its index +rather than its key, use: +\begin{definition}[\DescribeMacro{\dtlforcolumnidx}]% +\cs{dtlforcolumnidx}\marg{cs}\marg{db}\marg{col index}\marg{body} +\end{definition} +Both \cs{dtlforcolumn} and \cs{dtlforcolumnidx} have a starred +version that doesn't check for the existence of the given database. +You may use \ics{dtlbreak} within \meta{body} to break out of the loop +at the end of the current iteration. + +An alternative to \cs{DTLforeach} is to use \TeX's primitive +\ics{loop} with \ics{DTLgetvalue}, but this may not be faster. +For example, suppose I have a CSV +file with a single column (labelled \qt{Word}) with 1000 rows of +data (where the CSV file is called \texttt{test-data-1000.csv}). +First, let's use the unstarred version of \cs{DTLforeach}: +\begin{verbatim} +\batchmode +\documentclass{article} +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000.csv} + +\begin{document} +\DTLforeach{data}{\Word=Word}{\Word.\par} +\end{document} +\end{verbatim} +On my 64bit Linux computer, this document took 4.942s to compile. +Result from \texttt{time pdflatex test}: +\begin{verbatim} +real 0m4.942s +user 0m4.934s +sys 0m0.015s +\end{verbatim} +Now using the starred version of \cs{DTLforeach}: +\begin{verbatim} +\batchmode +\documentclass{article} +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000.csv} + +\begin{document} +\DTLforeach*{data}{\Word=Word}{\Word.\par} +\end{document} +\end{verbatim} +This took 2.138s to compile: +\begin{verbatim} +real 0m2.138s +user 0m2.122s +sys 0m0.020s +\end{verbatim} +Now using \TeX's \cs{loop}: +\begin{verbatim} +\batchmode +\documentclass{article} +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000.csv} + +\begin{document} + +\newcount\rowctr +\loop + \advance\rowctr by 1\relax + \DTLgetvalue{\Word}{data}{\rowctr}{1}% + \Word.\par +\ifnum\rowctr<\DTLrowcount{data} +\repeat + +\end{document} +\end{verbatim} +(This takes advantage of the fact that I know I only have one column +of data, so I only need to reference column~1 in \cs{DTLgetvalue}.) +This takes 2.638s to compile: +\begin{verbatim} +real 0m2.638s +user 0m2.622s +sys 0m0.020s +\end{verbatim} +which is slightly longer than using \cs{DTLforeach*} (but not nearly +as long as using the unstarred version). Another possible method is +to use \cs{dtlgetrow} and \cs{dtlgetentryfromcurrentrow}: +\begin{verbatim} +\batchmode +\documentclass{article} +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000.csv} + +\begin{document} + +\newcount\rowctr +\loop + \advance\rowctr by 1\relax + \dtlgetrow{data}{\rowctr}% + \dtlgetentryfromcurrentrow{\Word}{1}% + \Word.\par +\ifnum\rowctr<\DTLrowcount{data} +\repeat + +\end{document} +\end{verbatim} +This took 3.596s to compile: +\begin{verbatim} +real 0m3.596s +user 0m3.582s +sys 0m0.019s +\end{verbatim} +Another possibility is to use \cs{dtlforcolumnidx}, described above: +\begin{verbatim} +\batchmode +\documentclass{article} +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000.csv} + +\begin{document} + +\dtlforcolumnidx{\Word}{data}{1}{\Word.\par} + +\end{document} +\end{verbatim} +This took 2.093s to compile: +\begin{verbatim} +real 0m2.093s +user 0m2.083s +sys 0m0.013s +\end{verbatim} +So if you only want to iterate through one column, this is the +fastest method, but it's still more efficient to pre-process the +data using an external script that creates a \texttt{.tex} file that +can be \cs{input} into the document. + +Note that the build time increases with extra columns, \emph{even if +they're not required in the document}. For example, I created a new +CSV file called \texttt{test-data-1000-5.csv} that had four extra +columns (which were actually duplicates of the first column with +different headers, for simplicity). Just iterating through the first +column to obtain the same PDF as previously significantly increases +the time taken. The only modification to the above examples was an +edit to the \cs{DTLloaddb} line: +\begin{verbatim} +\DTLloaddb{data}{test-data-1000-5.csv} +\end{verbatim} +The fastest method using \cs{dtlforcolumnidx} took 25.688s: +\begin{verbatim} +real 0m25.688s +user 0m25.712s +sys 0m0.013s +\end{verbatim} +Using \cs{DTLforeach*} took 25.725s: +\begin{verbatim} +real 0m25.725s +user 0m25.744s +sys 0m0.018s +\end{verbatim} +The unstarred version took 35.665s: +\begin{verbatim} +real 0m35.665s +user 0m35.692s +sys 0m0.022s +\end{verbatim} +Using \cs{loop} and \cs{DTLgetvalue} took 27.844s: +\begin{verbatim} +real 0m27.844s +user 0m27.866s +sys 0m0.019s +\end{verbatim} +Using \cs{loop} and \cs{dtlgetrow} took 31.770s: +\begin{verbatim} +real 0m31.770s +user 0m31.785s +sys 0m0.028s +\end{verbatim} + +On the other hand, if I want to only iterate through, say, the last +100 rows of the data, it's simpler to use \cs{loop}. For example: +\begin{verbatim} +\batchmode +\documentclass{article} + +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000-5.csv} + +\begin{document} +\newcount\rowctr +\rowctr=\numexpr\DTLrowcount{data}-100\relax +\loop + \advance\rowctr by 1\relax + \DTLgetvalue{\Word}{data}{\rowctr}{1}% + \Word.\par +\ifnum\rowctr<\DTLrowcount{data} +\repeat +\end{document} +\end{verbatim} +This took 25.124s: +\begin{verbatim} +real 0m25.124s +user 0m25.138s +sys 0m0.023s +\end{verbatim} +The equivalent using \cs{DTLforeach} is: +\begin{verbatim} +\batchmode +\documentclass{article} + +\usepackage{datatool} + +\DTLloaddb{data}{test-data-1000-5.csv} + +\begin{document} +\newcount\firstidx +\firstidx=\numexpr\DTLrowcount{data}-100\relax +\DTLforeach*{data}{\Word=Word}% + {\ifnum\DTLcurrentindex>\firstidx\relax\Word.\par\fi} +\end{document} +\end{verbatim} +(Remember that the row count can't be used in the optional argument +of \cs{DTLforeach} as it's only incremented when the condition is +true.) This took 26.375s: +\begin{verbatim} +real 0m26.375s +user 0m26.381s +sys 0m0.029s +\end{verbatim} +This takes longer because it's still iterating over every row of the +database and is applying the condition to each row. + +\minisec{Summary} +\begin{itemize} +\item If possible, use an external script to pre-process the data so +that you can simply \cs{input} valid \LaTeX\ code into the document. +\item If you only want to iterate through one column of the data, +use \cs{dtlforcolumnidx}. +\item Remove\footnote{Naturally, make a copy of the original data, if +necessary.}\ unwanted columns and\slash or rows from the CSV file (and sort, if +necessary) using the spreadsheet application (or whatever) that was +used to generate the original CSV file. +\end{itemize} + +\chapter{Creating an index, glossary or list of acronyms +(\texorpdfstring{\sty{datagidx}}{datagidx} package)} +\label{sec:datagidx} + +The \sty{datagidx} package is provided as an alternative to the +\sty{glossaries} package. Rather than relying on an external +indexing application, such as \app{xindy} or +\app{makeindex}, it uses the database mechanism of the +\sty{datatool} package. \emph{\sty{datagidx} and \sty{glossaries} +are not compatible.} (Note: \sty{glossaries} version 4.04 now has an +option that uses \TeX\ to sort the glossaries instead of using +\app{makeindex} or \app{xindy}.) + +First a repeat of the caveat at the start of this manual: +\begin{important} +Use the right tool for the right job. +\end{important} +Don't expect \sty{datagidx} to perform as efficiently as an +application that is designed specifically to sort and collate entries. + +If, however, you are happy to exchange efficiency for the +convenience of not having to invoke an external application in +between \LaTeX\ runs, read on. + +Sections~\ref{sec:newgidx} and~\ref{sec:newterm} describe how to +create and populate a database that's used to store terms or +acronyms. By default the database is sorted when it's displayed +using \ics{printterms} (see section~\ref{sec:printterms}). This is +where the main inefficiency lies in this package. A~faster +alternative is to use \app{datatooltk} (see page~\pageref{datatooltk}) +and its \texttt{datagidx} plugin, which will allow you to enter +terms in a graphical environment and sort the terms. This way, you +only need to sort the database after you enter a new term and the +sorting is done by a more efficient language than \TeX. Note that +this means returning to using an external helper application, but it +only needs to be used when you add a new term rather than between +each pair of \LaTeX\ runs. + +Once you've edited and sorted the database in \app{datatooltk}, +you can then just load it using: +\begin{definition}[\DescribeMacro{\loadgidx}] +\cs{loadgidx}\oarg{options}\marg{filename}\marg{title} +\end{definition} +where \meta{filename} is the name of the file saved in +\app{datatooltk}. The remaining arguments \meta{options} and +\meta{title} are the same as for \cs{newgidx}, described in +section~\ref{sec:newgidx}. This command automatically sets the +default database to the loaded database. You can change the default +database using \cs{DTLgidxSetDefaultDB}, described in +section~\ref{sec:newterm}. + +Since \cs{loadgidx} is intended for use with presorted databases, +the \csopt{loadgidx}{sort} key defaults to nothing. + +\begin{important} +If you've opted to use \sty{datagidx} over \sty{glossaries} because +you don't want to install Perl, then don't bother with +\app{datatooltk} because, although it's a Java application, it requires +Perl for the plugins. +\end{important} + +\section{Defining Index/Glossary Databases} +\label{sec:newgidx} + +\begin{important} +The databases and their associated entries described here can only +be defined in the preamble. This is because the database must be set +up before the auxiliary file is read. If you don't want to lose your +place by constantly returning to the preamble to add a new term +while you edit your document, consider putting all your definitions +in a separate file which can be \cs{input} in the preamble. +You can then switch between files without losing your place +(provided you are using a decent text editor). Alternatively, use +\app{datatooltk}'s \texttt{datagidx} plugin as described above. +\end{important} + +First you need to define a customised database that will be used to +store the entries in your index, glossary or list of acronyms: +\begin{definition}[\DescribeMacro\newgidx] +\cs{newgidx}\oarg{options}\marg{label}\marg{title} +\end{definition} +This defines a new database with a unique label and a title. +For example: +\begin{verbatim} +\newgidx{index}{Index} +\end{verbatim} +I can now identify this database using the label \texttt{index}. The +title ``Index'' is the default heading when the database is +displayed using \cs{printterms} (see \autoref{sec:printterms}). + +The optional argument \meta{options} should be a key=value list. +Available options: +\begin{description} +\item[\csopt{newgidx}{showgroups}] Boolean option that indicates +whether or not to insert group headings (and a group separator) +between index groups, if headings are supported by the given style. +If no value is supplied, \textsf{true} is assumed. + +\item[\csopt{newgidx}{style}] The style to use. The value should +be the name of the style. Available styles are listed in +\autoref{sec:indexstyles}. + +\item[\csopt{newgidx}{sort}] How to sort the database. See +\autoref{sec:indexsort} for further details. + +\item[\csopt{newgidx}{balance}] This is a boolean option that +is only applied if \csopt{printterms}{columns} is greater than~1. +If \textsf{true}, the columns are balanced. If \textsf{false}, the +columns aren't balanced. If no value is specified, \textsf{true} is +assumed. If \verb|balance=false| and \verb|columns=2| +\ics{twocolumn} is used instead of \env{multicols*}. + +\item[\csopt{newgidx}{heading}] The heading at the start of the +index/glossary. + +\item[\csopt{newgidx}{postheading}] What to put immediately after +the heading. + +\end{description} + +\section{Locations} +\label{sec:locations} + +Each term in an index or glossary database has an associated +location list. This is initially null. When you display the database +using \ics{printterms} (see \autoref{sec:printterms}) only those +entries with a non-null location list or with a ``see'' +cross-reference are displayed. The location by default is the page +number on which the entry has been used. This may be changed to +another counter by redefining +\begin{definition}[\DescribeMacro\DTLgidxCounter] +\cs{DTLgidxCounter} +\end{definition} +to the name of the required counter. For example: +\begin{verbatim} +\renewcommand*{\DTLgidxCounter}{section} +\end{verbatim} +The \styfmt{datagidx} package knows about the following counter +styles: \texttt{arabic}, \texttt{roman}, \texttt{Roman}, +\texttt{alph} and \texttt{Alph}. If your location counter uses a +different style, you will need to add a new location type. This will +only work if the counter uses a command that expands to another +command that takes a number as its argument. For example, suppose I +want to use small caps Roman numeral page numbering. I need to +define a command (say \cs{myscroman}) that takes a counter name as +its argument but expands to another command that takes a number as +its argument, like this: +\begin{verbatim} +\newcommand*{\myscroman}[1]{\myscrromannum{\value{#1}}} +\newcommand*{\myscromannum}[1]{\textsc{\romannumeral#1}} +\end{verbatim} +Note that the font changing command \cs{textsc} is in the definition +of \cs{myscromannum} not in the definition of \cs{myscroman}. +The page counter can now be changed so that it uses \cs{myscroman}: +\begin{verbatim} +\renewcommand*{\thepage}{\myscroman{page}} +\end{verbatim} +I now have to indicate that \cs{myscromannum} is a valid location +type using: +\begin{definition}[\DescribeMacro\DTLgidxAddLocationType] +\cs{DTLgidxAddLocationType}\marg{cs name} +\end{definition} +where \meta{cs name} is the name of the control sequence without the +initial backslash. Like this: +\begin{verbatim} +\DTLgidxAddLocationType{myscromannum} +\end{verbatim} +Note that this is the command that takes a number as its argument +(\cs{myscromannum}) not the command that takes a counter name as its +argument (\cs{myscroman}). + +As with \app{makeindex} and \app{xindy}, locations may have +a compositor. The default compositor is a full stop but may be +changed by redefining +\begin{definition}[\DescribeMacro\DTLgidxSetCompositor] +\cs{DTLgidxSetCompositor} +\end{definition} +Alternatively, you can use the package option \pkgopt{compositor}. + +\section{Defining Terms} +\label{sec:newterm} + +Once you have defined the database, you can now define terms +associated with that database using +\begin{definition}[\DescribeMacro\newterm] +\cs{newterm}\oarg{options}\marg{name} +\end{definition} +where \meta{name} is the term and \meta{options} is a +comma-separated list of \meta{key}=\meta{value} options. The +following keys are available: +\begin{description} +\item[\csopt{newterm}{database}] Identifies the database in which to +store this term. For example: +\begin{verbatim} +\newterm[database=index]{reptile} +\end{verbatim} +It can be somewhat cumbersome having to keep typing the database for +each new term. Instead you can identify the default database using +\begin{definition}[\DescribeMacro\DTLgidxSetDefaultDB] +\cs{DTLgidxSetDefaultDB}\marg{label} +\end{definition} +\textbf{Note:} the argument \meta{label} is not expanded. + +Example: +\begin{verbatim} + % define two indexes: + \newgidx{index}{Index} + \newgidx{people}{People} + % Set "index" as the default database: + \DTLgidxSetDefaultDB{index} + % This batch of terms will be added to database "index": + \newterm{reptile} + \newterm{mammal} + \newterm{insect} + % Set "people" as the default database: + \DTLgidxSetDefaultDB{people} + % This batch of terms will be added to database "people": + \newterm{Bob} + \newterm{Mary} + \newterm{Jane} +\end{verbatim} + +\item[\csopt{newterm}{label}] A unique identifying label. This +should not contain any active characters. If omitted, the label is +extracted from \meta{name} (see below). + +\item[\csopt{newterm}{sort}] The sort key. If omitted, this is +extracted from \meta{name} (see below). + +\item[\csopt{newterm}{parent}] The parent entry, if this is a +sub-term. An entry may only have one parent. If you want the same +term to appear under two different parents, you'll have to define +two separate terms with the same name but different parents (and +different labels). This is the only way to avoid ambiguity with the +hyperlinks (if enabled). + +\item[\csopt{newterm}{text}] How the entry should appear in the +document text. This is \meta{name} by default. If this option is +used, \meta{name} indicates how the entry should appear in the +index, glossary or list of acronyms. + +\item[\csopt{newterm}{description}] An optional description. This is +usually not required for an index but needed for a glossary. + +\item[\csopt{newterm}{plural}] The plural form of the term. If +omitted this is formed by appending ``s'' to \meta{name} (or the +value of the \csopt{newterm}{text} key if supplied). + +\item[\csopt{newterm}{symbol}] An associated symbol if required. + +\item[\csopt{newterm}{short}] An associated short form if required. +(Default \meta{name}.) + +\item[\csopt{newterm}{long}] An associated long form if required. +(Default \meta{name}.) + +\item[\csopt{newterm}{shortplural}] An associated short plural if +required. (Default formed by appending ``s'' to the value of the +\csopt{newterm}{short} key.) + +\item[\csopt{newterm}{longplural}] An associated long plural if +required. (Default formed by appending ``s'' to the value of the +\csopt{newterm}{long} key.) + +\item[\csopt{newterm}{see}] A cross-reference to a synonym. The +value should be the label of another entry. This entry will not have +a location list, just the reference to the other term. + +\item[\csopt{newterm}{seealso}] A cross-reference to a closely +related term. This entry should have both a location list and a +reference to the other term. + +\end{description} + +If the \csopt{label} or \csopt{sort} key are omitted, \sty{datagidx} +tries to form sensible defaults. At the moment, this involves +stripping certain commands (\ics{MakeUppercase}, +\ics{MakeLowercase}, +\ics{MakeTextUppercase}, \ics{MakeTextLowercase}, \ics{acronymfont}, +\ics{textsc}, \ics{textbf}, \ics{textmd}, \ics{textit}, +\ics{textsl}, \ics{textrm}, \ics{texttt}, \ics{textsf}, \ics{emph}, +\ics{ensuremath} and \ics{textsuperscript}), stripping accents +and replacing certain control characters or control sequences +(\verb|~| is replace with a space and \verb|\&| is replaced with +\ics{andname} (if defined) or ``and'' (if \cs{andname} isn't +defined)). The Greek letter commands (\ics{alpha} etc) are converted +to their name. + +Examples: +\begin{enumerate} +\item \ics{ensuremath} is stripped and \ics{alpha} is converted to +``alpha'' so the following: +\begin{verbatim} +\newterm{\ensuremath{\alpha}} +\end{verbatim} +sets both the label and sort to \texttt{alpha} but the name and text +fields are set to \verb|\ensuremath{\alpha}|. + +\item Accent commands are stripped so the following: +\begin{verbatim} +\newterm{mac\'edoine} +\end{verbatim} +sets both the label and sort fields to \texttt{macedoine} but the +name and text fields are set to \verb|mac\'edoine|. + +\begin{important} +The first letter must be grouped if it's an accent or ligature or a +character outside the range \texttt{a}\ldots\texttt{z} or +\texttt{A}\ldots\texttt{Z}. +\end{important} + +\item This example must have the sort and label fields set manually +because the first letter has an accent: +\begin{verbatim} +\newterm[label=elite,sort=elite]{{\'e}lite} +\end{verbatim} + +\item The same applies if you are using the \sty{inputenc} package: +\begin{verbatim} +\newterm[label=elite,sort=elite]{{é}lite} +\end{verbatim} + +\item The same applies to plural terms set explicitly: +\begin{verbatim} +\newterm + [% + plural={{œ}sophagi},% + label={oesophagus},% + sort={oesophagus}% + ] + {{œ}sophagus} +\end{verbatim} + +\item Commands such as \ics{oe} aren't dealt with, so you must +manually set the label and sort key: +\begin{verbatim} +\newterm[label=manoeuvre,sort=manoeuvre]{man\oe uvre} +\end{verbatim} + +\item The same applies if you are using the \sty{inputenc} package: +\begin{verbatim} +\newterm[label=manoeuvre,sort=manoeuvre]{manœuvre} +\end{verbatim} + +\begin{important} +Take care if any of the values to fields contain a comma or equal +sign. The value must be grouped. +\end{important} + +\item This term contains a comma in some of the fields: +\begin{verbatim} +\newterm + [% + label={comma},% + sort={,},% + text={comma (,)}% + plural={commas (,)}% + ] + {, (comma)} +\end{verbatim} +In the text, the entry is \texttt{comma (,)} but in the index the +entry is sorted according to the comma symbol and is displayed as +\texttt{, (comma)}. + +\end{enumerate} + +\subsection{Commands to Assist Sorting} + +There are some situations where you will have to specify the sort +key, for example: +\begin{verbatim} +\newterm +[ + sort={Ten Downing Street} +] +{10 Downing Street} +\end{verbatim} + +However, there are some commands provided to help set the default +sort for entries that are sorted differently from the way they are +typeset in the index/glossary, which can help reduce the number of times you +need to explicitly set the sort field. + +\begin{definition}[\DescribeMacro\DTLgidxParen] +\cs{DTLgidxParen}\marg{text} +\end{definition} +This command is provided for parenthetical material that should be +typeset in the index, but should not contribute to the sort unless +there is an identical entry without parenthetical material. + +For example: +\begin{verbatim} +\newterm{0\DTLgidxParen{zero}} +\end{verbatim} +This term is typeset as \texttt{0 (zero)}, but has the sort and +label fields set to \texttt{0}. + +The default sort used is word-order sorting. This has a special +number group for entries where the sort field consists solely of +digits and they are sorted numerically rather than by string +comparison. Using \cs{DTLgidxParen} in this manner, the following +terms will appear in numerical order in the index: +\begin{verbatim} +\newterm{0\DTLgidxParen{zero}} +\newterm{1\DTLgidxParen{one}} +\newterm{2\DTLgidxParen{two}} +\newterm{3\DTLgidxParen{three}} +\newterm{10\DTLgidxParen{ten}} +\newterm{100\DTLgidxParen{one hundred}} +\newterm{20\DTLgidxParen{twenty}} +\end{verbatim} +If \cs{DTLgidxParen} was not used and the parentheses were +explicitly included, e.g.\ \texttt{0 (zero)}, then the entries would +be placed in the symbol group instead and be sorted according to +string (so \texttt{10 (ten)} would come before \texttt{2 (two)}). + +\begin{definition}[\DescribeMacro\DTLgidxPlace] +\cs{DTLgidxPlace}\marg{country/county}\marg{city/town} +\end{definition} +Use this command to indicate a place. For example: +\begin{verbatim} +\newterm{\DTLgidxPlace{USA}{New York}} +\end{verbatim} +This sets the label and name to \texttt{New York, USA}, the text +field is set to just \texttt{New York} and the sort field is set to +\verb|New York\datatoolplacecomma USA| (see \autoref{sec:sort}). + +\begin{definition}[\DescribeMacro\DTLgidxSubject] +\cs{DTLgidxSubject}\marg{subject}\marg{text} +\end{definition} +Use this to indicate a subject, concept or object. Example: +\begin{verbatim} +\newterm{\DTLgidxSubject{population}{New York}} +\end{verbatim} +Both the label and name fields default to \texttt{New York, +population}, the text field defaults to \texttt{population} and the +sort field is set to \verb|New York\datatoolsubjectcomma population| +(see \autoref{sec:sort}). + +\begin{definition}[\DescribeMacro\DTLgidxName] +\cs{DTLgidxName}\marg{forename(s)}\marg{surname} +\end{definition} +Use this command to index a person. The entry will be sorted +according to the surname then the forenames. The entry will be +displayed as \meta{surname}, \meta{forename(s)} in the index but +will be displayed as \meta{forename(s)} \meta{surname} when +referenced in the document. The label, on the other hand, is set to +just the surname. Example: +\begin{verbatim} +\newterm{\DTLgidxName{Donald E.}{Knuth}} +\end{verbatim} +This sets the name field to \texttt{Knuth, Donald E.}, the text +field to \texttt{Donald E. Knuth}, the label to \texttt{Knuth} and the sort field to +\texttt{Knuth\ics{datatoolpersoncomma} Donald E.} (see +\autoref{sec:sort}). + +A person's title (such as ``Dr'') should typically not affect the +sort, unless there is another person with the same surname and +forenames (or initials) without a title. To assist this, you can +identify a person's title using: +\begin{definition}[\DescribeMacro\DTLgidxRank] +\cs{DTLgidxRank}\marg{title}\marg{forename(s)/initial(s)} +\end{definition} +Using examples from the Oxford Style Manual: +\begin{verbatim} +\newterm[label=AliceMeynell]{\DTLgidxName{Meynell}{Alice}} +\newterm[label=DrMeynell]{\DTLgidxName{Meynell}{\DTLgidxRank{Dr}{A.}}} +\newterm[label=AMeynell]{\DTLgidxName{Meynell}{A.}} +\end{verbatim} +Here the labels must be set as the surnames are identical for each +entry, but the entries will be sorted in the order: ``Meynell, A.'', +``Meynell, Dr~A.'' and ``Meynell, Alice''. + +You can use +\begin{definition}[\DescribeMacro\DTLgidxNameNum] +\cs{DTLgidxNameNum}\marg{number} +\end{definition} +to indicate a number associated with a name. The number is typeset +as an uppercase Roman numeral in the text, but is sorted +numerically. + +For example: +\begin{verbatim} +\newterm{James~\DTLgidxNameNum{1}} +\end{verbatim} +This is typeset as \verb|James~I|, but gets the label +\texttt{James I} (note no tilde) and the sort field is set to +\texttt{James 01}. This means that if I want to index all the Kings +whose name is James, they will appear in the correct order in the +index. + +If a term contains a variant of ``Mac'' you can also use: +\begin{definition}[\DescribeMacro\DTLgidxMac] +\cs{DTLgidxMac}\marg{text} +\end{definition} +The entry will be typeset with \meta{text} but the sort key will +have \meta{text} replaced with \texttt{Mac}. Examples: +\begin{verbatim} +\newterm{\DTLgidxName{Joe}{\DTLgidxMac{Mc}Cullers}} +\newterm{\DTLgidxName{Bob}{\DTLgidxMac{M'}Fingal}} +\newterm{\DTLgidxMac{Mc}Carthyism} +\newterm{\DTLgidxMac{Mc}Guffin} +\end{verbatim} + +Similarly saints can be identified using: +\begin{definition}[\DescribeMacro\DTLgidxSaint] +\cs{DTLgidxSaint}\marg{text} +\end{definition} +Examples: +\begin{verbatim} +\newterm{\DTLgidxSaint{St} Julian} +\newterm{\DTLgidxName{Q.}{\DTLgidxSaint{St}~John-Smythe}} +\newterm{\DTLgidxPlace{\DTLgidxSaint{St}~Andrews}{Fife}} +\end{verbatim} +These will be sorted according to \texttt{Saint Julian}, +\verb|Saint John-Smythe\datatoolpersoncomma Q.| and +\verb|Saint Andrews\datatoolplacecomma Fife|. + +Particles, such as ``de'', ``von'' or ``of'' are usually ignored +when sorting. These can be identified using: +\begin{definition}[\DescribeMacro\DTLgidxParticle] +\cs{DTLgidxParticle}\marg{text} +\end{definition} +Examples: +\begin{verbatim} +\newterm{\DTLgidxName{Fred}{\DTLgidxParticle{de}{Winter}}} +\newterm{\DTLgidxName{Gustav}{\DTLgidxParticle{von}{Aschenbach}}} +\end{verbatim} +Here the names are sorted according to +\verb|Winter\datatoolpersoncomma Fred| and +\verb|Aschenbach\datatoolpersoncomma Gustav| but the labels are set +to \texttt{deWinter} and \texttt{vonAschenbach}. + +A person can also be indicated by their office, for example ``Henry, +scribe of Bury St~Edmunds''. For this, you can use: +\begin{definition}[\DescribeMacro\DTLgidxOffice] +\cs{DTLgidxOffice}\marg{office}\marg{name} +\end{definition} +Here the label defaults to just \meta{name}, so you may need to set +the label manually to ensure uniqueness. Examples: +\begin{verbatim} +\newterm +[ + label={HenrySonJohn} +] +{\DTLgidxOffice{son \DTLgidxParticle{of}{John}}{Henry}} + +\newterm +[ + label={HenryBeaumont} +] +{\DTLgidxOffice{bishop \DTLgidxParticle{of}{Bayeux}}{Henry +\DTLgidxParticle{de}{Beaumont}}} + +\newterm +[ + label={HenryScribe} +] +{\DTLgidxOffice{scribe \DTLgidxParticle{of}{Bury} + \DTLgidxSaint{St}~Edmunds}{Henry}} + + +\end{verbatim} + +You can hook into the mechanism that sets the default sort key by +adding to the definition of +\begin{definition}[\DescribeMacro\newtermlabelhook] +\cs{newtermlabelhook} +\end{definition} +You can use \sty{etoolbox}'s \ics{appto} command to append to this +hook. For example, suppose you want to index the terms \verb|\TeX|, +\verb|e\TeX| and \verb|pdf\TeX|, but you want the terms to have the +label and sort fields to be just \verb|TeX|, \verb|eTeX| and +\verb|pdfTeX|, then you can add to the hook so that it automatically +converts \ics{TeX} to just \texttt{TeX}: +\begin{verbatim} +\appto\newtermlabelhook{\def\TeX{TeX}} +\end{verbatim} +(Note that it's important to use the local \ics{def} rather than the +global \ics{gdef} to ensure the redefinition is localised.) + +Now the terms can simply be defined using: +\begin{verbatim} +\newterm{\TeX} +\newterm{e\TeX} +\newterm{pdf\TeX} +\end{verbatim} + +To assist in using this mechanism, the following commands are +available (these commands may also be used in the mandatory argument +of \cs{newterm}): +\begin{definition}[\DescribeMacro\DTLgidxNoFormat] +\cs{DTLgidxNoFormat}\marg{text} +\end{definition} +This commands simply does its argument, so any commands that should +be stripped from the label or sort field without the loss of their +argument can be \ics{let} to \cs{DTLgidxNoFormat}. For example, +suppose you want to define a command called, say, \cs{appname} that +you want to use to identify application names, like this: +\begin{verbatim} +\newcommand*{\app}[1]{\texttt{#1}} +\end{verbatim} +This command needs to be stripped from the label and sort, so it can +be added to the hook like this: +\begin{verbatim} +\appto\newtermlabelhook{\let\app\DTLgidxNoFormat} +\end{verbatim} +Now you can define terms like this: +\begin{verbatim} +\newterm{\app{makeindex}} +\newterm{\app{xindy}} +\end{verbatim} +The label and sort keys are then set to \texttt{makeindex} (for the +first term) and \texttt{xindy} (for the second term). + +\begin{definition}[\DescribeMacro\DTLgidxGobble] +\cs{DTLgidxGobble}\marg{text} +\end{definition} +This command discards its argument, so it can be used if you not +only want to strip a command but also its argument from the label +and sort fields. + +For example, suppose you want some terms to have a footnote (both in the +index/glossary and in the document text) but the footnote shouldn't +form part of the sort or label fields. You can add to the hook like +this: +\begin{verbatim} +\appto\newtermlabelhook{\let\footnote\DTLgidxGobble} +\end{verbatim} +Now you can define some terms with footnotes: +\begin{verbatim} +\newterm{foo\footnote{a note about foo}} +\newterm{bar\footnote{a note about bar}} +\end{verbatim} +The label and sort keys are then set to \texttt{foo} (for the first +term) and \texttt{bar} (for the second term). + +\begin{definition}[\DescribeMacro\DTLgidxIgnore] +\cs{DTLgidxIgnore} +\end{definition} +This is similar to \cs{DTLgidxGobble} but only affects the sort key +not the label. Example: +\begin{verbatim} +\newterm{de\DTLgidxIgnore{-}escalate} +\end{verbatim} +This is displayed as \texttt{de-escalate} and gets the label +\texttt{de-escalate} but is sorted according to \texttt{deescalate}. + +\begin{definition}[\DescribeMacro\DTLgidxStripBackslash] +\cs{DTLgidxStripBackslash}\marg{control sequence} +\end{definition} +This can be used to ``stringify'' a control sequence and remove the +leading backslash. For example, suppose you want to index the +ampersand symbol (\&) but you want to sort it according to the +actual symbol \verb|&|, you can do: +\begin{verbatim} +\newterm + [% + label={amp}, + sort={\DTLgidxStripBackslash{\&}}, + text={ampersand (\&)}, + plural={ampersands (\&)}, + ] + {\& (ampersand)} +\end{verbatim} + +\section{Referencing Terms} +\label{sec:useentry} + +You can reference terms using +\begin{definition}[\DescribeMacro\useentry] +\cs{useentry}\marg{label}\marg{field} +\end{definition} +This fetches the given field for the term identified by +\meta{label}, displays it and marks the term as having been used. +Example, suppose I have previous (in the preamble) defined the term +``reptile'' using: +\begin{verbatim} +\newterm{reptile} +\end{verbatim} +I can now reference this term in the document: +\begin{verbatim} +\useentry{reptile}{Text} +\end{verbatim} +or if I want the plural, I can use: +\begin{verbatim} +\useentry{reptile}{Plural} +\end{verbatim} +There are also uppercase versions: +\begin{definition}[\DescribeMacro\Useentry] +\cs{Useentry}\marg{label}\marg{field} +\end{definition} +This makes the first letter uppercase (using the \sty{mfirstuc} +package) or to make the whole text uppercase use: +\begin{definition}[\DescribeMacro\USEentry] +\cs{USEentry}\marg{label}\marg{field} +\end{definition} + +If you use the \sty{hyperref} package, the above commands will +automatically create hyperlinks to the relevant entry in the +index/glossary. You can suppress this action by using one of the +following analogous commands instead: +\begin{definition}[\DescribeMacro\useentrynl] +\cs{useentrynl}\marg{label}\marg{field} +\end{definition} +\begin{definition}[\DescribeMacro\Useentrynl] +\cs{Useentrynl}\marg{label}\marg{field} +\end{definition} +\begin{definition}[\DescribeMacro\USEentrynl] +\cs{USEentrynl}\marg{label}\marg{field} +\end{definition} + +You can also specify your own custom text: +\begin{definition}[\DescribeMacro\glslink] +\cs{glslink}\marg{label}\marg{text} +\end{definition} + +In all the above commands, the \meta{label} argument may optionally +start with \oarg{format}, where format is the name of a control +name \emph{without} the preceding backslash. This command will be +applied to this location in the entry's location list when it's +displayed in the index/glossary. + +For example: +\begin{verbatim} +\useentry{[textbf]reptile}{Text} +\end{verbatim} +Note that the command (\cs{textbf} in the above example) should take +one argument (the location). If you attempt to use, say, a +declaration (such as \cs{bfseries}) the effect won't be localised. + +You can display the value of a field without indexing it using: +\begin{definition}[\DescribeMacro\glsdispentry] +\cs{glsdispentry}\marg{label}\marg{field} +\end{definition} +To make the first letter uppercase, use: +\begin{definition}[\DescribeMacro\Glsdispentry] +\cs{Glsdispentry}\marg{label}\marg{field} +\end{definition} +The above commands aren't expandable. If you want to fetch a value +without displaying or using it, you can use: +\begin{definition}[\DescribeMacro\DTLgidxFetchEntry] +\cs{DTLgidxFetchEntry}\marg{cs}\marg{label}\marg{field} +\end{definition} +where \meta{cs} is a control sequence, \meta{label} is the label +that uniquely identifies the entry and \meta{field} is the required +field. The value of that field is stored in \meta{cs}. + +The predefined database fields are: +\begin{description} +\item[Name] How the term appears in the index/glossary (as specified +by the mandatory argument of \ics{newterm}). +\item[Text] The value of the \csopt{newterm}{text} field. +\item[Plural] The value of the \csopt{newterm}{plural} field. +\item[Description] The value of the \csopt{newterm}{description} +field. +\item[Symbol] The value of the \csopt{newterm}{symbol} field. +\item[Long] The value of the \csopt{newterm}{long} field. +\item[Short] The value of the \csopt{newterm}{short} field. +\item[LongPlural] The value of the \csopt{newterm}{longplural} +field. +\item[ShortPlural] The value of the \csopt{newterm}{shortplural} +field. +\item[See] The value of the \csopt{newterm}{see} field. +\item[SeeAlso] The value of the \csopt{newterm}{seealso} field. +\item[Sort] The value of the \csopt{newterm}{sort} field. +\item[Parent] The value of the \csopt{newterm}{parent} field. +\item[Label] The entry's unique identifying label. +\item[Used] Has the value 1 (entry has been used) or either 0 or +undefined (entry hasn't been used). +\item[Location] The entry's location list (picked up from the last +\LaTeX\ run). +\end{description} + +In addition, there are some fields designed for internal use: +\texttt{Child}, \texttt{FirstId} and \texttt{CurrentLocation}. + +You can add an entry to the index/glossary without displaying any +text using: +\begin{definition}[\DescribeMacro\glsadd] +\cs{glsadd}\marg{label} +\end{definition} +As with \cs{useentry}, \meta{label} maybe in the form +\oarg{format}\marg{label} where \meta{format} is the name of a +control sequence \emph{without} the leading backslash. + +You can also add all entries from a particular database using +\begin{definition}[\DescribeMacro\glsaddall] +\cs{glsaddall}\marg{db name} +\end{definition} +where \meta{db name} is the name of the database. + +Unlike the commands of the same name provided by the +\sty{glossaries} package, here there is a difference between +\cs{glsaddall} and using \cs{glsadd} on all entries in the database. +In the case of \cs{glsadd} a location is added to the location list +for that entry. However in the case of \cs{glsaddall} no location is +added to each entry's location list, but the location list is set to +non-null so the entry will appear in the index/glossary. + +\subsection{Shortcut Commands} + +There are some shortcuts to common fields (if you are used to the +\sty{glossaries} package, note that these commands have different +formats to the commands provided by \sty{glossaries} with the same +name): +\begin{definition}[\DescribeMacro\gls] +\cs{gls}\marg{label} +\end{definition} +This is equivalent to \cs{useentry}\marg{label}\verb|{Text}|. +\begin{definition}[\DescribeMacro\glspl] +\cs{glspl}\marg{label} +\end{definition} +This is equivalent to \cs{useentry}\marg{label}\verb|{Plural}|. +\begin{definition}[\DescribeMacro\glsnl] +\cs{glsnl}\marg{label} +\end{definition} +This is equivalent to \cs{useentrynl}\marg{label}\verb|{Text}|. +\begin{definition}[\DescribeMacro\glsplnl] +\cs{glsplnl}\marg{label} +\end{definition} +This is equivalent to \cs{useentrynl}\marg{label}\verb|{Plural}|. + +\begin{definition}[\DescribeMacro\Gls] +\cs{Gls}\marg{label} +\end{definition} +This is equivalent to \cs{Useentry}\marg{label}\verb|{Text}|. +\begin{definition}[\DescribeMacro\Glspl] +\cs{Glspl}\marg{label} +\end{definition} +This is equivalent to \cs{Useentry}\marg{label}\verb|{Plural}|. +\begin{definition}[\DescribeMacro\Glsnl] +\cs{Glsnl}\marg{label} +\end{definition} +This is equivalent to \cs{Useentrynl}\marg{label}\verb|{Text}|. +\begin{definition}[\DescribeMacro\Glsplnl] +\cs{Glsplnl}\marg{label} +\end{definition} +This is equivalent to \cs{Useentrynl}\marg{label}\verb|{Plural}|. + +\begin{definition}[\DescribeMacro\glssym] +\cs{glssym}\marg{label} +\end{definition} +This is equivalent to \cs{useentry}\marg{label}\verb|{Symbol}|. +\begin{definition}[\DescribeMacro\Glssym] +\cs{Glssym}\marg{label} +\end{definition} +This is equivalent to \cs{Useentry}\marg{label}\verb|{Symbol}|. + +\section{Adding Extra Fields} + +You can add new fields to the index/glossary database using: +\begin{definition}[\DescribeMacro\newtermaddfield] +\cs{newtermaddfield}\oarg{db list}\marg{field name}\marg{key +name}\marg{default value} +\end{definition} +The optional argument \meta{db list} is a comma-separated list of +databases that should have this new field. If omitted, the field +will be added to all the defined databases. The argument \meta{field +name} is the label to give this new column in the database(s). The +argument \meta{key name} is the name of the new key to use in the +optional argument of \ics{newterm}. The final argument \meta{default +value} is the default value if the key isn't used. Within +\meta{default value}, you may use +\begin{definition}[\DescribeMacro\field] +\cs{field}\marg{key} +\end{definition} +to indicate the value of another key. + + +For example, suppose I want to be able to specify an alternative +plural. I can add a new field like this: +\begin{verbatim} +\newtermaddfield{AltPlural}{altplural}{} +\end{verbatim} +This adds a new column with the label \texttt{AltPlural} to each +defined index/glossary database and adds a new key called +\texttt{altplural} that I can now use in \ics{newterm}. The default +is set to empty. Now I can define terms with an alternative plural: +\begin{verbatim} +\newterm[altplural=kine]{cow} +\end{verbatim} +In the document, I can use \verb|\gls{cow}| to display ``cow'', +\verb|\glspl{cow}| to display ``cows'' and +\verb|\useentry{cow}{AltPlural}| to display ``kine''. To make life a +little easier, I can define a new command to save typing: +\begin{verbatim} +\newcommand*{\glsaltpl}[1]{\useentry{#1}{AltPlural}} +\end{verbatim} +Now I can just do \verb|\glsaltpl{cow}| to display ``kine''. + +Here's another example. Suppose I want to add a field that produces +the past tense of a verb. In this case, the default should be formed +by appending ``ed'' to the \csopt{newterm}{text} field. The new +field can be defined as follows: +\begin{verbatim} +\newtermaddfield{Ed}{ed}{\field{text}ed} +\end{verbatim} +This adds a new column labelled ``Ed'' and defines a new key called +``ed'' that can be used with \ics{newterm}. Now I can defined some +verbs: +\begin{verbatim} +\newterm{jump} +\newterm[ed=went]{go} +\end{verbatim} + +Let's define a convenience command to access this field: +\begin{verbatim} +\newcommand*{\glsed}[1]{\useentry{#1}{Ed}} +\end{verbatim} +This new field can now be referenced in the document: +\begin{verbatim} +He \glsed{jump} over the gate. +She \glsed{go} to the shop. +\end{verbatim} +The above will be displayed as: He jumped over the gate. She went to +the shop. + +\section{Acronyms} + +You may have noticed that you can specify \csopt{newterm}{short} and +\csopt{newterm}{long} fields when you define a new term. There is a +convenient shortcut command which uses \ics{newterm} to define an +acronym. The syntax is: +\begin{definition}[\DescribeMacro\newacro] +\cs{newacro}\oarg{options}\marg{short}\marg{long} +\end{definition} +This is a shortcut for +\begin{alltt} +\ics{newterm} + [% + description=\{\ics{capitalisewords}\marg{long}\},% + short=\{\cs{acronymfont}\marg{short}\},% + long=\marg{long},% + text=\{\cs{DTLgidxAcrStyle}\marg{long}\{\cs{acronymfont}\marg{short}\}\},% + plural=\{\cs{DTLgidxAcrStyle}\{\meta{long}s\}\{\cs{acronymfont}\{\meta{short}s\}\}\},% + sort=\marg{short},% + \meta{options}% + ]% + {\ics{MakeTextUppercase}\marg{short}} +\end{alltt} +where \ics{capitalisewords} is defined in \sty{mfirstuc} +(automatically loaded by \styfmt{datagidx}) and +\ics{MakeTextUppercase} is defined in \sty{textcase} (automatically +loaded by \styfmt{datagidx}). The other commands used are defined by +\styfmt{datagidx}: +\begin{definition}[\DescribeMacro\acronymfont] +\cs{acronymfont} +\end{definition} +By default this just typesets its argument but can be redefined if +the acronyms need to be typeset in a certain style (such as small +caps). +\begin{definition}[\DescribeMacro\DTLgidxAcrStyle] +\cs{DTLgidxAcrStyle}\marg{long}\marg{short} +\end{definition} +This governs how the acronym is typeset in the \csopt{newterm}{text} +field. This defaults to: \meta{long} (\meta{short}). + +\subsection{Using Acronyms} + +You can use terms that represent acronyms via commands such as +\ics{useentry}. For example, if you define the following in the +preamble: +\begin{verbatim} +\newacro{css}{cascading style sheet} +\end{verbatim} +then later in the text you can use: +\begin{verbatim} +\useentry{css}{Short} +\end{verbatim} +to access the short form and +\begin{verbatim} +\useentry{css}{Long} +\end{verbatim} +to access the long form. You can also use +\begin{verbatim} +\useentry{css}{Text} +\end{verbatim} +(or \verb|\gls{css}|) to access the full version. However with +acronyms you generally only want the full form on first use and just +the short form on subsequent use. The following commands are +provided to do that. The singular form is obtained using: +\begin{definition}[\DescribeMacro\acr] +\cs{acr}\marg{label} +\end{definition} +The plural form is obtained using: +\begin{definition}[\DescribeMacro\acrpl] +\cs{acrpl}\marg{label} +\end{definition} + +Note that, unlike the \sty{glossaries} package, \cs{acr} isn't the +same as \cs{gls}. With \styfmt{datagidx}, \cs{gls} always references +the \csopt{newterm}{text} field. There is no ``first'' field. + +\begin{important} +Take care when using acronyms with \cls{beamer}. Using overlays can +cause problems with first use expansions. +\end{important} + +As a general rule, you're not supposed to capitalise the first +letter of an acronym (especially if it is displayed in small caps) but if you need to +you can use: +\begin{definition}[\DescribeMacro\Acr] +\cs{Acr}\marg{label} +\end{definition} +and +\begin{definition}[\DescribeMacro\Acrpl] +\cs{Acrpl}\marg{label} +\end{definition} + +\subsection{Unsetting and Resetting Acronyms} + +You can reset a term so it's marked as not used with: +\begin{definition}[\DescribeMacro\glsreset] +\cs{glsreset}\marg{label} +\end{definition} +or you can unset a term so it's marked as used with: +\begin{definition}[\DescribeMacro\glsunset] +\cs{glsunset}\marg{label} +\end{definition} + +You can reset all the terms defined in a given database using: +\begin{definition}[\DescribeMacro\glsresetall] +\cs{glsresetall}\marg{db name} +\end{definition} +or unset all the terms defined in a given database using: +\begin{definition}[\DescribeMacro\glsunsetall] +\cs{glsunsetall}\marg{db name} +\end{definition} +where \meta{db name} is the name of the database as supplied when +the database was defined using \ics{newgidx}. + +\section{Conditionals} + +You can test if a term exists using +\begin{definition}[\DescribeMacro\iftermexists] +\cs{iftermexists}\marg{label}\marg{true part}\marg{false part} +\end{definition} +You can test if a term has been used using: +\begin{definition}[\DescribeMacro\ifentryused] +\cs{ifentryused}\marg{label}\marg{true part}\marg{false part} +\end{definition} + +\section{Displaying the Index or Glossary} +\label{sec:printterms} + +The index or glossary can be displayed using +\begin{definition}[\DescribeMacro\printterms] +\cs{printterms}\oarg{options} +\end{definition} +You will need to run \LaTeX\ at least twice to ensure your +index/glossary is up-to-date. The first run will only display any +entries that have a ``See'' field defined. + +The optional argument \meta{options} is a comma-separated list of +\meta{key}=\meta{value} options. Available keys: +\begin{description} +\item[\csopt{printterms}{database}] The name of the database (as +given in \ics{newgidx}). + +\item[\csopt{printterms}{postdesc}] This may have the value +\textsf{dot} (put a full stop after the description) or +\textsf{none} (don't put a full stop after the description). + +\item[\csopt{printterms}{prelocation}] This indicates what to put +before the location list. Available values: +\begin{description} +\item[\textsf{none}] Nothing. +\item[\textsf{enspace}] An en-space. +\item[\textsf{space}] An ordinary space. +\item[\textsf{dotfill}] A dotted line (\ics{dotfill}). +\item[\textsf{hfill}] Expandable space (\ics{hfill}). +\end{description} + +\item[\csopt{printterms}{location}] This indicates how to display +the location list. Available values: +\begin{description} +\item[\textsf{hide}] Don't display the location list. +\item[\textsf{list}] Display the location list. +\item[\textsf{first}] Only display the first location in the list. +\end{description} + +\item[\csopt{printterms}{symboldesc}] How to format the symbol in +relation to the description. Available values: +\begin{description} +\item[\textsf{symbol}] Display the symbol but not the description. +\item[\textsf{desc}] Display the description but not the symbol +field. +\item[\textsf{(symbol) desc}] Display the symbol (if defined) in parentheses +followed by the description. +\item[\textsf{desc (symbol)}] Display the description followed by +the symbol (if defined) in parentheses. +\item[\textsf{symbol desc}] Display the symbol (if defined) followed +by the description. +\item[\textsf{desc symbol}] Display the description followed by the +symbol (if defined). +\end{description} + +\item[\csopt{printterms}{columns}] This should be a positive number +that indicates the page column layout. If the value is greater +than~1, the \env{multicols} environment is used (defined in the +\sty{multicol} package, which is automatically loaded). + +\item[\csopt{printterms}{namecase}] Indicates whether any case +change should be applied to the entry's name field. Available +values: +\begin{description} +\item[\textsf{nochange}] Don't apply a case change. +\item[\textsf{uc}] Convert the name to uppercase. +\item[\textsf{lc}] Convert the name to lowercase. +\item[\textsf{firstuc}] Convert the first letter to uppercase (using +\ics{makefirstuc} defined in \sty{mfirstuc}). +\item[\textsf{capitalise}] Capitalise initial letters of each word +in the name (using \ics{capitalisewords} defined in \sty{mfirstuc}). +\end{description} + +\item[\csopt{printterms}{namefont}] The font changing command to +apply to the name. (Include the initial backslash.) Declarations may +be used. + +\item[\csopt{printterms}{postname}] What to put after the name. + +\item[\csopt{printterms}{see}] Indicates how the cross-reference +(given in the ``See'' field) should be displayed. Available values: +\begin{description} +\item[\textsf{comma}] Insert a comma followed by a space in front of +the cross-reference. +\item[\textsf{brackets}] Insert a space before the cross-reference +and put the cross-reference in parentheses. +\item[\textsf{dot}] Insert a full stop followed by a space in front +of the cross-reference. +\item[\textsf{space}] Insert a space before the cross-reference. +\item[\textsf{nosep}] Don't insert anything before the +cross-reference. +\item[\textsf{semicolon}] Insert a semi-colon followed by a space in +front of the cross-reference. +\item[\textsf{location}] Display the cross-reference in the same way +as a location. +\end{description} + +\item[\csopt{printterms}{child}] Indicates whether child entries +should have their name displayed. Available values: \textsf{named} +(display the child's name) and \textsf{noname} (don't display the +child's name). + +\item[\csopt{printterms}{showgroups}] Boolean option that indicates +whether or not to insert group headings (and a group separator) +between index groups, if headings are supported by the given style. +If no value is supplied, \textsf{true} is assumed. + +\item[\csopt{printterms}{style}] The style to use. The value should +be the name of the style. Available styles are listed in +\autoref{sec:indexstyles}. + +\item[\csopt{printterms}{symbolwidth}] Some of the styles allow you +to specify a width for the symbol field. This width can be specified +with this option. The value will be ignored by some of the styles. + +\item[\csopt{printterms}{locationwidth}] Some of the styles allow you +to specify a width for the location field. This width can be specified +with this option. The value will be ignored by some of the styles. + +\item[\csopt{printterms}{childsort}] A boolean option that indicates +whether or not the child entries should be sorted. If \textsf{true}, the +child entries are listed using the same sort order as the sort +applied to the database. If \textsf{false}, the child entries are +listed in the order they were defined. If the value is missing, +\textsf{true} is assumed. + +\item[\csopt{printterms}{heading}] The heading at the start of the +index/glossary. + +\item[\csopt{printterms}{postheading}] What to put immediately after +the heading. + +\item[\csopt{printterms}{sort}] How to sort the database. See +\autoref{sec:indexsort} for further details. + +\item[\csopt{printterms}{balance}] This is a boolean option that +is only applied if \csopt{printterms}{columns} is greater than~1. +If \textsf{true}, the columns are balanced. If \textsf{false}, the +columns aren't balanced. If no value is specified, \textsf{true} is +assumed. + +\item[\csopt{printterms}{condition}] This specifies a boolean +condition (as used by \ics{DTLforeach}) so you can display only +those entries where the condition is met. For example, to only +display entries starting with ``H'' (not including any entry that is +just the letter ``H'') you can do: +\begin{verbatim} +\printterms[condition={\DTLisiopenbetween{\Name}{H}{I}}] +\end{verbatim} +\end{description} + +\subsection{Index or Glossary Styles} +\label{sec:indexstyles} + +The index or glossary style is given by the +\csopt{newgidx,printterms}{style} key in the optional argument of +\ics{newgidx} or \ics{printterms}. The following styles are +available: + +\begin{description} +\item[index] +The ``index'' style is a basic style for an index. This style +accepts the \csopt{printterms}{locationwidth} and +\csopt{printterms}{symbolwidth} keys in \ics{printterms}. This is +the default style. + +\item[indexalign] +The ``indexalign'' style is similar to the ``index'' style but +aligns the descriptions. + +\item[align] +The ``align'' style aligns the fields. This style +accepts the \csopt{printterms}{locationwidth} and +\csopt{printterms}{symbolwidth} keys in \ics{printterms}. + +\item[gloss] +The ``gloss'' style is a basic glossary style. This style uses +\begin{definition}[\DescribeMacro\DTLgidxChildSep] +\cs{DTLgidxChildSep} +\end{definition} +as the separator between child entries (defaults to a space) and +\begin{definition}[\DescribeMacro\DTLgidxPostChild] +\cs{DTLgidxPostChild} +\end{definition} +to indicate what to put after the list of child entries (defaults to +nothing). + +\item[dict] +The ``dict'' style is designed for dictionary-like glossaries. This +assumes a hierarchical structure where the top level entries have a +name. The next level is used to indicate a category (such as +``adjective'' or ``noun''). If there is only one meaning for the +term, this level also has a description. If there is more than one +meaning, each meaning should be a child of the category entry. Only +third level entries are numbered. No further levels are expected. +The symbol field is ignored. + +If \csopt{printterms}{showgroups} is set, the group headers will be +placed in a \ics{chapter} (if defined) or in a \ics{section} (if +\ics{chapter} isn't defined). + +This style uses: +\begin{definition}[\DescribeMacro\DTLgidxCategoryNameFont] +\cs{DTLgidxCategoryNameFont}\marg{text} +\end{definition} +The font used to display the name of the category (first child +level). +\begin{definition}[\DescribeMacro\DTLgidxCategorySep] +\cs{DTLgidxCategorySep} +\end{definition} +The category separator. (Defaults to a space). +\begin{definition}[\DescribeMacro\DTLgidxSubCategorySep] +\cs{DTLgidxSubCategorySep} +\end{definition} +The category separator. (Defaults to a space). +\begin{definition}[\DescribeMacro\DTLgidxDictPostItem] +\cs{DTLgidxDictPostItem} +\end{definition} +Indicates what to do at the end of each top-level item. (Defaults to +\cs{par}). + +The indentation is given by the length register +\begin{definition}[\DescribeMacro\datagidxdictindent] +\cs{datagidxdictindent} +\end{definition} +This value defaults to 1em. + +\end{description} + +For additional commands that affect the style of the indexes or +glossaries, see the documented code \texttt{datatool-code.pdf}. + +\subsection{Sorting the Index or Glossary Database} +\label{sec:indexsort} + +By default the index/glossary databases are sorted according to the +\texttt{Sort} field using the \ics{dtlwordindexcompare} handler (see +\autoref{sec:sort}). Note that the \emph{entire} database is sorted, +which is less efficient that using external indexing applications, +such as \app{makeindex} or \app{xindy}, which only sort the +terms that have been used in the document. In addition, the sorting +algorithm used by \styfmt{datatool} is less efficient than that used +by a custom-built sorting and collation application. + +The database is sorted at the start of \ics{printterms} according to +the value of the \csopt{printterms}{sort} key supplied by +\ics{printterms}. To completely suppress the sorting, set this key +to empty. Example: +\begin{verbatim} +\printterms[database=index,sort={},showgroups=false] +\end{verbatim} +Note that in the above, I also switched off the group headers as +they don't make sense with an unsorted index or glossary. + +If you want to use a different comparison handler, you can set the +\csopt{printterms}{sort} key to the required sort command, where you +can use +\begin{definition}[\DescribeMacro\DTLgidxCurrentdb] +\cs{DTLgidxCurrentdb} +\end{definition} +to indicate the current database. + +For example, to sort using letter rather than word comparison: +\begin{verbatim} +\printterms[database=index, + sort={\dtlsort{Sort}{\DTLgidxCurrentdb}{\dtlletterindexcompare}}] +\end{verbatim} + +You may recall from earlier that the index/glossary databases have a +column labelled ``FirstId''. This can be used if you want to sort +the database according to the order of usage. Example: +\begin{verbatim} +\printterms[database=index, + sort={\dtlsort{FirstId}{\DTLgidxCurrentdb}{\dtlcompare}}] +\end{verbatim} +Note that here I've used the \ics{dtlcompare} handler (which is the +fastest handler) as I'm only concerned with a numerical rather than +a string comparison. + +The default value of the \csopt{printterms}{sort} key is actually: +\begin{verbatim} +\dtlsort{Sort,FirstId}{\DTLgidxCurrentdb}{\dtlwordindexcompare}} +\end{verbatim} +This means that entries with duplicate ``Sort'' fields are then +sorted according to use. + +\subsubsection{Optimization} +\label{sec:optimize} + +If you have used \app{xindy} or \app{makeindex}, you'll be +familiar with the document creation process. The document is first +compiled, then the indexing application is run to sort and collate +the entries, then the document is compiled again (and possible once +more). This involves two (or three) \LaTeX\ runs and one sort and +collate run. With the \styfmt{datagidx} package, the sorting and +collation is done every \LaTeX\ run. For a large index, this can be +quite slow. If you're not editing the index or glossary, you might +prefer not to have to keep sorting the database whenever you update +the document. To assist this, \styfmt{datagidx} provides the +\pkgopt{optimize} package option. This may take the following +values: +\begin{description} +\item[\pkgoptval{off}{optimize}] Don't use the optimize facility. +(The index/glossary databases will be sorted every run, unless the +sort is switched off by setting the \csopt{printterms}{sort} key to +empty.) + +\item[\pkgoptval{low}{optimize}] Use the ``low'' optimize setting. +This only sorts the index/glossary databases every other run. +(Assuming that the sorting is done via the \cs{printterms}{sort} key +rather than explicitly using \ics{dtlsort} or \ics{DTLsort} +somewhere else in the document.) Don't use this option if sorting +the databases makes the document out-of-date. (For example, the +group headers use sectioning commands.) + +\item[\pkgoptval{high}{optimize}] Use the ``high'' optimize setting. +This sorts the index/glossary databases on the first run, then +writes the sorted databases to external files, which are read in on +subsequent runs. Again this assumes that the sorting is done via the +\cs{printterms}{sort} key. Don't use this option if you want to edit +the index/glossary database. +\end{description} + +\section{Package Options} +\label{sec:datagidxoptions} + +The following package options are available for \styfmt{datagidx}: +\begin{description} +\item[\pkgopt{utf8}] A boolean option (same as for +\sty{datatool-base}). If you both load \sty{inputenc} with UTF-8 +support and you use accent commands like \cs{'} or \cs{c} then make +sure you have at least version 2.05 of \sty{mfirstuc} if you want to +use commands like \cs{Gls}. + +\item[\pkgopt{optimize}] Sets the optimization. (See +\autoref{sec:optimize}.) + +\item[\pkgopt{columns}] Sets the default number of columns to use +for the indexes or glossaries. (See \autoref{sec:printterms}.) + +\item[\pkgopt{child}] Sets whether or not to show the name in child +entries, where the style supports this option. (See \autoref{sec:printterms}.) + +\item[\pkgopt{namecase}] Sets the case change for the entry's name. +(See \autoref{sec:printterms}.) + +\item[\pkgopt{namefont}] Sets the font for the entry's name. +(See \autoref{sec:printterms}.) + +\item[\pkgopt{postname}] Indicates what to put after the entry's name. +(See \autoref{sec:printterms}.) + +\item[\pkgopt{postdesc}] Indicates what to put after the entry's +description. (See \autoref{sec:printterms}.) + +\item[\pkgopt{prelocation}] Indicates what to put before the entry's +location. (See \autoref{sec:printterms}.) + +\item[\pkgopt{location}] Indicates how to display the entry's +location. (See \autoref{sec:printterms}.) + +\item[\pkgopt{see}] Indicates how to display the entry's +cross-reference list. (See \autoref{sec:printterms}.) + +\item[\pkgopt{symboldesc}] Indicates how to display the entry's +symbol in relation to the description. (See \autoref{sec:printterms}.) + +\item[\pkgopt{compositor}] Sets the location compositor. (See +\autoref{sec:locations}.) + +\item[\pkgopt{draft}] Displays additional information, such as +target names. + +\item[\pkgopt{final}] Hides the draft information. + +\item[\pkgopt{verbose}] Use \sty{datatool}'s verbose mode. + +\item[\pkgopt{nowarn}] A boolean option that suppresses +\sty{datagidx}'s rerun warnings. + +\end{description} + +\begin{example}{Creating an Index}{ex:index} +In this document, I have used the \sty{datagidx} package and the +\sty{hyperref} package. In the preamble, I have the following: +\begin{verbatim} +\usepackage{datagidx} +\usepackage[colorlinks]{hyperref} + +\newgidx{index}{Index}% define a database for the index + +\DTLgidxSetDefaultDB{index}% set this as the default + +\newterm{mac\'edoine} +\newterm{macram\'e} +\newterm[label=elite]{{\'e}lite} +\newterm{reptile} +\newterm[seealso={reptile}]{crocodylian} + +\newterm + [% + parent=crocodylian + ] + {crocodile} + +\newterm + [% + parent=crocodylian + ] + {alligator} + +\newterm + [% + parent=crocodylian, + description={(also cayman)} + ] + {caiman} + +\newterm[see={caiman}]{cayman} +\end{verbatim} + +Now here's some code to go in the document: +\begin{verbatim} +Here are some words containing accents: \gls{macedoine}, +\gls{macrame} and \gls{elite}. \Gls{elite} requires extra care as it +starts with an accented letter. A \gls{crocodylian} is a family of +\glspl{reptile} consisting of \glspl{crocodile}, \glspl{alligator} and +\glspl{caiman}. +\end{verbatim} +This produces the following: + +Here are some words containing accents: \gls{macedoine}, +\gls{macrame} and \gls{elite}. \Gls{elite} requires extra care as it +starts with an accented letter. A \gls{crocodylian} is a family of +\glspl{reptile} consisting of \glspl{crocodile}, \glspl{alligator} and +\glspl{caiman}. + +The index can then be displayed using: +\begin{verbatim} +\printterms[heading={\section*},database=index] +\end{verbatim} +This requires two runs to ensure the index is up-to-date. The +resulting index is as follows: + +\printterms + [ + heading={\section*}, + database={gidx-index} + ] + +\par\vskip\baselineskip\noindent +Here's the code if you want to add the letter groups (I've also +added a dotted line before the location): +\begin{verbatim} +\printterms + [ + heading={\section*}, + database=index, + prelocation=dotfill, + showgroups + ] +\end{verbatim} +which produces: +\printterms + [ + heading={\section*}, + database=gidx-index, + prelocation=dotfill, + showgroups + ] + +\end{example} + +\chapter{Pie Charts (\texorpdfstring{\sty{datapie}}{datapie} package)} +\label{sec:datapie} + +The \sty{datapie} package is not loaded by the \sty{datatool} package, +so you need to explicitly load \sty{datapie} if you want to use any of the +commands defined in this section. You will also need to have the +\sty{pgf}/\sty{tikz} packages installed. The \sty{datapie} package +may be given the following options: +\begin{description} +\item[{\pkgopt{color}}] Colour option (default). +\item[{\pkgopt{gray}}] Grey scale option. +\item[{\pkgopt{rotateinner}}] +Rotate inner labels so that they are aligned +with the pie chart radial axis. +\item[{\pkgopt{norotateinner}}] +Don't rotate inner labels (default). +\item[{\pkgopt{rotateouter}}] +Rotate outer labels so that they are aligned +with the pie chart radial axis. +\item[{\pkgopt{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 +\begin{definition}[\DescribeMacro{\DTLpiechart}]% +\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[\csopt{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[\csopt{DTLpiechart}{start}] +This is the starting angle of the first segment. The +value is 0 by default. + +\item[\csopt{DTLpiechart}{radius}] +This is the radius of the pie chart. The default value +is 2cm. + +\item[\csopt{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 radius. The default value is 0.5. + +\item[\csopt{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 radius. The default value is 1.25. + +\item[\csopt{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 radius. The default value is 0.2. + +\item[\csopt{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 \csopt{DTLpiechart}{innerratio} +and \csopt{DTLpiechart}{inneroffset}, not both. If you also want to +specify the radius, you must use \csopt{DTLpiechart}{radius} +before \csopt{DTLpiechart}{inneroffset}. If omitted, the inner +offset is obtained from the radius multiplied by the +\csopt{DTLpiechart}{innerratio} value. + +\item[\csopt{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 \csopt{DTLpiechart}{outerratio} +and \csopt{DTLpiechart}{outeroffset}, not both. If you also want to +specify the radius, you must use \csopt{DTLpiechart}{radius} +before \csopt{DTLpiechart}{outeroffset}. If omitted, the outer +offset is obtained from the radius multiplied by the +\csopt{DTLpiechart}{outerratio} value. + +\item[\csopt{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 \csopt{DTLpiechart}{cutawayratio} and +\csopt{DTLpiechart}{cutawayoffset}, not both. If +you also want to specify the radius, you must use +\csopt{DTLpiechart}{ratio} before +\csopt{DTLpiechart}{cutawayoffset}. If omitted, the cutaway offset +is obtained from the ratio multiplied by the +\csopt{DTLpiechart}{cutawayratio} value. + +\item[\csopt{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 \csopt{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[\csopt{DTLpiechart}{innerlabel}] +The value of this is positioned in the middle of each segment at a +distance of \csopt{DTLpiechart}{inneroffset} from the centre +of the pie chart. The default is the same as the value of +\csopt{DTLpiechart}{variable}. + +\item[\csopt{DTLpiechart}{outerlabel}] +The value of this is positioned at a distance of +\csopt{DTLpiechart}{outeroffset} from the centre of the pie chart. +The default is empty. + +\item[\csopt{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{rotateinner} and \pkgopt{norotateinner}. + +\item[\csopt{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{rotateouter} and \pkgopt{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}. The colours used are the +defaults. See \autoref{ex:piecolours} for an example that changes +the default colours. + +\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 \csopt{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 +\csopt{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} + +\section{Pie Chart Variables} + +\begin{definition}[\DescribeMacro{\DTLpievariable}]% +\cs{DTLpievariable} +\end{definition} +This command is set to the variable given by the +\csopt{DTLpiechart}{variable} setting in the \meta{settings list} +argument of \cs{DTLpiechart}. The \csopt{DTLpiechart}{innerlabel} +is set to \cs{DTLpievariable} by default. + +\begin{definition}[\DescribeMacro{\DTLpiepercent}]% +\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 +\desctr{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} + +\section{Pie Chart Label Formatting} + +\begin{definition}[\DescribeMacro{\DTLdisplayinnerlabel}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLdisplayouterlabel}]% +\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} + +\section{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 or if you want to change the default colours, you +will need to use +\begin{definition}[\DescribeMacro{\DTLsetpiesegmentcolor}]% +\cs{DTLsetpiesegmentcolor}\marg{n}\marg{color} +\end{definition}\noindent +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}. + +It is a good idea to set the colours so that each segment colour +is somehow relevant to whatever the segment represents. For +example, in the previous examples of pie charts depicting fruit, +some of default colours were inappropriate. Whilst red is +appropriate for apples and green is appropriate for pears, blue +doesn't really correspond to lemons or limes. + +\begin{definition}[\DescribeMacro{\DTLdopiesegmentcolor}]% +\cs{DTLdopiesegmentcolor}\marg{n} +\end{definition} +This sets the current text colour to that of the \meta{n}th +segment. + +\begin{definition}[\DescribeMacro{\DTLdocurrentpiesegmentcolor}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLpieoutlinecolor}]% +\cs{DTLpieoutlinecolor} +\end{definition} +This sets the outline colour for the pie chart. The default is +black. + +\begin{definition}[\DescribeMacro{\DTLpieoutlinewidth}]% +\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. The third segment (lemons and +limes) is set to yellow and the fourth segment (peaches) is set +to pink. In addition, a legend is created using \ics{DTLforeach}. +\begin{verbatim} +\begin{figure}[htbp] +\centering +\setlength{\DTLpieoutlinewidth}{2pt} +\DTLsetpiesegmentcolor{3}{yellow} +\DTLsetpiesegmentcolor{4}{pink} +\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 \csopt{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} +\DTLsetpiesegmentcolor{3}{yellow} +\DTLsetpiesegmentcolor{4}{pink} +\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} + +\section{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). + +\begin{definition}[\DescribeMacro{\DTLpieatbegintikz}]% +\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 (but be careful not to distort the chart). + +\begin{definition}[\DescribeMacro{\DTLpieatendtikz}]% +\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 +\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} +\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} + +\chapter{Scatter and Line Plots (\texorpdfstring{\sty{dataplot}}{dataplot} +package)} +\label{sec:dataplot} + +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}". + + +\begin{definition}[\DescribeMacro{\DTLplot}]% +\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 \csopt{DTLplot}{x} and \csopt{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 \csopt{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[\csopt{DTLplot}{x}] The database key +that specifies the $x$ co-ordinates. This setting is required. + +\item[\csopt{DTLplot}{y}] The database key that specifies +the $y$ co-ordinates. This setting is required. + +\item[\csopt{DTLplot}{markcolors}] A comma separated list of colour +names for the markers. An empty value will use the current colour. + +\item[\csopt{DTLplot}{linecolors}] A comma separated list of colour +names for the plot lines. An empty value will use the current colour. + +\item[\csopt{DTLplot}{colors}] A comma separated list of colour +names for the lines and markers. + +\item[\csopt{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[\csopt{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[\csopt{DTLplot}{width}] The width of the plot. This must +be a length. The plot width does not include outer tick marks or +labels. + +\item[\csopt{DTLplot}{height}] The height of the plot. This must +be a length. The plot height does not include outer tick marks +or labels. + +\item[\csopt{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[\csopt{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[\csopt{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[\csopt{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 \csopt{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[\csopt{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 \csopt{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[\csopt{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[\csopt{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[\csopt{DTLplot}{xticdir}] This sets the $x$ tick direction, +and may only take the values "in" or "out". + +\item[\csopt{DTLplot}{yticdir}] This sets the $y$ tick direction, +and may only take the values "in" or "out". + +\item[\csopt{DTLplot}{ticdir}] This sets the $x$ and $y$ tick +direction, and may only take the values "in" or "out". + +\item[\csopt{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 \csopt{DTLplot}{bounds} setting overrides +the \csopt{DTLplot}{minx}, \csopt{DTLplot}{maxx}, +\csopt{DTLplot}{miny} and \csopt{DTLplot}{maxy} settings. + +\item[\csopt{DTLplot}{minx}] The value is the minimum value +of the $x$ axis. + +\item[\csopt{DTLplot}{miny}] The value is the minimum value +of the $y$ axis. + +\item[\csopt{DTLplot}{maxx}] The value is the maximum value +of the $x$ axis. + +\item[\csopt{DTLplot}{maxy}] The value is the maximum value +of the $y$ axis. + +\item[\csopt{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 \csopt{DTLplot}{xticgap}. + +\item[\csopt{DTLplot}{xticgap}] This value specifies the +gap between the $x$ tick marks. + +\item[\csopt{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 \csopt{DTLplot}{yticgap}. + +\item[\csopt{DTLplot}{yticgap}] This value specifies the +gap between the $y$ tick marks. + +\item[\csopt{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[\csopt{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 \ctr{DTLplotroundXvar}. + +\item[\csopt{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 \ctr{DTLplotroundYvar}. + +\item[\csopt{DTLplot}{xlabel}] The value is the label for +the $x$ axis. If omitted, the axis has no label. + +\item[\csopt{DTLplot}{ylabel}] The value is the label for +the $y$ axis. If omitted, the axis has no label. + +\item[\csopt{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[\csopt{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.54}\relax +\DTLnewdbentry{groupa}{Weight}{48.0}\relax +\DTLnewrow{groupa}\relax +\DTLnewdbentry{groupa}{Height}{1.55}\relax +\DTLnewdbentry{groupa}{Weight}{45.4}\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 \csopt{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 (multiple datasets)]{A scatter plot} +\label{fig:2db} +\end{figure} + +Now let's add a legend using the \csopt{DTLplot}{legend} setting, +with the legend labels "Group A" and "Group B", +and set the $x$ tick intervals using \csopt{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 (with a legend)]{A scatter plot} +\label{fig:legend} +\end{figure} +\end{example} + +\section{Adding Information to the Plot} + +The \sty{datatool} package provides two hooks used at the beginning +and end of the \env{tikzpicture} environment: +\begin{definition}[\DescribeMacro{\DTLplotatbegintikz}]% +\cs{DTLplotatbegintikz} +\end{definition}\noindent +and +\begin{definition}[\DescribeMacro{\DTLplotatendtikz}]% +\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. However, to reduce the problem of exceeding \TeX's +maximum dimension, \cs{DTLplot} scales the plot which may distort +plot marks. To get around this use +\begin{definition}[\DescribeMacro{\dtlplothandlermark}] +\cs{dtlplothandlermark}\marg{pgf code} +\end{definition} +instead of \ics{pgfplothandlermark}\marg{pgf code}. (See +\autoref{ex:multikey}.) Note that \cs{dtlplothandlermark} is only +intended for use within the definition of \cs{DTLplotatbegintikz} or +\cs{DTLplotatendtikz}. If used elsewhere it will produce a warning +and act as though you'd just used \cs{pgfplothandlermark}. + +\begin{definition}[\DescribeMacro{\DTLaddtoplotlegend}]% +\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}. +(Obviously, \cs{DTLplotatendtikz} needs to be redefined before +using \cs{DTLplot}.) + +\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 (using the end plot hook to annotate the +plot)]{A scatter plot} + +\label{fig:annote} +\end{figure} +\end{example} + +\section{Global Plot Settings} + +\subsection{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}. + +\begin{definition}[\DescribeMacro{\DTLplotwidth}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLplotheight}]% +\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 + +\begin{definition}[\DescribeMacro{\DTLticklength}]% +\cs{DTLticklength} +\end{definition} +This governs the length of the tick marks. The default value is +5pt. + +\begin{definition}[\DescribeMacro{\DTLminorticklength}]% +\cs{DTLminorticklength} +\end{definition} +This governs the length of the minor tick marks. The default value is +2pt. + +\begin{definition}[\DescribeMacro{\DTLticklabeloffset}]% +\cs{DTLticklabeloffset} +\end{definition} +This governs the distance from the axis to the tick labels. The +default value is 8pt. + +\begin{definition}[\DescribeMacro{\DTLmintickgap}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLlegendxoffset}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLlegendyoffset}]% +\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. + +\subsection{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}[\DescribeCounter{DTLplotroundXvar}] +\ctrfmt{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 +\ctrfmt{DTLplotroundXvar}. + +\begin{definition}[\DescribeCounter{DTLplotroundYvar}] +\ctrfmt{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 +\ctrfmt{DTLplotroundYvar}. + +\subsection{Macros} +These macros govern the appearance of plots created using +\ics{DTLplot}. They can be changed using \cs{renewcommand}. + +\begin{definition}[\DescribeMacro{\DTLplotmarks}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLplotmarkcolors}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLplotlines}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLplotlinecolors}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLXAxisStyle}]% +\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} + +\begin{definition}[\DescribeMacro{\DTLYAxisStyle}]% +\cs{DTLYAxisStyle} +\end{definition} +This governs the style of the $y$ axis. It is analogous to +\cs{DTLXAxisStyle} described above. + +\begin{definition}[\DescribeMacro{\DTLmajorgridstyle}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLminorgridstyle}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLformatlegend}]% +\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. + +\section{Adding to a Plot Stream} + +\begin{definition}[\DescribeMacro{\DTLplotstream}]% +\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 + % compute 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 to 1 d.p. +\setcounter{DTLplotroundXvar}{1} + % redefine \DTLplotatbegintikz to plot the data for Experiment 1 +\renewcommand*{\DTLplotatbegintikz}{% + % set plot mark + \dtlplothandlermark{\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, however I've had to use +\ics{dtlplothandlermark} instead of \ics{pgfplothandlermark} +to prevent the plot marks from being distorted. +\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}{1} +\renewcommand*{\DTLplotatbegintikz}{% +\dtlplothandlermark{\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 (plotting from the same database using +different keys)]{Time to growth data} +\label{fig:multikey} +\end{figure} +\end{example} + +\chapter{Bar Charts (\texorpdfstring{\sty{databar}}{databar} +package)} +\label{sec:databar} + +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}". You must also have the \sty{pgf} package +installed. + +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{color}}] Created coloured bar charts +(default). + +\item[{\pkgopt{gray}}] Created grey scale bar charts. + +\item[{\pkgopt{vertical}}] Created vertical bar charts +(default). + +\item[{\pkgopt{horizontal}}] Created horizontal bar charts. +\end{description} + + + +\begin{definition}[\DescribeMacro{\DTLbarchart}]% +\cs{DTLbarchart}\oarg{condition}\marg{settings}\marg{db name}\marg{values} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLmultibarchart}]% +\cs{DTLmultibarchart}\oarg{condition}\marg{settings}\marg{db name}\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 \csopt{DTLbarchart}{variable} setting is +required for \cs{DTLbarchart} and the +\csopt{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[\csopt{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[\csopt{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[\csopt{DTLbarchart,DTLmultibarchart}{max}] +This specifies the maximum value on the $y$ axis. (This should +be a standard decimal value.) + +\item[\csopt{DTLbarchart,DTLmultibarchart}{length}] +This specifies the overall length of the $y$ axis, and must +be a dimension. + +\item[\csopt{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[\csopt{DTLbarchart,DTLmultibarchart}{axes}] +This setting specifies which axes to display. This may take one +of the following values: "both", "x", "y" or "none". + +\item[\csopt{DTLbarchart,DTLmultibarchart}{barlabel}] +This setting specifies the lower bar label. When used with +\cs{DTLmultibarchart} it indicates the group label. + +\item[\csopt{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[\csopt{DTLbarchart}{upperbarlabel}] +This setting specifies the upper bar label. This setting +is not available for \cs{DTLmultibarchart}. + +\item[\csopt{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[\csopt{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 \csopt{DTLbarchart}{yticgap}. + +\item[\csopt{DTLbarchart,DTLmultibarchart}{yticgap}] +This specifies the gap between the $y$ tick marks. (This should +be a standard decimal value.) + +\item[\csopt{DTLbarchart,DTLmultibarchart}{yticlabels}] +This must be a comma separated list of tick labels for the +$y$ axis. + +\item[\csopt{DTLbarchart,DTLmultibarchart}{ylabel}] +This specifies the label for the $y$ axis. + +\item[\csopt{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[\csopt{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} + +\section{Changing the Appearance of a Bar Chart} + + +\begin{definition}[\DescribeMacro{\DTLbarchartlength}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLbarwidth}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLbarlabeloffset}]% +\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}[\DescribeCounter{DTLbarroundvar}] +\ctrfmt{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 \ctrfmt{DTLbarroundvar}. You must use \cs{setcounter} +to change this value. + +\begin{definition}[\DescribeMacro{\DTLsetbarcolor}]% +\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. +It is recommended that you set the colour of each bar to +correspond with whatever the bar represents. + +\begin{definition}[\DescribeMacro{\DTLdobarcolor}]% +\cs{DTLdobarcolor}\marg{n} +\end{definition} +This sets the current colour to the colour of the \meta{n}th bar. + +\begin{definition}[\DescribeMacro{\DTLbaroutlinecolor}]% +\cs{DTLbaroutlinecolor} +\end{definition} +This macro contains the colour of the bar outlines. This defaults +to "black". + +\begin{definition}[\DescribeMacro{\DTLbaroutlinewidth}]% +\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. + + +\begin{definition}[\DescribeMacro{\DTLbaratbegintikz}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLbaratendtikz}]% +\cs{DTLbaratendtikz} +\end{definition} +This specifies any additional commands to add to the end of +the plot. It defaults to nothing. + +\begin{definition}[\DescribeMacro{\DTLeverybarhook}]% +\cs{DTLeverybarhook} +\end{definition} +The specifies code to apply at every bar. Within the definition +of \cs{DTLeverybarhook} you can use the commands +\DescribeMacro{\DTLstartpt}\cs{DTLstartpt} (the start +of the bar), \DescribeMacro{\DTLmidpt}\cs{DTLmidpt} +(the mid point of the bar) and +\DescribeMacro{\DTLendpt}\cs{DTLendpt} (the end of the bar). For +example (using the earlier "fruit" database): +\begin{verbatim} +\renewcommand*{\DTLeverybarhook}{% +\pgftext[at=\DTLmidpt]{\insertName\space(\insertValue)}% +} +\DTLbarchart{variable=\insertValue,axes=both, +ylabel=Quantity,max=50,verticalbars=false +}% +{fruit}{\insertValue=Value,\insertName=Name} +\end{verbatim} +This puts the name followed by the quantity in brackets in the +middle of the bar. + +\begin{definition}[\DescribeMacro{\ifDTLverticalbars}]% +\cs{ifDTLverticalbars} +\end{definition} +This conditional governs whether the chart uses vertical or +horizontal bars. + +\begin{definition}[\DescribeMacro{\DTLbarXlabelalign}]% +\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{vertical} +package option or the \csopt{DTLbarchart}{verticalbars} setting, +and defaults to "right" if you use the \pkgopt{horizontal} +package option or the \csopt{DTLbarchart}{verticalbars}"=false" +setting. + +\begin{definition}[\DescribeMacro{\DTLbarYticklabelalign}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLbardisplayYticklabel}]% +\cs{DTLbardisplayYticklabel}\marg{text} +\end{definition} +This specifies how to display the $y$ tick label. The argument +is the tick label. + +\begin{definition}[\DescribeMacro{\DTLdisplaylowerbarlabel}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLdisplaylowermultibarlabel}]% +\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}. + +\begin{definition}[\DescribeMacro{\DTLdisplayupperbarlabel}]% +\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. + +\begin{definition}[\DescribeMacro{\DTLdisplayuppermultibarlabel}]% +\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}{A 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 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 (labelled)]{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}: +\begin{definition}[\DescribeMacro{\DTLbarchartwidth}]% +\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 +\csopt{DTLmultibarchart}{variables}) setting and $g$ is the +group gap (as specified by the \csopt{DTLmultibarchart}{groupgap} setting). + +\begin{definition}[\DescribeMacro{\DTLnegextent}]% +\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 +\csopt{DTLbarchart,DTLmultibarchart}{maxdepth} setting.) + +\begin{definition}[\DescribeMacro{\DTLbarmax}]% +\cs{DTLbarmax} +\end{definition} +This is set to the maximum extent of the bar chart. (This value +corresponds to the +\csopt{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 (a horizontal bar chart)]{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 (a multi-bar chart)]{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} + \begin{figure}[htbp] + \centering + % compute the overall mean + \DTLmeanforkeys{marks}{Average}{\overallmean} + % round it to 2 decimal places + \DTLround{\overallmean}{\overallmean}{2} + % draw a grey dotted line indicating the overall mean + % covering the entire width of the bar chart + \renewcommand*{\DTLbaratendtikz}{% + \draw[lightgray,loosely dotted] (0,\overallmean) -- + (\DTLbarchartwidth,\overallmean) + node[right,black]{Average (\overallmean)};} + % Set the lower bar labels to draw a brace across the current + % group, along with the student's name and average score + \renewcommand*{\DTLdisplaylowerbarlabel}[1]{% + \tikz[baseline=(current bounding box.center)]{ + \draw[snake=brace,rotate=-90](0,0) -- (\DTLbargroupwidth,0);} + \DTLround{\theMean}{\theMean}{2}% + \shortstack{#1\\(Average: \theMean)}} + % draw the bar chart + \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} + \end{figure} +\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 (annotating a bar chart)]{Student marks} +\label{fig:multibarmean} +\end{figure} + +\end{example} + +\chapter{Converting a \texorpdfstring{\BibTeX}{BibTeX} database +into a \texorpdfstring{\sty{datatool}}{datatool} database +(\texorpdfstring{\sty{databib}}{databib} package)} +\label{sec:databib} + +The \sty{databib} package provides the means of converting a \BibTeX\ +database into a \sty{datatool} database. The database can then be +sorted using \cs{DTLsort}, described in \autoref{sec:sort}. +For example, you may want to sort the bibliography in +reverse chronological order. Once you have sorted the bibliography, +you can display it using \cs{DTLbibliography}, described in +\autoref{sec:thebib}, or you can iterate through the database +using \cs{DTLforeachbibentry}, described in \autoref{sec:foreachbib}. + +Note that the \sty{databib} +package is not automatically loaded by \sty{datatool}, so if +you want to use it, you must load it using +"\usepackage{databib}". + +\begin{important} +The purpose of this package is to provide a means for +authors to format their own bibliography style where there is no +bibliography style file available that produces the desired results. +The \cs{DTLsort} macro uses a much less efficient sorting algorithm +than \BibTeX, and loading the bibliography as a \sty{datatool} +database is much slower than loading a standard \filetype{bbl} file. If +you have a large database, and you are worried that \LaTeX\ may have +become stuck, try using the \pkgopt{verbose} option to \sty{datatool} +or use the command \cs{dtlverbosetrue}. This will print informative +messages to the console and transcript file, to let you know what's +going on. +\end{important} + +\section{\texorpdfstring{\BibTeX}{BibTeX}: An Overview} +\label{sec:bibtex} +This document assumes that you have at least some passing +familiarity with \BibTeX, but here follows a brief refresher. + +\BibTeX\ is an external application used in conjunction with \LaTeX. +When you run \BibTeX, you need to specify the name of the document's +auxiliary file (without the \filetype{aux} extension). \BibTeX\ then reads +this file and looks for the commands \cs{bibstyle} (which indicates +which bibliography style (\filetype{bst}) file to load), \cs{bibdata} +(which indicates which bibliography database (\filetype{bib}) files to +load) and \cs{citation} (produced by \cs{cite} and \cs{nocite}, which +indicates which entries should be included in the bibliography). +\BibTeX\ then creates a file with the extension \filetype{bbl} which +contains the bibliography, formatted according to the layout defined +in the bibliography style file. + +In general, given a document called, say, \texttt{mydoc.tex}, you +will have to perform the following steps to ensure that the +bibliography and all citations are up-to-date: +\begin{enumerate} +\item +\begin{verbatim} +latex mydoc +\end{verbatim} +This writes the citation information to the auxiliary file. +The bibliography currently doesn't exists, so it isn't displayed. +Citations will appear in the document as ?? since the internal +cross-references don't exist yet. + +\item +\begin{verbatim} +bibtex mydoc +\end{verbatim} +This reads the auxiliary file, and creates a file with the extension +\filetype{bbl} which typically contains the typeset bibliography. + +\item +\begin{verbatim} +latex mydoc +\end{verbatim} +Now that the \filetype{bbl} file exists, the bibliography can be input +into the document. The internal cross-referencing information for the +bibliography can now be written to the auxiliary file. + +\item +\begin{verbatim} +latex mydoc +\end{verbatim} +The cross-referencing information can be read from the auxiliary +file. +\end{enumerate} + +\subsection{\texorpdfstring{\BibTeX}{BibTeX} database} + +The bibliographic data required by \BibTeX\ must be stored in +a file with the extension \filetype{bib}, where each entry is stored +in the form:\par\vskip\baselineskip\noindent +{\obeylines +\noindent\texttt{@}\meta{entry\_type}\verb|{|\meta{cite\_key}\texttt, + \meta{field\_name} \texttt{=} \char`\"\meta{value}\char`\"\texttt, + \mbox{}\vdots + \meta{field\_name} \texttt{=} \char`\"\meta{value}\char`\" +\noindent\verb|}| +} +\par\vskip\baselineskip\noindent +Note that curly braces "{" and "}" may be used instead of \verb|"| +and \verb|"|. + +The entry type, given by \meta{entry\_type} above, indicates +the type of document. This may be one of: "article", "book", +"booklet", "inbook", "incollection", "inproceedings"\footnote +{Note that \texttt{conference} is a synonym for \texttt{inproceedings}.}, +"manual", +"mastersthesis", "misc", "phdthesis", "proceedings", \linebreak +"techreport" or "unpublished". + +The \meta{cite\_key} above is a unique label identifying this +entry, and is the label used in the argument of \cs{cite} or +\cs{nocite}. The available fields depends on the entry type, for +example, the field "journal" is required for the "article" entry +type, but is ignored for the "inproceedings" entry type. The standard +fields are: "address", "author", "booktitle", "chapter", "edition", +"editor", "howpublished", "institution", "journal", "key", "month", +"note", "number", "organization", "pages", "publisher", "school", +"series", "title", "type", "volume" and "year". + +Author and editor names must be entered in one of the following +ways: +\begin{enumerate} +\item \meta{First names} \meta{von part} \meta{Surname}, \meta{Jr part} + +The \meta{von part} is optional and is identified by the name(s) +starting with lowercase letters. The final comma followed by +\meta{Jr part} is also optional. Examples: +\begin{verbatim} +author = "Henry James de Vere" +\end{verbatim} +In the above, the first names are Henry James, the ``von part'' is +de and the surname is Vere. There is no ``junior part''. +\begin{verbatim} +author = "Mary-Jane Brown, Jr" +\end{verbatim} +In the above, the first name is Mary-Jane, there is no von part, +the surname is Brown and the junior part is Jr. +\begin{verbatim} +author = "Peter {Murphy Allen}" +\end{verbatim} +In the above, the first name is Peter, and the surname is Murphy +Allen. Note that in this case, the surname must be grouped, otherwise +Murphy would be considered part of the forename. +\begin{verbatim} +author = "Maria Eliza {\uppercase{d}e La} Cruz" +\end{verbatim} +In the above, the first name is Maria Eliza, the von part is +De La, and the surname is Cruz. In this case, the von part starts +with an uppercase letter, but specifying +\begin{verbatim} +author = "Maria Eliza De La Cruz" +\end{verbatim} +would make \BibTeX\ incorrectly classify ``Maria Eliza De La'' as +the first names, and the von part would be empty. Since \BibTeX\ +doesn't understand \LaTeX\ commands, using "{\uppercase{d}e La}" +will trick \BibTeX\ into thinking that it starts with a lower +case letter. + +\item \meta{von part} \meta{Surname}, \meta{Forenames} + +Again the \meta{von part} is optional, and is determined by the +case of the first letter. For example: +\begin{verbatim} +author = "de Vere, Henry James" +\end{verbatim} +\end{enumerate} + +Multiple authors or editors should be separated by the key word +"and", for example: +\begin{verbatim} +author = "Michel Goossens and Frank Mittlebach and Alexander Samarin" +\end{verbatim} + +Below is an example of a book entry: +\begin{verbatim} +@book{latexcomp, + title = "The \LaTeX\ Companion", + author = "Michel Goossens and Frank Mittlebach and + Alexander Samarin", + publisher = "Addison-Wesley", + year = 1994 +} +\end{verbatim} +Note that numbers may be entered without delimiters, as in "year = 1994". +There are also some predefined strings, including those for the month +names. You should always use these strings instead of the actual +month name, as the way the month name is displayed depends on the +bibliography style. For example: +\begin{verbatim} +@article{Cawley2007b, +author = "Gavin C. Cawley and Nicola L. C. Talbot", +title = "Preventing over-fitting in model selection via {B}ayesian + regularisation of the hyper-parameters", +journal = "Journal of Machine Learning Research", +volume = 8, +pages = "841--861", +month = APR, +year = 2007 +} +\end{verbatim} + +You can concatenate strings using the "#" character, for example: +\begin{verbatim} +month = JUL # "~31~--~" # AUG # "~4", +\end{verbatim} +Depending on the bibliography style, this may be displayed as: +July~31~--~August~4, or it may be displayed as: +Jul~31~--~Aug~4. For further information, see~\cite{Goossens}. + +\section{Loading a \texorpdfstring{\sty{databib}}{databib} +database} +\label{sec:loadbbl} + +The \sty{databib} package always requires the \texttt{databib.bst} +bibliography style file (which is supplied with this bundle). +You need to use \cs{cite} or \cs{nocite} as usual. If you want to +add all entries in the \filetype{bib} file to the \sty{datatool} database, +you can use "\nocite{*}". + +\begin{definition}[\DescribeMacro{\DTLloadbbl}]% +\cs{DTLloadbbl}\oarg{bbl name}\marg{db name}\marg{bib list} +\end{definition} +This command performs several functions: + +\begin{enumerate} +\item it writes the following line in the auxiliary file: +\begin{verbatim} +\bibstyle{databib} +\end{verbatim} +which tells \BibTeX\ to use the \texttt{databib.bst} +\BibTeX\ style file, + +\item it writes \cs{bibdata}\marg{bib list} to the +auxiliary file, which tells \BibTeX\ which \filetype{bib} files to use, + +\item it creates a \sty{datatool} database called \meta{db name}, + +\item it loads the file \meta{bbl name} if it exists. (The value +defaults to \cs{jobname}".bbl", which is the usual name for +a \filetype{bbl} file.) If the \filetype{bbl} file doesn't exist, the +database \meta{db name} will remain empty. +\end{enumerate} + +You then need to run your document through \LaTeX\ (or PDF\LaTeX) +and then run \BibTeX\ on the auxiliary file, as described in +\autoref{sec:bibtex}. This will create a \filetype{bbl} file which +contains all the commands required to add the bibliography information +to the \sty{datatool} database called \meta{db name}. The next +time you \LaTeX\ your document, this file will be read, and the +information will be added to \meta{db name}. + +\begin{important} +Note that \cs{DTLloadbbl} doesn't generate any text. Once you have +loaded the data, you can display the bibliography uses +\cs{DTLbibliography} (described below) or you can iterate through it +using \cs{DTLforeachbibentry} described in \autoref{sec:foreachbib}. +\end{important} + +Note that the \texttt{databib.bst} \BibTeX\ style file provides +the following additional fields: "isbn", "doi", "pubmed", "url" +and "abstract". +However these fields are ignored by the three predefined +\sty{databib} styles ("plain", "abbrv" and "alpha"). If you +want these fields to be displayed in the bibliography you will +need to modify the bibliography style (see \autoref{sec:modbibstyle}). + +\section{Displaying a \texorpdfstring{\sty{databib}}{databib} +database} +\label{sec:thebib} + +A \sty{databib} database which has been loaded using +\cs{DTLloadbbl} (described in \autoref{sec:loadbbl}) can be +displayed using: +\begin{definition}[\DescribeMacro{\DTLbibliography}] +\cs{DTLbibliography}\oarg{conditions}\marg{db name} +\end{definition}\noindent +where \meta{db name} is the name of the database. + +Within the optional argument \meta{condition}, you may use any of the +commands that may be used within the optional argument of +\cs{DTLforeach} \emph{In addition}, you may use the following +commands: + +\begin{definition}[\DescribeMacro{\DTLbibfieldexists}]% +\cs{DTLbibfieldexists}\marg{field label} +\end{definition} +This tests whether the field with the given label exists for the +current entry. +The field label may be one of: "Address", "Author", +"BookTitle", "Chapter", "Edition", "Editor", "HowPublished", +"Institution", "Journal", "Key", "Month", "Note", "Number", +"Organization", "Pages", "Publisher", "School", "Series", +"Title", "Type", "Volume", "Year", "ISBN", "DOI", "PubMed", +"Abstract", "Url" or "Eprints". + +For example, suppose you have loaded a \sty{databib} database +called "mybib" using \cs{DTLloadbbl} (described in +\autoref{sec:loadbbl}) then the following bibliography will only +include those entries which have a "Year" field: +\begin{verbatim} +\DTLbibliography[\DTLbibfieldexists{Year}]{mybib} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLbibfieldiseq}]% +\cs{DTLbibfieldiseq}\marg{field label}\marg{value} +\end{definition} +This tests whether the value of the field given by +\meta{field label} equals \meta{value}. If the field doesn't +exist for the current entry, this evaluates to false. +For example, the following will produce a bibliography which +only contains entries which have the "Year" field set to 2004: +\begin{verbatim} +\DTLbibliography[\DTLbibfieldiseq{Year}{2004}]{mybib} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLbibfieldcontains}]% +\cs{DTLbibfieldcontains}\marg{field label}\marg{sub string} +\end{definition} +This tests whether the value of the field given by \meta{field label} +contains \meta{sub string}. For example, the following will produce +a bibliography which only contains entries where the author field +contains the name "Knuth": +\begin{verbatim} +\DTLbibliography[\DTLbibfieldcontains{Author}{Knuth}]{mybib} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLbibfieldislt}]% +\cs{DTLbibfieldislt}\marg{field label}\marg{value} +\end{definition} +This tests whether the value of the field given by \meta{field label} +is less than \meta{value}. If the field doesn't exist for the +current entry, this evaluates to false. +For example, the following will produce a bibliography which only +contains entries whose "Year" field is less than 1983: +\begin{verbatim} +\DTLbibliography[\DTLbibfieldislt{Year}{1983}]{mybib} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLbibfieldisle}]% +\cs{DTLbibfieldisle}\marg{field label}\marg{value} +\end{definition} +This tests whether the value of the field given by \meta{field label} +is less than or equal to \meta{value}. If the field doesn't exist +for the current entry, this evaluates to false. +For example, the following will produce a bibliography which only +contains entries whose "Year" field is less than or equal to 1983: +\begin{verbatim} +\DTLbibliography[\DTLbibfieldisle{Year}{1983}]{mybib} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLbibfieldisgt}]% +\cs{DTLbibfieldisgt}\marg{field label}\marg{value} +\end{definition} +This tests whether the value of the field given by \meta{field label} +is greater than \meta{value}. If the field doesn't exist for the +current entry, this evaluates to false. +For example, the following will produce a bibliography which only +contains entries whose "Year" field is greater than 1983: +\begin{verbatim} +\DTLbibliography[\DTLbibfieldisgt{Year}{1983}]{mybib} +\end{verbatim} + +\begin{definition}[\DescribeMacro{\DTLbibfieldisge}]% +\cs{DTLbibfieldisge}\marg{field label}\marg{value} +\end{definition} +This tests whether the value of the field given by \meta{field label} +is greater than or equal to \meta{value}. If the field doesn't exist +for the current entry, this evaluates to false. +For example, the following will produce a bibliography which only +contains entries whose "Year" field is greater than or equal to 1983: +\begin{verbatim} +\DTLbibliography[\DTLbibfieldisge{Year}{1983}]{mybib} +\end{verbatim} + +Note that \cs{DTLbibliography} uses \cs{DTLforeachbibentry} +(described in \autoref{sec:foreachbib}) so you may also use +test the value of the counter \ctr{DTLbibrow} within +\meta{conditions}. You may also use the boolean commands defined +by the \sty{ifthen} package, such as \ics{not}. + +\begin{example}{Creating a list of publications since a given year}{ex:bibsince2000} +Suppose my boss has asked me to produce a list of my +publications in reverse chronological order, but doesn't want any +publications published prior +to the year 2000. I have a file called "nlct.bib" which contains +all my publications which I keep in the directory +\verb!$HOME/texmf/bibtex/bib/!. I could look through this file, +work out the labels for all the publications whose year field +is greater or equal to 2000, and +create a file with a \cs{nocite} command containing all those labels +in a comma separated list in reverse chronological order, +but I really can't be bothered to do that. +Instead, I can create the following document: +\begin{verbatim} +\documentclass{article} +\usepackage{databib} +\begin{document} +\nocite{*} +\DTLloadbbl{mybib}{nlct} +\DTLsort{Year=descending,Month=descending}{mybib} +\DTLbibliography[\DTLbibfieldisge{Year}{2000}]{mybib} +\end{document} +\end{verbatim} +Suppose I save this file as "mypubs.tex", then I need to do: +\begin{verbatim} +latex mypubs +bibtex mypubs +latex mypubs +\end{verbatim} +Notes: +\begin{enumerate} +\item "\nocite{*}" is used to add all the citations in the +bibliography file ("nlct.bib" in this case) to the \sty{databib} +database. + +\item "\DTLloadbbl{mybib}{nlct}" does the following: +\begin{enumerate} +\item writes the line +\begin{verbatim} +\bibstyle{databib} +\end{verbatim} +to the auxiliary file. This tells \BibTeX\ to use "databib.bst" +(which is supplied with this package). You therefore shouldn't +use \cs{bibliographystyle}. + +\item writes the line +\begin{verbatim} +\bibdata{nlct} +\end{verbatim} +to the auxiliary file. This tells \BibTeX\ that the bibliography +data is stored in the file "nlct.bib". Since I have placed this +file in \TeX's search path, \BibTeX\ will be able to find it. + +\item creates a \sty{datatool} database called "mybib". + +\item if the \filetype{bbl} file ("mypubs.bbl" in this example) exists, +it loads this file (which adds the bibliography data to the +database), otherwise it does nothing further. + +\end{enumerate} + +\item In my \BibTeX\ database ("nlct.bib" in this example), I +have remembered to use the \BibTeX\ month macros: "jan", "feb" +etc. This means that the months are stored in the database in +the form \cs{DTLmonthname}\marg{nn}, where \meta{nn} is a two +digit number from 01 to 12. \cs{DTLsort} ignores command names +when it compares strings, which means I can not only sort by +year, but also by month\footnote{as long as I haven't put anything +before the month name in the bibliography file, e.g.\ +\mbox{\texttt{month = "2~" \# apr}} will sort by 2~03, instead of +03}. + +\item Once I have loaded and sorted my database, I can then +display it using \cs{DTLbibliography}. This uses the style +given by the \sty{databib} \pkgopt{style} package option, +or the \cs{DTLbibliographystyle} command, both of which are +described in \autoref{sec:bibstyle}. + +\item I have filtered the bibliography using the optional +argument\linebreak "[\DTLbibfieldisge{Year}{2000}]", which checks if the +year field of the current entry is greater than or equal to +2000. (Note that if an entry has no year field, the condition +evaluates to false, and the entry will be omitted from the +bibliography.) + +\item If the bibliography database is large, sorting and creating +the bibliography may take a while. Using \sty{databib} is much +slower than using a standard \BibTeX\ style file. +\end{enumerate} +\end{example} + +\begin{example}{Creating a list of my 10 most recent +publications}{ex:top10bib} +Suppose now my boss has asked me to produce a list of my ten most +recent publications (in reverse chronological order). +As in the previous example, I have a file called "nlct.bib" +which contains all my publications. I can create the required +document as follows: +\begin{verbatim} +\documentclass{article} +\usepackage{databib} +\begin{document} +\nocite{*} +\DTLloadbbl{mybib}{nlct} +\DTLsort{Year=descending,Month=descending}{mybib} +\DTLbibliography[\value{DTLbibrow}<10]{mybib} +\end{document} +\end{verbatim} +\end{example} + +\section{Changing the bibliography style} +\label{sec:bibstyle} +The style of the bibliography produced using \cs{DTLbibliography} +depends on the \pkgopt{style} +package option, or can be set using +\begin{definition}[\DescribeMacro{\DTLbibliographystyle}]% +\cs{DTLbibliographystyle}\marg{style} +\end{definition} +Note that this is \emph{not} the same as \cs{bibliographystyle}, +as the \sty{databib} package uses its custom \texttt{databib.bst} +bibliography style file. + +Example: +\begin{verbatim} +\usepackage[style=plain]{databib} +\end{verbatim} +This sets the plain bibliography style. This is, in fact, the +default style, so it need not be specified. + +Available styles are: "plain", "abbrv" and "alpha". These are similar to the +standard \BibTeX\ styles of the same name, but are by no means +identical. The most notable difference is that these styles +do not sort the bibliography. It is up to you to sort the +bibliography using \cs{DTLsort} (described in \autoref{sec:sort}). + +\subsection{Modifying an existing style} +\label{sec:modbibstyle} + +This section describes some of the commands which are used to +format the bibliography. You can choose whichever predefined +style best fits your required style, and then modify the commands +described in this section. A description of the remaining +commands not listed in this section can be found in +\autoref{sec:src:bibnames}, \autoref{sec:src:displaybib} +and \autoref{sec:src:bibstyle}. + +\begin{definition}[\DescribeMacro{\DTLformatauthor}]% +\cs{DTLformatauthor}\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLformateditor}]% +\cs{DTLformateditor}\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} +\end{definition} +These commands are used to format an author/editor's name, +respectively. The list of authors and editors are stored in +the \sty{databib} database as a comma separated list of +\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} +data. This ensures that when you sort on the Author or Editor +field, the names will be sorted by the first author or editor's +surname. + +Within \cs{DTLformatauthor} and \cs{DTLformateditor}, you may +use the following commands: +\begin{definition}[\DescribeMacro{\DTLformatforenames}]% +\cs{DTLformatforenames}\marg{forenames} +\end{definition} +This is used by the "plain" style to display the author's +forenames\footnote{It also checks +whether \meta{forenames} ends with a full stop using +\cs{DTLcheckendsperiod} to prevent a sentence ending full stop +from following an abbreviation full stop}. + +\begin{definition}[\DescribeMacro{\DTLformatabbrvforenames}]% +\cs{DTLformatabbrvforenames}\marg{forenames} +\end{definition} +This is used by the "abbrv" style to display the author's +initials (which are determined from \meta{forenames}). +Note that if any of the authors has a name starting with an +accent, the accented letter must be grouped in order for this +command to work. For example: +\begin{verbatim} +author = "{\'E}lise {\"E}awyn Edwards", +\end{verbatim} +The initials are formed using \cs{DTLstoreinitials} described +in \autoref{sec:strings}, so if you want to change the way the +initials are displayed (e.g.\ put a space between them) you will +need to redefine the commands used by \cs{DTLstoreinitials} (such +as \cs{DTLbetweeninitials}). + +\begin{definition}[\DescribeMacro{\DTLformatsurname}]% +\cs{DTLformatsurname}\marg{surname} +\end{definition} +This displays its argument by default\footnote{It also checks +whether the surname ends with a full stop using +\cs{DTLcheckendsperiod}}. + +\begin{definition}[\DescribeMacro{\DTLformatvon}]% +\cs{DTLformatvon}\marg{von part} +\end{definition} +If the \meta{von part} is empty, this command does nothing, +otherwise it displays its argument followed by a +non-breakable space. +\begin{definition}[\DescribeMacro{\DTLformatjr}]% +\cs{DTLformatjr}\marg{jr part} +\end{definition} +If the \meta{jr part} is empty, this command displays nothing, +otherwise it displays a comma followed by its argument\footnote +{again, it also checks \meta{jr part} to determine if it ends +with a full stop}. + +For example, suppose you want the author's surname to appear +first in small capitals, followed by a comma and the forenames. This +can be achieved by redefining \cs{DTLformatauthor} as follows: +\begin{verbatim} +\renewcommand*{\DTLformatauthor}[4]{% +\textsc{\DTLformatvon{#1}% +\DTLformatsurname{#2}\DTLformatjr{#3}}, +\DTLformatforenames{#4}% +} +\end{verbatim} + +\begin{definition}[\DescribeCounter{DTLmaxauthors}] +\ctrfmt{DTLmaxauthors} +\end{definition} +The counter \ctrfmt{DTLmaxauthors} is used to determine the +maximum number of authors to display for a given entry. If the +entry's author list contains more than that number of authors, +\cs{etalname} is used, the definition of which is given in +\autoref{sec:src:bibnames}. The default value of +\ctrfmt{DTLmaxauthors} is \theDTLmaxauthors. + +\begin{definition}[\DescribeCounter{DTLmaxeditors}] +\ctrfmt{DTLmaxeditors} +\end{definition} +The \ctrfmt{DTLmaxeditors} counter is analogous to the +\ctrfmt{DTLmaxauthors} counter. It is used to determine the +maximum number of editor names to display. The default value +of \ctrfmt{DTLmaxeditors} is \theDTLmaxeditors. + +\DescribeMacro{\DTLandlast} +Within a list of author or editor names, \cs{DTLandlast} is +used between the last two names, otherwise +\DescribeMacro{\DTLandnotlast}\cs{DTLandnotlast} is used between +names. +However, if there are only two author or editor names, +\DescribeMacro{\DTLtwoand}\cs{DTLtwoand} +is used instead of \cs{DTLandlast}. + +\DescribeMacro\DTLbibitem +The command \cs{DTLbibitem} is used at the start of each +bibliography item. It uses \cs{bibitem} to provide a marker, +such as [1], and writes the citation information to the +\texttt{.aux} file. + +\DescribeMacro\DTLmbibitem +The command \cs{DTLmbibitem} is analogous to \cs{DTLbibitem} but is +for use with \cs{DTLmbibliography}. + +\DescribeMacro{\DTLendbibitem} +The command \cs{DTLendbibitem} is a hook provided to add +additional information at the end of each bibliography item. +This does nothing by default, but if you want to display the +additional fields provided by the "databib.bst" style file, +you can redefine \cs{DTLendbibitem} so that it displays a +particular field, if it is defined. Within this command, you +may use the commands \cs{DTLbibfield}, \cs{DTLifbibfieldexist} +and \cs{DTLifanybibfieldexist}, which are described in +\autoref{sec:foreachbib}. For example, if you have used the +"abstract" field in any of your entries, you can display the +abstract as follows: +\begin{verbatim} +\renewcommand{\DTLendbibitem}{% +\DTLifbibfieldexists{Abstract}{\DTLpar\textbf{Abstract} +\begin{quote}\DTLbibfield{Abstract}\end{quote}}{}} +\end{verbatim} +(Note that \cs{DTLpar} needs to be used instead of +\cs{par}.) + +\begin{example}{Compact bibliography}{ex:compactbib} +Suppose I don't have much space in my document, and I need to +produce a compact bibliography. Firstly, I can use the +bibliography style "abbrv", either through the package option: +\begin{verbatim} +\usepackage[style=abbrv]{databib} +\end{verbatim} +or using: +\begin{verbatim} +\DTLbibliographystyle{abbrv} +\end{verbatim} +Once I have set the style, I can further modify it thus: +\begin{verbatim} +\renewcommand*{\andname}{\&} +\renewcommand*{\editorname}{ed.} +\renewcommand*{\editorsname}{eds.} +\renewcommand*{\pagesname}{pp.} +\renewcommand*{\pagename}{p.} +\renewcommand*{\volumename}{vol.} +\renewcommand*{\numbername}{no.} +\renewcommand*{\editionname}{ed.} +\renewcommand*{\techreportname}{T.R.} +\renewcommand*{\mscthesisname}{MSc thesis} +\end{verbatim} +Now I can load\footnote{I can load the bibliography earlier, but +obviously the bibliography should only be displayed after the +bibliography styles have been set, otherwise they will have no +effect} and display the bibliography: +\begin{verbatim} + % create a database called mybib from the information given + % in mybib1.bib and mybib2.bib + \DTLloadbbl{mybib}{mybib1,mybib2} + % display the bibliography + \DTLbibliography{mybib} +\end{verbatim} +\end{example} + +\begin{example}{Highlighting a given author}{ex:highlightauthor} +Suppose my boss wants me to produce a list of all my publications +(which I have stored in the file "nlct.bib", as in +\autoref{ex:bibsince2000}). Most of my +publications have multiple co-authors, but suppose my boss would +like me to highlight my name so that when he skims through +the document, he can easily see my name in the list of +co-authors. I can do this by redefining \cs{DTLformatauthor} +so that it checks if the given surname matches mine. (This +assumes that none of the other co-author's share my surname.) +\begin{verbatim} +\renewcommand*{\DTLformatauthor}[4]{% +{\DTLifstringeq{#2}{Talbot}{\bfseries }{}% +\DTLformatforenames{#4} +\DTLformatvon{#1}% +\DTLformatsurname{#2}% +\DTLformatjr{#3}}} +\end{verbatim} +Notes: +\begin{enumerate} +\item I have used \cs{DTLifstringeq} (described in +\autoref{sec:ifconditions}) to perform the string comparison. +\item If one or more of my co-authors shared the same surname as +me, I would also have had to check the first name, however there +is regrettably a lack of consistency in my \filetype{bib} file when +it comes to my forenames. Sometimes my name is given as +\texttt{Nicola L. C. Talbot}, sometimes the middle initials +are omitted, \texttt{Nicola Talbot}, or sometimes, just initials +are used, \texttt{N. L. C. Talbot}. This can cause problems +when checking the forenames, but as long as the other authors +who share the same surname as me, don't also share the same +first initial, I can use \cs{DTLifStartsWith} or \cs{DTLisPrefix}, +which are described in \autoref{sec:ifconditions} and +\autoref{sec:ifthen}, respectively. Using the first approach +I can do: +\begin{verbatim} +\renewcommand*{\DTLformatauthor}[4]{% +{\DTLifstringeq{#2}{Talbot}{\DTLifStartsWith{#4}{N}{\bfseries }{}}{}% +\DTLformatforenames{#4} +\DTLformatvon{#1}% +\DTLformatsurname{#2}% +\DTLformatjr{#3}}} +\end{verbatim} +Using the second approach I can do: +\begin{verbatim} +\renewcommand*{\DTLformatauthor}[4]{% +{\ifthenelse{\DTLiseq{#2}{Talbot}\and +\DTLisPrefix{#4}{N}}{\bfseries }{}% +\DTLformatforenames{#4} +\DTLformatvon{#1}% +\DTLformatsurname{#2}% +\DTLformatjr{#3}}} +\end{verbatim} + +\item I have used a group to localise the effect of \cs{bfseries}. +\end{enumerate} +\end{example} + +\section{Iterating through a +\texorpdfstring{\sty{databib}}{databib} database} +\label{sec:foreachbib} + +\cs{DTLbibliography} (described in \autoref{sec:thebib}) may still +not meet your needs. For example, you may be required +to list journal papers and conference proceedings in separate +sections. In which case, you may find it easier to iterate through +the bibliography using: +\begin{definition}[\DescribeMacro{\DTLforeachbibentry}]% +\cs{DTLforeachbibentry}\oarg{condition}\marg{db name}\marg{text} +\end{definition} +\begin{definition}[\DescribeMacro{\DTLforeachbibentry*}]% +\cs{DTLforeachbibentry*}\oarg{condition}\marg{db name}\marg{text} +\end{definition} +This iterates through the \sty{databib} database called +\meta{db name} and does \meta{text} if \meta{condition} is met. +As with \cs{DTLforeach}, the starred version is read-only. + +\cs{DTLforeachbibentry} only makes local assignments, which means that it's unsuitable to display the references +in a~\env{tabular}-like environment (for example, the +\env{europecv} environment provided by the \cls{europecv} class). It's also a~short command, so +\meta{text} can't contain any paragraph breaks. Instead you can use +the analogous commands: +\begin{definition}[\DescribeMacro{\gDTLforeachbibentry}]% +\cs{gDTLforeachbibentry}\oarg{condition}\marg{db name}\marg{text} +\end{definition} +\begin{definition}[\DescribeMacro{\gDTLforeachbibentry*}]% +\cs{gDTLforeachbibentry*}\oarg{condition}\marg{db name}\marg{text} +\end{definition} + +For each row of the database, the following commands are set: +\begin{itemize} +\item \cs{DBIBcitekey} \DescribeMacro{\DBIBcitekey}This is the +unique label which identifies the current entry (as used in the +argument of \cs{cite} and \cs{nocite}). + +\item \cs{DBIBentrytype} \DescribeMacro{\DBIBentrytype}This +is the current entry type, and will be one of: "article", "book", +"booklet", "inbook", "incollection", "inproceedings", +"manual", "mastersthesis", "misc", "phdthesis", "proceedings", +"techreport" or "unpublished". (Note that even if you used the +entry type "conference" in your \filetype{bib} file, its entry type +will be set to "inproceedings"). +\end{itemize} + +The remaining fields may be accessed using: +\begin{definition}[\DescribeMacro{\DTLbibfield}]% +\cs{DTLbibfield}\marg{field label} +\end{definition}\noindent +where \meta{field label} may be one of: "Address", "Author", +"BookTitle", "Chapter", "Edition", "Editor", "HowPublished", +"Institution", "Journal", "Key", "Month", "Note", "Number", +"Organization", "Pages", "Publisher", "School", "Series", +"Title", "Type", "Volume", "Year", "ISBN", "DOI", "PubMed", +"Abstract" or "Url". + +Alternatively, you can assign the value of a field to a control +sequence \meta{cs} using: +\begin{definition}[\DescribeMacro\DTLbibfieldlet] +\cs{DTLbibfieldlet}\marg{cs}\marg{field label} +\end{definition} + +You can determine if a field exists for a given entry using +\begin{definition}[\DescribeMacro{\DTLifbibfieldexists}]% +\cs{DTLifbibfieldexists}\marg{field label}\marg{true part}\marg{false +part} +\end{definition} +If the field given by \meta{field label} exists for the current +bibliography entry, it does \meta{true part}, otherwise it +does \meta{false part}. + +\begin{definition}[\DescribeMacro{\DTLifbibanyfieldexists}]% +\cs{DTLifanybibfieldexists}\marg{field label list}\marg{true +part}\marg{false part} +\end{definition} +This is similar to \cs{DTLifbibfieldexists} except that the +first argument is a list of field names. If one or more of +the fields given in \meta{field label list} exists for the +current bibliography item, this does \meta{true part}, otherwise +it does \meta{false part}. + +\begin{definition}[\DescribeMacro{\DTLformatbibentry}]% +\cs{DTLformatbibentry} +\end{definition} +This formats the bibliography entry for the current row. It +checks for the existence of the command +\cs{DTLformat}\meta{entry type}, where \meta{entry type} +is given by \cs{DBIBentrytype}. These commands are defined +by the bibliography style. There is also a~version for use with +\cs{gDTLforeachbibentry}: +\begin{definition}[\DescribeMacro{\gDTLformatbibentry}]% +\cs{gDTLformatbibentry} +\end{definition} +It's also possible to use \cs{DTLformatbibentry} for a specific key, +rather than using it within \ics{DTLforeachbibentry} using: +\begin{definition} +\cs{DTLformatthisbibentry}\marg{db}\marg{cite key} +\end{definition} +where \meta{db} is the database name and \meta{cite key} is the +citation label. Note that none of these three commands use +\cs{bibitem}. You can manually insert \cs{bibitem}\marg{cite key} +in front of the command, or you can use: +\begin{definition} +\cs{DTLcustombibitem}\marg{marker code}\marg{ref text}\marg{cite key} +\end{definition} +This is like \cs{bibitem}\oarg{text}\marg{cite key} except that it uses +\meta{marker code} instead of \cs{item}\oarg{text} and it uses +\meta{ref text} instead of \verb|\the\value{\@listctr}|. + +\begin{definition}[\DescribeMacro{\DTLcomputewidestbibentry}]% +\cs{DTLcomputewidestbibentry}\marg{conditions}\marg{db +name}\marg{bib label}\marg{cmd} +\end{definition} +This computes the widest bibliography entry over all entries +satisfying \meta{conditions} in the database \meta{db name}, +where the label is given by \meta{bib label}, and the result +is stored in \meta{cmd}, which may then be used in the +argument of the \env{thebibliography} environment. + +The counter \desctr{DTLbibrow} keeps track of the current +bibliography entry. This is reset at the start of each +\cs{DTLforeachbibentry} and is incremented if \meta{conditions} +is met. + +Within the optional argument \meta{condition}, you may use any of the +commands that may be used within the optional argument of +\cs{DTLbibliography}, described in \autoref{sec:thebib}. + +\begin{example}{Separate List of Journals and Conference Papers}{ex:jcbib} +Suppose now my boss has decided that I need to produce a list +of all my publications, but they need to be separated so that +all the journal papers appear in one section, and all the +conference papers appear in another section. The journal papers +need to be labelled [J1], [J2] and so on, while the conference +papers need to be labelled [C1], [C2] and so on. (My boss isn't +interested in any of my other publications!) Again, all my +publications are stored in the \BibTeX\ database "nlct.bib". The +following creates the required document: +\begin{verbatim} +\documentclass{article} +\usepackage{databib} +\begin{document} +\nocite{*} +\DTLloadbbl{mybib}{nlct} + +\renewcommand*{\refname}{Journal Papers} +\DTLcomputewidestbibentry{\equal{\DBIBentrytype}{article}} +{mybib}{J\theDTLbibrow}{\widest} + +\begin{thebibliography}{\widest} +\DTLforeachbibentry[\equal{\DBIBentrytype}{article}]{mybib}{% +\bibitem[J\theDTLbibrow]{\DBIBcitekey} \DTLformatbibentry} +\end{thebibliography} + +\renewcommand*{\refname}{Conference Papers} +\DTLcomputewidestbibentry{\equal{\DBIBentrytype}{inproceedings}} +{mybib}{C\theDTLbibrow}{\widest} + +\begin{thebibliography}{\widest} +\DTLforeachbibentry[\equal{\DBIBentrytype}{inproceedings}]{mybib}{% +\bibitem[C\theDTLbibrow]{\DBIBcitekey} \DTLformatbibentry} +\end{thebibliography} + +\end{document} +\end{verbatim} +\end{example} + +\section{Multiple Bibliographies} +\label{sec:multibib} + +It is possible to have more than one bibliography in a document, +but it then becomes necessary to have a separate auxiliary file +for each bibliography, and each auxiliary file must then be +passed to \BibTeX. In order to do this, you need to use +\begin{definition}[\DescribeMacro{\DTLmultibibs}]% +\cs{DTLmultibibs}\marg{name list} +\end{definition} +where \meta{name list} is a comma separated list of names, +\meta{name}. For each \meta{name}, this command creates an +auxiliary file called \meta{name}".aux" (note that this +command may only be used in the preamble). + +When you want to cite an entry for a given bibliography named +in \cs{DTLmultibibs}, you must use: +\begin{definition}[\DescribeMacro{\DTLcite}]% +\cs{DTLcite}\oarg{text}\marg{mbib}\marg{cite key list} +\end{definition}\noindent +This is analogous to \cs{cite}\oarg{text}\marg{cite key list}, +but writes the \cs{citation} command to \meta{mbib}".aux" instead +of to the document's main auxiliary file. It also ensures that +the cross-referencing labels are based on \meta{mbib}, to allow +you to have the same reference in more than one bibliography +without incurring a ``multiply defined'' warning message. Note +that you can still use \cs{cite} to add citation information to +the main auxiliary file. + +If you want to add an entry to the bibliography without producing +any text, you can use +\begin{definition}[\DescribeMacro{\DTLnocite}] +\cs{DTLnocite}\marg{mbib}\marg{cite key list} +\end{definition}\noindent +which is analogous to \cs{nocite}\marg{cite key list}, where +again the citation information is written to \meta{mbib}".aux" +instead of the document's main auxiliary file. + +Note that for both \cs{DTLcite} and \cs{DTLnocite} the +\meta{mbib} part must be one of the names listed in +\cs{DTLmultibibs}. + +\begin{definition}[\DescribeMacro{\DTLloadmbbl}]% +\cs{DTLloadmbbl}\marg{mbib}\marg{db name}\marg{bib list} +\end{definition} +This is analogous to \cs{DTLloadbbl}\marg{db name}\marg{bib list} +described in \autoref{sec:loadbbl}. (Again \meta{mbib} must be +one of the names listed in \cs{DTLmultibibs}.) This creates +a new \sty{datatool} database called \meta{db name} and loads the +bibliography information from \meta{mbib}".bbl" (if it exists). + +\begin{definition}[\DescribeMacro{\DTLmbibliography}]% +\cs{DTLmbibliography}\oarg{condition}\marg{mbib}\marg{db name} +\end{definition} +This is analogous to \cs{DTLbibliography}\oarg{condition}\marg{db name}, +but is required when displaying a bibliography in which elements have +been cited using \cs{DTLcite} and \cs{DTLnocite}. + +\begin{example}{Multiple Bibliographies}{ex:multibib} +Suppose I need to create a document which contains a section listing +all my publications, but I also need to have separate sections +covering each of my research topics, with a mini-bibliography +at the end of each section. As in the earlier examples, all my +publications are stored in the file "nlct.bib" which is somewhere +on \TeX's path. Note that there will be some duplication as the +references in the mini-bibliographies will also appear in the +main bibliography at the end of the document, but using +\cs{DTLcite} and \cs{DTLmbibliography} ensures that all the +cross-referencing labels (and hyperlinks if they are enabled) +are unique. +\begin{verbatim} +\documentclass{article} +\usepackage{databib} +\DTLmultibibs{kernel,food} +\begin{document} +\section{Kernel methods} +In this section I'm going to describe some research work into +kernel methods, and in the process I'm going to cite some related +papers \DTLcite{kernel}{Cawley2007a,Cawley2006a}. + +\DTLloadmbbl{kernel}{kernelDB}{nlct} +\DTLmbibliography{kernel}{kernelDB} + +\section{Food research} + +In this section I'm going to describe some research work +in the area of food safety, and in the process, I'm going +to cite some related papers \DTLcite{food}{Peck1999,Barker1999a} + +\DTLloadmbbl{food}{foodDB}{nlct} +\DTLmbibliography{food}{foodDB} + +\cite{*} +\renewcommand{\refname}{Complete List of Publications} +\DTLloadbbl{fullDB}{nlct} +\DTLbibliography{fullDB} +\end{document} +\end{verbatim} +Notes: +\begin{enumerate} +\item This will create the files "kernel.aux" and "food.aux". +These will have to be passed to \BibTeX, in addition to the +documents main auxiliary file. So, if my document is called +"researchwork.tex", then I need to do: +\begin{verbatim} +latex researchwork +bibtex researchwork +bibtex kernel +bibtex food +latex researchwork +latex researchwork +\end{verbatim} + +\item "\cite{*}" is used to add all the entries in the bib file +to the main bibliography database. As before, \cs{DTLloadbbl} +and \cs{DTLbibliography} are used to load and display the main +bibliography. +\end{enumerate} +\end{example} + +\begin{important} +Don't try to directly input the ".bbl" file using \cs{input} (or +\cs{include}) instead of using \cs{DTLloadbbl} or \cs{DTLloadmbbl} +as these commands store the name of the required database and +initialise the database before loading the \texttt{.bbl} file. +Similarly, don't just copy the contents of the ".bbl" file into your +document without first defining the database using \ics{DTLnewdb} +and setting \ics{DTLBIBdbname} to the name of the database. +\end{important} + +\chapter{Referencing People (\sty{person} package)} +\label{sec:person} + +Sometimes when mail-merging, it may be necessary to reference a +person by their pronoun which can lead to the cumbersome and +impersonal ``he/she'' construct. The \sty{person} package +allows you to define a person by their full name, familiar name and +gender. You can then use the commands described in +\autoref{sec:refperson} to produce the appropriate pronoun. + +This can also be useful for other types of documents, such as an +order of service for a baptism or funeral. Since the +document is much the same from one person to the next, documents of +this nature are frequently simply copied and a search and replace +edit is used to change the relevant text. However this can lead to +errors (especially if the previous person's name was Mary!) With +the \sty{person} package, you need only change the definition of +the person by modifying the arguments of \cs{newperson}. + +\section{Defining and Undefining People} + +A person is defined (globally) using the command: +\begin{definition}[\DescribeMacro{\newperson}] +\cs{newperson}\oarg{label}\marg{full name}\marg{familiar name}\marg{gender} +\end{definition} +The optional argument is a unique label identifying this person, +in the event that there is more than one person. If \meta{label} +is omitted \texttt{anon} is used. (This is also the case for +subsequent commands that take an optional label.) +The gender may be any of those given by +\begin{definition}[\DescribeMacro{\malelabels}] +\cs{malelabels} +\end{definition} +or +\begin{definition}[\DescribeMacro{\femalelabels}] +\cs{femalelabels} +\end{definition} +The default definition of \cs{malelabels} is \texttt{\malelabels} +and the default definition of \cs{femalelabels} is +\texttt{\femalelabels}. You can add extra identifiers using +\begin{definition}[\DescribeMacro{\addmalelabel}] +\cs{addmalelabel}\marg{identifier} +\end{definition} +or +\begin{definition}[\DescribeMacro{\addfemalelabel}] +\cs{addfemalelabel}\marg{identifier} +\end{definition} +For example: +\begin{verbatim} +\addmalelabel{boy} +\addfemalelabel{girl} +\end{verbatim} + +The total number of defined people is given by: +\begin{definition}[\DescribeMacro{\thepeople}] +\cs{thepeople} +\end{definition} + +A person can be undefined using: +\begin{definition}[\DescribeMacro{\removeperson}] +\cs{removeperson}\oarg{label} +\end{definition} +where the person is given by \meta{label}. + +If more than one person has been defined, they can all be +removed using: +\begin{definition}[\DescribeMacro{\removeallpeople}] +\cs{removeallpeople} +\end{definition} +or you can remove a subset using: +\begin{definition}[\DescribeMacro{\removepeople}] +\cs{removepeople}\marg{list} +\end{definition} +where \meta{list} is a comma-separated list of labels. + +\section{Displaying Information} +\label{sec:refperson} + +Once a person has been defined, you can display their name using: +\begin{definition}[\DescribeMacro{\personfullname}] +\cs{personfullname}\oarg{label} +\end{definition} +where \meta{label} is the unique label used in the optional +argument to \cs{newperson}. The person's familiar name is displayed +using: +\begin{definition}[\DescribeMacro{\personname}] +\cs{personname}\oarg{label} +\end{definition} +The person's pronoun (``he'' or ``she'') is displayed using: +\begin{definition}[\DescribeMacro{\personpronoun}] +\cs{personpronoun}\oarg{label} +\end{definition} +The objective pronoun (``him'' or ``her'') is displayed using: +\begin{definition}[\DescribeMacro{\personobjpronoun}] +\cs{personobjpronoun}\oarg{label} +\end{definition} +The possessive adjective (``his'' or ``her'') is displayed using: +\begin{definition}[\DescribeMacro{\personpossadj}] +\cs{personpossadj}\oarg{label} +\end{definition} +The possessive pronoun ``his'' or ``hers'' is displayed using: +\begin{definition}[\DescribeMacro{\personposspronoun}] +\cs{personposspronoun}\oarg{label} +\end{definition} +The person's relationship to their parent (``son'' or ``daughter'') +is displayed using: +\begin{definition}[\DescribeMacro{\personchild}] +\cs{personchild}\oarg{label} +\end{definition} +The person's relationship to their child (``mother'' or ``father'') +is displayed using: +\begin{definition}[\DescribeMacro{\personparent}] +\cs{personparent}\oarg{label} +\end{definition} +The person's relationship to their sibling (``brother'' or +``sister'') is displayed using: +\begin{definition}[\DescribeMacro{\personsibling}] +\cs{personsibling}\oarg{label} +\end{definition} + +If the word occurs at the start of a sentence, you will need one +of the following commands, which are as the above, except the +first letter is converted to upper case: +\begin{definition}[\DescribeMacro{\Personpronoun}] +\cs{Personpronoun}\oarg{label} +\end{definition} +\begin{definition}[\DescribeMacro{\Personobjpronoun}] +\cs{Personobjpronoun}\oarg{label} +\end{definition} +\begin{definition}[\DescribeMacro{\Personpossadj}] +\cs{Personpossadj}\oarg{label} +\end{definition} +\begin{definition}[\DescribeMacro{\Personposspronoun}] +\cs{Personposspronoun}\oarg{label} +\end{definition} +\begin{definition}[\DescribeMacro{\Personchild}] +\cs{Personchild}\oarg{label} +\end{definition} +\begin{definition}[\DescribeMacro{\Personparent}] +\cs{Personparent}\oarg{label} +\end{definition} +\begin{definition}[\DescribeMacro{\Personsibling}] +\cs{Personsibling}\oarg{label} +\end{definition} + +\begin{example}{Order of Service (Memorial)}{ex:memorial} +This example is for a memorial order of service. + +\begin{verbatim} +\documentclass{article} + +\usepackage{person} + +\newperson{Jane Doe}{Jane}{female} + +\begin{document} +\begin{center} +\Large +In Memory of \personfullname +\end{center} + +We are gathered here to remember our \personsibling\ \personname. +\Personpronoun\ will be much missed, and \personpossadj\ +family are in our prayers. +\end{document} +\end{verbatim} + +\newperson{Jane Doe}{Jane}{female} +\begin{center} +\Large +In Memory of \personfullname +\end{center} + +We are gathered here to remember our \personsibling\ \personname. +\Personpronoun\ will be much missed, and \personpossadj\ +family are in our prayers. +\removeperson + +\end{example} + +If there is more than one person, you will need to use the +optional argument \meta{label} to \cs{newperson} to uniquely +identify each person. You can then list all of the people's full +or familiar names using: +\begin{definition}[\DescribeMacro{\peoplefullname}] +\cs{peoplefullname} +\end{definition} +\begin{definition}[\DescribeMacro{\peoplename}] +\cs{peoplename} +\end{definition} +Note that if there is only one person defined, these commands behave +the same as \cs{personfullname}\oarg{label} and +\cs{personname}[\meta{label}]. + +Similarly for the pronouns: +\begin{definition}[\DescribeMacro{\peoplepronoun}] +\cs{peoplepronoun} +\end{definition} +\begin{definition}[\DescribeMacro{\Peoplepronoun}] +\cs{Peoplepronoun} +\end{definition} +\begin{definition}[\DescribeMacro{\peopleobjpronoun}] +\cs{peopleobjpronoun} +\end{definition} +\begin{definition}[\DescribeMacro{\Peopleobjpronoun}] +\cs{Peopleobjpronoun} +\end{definition} +\begin{definition}[\DescribeMacro{\peoplepossadj}] +\cs{peoplepossadj} +\end{definition} +\begin{definition}[\DescribeMacro{\Peoplepossadj}] +\cs{Peoplepossadj} +\end{definition} +\begin{definition}[\DescribeMacro{\peopleposspronoun}] +\cs{peopleposspronoun} +\end{definition} +\begin{definition}[\DescribeMacro{\Peopleposspronoun}] +\cs{Peopleposspronoun} +\end{definition} +where, again, if only one person has been defined, each of these +commands is equivalent to +\cs{person}\ldots\oarg{label} or +\cs{Person}\ldots\oarg{label}. If more than +one person has been defined, these commands will display +they/them/their/theirs or They/Them/Their/Theirs, as appropriate. + +Likewise for relationship commands: +\begin{definition}[\DescribeMacro{\peoplechild}] +\cs{peoplechild} +\end{definition} +\begin{definition}[\DescribeMacro{\Peoplechild}] +\cs{Peoplechild} +\end{definition} +\begin{definition}[\DescribeMacro{\peopleparent}] +\cs{peopleparent} +\end{definition} +\begin{definition}[\DescribeMacro{\Peopleparent}] +\cs{Peopleparent} +\end{definition} +\begin{definition}[\DescribeMacro{\peoplesibling}] +\cs{peoplesibling} +\end{definition} +\begin{definition}[\DescribeMacro{\Peoplesibling}] +\cs{Peoplesibling} +\end{definition} + +\begin{example}{Order of Service (Baptism)}{ex:baptism} +In this example two people are defined. +\begin{verbatim} +\documentclass{article} + +\usepackage{person} + +\newperson[john]{John Joseph}{John}{male} +\newperson[jane]{Jane Mary}{Jane}{female} + +\begin{document} +\begin{center} +\Large +Baptism of \peoplefullname. +\end{center} + +Today we welcome \peoplename\ into God's family, may He guide +and protect \peopleobjpronoun. +\end{document} +\end{verbatim} + +This is produces the following text: + +\newperson[john]{John Joseph}{John}{male} +\newperson[jane]{Jane Mary}{Jane}{female} + +\begin{center} +\Large +Baptism of \peoplefullname. +\end{center} + +Today we welcome \peoplename\ into God's family, may He guide +and protect \peopleobjpronoun. +\removeallpeople +\end{example} + +\begin{example}{Mail Merging Using Appropriate Gender}{ex:personmerge} +In this example I have a CSV file called \texttt{students.csv} +containing the following: +\begin{verbatim} +FirstName,Surname,Gender,Parent,Address +John,"Smith, Jr",M,Mr and Mrs Smith,1 The Street\\Newtown +Jane,Brown,F,Ms Brown,2 The Avenue\\Oldtown +Andy,Brown,male,Mr Brown and Miss Sepia,3 The Road\\Newtown +Z\"oe,Adams,f,Mr and Mrs Adams,5 The Street\\Newtown +Roger,Brady,m,Mrs Brady,6 The Avenue\\Oldtowm +Clare,Vernon,female,Mr Vernon,7 The Close\\Anytown +\end{verbatim} +Suppose I have to write to each student's parents regarding their +child. I can load the information using \ics{DTLloaddb} (described +in \autoref{sec:loaddb}). I can then iterate through the database +and define the student as a person and use the commands defined in +the \sty{person} package to display the correct gender related text. +I could give each person a unique label based on the row count +(\ics{DTLcurrentindex}), but since I don't need to reuse the +information, I can use the default "anon" label and undefine the +person when no longer required. + +Note that in the CSV file, the gender label isn't consistent. +For some students the gender is identified by a single letter +(``m'' or ``f'') and for others the gender is identified by a +complete word (``male'' or ``female''). There's also no regard +for case. This doesn't matter to \ics{newperson} as all the +identifiers used are listed in \ics{malelabels} and +\ics{femalelabels}. + +The following is an example letter sent to all parents: +\begin{verbatim} +\documentclass{letter} +\usepackage{person} + +% load student information from file "students.csv" +\DTLloaddb{students}{students.csv} +\begin{document} +% Iterate through the student database: +\DTLforeach{students}{\FirstName=FirstName,\Surname=Surname,% +\Gender=Gender,\Parent=Parent,\Address=Address}{% +% Define "anon": + \newperson{\FirstName\space\Surname}{\FirstName}{\Gender}% +% Do the letter: + \begin{letter}{\Parent\\\Address} + \opening{Dear \Parent} + Your \personchild\ \personname\ has been awarded a + place. We look forward to seeing \personobjpronoun\ + on \personpossadj\ arrival. + \closing{Yours Sincerely} + \end{letter} +% Undefine "anon": + \removeperson +} +\end{document} +\end{verbatim} + +The body of the first letter appears as follows: +\newperson{John Smith Jr}{John}{m} +\par\vskip\baselineskip + + Your \personchild\ \personname\ has been awarded a + place. We look forward to seeing \personobjpronoun\ + on \personpossadj\ arrival. + +\removeperson +\par\vskip\baselineskip +Whereas the body of the second letter appears as follows: +\newperson{Jane Brown}{Jane}{f} +\par\vskip\baselineskip + + Your \personchild\ \personname\ has been awarded a + place. We look forward to seeing \personobjpronoun\ + on \personpossadj\ arrival. + +\removeperson +\end{example} + +\section{Advanced Commands} + +This section describes additional commands provided by the +\sty{person} package. More detail can be found in +the documented code (datatool-code.pdf). + +\subsection{Conditionals} + +\begin{definition}[\DescribeMacro{\ifpersonexists}] +\cs{ifpersonexists}\marg{label}\marg{true part}\marg{false part} +\end{definition} +Tests if the person identified by \meta{label} has been defined. +If true, do \meta{true part} otherwise do \meta{false part}. + +\begin{definition}[\DescribeMacro{\ifmale}] +\cs{ifmale}\marg{label}\marg{true part}\marg{false part} +\end{definition} +Test if the person identified by \meta{label} is male. +If true, do \meta{true part} otherwise do \meta{false part}. + +\begin{definition}[\DescribeMacro{\iffemale}] +\cs{iffemale}\marg{label}\marg{true part}\marg{false part} +\end{definition} +Test if the person identified by \meta{label} is female. +If true, do \meta{true part} otherwise do \meta{false part}. + +\begin{definition}[\DescribeMacro{\ifallmale}] +\cs{ifallmale}\oarg{label list}\marg{true part}\marg{false part} +\end{definition} +Tests if all the people listed in \meta{label list} are male. +If true, do \meta{true part} otherwise do \meta{false part}. +If \meta{label list} is omitted, applied to all defined people. +\begin{definition}[\DescribeMacro{\ifallfemale}] +\cs{ifallfemale}\oarg{label list}\marg{true part}\marg{false part} +\end{definition} +Likewise to test if all the people tested are female. + +To determine if a string is an allowed male label: +\begin{definition}[\DescribeMacro{\ifmalelabel}] +\cs{ifmalelabel}\marg{identifier}\marg{true part}\marg{false part} +\end{definition} +where \meta{identifier} is the string to be tested. If true, do +\meta{true part} otherwise do \meta{false part}. +For example: +\begin{verbatim} +\def\gender{M} +\ifmalelabel{\gender}{male}{not male} +\end{verbatim} +Similarly to for an allowed female label: +\begin{definition}[\DescribeMacro{\iffemalelabel}] +\cs{iffemalelabel}\marg{identifier}\marg{true part}\marg{false part} +\end{definition} +For example: +\begin{verbatim} +\ifmalelabel{\gender}{Male}{% + \iffemalelabel{\gender}{Female}% + {Undefined Gender}% +} +\end{verbatim} + +\subsection{Iterating Through Defined People} + +You can iterate through all defined people using: +\begin{definition}[\DescribeMacro{\foreachperson}] +\cs{foreachperson}(\meta{name cs},\meta{full name cs},\meta{gender cs},\meta{label cs})\cs{do}\marg{body} +\end{definition} +At each iteration, \meta{name cs}, \meta{full name cs}, +\meta{gender cs} and \meta{label cs} are set to the current person's +name, full name, gender and label, respectively. (These arguments +must all be command names.) Note that the gender is set to +the definition of \DescribeMacro{\malename}\cs{malename} or +\DescribeMacro{\femalename}\cs{femalename}, as appropriate.\footnote{Predefined names provided by the \sty{person} package are described +in the documented code (datatool-code.pdf).} Once these +commands are set, \meta{body} is applied. + +If you only want to iterate through a subset of defined people, +you can use: +\begin{definition} +\cs{foreachperson}(\meta{name cs},\meta{full name cs},\meta{gender cs},\meta{label cs})\cs{in}\marg{list}\cs{do}\marg{body} +\end{definition} +where \meta{list} is a comma-separated list of labels. + +\subsection{Accessing Individual Information} + +\begin{definition}[\DescribeMacro{\getpersongender}] +\cs{getpersongender}\marg{cs}\marg{label} +\end{definition} +Gets the gender of the person identified by \meta{label} and +stores in \meta{cs} (which must be a command name). This +sets \meta{cs} to the definition of \ics{malename} or +\ics{femalename} as appropriate. + +\begin{definition}[\DescribeMacro{\getpersonname}] +\cs{getpersonname}\marg{cs}\marg{label} +\end{definition} +Gets the name of the person identified by \meta{label} and +stores in \meta{cs} (which must be a command name). + +\begin{definition}[\DescribeMacro{\getpersonfullname}] +\cs{getpersonfullname}\marg{cs}\marg{label} +\end{definition} +Gets the full name of the person identified by \meta{label} and +stores in \meta{cs} (which must be a command name). + +\clearpage +\phantomsection +\addcontentsline{toc}{chapter}{\bibname} +\DTLbibliography{docbib} + +\clearpage +\phantomsection +\addcontentsline{toc}{chapter}{Acknowledgements} +\chapter*{Acknowledgements} + +Many thanks to Morten~H\o gholm for providing a much more +efficient way of storing the information in databases which +has significantly improved the time it takes to \LaTeX\ documents +containing large databases. + +\clearpage +\phantomsection +\addcontentsline{toc}{chapter}{\indexname} +\PrintIndex + +\end{document} |