pygae/galgebra

View on GitHub
galgebra/gprinter.py

Summary

Maintainability
C
1 day
Test Coverage
from .printer import GaLatexPrinter, isinteractive, Format_cnt, latex
import subprocess
import sys
import shutil
import inspect

from sympy import init_printing

try:
    from IPython.display import display, Math
except ImportError:
    pass

SYS_CMD = {'linux2': {'rm': 'rm', 'evince': 'evince', 'null': ' > /dev/null', '&': '&'},
           'linux': {'rm': 'rm', 'evince': 'evince', 'null': ' > /dev/null', '&': '&'},
           'win32': {'rm': 'del', 'evince': 'start', 'null': ' > NUL', '&': ''},
           'darwin': {'rm': 'rm', 'evince': 'open', 'null': ' > /dev/null', '&': '&'}}


class LaTeX:
    # LaTeX data
    line_sep = """
************************************************************************
"""
    latex_flg = False
    latex_str = ''

    latex_preamble = """
\\pagestyle{empty}
\\usepackage[utf8]{inputenc}
\\usepackage{amsmath}
\\usepackage{amsfonts}
\\usepackage{amssymb}
\\usepackage{amsbsy}
\\usepackage{tensor}
\\usepackage{listings}
\\usepackage{color}
\\usepackage{xcolor}
\\usepackage{bm}
\\usepackage{breqn}
\\definecolor{gray}{rgb}{0.95,0.95,0.95}
\\setlength{\\parindent}{0pt}
\\DeclareMathOperator{\\Tr}{Tr}
\\DeclareMathOperator{\\Adj}{Adj}
\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}
\\newcommand{\\lp}{\\left (}
\\newcommand{\\rp}{\\right )}
\\newcommand{\\paren}[1]{\\lp {#1} \\rp}
\\newcommand{\\half}{\\frac{1}{2}}
\\newcommand{\\llt}{\\left <}
\\newcommand{\\rgt}{\\right >}
\\newcommand{\\abs}[1]{\\left |{#1}\\right | }
\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}
\\newcommand{\\lbrc}{\\left \\{}
\\newcommand{\\rbrc}{\\right \\}}
\\newcommand{\\W}{\\wedge}
\\newcommand{\\prm}[1]{{#1}^{\\prime}}
\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}
\\newcommand{\\R}{\\dagger}
\\newcommand{\\deriv}[3]{\\bfrac{d^{#3}#1}{d{#2}^{#3}}}
\\newcommand{\\grade}[2]{\\left < {#1} \\right >_{#2}}
\\newcommand{\\f}[2]{{#1}\\lp{#2}\\rp}
\\newcommand{\\eval}[2]{\\left . {#1} \\right |_{#2}}
\\newcommand{\\Nabla}{\\boldsymbol{\\nabla}}
\\newcommand{\\eb}{\\boldsymbol{e}}
\\newcommand{\\bs}[1]{\\boldsymbol{#1}}
\\newcommand{\\grad}{\\bs{\\nabla}}
\\usepackage{float}
\\floatstyle{plain} % optionally change the style of the new float
\\newfloat{Code}{H}{myc}
\\lstloadlanguages{Python}
\\begin{document}

"""

    ip_cmds = \
        [r'$$\DeclareMathOperator{\Tr}{Tr}$$',
            r'$$\DeclareMathOperator{\Adj}{Adj}$$',
            r'$$\newcommand{\bfrac}[2]{\displaystyle\frac{#1}{#2}}$$',
            r'$$\newcommand{\lp}{\left (}$$',
            r'$$\newcommand{\rp}{\right )}$$',
            r'$$\newcommand{\paren}[1]{\lp {#1} \rp}$$',
            r'$$\newcommand{\half}{\frac{1}{2}}$$',
            r'$$\newcommand{\llt}{\left <}$$',
            r'$$\newcommand{\rgt}{\right >}$$',
            r'$$\newcommand{\abs}[1]{\left |{#1}\right | }$$',
            r'$$\newcommand{\pdiff}[2]{\bfrac{\partial {#1}}{\partial {#2}}}$$',
            r'$$\newcommand{\npdiff}[3]{\bfrac{\partial^{#3} {#1}}{\partial {#2}^{#3}}}$$',
            r'$$\newcommand{\lbrc}{\left \{}$$',
            r'$$\newcommand{\rbrc}{\right \}}$$',
            r'$$\newcommand{\W}{\wedge}$$',
            r'$$\newcommand{\prm}[1]{{#1}^{\prime}}$$',
            r'$$\newcommand{\ddt}[1]{\bfrac{d{#1}}{dt}}$$',
            r'$$\newcommand{\R}{\dagger}$$',
            r'$$\newcommand{\deriv}[3]{\bfrac{d^{#3}#1}{d{#2}^{#3}}}$$',
            r'$$\newcommand{\grade}[2]{\left < {#1} \right >_{#2}}$$',
            r'$$\newcommand{\f}[2]{{#1}\lp {#2} \rp}$$',
            r'$$\newcommand{\eval}[2]{\left . {#1} \right |_{#2}}$$',
            r'$$\newcommand{\bs}[1]{\boldsymbol{#1}}$$',
            r'$$\newcommand{\grad}{\bs{\nabla}}$$']

# ***********************************************************************


def gFormat(Fmode: bool = True, Dmode: bool = True, inverse='full'):
    r"""
    Turns on latex printing with configurable options.

    This redirects printer output so that latex compiler can capture it.

    ``Format()`` is also required for printing from *ipython notebook* (note that ``xpdf()`` is not needed to print from *ipython notebook*).

    Parameters
    ----------
    Fmode:
        Value for the ``omit_function_args`` setting of
        :class:`GaLatexPrinter`.
    Dmode:
        Value for the ``omit_partial_derivative_fraction`` setting of
        :class:`GaLatexPrinter`.
    """
    global Format_cnt

    GaLatexPrinter.set_global_settings(
        omit_partial_derivative_fraction=Dmode,
        omit_function_args=Fmode,
        inv_trig_style=inverse,
    )

    if Format_cnt == 0:
        Format_cnt += 1

        LaTeX.latex_flg = True

        if isinteractive():
            init_printing(use_latex='mathjax')
            from IPython.display import Math, display
            cmds = '\n'.join(LaTeX.ip_cmds)
            display(Math(cmds))

    return


def gprint(*xargs):
    """
    Print latex or text from python script or latex from Jupyter Notebook/Lab

    """
    x = []
    fstr = ''
    new_eq_flg = False
    i = 0
    for xi in xargs:
        if isinstance(xi, str):
            if r'\\' in xi and i > 0:
                if isinteractive():
                    xi_rep = xi.replace(r'\\', r'\end{equation*}@\begin{equation*} ')
                else:
                    xi_rep = xi.replace(r'\\', r'\end{equation*}'+'\n'+r'\begin{equation*} ')
                new_eq_flg = True
                fstr += xi_rep
            else:
                fstr += xi
        elif isinstance(xi, type):
            if LaTeX.latex_flg:
                fstr += r' \text{'+str(xi)+'} '
            else:
                fstr += str(xi)
        else:
            if LaTeX.latex_flg:
                x.append(latex(xi))
                if new_eq_flg:
                    new_eq_flg = False
                fstr += r' %s '
            else:
                x.append(str(xi))
                fstr += r' %s '

        i += 1

    if LaTeX.latex_flg:
        if isinteractive():
            lstr = fstr % tuple(x)
            if '@' in lstr:
                lines = lstr.split('@')
                lines[0] = r'\begin{equation*} '+lines[0]
                lines[-1] += r'\end{equation*}'
                for line in lines:
                    display(Math(line))
            else:
                display(Math(lstr))
        else:
            LaTeX.latex_str += r'\begin{equation*} ' + (fstr % tuple(x)) + r'\end{equation*} '+'\n'
    else:
        print(fstr % tuple(x))

    return


def gxpdf(filename=None, paper=(14, 11), crop=False, png=False, prog=False, debug=False, pt='10pt', pdfprog='pdflatex', evince=True, rm=True, null=True, documentclass='book'):

    """
    Post processes LaTeX output (see comments below), adds preamble and
    postscript, generates tex file, inputs file to latex, displays resulting
    pdf file.

    Arg         Value       Result
    pdfprog    'pdflatex'   Use pdfprog to generate pdf output, only generate tex if pdfprog is None
    crop        True        Use "pdfcrop" to crop output file (pdfcrop must be installed, linux only)
    png         True        Use "convert" to produce png output (imagemagick must be installed, linux only)

    We assume that if gxpdf() is called then gFormat() has been called at the beginning of the program.
    """

    latex_str = paper_format(paper, pt, documentclass)+LaTeX.latex_preamble+LaTeX.latex_str+r'\end{document}'
    # Clean up the latex string after printing
    LaTeX.latex_str = ''

    if filename is None:
        pyfilename = sys.argv[0]
        rootfilename = pyfilename.replace('.py', '')
        tex_filename = rootfilename + '.tex'
        pdf_filename = rootfilename + '.pdf'
    else:
        tex_filename = filename
        pdf_filename = tex_filename.replace('.tex', '.pdf')
        rootfilename = tex_filename.replace('.tex', '')

    if debug:
        print('latex file =', filename)

    with open(tex_filename, 'w') as latex_file:
        latex_file.write(latex_str)

    if pdfprog is not None:
        sys_cmd = SYS_CMD[sys.platform]
        pdflatex = shutil.which(pdfprog)

        if debug:  # Display latex excution output for debugging purposes
            print('pdflatex path =', pdflatex)
            # os.system(pdfprog + ' ' + filename[:-4])
        else:  # Works for Linux don't know about Windows
            if null:
                subprocess.call([pdfprog, tex_filename, sys_cmd['null']])
            else:
                subprocess.call([pdfprog, tex_filename])
            # os.system(pdfprog + ' ' + filename[:-4] + sys_cmd['null'])

        if evince:
            subprocess.call([sys_cmd['evince'], pdf_filename])

        # eval(input('!!!!Return to continue!!!!\n'))

        if rm:
            if debug:
                subprocess.call([sys_cmd['rm'], rootfilename+'.aux ', rootfilename+'.log'])
            else:
                subprocess.call([sys_cmd['rm'], rootfilename+'.aux ', rootfilename+'.log ', rootfilename+'.tex'])
        if crop:
            subprocess.call(['pdfcrop', pdf_filename])
            subprocess.call(['rm', pdf_filename])
            subprocess.call(['mv', rootfilename+'-crop.pdf', pdf_filename])
        if png:
            subprocess.call(['Pdf2Png', rootfilename])
    return


def paper_format(paper, pt, documentclass='book'):  # Set size of paper and font size

    if paper == 'letter':
        paper_size = """
\\documentclass[@10pt@,fleqn]{%s}
""" % documentclass
    else:
        paper_size = """
\\documentclass[@10pt@,fleqn]{%s}
\\usepackage[vcentering]{geometry}
""" % documentclass
        if paper == 'landscape':
            paper = [11, 8.5]
        paper_size += '\\geometry{papersize={' + str(paper[0]) + \
                      'in,' + str(paper[1]) + 'in},total={' + str(paper[0] - 1) + \
                      'in,' + str(paper[1] - 1) + 'in}}\n'

    paper_size = paper_size.replace('@10pt@', pt)

    return paper_size


def gPrint_Function():
    """ Print out the source of the current function """

    tmp_str = inspect.getsource(inspect.currentframe().f_back)
    if LaTeX.latex_flg:
        LaTeX.latex_str += r'\begin{lstlisting}[language=Python,showspaces=false,showstringspaces=false,backgroundcolor=\color{gray},frame=single]%s\end{lstlisting}\text{Code Output:}' % tmp_str
    else:
        print('\n' + 80 * '*')
        print(tmp_str)
        print('Code output:\n')
    return