I'm kinda new to PySide2 and QML and I really need a way to replace all the points in an XYSeries at once. Since the QML item does not have a function that does so, I thought I had to create a custom class (that would inherits from QtCharts.QXYSeries), implement the function I need and then register the new type with PySide2.QtQml.qmlRegisterType, but I don't know how that should be done and I haven't been able to find an answer online (or at least one that I could understand).
So, to cut a long story short, what I need to know is if there's a way to change all the points of an XYSeries and how can it be done (e.g. creating a custom class and registering it, accessing the Item declarend in the .qml file from python and chaning its properties, etc...).
I know my question is really vague but I do not know where to look and what to do...
EDIT
I have a python class that acquires data from an instruments and generates an array of X and Y points. Since this arrays are made from at least 1000 points and since I need to have a refresh rate of at least 1Hz, it's impossible to do it adding one point at a time (I have an signal that sends the whole array to the qml interface and there, for the moment, I simply clear the series and add one XY couple at a time. It works but it's too damn slow).
One possible solution is to create a class that allows access to a QML object from Python, in this case I create the helper class that I export to QML through setContextProperty by linking the series with a qproperty.
main.py
import random
from PySide2 import QtCore, QtWidgets, QtQml
from PySide2.QtCharts import QtCharts
class Helper(QtCore.QObject):
serieChanged = QtCore.Signal()
def __init__(self, parent=None):
super(Helper, self).__init__(parent)
self._serie = None
def serie(self):
return self._serie
def setSerie(self, serie):
if self._serie == serie:
return
self._serie = serie
self.serieChanged.emit()
serie = QtCore.Property(QtCharts.QXYSeries, fget=serie, fset=setSerie, notify=serieChanged)
@QtCore.Slot(list)
def replace_points(self, points):
if self._serie is not None:
self._serie.replace(points)
class Provider(QtCore.QObject):
pointsChanged = QtCore.Signal(list)
def __init__(self, parent=None):
super(Provider, self).__init__(parent)
timer = QtCore.QTimer(
self,
interval=100,
timeout=self.generate_points
)
timer.start()
@QtCore.Slot()
def generate_points(self):
points = []
for i in range(101):
point = QtCore.QPointF(i, random.uniform(-10, 10))
points.append(point)
self.pointsChanged.emit(points)
if __name__ == '__main__':
import os
import sys
app = QtWidgets.QApplication(sys.argv)
helper = Helper()
provider = Provider()
provider.pointsChanged.connect(helper.replace_points)
engine = QtQml.QQmlApplicationEngine()
engine.rootContext().setContextProperty("helper", helper)
file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
engine.load(QtCore.QUrl.fromLocalFile(file))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtCharts 2.3
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ChartView{
anchors.fill: parent
LineSeries{
id: serie
axisX: axisX
axisY: axisY
}
ValueAxis {
id: axisX
min: 0
max: 100
}
ValueAxis {
id: axisY
min: -10
max: 10
}
Component.onCompleted: helper.serie = serie
}
}