Python / Matplotlib / Pyside快速时间跟踪滚动 [英] Python/Matplotlib/Pyside Fast Timetrace scrolling

查看:95
本文介绍了Python / Matplotlib / Pyside快速时间跟踪滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有大量的时间痕迹,必须进行目视检查,因此我需要一个快速滚动工具。

I have large time-traces that must be inspected visually, so I need a fast scrolling tool.

如何实现最快的Maplotlib / Pyside滚动?

How can I achieve the fastest Maplotlib/Pyside scrolling?

我知道,我在MPL图形上添加了PySide滚动条,并使用 set_xlim()方法。这还不够快,特别是因为在最终应用程序中,我必须在不同的子图中至少有8条时间轨迹,这些轨迹必须全部一起滚动。 附上了该图的图

Right know, I added a PySide scroll-bar to a MPL figure and update the x-range of the plot with set_xlim() method. This is not fast enough especially because in the final application I have at least 8 time-traces in different subplots that must all scroll together. A figure of the plot is attached.

还有改进的空间吗?

在这里,我附上了演示代码,该代码演示了相对较低的滚动。很长,但几乎是所有样板代码。有趣的一点(需要改进)是在 xpos_changed()方法中,更改了图的xlimits。

Here I attach the demo code that demonstrate the relatively low scrolling. It's long but it's almost all boiler-plate code. The interesting bit (that needs improvement) is in xpos_changed() method where the plot xlimits are changed.

编辑:下面,我结合了 tcaswell 建议的一些微优化,但是更新速度没有提高。

Below I incorporated some micro-optimizations suggested by tcaswell, but the update speed is not improved.

from PySide import QtGui, QtCore
import pylab as plt
import numpy as np

N_SAMPLES = 1e6

def test_plot():
    time = np.arange(N_SAMPLES)*1e-3
    sample = np.random.randn(N_SAMPLES)
    plt.plot(time, sample, label="Gaussian noise")
    plt.title("1000s Timetrace \n (use the slider to scroll and the spin-box to set the width)")
    plt.xlabel('Time (s)')
    plt.legend(fancybox=True)
    q = ScrollingToolQT(plt.gcf(), scroll_step=10)
    return q   # WARNING: it's important to return this object otherwise
               # python will delete the reference and the GUI will not respond!


class ScrollingToolQT(object):
    def __init__(self, fig, scroll_step=10):
        # Setup data range variables for scrolling
        self.fig = fig
        self.scroll_step = scroll_step
        self.xmin, self.xmax = fig.axes[0].get_xlim()
        self.width = 1 # axis units
        self.pos = 0   # axis units
        self.scale = 1e3 # conversion betweeen scrolling units and axis units

        # Save some MPL shortcuts
        self.ax = self.fig.axes[0]
        self.draw = self.fig.canvas.draw
        #self.draw_idle = self.fig.canvas.draw_idle

        # Retrive the QMainWindow used by current figure and add a toolbar
        # to host the new widgets
        QMainWin = fig.canvas.parent()
        toolbar = QtGui.QToolBar(QMainWin)
        QMainWin.addToolBar(QtCore.Qt.BottomToolBarArea, toolbar)

        # Create the slider and spinbox for x-axis scrolling in toolbar
        self.set_slider(toolbar)
        self.set_spinbox(toolbar)

        # Set the initial xlimits coherently with values in slider and spinbox
        self.ax.set_xlim(self.pos,self.pos+self.width)
        self.draw()

    def set_slider(self, parent):
        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, parent=parent)
        self.slider.setTickPosition(QtGui.QSlider.TicksAbove)
        self.slider.setTickInterval((self.xmax-self.xmin)/10.*self.scale)
        self.slider.setMinimum(self.xmin*self.scale)
        self.slider.setMaximum((self.xmax-self.width)*self.scale)
        self.slider.setSingleStep(self.width*self.scale/4.)
        self.slider.setPageStep(self.scroll_step*self.width*self.scale)
        self.slider.setValue(self.pos*self.scale) # set the initial position
        self.slider.valueChanged.connect(self.xpos_changed)
        parent.addWidget(self.slider) 

    def set_spinbox(self, parent):
        self.spinb = QtGui.QDoubleSpinBox(parent=parent)
        self.spinb.setDecimals(3)
        self.spinb.setRange(0.001,3600.)
        self.spinb.setSuffix(" s")
        self.spinb.setValue(self.width)   # set the initial width
        self.spinb.valueChanged.connect(self.xwidth_changed)
        parent.addWidget(self.spinb)

    def xpos_changed(self, pos):
        #pprint("Position (in scroll units) %f\n" %pos)
        pos /= self.scale
        self.ax.set_xlim(pos, pos+self.width)
        self.draw()

    def xwidth_changed(self, width):
        #pprint("Width (axis units) %f\n" % step)
        if width <= 0: return
        self.width = width
        self.slider.setSingleStep(self.width*self.scale/5.)
        self.slider.setPageStep(self.scroll_step*self.width*self.scale)
        old_xlim = self.ax.get_xlim()
        self.xpos_changed(old_xlim[0]*self.scale)


if __name__ == "__main__":
    q = test_plot()
    plt.show()


推荐答案

这似乎更快或更敏感:

from PySide import QtGui, QtCore
import pylab as plt
import numpy as np

N_SAMPLES = 1e6

def test_plot():
    time = np.arange(N_SAMPLES)*1e-3
    sample = np.random.randn(N_SAMPLES)
    plt.plot(time, sample, label="Gaussian noise")
    plt.legend(fancybox=True)
    plt.title("Use the slider to scroll and the spin-box to set the width")
    q = ScrollingToolQT(plt.gcf())
    return q   # WARNING: it's important to return this object otherwise
               # python will delete the reference and the GUI will not respond!


class ScrollingToolQT(object):
    def __init__(self, fig):
        # Setup data range variables for scrolling
        self.fig = fig
        self.xmin, self.xmax = fig.axes[0].get_xlim()
        self.step = 1 # axis units

        self.scale = 1e3 # conversion betweeen scrolling units and axis units

        # Retrive the QMainWindow used by current figure and add a toolbar
        # to host the new widgets
        QMainWin = fig.canvas.parent()
        toolbar = QtGui.QToolBar(QMainWin)
        QMainWin.addToolBar(QtCore.Qt.BottomToolBarArea, toolbar)

        # Create the slider and spinbox for x-axis scrolling in toolbar
        self.set_slider(toolbar)
        self.set_spinbox(toolbar)

        # Set the initial xlimits coherently with values in slider and spinbox
        self.set_xlim = self.fig.axes[0].set_xlim
        self.draw_idle = self.fig.canvas.draw_idle
        self.ax = self.fig.axes[0]
        self.set_xlim(0, self.step)
        self.fig.canvas.draw()

    def set_slider(self, parent):
        # Slider only support integer ranges so use ms as base unit
        smin, smax = self.xmin*self.scale, self.xmax*self.scale

        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, parent=parent)
        self.slider.setTickPosition(QtGui.QSlider.TicksAbove)
        self.slider.setTickInterval((smax-smin)/10.)
        self.slider.setMinimum(smin)
        self.slider.setMaximum(smax-self.step*self.scale)
        self.slider.setSingleStep(self.step*self.scale/5.)
        self.slider.setPageStep(self.step*self.scale)
        self.slider.setValue(0)  # set the initial position
        self.slider.valueChanged.connect(self.xpos_changed)
        parent.addWidget(self.slider)

    def set_spinbox(self, parent):
        self.spinb = QtGui.QDoubleSpinBox(parent=parent)
        self.spinb.setDecimals(3)
        self.spinb.setRange(0.001, 3600.)
        self.spinb.setSuffix(" s")
        self.spinb.setValue(self.step)   # set the initial width
        self.spinb.valueChanged.connect(self.xwidth_changed)
        parent.addWidget(self.spinb)

    def xpos_changed(self, pos):
        #pprint("Position (in scroll units) %f\n" %pos)
        #        self.pos = pos/self.scale
        pos /= self.scale
        self.set_xlim(pos, pos + self.step)
        self.draw_idle()

    def xwidth_changed(self, xwidth):
        #pprint("Width (axis units) %f\n" % step)
        if xwidth <= 0: return
        self.step = xwidth
        self.slider.setSingleStep(self.step*self.scale/5.)
        self.slider.setPageStep(self.step*self.scale)
        old_xlim = self.ax.get_xlim()
        self.xpos_changed(old_xlim[0] * self.scale)
#        self.set_xlim(self.pos,self.pos+self.step)
 #       self.fig.canvas.draw()

if __name__ == "__main__":
    q = test_plot()
    plt.show()

这篇关于Python / Matplotlib / Pyside快速时间跟踪滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆