📜 ⬆️ ⬇️

Bindings QCustomPlot for Python

Good afternoon, hrobrozhiteli!

Introduction


In his free time, he became interested in writing applications on PyQt5. And, at the end of May, MyWallet decided to rewrite its long- term home bookkeeping project from pluses into Python, as a number of architectural errors were made in the previous version, which we didn’t want to be fixed. Therefore, having collected PyQt5 from the source code for Fedora 21, I implemented all the functionality that was previously for about two weeks. And now the question arises in the visualization of data on expenses / income monthly. Since I had experience of data visualization using QCustomPlot , I wanted to do a visualization with this one. But unfortunately, did not find the binds.

Assembly


After viewing the source code of PyQt5, it was found that the generation of bindings was implemented using SIP ). SIP accepts something like a stripped-down header for class methods (of course, with its so-called annotations), and C ++ code for generating a ready-made python module at output.

So, to build the QCustomPlot module for Python, we need:
  1. Qt 5.x.
  2. SIP is the most recent version.
  3. PyQt 5.x.
  4. Compiled as a dynamically linked qcustomplot library compiled under Qt 5.x.
  5. A special type of file with a description of the interface classes of the library.

')
Having rummaged around github'u in search of a ready-made interface file for this, I came across a qcustomplot-python repository, the owner of which collected binds, true for PyQt4. By analogy, we get the qcustomplot.sip interface file.

In the same repository, you can also find configure.py, which, as you know, is necessary for building and installing Python modules. This file had to be adapted to the new version of PyQt.

Well, then the standard:

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


Make sure everything worked out for us, launch 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__'] >>> , 'QCPItemPosition', 'QCPItemRect', 'QCPItemStraightLine', 'QCPItemText', 'QCPItemTracer', 'QCPLayer', 'QCPLayerable', 'QCPLayout', 'QCPLayoutElement', 'QCPLayoutGrid', ' $ 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__'] >>> 


Well, to make it absolutely beautiful, I quote the code of one of the BarsDemo examples:
Sample code
 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()) 


Here is what happened:
Result
image


PS


Link to the source repository: QCustomPlot-PyQt5 . The repositories in the RPMS directory contain SRPM and RPM for Fedora21 (PyQt5, qcustomplot 1.3.1 and python3-qcustomplot).

All comments and suggestions are welcome. I hope this module is useful to you. Thanks for attention!

Source: https://habr.com/ru/post/260761/


All Articles