【问题标题】:How to implement 'playhead' kind of feature on a simple graph?如何在简单的图表上实现“播放头”类型的功能?
【发布时间】:2021-05-28 23:47:21
【问题描述】:

这是我想要实现的目标:

  • 我有一个使用 Pyqtgraph 绘制的 x vs y 数据的简单图
  • 叠加在此图表上,我希望有一个“播放头”类型的线条,它在 x 轴上移动(类似于视频编辑器中的时间线滑动条)
  • 应该从回调函数动态接收这条线在 x 轴上的位置

请看下面的图片以清楚地理解。

【问题讨论】:

  • 你想让它自动移动吗(比如扫描所有的情节)?还是手动?
  • 线条的位置应该根据它从外部函数接收到的输入(与 x 轴值完全对应)而改变。这清楚吗?如果我解释得不够清楚,请告诉我。

标签: python pyqt5 pyqtgraph


【解决方案1】:

你可以创建一个无限的垂直线对象,这是pyqtgraph的一部分:InfiniteLine

import pyqtgraph as pg
v_line = pg.InfiniteLine(angle=90, movable=True)

此对象具有可通过拖动移动的属性,每次移动线时它都会发出一个信号:sigPositionChanged。您可以将此信号与返回其位置值或数据的最接近 x 值及其相应 y 值的函数连接。

v_line.sigPositionChanged.connect(some_function)

您在评论中说,该位置取决于函数的输入或输出。然后你可以使用InfiniteLine对象的setPos()方法改变位置。

v_line.setPos(10) 

下面是我做的一个例子,你可以从代码中得到更好的理解。 在本例中,您可以手动拖动垂直线,它只能“放置”在 x 数据的值中,并且 x 和 y 值将显示在框中。

此外,您只能更改与 x 值对应的框的值,当您按 Return/Enter 键时,行的位置将转到数据中最近的 x 值。

代码如下:

import sys 
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui

class MyApp(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        lay_1 = QtGui.QVBoxLayout()
        lay_2 = QtGui.QHBoxLayout()
        self.setLayout(lay_1)
        label_1 = QtGui.QLabel('Marker Value :  x = ')
        label_2 = QtGui.QLabel(', y = ')
        self.box_1 = QtGui.QDoubleSpinBox()
        self.box_1.setButtonSymbols(2)
        self.box_2 = QtGui.QDoubleSpinBox()
        self.box_2.setButtonSymbols(2)
        self.box_2.setReadOnly(True)
        spacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
        self.graf = pg.PlotWidget()
        self.plt = self.graf.plot()
        self.v_line = pg.InfiniteLine(angle=90, movable=True)
        lay_1.addLayout(lay_2)
        lay_1.addWidget(self.graf)
        lay_2.addWidget(label_1)
        lay_2.addWidget(self.box_1)
        lay_2.addWidget(label_2)
        lay_2.addWidget(self.box_2)
        lay_2.addItem(spacer)
        self.graf.addItem(self.v_line)
        x = np.arange(100)/10*np.pi
        y = np.sin(x)*np.exp(-x/10)*10
        self.box_1.setRange(x.min(), x.max())
        self.box_2.setRange(y.min(), y.max())
        self.data = [x, y]
        self.plt.setData(*self.data)
        self.v_line.sigPositionChanged.connect(self.upd_drag)
        self.box_1.lineEdit().returnPressed.connect(self.box_edited)

    def get_xy(self, x_val):
        '''For filtering the position of the vertical lines, selecting
        limits and only prefered positions related to the x-data'''
        x_data = self.data[0]
        y_data = self.data[1]
        x_min = min(x_data)
        x_max = max(x_data)
        if x_val < x_min:
            x_val = x_min
        elif x_val > x_max: 
            x_val = x_max
        i = np.abs(x_data-x_val).argmin()
        x_val = x_data[i]
        y_val = y_data[i]
        return x_val, y_val

    def box_edited(self):
        pos = self.box_1.value()
        self.upd_v_line(pos)
        
    def upd_drag(self, line):
        pos = line.pos()[0]
        self.upd_v_line(pos)

    def upd_v_line(self, pos):
        x, y = self.get_xy(pos)
        self.v_line.setPos(x)
        self.box_1.setValue(x)
        self.box_2.setValue(y)

if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

【讨论】:

    猜你喜欢
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多