Bindings QCustomPlot для Python

Добрий день, хаброжители!

Введення
У вільний від роботи час захопився написанням програм на PyQt5. І свій давній проект з ведення домашньої бухгалтерії MyWallet вирішив наприкінці травня переписати з плюсів на Python, так як в попередній версії були допущені ряд архітектурних помилок, які хотілося виправляти. Тому зібравши PyQt5 з исходников під Fedora 21, десь за два тижні реалізував весь функціонал, який був раніше. І тепер постає питання у візуалізації даних щодо витрат/доходів помісячно. Так як мав досвід візуалізації даних за допомогою QCustomPlot , хотів візуалізацію зробити з допомогою цієї либы. Але на жаль, не знайшов биндов.


Збірка
Після перегляду вихідного PyQt5 було з'ясовано, що генерація биндов реалізована за допомогою SIP). SIP приймає на вхід щось на зразок спрощеного заголовка методів класу (природно, зі своїми так званими анотаціями), а на виході генерує C++ код для створення готового модуля python.

Отже, для складання модуля QCustomPlot для Python нам знадобиться:
  1. Qt 5.x.
  2. SIP найбільш свіжої версії.
  3. PyQt 5.x.
  4. Зібрана у вигляді динамічних бібліотек qcustomplot, зібраної під Qt 5.x.
  5. Файл спеціального виду з описом інтерфейсу класів бібліотеки.


Понишпоривши по github'у пошуках готового файлу інтерфейсу для цієї либы, натрапив на репозиторій qcustomplot-python, власник якого зібрав бінди, правда для PyQt4. Діючи за аналогією, отримуємо файл інтерфейсу либы qcustomplot.sip.

В цьому ж репозиторії можна знайти і configure.py, який, як відомо, необхідний для збирання і встановлення модулів Python. Даний файл довелося адаптувати до нової версії PyQt.

Ну, а далі стандартно:

$ python3 configure.py build
$ make
$ sudo make install 


Переконаємося, що у нас все вийшло, запуститим IPy:
$ python3
>>> import qcustomplot
>>> dir(qcustomplot)
['QCP', 'QCPAbstractItem', 'QCPAbstractLegendItem', 'QCPAbstractPlottable', 'QCPAxis', 'QCPAxisRect', 'QCPBarData', 'QCPBars', 'QCPBarsGroup', 'QCPColorGradient', 'QCPColorMap', 'QCPColorMapData', 'QCPColorScale', 'QCPColorScaleAxisRectPrivate', 'QCPCurve', 'QCPCurveData', 'QCPData', 'QCPFinancial', 'QCPFinancialData', 'QCPGraph', 'QCPGrid', 'QCPItemAnchor', 'QCPItemBracket', 'QCPItemCurve', 'QCPItemEllipse', 'QCPItemLine', 'QCPItemPixmap', 'QCPItemPosition', 'QCPItemRect', 'QCPItemStraightLine', 'QCPItemText', 'QCPItemTracer', 'QCPLayer', 'QCPLayerable', 'QCPLayout', 'QCPLayoutElement', 'QCPLayoutGrid', 'QCPLayoutInset', 'QCPLegend', 'QCPLineEnding', 'QCPMarginGroup', 'QCPPainter', 'QCPPlotTitle', 'QCPPlottableLegendItem', 'QCPRange', 'QCPScatterStyle', 'QCPStatisticalBox', 'QCustomPlot', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
>>> 


Ну, а щоб зовсім було красиво, наводжу код одного з прикладів BarsDemo:
Код прикладу
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QColor, QPen
from qcustomplot import QCustomPlot, QCPBars, QCP

if __name__ == '__main__':

app = QApplication(sys.argv)

w = QCustomPlot()
regen = QCPBars(w.xAxis, w.yAxis)
nuclear = QCPBars(w.xAxis, w.yAxis)
fossil = QCPBars(w.xAxis, w.yAxis)

w.addPlottable(regen)
w.addPlottable(nuclear)
w.addPlottable(fossil)

pen = QPen()
pen.setWidthF(1.2)
fossil.setName('Fossil fuels')
pen.setColor(QColor(255, 131, 0))
fossil.setPen(pen)
fossil.setBrush(QColor(255, 131, 0, 50))
nuclear.setName('Nuclear')
pen.setColor(QColor(1, 92, 192))
nuclear.setPen(pen)
nuclear.setBrush(QColor(1, 92, 191, 50))
regen.setName('Regenerative')
pen.setColor(QColor(150, 222, 0))
regen.setPen(pen)
regen.setBrush(QColor(150, 222, 0, 70))
nuclear.moveAbove(fossil)
regen.moveAbove(nuclear)

ticks= [1, 2, 3, 4, 5, 6, 7]
labels = ['USA', 'Japan', 'Germany', 'France', 'UK', 'Italy', 'Canada']
w.xAxis.setAutoTicks(False)
w.xAxis.setAutoTickLabels(False)
w.xAxis.setTickVector(ticks)
w.xAxis.setTickVectorLabels(labels)
w.xAxis.setTickLabelRotation(60)
w.xAxis.setSubTickCount(0)
w.xAxis.grid().setVisible(True)
w.xAxis.setRange(0, 8)

w.yAxis.setRange(0, 12.1)
w.yAxis.setPadding(5)
w.yAxis.setLabel('Power Consumption in\nKilowatts per Capita (2007)')
w.yAxis.grid().setSubGridVisible(True)

grid_pen = QPen()
grid_pen.setStyle(Qt.SolidLine)
grid_pen.setColor(QColor(0, 0, 0, 25))
w.yAxis.grid().setSubGridPen(grid_pen)

fossil_data= [0.86 * 10.5, 0.83 * 5.5, 0.84 * 5.5, 0.52 * 5.8, 0.89 * 5.2, 0.90 * 4.2, 0.67 * 11.2]
nuclear_data= [0.08 * 10.5, 0.12 * 5.5, 0.12 * 5.5, 0.40 * 5.8, 0.09 * 5.2, 0.00 * 4.2, 0.07 * 11.2]
regen_data= [0.06 * 10.5, 0.05 * 5.5, 0.04 * 5.5, 0.06 * 5.8, 0.02 * 5.2, 0.07 * 4.2, 0.25 * 11.2]
fossil.setData(ticks, fossil_data)
nuclear.setData(ticks, nuclear_data)
regen.setData(ticks, regen_data)

w.legend.setVisible(True)
w.axisRect().insetLayout().setInsetAlignment(0, Qt.AlignTop|Qt.AlignHCenter)
w.legend.setBrush(QColor(255, 255, 255, 200))
legendPen = QPen()
legendPen.setColor(QColor(130, 130, 130, 200))
w.legend.setBorderPen(legendPen)
w.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom)

w.show()

sys.exit(app.exec())


Ось, що вийшло:
Результатimage


p.s.
Посилання на репозиторій з исходниками: QCustomPlot-PyQt5. В репозиторії в каталозі RPMS знаходяться SRPM і RPM для Fedora21 (PyQt5, qcustomplot 1.3.1 і python3-qcustomplot).

Всі коментарі та побажання вітаються. Сподіваюся, цей модуль вам стане в нагоді. Спасибі за увагу!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.