【问题标题】:Is it possible for Python to display LaTex in real time in a text box?Python是否可以在文本框中实时显示LaTex?
【发布时间】:2016-04-15 00:12:30
【问题描述】:

我计划制作一个 GUI,用户可以在其中将他们的数学表达式输入到文本框中,例如 Tkinter Entry Widget,并且他们的表达式将以您在 @987654321 中键入表达式时看到的相同方式显示@。

这可能吗?如果是这样,那么我必须使用哪些模块才能完成此操作?

【问题讨论】:

  • 如果你尝试让 MathJax 在你的应用程序中工作会更好。 TeX 是一个大型发行版。
  • 好的,我去看看。

标签: python user-interface tkinter


【解决方案1】:

这个问题太笼统了。我不太确定是否应该就此关闭它。尽管如此,这里有一个关于如何让乳胶与 Tk 和 matplotlib 交互工作的 sn-p。

在 Entry 小部件中输入一些内容,然后按 Enter。

import matplotlib
import matplotlib.pyplot as plt

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk

def graph(event=None):
    tmptext = entry.get()
    tmptext = "$"+tmptext+"$"

    ax.clear()
    ax.text(0.2, 0.6, tmptext, fontsize=50)  
    canvas.draw()

root = tk.Tk()

mainframe = tk.Frame(root)
mainframe.pack()

entry = tk.Entry(mainframe, width=70)
entry.pack()

label = tk.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=True)
canvas._tkcanvas.pack(side="top", fill="both", expand=True)

ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

entry.insert(0, r"\sum_{i=0}^\infty x_i \frac{y_i}{z_i}")
graph()

root.bind("<Return>", graph)
root.mainloop()

代码应该会产生一个如下图所示的窗口:

如果您想拥有像他们这样的漂亮界面,这还不够。他们很可能有类似明文到 Latex 到 Unicode 的转换设置。或者甚至可能直接从纯文本到 Unicode,但我不知道有任何解析器可以像乳胶一样好的数学表达式,所以所有的规则可能都必须重新编码,这是很多工作,所以他们很可能跳过了这一步,而是让乳胶做繁重的工作,然后将乳胶解析为 Unicode/Utf8 或任何可以处理所有符号的编码。

然后他们通过“额外”的东西(即 django 和 jinja 模板)倾倒所有东西,这些东西根据元素的类型(二元运算符、变量、指数......)为每个元素分配自己的漂亮 css 类,以便拥有完整的数学输出看起来不错,仍然可以复制。

无论如何,这个问题的内容太多了,实际上不可能给出一个简洁的包罗万象的简单答案。

【讨论】:

  • 那不是 TeX 输出。这是一个近似值。
  • @SeanAllred;你是对的,这是 matplotlib 的数学文本渲染,它更快但选项更少。如果 OP 想要使用 Latex 渲染,他/她应该在 matplotlib 的 rc 设置中设置 text.usetex : True 。谢谢。
【解决方案2】:

还有一个使用sympy的解决方案。它的部分灵感来自对this subreddit 的回答。特别是它使用sympy.printing.preview 方法。

这是导入部分

#!/usr/bin/python3

from tkinter import *
import sympy as sp
from PIL import Image, ImageTk
from io import BytesIO

然后我定义了 GUI,非常标准的东西。我没有花太多力气

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()

然后我们定义渲染LaTeX的函数(保持缩进)

    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()

我选择文档类standalone 是为了使生成的文档的大小适应其内容。然后我使用包pagecolor 使页面与背景无缝融合。另请注意,PIL 与每个format 都不兼容。例如,选择 .pdf 的输出会在定义 img 时产生错误,而选择 .png 会在定义 photo 时产生问题。 .ps 格式效果很好,而且它也是矢量的,这很好。

终于有人需要了

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

这就是它的样子


注意: 在那里,我将图片放大了 10 倍,然后将其缩小了 1/2。这只是因为它看起来更平滑和更好,但它不是必需的。第一次缩放使用 .ps 格式的矢量特性,因此不会丢失分辨率,而第二次缩放作用于光栅化图像。

【讨论】:

  • 出现“RuntimeError:latex program is not installed”怎么办?
  • 如果你手动编写一个.tex文件并在终端上用pdflatex编译它会产生输出吗?
  • 是的,但是我提到了 pdflatex.exe 由 compiler= 定位的完整路径。只有这样它才会输出一个 tex 文件和一个 .pdf。我该如何修改上面的代码提到了路径?我认为这将解决问题
  • 如果您查看source code,它使用函数find_executable 来查找可执行文件。它在PATH 环境变量中查找路径。我不知道如何在 Windows 上编辑它,但它非常适合谷歌搜索(e.g.)
  • 很高兴在这里看到 Matplotlib 免费解决方案。奖励积分:用于将sympy 表达式直接转换为图像。缺点:着色对我不起作用,它尝试安装pagecolor 并因错误而崩溃(RuntimeError: 'latex' 异常退出并出现以下输出)。另外,我需要将选项更改为png,因为它因错误而崩溃(OSError: Unable to locate Ghostscript on paths)。
【解决方案3】:

这是一个工作示例(python2,raspbian),虽然它不是很优雅。这是众多解决方案中的一种,但它显示了从乳胶源文件到 Tkinter 程序的所有步骤。

from subprocess import call
try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk

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 file:
    file.write("\n".join(TEX))

call(["latex", "doc1.tex"])
call(["dvips", "doc1.dvi", "-o", "doc1.ps"])
call(["gs", "-sDEVICE=ppmraw", "-dNOPAUSE", "-dBATCH", "-dSAFER", "-sOutputFile=doc1.ppm", "doc1.ps"])

root1 = tk.Tk()
img1 = tk.PhotoImage(file="doc1.ppm")
label1 = tk.Label(root1, image=img1)
label1.pack()
root1.mainloop()

有很多可能的变化:将latex编译为pdf而不是ps;使用其他图像文件格式;使用库 PIL 支持其他格式等。

这个解决方案也效率很低(别告诉我,我知道)。例如,在我的系统上,ppm 文件为 1,5Mb。方程式也出现在大页面的中间(需要裁剪)。

即使它需要改进,它也会回答您的问题(在 Tkinter 程序中显示 LaTeX 文档),并且应该为您提供一个起点。

【讨论】:

    【解决方案4】:

    几个建议:

    • 在后端将 Te​​x 转换为 pdf/image 并渲染图像
    • 使用 Latex 进行文本渲染,使用 matplotlib

    【讨论】:

      猜你喜欢
      • 2018-07-03
      • 2019-10-25
      • 2020-11-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多