I was recently asked about using sympy
in Python to print \(LaTeX\) formulas in RMarkdown notebooks. I misunderstood the question at first but after some thought I realized that I didn’t know if it would work… but I should try it.
Yes, printing elements of a matrix. So it's due to the prog languages' differences ( R vs Python), not rmarkdown vs Jupyter Notebook? pic.twitter.com/Any4qIDHS7
— Eyayaw T. Beze (@EyayawBeze) July 25, 2020
I knew that I could run Python chunks in an RMarkdown notebook. And I knew how to change the working conda environment so I could install sympy
. But I wasn’t so sure about getting the \(LaTeX\) produced by sympy
to print out properly.
I tend to explicitly set my conda environment in my RMD file. Here I set it to r-reticulate
which should be the default, but I do this so that it will remind me later what environment I’m using. Because when I come back to this in a few months I’ll have forgotten.
library(reticulate)
use_condaenv(condaenv = "r-reticulate", required=TRUE)
to install conda packages from R or from your Rmd file you can do something like:
reticulate::conda_install("r-reticulate","sympy")
Or you can use conda to activate the environment and install sympy
with conda install -c anaconda sympy
The we can do magic like this:
Then we can run some Python chunks that depend on sympy
from sympy import *
x = symbols('x')
a = Integral(cos(x)*exp(x), x)
output = Eq(a, a.doit())
print('$' + latex(output) + '$')
\(\int e^{x} \cos{\left(x \right)}\, dx = \frac{e^{x} \sin{\left(x \right)}}{2} + \frac{e^{x} \cos{\left(x \right)}}{2}\)
This works because of two pieces of code. One of which you can’t see above. In the code chunk that runs above I set the language to python and told it to print out the results asis
:
{python, results='asis'}
The asis
flag tells knitr
not to molest the resulting text string, just send it straight to the display. When I did that at first I ended up with this:
from sympy import *
x = symbols('x')
a = Integral(cos(x)*exp(x), x)
output = Eq(a, a.doit())
print( latex(output) )
e^{x} , dx = +
Which baffled me because that’s \(LaTeX\) but it’s not rendered… then (with some google help) I realized that in RMarkdown if we have stand alone \(LaTeX\) we wrap them in dollar signs to tell knitr
to render them… in this case using MathJax. So I just added $
around the content like this:
print('$' + latex(output) + '$')
Of course if I were going to do this more than once I’d make a function to do it like this:
from sympy import *
def latex_rmd_print(input_string):
print('$' + latex(input_string) + '$')
Which then makes the earlier example a lot simpler… but don’t forget the results='asis'
in any code chunk that calls latex_rmd_print
:
x = symbols('x')
a = Integral( cos(x)*exp(x), x )
latex_rmd_print( Eq(a, a.doit()) )
\(\int e^{x} \cos{\left(x \right)}\, dx = \frac{e^{x} \sin{\left(x \right)}}{2} + \frac{e^{x} \cos{\left(x \right)}}{2}\)