I have trouble using pygtgraph scrolling plots
The expected results are quite similar to the pyqtgraph-examples-scrolling plots-plot5
X-values are times, which can be generated by a simple function. Y-Values are random values.
Each 10 seconds samples as one chunk and each plot can have max. 30 seconds samples, which means 3 chunks. The current plot window only shows the latest 10 seconds samples
For example, now there are total 60 seconds samples:
My current code is below, it can only show latest 30s data.
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import random
win = pg.GraphicsLayoutWidget(show=True)
win.setWindowTitle('Scrolling Plots')
p1 = win.addPlot()
p1.setYRange(0,10)
xVal = [0]
yVal = [0]
def genTime(): # used to generate time
t = 0
while True:
t += np.random.random_sample()
yield t
t = np.ceil(t)
xTime = genTime()
#=====================================================
viewSize = 10 # current window show only latest 10s data
plotSize = 30 # plot 30s data -> 3 chunk
lstCurves = [] # List for Curves
def update():
global p1, xVal, yVal, lstCurves
#for c in lstCurves:
# c.setPos(xVal[-1], 0)
i = np.ceil(xVal[-1]) % viewSize # e.g. when time is 9.2s -> one 10s view size is full, append to curves list as one chunk
if i == 0:
curve = p1.plot()
lstCurves.append(curve)
xValLast = xVal[-1]
yValLast = yVal[-1]
xVal = [xValLast]
yVal = [yValLast]
while len(lstCurves) > 3: # max 3 chunk (30 s)
p1.removeItem(lstCurves.pop(0)) # remove the oldest 10s
else:
curve = lstCurves[-1] # latest 10s curve
xVal.append(next(xTime))
yVal.append(random.randint(0,9))
curve.setData(xVal, yVal)
print(len(lstCurves))
#======================================================
timer = pg.QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1000)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
I have tried using curve.setPos(xx, 0)
, It looks like the whole curve is moving along the x-axis, but the mapping relationship between X-value and Y-value is broken
I have also tried using setXRange()
to dynamically change x-axis display-range in update()
func. But in this case, I can't use the mouse to drag the x-axis back to view the old data any more.
My English is not good, I hope you can understand my question. Any suggestions would be sincerely appreciated!
The reasons your code don't do what you want are:
setRange()
method inside the update
function, it will force that range every time you add another value to the data. Then the drag will not work as you wantWell, from my perspective using the mouse drag to visualize the other data is not very convenient, I suggest to use an external widget to control the range of the data you want to view, like, a slider, scroll bar, spin box, ...
A QScrollBar
can do the job and it will look esthetic in a GUI.
Before my Alternative Solution, I have a suggestion for you:
global
, and you could reuse the widget for other purposes.Try this:
import sys
import random
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
class MyApp(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
## Creating the Widgets and Layouts
self.plot_widget = pg.PlotWidget()
self.layout = QtGui.QVBoxLayout()
self.sbutton = QtGui.QPushButton("Start / Continue")
self.ebutton = QtGui.QPushButton("Stop")
self.timer = pg.QtCore.QTimer()
self.scroll = QtGui.QScrollBar(QtCore.Qt.Horizontal)
## Creating the variables and constants
self.data = [[0], [random.randint(0,9)]] ## [xVal, yVal] to create less variables
self.plot_item = self.plot_widget.plot(*self.data)
self.plot_widget.setYRange(0, 10)
self.xTime = self.genTime()
self.vsize = 10
self.psize = 30
## Building the Widget
self.setLayout(self.layout)
self.layout.addWidget(self.sbutton)
self.layout.addWidget(self.ebutton)
self.layout.addWidget(self.plot_widget)
self.layout.addWidget(self.scroll)
## Changing some properties of the widgets
self.plot_widget.setMouseEnabled(x=False, y=False)
self.ebutton.setEnabled(False)
self.scroll.setEnabled(False)
self.scroll.setMaximum(self.psize-self.vsize)
self.scroll.setValue(self.psize-self.vsize)
## Coneccting the signals
self.sbutton.clicked.connect(self.start)
self.ebutton.clicked.connect(self.stop)
self.timer.timeout.connect(self.update)
self.scroll.valueChanged.connect(self.upd_scroll)
def genTime(self): # used to generate time
t = 0
while True:
t += np.random.random_sample()
yield t
t = np.ceil(t)
def upd_scroll(self):
val = self.scroll.value()
xmax = np.ceil(self.data[0][-1+self.vsize-self.psize+val])-1
xmin = xmax-self.vsize
self.plot_widget.setXRange(xmin, xmax)
def update(self):
num = len(self.data[0])
if num <= self.psize:
self.plot_item.setData(*self.data)
else:
self.plot_item.setData(
self.data[0][-self.psize:],
self.data[1][-self.psize:]
)
if num == self.vsize:
self.scroll.setEnabled(True)
self.data[0].append(next(self.xTime))
self.data[1].append(random.randint(0,9))
if num > self.vsize :
self.upd_scroll()
def start(self):
self.sbutton.setEnabled(False)
self.ebutton.setEnabled(True)
self.timer.start(100)
def stop(self):
self.sbutton.setEnabled(True)
self.ebutton.setEnabled(False)
self.timer.stop()
self.upd_scroll()
def closeEvent(self, event):
self.timer.stop()
event.accept()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
It may look like this: