0

Background

Hello, and thanks in advance for any insights you all can offer! Sorry for the very long post, but I noticed most new users are chastised for not sharing enough context. The TLDR version is I can't figure out how to use cell values read in with pgfplottable inside of boolean expressions from etools.

I am struggling to format certain pieces of text based on values being read in from a csv. Every year I have to create a document with more or less the same outline but with different values in certain places each year. For instance in 2015 the document might say:

The total nameplate capacity for the United States in 2015 was 1,159,748 MW.

but in 2016 this sentence should be updated to:

The total nameplate capacity for the United States in 2015 was 1,174,115 MW.

We are trying to transition this to a more efficient process with Python + LaTeX, with the actual data/figures being saved to csv's with Python and the documents being auto-updated with LaTeX reading in those csv's, the idea being that we could recreate all the documents with a single command-line script.

So far, with the help of this answer, I do not have any trouble actually reading in the csv's and printing it 'inline' into LaTeX. MWE:

\documentclass[16pt]{article}

\usepackage{pgfplotstable, pgfplots, etoolbox, xcolor}

\pgfplotstableread[col sep=comma]{data_values_test.csv}\sectionIIvars

\def\getcell#1#2#3{
    \pgfplotstablegetelem{#1}{#2}\of{#3}\pgfplotsretval%
}

\begin{document}
Renewable electricity in was \textbf{\getcell{8}{all_re}{\sectionIIvars}\% of total installed electricity capacity and \getcell{3}{all_re}\sectionIIvars}\% of total annual generation in the United States}.
\end{document}

Which spits out:

code output showing csv's properly read and printed

I can figure out a way to share the actual csv's with you but they're quite simple: 1st row is header/names (for instance you can see from the code there is a column titled 'all_re'). The first column are just names (character strings) to help us keep track of which row corresponds to which variable. The rest of the csv is just numbers. The '\getcell{8}{all_re}{\sectionIIvars}' function allows me to access the cell's content for row 8, column 'all_re' from the pre-defined table '\sectionIIvars'.

The Problem

The LaTeX outputs here will be passed to a team that will make them 'publication-ready' and we often need to pass this team multiple iterations of the document as figures are constantly being updated right up until the final publication. In order to reduce the time this external team needs to update the 'publication-ready' drafts we want to be able to automatically format values that have changed between iterations. For instance, if the second value in the above code snippet changed from 15.55 to 17.56 between iterations, we want that 17.56 to appear in red. Even if none of the code in the '.tex' file changed, just in the underlying csv. See below:

enter image description here

Unfortunately, I cannot get this to work! A few things I tried to no avail:

Latexdiff

I ruled this out immediately because based on what I could tell this only captures changes in the '.tex' files themselves. Since the actual .tex files don't change here it would not be able to help.

ifboolexpr

Most of my time has been spent here. This is all based on a command written in this answer. In each case I am trying to get the boolean function to compare an answer in one csv with an answer in another csv. The idea being that a Python script could compare answers in the '\sectionIIvars' table between iterations and write whether or not the actual answer had changed to a second csv (let's call it '\booltestsecII'). Latex could then print the answers in the '\sectionIIvars' but format them based on the '\booltestsecII'. The '\booltestsecII' would be the same size and shape of '\sectionIIvars' but with only 0's and 1's (for 'didn't change' and 'changed!' respectively).

Attempt 1

First I tried re-writing the getcell function to take an additional argument so that it would compare the same row and cell between '\sectionIIvars' and \booltestsecII':

\documentclass[16pt]{article}

\usepackage{pgfplotstable, pgfplots, etoolbox, xcolor}

\pgfplotstableread[col sep=comma]{data_values_test.csv}\sectionIIvars
\pgfplotstableread[col sep=comma]{Boolean_change_test.csv}\booltestsecII

\newcommand{\getcell}[4]{
      \ifboolexpr{ test {\ifnumcomp{\pgfplotstablegetelem{#1}{#2}\of{#4}\pgfplotsretval}{=}{1}}}
        {\pgfplotstablegetelem{#1}{#2}\of{#3}\pgfplotsretval}
        {\textcolor{red}{\pgfplotstablegetelem{#1}{#2}\of{#3}\pgfplotsretval}}
}

\begin{document}

Renewable electricity in was \textbf{\getcell{8}{all_re}{\sectionIIvars}{\booltestsecII}\% of total installed electricity capacity and \getcell{3}{all_re}{\sectionIIvars}{\booltestsecII}\% of total annual generation in the United States}.

\end{document}

This produced a "! Missing number, treated as zero." error (which tends to indicate a missing required function input) even though I thought I had provided all necessary inputs. If I try and proceed it produces a 'Missing = inserted for \ifnum.' error. If I try and proceed yet again it produces a '! You can't use `\numexpr' in horizontal mode.'

Attempt 2

I thought perhaps this had something to do with nested macros so I tried changing the function definition like so (based on this question):

\newcommand{\getcell}[4]{
      \ifboolexpr{ test {\ifnumcomp{\pgfplotstablegetelem{##1}{##2}\of{##4}\pgfplotsretval}{=}{1}}}
        {\pgfplotstablegetelem{##1}{##2}\of{##3}\pgfplotsretval}
        {\textcolor{red}{\pgfplotstablegetelem{##1}{##2}\of{##4}\pgfplotsretval}}
}

But that produced the same errors.

Attempt 3

I tried to simplify a bit and just focus on reading in a value from a csv and then comparing it to a numerical value using 'ifboolexpr' but that did not work either:

\documentclass[16pt]{article}

\usepackage{pgfplotstable, pgfplots, etoolbox, xcolor}

\pgfplotstableread[col sep=comma]{Boolean_change_test.csv}\booltestsecII

\newcommand{\checkchangesecII}[3]{
      \ifboolexpr{ test {\value{\pgfplotstablegetelem{#1}{#2}\of{#3}\pgfplotsretval}{=}{1}}}
        {do this}
        {\textcolor{red}{do that}}
}


\begin{document}

\checkchangesecII{0}{solar}{\booltestsecII}

\end{document}

This produces a '! Missing \endcsname inserted.' error and then a '! Extra \endcsname.' error before finally printing "1=1do that":

enter image description here

Summary

So far I haven't gotten anywhere but am very interested in hearing anyone's theories. I think it may be that even though LaTeX is reading in numerical values, perhaps it does not recognize them as such and is therefore unable to compare a 'numerical 1' with a 'character string 1'? I don't know how to check or correct this, hence why I'm writing here.

Thanks for any and all feedback. Sorry if this is a poorly formatted question, please let me know and I'll edit it as best as I can.

1

You were pretty close:

In attempt 1, you used

\ifboolexpr{ test {\ifnumcomp{\pgfplotstablegetelem{#1}{#2}\of{#4}\pgfplotsretval}{=}{1}}}

Here \pgfplotstablegetelem{#1}{#2}\of{#4} assigns 1 or 0 to \pgfplotsretval and afterwards you use \pgfplotsretval. Why is this required? Why doesn't \pgfplotstablegetelem{#1}{#2}\of{#4} directly give the return value? The problem is that some operations, like assignments and other stuff which is necessary in \pgfplotstablegetelem are not "expandable". That basically means that they can be executed, but they can not stand where a value is required. So using \pgfplotstablegetelem inside of \test where the value you want to test is expected wouldn't work. That's where \pgfplotsretval comes into play: You can move \pgfplotstablegetelem before the test and only use the expandable \pgfplotsretval on the inside:

\documentclass[16pt]{article}

\usepackage{pgfplotstable, pgfplots, etoolbox, xcolor}

\pgfplotstableread[col sep=comma]{data_values_test.csv}\sectionIIvars
\pgfplotstableread[col sep=comma]{Boolean_change_test.csv}\booltestsecII

\newcommand{\getcell}[4]{
      \pgfplotstablegetelem{#1}{#2}\of{#4}
      \ifboolexpr{ test {\ifnumcomp{\pgfplotsretval}{=}{1}}}
        {\pgfplotstablegetelem{#1}{#2}\of{#3}\pgfplotsretval}
        {\textcolor{red}{\pgfplotstablegetelem{#1}{#2}\of{#3}\pgfplotsretval}}
}

\begin{document}

Renewable electricity in was \textbf{\getcell{8}{all_re}{\sectionIIvars}{\booltestsecII}\% of total installed electricity capacity and \getcell{3}{all_re}{\sectionIIvars}{\booltestsecII}\% of total annual generation in the United States}.

\end{document}

enter image description here

| improve this answer | |
  • Ha! Works like a charm, thanks so much! And thanks for the solid explanation as well. Just goes to show one LaTeXer's insurmountable obstacle is another's speed bump ... – tjk8000 Aug 21 '19 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.