Is it possible for Python to display LaTex in real time in a text box?

后端 未结 4 2077
孤独总比滥情好
孤独总比滥情好 2020-12-28 22:47

I plan on making a GUI where the user would input their mathematical expressions into a text box, such as Tkinter Entry Widget, and their expressions would be displayed in t

相关标签:
4条回答
  • 2020-12-28 23:10

    This is a working example (python2, raspbian), although it is not very elegant. This is one solution among a multitude, but it shows all the steps from the latex source file to the Tkinter program.

    from subprocess import call
    import Tkinter
    
    TEX = (  # use raw strings for backslash
      r"\documentclass{article}",
      r"\begin{document}",
      r"$$a^2 + b^2 = c^2$$",
      r"$$x=\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$",
      r"\end{document}",
    )
    
    with open('doc1.tex','w') as out_file:
      for t in TEX:
        out_file.write("%s\n" % t)
    
    call(['latex','doc1.tex'])
    call(['dvips','doc1.dvi','-o','doc1.ps'])
    call(['gs','-sDEVICE=ppmraw','-dNOPAUSE','-dBATCH','-dSAFER','-sOutputFile=doc1.ppm','doc1.ps'])
    
    root1 = Tkinter.Tk()
    img1 = Tkinter.PhotoImage(file="doc1.ppm")
    label1 = Tkinter.Label(root1, image=img1)
    label1.pack()
    root1.mainloop()
    

    There are a lot of possible variations: compile latex to pdf instead of ps; use other image file formats; use library PIL to support other formats, etc.

    This solution is also very inefficient (don't tell me, I know). For example, on my system, the ppm file is 1,5Mb. The equations also appear in the middle of a big page (it would need to be cropped).

    Even if it needs improvement, it answers your question (display a LaTeX document in a Tkinter program) and should give you a starting point.

    0 讨论(0)
  • 2020-12-28 23:21

    There is also a solution that uses sympy. It was partly inspired by an answer to this subreddit. In particular it uses the sympy.printing.preview method.

    This is the import part

    #!/usr/bin/python3
    
    from tkinter import *
    import sympy as sp
    from PIL import Image, ImageTk
    from io import BytesIO
    

    Then I define the GUI, pretty standard stuff. I didn't put too much effort into it

    class Root():
        def __init__(self, master):
            #Define the main window and the relevant widgets
            self.master = master
            master.geometry("800x300")
            self.strvar = StringVar()
            self.label = Label(master)
            self.entry = Entry(master, textvariable = self.strvar, width = 80)
            self.button = Button(text = "LaTeX!", command = self.on_latex)
            #The Euler product formula
            self.strvar.set("\prod_{p\,\mathrm{prime}}\\frac1{1-p^{-s}} = \sum_{n=1}^\infty \\frac1{n^s}")
    
            #Pack everything
            self.entry.pack()
            self.button.pack()
            self.label.pack()
    

    Then let's define the function that renders LaTeX (keep the indentation)

        def on_latex(self):
            expr = "$\displaystyle " + self.strvar.get() + "$"
    
            #This creates a ByteIO stream and saves there the output of sympy.preview
            f = BytesIO()
            the_color = "{" + self.master.cget('bg')[1:].upper()+"}"
            sp.preview(expr, euler = False, preamble = r"\documentclass{standalone}"
                       r"\usepackage{pagecolor}"
                       r"\definecolor{graybg}{HTML}" + the_color +
                       r"\pagecolor{graybg}"
                       r"\begin{document}",
                       viewer = "BytesIO", output = "ps", outputbuffer=f)
            f.seek(0)
            #Open the image as if it were a file. This works only for .ps!
            img = Image.open(f)
            #See note at the bottom
            img.load(scale = 10)
            img = img.resize((int(img.size[0]/2),int(img.size[1]/2)),Image.BILINEAR)
            photo = ImageTk.PhotoImage(img)
            self.label.config(image = photo)
            self.label.image = photo
            f.close()
    

    I choose the document class standalone in order to adapt the size of the produced document to its content. Then I use the package pagecolor to make the page blend seamlessly with the background. Notice also that PIL is not compatible with every format. Choosing an output of .pdf, for instance, will generate an error when defining img and choosing .png will give problems when defining photo. The format .ps works well and it's also vectorial, which is nice.

    Finally one needs

    master = Tk()
    root   = Root(master)
    master.mainloop()
    

    This is what it looks like


    Note: There I scaled the picture up by 10 and scaled it down by 1/2. This is only because it looks a bit smoother and nicer, but it's not needed. The first scaling uses the vectorial nature of the .ps format so it doesn't lose resolution, while the second scaling acts on the rasterized image.

    0 讨论(0)
  • 2020-12-28 23:22

    A couple of suggestions:

    • Convert Tex to pdf/image in the backend and render the image instead
    • Text rendering with Latex using matplotlib
    0 讨论(0)
  • 2020-12-28 23:27

    This question is way too broad. I'm not overly sure should it be closed for that matter. Nontheless, here's a snippet on how to, at least, get latex working with Tk and matplotlib interactively.

    Enter something in the Entry widget and press enter.

    import matplotlib
    import matplotlib.pyplot as plt
    
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    matplotlib.use('TkAgg')
    
    from Tkinter import *
    from ttk import *
    
    def graph(text):
        tmptext = entry.get()
        tmptext = "$"+tmptext+"$"
    
        ax.clear()
        ax.text(0.2, 0.6, tmptext, fontsize = 50)  
        canvas.draw()
    
    
    root = Tk()
    
    mainframe = Frame(root)
    mainframe.pack()
    
    text = StringVar()
    entry = Entry(mainframe, width=70, textvariable=text)
    entry.pack()
    
    label = Label(mainframe)
    label.pack()
    
    fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100)
    ax = fig.add_subplot(111)
    
    canvas = FigureCanvasTkAgg(fig, master=label)
    canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
    canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
    
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    root.bind('<Return>', graph)
    root.mainloop()
    

    code should produce a window such as one bellow:

    If you want to have a nice interface like theirs this will not be enough. They most likely have something like a plaintext to Latex to Unicode conversion setup. Or even perhaps directly from plaintext to Unicode but I am not aware of any parser for math expressions as nice as latex so all the rules would presumably have to be re-coded and that's a lot of work so they most likely skipped that step and instead let latex do the heavy lifting and then just parse latex to Unicode/Utf8 or whichever encoding can handle all the signs.

    Then they dumped everything through something "extra" (i.e. django and jinja templating) that assigns each element its own nice css class based on the type of element (binary operator, variable, exponent...) in order to have the full math output that looks nice and can still be copied.

    In any case there's so much going on in this question it's not really possible to give a concise all-encompassing easy answer.

    0 讨论(0)
提交回复
热议问题