Введение
В свободное от работы время увлекся написанием приложений на PyQt5. И свой давний проект по ведению домашней бухгалтерии MyWallet решил в конце мая переписать с плюсов на Python, так как в предыдущей версии были допущены ряд архитектурных ошибок, которые на хотелось исправлять. Поэтому собрав PyQt5 из исходников под Fedora 21, где-то за две недели реализовал весь функционал, который был ранее. И теперь встает вопрос в визуализации данных по расходам/доходам помесячно. Так как имел опыт визуализации данных с помощью QCustomPlot , хотел визуализацию сделать с помощью этой либы. Но к огорчению, не нашел биндов.
Сборка
После просмотра исходников PyQt5 было выяснено, что генерация биндов реализована с помощью SIP). SIP принимает на вход что-то вроде урезанного заголовка методов класса (естественно, со своими так называемыми аннотациями), а на выходе генерирует C++ код для создания готового модуля python.
Итак, для сборки модуля QCustomPlot для Python нам понадобится:
- Qt 5.x.
- SIP наиболее свежей версии.
- PyQt 5.x.
- Собранная в виде динамически подключаемой библиотеки qcustomplot, собранной под Qt 5.x.
- Файл специального вида с описанием интерфейса классов библиотеки.
Покопавшись по 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())
Вот, что получилось:
P.S.
Ссылка на репозиторий с исходниками: QCustomPlot-PyQt5. В репозитории в каталоге RPMS находятся SRPM и RPM для Fedora21 (PyQt5, qcustomplot 1.3.1 и python3-qcustomplot).
Все комментарии и пожелания приветствуются. Надеюсь, этот модуль вам пригодится. Спасибо за внимание!
This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий