Search code examples
pythonraspberry-pi3pyside2dynamically-generatedgraphing

Graphing dynamically with python and QML Oscilloscope works great, but the same program doesn't work in raspberry pi, replace function don't work


I am running a Qt QML application with Python. I am graphing values using qt charts dynamically. To do this I made a similar code as in the oscilloscope example from Qt documentation, except that instead of C++ I used Python. I first created a line series in QML. Then I exposed a class called "Bridge" as "con" to QML using context property. Inside the class called "Bridge", I generated the initial data. Then I am updating the chart every time the timer counts by passing the series to the "Bridge" class and then using the replace function so that the series gets the data fastly instead of using clear and append.

import QtQuick 2.10
import QtQuick.Window 2.5
import QtQuick.Controls 2.4
import QtCharts 2.0

Window {
    id: window
    title: qsTr("QML and Python graphing dynamically")
    width: 640
    height: 480
    color: "#1b480d"
    visible: true

    Timer{
        id: miTimer
        interval: 1 / 24 * 1000  //update every 200ms
        running: true
        repeat: true
        onTriggered: {
            con.update_series(chart.series(0))
        }
    }

    Label {
        id: label
        x: 298
        color: "#f1f3f4"
        text: qsTr("Graphin dynamically with python")
        anchors.horizontalCenterOffset: 0
        anchors.top: parent.top
        anchors.topMargin: 10
        font.bold: true
        font.pointSize: 25
        anchors.horizontalCenter: parent.horizontalCenter
    }

    ChartView {
        id: chart
        x: 180
        y: 90
        width: 500
        height: 300
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter

        ValueAxis{
            id: axisX
            min: 0
            max: 200
        }

        ValueAxis{
            id: axisY
            min: 0
            max: 100
        }

        }

    Component.onCompleted: {
        console.log("Se ha iniciado QML\n")
        var series = chart.createSeries(ChartView.SeriesTypeLine,"My grafico",axisX,axisY)
        con.generateData()
    }
}

This QML essentially is a chart in the center. In Component.onCompleted, I create a line series which is using a context property class, I update it using python.

# This Python file uses the following encoding: utf-8
import sys
from os.path import abspath, dirname, join
import random

from PySide2.QtCore import QObject, Slot, QPoint
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCharts import QtCharts
from PySide2.QtWidgets import QApplication # <---

class Bridge(QObject):
    def __init__(self, parent=None):
        super(Bridge, self).__init__(parent)
        self.my_data = []
        self.index = -1

    @Slot(QtCharts.QAbstractSeries)
    def update_series(self, series):
        self.index += 1
        if(self.index > 4):
            self.index = 0
        series.replace(self.my_data[self.index])

    @Slot()
    def generateData(self):
        my_data = []

        for i in range (5):
            my_list = []
            for j in range(200):
                my_list.append(QPoint(j,random.uniform(0,100)))
            self.my_data.append(my_list)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    engine = QQmlApplicationEngine()

    bridge = Bridge()

    # Expose the Python object to QML
    context = engine.rootContext()
    context.setContextProperty("con", bridge)

    #engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))
    # Get the path of the current directory, and then add the name
    # of the QML file, to load it.
    qmlFile = join(dirname(__file__), 'main.qml')
    engine.load(abspath(qmlFile))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

It works nicely.

enter image description here

The problem is that the exact same program doesn't work in the raspberry pi 3. The error is on series.replace(self.my_data[self.index])

It says TypeError:

replace(double,double,double,double) needs 4 argument(s), 1 given!

To run the code on the raspberry pi I installed Pyside2 libraries from: https://forum.qt.io/topic/112813/installing-pyside2-on-raspberry-pi/7 Its version is PySide2 5.11.2.

And for QML modules I used sudo apt-get install qml-module-xxxxxxx for each needed library


Solution

  • One possible solution is to replace

    series.replace(self.my_data[self.index])
    

    with:

    series.clear()
    for p in self.my_data[self.index]:
        series.append(p.x(), p.y())