10

The math problem that I'm solving gives different analytical solutions in different scenarios, and I would like to summarize the result in a nice table. IPython Notebook renders the list nicely: for example:

import sympy
from pandas import DataFrame
from sympy import *
init_printing()
a, b, c, d = symbols('a b c d')
t = [[a/b, b/a], [c/d, d/c]]
t

enter image description here

However, when I summarize the answers into a table using DataFrame, the math cannot be rendered any more:

df = DataFrame(t, index=['Situation 1', 'Situation 2'], columns=['Answer1','Answer2'])
df

enter image description here

"print df.to_latex()" also gives the same result. I also tried "print(latex(t))" but it gives this after compiling in LaTex, which is alright, but I still need to manually convert it to a table:

enter image description here

How should I use DataFrame properly in order to render the math properly? Or is there any other way to export the math result into a table in Latex? Thanks!

Update: 01/25/14 Thanks again to @Jakob for solving the problem. It works perfectly for simple matrices, though there are still some minor problems for more complicated math expressions. But I guess like @asmeurer said, perfection requires an update in IPython and Pandas.

enter image description here

Update: 01/26/14 If I render the result directly, i.e. just print the list, it works fine: enter image description here

Titanic
  • 557
  • 1
  • 8
  • 21
  • [This](https://github.com/pydata/pandas/pull/5763) could be useful. – TomAugspurger Jan 22 '14 at 20:55
  • Thanks, @TomAugspurger. I changed one value in their 'df' to 'a/b', but the final table output still couldn't render the math well. – Titanic Jan 22 '14 at 21:09
  • I think this is a duplicate of http://stackoverflow.com/questions/18503351/how-to-get-a-latex-table-of-sympy-expressions-in-ipython-notebook (SO won't let me mark it as such because it can't find it in the duplicate dialog) – asmeurer Jan 23 '14 at 03:17
  • And in particular see my comment on that question. I don't think this is possible without an improvement in IPython and/or pandas. – asmeurer Jan 23 '14 at 03:20
  • Can you try rendering the complicated expressions directly? It is more likely that you reach the possibilities of MathJax and an update of IPython, sympy or pandas will not solve your problem, here. – Jakob Jan 26 '14 at 08:04
  • Yes. Rendering the complicated expression directly works well. It only messes up after adding it to DataFrame. Please see my update above – Titanic Jan 26 '14 at 11:47
  • After some digging I found a solution to your problem! See my update below. – Jakob Jan 27 '14 at 13:52
  • Awesome! It works perfectly! – Titanic Jan 27 '14 at 14:47

1 Answers1

6

MathJax is currently not able to render tables, hence the most obvious approach (pure latex) does not work.

However, following the advise of @asmeurer you should use an html table and render the cell content as latex. In your case this could be easily achieved by the following intermediate step:

from sympy import latex
tl = map(lambda tc: '$'+latex(tc)+'$',t)
df = DataFrame(tl, index=['Situation 1', 'Situation 2'], columns=['Answer'])
df

which gives:
enter image description here


Update:

In case of two dimensional data, the simple map function will not work directly. To cope with this situation the numpy shape, reshape and ravel functions could be used like:

import numpy as np
t = [[a/b, b/a],[a*a,b*b]]
tl=np.reshape(map(lambda tc: '$'+latex(tc)+'$',np.ravel(t)),np.shape(t))
df = DataFrame(tl, index=['Situation 1', 'Situation 2'], columns=['Answer 1','Answer 2'])
df

This gives:
enter image description here


Update 2:

Pandas crops cell content if the string length exceeds a certain number. E.g a more complicated expression like

t1 = [a/2+b/2+c/2+d/2]
tl=np.reshape(map(lambda tc: '$'+latex(tc)+'$',np.ravel(t1)),np.shape(t1))
df = DataFrame(tl, index=['Situation 1'], columns=['Answer 1'])
df

gives:
enter image description here

To cope with this issue a pandas package option has to be altered, for details see here. For the present case the max_colwidth has to be changed. The default value is 50, hence let's change it to 100:

import pandas as pd
pd.options.display.max_colwidth=100
df

gives:
enter image description here

akim
  • 8,255
  • 3
  • 44
  • 60
Jakob
  • 19,815
  • 6
  • 75
  • 94
  • Thanks, @Jakob. It works for the example above, but when the value is more than one-dimension, then it gives me error `ValueError: Shape of passed values is (1, 2), indices imply (2, 2)`. – Titanic Jan 25 '14 at 12:30
  • Just a quick guess, have you specified a second column title? If I omit a second column title I get exactly this error. Or could you be more specific on the type of data you are trying to display. – Jakob Jan 25 '14 at 20:05
  • To @Jakob: I did include the second column title, see the code in question: `columns=['Answer1','Answer2']`. The type of data that I'm trying to display is a bunch of math equations (using SymPy), which are analytical solutions from some economic optimization problem. – Titanic Jan 25 '14 at 22:22
  • @Titanic I've updated my answer to deal with 2d data. Strange that I didn't met your issue!? – Jakob Jan 25 '14 at 22:39
  • Thanks a lot, @Jakob. I didn't know I needed to add `np.ravel(t)),np.shape(t)` for 2d data. I'll look it up for more explanation. Thanks! – Titanic Jan 26 '14 at 02:39
  • Great it works! Just a quick comment, the original map function converts the 2d data to a 1d data (sympy.latex works well with lists), hence it is required to take care of each cell individually -> ravel reshapes the 2d array into 1d and the subsequent reshape builds up the 2d version again. – Jakob Jan 26 '14 at 08:01