How to return multiple latex or org tables from an org-mode's source block?

260 Views Asked by At

My specific problem is that a lot of times I use python source blocks in org-mode to run the same statistical analysis on a lot of variables of a dataframe and then present them as latex tables. It becomes really tedious to do each analysis manually so I want to use a for loop:

#+begin_src python :exports results :session :results latex   
import pandas as pd   
df = pd.DataFrame({'a': [1, 2, 3, 4, 5],
                        'b': [9, 8, 7, 6, 5]})

for var in df.columns:
    df[var].value_counts().to_latex()
#+end_src

The problem is that it only returns the last value returned by the source block (last run of the for loop.

#+Results:
#+BEGIN_LaTeX
\begin{tabular}{lr}
\toprule
{} &  b \\
\midrule
7 &  1 \\
6 &  1 \\
5 &  1 \\
9 &  1 \\
8 &  1 \\
\bottomrule
\end{tabular}
#+END_LaTeX

So is there a way to actually get more than one latex or org table from a source block?

EDIT: Thinking on @dschwilk answer, what I would need is to return multiple #+Results blocks (one for every latex or org table) so that I may add text descriptions between them. Such as:

Description for table 1
#+RESULTS:
#+BEGIN_LaTeX
\begin{tabular}{lr}
\toprule
{} &  a \\
\midrule
5 &  1 \\
4 &  1 \\
3 &  1 \\
2 &  1 \\
1 &  1 \\
\bottomrule
\end{tabular}
#+END_LaTeX

Description for table 2    
#+RESULTS:
\begin{tabular}{lr}
\toprule
{} &  b \\
\midrule
7 &  1 \\
6 &  1 \\
5 &  1 \\
9 &  1 \\
8 &  1 \\
\bottomrule
\end{tabular}
#+END_LaTeX
3

There are 3 best solutions below

0
user3566180 On BEST ANSWER

I managed to get something close to what I want but I have to run multiple src_blocks (which I really wanted to avoid).

I have a source block that creates all the tables and stores them on a list and make a new src_block for each table and return it.

For example:

#+begin_src python :exports results :session :results silent)
  import pandas as pd
  results_tables = []
  d = pd.DataFrame({'a': [1, 2, 3, 4, 5],
                    'b': [9, 8, 7, 6, 5]})

  for var in d.columns:
      results_tables.append(d[var].value_counts().to_latex())
#+end_src

#+RESULTS:
#+begin_src python :exports results :session :results latex
results_tables[0]
#+end_src

#+RESULTS:
#+BEGIN_LaTeX
\begin{tabular}{lr}
\toprule
{} &  a \\
\midrule
5 &  1 \\
4 &  1 \\
3 &  1 \\
2 &  1 \\
1 &  1 \\
\bottomrule
\end{tabular}
#+END_LaTeX

#+begin_src python :exports results :session :results latex
results_tables[1]
#+end_src

#+RESULTS:
#+BEGIN_LaTeX
\begin{tabular}{lr}
\toprule
{} &  b \\
\midrule
7 &  1 \\
6 &  1 \\
5 &  1 \\
9 &  1 \\
8 &  1 \\
\bottomrule
\end{tabular}
#+END_LaTeX
1
dschwilk On

Would creating the text output you want in python work? For example, gather the produced LaTeX up and add \table{} and \caption:

#+begin_src python :exports results :session :results latex   
import pandas as pd   
df = pd.DataFrame({'a': [1, 2, 3, 4, 5],
                        'b': [9, 8, 7, 6, 5]})

var_dict = {}
for var in df.columns:
    var_dict[var] = df[var].value_counts().to_latex()

res = '\n'.join(['\\begin{table}\n\\caption{Variable: %s} \n\n %s\n\end{table}' % (key, value) for (key, value) in var_dict.items()])
res
#+end_src

#+results:
#+BEGIN_EXPORT latex
\begin{table}
\caption{Variable: a} 

 \begin{tabular}{lr}
\toprule
{} &  a \\
\midrule
5 &  1 \\
4 &  1 \\
3 &  1 \\
2 &  1 \\
1 &  1 \\
\bottomrule
\end{tabular}

\end{table}
\begin{table}
\caption{Variable: b} 

 \begin{tabular}{lr}
\toprule
{} &  b \\
\midrule
7 &  1 \\
6 &  1 \\
5 &  1 \\
9 &  1 \\
8 &  1 \\
\bottomrule
\end{tabular}

\end{table}
#+END_EXPORT
3
Bobby Durrett On

You could create a list and append the latex output to it in each loop:

latex_list=[]
for var in df.columns:
    latex_list.append(df[var].value_counts().to_latex())

Maybe print like this:

for e in latex_list:
    print(e)