3

I am using the "functions" \findmin and findmax from here quite much to dynamical format and set plots from CSV data I read in.

In the same vein, I want a function \findFirstNonZeroIndex, which returns the integer index of the first element which is non-zero in a specified column. Since all my data are non-negative integers, non-zero is equal to being greater than 0.

Since the indices in pgfplotstable start with 0, how do I add 1 to this number?

From the pgfplotstable manuel, the iflessthan command seems capable of doing what I want:

\pgfplotstablesort[sort key={#2},sort cmp={
  iflessthan/.code args={#1#2#3#4}{%
    % here comes your code
  }%
}]{\result}{\datatable}

Some example data:

\begin{filecontents}{table.dat}
  x y
  1 0
  2 0
  3 30
  4 0
  5 50
\end{filecontents}

If possible, I do only want to use the column =y=index[1] and get something like \findFirstNonZeroIndex{\inputtable}{\outputvalue}. In this example, \outputvalue should be 3.

If it is easier, up to now I only use integer values in column y sorted ascending. So there would not be a 0 in row x=4.

I just do not know enough on how to get started. Any help would be appreciated.

Edit

Steven B. Segletes just answered my question with the help of package readarray.

Out of curiosity, is there a solution using the pgf framework?

3

Here's how you can do this using PGFPlotstable. I defined a macro that takes three arguments: The macro containing the table that was loaded using \pgfplotstableread, the name of the column, and the macro that contains the output. Note that PGFPlotstable uses zero based indexing, so if the first non-zero element is in the third row, the output will be 2. If no non-zero values are found, the output will be -1.

\documentclass{article}
\usepackage{filecontents}
\usepackage{pgfplotstable}

\begin{filecontents}{table.dat}
  x y
  1 0
  2 0
  3 30
  4 0
  5 50
\end{filecontents}

\newcommand\findFirstNonZeroIndex[3]{
    \def#3{-1}
    \pgfplotstableforeachcolumnelement{#2}\of{#1}\as\cell{
        \ifnum#3=-1
            \ifnum\cell>0
                \xdef#3{\pgfplotstablerow}
            \fi
        \fi
    }
}

\begin{document}

\pgfplotstableread{table.dat}\datatable
\findFirstNonZeroIndex{\datatable}{y}{\outputvalue}
\outputvalue

\end{document}
  • Thank you. As I understand this approach only works when comparing integers, as I requested (because of \ifnum ?!). How would one modify this solution to compare doubles, i.e. find the first row with double element > 0? – Marco Breitig Feb 24 '15 at 14:30
  • @MarcoBreitig: Do you have large numbers (greater than 16000)? – Jake Feb 24 '15 at 14:41
  • No, between 100 to 3000 elements per column. – Marco Breitig Feb 24 '15 at 15:08
  • 1
    @MarcoBreitig: Sorry, I meant the values of your floats. If they're under 16000 you can simply use \ifdim\cell pt>0pt, but if they're larger than that you'll need to use the fpu library. – Jake Feb 24 '15 at 15:14
  • In the same region, just counting. The double data is in [0,1], building ratios. Thx, I just tried it and it works. :-) – Marco Breitig Feb 24 '15 at 15:22
2

The macro \firstdata{column} will find the first positive entry in the specified column (beginning at row 2, since row 1 is alphabetic). Once found, it will output the value of column 1 from that row, which, in the data structure, is the datapoint number.

Thus, this MWE outputs the result 3.

The readarray package stores the file in one large \def, in this case \mydata. It then creates an array structure, here named thedata, by reading \mydata as a 2 column array of space-separated values. Individual cells of the array may be recalled with \arrayij{thedata}{row}{column} and compared against 0 to detect positiveness.

\documentclass{article}
\usepackage{readarray,filecontents,ifthen}
\begin{filecontents*}{table.dat}
  x y
  1 0
  2 0
  3 30
  4 0
  5 50
\end{filecontents*}
\readdef{table.dat}{\mydata}
\readArrayij{\mydata}{thedata}{2}
\newcounter{currentrow}
\def\firstdata#1{%
  \setcounter{currentrow}{1}%
  \whiledo{\value{currentrow}<\thedataROWS}{%
    \stepcounter{currentrow}%
    \ifnum\arrayij{thedata}{\thecurrentrow}{#1}>0
      \arrayij{thedata}{\thecurrentrow}{1}%
      \setcounter{currentrow}{\thedataROWS}%
    \fi%
  }%
}
\begin{document}
\firstdata{2}
\end{document}
  • Thx! I see you use the packages readarray and filecontents. Are they related to pgf or on their own? – Marco Breitig Feb 24 '15 at 12:27
  • 1
    They are on their own. I wrote the readarray package, but don't know a lick about pgf. – Steven B. Segletes Feb 24 '15 at 12:27
  • @MarcoBreitig I only use filecontents as a vehicle to create the data to begin with. If the data already exists in a separate file, or is placed inside of a \def within the document through some other means, the filecontents would not be required. – Steven B. Segletes Feb 24 '15 at 12:34
  • Ah of course. That is the pitfall if you do not give a MWE yourself. Thank you for pointing this out! – Marco Breitig Feb 24 '15 at 12:48

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.