Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QT charts extremely slow - QLineSeries
Forum Updated to NodeBB v4.3 + New Features

QT charts extremely slow - QLineSeries

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qtchartqtchartsqlineseriespython
25 Posts 4 Posters 8.2k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Witc

    @JonB @fcarney @Bob64
    Probably with my best solution below, it takes about 5 seconds to plot 5000 values

    Python file - the slot fillSigChart is called from QML

    @Slot(QLineSeries)
        def fillSigChart(self,serie1):
           
            start = time.time()
            for i in self.x:
                serie1.append(i, self.y[i])   # filling serie with my prepared data
            end = time.time()
            print(end - start)
    

    In QML file: I call the slot above

    Connections{ 
      target: backend
      function onSigPlotData(x,y){
        myChart.removeAllSeries();
        myChart.zoomReset()
        var serie1 = myChart.createSeries(ChartView.SeriesTypeLine, "Signal ", axisX, axisY);
        serie1.useOpenGl = true
                
        backend.fillSigChart(serie1)       // pass serie1 to python and then fill it with data
       } 
     }
    
    
    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by
    #21

    @Witc
    OK, so at least we understand how to/that you can go from QML to Python and back passing a series around.

    It might be that this is as good as it gets. However, you are still appending points one by one and this may be "expensive", we don't know.

    There is an overload of append() which accepts a pre-built list of points: PySide2.QtCharts.QtCharts.QXYSeries.append(points). In C++ this is void QXYSeries::append(const QList<QPointF> &points).

    You should try this. So instead of serie1.append(i, self.y[i]) you want to first build all the points into a list in the loop and then append them in one go afterwards. I would guess something like:

    points = []
    for i in self.x:
        points.append(QPointF(i, self.y[i]))   # filling points with my prepared data
    serie.append(points)  # append list of points in one call
    

    Does that make it any faster?

    Even better, given that you start with no points you need to retain and just want the newly created points, might be serie.replace(points)

    Note: This is much faster than replacing data points one by one, or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced() when the points have been replaced.

    W 1 Reply Last reply
    2
    • B Offline
      B Offline
      Bob64
      wrote on last edited by Bob64
      #22

      I concur with @JonB regarding appending multiple points at once, or replacing the data vs appending points one at a time. I found it made a massive difference.

      One point at a time is slow in C++, but you will be paying a double penalty in Python as each individual call has to go through a wrapper layer. The Python overhead of the calls taking a list will mainly be the conversion of the Python list to the QList. I would hope that conversions like Python list to QList are optimised as much as they can be as they will be pervasive operations in a Python Qt application.

      1 Reply Last reply
      0
      • JonBJ JonB

        @Witc
        OK, so at least we understand how to/that you can go from QML to Python and back passing a series around.

        It might be that this is as good as it gets. However, you are still appending points one by one and this may be "expensive", we don't know.

        There is an overload of append() which accepts a pre-built list of points: PySide2.QtCharts.QtCharts.QXYSeries.append(points). In C++ this is void QXYSeries::append(const QList<QPointF> &points).

        You should try this. So instead of serie1.append(i, self.y[i]) you want to first build all the points into a list in the loop and then append them in one go afterwards. I would guess something like:

        points = []
        for i in self.x:
            points.append(QPointF(i, self.y[i]))   # filling points with my prepared data
        serie.append(points)  # append list of points in one call
        

        Does that make it any faster?

        Even better, given that you start with no points you need to retain and just want the newly created points, might be serie.replace(points)

        Note: This is much faster than replacing data points one by one, or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced() when the points have been replaced.

        W Offline
        W Offline
        Witc
        wrote on last edited by
        #23

        @JonB

        Your idea to serie1.append(points) had no improvement - it took also about 5 seconds, but your second idea with serie1.replace(points) has great result!

        Solution in python:

        start = time.time()
        points = []
        for i in self.x:
             points.append(QPointF(i, self.y[i]))   # filling points with my prepared data 
        serie1.replace(points)  # fill list of points in one call
        end = time.time()
        print(end - start)
        

        for 50000 values it takes only 126 ms, for 5000 values it takes 13 ms

        I think we can consider this thread as solved - or any other ideas?
        Thank you all @JonB @Bob64 @fcarney for help!

        JonBJ 1 Reply Last reply
        2
        • W Witc

          @JonB

          Your idea to serie1.append(points) had no improvement - it took also about 5 seconds, but your second idea with serie1.replace(points) has great result!

          Solution in python:

          start = time.time()
          points = []
          for i in self.x:
               points.append(QPointF(i, self.y[i]))   # filling points with my prepared data 
          serie1.replace(points)  # fill list of points in one call
          end = time.time()
          print(end - start)
          

          for 50000 values it takes only 126 ms, for 5000 values it takes 13 ms

          I think we can consider this thread as solved - or any other ideas?
          Thank you all @JonB @Bob64 @fcarney for help!

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #24

          @Witc
          :) I guess the append() maybe just appends one at a time, even if it's empty. The replace() presumably does not have to do that.

          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #25

            "append" causes a redraw. There is no way to disable the redraw that I can find. The QML api for charts is kinda crappy for adding data points. Which is why I had to use "replace" in C++. I have done thousands of points this way and it doesn't cause delays in the UI interface.

            C++ is a perfectly valid school of magic.

            1 Reply Last reply
            1
            • JonBJ JonB referenced this topic on
            • JonBJ JonB referenced this topic on
            • JonBJ JonB referenced this topic on

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved