Darstellung von Latexcode mit PyQt

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Brando
User
Beiträge: 171
Registriert: Donnerstag 28. Januar 2016, 15:36

Hallo, ich habe eine Möglichkeit gefunden eine Latexdarstellung eines Vektors zu bilden. Allerdings weiß ich nicht, wie ich das in einem Label von PyQt ausgebe. Folgenden Code habe ich nicht zum Laufen gebracht:

Code: Alles auswählen

from PyQt4 import QtGui, QtCore

import sys
from sympy.matrices import *
from sympy.printing import *
from IPython.display import display, HTML, Math, Latex, clear_output
# from ipywidgets import widgets
from random import randint


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    mw = QtGui.QWidget()
    x = Matrix()
    x = Matrix([randint(-20,20), randint(-20,20), randint(-20,20)])
    a1 = latex(x)
    a1 = a1.replace("left[", "left(")
    a1 = a1.replace("right]", "right)")
    print (a1)
    labelPT = QtGui.QLabel()
    labelPT.setText("$\langle" + a1 + "\\rangle$")
    labelPT.setAlignment(QtCore.Qt.AlignRight)

    labelRT = QtGui.QLabel()
    labelRT.setText('one two three four <b>five</b> six seven eight nine ten')
    labelRT.setAlignment(QtCore.Qt.AlignRight)

    vbox = QtGui.QVBoxLayout()
    vbox.addWidget(labelPT)
    vbox.addWidget(labelRT)

    mw.setLayout(vbox)
    mw.setMinimumWidth(30)
    mw.show()

    sys.exit(app.exec_())
Inbsbesondere die Zeile: labelPT.setText("$\langle" + a1 + "\\rangle$")
funktioniert nicht.
Brando
User
Beiträge: 171
Registriert: Donnerstag 28. Januar 2016, 15:36

Hallo, jetzt habe ich Code gefunden, der Latex darstellt in PyQt. Allerdings kann ich den nicht so lesen, wie ich es mir wünsche. Wie kann ich meinen Vektor a1 - der jetzt nur leer herumsteht in dem Code und auf Latex formatiert wurde - in Latex mit PyQt darstellen. Was von dem Code brauche ich dazu?

Code: Alles auswählen

# -*- coding: utf-8 -*-
"""
Created on Wed Mar 23 08:30:13 2016

@author: rk480158
"""

import sys
import matplotlib as mpl
from matplotlib.backends.backend_agg import FigureCanvasAgg
from PyQt4  import QtGui, QtCore
import matplotlib.pyplot as plt
from matplotlib import rcParams
from sympy.matrices import *
from sympy.printing import *
from IPython.display import display, HTML, Math, Latex, clear_output
# from ipywidgets import widgets
from random import randint

def mathTex_to_QPixmap(mathTex, fs):

    #---- set up a mpl figure instance ----

    fig = mpl.figure.Figure()
    fig.patch.set_facecolor('none')
    fig.set_canvas(FigureCanvasAgg(fig))
    renderer = fig.canvas.get_renderer()

    #---- plot the mathTex expression ----

    ax = fig.add_axes([0, 0, 1, 1])
    ax.axis('off')
    ax.patch.set_facecolor('none')
    t = ax.text(0, 0, mathTex, ha='left', va='bottom', fontsize=fs)

    #---- fit figure size to text artist ----

    fwidth, fheight = fig.get_size_inches()
    fig_bbox = fig.get_window_extent(renderer)

    text_bbox = t.get_window_extent(renderer)

    tight_fwidth = text_bbox.width * fwidth / fig_bbox.width
    tight_fheight = text_bbox.height * fheight / fig_bbox.height

    fig.set_size_inches(tight_fwidth, tight_fheight)

    #---- convert mpl figure to QPixmap ----

    buf, size = fig.canvas.print_to_buffer()
    qimage = QtGui.QImage.rgbSwapped(QtGui.QImage(buf, size[0], size[1],
                                                  QtGui.QImage.Format_ARGB32))
    qpixmap = QtGui.QPixmap(qimage)

    return qpixmap
    
    
class MyQTableWidget(QtGui.QTableWidget):   
    def __init__(self, parent=None):
        super(MyQTableWidget, self).__init__(parent)

        self.setHorizontalHeader(MyHorizHeader(self))

    def setHorizontalHeaderLabels(self, headerLabels, fontsize):

        qpixmaps = []
        indx = 0
        for labels in headerLabels:
            qpixmaps.append(mathTex_to_QPixmap(labels, fontsize))            
            self.setColumnWidth(indx, qpixmaps[indx].size().width() + 16)
            indx += 1

        self.horizontalHeader().qpixmaps = qpixmaps

        super(MyQTableWidget, self).setHorizontalHeaderLabels(headerLabels)


class MyHorizHeader(QtGui.QHeaderView):
    def __init__(self, parent):
        super(MyHorizHeader, self).__init__(QtCore.Qt.Horizontal, parent)

        self.setClickable(True)
        self.setStretchLastSection(True)

        self.qpixmaps = []

    def paintSection(self, painter, rect, logicalIndex):

        if not rect.isValid():
            return

        #------------------------------ paint section (without the label) ----

        opt = QtGui.QStyleOptionHeader()        
        self.initStyleOption(opt)

        opt.rect = rect
        opt.section = logicalIndex
        opt.text = ""

        #---- mouse over highlight ----

        mouse_pos = self.mapFromGlobal(QtGui.QCursor.pos())               
        if rect.contains(mouse_pos):
            opt.state |= QtGui.QStyle.State_MouseOver

        #---- paint ----

        painter.save()        
        self.style().drawControl(QtGui.QStyle.CE_Header, opt, painter, self)
        painter.restore()

        #------------------------------------------- paint mathText label ----

        qpixmap = self.qpixmaps[logicalIndex]

        #---- centering ----

        xpix = (rect.width() - qpixmap.size().width()) / 2. + rect.x()
        ypix = (rect.height() - qpixmap.size().height()) / 2.

        #---- paint ----

        rect = QtCore.QRect(xpix, ypix, qpixmap.size().width(),
                            qpixmap.size().height())
        painter.drawPixmap(rect, qpixmap)        

    def sizeHint(self):

        baseSize = QtGui.QHeaderView.sizeHint(self)

        baseHeight = baseSize.height()
        if len(self.qpixmaps):
            for pixmap in self.qpixmaps:
               baseHeight = max(pixmap.height() + 8, baseHeight)
        baseSize.setHeight(baseHeight)

        self.parentWidget().repaint()

        return baseSize

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    rcParams['text.usetex'] = True
    rcParams['text.latex.preamble'] = r'\usepackage{amsmath}'

    w = MyQTableWidget()
    w.verticalHeader().hide()
    x = Matrix()
    x = Matrix([randint(-20,20), randint(-20,20), randint(-20,20)])
    a1 = latex(x) 
    
    headerLabels = [
        '$C_{soil}=(1 - n) C_m + \\theta_w C_w$',
        '$k_{soil}=\\frac{\\sum f_j k_j \\theta_j}{\\sum f_j \\theta_j}$',
        '$\\lambda_{soil}=k_{soil} / C_{soil}$']
    
    # headerLabels = [ a1,a1,a1]
    w.setColumnCount(len(headerLabels))
    w.setHorizontalHeaderLabels(headerLabels, 25)        
    w.setRowCount(3)
    w.setAlternatingRowColors(True)

    k = 1
    for j in range(3):
        for i in range(3):
            w.setItem(i, j, QtGui.QTableWidgetItem('Value %i' % (k)))
            k += 1

    w.show() 
    w.resize(700, 200)
    # w.resize(700,700)
    sys.exit(app.exec_())
Wenn ich die Sache mit a1 aktiviere(headerLabels so geändert wie es auskommentiert ist], dann kommt folgende Fehlermeldung:

RuntimeError: LaTeX was not able to process the following string:
'\\\\left[\\\\begin{matrix}8\\\\\\\\3\\\\\\\\8\\\\end{matrix}\\\\right]'

Wo kommen die vielen \ her?
BlackJack

@Brando: Das ist der Versuch die \ so zu escapen das sie als Text dargestellt werden. Würde nicht passieren wenn Du nicht versuchen würdest Text zu setzen sondern eine Formel. Lass Dir mal `a1` ausgeben und vergleiche das mit den Formeln die Du manuell als LaTeX geschrieben hast, dann sollte Dir auffallen das `sympy.latex()` etwas weglässt was Du geschrieben hast. Schau Dir mal die Dokumention von der Funktion an, dann weisst Du a) was das ist was fehlt, und b) wie man das ändern kann. :-)
Brando
User
Beiträge: 171
Registriert: Donnerstag 28. Januar 2016, 15:36

Wenn ich noch einsetze:

headerLabels = ['$%s$'%a1,'$%s$'%a1,'$%s$'%a1]

dann funktioniert das Programm.
BlackJack

@Brando: Das löst das Problem aber an der falschen Stelle. Lass die `latex()`-Funktion gleich die richtige Zeichenkette erstellen, dann musst Du hinterher nichts ausbessern.
Antworten