Skip to content

Commit

Permalink
Merge branch 'latex'
Browse files Browse the repository at this point in the history
  • Loading branch information
NielXu committed Jan 9, 2019
2 parents b6c006a + 4839776 commit 4c9f35e
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
5 changes: 4 additions & 1 deletion .gitignore
@@ -1 +1,4 @@
__pycache__
__pycache__
.DS_Store


18 changes: 18 additions & 0 deletions README.md
Expand Up @@ -91,6 +91,24 @@ the output will be displayed on the console:
(1) (2)
```

# Latex
`lat.py` module allows you to convert from python math expressions to latex codes. For instance:
```python
tree = build("2+pi*sin(x+2)/cos(x^(y+1))") # Build a ast first
lat_expr = tolat(expr) # Convert to latex code
# The output will be:
# ${2+\frac{{\pi*sin({x+2})}}{cos({x^{y+1}})}}$
```
Furthermore, you can generate .tex file by given latex code. The file will only contains the header, footer and the given expression:
```python
totex(lat_expr, "/location") # Save the .tex file to given location with name
```
After that, a pdf file can be generated by compiling the .tex file
<b>(Please make sure you have pdflatex installed)</b>
```python
topdf("/location", "/target") # Compiling .tex file from source and save the files to target location
```

# Operations
Here are some symbols and special numbers that AST supports:

Expand Down
92 changes: 92 additions & 0 deletions lat.py
@@ -0,0 +1,92 @@
import ast
import subprocess
import os
from expr import is_number, is_letter, is_func, is_unary


header = r'''\documentclass{standalone}
\begin{document}
'''


footer = r'''\end{document}'''


latex_mapper = {
"/" : lambda x,y : "\\frac{"+x+"}{"+y+"}"
}


special_mapper = {
"pi" : lambda x : "\\pi"
}


def tolat(a):
"""Convert a AST to latex format code, so that a pdf of the
given formula can be generated.
"""
def _eval(n):
if n is None:
return ''
if n.sym in special_mapper:
return special_mapper[n.sym](n.sym)
if is_number(n.sym) or (is_letter(n.sym) and not is_func(n.sym)):
return n.sym
left = _eval(n.left)
right = _eval(n.right)
if n.sym in latex_mapper:
return latex_mapper[n.sym](left, right)
elif is_unary(n.sym):
return n.sym + '(' + _eval(n.right) + ')'
else:
return '{'+left + n.sym + right+'}'
return '$'+_eval(a.root)+'$'


def totex(lat, loc):
"""Convert a snippet of the latex code to a complete latex code by
adding header and footer. And save the file as .tex format to the
given location, or create new file if it does not exist. If the
header and footer were not added, the compile phase will fail.
"""
code = header + lat + footer
with open(loc, "w+") as f:
f.write(code)


def topdf(source, des, rm=False):
"""Compile the .tex file from given source location
and save the result to the given file destination.
If rm is enabled, all files except for the pdf file
will be removed after the compilation.
"""
command = ["pdflatex", "-output-directory", des, source]
subprocess.call(command)
if rm:
from os import listdir, remove
from os.path import isfile, join, splitext, basename
name = splitext(basename(source))[0]
for f in listdir(des):
if isfile(join(des, f)):
fname, ext = splitext(f)
if fname == name and ext != ".pdf":
remove(os.path.join(des, f))


def fastpdf(a, des, name, rm=False):
"""Fastest way to generate a pdf from given AST and without
saving .tex file or anything. Calling this method will directly
generate the pdf file. If rm is enabled, all files except for
the pdf file will be removed after the compilation.
"""
latex = tolat(a)
totex(latex, os.path.join(os.path.curdir, name+".tex"))
topdf(os.path.join(os.path.curdir, name+".tex"), des, rm=rm)
p = os.path.join(os.path.curdir, name+".tex")
if os.path.isfile(p):
os.remove(p)


# a = ast.build("2+pi*sin(x+2)/cos(x^(y+1))")
# fastpdf(a, "/Users/danielxu/Desktop/github/pexpr", "example", rm=True)

0 comments on commit 4c9f35e

Please sign in to comment.