Возможно ли для Python отображать LaTex в реальном времени в текстовом поле?
Я планирую создать графический интерфейс, в котором пользователь будет вводить свои математические выражения в текстовое поле, такое как виджет ввода Tkinter, и их выражения будут отображаться так же, как при вводе выражений в Symbolab.
Это возможно? Если да, то какие модули мне нужно использовать для этого?
3 ответа
Этот вопрос слишком широкий. Я не слишком уверен, должен ли он быть закрыт по этому вопросу. Тем не менее, вот фрагмент о том, как, по крайней мере, заставить латекс работать с Tk и matplotlib в интерактивном режиме.
Введите что-то в виджете ввода и нажмите клавишу ввода.
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()
Код должен создать окно, например, одно ниже:
Если вы хотите иметь хороший интерфейс, подобный их, этого будет недостаточно. Скорее всего, они имеют что-то вроде настройки преобразования текста в латекс в юникод. Или, может быть, даже напрямую из открытого текста в Unicode, но я не знаю ни одного парсера для математических выражений, который был бы так хорош, как латекс, так что все правила, вероятно, пришлось бы перекодировать, и это большая работа, поэтому они, скорее всего, пропустили этот шаг и вместо этого пусть латекс выполняет тяжелую работу, а затем просто анализирует латекс в Unicode/Utf8 или любую другую кодировку, которая может обработать все признаки.
Затем они выгружают все через что-то "лишнее" (т.е. шаблоны django и jinja), которое присваивает каждому элементу свой собственный класс CSS, основанный на типе элемента (бинарный оператор, переменная, экспонента...), чтобы получить полный математический вывод это выглядит красиво и все еще может быть скопировано.
В любом случае в этом вопросе так много всего происходит, что на самом деле невозможно дать краткий всеобъемлющий простой ответ.
Также существует решение, использующее sympy
. Частично он был вдохновлен ответом на этот сабреддит. В частности, он использует sympy.printing.preview
метод.
Это импортная часть
#!/usr/bin/python3
from tkinter import *
import sympy as sp
from PIL import Image, ImageTk
from io import BytesIO
Затем я определяю графический интерфейс, довольно стандартный материал. Я не приложил к этому слишком много усилий
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
не совместим со всеми форматами. Например, выбор формата вывода.pdf вызовет ошибку при определенииimg
и выбор.png вызовет проблемы при определении photo
. Формат.ps хорошо работает, и он тоже векторный, что приятно.
Наконец нужно
master = Tk()
root = Root(master)
master.mainloop()
вот как это выглядит
Примечание: там я увеличил изображение на 10 и уменьшил его на 1/2. Это только потому, что он выглядит немного ровнее и красивее, но в этом нет необходимости. Первое масштабирование использует векторную природу формата.ps, поэтому оно не теряет разрешение, а второе масштабирование действует на растеризованное изображение.
Это рабочий пример (python2, raspbian), хотя он не очень элегантный. Это одно из множества решений, но оно показывает все шаги от исходного файла латекса до программы Tkinter.
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()
Существует множество возможных вариантов: компилировать латекс в pdf вместо ps; использовать другие форматы файлов изображений; использовать библиотеку PIL для поддержки других форматов и т. д.
Это решение также очень неэффективно (не говорите мне, я знаю). Например, в моей системе ppm
файл 1,5 Мб. Уравнения также появляются в середине большой страницы (ее нужно обрезать).
Даже если он нуждается в улучшении, он отвечает на ваш вопрос (отображает документ LaTeX в программе Tkinter) и должен дать вам отправную точку.
Пара предложений:
- Конвертируйте Tex в pdf/image в бэкэнде и вместо этого визуализируйте изображение
- Рендеринг текста с помощью латекса с использованием matplotlib