Skip to main content

PyQt5 widgets for rendering and editing mathematical formulas

Project description

pyqt5-math-widget

A PyQt5 library for rendering and interactively editing mathematical formulas. No LaTeX engine required — everything is rendered natively via QPainter.


Installation

pip install pyqt5-math-widget

Widgets

Class Purpose
MathView Read-only formula renderer
MathEditor Interactive formula editor with toolbar
MathDialog Modal dialog wrapping MathEditor

MathView — read-only renderer

Basic usage

from pyqt5_math_widget import MathView, FracNode, TextNode, SqrtNode

view = MathView()
view.set_node(FracNode(TextNode("1"), SqrtNode(TextNode("x"))))
layout.addWidget(view)

From a FormulaModel

from pyqt5_math_widget import MathView, FormulaModel

model = FormulaModel()
model.insert_frac()
model.insert_greek("pi")

view = MathView.from_model(model)

API

view.set_node(node)           # Set formula from a FormulaNode
view.set_model(model)         # Attach a FormulaModel
view.set_text("sin(x)")       # Set from plain text
view.set_zoom(1.5)            # Scale factor (default 1.0)
view.zoom()                   # -> float
view.set_background(color)    # QColor fill
view.set_transparent(True)    # Transparent background
view.set_padding(16, 12)      # Horizontal, vertical padding in px
view.set_foreground(color)    # Global text colour
view.to_pixmap(scale=2.0)     # -> QPixmap (for export/saving)
view.to_latex()               # -> str
view.to_sympy()               # -> str
view.to_text()                # -> str
view.model()                  # -> FormulaModel

MathEditor — interactive editor

Basic usage

from pyqt5_math_widget import MathEditor

editor = MathEditor()
editor.formula_changed.connect(lambda s: print("sympy:", s))
editor.latex_changed.connect(lambda s: print("latex:", s))
layout.addWidget(editor)

Constructor parameters

MathEditor(
    parent=None,
    show_toolbar=True,          # Show button toolbar below canvas
    toolbar_groups=None,        # List of group names to show (see below)
    zoom=1.0,                   # Initial zoom level
    readonly=False,             # Disable editing
)

Toolbar groups

Pass a subset of these strings to toolbar_groups:

Group Contents
"struct" fraction, sqrt, power, subscript, integral, sum, product, limit, matrix, ...
"operators" +, -, ·, ×, =, ≠, ≤, ≥, ±, ≈, ∂, ∇, ∈, ∀, →, ...
"greek" α β γ δ ε θ λ μ ν π ρ σ τ φ ψ ω Σ Π Γ Δ Θ Ω ∞ ...
"functions" sin cos tan arcsin log ln exp max min det tr ...
"edit" Delete, Clear, ← →, Undo, Redo
editor.set_toolbar_groups(["struct", "greek", "edit"])

Programmatic insertion API

editor.insert_frac()                   # Fraction a/b
editor.insert_sqrt(nth=False)          # Square root
editor.insert_sqrt(nth=True)           # Nth root
editor.insert_power(wrap_current=True) # Superscript
editor.insert_subscript()              # Subscript
editor.insert_power_sub()              # Combined x^n_m
editor.insert_parens("(", ")")         # Parentheses (any bracket pair)
editor.insert_parens("[", "]")         # Square brackets
editor.insert_abs()                    # |x|
editor.insert_integral(definite=True)  # Definite integral
editor.insert_integral(definite=False) # Indefinite integral
editor.insert_sum(with_limits=True)    # Sum Σ
editor.insert_product(with_limits=True)# Product Π
editor.insert_limit()                  # lim
editor.insert_matrix(2, 2, "(")        # 2x2 matrix with round brackets
editor.insert_matrix(3, 3, "[")        # 3x3 matrix with square brackets
editor.insert_overline()               # Overline
editor.insert_underline()              # Underline
editor.insert_func("sin")             # sin(...) function
editor.insert_greek("alpha")          # α
editor.insert_operator("->")          # →
editor.insert_text("x", italic=True)  # Plain character
editor.insert_node(my_node)           # Raw FormulaNode

Editing control

editor.delete_at_cursor()    # Delete at cursor (Backspace)
editor.clear()               # Clear entire formula
editor.undo()                # Ctrl+Z
editor.redo()                # Ctrl+Y
editor.can_undo()            # -> bool
editor.can_redo()            # -> bool
editor.cursor_left()         # Move cursor left
editor.cursor_right()        # Move cursor right

Output

editor.to_sympy()    # "integrate(sin(x), x)"
editor.to_latex()    # r"\int \sin(x)\,dx"
editor.to_text()     # "integrate(sin(x), x)"
editor.to_pixmap(scale=2.0)   # -> QPixmap

Display control

editor.set_zoom(1.5)
editor.set_readonly(True)
editor.set_toolbar_visible(False)
editor.model()                # -> FormulaModel for direct access
editor.set_model(model)       # Replace model

MathDialog — modal dialog

from pyqt5_math_widget import MathDialog
from PyQt5.QtWidgets import QDialog

dlg = MathDialog(
    parent=self,
    title="Insert Formula",
    initial_text="sin(x)",
    toolbar_groups=["struct", "greek", "edit"],
    show_output=True,
    zoom=1.1,
)
if dlg.exec_() == QDialog.Accepted:
    print(dlg.result_sympy())
    print(dlg.result_latex())
    print(dlg.result_text())

Connect the signal without blocking:

dlg = MathDialog(parent=self)
dlg.accepted_formula.connect(lambda s: print("inserted:", s))
dlg.show()

FormulaModel — programmatic tree manipulation

from pyqt5_math_widget import FormulaModel

model = FormulaModel()
model.insert_frac()
model.insert_text("x")
model.move_right()
model.insert_text("2")

print(model.to_sympy())  # (x) / (2)
print(model.to_latex())  # \frac{x}{2}

model.undo()
model.redo()
model.clear()

Formula node tree

Build a formula tree and display it statically:

from pyqt5_math_widget import (
    MathView, SeqNode, TextNode, FracNode, SqrtNode,
    PowerNode, IntegralNode, SumProdNode, MatrixNode,
    ParenNode, AbsNode,
)

root = SeqNode([
    TextNode("E"),
    TextNode("="),
    FracNode(
        TextNode("m"),
        SqrtNode(SeqNode([TextNode("1"), TextNode("-"), PowerNode(TextNode("v"), TextNode("2"))])),
    ),
])

view = MathView()
view.set_node(root)

Available node types

Class Description
TextNode(text, size, italic, bold, color) Text / symbol
PlaceholderNode(size) Editable placeholder
SeqNode(children) Horizontal sequence
FracNode(num, den) Fraction
SqrtNode(body, index=None) Square / nth root
PowerNode(base, exp) Superscript
SubNode(base, sub) Subscript
PowerSubNode(base, exp, sub) Combined sup+sub
ParenNode(body, left, right) Scalable brackets
AbsNode(body) Absolute value
IntegralNode(body, var, lower, upper) Integral
SumProdNode(kind, body, var, lower, upper) Sum / Product
LimitNode(body, var, approach, direction) Limit
MatrixNode(rows, left, right) Matrix
OverlineNode(body) Overline
UnderlineNode(body) Underline

Each node implements:

node.to_sympy()   # SymPy expression string
node.to_latex()   # LaTeX string
node.to_text()    # Plain text
node.measure(painter)  # -> RenderMetrics
node.draw(painter, x, y, hits, selected, cursor_id)
node.collect_ids()     # -> List[int]
node.clone()           # deep copy

Constants and maps

from pyqt5_math_widget import GREEK_MAP, OPERATOR_MAP

GREEK_MAP["alpha"]   # -> "α"
OPERATOR_MAP["->"]   # -> "→"

Integration

from pyqt5_math_widget import MathDialog
from PyQt5.QtWidgets import QPushButton

btn = QPushButton("\u03A3")
btn.clicked.connect(lambda: self._open_formula_editor())

def _open_formula_editor(self):
    dlg = MathDialog(initial_text=self._input.text(), parent=self.window())
    if dlg.exec_():
        self._input.setText(dlg.result_sympy())

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyqt5_math_widget-1.0.1-py3-none-any.whl (24.1 kB view details)

Uploaded Python 3

File details

Details for the file pyqt5_math_widget-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for pyqt5_math_widget-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ca967978a452c97f0b1c793bf1c4bcdd95cb5f06046d1a67ac03b2295fb72e60
MD5 82f5ca390bf6dc41383515d451f78733
BLAKE2b-256 afd16eb29b42fa2cc4d6343ba0cdec8c6e46b24df668cd606527c4a2a55380e2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page