[Tex/LaTex] Getting specific row/column values from a csv file to use in text, figures or table cells

csvdatabaseexternal filestables

I am trying to do the following:

  1. read a csv (or other similar format) external file with numerical and string data into an object;

  2. reference/get an specific value from such object to use into an specific cell of a table or in a figure.

That means, I do not want to convert a csv file or such into a table. I do not want to use packages to build a table.

So, for instance, suppose that I have the following code to generate a very simple table:

\documentclass[]{article}

\begin{document}

\begin{table}[]
    \centering
    \caption{My example}
    \begin{tabular}{lllll}
        1  & 2  & 3  & 4  & 5 \\
        6  & 7  & 8  & xyz  & 9 \\
        10 & 11 & 12 & 13 & 14
    \end{tabular}
\end{table}

\end{document}

Where it is written "xyz", I want to actually write a command that references/gets the value of a specific row/column of a csv or similar file. Is there a way to accomplish such a thing?

Best Answer

This uses lua function call to read the specific field in the CVS file. For example, given this CVS file in the directory

123,Poty city,Poti,red,-295731.42857144,617222.85714285
124,Lanchhuti city,Poti,red,-299217.14285715,647851.42857142
125,Ozurgeti city,Poti,red,-317217.14285715,648422.85714285
126,Samtredia city,Poti,red,-287502.85714287,672022.85714285

Then to insert, say the field located at row 2 and column 5, which is -299217.14285715, and the field at row 1 and column 3, which is Poty city in the Latex table, then the code is

\begin{tabular}{|l|l|l|l|l|}\hline
    1  & \getField{1}{2}   & 3  & 4                & 5 \\\hline
    6  & 7                 & 8  & \getField{2}{5}  & 9  \\\hline
    10 & 11                & 12 & 13               & 14 \\\hline
\end{tabular}

Which generates the table:

Mathematica graphics

The full code is below. I googled lua code to parse CVS files, there are few on the net, I found one that worked and used it. There does not seem to be a build in API in lua itself for this. The CVS file is read automatically. The cvs file name is hardcoded in the code below. The latex file needs to be compiled with lualatex not pdflatex

\documentclass[]{article}
\usepackage{luacode}

\begin{luacode*} -- CVS API: http://nocurve.com/simple-csv-read-and-write-using-lua/
 local function split(str, sep)     
     fields={}
     local matchfunc = string.gmatch(str, "([^"..sep.."]+)")
     if not matchfunc then return {str} end
     for str in matchfunc do
         table.insert(fields, str)
     end
     return fields
end

function read(path, sep, tonum)
    tonum = tonum or true
    sep = sep or ','
    local csvFile = {}
    local file = assert(io.open(path, "r"))
    for line in file:lines() do
        fields = split(line, sep)
        if tonum then -- convert numeric fields to numbers
            for i=1,#fields do
                fields[i] = tonumber(fields[i]) or fields[i]
            end
        end
        table.insert(csvFile, fields)
    end
    file:close()
    return csvFile
end

local m = read('./c.cvs') -- read file csv file to local matrix m

function getField(row,col) -- API to latex command below
tex.print(m[row][col])
end

\end{luacode*}
\newcommand\getField[2]{\directlua{getField(#1,#2) }}%

\begin{document}

\begin{table}[]
    \centering
    \caption{My example}
    \begin{tabular}{|l|l|l|l|l|}\hline
        1  & \getField{1}{2}   & 3  & 4                & 5 \\\hline
        6  & 7                 & 8  & \getField{2}{5}  & 9  \\\hline
        10 & 11                & 12 & 13               & 14 \\\hline
    \end{tabular}
\end{table}

\end{document}

Update

I figured why stop at just reading field? Why not add a Latex command to load the whole CVS file and convert it to a Latex table? This will be much more useful also. So here is a new implementation that loads a CVS file and makes a Latex table, all automatically. This will be useful for making reports and such.

The Latex command is called getCVS{"fileName"} and used as follows

\begin{table}[]
    \centering
    \caption{My CVS file in a Latex table}
    \getCVS{"c.cvs"}
\end{table}

Using the above CVS file, the table generated is

Mathematica graphics

The full code is below

\documentclass[]{article}
\usepackage{luacode}    
\begin{luacode*} -- CVS API http://nocurve.com/simple-csv-read-and-write-using-lua/
 local function split(str, sep)     
     fields={}
     local matchfunc = string.gmatch(str, "([^"..sep.."]+)")
     if not matchfunc then return {str} end
     for str in matchfunc do
         table.insert(fields, str)
     end
     return fields
end

function read(path, sep, tonum)
    tonum = tonum or true
    sep = sep or ','
    local csvFile = {}
    local file = assert(io.open(path, "r"))
    for line in file:lines() do
        fields = split(line, sep)
        if tonum then -- convert numeric fields to numbers
            for i=1,#fields do
                fields[i] = tonumber(fields[i]) or fields[i]
            end
        end
        table.insert(csvFile, fields)
    end
    file:close()
    return csvFile
end        
function getCVS(fileName)
 local m = read(fileName) -- read CVS file to matrix m
 local nRow = #m
 local nCol = #m[1]    
 tex.sprint("\\begin{tabular}{")
 for j=1,nCol do
     tex.sprint("|l")
 end
 tex.print("|}\\hline")

 for i = 1,nRow do
   for j = 1,nCol do
       tex.sprint(m[i][j])
       if j<nCol then tex.sprint("&") end
   end
   tex.print("\\\\ \\hline")
 end
 tex.print("\\end{tabular}")
end

\end{luacode*}
\newcommand\getCVS[1]{\directlua{getCVS(#1) }}%

\begin{document}    
\begin{table}[]
    \centering
    \caption{My CVS file in a Latex table}
    \getCVS{"c.cvs"}
\end{table}
\end{document}
Related Question