• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Bindings for graphics lib QCustomPlot2 for PyQt5


Commit MetaInfo

Revisióne9bb26714ec875c7f5d68a4876f2a610e82b8bd3 (tree)
Tiempo2018-12-01 17:55:28
AutorChristopher Gilbert <christopher.john.gilbert@gmai...>
CommiterChristopher Gilbert

Log Message

Ported more of the QCustomPlot demos to Python

Cambiar Resumen

Diferencia incremental

--- a/all.sip
+++ b/all.sip
@@ -35,13 +35,13 @@ QCustomPlot Website/Contact: http://www.qcustomplot.com
3535 %Include axistickerlog.sip
3636 %Include axis.sip
3737 %Include scatterstyle.sip
38-//%Include datacontainer.sip
38+%Include datacontainer.sip
3939 %Include plottable.sip
4040 %Include item.sip
4141 %Include core.sip
4242 %Include plottable1d.sip
4343 %Include colorgradient.sip
44-//#include "selectiondecorator-bracket.h"
44+%Include selectiondecorator-bracket.sip
4545 %Include layoutelement-axisrect.sip
4646 %Include layoutelement-legend.sip
4747 %Include layoutelement-textelement.sip
--- a/axistickertext.sip
+++ b/axistickertext.sip
@@ -8,6 +8,117 @@
88 */
99
1010
11+%MappedType QMap<double, QString>
12+{
13+%TypeHeaderCode
14+// Include the library interface to the type being mapped.
15+#include <QMap>
16+#include <QString>
17+%End
18+
19+%ConvertFromTypeCode
20+ PyObject *d = PyDict_New();
21+
22+ if (!d)
23+ return 0;
24+
25+ QMap<double, QString>::const_iterator it = sipCpp->constBegin();
26+ QMap<double, QString>::const_iterator end = sipCpp->constEnd();
27+
28+ while (it != end)
29+ {
30+ PyObject *kobj = PyFloat_FromDouble(it.key());
31+
32+ if (!kobj)
33+ {
34+ Py_DECREF(d);
35+ return 0;
36+ }
37+
38+ QString *v = new QString(it.value());
39+ PyObject *vobj = sipConvertFromNewType(v, sipType_QString,
40+ sipTransferObj);
41+
42+ if (!vobj)
43+ {
44+ delete v;
45+ Py_DECREF(kobj);
46+ Py_DECREF(d);
47+ return 0;
48+ }
49+
50+ int rc = PyDict_SetItem(d, kobj, vobj);
51+
52+ Py_DECREF(vobj);
53+ Py_DECREF(kobj);
54+
55+ if (rc < 0)
56+ {
57+ Py_DECREF(d);
58+ return 0;
59+ }
60+
61+ ++it;
62+ }
63+
64+ return d;
65+%End
66+
67+%ConvertToTypeCode
68+ if (!sipIsErr)
69+ return PyDict_Check(sipPy);
70+
71+ QMap<double, QString> *qm = new QMap<double, QString>;
72+
73+ SIP_SSIZE_T pos = 0;
74+ PyObject *kobj, *vobj;
75+
76+ while (PyDict_Next(sipPy, &pos, &kobj, &vobj))
77+ {
78+ PyErr_Clear();
79+ double k = PyFloat_AsDouble(kobj);
80+
81+ if (PyErr_Occurred())
82+ {
83+ PyErr_Format(PyExc_TypeError,
84+ "a key has type '%s' but 'float' is expected",
85+ Py_TYPE(kobj)->tp_name);
86+
87+ delete qm;
88+ *sipIsErr = 1;
89+
90+ return 0;
91+ }
92+
93+ int vstate;
94+ QString* v = reinterpret_cast<QString*>(
95+ sipForceConvertToType(
96+ vobj, sipType_QString, sipTransferObj, SIP_NOT_NONE, &vstate, sipIsErr
97+ )
98+ );
99+
100+ if (*sipIsErr)
101+ {
102+ PyErr_Format(PyExc_TypeError,
103+ "a value has type '%s' but 'QString' is expected",
104+ Py_TYPE(vobj)->tp_name);
105+ sipReleaseType(v, sipType_QString, vstate);
106+ delete qm;
107+ return 0;
108+ }
109+
110+ qm->insert(k, *v);
111+
112+ sipReleaseType(v, sipType_QString, vstate);
113+ }
114+
115+ *sipCppPtr = qm;
116+
117+ return sipGetState(sipTransferObj);
118+%End
119+};
120+
121+
11122 class QCPAxisTickerText : public QCPAxisTicker
12123 {
13124 %TypeHeaderCode
@@ -17,17 +128,17 @@ public:
17128 QCPAxisTickerText();
18129
19130 // getters:
20- // QMap<double, QString> &ticks();
131+ QMap<double, QString> &ticks();
21132 int subTickCount() const;
22133
23134 // setters:
24- // void setTicks(const QMap<double, QString> &ticks);
135+ void setTicks(const QMap<double, QString> &ticks);
25136 void setTicks(const QVector<double> &positions, const QVector<QString> labels);
26137 void setSubTickCount(int subTicks);
27138
28139 // non-virtual methods:
29140 void clear();
30141 void addTick(double position, QString label);
31- // void addTicks(const QMap<double, QString> &ticks);
142+ void addTicks(const QMap<double, QString> &ticks);
32143 void addTicks(const QVector<double> &positions, const QVector<QString> &labels);
33144 };
--- /dev/null
+++ b/datacontainer.sip
@@ -0,0 +1,56 @@
1+/** PyQt5 binding for QCustomPlot v2.0.0
2+ *
3+ * Authors: Dmitry Voronin, Giuseppe Corbelli, Christopher Gilbert
4+ * License: MIT
5+ *
6+ * QCustomPlot author: Emanuel Eichhammer
7+ * QCustomPlot Website/Contact: http://www.qcustomplot.com
8+ */
9+
10+
11+template <DataType>
12+class QCPDataContainer
13+{
14+%TypeHeaderCode
15+#include <QCustomPlot/src/datacontainer.h>
16+%End
17+public:
18+ //typedef QVector<DataType>::const_iterator const_iterator;
19+ //typedef QVector<DataType>::iterator iterator;
20+
21+ QCPDataContainer();
22+
23+ // getters:
24+ int size() const;
25+ bool isEmpty() const;
26+ bool autoSqueeze() const;
27+
28+ // setters:
29+ void setAutoSqueeze(bool enabled);
30+
31+ // non-virtual methods:
32+ void set(const QCPDataContainer<DataType> &data);
33+ void set(const QVector<DataType> &data, bool alreadySorted=false);
34+ void add(const QCPDataContainer<DataType> &data);
35+ void add(const QVector<DataType> &data, bool alreadySorted=false);
36+ void add(const DataType &data);
37+ void removeBefore(double sortKey);
38+ void removeAfter(double sortKey);
39+ void remove(double sortKeyFrom, double sortKeyTo);
40+ void remove(double sortKey);
41+ void clear();
42+ void sort();
43+ void squeeze(bool preAllocation=true, bool postAllocation=true);
44+
45+ //const_iterator constBegin() const;
46+ //const_iterator constEnd() const;
47+ //iterator begin();
48+ //iterator end();
49+ //const_iterator findBegin(double sortKey, bool expandedRange=true) const;
50+ //const_iterator findEnd(double sortKey, bool expandedRange=true) const;
51+ //const_iterator at(int index) const;
52+ QCPRange keyRange(bool &foundRange, QCP::SignDomain signDomain=QCP::sdBoth);
53+ QCPRange valueRange(bool &foundRange, QCP::SignDomain signDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange());
54+ QCPDataRange dataRange() const;
55+ //void limitIteratorsToDataRange(const_iterator &begin, const_iterator &end, const QCPDataRange &dataRange) const;
56+};
--- a/examples/interactions/mainwindow.py
+++ b/examples/interactions/mainwindow.py
@@ -7,20 +7,224 @@
77 # License: MIT
88 #
99 # QCustomPlot author: Emanuel Eichhammer
10-# QCustomPlot Website/Contact: http://www.qcustomplot.com
10+# QCustomPlot Website/Contact: http:#www.qcustomplot.com
1111
12-import math
12+import math, random
1313
14-from PyQt5.QtCore import QTimer, QPointF, Qt
15-from PyQt5.QtGui import QPen, QBrush, QColor, QRadialGradient
16-from PyQt5.QtWidgets import QMainWindow
14+from PyQt5.QtCore import Qt
15+from PyQt5.QtGui import QPen, QColor, QFont
16+from PyQt5.QtWidgets import QMainWindow, QLineEdit, QMenu, QAction, QInputDialog
1717 from PyQt5.uic import loadUi
1818
19-# import QCustomPlot2
19+import QCustomPlot2
20+
21+from QCustomPlot2 import QCPTextElement, QCPAxis, QCPDataSelection, QCPLegend, QCPPlottableLegendItem, QCPScatterStyle, QCP
2022
21-# from QCustomPlot2 import QCP
2223
2324 class MainWindow(QMainWindow):
25+
2426 def __init__(self, argv, parent=None):
2527 super().__init__(parent)
26- loadUi("mainwindow.ui", self)
\ No newline at end of file
28+ loadUi("examples/interactions/mainwindow.ui", self)
29+
30+ self.customPlot.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom or QCP.iSelectAxes or
31+ QCP.iSelectLegend or QCP.iSelectPlottables)
32+ self.customPlot.xAxis.setRange(-8, 8)
33+ self.customPlot.yAxis.setRange(-5, 5)
34+ self.customPlot.axisRect().setupFullAxesBox()
35+
36+ self.customPlot.plotLayout().insertRow(0)
37+ self.title = QCPTextElement(self.customPlot, "Interaction Example", QFont("sans", 17, QFont.Bold))
38+ self.customPlot.plotLayout().addElement(0, 0, self.title)
39+
40+ self.customPlot.xAxis.setLabel("x Axis")
41+ self.customPlot.yAxis.setLabel("y Axis")
42+ self.customPlot.legend.setVisible(True)
43+ legendFont = QFont()
44+ legendFont.setPointSize(10)
45+ self.customPlot.legend.setFont(legendFont)
46+ self.customPlot.legend.setSelectedFont(legendFont)
47+ self.customPlot.legend.setSelectableParts(QCPLegend.spItems) # legend box shall not be selectable, only legend items
48+
49+ self.addRandomGraph()
50+ self.addRandomGraph()
51+ self.addRandomGraph()
52+ self.addRandomGraph()
53+ self.customPlot.rescaleAxes()
54+
55+ # connect slot that ties some axis selections together (especially opposite axes):
56+ self.customPlot.selectionChangedByUser.connect(self.selectionChanged)
57+ # connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed:
58+ self.customPlot.mousePress.connect(self.mousePress)
59+ self.customPlot.mouseWheel.connect(self.mouseWheel)
60+
61+ # make bottom and left axes transfer their ranges to top and right axes:
62+ self.customPlot.xAxis.rangeChanged.connect(self.customPlot.xAxis2.setRange)
63+ self.customPlot.yAxis.rangeChanged.connect(self.customPlot.yAxis2.setRange)
64+
65+ # connect some interaction slots:
66+ self.customPlot.axisDoubleClick.connect(self.axisLabelDoubleClick)
67+ self.customPlot.legendDoubleClick.connect(self.legendDoubleClick)
68+ self.title.doubleClicked.connect(self.titleDoubleClick)
69+
70+ # connect slot that shows a message in the status bar when a graph is clicked:
71+ self.customPlot.plottableClick.connect(self.graphClicked)
72+
73+ # setup policy and connect slot for context menu popup:
74+ self.customPlot.setContextMenuPolicy(Qt.CustomContextMenu)
75+ self.customPlot.customContextMenuRequested.connect(self.contextMenuRequest)
76+
77+ def titleDoubleClick(self, event):
78+ try:
79+ title = QCPTextElement(self.sender())
80+ except (ValueError, TypeError):
81+ title = None
82+ if not title is None:
83+ # Set the plot title by double clicking on it
84+ newTitle, ok = QInputDialog.getText(self, "QCustomPlot example", "New plot title:", QLineEdit.Normal, title.text())
85+ if ok:
86+ title.setText(newTitle)
87+ self.customPlot.replot()
88+
89+ def axisLabelDoubleClick(self, axis, part):
90+ # Set an axis label by double clicking on it
91+ if part == QCPAxis.spAxisLabel: # only react when the actual axis label is clicked, not tick label or axis backbone
92+ newLabel, ok = QInputDialog.getText(self, "QCustomPlot example", "New axis label:", QLineEdit.Normal, axis.label())
93+ if ok:
94+ axis.setLabel(newLabel)
95+ self.customPlot.replot()
96+
97+ def legendDoubleClick(self, legend, item):
98+ # Rename a graph by double clicking on its legend item
99+ if not item is None: # only react if item was clicked (user could have clicked on border padding of legend where there is no item, then item is 0)
100+ plItem = QCPPlottableLegendItem(item)
101+ newName, ok = QInputDialog.getText(self, "QCustomPlot example", "New graph name:", QLineEdit.Normal, plItem.plottable().name())
102+ if ok:
103+ plItem.plottable().setName(newName)
104+ self.customPlot.replot()
105+
106+ def selectionChanged(self):
107+ # normally, axis base line, axis tick labels and axis labels are selectable separately, but we want
108+ # the user only to be able to select the axis as a whole, so we tie the selected states of the tick labels
109+ # and the axis base line together. However, the axis label shall be selectable individually.
110+ #
111+ # The selection state of the left and right axes shall be synchronized as well as the state of the
112+ # bottom and top axes.
113+ #
114+ # Further, we want to synchronize the selection of the graphs with the selection state of the respective
115+ # legend item belonging to that graph. So the user can select a graph by either clicking on the graph itself
116+ # or on its legend item.
117+
118+ # make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
119+ if (self.customPlot.xAxis.selectedParts() & QCPAxis.spAxis or self.customPlot.xAxis.selectedParts() & QCPAxis.spTickLabels or
120+ self.customPlot.xAxis2.selectedParts() & QCPAxis.spAxis or self.customPlot.xAxis2.selectedParts() & QCPAxis.spTickLabels):
121+ self.customPlot.xAxis2.setSelectedParts(QCPAxis.spAxis or QCPAxis.spTickLabels)
122+ self.customPlot.xAxis.setSelectedParts(QCPAxis.spAxis or QCPAxis.spTickLabels)
123+ # make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
124+ if (self.customPlot.yAxis.selectedParts() & QCPAxis.spAxis or self.customPlot.yAxis.selectedParts() & QCPAxis.spTickLabels or
125+ self.customPlot.yAxis2.selectedParts() & QCPAxis.spAxis or self.customPlot.yAxis2.selectedParts() & QCPAxis.spTickLabels):
126+ self.customPlot.yAxis2.setSelectedParts(QCPAxis.spAxis or QCPAxis.spTickLabels)
127+ self.customPlot.yAxis.setSelectedParts(QCPAxis.spAxis or QCPAxis.spTickLabels)
128+
129+ # synchronize selection of graphs with selection of corresponding legend items:
130+ for i in range(self.customPlot.graphCount()):
131+ graph = self.customPlot.graph(i)
132+ item = self.customPlot.legend.itemWithPlottable(graph)
133+ if item.selected() or graph.selected():
134+ item.setSelected(True)
135+ graph.setSelection(QCPDataSelection(graph.data().dataRange()))
136+
137+ def mousePress(self):
138+ # if an axis is selected, only allow the direction of that axis to be dragged
139+ # if no axis is selected, both directions may be dragged
140+
141+ if self.customPlot.xAxis.selectedParts() & QCPAxis.spAxis:
142+ self.customPlot.axisRect().setRangeDrag(self.customPlot.xAxis.orientation())
143+ elif self.customPlot.yAxis.selectedParts() & QCPAxis.spAxis:
144+ self.customPlot.axisRect().setRangeDrag(self.customPlot.yAxis.orientation())
145+ else:
146+ self.customPlot.axisRect().setRangeDrag(Qt.Horizontal or Qt.Vertical)
147+
148+ def mouseWheel(self):
149+ # if an axis is selected, only allow the direction of that axis to be zoomed
150+ # if no axis is selected, both directions may be zoomed
151+
152+ if self.customPlot.xAxis.selectedParts() & QCPAxis.spAxis:
153+ self.customPlot.axisRect().setRangeZoom(self.customPlot.xAxis.orientation())
154+ elif self.customPlot.yAxis.selectedParts() & QCPAxis.spAxis:
155+ self.customPlot.axisRect().setRangeZoom(self.customPlot.yAxis.orientation())
156+ else:
157+ self.customPlot.axisRect().setRangeZoom(Qt.Horizontal or Qt.Vertical)
158+
159+ def addRandomGraph(self):
160+ n = 50 # number of points in graph
161+ xScale = (random.random() + 0.5)*2
162+ yScale = (random.random() + 0.5)*2
163+ xOffset = (random.random() - 0.5)*4
164+ yOffset = (random.random() - 0.5)*10
165+ r1 = (random.random() - 0.5)*2
166+ r2 = (random.random() - 0.5)*2
167+ r3 = (random.random() - 0.5)*2
168+ r4 = (random.random() - 0.5)*2
169+ x, y = [], []
170+ for i in range(n):
171+ x.append((i/float(n)-0.5)*10.0*xScale + xOffset)
172+ y.append((math.sin(x[i]*r1*5)*math.sin(math.cos(x[i]*r2)*r4*3)+r3*math.cos(math.sin(x[i])*r4*2))*yScale + yOffset)
173+
174+ self.customPlot.addGraph()
175+ self.customPlot.graph().setName("New graph {}".format(self.customPlot.graphCount()-1))
176+ self.customPlot.graph().setData(x, y)
177+ self.customPlot.graph().setLineStyle(random.randint(1, 6))
178+ if random.randint(0, 100) > 50:
179+ self.customPlot.graph().setScatterStyle(QCPScatterStyle(random.randint(1, 15)))
180+ graphPen = QPen()
181+ graphPen.setColor(QColor(random.randint(10, 255), random.randint(10, 255), random.randint(10, 255)))
182+ graphPen.setWidthF(random.random()*2+1)
183+ self.customPlot.graph().setPen(graphPen)
184+ self.customPlot.replot()
185+
186+ def removeSelectedGraph(self):
187+ if self.customPlot.selectedGraphs().size() > 0:
188+ self.customPlot.removeGraph(self.customPlot.selectedGraphs().first())
189+ self.customPlot.replot()
190+
191+ def removeAllGraphs(self):
192+ self.customPlot.clearGraphs()
193+ self.customPlot.replot()
194+
195+ def contextMenuRequest(self, pos):
196+ menu = QMenu(self)
197+ menu.setAttribute(Qt.WA_DeleteOnClose)
198+
199+ if self.customPlot.legend.selectTest(pos, False) >= 0: # context menu on legend requested
200+ menu.addAction("Move to top left", self.moveLegend).setData(int(Qt.AlignTop or Qt.AlignLeft))
201+ menu.addAction("Move to top center", self.moveLegend).setData(int(Qt.AlignTop or Qt.AlignHCenter))
202+ menu.addAction("Move to top right", self.moveLegend).setData(int(Qt.AlignTop or Qt.AlignRight))
203+ menu.addAction("Move to bottom right", self.moveLegend).setData(int(Qt.AlignBottom or Qt.AlignRight))
204+ menu.addAction("Move to bottom left", self.moveLegend).setData(int(Qt.AlignBottom or Qt.AlignLeft))
205+ else: # general context menu on graphs requested
206+ menu.addAction("Add random graph", self.addRandomGraph)
207+ if len(self.customPlot.selectedGraphs()) > 0:
208+ menu.addAction("Remove selected graph", self.removeSelectedGraph)
209+ if self.customPlot.graphCount() > 0:
210+ menu.addAction("Remove all graphs", self.removeAllGraphs)
211+
212+ menu.popup(self.customPlot.mapToGlobal(pos))
213+
214+ def moveLegend(self):
215+ try:
216+ contextAction = QAction(self.sender())
217+ except (ValueError, TypeError):
218+ contextAction = None
219+ if not contextAction is None: # make sure self slot is really called by a context menu action, so it carries the data we need
220+ dataInt, ok = contextAction.data().toInt()
221+ if ok:
222+ self.customPlot.axisRect().insetLayout().setInsetAlignment(0, dataInt)
223+ self.customPlot.replot()
224+
225+ def graphClicked(self, plottable, dataIndex):
226+ # since we know we only have QCPGraphs in the plot, we can immediately access interface1D()
227+ # usually it's better to first check whether interface1D() returns non-zero, and only then use it.
228+ dataValue = plottable.interface1D().dataMainValue(dataIndex)
229+ message = "Clicked on graph '{}' at data point #{} with value {}.".format(plottable.name(), dataIndex, dataValue)
230+ self.statusBar.showMessage(message, 2500)
--- a/examples/interactions/mainwindow.ui
+++ b/examples/interactions/mainwindow.ui
@@ -94,7 +94,7 @@ p, li { white-space: pre-wrap; }
9494 <customwidget>
9595 <class>QCustomPlot</class>
9696 <extends>QWidget</extends>
97- <header>../../qcustomplot.h</header>
97+ <header>QCustomPlot2</header>
9898 <container>1</container>
9999 </customwidget>
100100 </customwidgets>
--- a/examples/plots/mainwindow.py
+++ b/examples/plots/mainwindow.py
@@ -7,45 +7,48 @@
77 # License: MIT
88 #
99 # QCustomPlot author: Emanuel Eichhammer
10-# QCustomPlot Website/Contact: http://www.qcustomplot.com
10+# QCustomPlot Website/Contact: http:#www.qcustomplot.com
1111
12-import math
12+import math, random
1313
14-from PyQt5.QtCore import QTimer, QPointF, Qt
15-from PyQt5.QtGui import QPen, QBrush, QColor, QRadialGradient
14+from PyQt5.QtCore import QTime, QTimer, QPointF, Qt, QLocale, QDateTime, QMargins
15+from PyQt5.QtGui import QPen, QBrush, QColor, QRadialGradient, QFont, QPainterPath, QLinearGradient, QPixmap
1616 from PyQt5.QtWidgets import QMainWindow
1717 from PyQt5.uic import loadUi
1818
1919 import QCustomPlot2
2020
21-from QCustomPlot2 import QCP
21+from QCustomPlot2 import (QCP, QCPAxisTickerTime, QCPColorMap, QCPRange, QCPColorScale, QCPAxis, QCPColorGradient,
22+ QCPMarginGroup, QCPScatterStyle, QCPGraph, QCustomPlot, QCPLineEnding, QCPBars, QCPErrorBars, QCPAxisTickerDateTime,
23+ QCPAxisTickerText, QCPGraphData, QCPAxisTickerPi, QCPTextElement, QCPItemBracket, QCPItemText, QCPItemTracer,
24+ QCPItemPosition, QCPItemCurve)
2225
2326 class MainWindow(QMainWindow):
2427 def __init__(self, argv, parent=None):
2528 super().__init__(parent)
26- loadUi("mainwindow.ui", self)
29+ loadUi("examples/plots/mainwindow.ui", self)
2730
2831 self._available_demos = {
2932 0: self.setupQuadraticDemo,
3033 1: self.setupSimpleDemo,
31-# 2: self.setupSincScatterDemo,
32-# 3: self.setupScatterStyleDemo,
33-# 4: self.setupScatterPixmapDemo,
34-# 5: self.setupLineStyleDemo,
35-# 6: self.setupDateDemo,
36-# 7: self.setupTextureBrushDemo,
37-# 8: self.setupMultiAxisDemo,
38-# 9: self.setupLogarithmicDemo,
39-# 10: self.setupRealtimeDataDemo,
34+ 2: self.setupSincScatterDemo,
35+ 3: self.setupScatterStyleDemo,
36+ 4: self.setupScatterPixmapDemo,
37+ 5: self.setupLineStyleDemo,
38+ 6: self.setupDateDemo,
39+ 7: self.setupTextureBrushDemo,
40+ 8: self.setupMultiAxisDemo,
41+ 9: self.setupLogarithmicDemo,
42+ 10: self.setupRealtimeDataDemo,
4043 11: self.setupParametricCurveDemo,
41-# 12: self.setupBarChartDemo,
42-# 13: self.setupStatisticalDemo,
43-# 14: self.setupSimpleItemDemo,
44-# 15: self.setupItemDemo,
45-# 16: self.setupStyledDemo,
46-# 17: self.setupAdvancedAxesDemo,
47-# 18: self.setupColorMapDemo,
48-# 19: self.setupFinancialDemo,
44+ 12: self.setupBarChartDemo,
45+ 13: self.setupStatisticalDemo,
46+ 14: self.setupSimpleItemDemo,
47+ 15: self.setupItemDemo,
48+ 16: self.setupStyledDemo,
49+ 17: self.setupAdvancedAxesDemo,
50+ 18: self.setupColorMapDemo,
51+ 19: self.setupFinancialDemo,
4952 }
5053
5154 self.currentDemoIndex = -1
@@ -87,24 +90,20 @@ class MainWindow(QMainWindow):
8790
8891 def setupSimpleDemo(self):
8992 self.demoName = "Simple Demo"
90-
9193 # add two new graphs and set their look:
9294 self.customPlot.addGraph()
93- self.customPlot.graph(0).setPen(QPen(QColor("blue"))) # line color blue for first graph
94- self.customPlot.graph(0).setBrush(QBrush(QColor(0, 0, 255, 20))) # first graph will be filled with translucent blue
95- self.customPlot.addGraph();
96- self.customPlot.graph(1).setPen(QPen(QColor("red"))) # line color red for second graph
95+ self.customPlot.graph(0).setPen(QPen(Qt.blue)) # line color blue for first graph
96+ self.customPlot.graph(0).setBrush(QBrush(QColor(0, 0, 255, 20))) # first graph will be filled with translucent blue
97+ self.customPlot.addGraph()
98+ self.customPlot.graph(1).setPen(QPen(Qt.red)) # line color red for second graph
9799 # generate some points of data (y0 for first, y1 for second graph):
98- x = [0.0] * 251
99- y0 = [0.0] * 251
100- y1 = [0.0] * 251
101- for i in range(0, 251):
102- x[i] = float(i)
103- y0[i] = pow(math.e, -i/150.0) * math.cos(i/10.0) # exponentially decaying cosine
104- y1[i] = pow(math.e, -i/150.0) # exponential envelope
105-
100+ x, y0, y1 = [], [], []
101+ for i in range (251):
102+ x.append(i)
103+ y0.append(math.exp(-i/150.0)*math.cos(i/10.0)) # exponentially decaying cosine
104+ y1.append(math.exp(-i/150.0)) # exponential envelope
106105 # configure right and top axis to show ticks but no labels:
107- # (see QCPAxisRect::setupFullAxesBox for a quicker method to do this)
106+ # (see QCPAxisRect.setupFullAxesBox for a quicker method to do this)
108107 self.customPlot.xAxis2.setVisible(True)
109108 self.customPlot.xAxis2.setTickLabels(False)
110109 self.customPlot.yAxis2.setVisible(True)
@@ -119,29 +118,368 @@ class MainWindow(QMainWindow):
119118 self.customPlot.graph(0).rescaleAxes()
120119 # same thing for graph 1, but only enlarge ranges (in case graph 1 is smaller than graph 0):
121120 self.customPlot.graph(1).rescaleAxes(True)
122- # Note: we could have also just called customPlot->rescaleAxes(); instead
121+ # Note: we could have also just called self.customPlot.rescaleAxes() instead
123122 # Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking:
124- # TODO: figure out how to skip the explicit intermediate QCP.Interactions
125- self.customPlot.setInteractions(QCustomPlot.QCP.Interactions(QCP.iRangeDrag | QCP.iRangeZoom | QCP.iSelectPlottables))
126-
127-# void setupSincScatterDemo(QCustomPlot *customPlot);
128-# void setupScatterStyleDemo(QCustomPlot *customPlot);
129-# void setupLineStyleDemo(QCustomPlot *customPlot);
130-# void setupScatterPixmapDemo(QCustomPlot *customPlot);
131-# void setupDateDemo(QCustomPlot *customPlot);
132-# void setupTextureBrushDemo(QCustomPlot *customPlot);
133-# void setupMultiAxisDemo(QCustomPlot *customPlot);
134-# void setupLogarithmicDemo(QCustomPlot *customPlot);
135-# void setupRealtimeDataDemo(QCustomPlot *customPlot);
123+ self.customPlot.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom or QCP.iSelectPlottables)
124+
125+ def setupSincScatterDemo(self):
126+ self.demoName = "Sinc Scatter Demo"
127+ self.customPlot.legend.setVisible(True)
128+ self.customPlot.legend.setFont(QFont("Helvetica",9))
129+ # set locale to english, so we get english decimal separator:
130+ self.customPlot.setLocale(QLocale(QLocale.English, QLocale.UnitedKingdom))
131+ # add confidence band graphs:
132+ self.customPlot.addGraph()
133+ pen = QPen()
134+ pen.setStyle(Qt.DotLine)
135+ pen.setWidth(1)
136+ pen.setColor(QColor(180,180,180))
137+ self.customPlot.graph(0).setName("Confidence Band 68%")
138+ self.customPlot.graph(0).setPen(pen)
139+ self.customPlot.graph(0).setBrush(QBrush(QColor(255,50,30,20)))
140+ self.customPlot.addGraph()
141+ self.customPlot.legend.removeItem(self.customPlot.legend.itemCount()-1) # don't show two confidence band graphs in legend
142+ self.customPlot.graph(1).setPen(pen)
143+ self.customPlot.graph(0).setChannelFillGraph(self.customPlot.graph(1))
144+ # add theory curve graph:
145+ self.customPlot.addGraph()
146+ pen.setStyle(Qt.DashLine)
147+ pen.setWidth(2)
148+ pen.setColor(Qt.red)
149+ self.customPlot.graph(2).setPen(pen)
150+ self.customPlot.graph(2).setName("Theory Curve")
151+ # add data point graph:
152+ self.customPlot.addGraph()
153+ self.customPlot.graph(3).setPen(QPen(Qt.blue))
154+ self.customPlot.graph(3).setLineStyle(QCPGraph.lsNone)
155+ self.customPlot.graph(3).setScatterStyle(QCPScatterStyle(QCPScatterStyle.ssCross, 4))
156+ # add error bars:
157+ # TODO
158+ #errorBars = QCPErrorBars(self.customPlot.xAxis, self.customPlot.yAxis)
159+ #errorBars.removeFromLegend()
160+ #errorBars.setAntialiased(False)
161+ #errorBars.setDataPlottable(self.customPlot.graph(3))
162+ #errorBars.setPen(QPen(QColor(180,180,180)))
163+ self.customPlot.graph(3).setName("Measurement")
164+
165+ # generate ideal sinc curve data and some randomly perturbed data for scatter plot:
166+ x0, y0 = [], []
167+ yConfUpper, yConfLower = [], []
168+ for i in range (250):
169+ x0.append((i/249.0-0.5)*30+0.01) # by adding a small offset we make sure not do divide by zero in next code line
170+ y0.append(math.sin(x0[i])/x0[i]) # sinc function
171+ yConfUpper.append(y0[i]+0.15)
172+ yConfLower.append(y0[i]-0.15)
173+ x0[i] *= 1000
174+ x1, y1, y1err = [], [], []
175+ for i in range (50):
176+ # generate a gaussian distributed random number:
177+ tmp1 = random.random()
178+ tmp2 = random.random()
179+ r = math.sqrt(-2*math.log(tmp1))*math.cos(2*math.pi*tmp2) # box-muller transform for gaussian distribution
180+ # set y1 to value of y0 plus a random gaussian pertubation:
181+ x1.append((i/50.0-0.5)*30+0.25)
182+ y1.append(math.sin(x1[i])/x1[i]+r*0.15)
183+ x1[i] *= 1000
184+ y1err.append(0.15)
185+ # pass data to graphs and let QCustomPlot determine the axes ranges so the whole thing is visible:
186+ self.customPlot.graph(0).setData(x0, yConfUpper)
187+ self.customPlot.graph(1).setData(x0, yConfLower)
188+ self.customPlot.graph(2).setData(x0, y0)
189+ self.customPlot.graph(3).setData(x1, y1)
190+ # TODO
191+ #errorBars.setData(y1err)
192+ self.customPlot.graph(2).rescaleAxes()
193+ self.customPlot.graph(3).rescaleAxes(True)
194+ # setup look of bottom tick labels:
195+ self.customPlot.xAxis.setTickLabelRotation(30)
196+ self.customPlot.xAxis.ticker().setTickCount(9)
197+ self.customPlot.xAxis.setNumberFormat("ebc")
198+ self.customPlot.xAxis.setNumberPrecision(1)
199+ self.customPlot.xAxis.moveRange(-10)
200+ # make top right axes clones of bottom left axes. Looks prettier:
201+ self.customPlot.axisRect().setupFullAxesBox()
202+
203+ def setupScatterStyleDemo(self):
204+ self.demoName = "Line Style Demo"
205+ self.customPlot.legend.setVisible(True)
206+ self.customPlot.legend.setFont(QFont("Helvetica", 9))
207+ self.customPlot.legend.setRowSpacing(-3)
208+ shapes = [QCPScatterStyle.ssCross, QCPScatterStyle.ssPlus, QCPScatterStyle.ssCircle, QCPScatterStyle.ssDisc, QCPScatterStyle.ssSquare, QCPScatterStyle.ssDiamond, QCPScatterStyle.ssStar, QCPScatterStyle.ssTriangle, QCPScatterStyle.ssTriangleInverted, QCPScatterStyle.ssCrossSquare, QCPScatterStyle.ssPlusSquare, QCPScatterStyle.ssCrossCircle, QCPScatterStyle.ssPlusCircle, QCPScatterStyle.ssPeace, QCPScatterStyle.ssCustom]
209+
210+ pen = QPen()
211+ # add graphs with different scatter styles:
212+ for i, shape in enumerate(shapes):
213+ self.customPlot.addGraph()
214+ pen.setColor(QColor(math.sin(i*0.3)*100+100, math.sin(i*0.6+0.7)*100+100, math.sin(i*0.4+0.6)*100+100))
215+ # generate data:
216+ x, y = [], []
217+ for k in range(10):
218+ x.append(k/10.0 * 4*3.14 + 0.01)
219+ y.append(7*math.sin(x[k])/x[k] + (len(shapes)-i)*5)
220+ self.customPlot.graph().setData(x, y)
221+ self.customPlot.graph().rescaleAxes(True)
222+ self.customPlot.graph().setPen(pen)
223+ self.customPlot.graph().setName(str(shape))
224+ self.customPlot.graph().setLineStyle(QCPGraph.lsLine)
225+ # set scatter style:
226+ if shape != QCPScatterStyle.ssCustom:
227+ self.customPlot.graph().setScatterStyle(QCPScatterStyle(shape, 10))
228+ else:
229+ customScatterPath = QPainterPath()
230+ for i in range(3):
231+ customScatterPath.cubicTo(math.cos(2*math.pi*i/3.0)*9, math.sin(2*math.pi*i/3.0)*9, math.cos(2*math.pi*(i+0.9)/3.0)*9, math.sin(2*math.pi*(i+0.9)/3.0)*9, 0, 0)
232+ self.customPlot.graph().setScatterStyle(QCPScatterStyle(customScatterPath, QPen(Qt.black, 0), QColor(40, 70, 255, 50), 10))
233+ # set blank axis lines:
234+ self.customPlot.rescaleAxes()
235+ self.customPlot.xAxis.setTicks(False)
236+ self.customPlot.yAxis.setTicks(False)
237+ self.customPlot.xAxis.setTickLabels(False)
238+ self.customPlot.yAxis.setTickLabels(False)
239+ # make top right axes clones of bottom left axes:
240+ self.customPlot.axisRect().setupFullAxesBox()
241+
242+ def setupLineStyleDemo(self):
243+ self.demoName = "Line Style Demo"
244+ self.customPlot.legend.setVisible(True)
245+ self.customPlot.legend.setFont(QFont("Helvetica", 9))
246+ pen = QPen()
247+ lineNames = ["lsNone", "lsLine", "lsStepLeft", "lsStepRight", "lsStepCenter", "lsImpulse"]
248+ # add graphs with different line styles:
249+ for i in range(int(QCPGraph.lsImpulse)):
250+ self.customPlot.addGraph()
251+ pen.setColor(QColor(math.sin(i*1+1.2)*80+80, math.sin(i*0.3+0)*80+80, math.sin(i*0.3+1.5)*80+80))
252+ self.customPlot.graph().setPen(pen)
253+ self.customPlot.graph().setName(lineNames[i-int(QCPGraph.lsNone)])
254+ self.customPlot.graph().setLineStyle(QCPGraph.LineStyle(i))
255+ self.customPlot.graph().setScatterStyle(QCPScatterStyle(QCPScatterStyle.ssCircle, 5))
256+ # generate data:
257+ x, y = [], []
258+ for j in range(15):
259+ x.append(j/15.0 * 5*3.14 + 0.01)
260+ y.append(7*math.sin(x[j])/x[j] - (i-QCPGraph.lsNone)*5 + (QCPGraph.lsImpulse)*5 + 2)
261+ self.customPlot.graph().setData(x, y)
262+ self.customPlot.graph().rescaleAxes(True)
263+ # zoom out a bit:
264+ self.customPlot.yAxis.scaleRange(1.1, self.customPlot.yAxis.range().center())
265+ self.customPlot.xAxis.scaleRange(1.1, self.customPlot.xAxis.range().center())
266+ # set blank axis lines:
267+ self.customPlot.xAxis.setTicks(False)
268+ self.customPlot.yAxis.setTicks(True)
269+ self.customPlot.xAxis.setTickLabels(False)
270+ self.customPlot.yAxis.setTickLabels(True)
271+ # make top right axes clones of bottom left axes:
272+ self.customPlot.axisRect().setupFullAxesBox()
273+
274+ def setupScatterPixmapDemo(self):
275+ self.demoName = "Scatter Pixmap Demo"
276+
277+ def setupDateDemo(self):
278+ self.demoName = "Date Demo"
279+ # set locale to english, so we get english month names:
280+ self.customPlot.setLocale(QLocale(QLocale.English, QLocale.UnitedKingdom))
281+ # seconds of current time, we'll use it as starting point in time for data:
282+ now = QDateTime.currentDateTime().toTime_t()
283+ random.seed(8) # set the random seed, so we always get the same random data
284+ # create multiple graphs:
285+ for gi in range(5):
286+ self.customPlot.addGraph()
287+ color = QColor(20+200/4.0*gi,70*(1.6-gi/4.0), 150, 150)
288+ self.customPlot.graph().setLineStyle(QCPGraph.lsLine)
289+ self.customPlot.graph().setPen(QPen(color.lighter(200)))
290+ self.customPlot.graph().setBrush(QBrush(color))
291+ # generate random walk data:
292+ timeData = []
293+ for i in range(250):
294+ key = now + 24*3600*i
295+ if i == 0:
296+ value = (i/50.0+1)*(random.random()-0.5)
297+ else:
298+ value = math.fabs(timeData[i-1].value)*(1+0.02/4.0*(4-gi)) + (i/50.0+1)*(random.random()-0.5)
299+ timeData.append(QCPGraphData(key, value))
300+ self.customPlot.graph().data().set(timeData)
301+ # configure bottom axis to show date instead of number:
302+ dateTicker = QCPAxisTickerDateTime()
303+ dateTicker.setDateTimeFormat("d. MMMM\nyyyy")
304+ self.customPlot.xAxis.setTicker(dateTicker)
305+ # configure left axis text labels:
306+ textTicker = QCPAxisTickerText()
307+ textTicker.addTick(10, "a bit\nlow")
308+ textTicker.addTick(50, "quite\nhigh")
309+ self.customPlot.yAxis.setTicker(textTicker)
310+ # set a more compact font size for bottom and left axis tick labels:
311+ self.customPlot.xAxis.setTickLabelFont(QFont(QFont().family(), 8))
312+ self.customPlot.yAxis.setTickLabelFont(QFont(QFont().family(), 8))
313+ # set axis labels:
314+ self.customPlot.xAxis.setLabel("Date")
315+ self.customPlot.yAxis.setLabel("Random wobbly lines value")
316+ # make top and right axes visible but without ticks and labels:
317+ self.customPlot.xAxis2.setVisible(True)
318+ self.customPlot.yAxis2.setVisible(True)
319+ self.customPlot.xAxis2.setTicks(False)
320+ self.customPlot.yAxis2.setTicks(False)
321+ self.customPlot.xAxis2.setTickLabels(False)
322+ self.customPlot.yAxis2.setTickLabels(False)
323+ # set axis ranges to show all data:
324+ self.customPlot.xAxis.setRange(now, now+24*3600*249)
325+ self.customPlot.yAxis.setRange(0, 60)
326+ # show legend with slightly transparent background brush:
327+ self.customPlot.legend.setVisible(True)
328+ self.customPlot.legend.setBrush(QColor(255, 255, 255, 150))
329+
330+ def setupTextureBrushDemo(self):
331+ self.demoName = "Texture Brush Demo"
332+
333+ def setupMultiAxisDemo(self):
334+ self.customPlot.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom)
335+ self.demoName = "Multi Axis Demo"
336+
337+ self.customPlot.setLocale(QLocale(QLocale.English, QLocale.UnitedKingdom)) # period as decimal separator and comma as thousand separator
338+ self.customPlot.legend.setVisible(True)
339+ legendFont = QFont() # start out with MainWindow's font..
340+ legendFont.setPointSize(9) # and make a bit smaller for legend
341+ self.customPlot.legend.setFont(legendFont)
342+ self.customPlot.legend.setBrush(QBrush(QColor(255,255,255,230)))
343+ # by default, the legend is in the inset layout of the main axis rect. So this is how we access it to change legend placement:
344+ self.customPlot.axisRect().insetLayout().setInsetAlignment(0, Qt.AlignBottom or Qt.AlignRight)
345+
346+ # setup for graph 0: key axis left, value axis bottom
347+ # will contain left maxwell-like function
348+ self.customPlot.addGraph(self.customPlot.yAxis, self.customPlot.xAxis)
349+ self.customPlot.graph(0).setPen(QPen(QColor(255, 100, 0)))
350+ self.customPlot.graph(0).setBrush(QBrush(QPixmap("./balboa.jpg"))) # fill with texture of specified image
351+ self.customPlot.graph(0).setLineStyle(QCPGraph.lsLine)
352+ self.customPlot.graph(0).setScatterStyle(QCPScatterStyle(QCPScatterStyle.ssDisc, 5))
353+ self.customPlot.graph(0).setName("Left maxwell function")
354+
355+ # setup for graph 1: key axis bottom, value axis left (those are the default axes)
356+ # will contain bottom maxwell-like function with error bars
357+ self.customPlot.addGraph()
358+ self.customPlot.graph(1).setPen(QPen(Qt.red))
359+ self.customPlot.graph(1).setBrush(QBrush(QPixmap("./balboa.jpg"))) # same fill as we used for graph 0
360+ self.customPlot.graph(1).setLineStyle(QCPGraph.lsStepCenter)
361+ self.customPlot.graph(1).setScatterStyle(QCPScatterStyle(QCPScatterStyle.ssCircle, Qt.red, Qt.white, 7))
362+ self.customPlot.graph(1).setName("Bottom maxwell function")
363+ # TODO
364+ #errorBars = QCPErrorBars(self.customPlot.xAxis, self.customPlot.yAxis)
365+ #errorBars.removeFromLegend()
366+ #errorBars.setDataPlottable(self.customPlot.graph(1))
367+
368+ # setup for graph 2: key axis top, value axis right
369+ # will contain high frequency sine with low frequency beating:
370+ self.customPlot.addGraph(self.customPlot.xAxis2, self.customPlot.yAxis2)
371+ self.customPlot.graph(2).setPen(QPen(Qt.blue))
372+ self.customPlot.graph(2).setName("High frequency sine")
373+
374+ # setup for graph 3: same axes as graph 2
375+ # will contain low frequency beating envelope of graph 2
376+ self.customPlot.addGraph(self.customPlot.xAxis2, self.customPlot.yAxis2)
377+ blueDotPen = QPen()
378+ blueDotPen.setColor(QColor(30, 40, 255, 150))
379+ blueDotPen.setStyle(Qt.DotLine)
380+ blueDotPen.setWidthF(4)
381+ self.customPlot.graph(3).setPen(blueDotPen)
382+ self.customPlot.graph(3).setName("Sine envelope")
383+
384+ # setup for graph 4: key axis right, value axis top
385+ # will contain parabolically distributed data points with some random perturbance
386+ self.customPlot.addGraph(self.customPlot.yAxis2, self.customPlot.xAxis2)
387+ self.customPlot.graph(4).setPen(QColor(50, 50, 50, 255))
388+ self.customPlot.graph(4).setLineStyle(QCPGraph.lsNone)
389+ self.customPlot.graph(4).setScatterStyle(QCPScatterStyle(QCPScatterStyle.ssCircle, 4))
390+ self.customPlot.graph(4).setName("Some random data around\na quadratic function")
391+
392+ # generate data, just playing with numbers, not much to learn here:
393+ x0, y0 = [], []
394+ x1, y1, y1err = [], [], []
395+ x2, y2 = [], []
396+ x3, y3 = [], []
397+ x4, y4 = [], []
398+ for i in range(25): # data for graph 0
399+ x0.append(3*i/25.0)
400+ y0.append(math.exp(-x0[i]*x0[i]*0.8)*(x0[i]*x0[i]+x0[i]))
401+ for i in range(15): # data for graph 1
402+ x1.append(3*i/15.0)
403+ y1.append(math.exp(-x1[i]*x1[i])*(x1[i]*x1[i])*2.6)
404+ y1err.append(y1[i]*0.25)
405+ for i in range(250): # data for graphs 2, 3 and 4
406+ x2.append(i/250.0*3*math.pi)
407+ x3.append(x2[i])
408+ x4.append(i/250.0*100-50)
409+ y2.append(math.sin(x2[i]*12)*math.cos(x2[i])*10)
410+ y3.append(math.cos(x3[i])*10)
411+ y4.append(0.01*x4[i]*x4[i] + 1.5*(random.random()-0.5) + 1.5*math.pi)
412+
413+ # pass data points to graphs:
414+ self.customPlot.graph(0).setData(x0, y0)
415+ self.customPlot.graph(1).setData(x1, y1)
416+ # TODO
417+ #errorBars.setData(y1err)
418+ self.customPlot.graph(2).setData(x2, y2)
419+ self.customPlot.graph(3).setData(x3, y3)
420+ self.customPlot.graph(4).setData(x4, y4)
421+ # activate top and right axes, which are invisible by default:
422+ self.customPlot.xAxis2.setVisible(True)
423+ self.customPlot.yAxis2.setVisible(True)
424+ # set ranges appropriate to show data:
425+ self.customPlot.xAxis.setRange(0, 2.7)
426+ self.customPlot.yAxis.setRange(0, 2.6)
427+ self.customPlot.xAxis2.setRange(0, 3.0*math.pi)
428+ self.customPlot.yAxis2.setRange(-70, 35)
429+ # set pi ticks on top axis:
430+ self.customPlot.xAxis2.setTicker(QCPAxisTickerPi())
431+ # add title layout element:
432+ self.customPlot.plotLayout().insertRow(0)
433+ self.customPlot.plotLayout().addElement(0, 0, QCPTextElement(self.customPlot, "Way too many graphs in one plot", QFont("sans", 12, QFont.Bold)))
434+ # set labels:
435+ self.customPlot.xAxis.setLabel("Bottom axis with outward ticks")
436+ self.customPlot.yAxis.setLabel("Left axis label")
437+ self.customPlot.xAxis2.setLabel("Top axis label")
438+ self.customPlot.yAxis2.setLabel("Right axis label")
439+ # make ticks on bottom axis go outward:
440+ self.customPlot.xAxis.setTickLength(0, 5)
441+ self.customPlot.xAxis.setSubTickLength(0, 3)
442+ # make ticks on right axis go inward and outward:
443+ self.customPlot.yAxis2.setTickLength(3, 3)
444+ self.customPlot.yAxis2.setSubTickLength(1, 1)
445+
446+ def setupLogarithmicDemo(self):
447+ self.demoName = "Logarithmic Demo"
448+
449+ def setupRealtimeDataDemo(self):
450+ self.demoName = "Realtime Data Demo"
451+ self.time = QTime(QTime.currentTime())
452+ self.lastPointKey = 0.0
453+ self.frameCount = 0
454+ self.lastFpsKey = 0
455+
456+ self.customPlot.addGraph() # blue line
457+ self.customPlot.graph(0).setPen(QPen(QColor(40, 110, 255)))
458+ self.customPlot.addGraph() # red line
459+ self.customPlot.graph(1).setPen(QPen(QColor(255, 110, 40)))
460+
461+ timeTicker = QCPAxisTickerTime()
462+ timeTicker.setTimeFormat("%h:%m:%s")
463+ self.customPlot.xAxis.setTicker(timeTicker)
464+ self.customPlot.axisRect().setupFullAxesBox()
465+ self.customPlot.yAxis.setRange(-1.2, 1.2)
466+
467+ # make left and bottom axes transfer their ranges to right and top axes:
468+ self.customPlot.xAxis.rangeChanged.connect(self.customPlot.xAxis2.setRange)
469+ self.customPlot.yAxis.rangeChanged.connect(self.customPlot.yAxis2.setRange)
470+
471+ # setup a timer that repeatedly calls MainWindow.realtimeDataSlot:
472+ self.dataTimer = QTimer()
473+ self.dataTimer.timeout.connect(self.realtimeDataSlot)
474+ self.dataTimer.start(0) # Interval 0 means to refresh as fast as possible
136475
137476 def setupParametricCurveDemo(self):
138477 self.demoName = "Parametric Curves Demo"
139-
140478 # create empty curve objects. As they are not adopted by main QCustomPlot an explicit
141479 # reference must be kept
142- self.fermatSpiral1 = QCustomPlot.QCPCurve(self.customPlot.xAxis, self.customPlot.yAxis)
143- self.fermatSpiral2 = QCustomPlot.QCPCurve(self.customPlot.xAxis, self.customPlot.yAxis)
144- self.deltoidRadial = QCustomPlot.QCPCurve(self.customPlot.xAxis, self.customPlot.yAxis)
480+ self.fermatSpiral1 = QCustomPlot2.QCPCurve(self.customPlot.xAxis, self.customPlot.yAxis)
481+ self.fermatSpiral2 = QCustomPlot2.QCPCurve(self.customPlot.xAxis, self.customPlot.yAxis)
482+ self.deltoidRadial = QCustomPlot2.QCPCurve(self.customPlot.xAxis, self.customPlot.yAxis)
145483 # generate the curve data points:
146484 pointCount = 501
147485 dataSpiral1 = [[0.0] * pointCount, [0.0] * pointCount, [0.0] * pointCount]
@@ -160,7 +498,7 @@ class MainWindow(QMainWindow):
160498 dataDeltoid[1][i] = 2 * math.cos(2*theta) + math.cos(1*theta) + 2 * math.sin(theta)
161499 dataDeltoid[2][i] = 2 * math.sin(2*theta) - math.sin(1*theta)
162500
163- # pass the data to the curves; we know t (i in loop above) is ascending, so set alreadySorted=true (saves an extra internal sort):
501+ # pass the data to the curves we know t (i in loop above) is ascending, so set alreadySorted=true (saves an extra internal sort):
164502 self.fermatSpiral1.setData(dataSpiral1[0], dataSpiral1[1], dataSpiral1[2], True)
165503 self.fermatSpiral2.setData(dataSpiral2[0], dataSpiral2[1], dataSpiral2[2], True)
166504 self.deltoidRadial.setData(dataDeltoid[0], dataDeltoid[1], dataDeltoid[2], True)
@@ -176,17 +514,322 @@ class MainWindow(QMainWindow):
176514 self.deltoidRadial.setPen(QPen(QColor(170, 20, 240)))
177515 self.deltoidRadial.setBrush(QBrush(radialGrad))
178516 # set some basic customPlot config:
179- self.customPlot.setInteractions(QCustomPlot.QCP.Interactions(QCustomPlot.QCP.iRangeDrag | QCustomPlot.QCP.iRangeZoom | QCustomPlot.QCP.iSelectPlottables))
517+ self.customPlot.setInteractions(QCustomPlot2.QCP.Interactions(QCustomPlot2.QCP.iRangeDrag or QCustomPlot2.QCP.iRangeZoom or QCustomPlot2.QCP.iSelectPlottables))
180518 self.customPlot.axisRect().setupFullAxesBox()
181519 self.customPlot.rescaleAxes()
182520
183-# void setupBarChartDemo(QCustomPlot *customPlot);
184-# void setupStatisticalDemo(QCustomPlot *customPlot);
185-# void setupSimpleItemDemo(QCustomPlot *customPlot);
186-# void setupItemDemo(QCustomPlot *customPlot);
187-# void setupStyledDemo(QCustomPlot *customPlot);
188-# void setupAdvancedAxesDemo(QCustomPlot *customPlot);
189-# void setupColorMapDemo(QCustomPlot *customPlot);
190-# void setupFinancialDemo(QCustomPlot *customPlot);
191-#
192-# void setupPlayground(QCustomPlot *customPlot);
521+ def setupBarChartDemo(self):
522+ self.demoName = "Bar Chart Demo"
523+
524+ def setupStatisticalDemo(self):
525+ self.demoName = "Statistical Demo"
526+
527+ def setupSimpleItemDemo(self):
528+ self.demoName = "Simple Item Demo"
529+
530+ def setupItemDemo(self):
531+ self.demoName = "Item Demo"
532+ self.frameCount = 0
533+ self.lastFpsKey = 0
534+ self.customPlot.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom)
535+ graph = self.customPlot.addGraph()
536+ n = 500
537+ phase = 0.0
538+ k = 3.0
539+ x, y = [], []
540+ for i in range(n):
541+ x.append(i/float((n-1)*34 - 17))
542+ y.append(math.exp(-x[i]*x[i]/20.0)*math.sin(k*x[i]+phase))
543+ graph.setData(x, y)
544+ graph.setPen(QPen(Qt.blue))
545+ graph.rescaleKeyAxis()
546+ self.customPlot.yAxis.setRange(-1.45, 1.65)
547+ self.customPlot.xAxis.grid().setZeroLinePen(QPen(Qt.NoPen))
548+
549+ # add the bracket at the top:
550+ bracket = QCPItemBracket(self.customPlot)
551+ bracket.left.setCoords(-8, 1.1)
552+ bracket.right.setCoords(8, 1.1)
553+ bracket.setLength(13)
554+
555+ # add the text label at the top:
556+ wavePacketText = QCPItemText(self.customPlot)
557+ wavePacketText.position.setParentAnchor(bracket.center)
558+ wavePacketText.position.setCoords(0, -10) # move 10 pixels to the top from bracket center anchor
559+ wavePacketText.setPositionAlignment(Qt.AlignBottom or Qt.AlignHCenter)
560+ wavePacketText.setText("Wavepacket")
561+ wavePacketText.setFont(QFont(QFont().family(), 10))
562+
563+ # add the phase tracer (red circle) which sticks to the graph data (and gets updated in bracketDataSlot by timer event):
564+ phaseTracer = QCPItemTracer(self.customPlot)
565+ self.itemDemoPhaseTracer = phaseTracer # so we can access it later in the bracketDataSlot for animation
566+ phaseTracer.setGraph(graph)
567+ phaseTracer.setGraphKey((math.pi*1.5-phase)/k)
568+ phaseTracer.setInterpolating(True)
569+ phaseTracer.setStyle(QCPItemTracer.tsCircle)
570+ phaseTracer.setPen(QPen(Qt.red))
571+ phaseTracer.setBrush(QBrush(Qt.red))
572+ phaseTracer.setSize(7)
573+
574+ # add label for phase tracer:
575+ phaseTracerText = QCPItemText(self.customPlot)
576+ phaseTracerText.position.setType(QCPItemPosition.ptAxisRectRatio)
577+ phaseTracerText.setPositionAlignment(Qt.AlignRight or Qt.AlignBottom)
578+ phaseTracerText.position.setCoords(1.0, 0.95) # lower right corner of axis rect
579+ phaseTracerText.setText("Points of fixed\nphase define\nphase velocity vp")
580+ phaseTracerText.setTextAlignment(Qt.AlignLeft)
581+ phaseTracerText.setFont(QFont(QFont().family(), 9))
582+ phaseTracerText.setPadding(QMargins(8, 0, 0, 0))
583+
584+ # add arrow pointing at phase tracer, coming from label:
585+ phaseTracerArrow = QCPItemCurve(self.customPlot)
586+ phaseTracerArrow.start.setParentAnchor(phaseTracerText.left)
587+ phaseTracerArrow.startDir.setParentAnchor(phaseTracerArrow.start)
588+ phaseTracerArrow.startDir.setCoords(-40, 0) # direction 30 pixels to the left of parent anchor (tracerArrow.start)
589+ phaseTracerArrow.end.setParentAnchor(phaseTracer.position)
590+ phaseTracerArrow.end.setCoords(10, 10)
591+ phaseTracerArrow.endDir.setParentAnchor(phaseTracerArrow.end)
592+ phaseTracerArrow.endDir.setCoords(30, 30)
593+ phaseTracerArrow.setHead(QCPLineEnding(QCPLineEnding.esSpikeArrow))
594+ phaseTracerArrow.setTail(QCPLineEnding(QCPLineEnding.esBar, (phaseTracerText.bottom.pixelPosition().y()-phaseTracerText.top.pixelPosition().y())*0.85))
595+
596+ # add the group velocity tracer (green circle):
597+ groupTracer = QCPItemTracer(self.customPlot)
598+ groupTracer.setGraph(graph)
599+ groupTracer.setGraphKey(5.5)
600+ groupTracer.setInterpolating(True)
601+ groupTracer.setStyle(QCPItemTracer.tsCircle)
602+ groupTracer.setPen(QPen(Qt.green))
603+ groupTracer.setBrush(QBrush(Qt.green))
604+ groupTracer.setSize(7)
605+
606+ # add label for group tracer:
607+ groupTracerText = QCPItemText(self.customPlot)
608+ groupTracerText.position.setType(QCPItemPosition.ptAxisRectRatio)
609+ groupTracerText.setPositionAlignment(Qt.AlignRight or Qt.AlignTop)
610+ groupTracerText.position.setCoords(1.0, 0.20) # lower right corner of axis rect
611+ groupTracerText.setText("Fixed positions in\nwave packet define\ngroup velocity vg")
612+ groupTracerText.setTextAlignment(Qt.AlignLeft)
613+ groupTracerText.setFont(QFont(QFont().family(), 9))
614+ groupTracerText.setPadding(QMargins(8, 0, 0, 0))
615+
616+ # add arrow pointing at group tracer, coming from label:
617+ groupTracerArrow = QCPItemCurve(self.customPlot)
618+ groupTracerArrow.start.setParentAnchor(groupTracerText.left)
619+ groupTracerArrow.startDir.setParentAnchor(groupTracerArrow.start)
620+ groupTracerArrow.startDir.setCoords(-40, 0) # direction 30 pixels to the left of parent anchor (tracerArrow.start)
621+ groupTracerArrow.end.setCoords(5.5, 0.4)
622+ groupTracerArrow.endDir.setParentAnchor(groupTracerArrow.end)
623+ groupTracerArrow.endDir.setCoords(0, -40)
624+ groupTracerArrow.setHead(QCPLineEnding(QCPLineEnding.esSpikeArrow))
625+ groupTracerArrow.setTail(QCPLineEnding(QCPLineEnding.esBar, (groupTracerText.bottom.pixelPosition().y()-groupTracerText.top.pixelPosition().y())*0.85))
626+
627+ # add dispersion arrow:
628+ arrow = QCPItemCurve(self.customPlot)
629+ arrow.start.setCoords(1, -1.1)
630+ arrow.startDir.setCoords(-1, -1.3)
631+ arrow.endDir.setCoords(-5, -0.3)
632+ arrow.end.setCoords(-10, -0.2)
633+ arrow.setHead(QCPLineEnding(QCPLineEnding.esSpikeArrow))
634+
635+ # add the dispersion arrow label:
636+ dispersionText = QCPItemText(self.customPlot)
637+ dispersionText.position.setCoords(-6, -0.9)
638+ dispersionText.setRotation(40)
639+ dispersionText.setText("Dispersion with\nvp < vg")
640+ dispersionText.setFont(QFont(QFont().family(), 10))
641+
642+ # setup a timer that repeatedly calls MainWindow.bracketDataSlot:
643+ self.dataTimer = QTimer()
644+ self.dataTimer.timeout.connect(self.bracketDataSlot)
645+ self.dataTimer.start(0) # Interval 0 means to refresh as fast as possible
646+
647+ def setupStyledDemo(self):
648+ self.demoName = "Styled Demo"
649+ # add two new graphs and set their look:
650+ # prepare data:
651+ x1, y1 = [], []
652+ x2, y2 = [], []
653+ x3, y3 = [], []
654+ x4, y4 = [], []
655+ for i in range(20):
656+ x1.append(i/float(20-1)*10)
657+ y1.append(math.cos(x1[i]*0.8+math.sin(x1[i]*0.16+1.0))*math.sin(x1[i]*0.54)+1.4)
658+ for i in range(100):
659+ x2.append(i/float(100-1)*10)
660+ y2.append(math.cos(x2[i]*0.85+math.sin(x2[i]*0.165+1.1))*math.sin(x2[i]*0.50)+1.7)
661+ for i in range(20):
662+ x3.append(i/float(20-1)*10)
663+ y3.append(0.05+3*(0.5+math.cos(x3[i]*x3[i]*0.2+2)*0.5)/float(x3[i]+0.7)+random.random()*0.01)
664+ for i in range(20):
665+ x4.append(x3[i])
666+ y4.append((0.5-y3[i])+((x4[i]-2)*(x4[i]-2)*0.02))
667+
668+ # create and configure plottables:
669+ graph1 = self.customPlot.addGraph()
670+ graph1.setData(x1, y1)
671+ graph1.setScatterStyle(QCPScatterStyle(QCPScatterStyle.ssCircle, QPen(Qt.black, 1.5), QBrush(Qt.white), 9))
672+ graph1.setPen(QPen(QColor(120, 120, 120), 2))
673+
674+ graph2 = self.customPlot.addGraph()
675+ graph2.setData(x2, y2)
676+ graph2.setPen(QPen(Qt.NoPen))
677+ graph2.setBrush(QColor(200, 200, 200, 20))
678+ graph2.setChannelFillGraph(graph1)
679+
680+ bars1 = QCPBars(self.customPlot.xAxis, self.customPlot.yAxis)
681+ bars1.setWidth(9/float(len(x3)))
682+ bars1.setData(x3, y3)
683+ bars1.setPen(QPen(Qt.NoPen))
684+ bars1.setBrush(QColor(10, 140, 70, 160))
685+
686+ bars2 = QCPBars(self.customPlot.xAxis, self.customPlot.yAxis)
687+ bars2.setWidth(9/float(len((x4))))
688+ bars2.setData(x4, y4)
689+ bars2.setPen(QPen(Qt.NoPen))
690+ bars2.setBrush(QColor(10, 100, 50, 70))
691+ bars2.moveAbove(bars1)
692+
693+ # move bars above graphs and grid below bars:
694+ self.customPlot.addLayer("abovemain", self.customPlot.layer("main"), QCustomPlot.limAbove)
695+ self.customPlot.addLayer("belowmain", self.customPlot.layer("main"), QCustomPlot.limBelow)
696+ graph1.setLayer("abovemain")
697+ self.customPlot.xAxis.grid().setLayer("belowmain")
698+ self.customPlot.yAxis.grid().setLayer("belowmain")
699+
700+ # set some pens, brushes and backgrounds:
701+ self.customPlot.xAxis.setBasePen(QPen(Qt.white, 1))
702+ self.customPlot.yAxis.setBasePen(QPen(Qt.white, 1))
703+ self.customPlot.xAxis.setTickPen(QPen(Qt.white, 1))
704+ self.customPlot.yAxis.setTickPen(QPen(Qt.white, 1))
705+ self.customPlot.xAxis.setSubTickPen(QPen(Qt.white, 1))
706+ self.customPlot.yAxis.setSubTickPen(QPen(Qt.white, 1))
707+ self.customPlot.xAxis.setTickLabelColor(Qt.white)
708+ self.customPlot.yAxis.setTickLabelColor(Qt.white)
709+ self.customPlot.xAxis.grid().setPen(QPen(QColor(140, 140, 140), 1, Qt.DotLine))
710+ self.customPlot.yAxis.grid().setPen(QPen(QColor(140, 140, 140), 1, Qt.DotLine))
711+ self.customPlot.xAxis.grid().setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt.DotLine))
712+ self.customPlot.yAxis.grid().setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt.DotLine))
713+ self.customPlot.xAxis.grid().setSubGridVisible(True)
714+ self.customPlot.yAxis.grid().setSubGridVisible(True)
715+ self.customPlot.xAxis.grid().setZeroLinePen(QPen(Qt.NoPen))
716+ self.customPlot.yAxis.grid().setZeroLinePen(QPen(Qt.NoPen))
717+ self.customPlot.xAxis.setUpperEnding(QCPLineEnding(QCPLineEnding.esSpikeArrow))
718+ self.customPlot.yAxis.setUpperEnding(QCPLineEnding(QCPLineEnding.esSpikeArrow))
719+ plotGradient = QLinearGradient()
720+ plotGradient.setStart(0, 0)
721+ plotGradient.setFinalStop(0, 350)
722+ plotGradient.setColorAt(0, QColor(80, 80, 80))
723+ plotGradient.setColorAt(1, QColor(50, 50, 50))
724+ self.customPlot.setBackground(plotGradient)
725+ axisRectGradient = QLinearGradient()
726+ axisRectGradient.setStart(0, 0)
727+ axisRectGradient.setFinalStop(0, 350)
728+ axisRectGradient.setColorAt(0, QColor(80, 80, 80))
729+ axisRectGradient.setColorAt(1, QColor(30, 30, 30))
730+ self.customPlot.axisRect().setBackground(axisRectGradient)
731+
732+ self.customPlot.rescaleAxes()
733+ self.customPlot.yAxis.setRange(0, 2)
734+
735+ def setupAdvancedAxesDemo(self):
736+ self.demoName = "Advanced Axes Demo"
737+
738+ def setupColorMapDemo(self):
739+ # configure axis rect:
740+ self.customPlot.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom) # this will also allow rescaling the color scale by dragging/zooming
741+ self.customPlot.axisRect().setupFullAxesBox(True)
742+ self.customPlot.xAxis.setLabel("x")
743+ self.customPlot.yAxis.setLabel("y")
744+
745+ # set up the QCPColorMap:
746+ colorMap = QCPColorMap(self.customPlot.xAxis, self.customPlot.yAxis)
747+ nx = 200
748+ ny = 200
749+ colorMap.data().setSize(nx, ny) # we want the color map to have nx * ny data points
750+ colorMap.data().setRange(QCPRange(-4, 4), QCPRange(-4, 4)) # and span the coordinate range -4..4 in both key (x) and value (y) dimensions
751+ # now we assign some data, by accessing the QCPColorMapData instance of the color map:
752+ for xIndex in range(nx):
753+ for yIndex in range(ny):
754+ x, y = colorMap.data().cellToCoord(xIndex, yIndex)
755+ r = 3*math.sqrt(x*x+y*y)+1e-2
756+ z = 2*x*(math.cos(r+2)/r-math.sin(r+2)/r) # the B field strength of dipole radiation (modulo physical constants)
757+ colorMap.data().setCell(xIndex, yIndex, z)
758+
759+ # add a color scale:
760+ colorScale = QCPColorScale(self.customPlot)
761+ self.customPlot.plotLayout().addElement(0, 1, colorScale) # add it to the right of the main axis rect
762+ colorScale.setType(QCPAxis.atRight) # scale shall be vertical bar with tick/axis labels right (actually atRight is already the default)
763+ colorMap.setColorScale(colorScale) # associate the color map with the color scale
764+ colorScale.axis().setLabel("Magnetic Field Strength")
765+
766+ # set the color gradient of the color map to one of the presets:
767+ colorMap.setGradient(QCPColorGradient(QCPColorGradient.gpPolar))
768+ # we could have also created a QCPColorGradient instance and added own colors to
769+ # the gradient, see the documentation of QCPColorGradient for what's possible.
770+
771+ # rescale the data dimension (color) such that all data points lie in the span visualized by the color gradient:
772+ colorMap.rescaleDataRange()
773+
774+ # make sure the axis rect and color scale synchronize their bottom and top margins (so they line up):
775+ marginGroup = QCPMarginGroup(self.customPlot)
776+ self.customPlot.axisRect().setMarginGroup(QCP.msBottom or QCP.msTop, marginGroup)
777+ colorScale.setMarginGroup(QCP.msBottom or QCP.msTop, marginGroup)
778+
779+ # rescale the key (x) and value (y) axes so the whole color map is visible:
780+ self.customPlot.rescaleAxes()
781+
782+ def setupFinancialDemo(self):
783+ self.tmp = 0
784+
785+# void setupPlayground(QCustomPlot *customPlot)
786+
787+ def realtimeDataSlot(self):
788+ #static QTime time(QTime.currentTime())
789+ # calculate two new data points:
790+ key = self.time.elapsed()/1000.0 # time elapsed since start of demo, in seconds
791+ if key-self.lastPointKey > 0.002: # at most add point every 2 ms
792+ # add data to lines:
793+ self.customPlot.graph(0).addData(key, math.sin(key)+random.random()*1*math.sin(key/0.3843))
794+ self.customPlot.graph(1).addData(key, math.cos(key)+random.random()*0.5*math.sin(key/0.4364))
795+ # rescale value (vertical) axis to fit the current data:
796+ #self.customPlot.graph(0).rescaleValueAxis()
797+ #self.customPlot.graph(1).rescaleValueAxis(true)
798+ self.lastPointKey = key
799+ # make key axis range scroll with the data (at a constant range size of 8):
800+ self.customPlot.xAxis.setRange(key, 8, Qt.AlignRight)
801+ self.customPlot.replot()
802+
803+ # calculate frames per second:
804+ self.frameCount += 1
805+ if key-self.lastFpsKey > 2: # average fps over 2 seconds
806+ self.statusBar.showMessage(
807+ f"{self.frameCount/(key-self.lastFpsKey)} FPS, Total Data points: {self.customPlot.graph(0).data().size()+self.customPlot.graph(1).data().size()}")
808+ self.lastFpsKey = key
809+ self.frameCount = 0
810+
811+ def bracketDataSlot(self):
812+ secs = QCPAxisTickerDateTime.dateTimeToKey(QDateTime.currentDateTime())
813+
814+ # update data to make phase move:
815+ n = 500
816+ phase = secs*5.0
817+ k = 3.0
818+ x, y = [], []
819+ for i in range(n):
820+ x.append(i/float((n-1)*34 - 17))
821+ y.append(math.exp(-x[i]*x[i]/20.0)*math.sin(k*x[i]+phase))
822+ self.customPlot.graph().setData(x, y)
823+
824+ self.itemDemoPhaseTracer.setGraphKey((8*math.pi+math.fmod(math.pi*1.5-phase, 6*math.pi))/k)
825+
826+ self.customPlot.replot()
827+
828+ # calculate frames per second:
829+ key = secs
830+ self.frameCount += 1
831+ if key-self.lastFpsKey > 2: # average fps over 2 seconds
832+ self.statusBar.showMessage(
833+ f"{self.frameCount/(key-self.lastFpsKey)} FPS, Total Data points: {self.customPlot.graph(0).data().size()}")
834+ self.lastFpsKey = key
835+ self.frameCount = 0
--- a/examples/plots/mainwindow.ui
+++ b/examples/plots/mainwindow.ui
@@ -27,7 +27,7 @@
2727 <customwidget>
2828 <class>QCustomPlot</class>
2929 <extends>QWidget</extends>
30- <header>QCustomPlot</header>
30+ <header>QCustomPlot2</header>
3131 <container>1</container>
3232 </customwidget>
3333 </customwidgets>
--- a/examples/scrollbar-axis-range-control/mainwindow.py
+++ b/examples/scrollbar-axis-range-control/mainwindow.py
@@ -16,11 +16,66 @@ from PyQt5.QtGui import QPen, QBrush, QColor, QRadialGradient
1616 from PyQt5.QtWidgets import QMainWindow
1717 from PyQt5.uic import loadUi
1818
19-# import QCustomPlot2
19+import QCustomPlot2
2020
21-# from QCustomPlot2 import QCP
21+from QCustomPlot2 import QCP
2222
2323 class MainWindow(QMainWindow):
2424 def __init__(self, argv, parent=None):
2525 super().__init__(parent)
26- loadUi("mainwindow.ui", self)
\ No newline at end of file
26+ loadUi("examples/scrollbar-axis-range-control/mainwindow.ui", self)
27+
28+ self.setupPlot()
29+
30+ # configure scroll bars:
31+ # Since scroll bars only support integer values, we'll set a high default range of -500..500 and
32+ # divide scroll bar position values by 100 to provide a scroll range -5..5 in floating point
33+ # axis coordinates. if you want to dynamically grow the range accessible with the scroll bar,
34+ # just increase the the minimum/maximum values of the scroll bars as needed.
35+ self.horizontalScrollBar.setRange(-500, 500)
36+ self.verticalScrollBar.setRange(-500, 500)
37+
38+ # create connection between axes and scroll bars:
39+ self.horizontalScrollBar.valueChanged.connect(self.horzScrollBarChanged)
40+ self.verticalScrollBar.valueChanged.connect(self.vertScrollBarChanged)
41+ self.plot.xAxis.rangeChanged.connect(self.xAxisChanged)
42+ self.plot.yAxis.rangeChanged.connect(self.yAxisChanged)
43+
44+ # initialize axis range (and scroll bar positions via signals we just connected):
45+ self.plot.xAxis.setRange(0, 6, Qt.AlignCenter)
46+ self.plot.yAxis.setRange(0, 10, Qt.AlignCenter)
47+
48+ def setupPlot(self):
49+ # The following plot setup is mostly taken from the plot demos:
50+ self.plot.addGraph()
51+ self.plot.graph().setPen(QPen(Qt.blue))
52+ self.plot.graph().setBrush(QBrush(QColor(0, 0, 255, 20)))
53+ self.plot.addGraph()
54+ self.plot.graph().setPen(QPen(Qt.red))
55+ x, y0, y1 = [], [], []
56+ for i in range(500):
57+ x.append((i/499.0-0.5)*10)
58+ y0.append(math.exp(-x[i]*x[i]*0.25)*math.sin(x[i]*5)*5)
59+ y1.append(math.exp(-x[i]*x[i]*0.25)*5)
60+ self.plot.graph(0).setData(x, y0)
61+ self.plot.graph(1).setData(x, y1)
62+ self.plot.axisRect().setupFullAxesBox(True)
63+ self.plot.setInteractions(QCP.iRangeDrag or QCP.iRangeZoom)
64+
65+ def horzScrollBarChanged(self, value):
66+ if math.fabs(self.plot.xAxis.range().center()-value/100.0) > 0.01: # if user is dragging plot, we don't want to replot twice
67+ self.plot.xAxis.setRange(value/100.0, self.plot.xAxis.range().size(), Qt.AlignCenter)
68+ self.plot.replot()
69+
70+ def vertScrollBarChanged(self, value):
71+ if math.fabs(self.plot.yAxis.range().center()+value/100.0) > 0.01: # if user is dragging plot, we don't want to replot twice
72+ self.plot.yAxis.setRange(-value/100.0, self.plot.yAxis.range().size(), Qt.AlignCenter)
73+ self.plot.replot()
74+
75+ def xAxisChanged(self, range):
76+ self.horizontalScrollBar.setValue(round(range.center()*100.0)) # adjust position of scroll bar slider
77+ self.horizontalScrollBar.setPageStep(round(range.size()*100.0)) # adjust size of scroll bar slider
78+
79+ def yAxisChanged(self, range):
80+ self.verticalScrollBar.setValue(round(-range.center()*100.0)) # adjust position of scroll bar slider
81+ self.verticalScrollBar.setPageStep(round(range.size()*100.0)) # adjust size of scroll bar slider
\ No newline at end of file
--- a/examples/scrollbar-axis-range-control/mainwindow.ui
+++ b/examples/scrollbar-axis-range-control/mainwindow.ui
@@ -58,7 +58,7 @@
5858 <customwidget>
5959 <class>QCustomPlot</class>
6060 <extends>QWidget</extends>
61- <header>../../qcustomplot.h</header>
61+ <header>QCustomPlot2</header>
6262 <container>1</container>
6363 </customwidget>
6464 </customwidgets>
--- a/examples/text-document-integration/mainwindow.py
+++ b/examples/text-document-integration/mainwindow.py
@@ -16,11 +16,11 @@ from PyQt5.QtGui import QPen, QBrush, QColor, QRadialGradient
1616 from PyQt5.QtWidgets import QMainWindow
1717 from PyQt5.uic import loadUi
1818
19-# import QCustomPlot2
19+import QCustomPlot2
2020
21-# from QCustomPlot2 import QCP
21+from QCustomPlot2 import QCP
2222
2323 class MainWindow(QMainWindow):
2424 def __init__(self, argv, parent=None):
2525 super().__init__(parent)
26- loadUi("mainwindow.ui", self)
\ No newline at end of file
26+ loadUi("examples/text-document-integration/mainwindow.ui", self)
\ No newline at end of file
--- a/examples/text-document-integration/mainwindow.ui
+++ b/examples/text-document-integration/mainwindow.ui
@@ -131,7 +131,7 @@
131131 <customwidget>
132132 <class>QCustomPlot</class>
133133 <extends>QWidget</extends>
134- <header>../../qcustomplot.h</header>
134+ <header>QCustomPlot2</header>
135135 <container>1</container>
136136 </customwidget>
137137 </customwidgets>
--- a/helper.h
+++ b/helper.h
@@ -4,7 +4,6 @@
44 typedef QCPAbstractPlottable1D<QCPGraphData> QCPAbstractPlottable1D_QCPGraphData;
55 typedef QCPAbstractPlottable1D<QCPBarsData> QCPAbstractPlottable1D_QCPBarsData;
66 typedef QCPAbstractPlottable1D<QCPCurveData> QCPAbstractPlottable1D_QCPCurveData;
7-typedef QCPAbstractPlottable1D<QCPErrorBarsData> QCPAbstractPlottable1D_QCPErrorBarsData;
87 typedef QCPAbstractPlottable1D<QCPStatisticalBoxData> QCPAbstractPlottable1D_QCPStatisticalBoxData;
98 typedef QCPAbstractPlottable1D<QCPFinancialData> QCPAbstractPlottable1D_QCPFinancialData;
109
--- a/item-bracket.sip
+++ b/item-bracket.sip
@@ -20,7 +20,7 @@ public:
2020 ,bsCalligraphic ///< A curly brace with varying stroke width giving a calligraphic impression
2121 };
2222
23- explicit QCPItemBracket(QCustomPlot *parentPlot);
23+ explicit QCPItemBracket(QCustomPlot *parentPlot /TransferThis/);
2424 virtual ~QCPItemBracket();
2525
2626 // getters:
@@ -38,7 +38,7 @@ public:
3838 // reimplemented virtual methods:
3939 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
4040
41- //QCPItemPosition * const left;
42- //QCPItemPosition * const right;
43- //QCPItemAnchor * const center;
41+ QCPItemPosition * left /NoSetter/;
42+ QCPItemPosition * right /NoSetter/;
43+ QCPItemAnchor * center /NoSetter/;
4444 };
--- a/item-curve.sip
+++ b/item-curve.sip
@@ -14,7 +14,7 @@ class QCPItemCurve : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-curve.h>
1515 %End
1616 public:
17- explicit QCPItemCurve(QCustomPlot *parentPlot);
17+ explicit QCPItemCurve(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemCurve();
1919
2020 // getters:
@@ -32,8 +32,8 @@ public:
3232 // reimplemented virtual methods:
3333 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
3434
35- //QCPItemPosition * const start;
36- //QCPItemPosition * const startDir;
37- //QCPItemPosition * const endDir;
38- //QCPItemPosition * const end;
35+ QCPItemPosition * start /NoSetter/;
36+ QCPItemPosition * startDir /NoSetter/;
37+ QCPItemPosition * endDir /NoSetter/;
38+ QCPItemPosition * end /NoSetter/;
3939 };
--- a/item-ellipse.sip
+++ b/item-ellipse.sip
@@ -14,7 +14,7 @@ class QCPItemEllipse : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-ellipse.h>
1515 %End
1616 public:
17- explicit QCPItemEllipse(QCustomPlot *parentPlot);
17+ explicit QCPItemEllipse(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemEllipse();
1919
2020 // getters:
@@ -32,15 +32,15 @@ public:
3232 // reimplemented virtual methods:
3333 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
3434
35- //QCPItemPosition * const topLeft;
36- //QCPItemPosition * const bottomRight;
37- //QCPItemAnchor * const topLeftRim;
38- //QCPItemAnchor * const top;
39- //QCPItemAnchor * const topRightRim;
40- //QCPItemAnchor * const right;
41- //QCPItemAnchor * const bottomRightRim;
42- //QCPItemAnchor * const bottom;
43- //QCPItemAnchor * const bottomLeftRim;
44- //QCPItemAnchor * const left;
45- //QCPItemAnchor * const center;
35+ QCPItemPosition * topLeft /NoSetter/;
36+ QCPItemPosition * bottomRight /NoSetter/;
37+ QCPItemAnchor * topLeftRim /NoSetter/;
38+ QCPItemAnchor * top /NoSetter/;
39+ QCPItemAnchor * topRightRim /NoSetter/;
40+ QCPItemAnchor * right /NoSetter/;
41+ QCPItemAnchor * bottomRightRim /NoSetter/;
42+ QCPItemAnchor * bottom /NoSetter/;
43+ QCPItemAnchor * bottomLeftRim /NoSetter/;
44+ QCPItemAnchor * left /NoSetter/;
45+ QCPItemAnchor * center /NoSetter/;
4646 };
--- a/item-line.sip
+++ b/item-line.sip
@@ -14,7 +14,7 @@ class QCPItemLine : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-line.h>
1515 %End
1616 public:
17- explicit QCPItemLine(QCustomPlot *parentPlot);
17+ explicit QCPItemLine(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemLine();
1919
2020 // getters:
@@ -32,6 +32,6 @@ public:
3232 // reimplemented virtual methods:
3333 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
3434
35- //QCPItemPosition * const start;
36- //QCPItemPosition * const end;
35+ QCPItemPosition * start /NoSetter/;
36+ QCPItemPosition * end /NoSetter/;
3737 };
--- a/item-pixmap.sip
+++ b/item-pixmap.sip
@@ -14,7 +14,7 @@ class QCPItemPixmap : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-pixmap.h>
1515 %End
1616 public:
17- explicit QCPItemPixmap(QCustomPlot *parentPlot);
17+ explicit QCPItemPixmap(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemPixmap();
1919
2020 // getters:
@@ -34,12 +34,12 @@ public:
3434 // reimplemented virtual methods:
3535 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
3636
37- //QCPItemPosition * const topLeft;
38- //QCPItemPosition * const bottomRight;
39- //QCPItemAnchor * const top;
40- //QCPItemAnchor * const topRight;
41- //QCPItemAnchor * const right;
42- //QCPItemAnchor * const bottom;
43- //QCPItemAnchor * const bottomLeft;
44- //QCPItemAnchor * const left;
37+ QCPItemPosition * topLeft /NoSetter/;
38+ QCPItemPosition * bottomRight /NoSetter/;
39+ QCPItemAnchor * top /NoSetter/;
40+ QCPItemAnchor * topRight /NoSetter/;
41+ QCPItemAnchor * right /NoSetter/;
42+ QCPItemAnchor * bottom /NoSetter/;
43+ QCPItemAnchor * bottomLeft /NoSetter/;
44+ QCPItemAnchor * left /NoSetter/;
4545 };
--- a/item-rect.sip
+++ b/item-rect.sip
@@ -14,7 +14,7 @@ class QCPItemRect : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-rect.h>
1515 %End
1616 public:
17- explicit QCPItemRect(QCustomPlot *parentPlot);
17+ explicit QCPItemRect(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemRect();
1919
2020 // getters:
@@ -32,12 +32,12 @@ public:
3232 // reimplemented virtual methods:
3333 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
3434
35- //QCPItemPosition * const topLeft;
36- //QCPItemPosition * const bottomRight;
37- //QCPItemAnchor * const top;
38- //QCPItemAnchor * const topRight;
39- //QCPItemAnchor * const right;
40- //QCPItemAnchor * const bottom;
41- //QCPItemAnchor * const bottomLeft;
42- //QCPItemAnchor * const left;
35+ QCPItemPosition * topLeft /NoSetter/;
36+ QCPItemPosition * bottomRight /NoSetter/;
37+ QCPItemAnchor * top /NoSetter/;
38+ QCPItemAnchor * topRight /NoSetter/;
39+ QCPItemAnchor * right /NoSetter/;
40+ QCPItemAnchor * bottom /NoSetter/;
41+ QCPItemAnchor * bottomLeft /NoSetter/;
42+ QCPItemAnchor * left /NoSetter/;
4343 };
--- a/item-straightline.sip
+++ b/item-straightline.sip
@@ -14,7 +14,7 @@ class QCPItemStraightLine : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-straightline.h>
1515 %End
1616 public:
17- explicit QCPItemStraightLine(QCustomPlot *parentPlot);
17+ explicit QCPItemStraightLine(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemStraightLine();
1919
2020 // getters:
@@ -28,6 +28,6 @@ public:
2828 // reimplemented virtual methods:
2929 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
3030
31- //QCPItemPosition * const point1;
32- //QCPItemPosition * const point2;
31+ QCPItemPosition * point1 /NoSetter/;
32+ QCPItemPosition * point2 /NoSetter/;
3333 };
--- a/item-text.sip
+++ b/item-text.sip
@@ -14,7 +14,7 @@ class QCPItemText : public QCPAbstractItem /NoDefaultCtors/
1414 #include <QCustomPlot/src/items/item-text.h>
1515 %End
1616 public:
17- explicit QCPItemText(QCustomPlot *parentPlot);
17+ explicit QCPItemText(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPItemText();
1919
2020 // getters:
@@ -50,13 +50,13 @@ public:
5050 // reimplemented virtual methods:
5151 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
5252
53- //QCPItemPosition * const position;
54- //QCPItemAnchor * const topLeft;
55- //QCPItemAnchor * const top;
56- //QCPItemAnchor * const topRight;
57- //QCPItemAnchor * const right;
58- //QCPItemAnchor * const bottomRight;
59- //QCPItemAnchor * const bottom;
60- //QCPItemAnchor * const bottomLeft;
61- //QCPItemAnchor * const left;
53+ QCPItemPosition * position /NoSetter/;
54+ QCPItemAnchor * topLeft /NoSetter/;
55+ QCPItemAnchor * top /NoSetter/;
56+ QCPItemAnchor * topRight /NoSetter/;
57+ QCPItemAnchor * right /NoSetter/;
58+ QCPItemAnchor * bottomRight /NoSetter/;
59+ QCPItemAnchor * bottom /NoSetter/;
60+ QCPItemAnchor * bottomLeft /NoSetter/;
61+ QCPItemAnchor * left /NoSetter/;
6262 };
--- a/item-tracer.sip
+++ b/item-tracer.sip
@@ -21,7 +21,7 @@ public:
2121 ,tsSquare ///< A square
2222 };
2323
24- explicit QCPItemTracer(QCustomPlot *parentPlot);
24+ explicit QCPItemTracer(QCustomPlot *parentPlot /TransferThis/);
2525 virtual ~QCPItemTracer();
2626
2727 // getters:
@@ -52,5 +52,5 @@ public:
5252 // non-virtual methods:
5353 void updatePosition();
5454
55- //QCPItemPosition * const position;
55+ QCPItemPosition * position /NoSetter/;
5656 };
--- a/layoutelement-colorscale.sip
+++ b/layoutelement-colorscale.sip
@@ -14,7 +14,7 @@ class QCPColorScale : public QCPLayoutElement
1414 #include <QCustomPlot/src/qcp.h>
1515 %End
1616 public:
17- explicit QCPColorScale(QCustomPlot *parentPlot);
17+ explicit QCPColorScale(QCustomPlot *parentPlot /TransferThis/);
1818 virtual ~QCPColorScale();
1919
2020 // getters:
--- a/plottable-colormap.sip
+++ b/plottable-colormap.sip
@@ -57,7 +57,7 @@ class QCPColorMap : public QCPAbstractPlottable
5757 #include <QCustomPlot/src/plottables/plottable-colormap.h>
5858 %End
5959 public:
60- explicit QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis);
60+ explicit QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis) /Transfer/;
6161 virtual ~QCPColorMap();
6262
6363 // getters:
--- a/plottable-curve.sip
+++ b/plottable-curve.sip
@@ -31,6 +31,7 @@ public:
3131 double value;
3232 };
3333
34+typedef QCPDataContainer<QCPCurveData> QCPCurveDataContainer;
3435 typedef QCPAbstractPlottable1D<QCPCurveData> QCPAbstractPlottable1D_QCPCurveData;
3536
3637 class QCPCurve : public QCPAbstractPlottable1D_QCPCurveData
@@ -50,15 +51,19 @@ public:
5051 virtual ~QCPCurve();
5152
5253 // getters:
53- // TODO: provide methodcode
54- // QSharedPointer<QCPCurveDataContainer> data() const { return mDataContainer; }
54+ QCPCurveDataContainer* data() const;
55+ %MethodCode
56+ sipRes = sipCpp->data().data();
57+ %End
5558 QCPScatterStyle scatterStyle() const;
5659 int scatterSkip() const;
5760 LineStyle lineStyle() const;
5861
5962 // setters:
60- // TODO: provide methodcode
61- // void setData(QSharedPointer<QCPCurveDataContainer> data);
63+ void setData(QCPCurveDataContainer *data /Transfer/);
64+ %MethodCode
65+ sipCpp->setData(QSharedPointer<QCPCurveDataContainer>(a0));
66+ %End
6267 void setData(const QVector<double> &t, const QVector<double> &keys, const QVector<double> &values, bool alreadySorted=false);
6368 void setData(const QVector<double> &keys, const QVector<double> &values);
6469 void setScatterStyle(const QCPScatterStyle &style);
--- a/plottable-errorbar.sip
+++ b/plottable-errorbar.sip
@@ -22,6 +22,8 @@ public:
2222 double errorPlus;
2323 };
2424
25+typedef QVector<QCPErrorBarsData> QCPErrorBarsDataContainer;
26+
2527 class QCPErrorBars : public QCPAbstractPlottable, public QCPPlottableInterface1D
2628 {
2729 %TypeHeaderCode
@@ -32,18 +34,24 @@ public:
3234 ,etValueError ///< The errors are for the value dimension (bars appear parallel to the value axis)
3335 };
3436
35- explicit QCPErrorBars(QCPAxis *keyAxis, QCPAxis *valueAxis);
37+ explicit QCPErrorBars(QCPAxis *keyAxis, QCPAxis *valueAxis) /Transfer/;
3638 virtual ~QCPErrorBars();
3739
3840 // getters:
39- // QSharedPointer<QCPErrorBarsDataContainer> data() const;
41+ QCPErrorBarsDataContainer* data() const;
42+ %MethodCode
43+ sipRes = sipCpp->data().data();
44+ %End
4045 QCPAbstractPlottable *dataPlottable() const;
4146 ErrorType errorType() const;
4247 double whiskerWidth() const;
4348 double symbolGap() const;
4449
4550 // setters:
46- // void setData(QSharedPointer<QCPErrorBarsDataContainer> data);
51+ void setData(QCPErrorBarsDataContainer *data /Transfer/);
52+ %MethodCode
53+ sipCpp->setData(QSharedPointer<QCPErrorBarsDataContainer>(a0));
54+ %End
4755 void setData(const QVector<double> &error);
4856 void setData(const QVector<double> &errorMinus, const QVector<double> &errorPlus);
4957 void setDataPlottable(QCPAbstractPlottable* plottable);
@@ -71,5 +79,5 @@ public:
7179
7280 // reimplemented virtual methods:
7381 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const;
74- // virtual QCPPlottableInterface1D *interface1D();
82+ virtual QCPPlottableInterface1D *interface1D();
7583 };
--- a/plottable-financial.sip
+++ b/plottable-financial.sip
@@ -33,6 +33,7 @@ public:
3333 double close;
3434 };
3535
36+typedef QCPDataContainer<QCPFinancialData> QCPFinancialDataContainer;
3637 typedef QCPAbstractPlottable1D<QCPFinancialData> QCPAbstractPlottable1D_QCPFinancialData;
3738
3839 class QCPFinancial : public QCPAbstractPlottable1D_QCPFinancialData
@@ -52,11 +53,14 @@ public:
5253 ,csCandlestick ///< Candlestick representation
5354 };
5455
55- explicit QCPFinancial(QCPAxis *keyAxis, QCPAxis *valueAxis);
56+ explicit QCPFinancial(QCPAxis *keyAxis, QCPAxis *valueAxis) /Transfer/;
5657 virtual ~QCPFinancial();
5758
5859 // getters:
59- //QSharedPointer<QCPFinancialDataContainer> data() const;
60+ QCPFinancialDataContainer* data() const;
61+ %MethodCode
62+ sipRes = sipCpp->data().data();
63+ %End
6064 ChartStyle chartStyle() const;
6165 double width() const;
6266 WidthType widthType() const;
@@ -67,7 +71,10 @@ public:
6771 QPen penNegative() const;
6872
6973 // setters:
70- //void setData(QSharedPointer<QCPFinancialDataContainer> data);
74+ void setData(QCPFinancialDataContainer *data /Transfer/);
75+ %MethodCode
76+ sipCpp->setData(QSharedPointer<QCPFinancialDataContainer>(a0));
77+ %End
7178 void setData(const QVector<double> &keys, const QVector<double> &open, const QVector<double> &high, const QVector<double> &low, const QVector<double> &close, bool alreadySorted=false);
7279 void setChartStyle(ChartStyle style);
7380 void setWidth(double width);
@@ -89,5 +96,5 @@ public:
8996 virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const;
9097
9198 // static methods:
92- //static QCPFinancialDataContainer timeSeriesToOhlc(const QVector<double> &time, const QVector<double> &value, double timeBinSize, double timeBinOffset = 0);
99+ static QCPFinancialDataContainer timeSeriesToOhlc(const QVector<double> &time, const QVector<double> &value, double timeBinSize, double timeBinOffset = 0);
93100 };
--- a/plottable-graph.sip
+++ b/plottable-graph.sip
@@ -30,7 +30,7 @@ public:
3030 double value;
3131 };
3232
33-
33+typedef QCPDataContainer<QCPGraphData> QCPGraphDataContainer;
3434 typedef QCPAbstractPlottable1D<QCPGraphData> QCPAbstractPlottable1D_QCPGraphData;
3535
3636 class QCPGraph : public QCPAbstractPlottable1D_QCPGraphData
@@ -54,8 +54,10 @@ public:
5454 virtual ~QCPGraph();
5555
5656 // getters:
57- // TODO: provide methodcode
58- // QSharedPointer<QCPGraphDataContainer> data() const;
57+ QCPGraphDataContainer* data() const;
58+ %MethodCode
59+ sipRes = sipCpp->data().data();
60+ %End
5961 LineStyle lineStyle() const;
6062 QCPScatterStyle scatterStyle() const;
6163 int scatterSkip() const;
@@ -63,8 +65,10 @@ public:
6365 bool adaptiveSampling() const;
6466
6567 // setters:
66- // TODO: provide methodcode
67- // void setData(QSharedPointer<QCPGraphDataContainer> data);
68+ void setData(QCPGraphDataContainer *data /Transfer/);
69+ %MethodCode
70+ sipCpp->setData(QSharedPointer<QCPGraphDataContainer>(a0));
71+ %End
6872 void setData(const QVector<double> &keys, const QVector<double> &values, bool alreadySorted=false);
6973 void setLineStyle(LineStyle ls);
7074 void setScatterStyle(const QCPScatterStyle &style);
--- a/plottable-statisticalbox.sip
+++ b/plottable-statisticalbox.sip
@@ -35,6 +35,7 @@ public:
3535 QVector<double> outliers;
3636 };
3737
38+typedef QCPDataContainer<QCPStatisticalBoxData> QCPStatisticalBoxDataContainer;
3839 typedef QCPAbstractPlottable1D<QCPStatisticalBoxData> QCPAbstractPlottable1D_QCPStatisticalBoxData;
3940
4041 class QCPStatisticalBox : public QCPAbstractPlottable1D_QCPStatisticalBoxData
@@ -45,10 +46,13 @@ class QCPStatisticalBox : public QCPAbstractPlottable1D_QCPStatisticalBoxData
4546 typedef QCPAbstractPlottable1D<QCPStatisticalBoxData> QCPAbstractPlottable1D_QCPStatisticalBoxData;
4647 %End
4748 public:
48- explicit QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis);
49+ explicit QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis) /Transfer/;
4950
5051 // getters:
51- //QSharedPointer<QCPStatisticalBoxDataContainer> data() const;
52+ QCPStatisticalBoxDataContainer* data() const;
53+ %MethodCode
54+ sipRes = sipCpp->data().data();
55+ %End
5256 double width() const;
5357 double whiskerWidth() const;
5458 QPen whiskerPen() const;
@@ -58,7 +62,10 @@ public:
5862 QCPScatterStyle outlierStyle() const;
5963
6064 // setters:
61- //void setData(QSharedPointer<QCPStatisticalBoxDataContainer> data);
65+ void setData(QCPStatisticalBoxDataContainer *data /Transfer/);
66+ %MethodCode
67+ sipCpp->setData(QSharedPointer<QCPStatisticalBoxDataContainer>(a0));
68+ %End
6269 void setData(const QVector<double> &keys, const QVector<double> &minimum, const QVector<double> &lowerQuartile, const QVector<double> &median, const QVector<double> &upperQuartile, const QVector<double> &maximum, bool alreadySorted=false);
6370 void setWidth(double width);
6471 void setWhiskerWidth(double width);
--- /dev/null
+++ b/selectiondecorator-bracket.sip
@@ -0,0 +1,54 @@
1+/** PyQt5 binding for QCustomPlot v2
2+ *
3+ * Authors: Dmitry Voronin, Giuseppe Corbelli, Christopher Gilbert
4+ * License: MIT
5+ *
6+ * QCustomPlot author: Emanuel Eichhammer
7+ * QCustomPlot Website/Contact: http://www.qcustomplot.com
8+ */
9+
10+
11+class QCPSelectionDecoratorBracket : public QCPSelectionDecorator /NoDefaultCtors/
12+{
13+%TypeHeaderCode
14+#include <QCustomPlot/src/qcp.h>
15+%End
16+public:
17+ enum BracketStyle { bsSquareBracket ///< A square bracket is drawn.
18+ ,bsHalfEllipse ///< A half ellipse is drawn. The size of the ellipse is given by the bracket width/height properties.
19+ ,bsEllipse ///< An ellipse is drawn. The size of the ellipse is given by the bracket width/height properties.
20+ ,bsPlus ///< A plus is drawn.
21+ ,bsUserStyle ///< Start custom bracket styles at this index when subclassing and reimplementing \ref drawBracket.
22+ };
23+
24+ QCPSelectionDecoratorBracket();
25+ virtual ~QCPSelectionDecoratorBracket();
26+
27+ // getters:
28+ QPen bracketPen() const;
29+ QBrush bracketBrush() const;
30+ int bracketWidth() const;
31+ int bracketHeight() const;
32+ BracketStyle bracketStyle() const;
33+ bool tangentToData() const;
34+ int tangentAverage() const;
35+
36+ // setters:
37+ void setBracketPen(const QPen &pen);
38+ void setBracketBrush(const QBrush &brush);
39+ void setBracketWidth(int width);
40+ void setBracketHeight(int height);
41+ void setBracketStyle(BracketStyle style);
42+ void setTangentToData(bool enabled);
43+ void setTangentAverage(int pointCount);
44+
45+ // introduced virtual methods:
46+ virtual void drawBracket(QCPPainter *painter, int direction) const;
47+
48+ // virtual methods:
49+ virtual void drawDecoration(QCPPainter *painter, QCPDataSelection selection);
50+
51+private:
52+ QCPSelectionDecoratorBracket(const QCPSelectionDecoratorBracket&);
53+ QCPSelectionDecoratorBracket& operator=(const QCPSelectionDecoratorBracket&);
54+};
--- a/setup.py
+++ b/setup.py
@@ -164,17 +164,17 @@ class MyBuilderExt(build_ext):
164164 return join(cfg.default_sip_dir, 'PyQt5')
165165
166166 setup(
167- name='QCustomPlot',
167+ name='QCustomPlot2',
168168 version='2.0.1',
169- description='QCustomPlot is a PyQt5 widget for plotting and data visualization',
170- author='Dmitry Voronin, Giuseppe Corbelli',
169+ description='QCustomPlot is a Qt widget for plotting and data visualization',
170+ author='Dmitry Voronin, Giuseppe Corbelli, Christopher Gilbert',
171171 author_email='carriingfate92@yandex.ru',
172- url='https://github.com/dimv36/QCustomPlot-PyQt5',
172+ url='https://github.com/cjgdev/QCustomPlot2-PyQt5',
173173 platforms=['Linux'],
174174 license='MIT',
175175 ext_modules=[
176176 Extension(
177- 'QCustomPlot',
177+ 'QCustomPlot2',
178178 ['all.sip'],
179179 include_dirs=['.']
180180 ),