3

I would like to conditionally print something in a report, based on whether there was a non-zero data point or not (for this example, \DepthOne and \DepthThree are to be tested).

I start by reading values in from a csv table using \csvreader, and then I assign these a label using \newcommand. Then I apply a test on the label using \ifnum. The behaviour in the implementation below is not what I hoped for. For instance, I get missing number, treated as zero errors and weird output preceding the sentence. Also, oddly one of the labels I assigned (\SampleName) doesn't seem to persist.

Is it possible to do what I am attempting, and what is the right way to go about this?

\documentclass[10pt]{report}

\usepackage{csvsimple}
\usepackage{filecontents}

\newcommand*{\ThisRock}{examplecsv}

% Make up some data in a CSV file called examplecsv.csv
\begin{filecontents*}{\ThisRock.csv}
    SampleName,Depth1,DepthTwo,Depth3
    ROCK001,48,52,0
\end{filecontents*}

% Pick out specific data in the file and create labels for them to be read by latex
\newcommand*{\SampleName}{\csvreader{\ThisRock.csv}{1=\SampleName}{\SampleName}}
\newcommand*{\DepthOne}{\csvreader{\ThisRock.csv}{2=\Depth1}{\Depth1}}
\newcommand*{\DepthTwo}{\csvreader{\ThisRock.csv}{3=\DepthTwo}{\DepthTwo}}
\newcommand*{\DepthThree}{\csvreader{\ThisRock.csv}{4=\Depth3}{\Depth3}}

\begin{document}
% Show the data (normally this is underwater)
\csvautotabular{examplecsv.csv} \\

% Expect this to print the sentence twice fully (first time is okay, second time incomplete?)
The rock sampled was called \SampleName. \\
The rock sampled was called \SampleName. \\

% Because there is some non-zero data for the first sample, expect this to print the sentence
\ifnum\ifnum\DepthOne>0 1\else0\fi
=1 %
\noindent The first sample hole was drilled to \DepthOne~mm\\
\else
\\
\fi

% Because the data is zero for the third sample, expect this not to print the sentence
\ifnum\ifnum\DepthThree>0 1\else0\fi
=1 %
\noindent The third sample hole was drilled to \DepthThree~mm\\
\else
\\
\fi

\end{document}
3
  • 1
    \DepthOne etc. aren't expandable apparently, so \ifnum\Depth... will fail -- it can't evaluate the test,\cvsreader is not expandable since it has an optional first argument, so \DepthOne etc. can't be expanded as well
    – user31729
    Commented Feb 9, 2017 at 22:55
  • Perhaps the macros \ifcvsstrequal etc. (see the manual please) are more useful? I can't test right now... it's late and I am tired!
    – user31729
    Commented Feb 9, 2017 at 22:59
  • Perhaps have a look at the readarray package, as an alternative. Commented Feb 10, 2017 at 2:45

3 Answers 3

2

This answer actually refers to your comment to egreg's answer:

What happens when I wish to access the \samplename label outside the \csvreader context?

You can use the \csvreader context for making global assignments after sufficiently expanding local "variables"/macros—in order to obtain the values, the "variables" need to be expanded twice:

% Make up some data in a CSV file
\begin{filecontents*}{\jobname.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
ROCK002,1,2,3
\end{filecontents*}

\documentclass[10pt]{report}
\usepackage{csvsimple}

\newcount\Samplenumber
\newcommand*\GlobalSamplename{}%
\newcommand*\GlobalDepthone{}%
\newcommand*\GlobalDepthtwo{}%
\newcommand*\GlobalDepththree{}%
%
\newcommand*\GlobalSamplenamederrorefault{\texttt{??}}%
\newcommand*\GlobalDepthoneerrorefault{0}%
\newcommand*\GlobalDepthtwoerrorefault{0}%
\newcommand*\GlobalDepththreeerrorefault{0}%
%
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newcommand\expandtwice{}%
\long\def\expandtwice#1#{\innerexpandtwice{#1}}%
\newcommand\innerexpandtwice[2]{%
  \expandafter\expandafter\expandafter\PassFirstToSecond
  \expandafter\expandafter\expandafter{#2}{#1}%
}%

\makeatletter

\newcommand\ReadToMacrosSampleDataRowNumber[1]{%
  \@bsphack
  \begingroup
  \let\GlobalSamplename=\UndEfINeD
  \Samplenumber=0 %
  \csvreader{\jobname.csv}{%
    SampleName=\InsideCsvreaderSamplename,
    Depth1=\InsideCsvreaderDepthone,
    DepthTwo=\InsideCsvreaderDepthtwo,
    Depth3=\InsideCsvreaderDepththree,
  }{%
    \advance\Samplenumber by 1\relax
    %
    \ifnum#1=\Samplenumber\relax
      \expandtwice\gdef\GlobalSamplename{\InsideCsvreaderSamplename}%
      \expandtwice\gdef\GlobalDepthone{\InsideCsvreaderDepthone}%
      \expandtwice\gdef\GlobalDepthtwo{\InsideCsvreaderDepthtwo}%
      \expandtwice\gdef\GlobalDepththree{\InsideCsvreaderDepththree}%
    \fi
  }%
  \ifx\GlobalSamplename\UndEfINeD
    \@latex@error{Row #1 not available}{Seems your sheet of csv data does not have #1 rows.}%
    \global\let\GlobalSamplename=\GlobalSamplenamederrorefault
    \global\let\GlobalDepthone=\GlobalDepthoneerrorefault
    \global\let\GlobalDepthtwo=\GlobalDepthtwoerrorefault
    \global\let\GlobalDepththree=\GlobalDepththreeerrorefault
  \fi
  \endgroup
  \@esphack
}%
\makeatother

\begin{document}

\noindent\csvautotabular{\jobname.csv}

\bigskip

Reading data row number 2 via
\verb|\ReadToMacrosSampleDataRowNumber{2}| and
using placeholder-macros outside
\verb|\csvreader|:\ReadToMacrosSampleDataRowNumber{2}

The rock sampled was called \GlobalSamplename.

The rock sampled was called \GlobalSamplename.

\ifnum\GlobalDepthone>0 %
  The first sample hole was drilled to \GlobalDepthone~mm.
\fi

\ifnum\GlobalDepthtwo>0 %
  The second sample hole was drilled to \GlobalDepthtwo~mm.
\fi

\ifnum\GlobalDepththree>0 %
  The third sample hole was drilled to \GlobalDepththree~mm.
\fi

\noindent\hrulefill\null

Reading data row number 1 via
\verb|\ReadToMacrosSampleDataRowNumber{1}| and
using placeholder-macros outside
\verb|\csvreader|:\ReadToMacrosSampleDataRowNumber{1}

The rock sampled was called \GlobalSamplename.

The rock sampled was called \GlobalSamplename.

\ifnum\GlobalDepthone>0 %
  The first sample hole was drilled to \GlobalDepthone~mm.
\fi

\ifnum\GlobalDepthtwo>0 %
  The second sample hole was drilled to \GlobalDepthtwo~mm.
\fi

\ifnum\GlobalDepththree>0 %
  The third sample hole was drilled to \GlobalDepththree~mm.
\fi

\noindent\hrulefill\null

Reading non-existing data row number 3 via
\verb|\ReadToMacrosSampleDataRowNumber{3}| and
using placeholder-macros outside
\verb|\csvreader|---this yields an error-message and
errordefault-values:\ReadToMacrosSampleDataRowNumber{3}

The rock sampled was called \GlobalSamplename.

The rock sampled was called \GlobalSamplename.

\verb|\GlobalSamplename| is assigned the errordefault value \GlobalSamplename.

\verb|\GlobalDepthone| is assigned the errordefault value \GlobalDepthone.

\verb|\GlobalDepthtwo| is assigned the errordefault value \GlobalDepthtwo.

\verb|\GlobalDepththree| is assigned the errordefault value \GlobalDepththree.

\ifnum\GlobalDepthone>0 %
  The first sample hole was drilled to \GlobalDepthone~mm.
\fi

\ifnum\GlobalDepthtwo>0 %
  The second sample hole was drilled to \GlobalDepthtwo~mm.
\fi

\ifnum\GlobalDepththree>0 %
  The third sample hole was drilled to \GlobalDepththree~mm.
\fi

\end{document}

enter image description here

1

I did some more research based on what @egreg suggested and I figured I can use datatool to do what I want:

\begin{filecontents*}{rockdata.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
\end{filecontents*}

\documentclass[10pt]{report}
\usepackage{datatool}

\DTLloaddb{rocks}{rockdata.csv}

\begin{document}

% This replaces the \newcommand step
\DTLforeach*{rocks}% database label
{\SampleName=SampleName,\DepthOne=Depth1,\DepthTwo=DepthTwo,\DepthThree=Depth3}% Assignment
{}% Things can be done in here

% But things can also seemingly be done out here too
\noindent The rock sampled was called \SampleName.\\
\dtlifnumeq{\DepthOne}{0}{\\}{The first sample hole was drilled to \DepthOne~mm\\}
\dtlifnumeq{\DepthTwo}{0}{\\}{The second sample hole was drilled to \DepthTwo~mm\\}
\dtlifnumeq{\DepthThree}{0}{\\}{The third sample hole was drilled to \DepthThree~mm\\}

\end{document}

More guru way

Ultimately I can separate the ugly data-collecting machinery into a style file and use the labels created by datatools to run the conditional tests I want:

LaTex file:

\begin{filecontents*}{rockdata.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
\end{filecontents*}

\documentclass[10pt]{report}
\usepackage{datatool}

% User-defined package here
\usepackage{LoadRocks}

\begin{document}

% But things can also seemingly be done out here too
\noindent The rock sampled was called \SampleName.\\
\dtlifnumeq{\DepthOne}{0}{\\}{The first sample hole was drilled to \DepthOne~mm\\}
\dtlifnumeq{\DepthTwo}{0}{\\}{The second sample hole was drilled to \DepthTwo~mm\\}
\dtlifnumeq{\DepthThree}{0}{\\}{The third sample hole was drilled to \DepthThree~mm\\}

\end{document}

Style file LoadRocks.sty:

\ProvidesPackage{LoadRocks}[]
\DTLloaddb{rocks}{rockdata.csv}

\DTLforeach*{rocks}% database label
{\SampleName=SampleName,\DepthOne=Depth1,\DepthTwo=DepthTwo,\DepthThree=Depth3}% Assignment
{}

enter image description here

1
1

You're misunderstanding what \csvreader does.

% Make up some data in a CSV file
\begin{filecontents*}{\jobname.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
ROCK002,1,2,3
\end{filecontents*}

\documentclass[10pt]{report}
\usepackage{csvsimple}

\begin{document}

\csvautotabular{\jobname.csv}

\bigskip

\csvreader{\jobname.csv}{
    SampleName=\samplename,
    Depth1=\depthone,
    DepthTwo=\depthtwo,
    Depth3=\depththree,
  }
  {%
   The rock sampled was called \samplename.

   The rock sampled was called \samplename.

   \ifnum\depthone>0
     The first sample hole was drilled to \depthone~mm
   \fi

   \ifnum\depththree>0
     The third sample hole was drilled to \depththree~mm
   \fi

   \bigskip
  }

\end{document}

enter image description here

If you want to have all data available in any place of your document, you have to index the rows.

% Make up some data in a CSV file
\begin{filecontents*}{\jobname.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
ROCK002,1,2,3
\end{filecontents*}

\documentclass{article}
\usepackage{csvsimple}
\usepackage{xparse}
\usepackage{siunitx}

\ExplSyntaxOn
\NewDocumentCommand{\rocks}{m}
 {
  \csvreader{#1}{}
   {
    \int_gincr:N \g_fejoia_rocks_int
    \prop_new:c { g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
    \prop_gput:cno
     { g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
     { SampleName } { \csvcoli }
    \prop_gput:cno
     { g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
     { DepthOne } { \csvcolii }
    \prop_gput:cno
     { g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
     { DepthTwo } { \csvcoliii }
    \prop_gput:cno
     { g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
     { DepthThree } { \csvcoliv }
   }
}
\int_new:N \g_fejoia_rocks_int
\DeclareExpandableDocumentCommand{\getrock}{mm}
 {
  \prop_item:cn { g_fejoia_rocks_#1_prop } { #2 }
 }
\ExplSyntaxOff

\rocks{\jobname.csv}

\begin{document}

\csvautotabular{\jobname.csv}

\bigskip

\section{First rock}
The rock sampled was called \getrock{1}{SampleName}.

\ifnum\getrock{1}{DepthOne}>0
  The first sample hole was drilled to \SI{\getrock{1}{DepthOne}}{\mm}
\fi

\ifnum\getrock{1}{DepthThree}>0
  The third sample hole was drilled to \SI{\getrock{1}{DepthThree}}{\mm}
\fi

\section{Second rock}
The rock sampled was called \getrock{2}{SampleName}.

\ifnum\getrock{2}{DepthOne}>0
  The first sample hole was drilled to \SI{\getrock{2}{DepthOne}}{\mm}
\fi

\ifnum\getrock{2}{DepthThree}>0
  The third sample hole was drilled to \SI{\getrock{2}{DepthThree}}{\mm}
\fi

\end{document}

enter image description here

3
  • What happens when I wish to access the \samplename label outside the \csvreader context? I have the \csvreader in a separate style file and I create labels for each data point, which I intend to access throughout the document.
    – fejoa
    Commented Feb 9, 2017 at 23:43
  • @wryan Probably you want to look at datatool. Do you have different files for each sample?
    – egreg
    Commented Feb 9, 2017 at 23:48
  • I can cause my system to look at one csv file per sample rather than store everything in one csv. This post on using datatool with csv really helped
    – fejoa
    Commented Feb 10, 2017 at 1:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .