I am trying to add a ROI in real-time with a button click. Once it is added, the ROI is blocking the line plot to scroll. I tried adding the line Plot widget as a parent to the ROI, that didn't work. Is there any way to make the ROI scroll outside of the view along with line plot? Also, how do I retain the historical data and ROIs, currently, the data is replaced by the new data.
Thanks.
import signal
import time
from math import sin
from threading import Thread
from time import sleep
import pyqtgraph as pg
from pglive.kwargs import Axis
from pglive.sources.data_connector import DataConnector
from pglive.sources.live_axis import LiveAxis
from pglive.sources.live_plot import LiveLinePlot
from pglive.sources.live_plot_widget import LivePlotWidget
"""
In this example Line plot is displayed.
"""
import random
import signal
import sys
from math import sin
from time import sleep
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication,QPushButton
running = True
app = QApplication(sys.argv)
button = QPushButton('Add Rect')
def addRect(button):
print('Added')
roi= pg.ROI((time.time()-3,-1.5),(2,3),pen='g',movable=False)
roi.setZValue(10)
time_axis_plot_widget.addItem(roi)
button.clicked.connect(addRect)
def stop():
"""Stop current QApplication"""
global running
running = False
app.exit(0)
# Connect SIGINT with stop function
signal.signal(signal.SIGINT, lambda sig, frame: stop())
connectors = []
layout = pg.LayoutWidget()
# Define Time plot
left_axis = LiveAxis("left", axisPen="red", textPen="red")
bottom_axis = LiveAxis("bottom", axisPen="green", textPen="green", **{Axis.TICK_FORMAT: Axis.TIME})
time_axis_plot_widget = LivePlotWidget(title="Time Line Plot # 100Hz",
axisItems={'bottom': bottom_axis, 'left': left_axis})
plot = LiveLinePlot()
time_axis_plot_widget.addItem(plot)
connectors.append(DataConnector(plot, max_points=600))
layout.addWidget(time_axis_plot_widget)
layout.addWidget(button)
layout.show()
def sin_wave_generator(*data_connectors):
"""Sinus wave generator"""
x = 0
while running:
x += 1
for data_connector in data_connectors:
data_connector.cb_append_data_point(sin(x * 0.01), time.time())
sleep(0.01)
Thread(target=sin_wave_generator, args=connectors).start()
signal.signal(signal.SIGINT, lambda sig, frame: stop())
app.exec()
stop()
Related
I am trying to create a polygon selector in my PySide2 application. Selector is working fine, but then I want to add functionality to reset/start new polygon when escape button is pressed. Something similar to this PolygonSelector example, when escape is pressed.
https://matplotlib.org/stable/gallery/widgets/polygon_selector_demo.html
I tried method .clear() but it does not seems to work for me.
import sys
import numpy as np
from PySide2 import QtWidgets, QtGui
from matplotlib.backends.backend_qtagg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
from matplotlib.widgets import PolygonSelector
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
shortcut_clear_selection = QtWidgets.QShortcut(QtGui.QKeySequence("Escape"), self._main)
shortcut_clear_selection.activated.connect(self.callback_clear_selection)
layout = QtWidgets.QVBoxLayout(self._main)
static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
layout.addWidget(NavigationToolbar(static_canvas, self))
layout.addWidget(static_canvas)
ax = static_canvas.figure.subplots()
t = np.linspace(0, 10, 501)
ax.plot(t, np.tan(t), ".")
self.poly = PolygonSelector(ax, self.onselect)
def onselect(self, verts):
pass
def callback_clear_selection(self):
# HERE should be the reset part
self.poly.clear()
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
app.activateWindow()
app.raise_()
qapp.exec_()
Problem is, that ESC key release event is not handled by PolygonSelector but Your callback. Therefore, to clear polygon and restart creation of polygon You have to clear polygon data and show selector again. clear method was just hiding selector, but polygon data stayed unchanged.
Change Your callback code into this:
def callback_clear_selection(self):
# HERE should be the reset
self.poly._xs, self.poly._ys = [0], [0]
self.poly._selection_completed = False
self.poly.set_visible(True)
Now, when You press ESC, polygon should be removed and You can start selection of new one.
Some years ago, I already experimented with embedding live matplotlib plots in a PyQt5 GUI. Live plots show a data-stream real-time, captured from a sensor, some process, ... I got that working, and you can read the related posts here:
Matplotlib animation inside your own GUI
How do I plot in real-time in a while loop using matplotlib?
Now I need to do the same thing again. I remember my previous approach worked, but couldn't keep up with fast datastreams. I found a couple of example codes on the internet, that I'd like to present to you. One of them is clearly faster than the other, but I don't know why. I'd like to gain more insights. I believe a deeper understanding will enable me to keep my interactions with PyQt5 and matplotlib efficient.
1. First example
This example is based on this article:
https://matplotlib.org/3.1.1/gallery/user_interfaces/embedding_in_qt_sgskip.html
The article is from the official matplotlib website, and explains how to embed a matplotlib figure in a PyQt5 window.
I did a few minor adjustments to the example code, but the basics are still the same. Please copy-paste the code below to a Python file and run it:
#####################################################################################
# #
# PLOT A LIVE GRAPH IN A PYQT WINDOW #
# EXAMPLE 1 #
# ------------------------------------ #
# This code is inspired on: #
# https://matplotlib.org/3.1.1/gallery/user_interfaces/embedding_in_qt_sgskip.html #
# #
#####################################################################################
from __future__ import annotations
from typing import *
import sys
import os
from matplotlib.backends.qt_compat import QtCore, QtWidgets
# from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvas
# from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib as mpl
import numpy as np
class ApplicationWindow(QtWidgets.QMainWindow):
'''
The PyQt5 main window.
'''
def __init__(self):
super().__init__()
# 1. Window settings
self.setGeometry(300, 300, 800, 400)
self.setWindowTitle("Matplotlib live plot in PyQt - example 1")
self.frm = QtWidgets.QFrame(self)
self.frm.setStyleSheet("QWidget { background-color: #eeeeec; }")
self.lyt = QtWidgets.QVBoxLayout()
self.frm.setLayout(self.lyt)
self.setCentralWidget(self.frm)
# 2. Place the matplotlib figure
self.myFig = MyFigureCanvas(x_len=200, y_range=[0, 100], interval=20)
self.lyt.addWidget(self.myFig)
# 3. Show
self.show()
return
class MyFigureCanvas(FigureCanvas):
'''
This is the FigureCanvas in which the live plot is drawn.
'''
def __init__(self, x_len:int, y_range:List, interval:int) -> None:
'''
:param x_len: The nr of data points shown in one plot.
:param y_range: Range on y-axis.
:param interval: Get a new datapoint every .. milliseconds.
'''
super().__init__(mpl.figure.Figure())
# Range settings
self._x_len_ = x_len
self._y_range_ = y_range
# Store two lists _x_ and _y_
self._x_ = list(range(0, x_len))
self._y_ = [0] * x_len
# Store a figure ax
self._ax_ = self.figure.subplots()
# Initiate the timer
self._timer_ = self.new_timer(interval, [(self._update_canvas_, (), {})])
self._timer_.start()
return
def _update_canvas_(self) -> None:
'''
This function gets called regularly by the timer.
'''
self._y_.append(round(get_next_datapoint(), 2)) # Add new datapoint
self._y_ = self._y_[-self._x_len_:] # Truncate list _y_
self._ax_.clear() # Clear ax
self._ax_.plot(self._x_, self._y_) # Plot y(x)
self._ax_.set_ylim(ymin=self._y_range_[0], ymax=self._y_range_[1])
self.draw()
return
# Data source
# ------------
n = np.linspace(0, 499, 500)
d = 50 + 25 * (np.sin(n / 8.3)) + 10 * (np.sin(n / 7.5)) - 5 * (np.sin(n / 1.5))
i = 0
def get_next_datapoint():
global i
i += 1
if i > 499:
i = 0
return d[i]
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
qapp.exec_()
You should see the following window:
2. Second example
I found another example of live matplotlib graphs here:
https://learn.sparkfun.com/tutorials/graph-sensor-data-with-python-and-matplotlib/speeding-up-the-plot-animation
However, the author doesn't use PyQt5 to embed his live plot. Therefore, I've modified the code a bit, to get the plot in a PyQt5 window:
#####################################################################################
# #
# PLOT A LIVE GRAPH IN A PYQT WINDOW #
# EXAMPLE 2 #
# ------------------------------------ #
# This code is inspired on: #
# https://learn.sparkfun.com/tutorials/graph-sensor-data-with-python-and-matplotlib/speeding-up-the-plot-animation #
# #
#####################################################################################
from __future__ import annotations
from typing import *
import sys
import os
from matplotlib.backends.qt_compat import QtCore, QtWidgets
# from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvas
# from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib as mpl
import matplotlib.figure as mpl_fig
import matplotlib.animation as anim
import numpy as np
class ApplicationWindow(QtWidgets.QMainWindow):
'''
The PyQt5 main window.
'''
def __init__(self):
super().__init__()
# 1. Window settings
self.setGeometry(300, 300, 800, 400)
self.setWindowTitle("Matplotlib live plot in PyQt - example 2")
self.frm = QtWidgets.QFrame(self)
self.frm.setStyleSheet("QWidget { background-color: #eeeeec; }")
self.lyt = QtWidgets.QVBoxLayout()
self.frm.setLayout(self.lyt)
self.setCentralWidget(self.frm)
# 2. Place the matplotlib figure
self.myFig = MyFigureCanvas(x_len=200, y_range=[0, 100], interval=20)
self.lyt.addWidget(self.myFig)
# 3. Show
self.show()
return
class MyFigureCanvas(FigureCanvas, anim.FuncAnimation):
'''
This is the FigureCanvas in which the live plot is drawn.
'''
def __init__(self, x_len:int, y_range:List, interval:int) -> None:
'''
:param x_len: The nr of data points shown in one plot.
:param y_range: Range on y-axis.
:param interval: Get a new datapoint every .. milliseconds.
'''
FigureCanvas.__init__(self, mpl_fig.Figure())
# Range settings
self._x_len_ = x_len
self._y_range_ = y_range
# Store two lists _x_ and _y_
x = list(range(0, x_len))
y = [0] * x_len
# Store a figure and ax
self._ax_ = self.figure.subplots()
self._ax_.set_ylim(ymin=self._y_range_[0], ymax=self._y_range_[1])
self._line_, = self._ax_.plot(x, y)
# Call superclass constructors
anim.FuncAnimation.__init__(self, self.figure, self._update_canvas_, fargs=(y,), interval=interval, blit=True)
return
def _update_canvas_(self, i, y) -> None:
'''
This function gets called regularly by the timer.
'''
y.append(round(get_next_datapoint(), 2)) # Add new datapoint
y = y[-self._x_len_:] # Truncate list _y_
self._line_.set_ydata(y)
return self._line_,
# Data source
# ------------
n = np.linspace(0, 499, 500)
d = 50 + 25 * (np.sin(n / 8.3)) + 10 * (np.sin(n / 7.5)) - 5 * (np.sin(n / 1.5))
i = 0
def get_next_datapoint():
global i
i += 1
if i > 499:
i = 0
return d[i]
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
qapp.exec_()
The resulting live plot is exactly the same. However, if you start playing around with the interval parameter from the MyFigureCanvas() constructor, you will notice that the first example won't be able to follow. The second example can go much faster.
3. Questions
I've got a couple of questions I'd like to present to you:
The QtCore and QtWidgets classes can be imported like this:
from matplotlib.backends.qt_compat import QtCore, QtWidgets
or like this:
from PyQt5 import QtWidgets, QtCore
Both work equally well. Is there a reason to prefer one over the other?
The FigureCanvas can be imported like this:
from matplotlib.backends.backend_qt5agg import FigureCanvas
or like this:
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
But I already figured out why. The backend_qt5agg file seems to define FigureCanvas as an alias for FigureCanvasQTAgg.
Why exactly is the second example so much faster than the first one? Honestly, it surprises me. The first example is based on a webpage from the official matplotlib website. I'd expect that one to be better.
Do you have any suggestions to make the second example even faster?
4. Edits
Based on the webpage:
https://bastibe.de/2013-05-30-speeding-up-matplotlib.html
I modified the first example to increase its speed. Please have a look at the code:
#####################################################################################
# #
# PLOT A LIVE GRAPH IN A PYQT WINDOW #
# EXAMPLE 1 (modified for extra speed) #
# -------------------------------------- #
# This code is inspired on: #
# https://matplotlib.org/3.1.1/gallery/user_interfaces/embedding_in_qt_sgskip.html #
# and on: #
# https://bastibe.de/2013-05-30-speeding-up-matplotlib.html #
# #
#####################################################################################
from __future__ import annotations
from typing import *
import sys
import os
from matplotlib.backends.qt_compat import QtCore, QtWidgets
# from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvas
# from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib as mpl
import numpy as np
class ApplicationWindow(QtWidgets.QMainWindow):
'''
The PyQt5 main window.
'''
def __init__(self):
super().__init__()
# 1. Window settings
self.setGeometry(300, 300, 800, 400)
self.setWindowTitle("Matplotlib live plot in PyQt - example 1 (modified for extra speed)")
self.frm = QtWidgets.QFrame(self)
self.frm.setStyleSheet("QWidget { background-color: #eeeeec; }")
self.lyt = QtWidgets.QVBoxLayout()
self.frm.setLayout(self.lyt)
self.setCentralWidget(self.frm)
# 2. Place the matplotlib figure
self.myFig = MyFigureCanvas(x_len=200, y_range=[0, 100], interval=1)
self.lyt.addWidget(self.myFig)
# 3. Show
self.show()
return
class MyFigureCanvas(FigureCanvas):
'''
This is the FigureCanvas in which the live plot is drawn.
'''
def __init__(self, x_len:int, y_range:List, interval:int) -> None:
'''
:param x_len: The nr of data points shown in one plot.
:param y_range: Range on y-axis.
:param interval: Get a new datapoint every .. milliseconds.
'''
super().__init__(mpl.figure.Figure())
# Range settings
self._x_len_ = x_len
self._y_range_ = y_range
# Store two lists _x_ and _y_
self._x_ = list(range(0, x_len))
self._y_ = [0] * x_len
# Store a figure ax
self._ax_ = self.figure.subplots()
self._ax_.set_ylim(ymin=self._y_range_[0], ymax=self._y_range_[1]) # added
self._line_, = self._ax_.plot(self._x_, self._y_) # added
self.draw() # added
# Initiate the timer
self._timer_ = self.new_timer(interval, [(self._update_canvas_, (), {})])
self._timer_.start()
return
def _update_canvas_(self) -> None:
'''
This function gets called regularly by the timer.
'''
self._y_.append(round(get_next_datapoint(), 2)) # Add new datapoint
self._y_ = self._y_[-self._x_len_:] # Truncate list y
# Previous code
# --------------
# self._ax_.clear() # Clear ax
# self._ax_.plot(self._x_, self._y_) # Plot y(x)
# self._ax_.set_ylim(ymin=self._y_range_[0], ymax=self._y_range_[1])
# self.draw()
# New code
# ---------
self._line_.set_ydata(self._y_)
self._ax_.draw_artist(self._ax_.patch)
self._ax_.draw_artist(self._line_)
self.update()
self.flush_events()
return
# Data source
# ------------
n = np.linspace(0, 499, 500)
d = 50 + 25 * (np.sin(n / 8.3)) + 10 * (np.sin(n / 7.5)) - 5 * (np.sin(n / 1.5))
i = 0
def get_next_datapoint():
global i
i += 1
if i > 499:
i = 0
return d[i]
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
qapp.exec_()
The result is pretty amazing. The modifications make the first example definitely much faster! However, I don't know if this makes the first example equally fast now to the second example. They're certainly close to each other. Anyone an idea who wins?
Also, I noticed that one vertical line on the left, and one horizontal line on top is missing:
It's not a big deal, but I just wonder why.
The second case (using FuncAnimation) is faster because it uses "blitting", which avoids redrawing things that do not change between frames.
The example provided on the matplotlib website for embedding in qt was not written with speed in mind, hence the poorer performance. You'll notice that it calls ax.clear() and ax.plot() at each iteration, causing the whole canvas to be redrawn everytime. If you were to use the same code as in the code with FuncAnimation (that is to say, create an Axes and an artist, and update the data in the artist instead of creating a new artists every time) you should get pretty close to the same performance I believe.
I have a QtGraph plot and I want to show it in a QLabel, Qwidget or Graphicsview in a GUI that I made in Qt Designer, but I can't find a direct way that shows that graph. I am streaming a video from a camera and I could easily show it in my GUI, but I am struggling with this one.
The problem is in showing.
#These are the libraries which have been used in the app.
import sys
import numpy as np
import cv2
import pyqtgraph as pg
import datetime
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication , QMainWindow
from PyQt5.uic import loadUi
from PyQt5 import QtGui
#this is the main class for this app and get the visual GUI from QtDesigner
class VideoStream(QMainWindow):
def __init__(self):
super(VideoStream , self).__init__()
loadUi('VideoStream.ui',self)
self.image= None
#self.l_values is the place that we collect the intensity values for each frame
self.l_values = []
#This is a button to set the geometry of our mask for the specific zone of lightness
self.Apply_Button.clicked.connect(self.Geometry)
#this button save the maximum values of the specific zone in a text file
#self.Save_Button.clicked.connect(self.save_data)
self.startButton.clicked.connect(self.start_webcam)
self.stopButton.clicked.connect(self.stop_webcam)
#these two variables are the height and width of our camera.
#With different cameras this part should be changed.
self.cameraHeight=480
self.cameraWidth=640
#This function shows the stream in the GUI we created by qtdesigner
def displayImage(self,img,window=1):
qformat=QtGui.QImage.Format_Grayscale8
outImage=QtGui.QImage(img, img.shape[1],img.shape[0],qformat)
self.imgLabel.setPixmap(QtGui.QPixmap.fromImage(outImage))
self.imgLabel.setScaledContents(True)
#for the seperate canvas you should click on the move button in that window once
def displayHist(self,img, window=1):
self.avr = int(np.average(self.image)*25)
self.avrage=np.array([self.avr])
if self.l<=self.bufferSize:
self.plt.setRange(xRange=[max(self.l- 100, 0), self.l])
self.data[self.l:self.l+self.n] = self.avrage
self.curve.setData(self.data)
print(self.l)
self.l = (self.l+self.n)
if self.l%100==0:
if self.l>=100:
print("y ",self.k,np.max(self.data[self.l-100:self.l]))
self.k=self.k+1
elif self.l==0:
print("- ",self.k,np.max(self.data[-(100-self.l):]))
else:
print("n ",self.k,max(np.max(self.data[-(100-self.l):]),np.max(self.data[:self.l])))
self.k=self.k+1
self.line.setValue(self.l)
if self.l>self.bufferSize:
self.plt.setRange(xRange=[max(self.bufferSize- 100, 0), self.bufferSize])
for j in range(self.bufferSize-1):
self.data[j]=self.data[j+1]
self.data[-1]=self.avrage
self.curve.setData(self.data)
self.l = (self.l+self.n)
self.line.setValue(self.bufferSize)
#this is the place that I don't have any idea what to do
I am interested in real time graph. My aim is to update graph with another definition callback. I tried to debug but I don't see anythink after exec_() command. I tried to call update insteaded of Qtimer.
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from multiprocessing import Process, Manager,Queue
def f(name):
app2 = QtGui.QApplication([])
win2 = pg.GraphicsWindow(title="Basic plotting examples")
win2.resize(1000,600)
win2.setWindowTitle('pyqtgraph example: Plotting')
p2 = win2.addPlot(title="Updating plot")
curve = p2.plot(pen='y')
def updateInProc(curve):
t = np.arange(0,3.0,0.01)
s = np.sin(2 * np.pi * t + updateInProc.i)
curve.setData(t,s)
updateInProc.i += 0.1
QtGui.QApplication.instance().exec_()
updateInProc.i = 0
timer = QtCore.QTimer()
timer.timeout.connect(lambda: updateInProc(curve))
timer.start(50)
if __name__ == '__main__':
m=f()
m
I want to use another definition like
def UpdateCallback():
for x in range(1,100):
m.updateInProc(x,time)
I deleted Qtimer then I tried to send data but I did not see at graph
I am trying to work with Chaco and pyqt in plotting a real-time data acquisition task for laboratory hardware. I was previously using matplotlib, however it proved to be too slow (I even tried animation). The following code works fine when I embedded a matplotlib plot in a pyqt window, but with chaco, nothing happens when I emit my update signal from inside a thread. This code will work if you do not use a thread for the simulated acquisition. I have tried using qthreads to no avail either (including something like this: Threading and Signals problem in PyQt). Is there anyone out there who has used pyqt + chaco + threading that could help me find where I am going wrong, or what is happening?
import sys
import threading, time
import numpy as np
from enthought.etsconfig.etsconfig import ETSConfig
ETSConfig.toolkit = "qt4"
from enthought.enable.api import Window
from enthought.chaco.api import ArrayPlotData, Plot
from PyQt4 import QtGui, QtCore
class Signals(QtCore.QObject):
done_collecting = QtCore.pyqtSignal(np.ndarray, np.ndarray)
class PlotWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
x = np.linspace(0,2*np.pi,200)
y = np.sin(x)
plotdata = ArrayPlotData(x=x, y=y)
plot = Plot(plotdata, padding=50, border_visible=True)
plot.plot(('x', 'y'))
window = Window(self,-1, component=plot)
self.setCentralWidget(window.control)
self.resize(500,500)
self.pd = plotdata
def update_display(self, x, y):
print 'updating'
self.pd.set_data('x', x)
self.pd.set_data('y', y)
def run_collection(signal):
# this is where I would start and stop my hardware,
# but I will just call the read function myself here
for i in range(1,10):
every_n_collected(i, signal)
time.sleep(0.5)
def every_n_collected(frequency, signal):
# dummy data to take place of device read
x = np.linspace(0,2*np.pi,200)
y = np.sin(x*frequency)
print 'emitting'
signal.emit(x, y)
QtGui.QApplication.processEvents()
def main():
plt = PlotWindow()
plt.show()
QtGui.QApplication.processEvents()
signals = Signals()
signals.done_collecting.connect(plt.update_display)
t = threading.Thread(target=run_collection, args=(signals.done_collecting,))
t.start()
t.join()
QtGui.QApplication.processEvents()
# it works without threads though...
# run_collection(signals.done_collecting)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main()
Your call to join on the mainthread (which is the UI thread) is blocking that thread and prevents the events to be processed by the UI. If you started the app/GUI event loop in the main function and wait for the app to be closed without calling t.join(), it should work fine.
This is the way to do it with regular Traits/TraitsUI/Chaco apps.
import time
import threading
import numpy as np
from traits.etsconfig.etsconfig import ETSConfig
ETSConfig.toolkit = "qt4"
from enable.api import ComponentEditor
from chaco.api import ArrayPlotData, Plot
from traits.api import Event, HasTraits, Instance
from traitsui.api import View, Item
class PlotWindow(HasTraits):
dataset = Instance(ArrayPlotData)
plot = Instance(Plot)
def _dataset_default(self):
x = np.linspace(0,2*np.pi,200)
y = np.sin(x)
plotdata = ArrayPlotData(x=x, y=y)
return plotdata
def _plot_default(self):
plot = Plot(self.dataset, padding=50, border_visible=True)
plot.plot(('x', 'y'))
return plot
def update_display(self, x, y):
print 'updating', threading.current_thread()
self.dataset.set_data('x', x)
self.dataset.set_data('y', y)
traits_view = View(
Item('plot', editor=ComponentEditor(size=(400, 400)), show_label=False)
)
def run_collection(datamodel):
# this is where I would start and stop my hardware,
# but I will just call the read function myself here
for i in range(1,10):
x = np.linspace(0,2*np.pi,200)
y = np.sin(x*i)
datamodel.update_display(x, y)
time.sleep(0.5)
def main():
plot = PlotWindow()
t = threading.Thread(target=run_collection, args=(plot,))
t.start()
# Starts the UI and the GUI mainloop
plot.configure_traits()
# don't call t.join() as it blocks the current thread...
if __name__ == "__main__":
main()