QCustomPlot Bindings for Python
Good afternoon, habrozhiteli!
In his spare time, he became interested in writing applications in PyQt5. And at the end of May, MyWallet decided to rewrite its long-standing project on conducting home accounting from Python pluses, as in the previous version a number of architectural errors were made that we wanted to correct. Therefore, collecting PyQt5 from source for Fedora 21, somewhere in two weeks I realized all the functionality that was previously. And now the question arises in the visualization of data on expenses / income on a monthly basis. Since I had experience visualizing data using QCustomPlot , I wanted to do the visualization using this lib. But unfortunately, I did not find the binds.
After looking at the source of PyQt5, it was found out that the generation of binds was implemented using SIP ). SIP receives something like a stripped-down header of class methods (naturally, with its so-called annotations), and generates C ++ code to create a ready-made python module.
So, to build the QCustomPlot module for Python, we need:
Rummaging through github in search of a ready-made interface file for this lib, I came across the qcustomplot-python repository , the owner of which collected binders, though for PyQt4. By analogy, we get the qcustomplot.sip interface file.
You can also find configure.py in the same repository, 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 standard:
Make sure that everything worked out for us, run IPy:
Well, in order to be completely beautiful, I give the code of one of the BarsDemo examples :
Here's what happened:
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 comes in handy. Thanks for attention!
Introduction
In his spare time, he became interested in writing applications in PyQt5. And at the end of May, MyWallet decided to rewrite its long-standing project on conducting home accounting from Python pluses, as in the previous version a number of architectural errors were made that we wanted to correct. Therefore, collecting PyQt5 from source for Fedora 21, somewhere in two weeks I realized all the functionality that was previously. And now the question arises in the visualization of data on expenses / income on a monthly basis. Since I had experience visualizing data using QCustomPlot , I wanted to do the visualization using this lib. But unfortunately, I did not find the binds.
Assembly
After looking at the source of PyQt5, it was found out that the generation of binds was implemented using SIP ). SIP receives something like a stripped-down header of class methods (naturally, with its so-called annotations), and generates C ++ code to create a ready-made python module.
So, to build the QCustomPlot module for Python, we need:
- Qt 5.x.
- SIP is the most recent version.
- PyQt 5.x.
- Assembled as a dynamic link library qcustomplot, assembled under Qt 5.x.
- A special kind of file with a description of the library class interface.
Rummaging through github in search of a ready-made interface file for this lib, I came across the qcustomplot-python repository , the owner of which collected binders, though for PyQt4. By analogy, we get the qcustomplot.sip interface file.
You can also find configure.py in the same repository, 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 standard:
$ python3 configure.py build
$ make
$ sudo make install
Make sure that everything worked out for us, run 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__']
>>>
Well, in order to be completely beautiful, I give the code of one of the BarsDemo examples :
Example 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's what happened:
Result
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 comes in handy. Thanks for attention!