0

I am trying to plot a line with matplotlib, but the data points is huge (4410000), so I plan to down-sample it, I refer to the example on the matplotlib website resampling data, and an another similar question Matplotlib callbacks don't work when matplotlib.FigureCanvas is embedded in a PyQt5 application?

but my demo-code bellow doesn't work yet, why?:

import sys
import numpy as np
from PyQt5 import QtWidgets  # import PyQt5 before matplotlib

import matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

matplotlib.use("Qt5Agg")


class DataDisplayDownsampler(object):

    def __init__(self, xdata, ydata):
        self.origYData = ydata
        self.origXData = xdata
        self.max_points = 3000
        self.delta = xdata[-1] - xdata[0]
        self.line = None

    def downsample(self, xstart, xend):
        # get the points in the view range
        mask = (self.origXData > xstart) & (self.origXData < xend)
        # dilate the mask by one to catch the points just outside
        # of the view range to not truncate the line
        mask = np.convolve([1, 1], mask, mode='same').astype(bool)
        # sort out how many points to drop
        ratio = max(np.sum(mask) // self.max_points, 1)

        # mask data
        xdata = self.origXData[mask]
        ydata = self.origYData[mask]

        # downsample data
        xdata = xdata[::ratio]
        ydata = ydata[::ratio]

        print("using {} of {} visible points".format(
            len(ydata), np.sum(mask)))

        return xdata, ydata

    def update(self, ax):
        # Update the line
        lims = ax.viewLim
        if np.abs(lims.width - self.delta) > 1e-8:
            self.delta = lims.width
            xstart, xend = lims.intervalx
            self.line.set_data(*self.downsample(xstart, xend))
            ax.figure.canvas.draw_idle()


class MplCanvas(FigureCanvasQTAgg):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axe = fig.add_subplot(111)
        super().__init__(fig)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        sc = MplCanvas(self, width=5, height=4, dpi=100)
        fs = 44100
        time_length = 100
        x = np.arange(fs * time_length) / fs
        y1 = np.random.randn(len(x))

        ds = DataDisplayDownsampler(x, y1)
        ds.line, = sc.axe.plot(x, y1, lw=2, label='random noise')
        sc.axe.callbacks.connect('xlim_changed', ds.update)  # doesn't work

        toolbar = NavigationToolbar(sc, self)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(toolbar)
        layout.addWidget(sc)

        widget = QtWidgets.QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.show()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    mw = window
    mw.show()
    app.exec_()

bactone
  • 107
  • 1
  • 8

0 Answers0