Add dynamic Text update to pyQt script - python

I would like to add the ability to update a data field (number) on my current pyqt script. I was trying to use "addLabel" but I can't update their content dynamically.
Any suggestion on how to make it? I am using addPlot function to create the plots which will be processing some data from a UDP packet. In some cases, I want to just show the value dynamically. Not sure what will be the best widget to use for this purpose?
Current script:
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from pyqtgraph.ptime import time
import struct
from struct import pack, unpack
import socket
app = QtGui.QApplication([])
data = []
data_throttle = []
data_brake = []
data_steering = []
data_state = []
data_error = []
pg.setConfigOption('background', (0,0,0))
#pg.setConfigOption(antialias=True)
win = pg.GraphicsWindow()
win.resize(500,200)
p1 = win.addPlot(title="Sequence")
p1.setWindowTitle('Sequence')
p1.setRange(QtCore.QRectF(0, 0, 100, 150))
#p1.setLabel('bottom', 'Packet', units=' ')
p1.showGrid(True, True)
p2 = win.addPlot(title="Throttle")
p2.setWindowTitle('Throttle')
p2.setRange(QtCore.QRectF(0, 0, 100, 255))
#p2.setLabel('bottom', 'Packet', units=' ')
p2.showGrid(True, True)
p3 = win.addPlot(title="Brake")
p3.setWindowTitle('Brake')
p3.setRange(QtCore.QRectF(0, 0, 100, 255))
#p3.setLabel('bottom', 'Packet', units=' ')
p3.showGrid(True, True)
p4 = win.addPlot(title="Steering")
p4.setWindowTitle('Steering')
p4.setRange(QtCore.QRectF(0, -1, 100, 2))
#p4.setLabel('bottom', 'Packet', units=' ')git
p4.showGrid(True, True)
p5 = win.addPlot(title="Vehicle State")
p5.setWindowTitle('Vehicle State')
p5.setRange(QtCore.QRectF(0, 0, 100, 10))
#p5.setLabel('bottom', 'Packet', units=' ')
p5.showGrid(True, True)
p6 = win.addPlot(title="Errors")
p6.setWindowTitle('Errors')
p6.setRange(QtCore.QRectF(0, 0, 100, 10))
#p6.setLabel('bottom', 'Packet', units=' ')
p6.showGrid(True, True)
top_label = "Percent"
bottom_label = "85"
l_labels = win.addLayout(col=1, colspan=1)
l_labels.addLabel(top_label, row=0, col=0, rowspan=1, colspan=1, size='30pt', bold=True)
l_labels.addLabel(bottom_label, row=2, col=0, rowspan=4, colspan=1, size='200pt', color='606060')
l_labels.setContentsMargins(0, 0, 0, 100)
curve = p1.plot(pen='r')
curve2 = p2.plot(pen='b')
curve3 = p3.plot(pen='g')
curve4 = p4.plot(pen='y')
curve5 = p5.plot(pen='r')
curve6 = p6.plot(pen='b')
# Receive UDP packets transmitted by a broadcasting service
RECEIVE_IP = ''
RECEIVE_PORT = 2337
RECEIVE_ADDRESS = (RECEIVE_IP, RECEIVE_PORT)
recv_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recv_socket.bind(RECEIVE_ADDRESS)
JOY_CODE = '=HBBBhHQQB'
ACK_CODE = '=HHBBHBBhBqB'
ptr = 0
lastTime = time()
fps = None
def update():
global recv_socket, fScale
global curve, data, data_throttle, data_brake, data_steering, ptr, p, lastTime, fps, data_state, data_error
recv_message, address = recv_socket.recvfrom(22)
message_id, ack_payload, ack_seq, vehicle_state, vehicle_speed, throttle, brake, steering, error, timestamp, checksum = struct.unpack(ACK_CODE, recv_message)
#data = throttle
data.append(ack_seq)
data = data[-100:]
data_throttle.append(throttle)
data_throttle = data_throttle[-100:]
data_brake.append(brake)
data_brake = data_brake[-100:]
data_steering.append(steering / 32768)
data_steering = data_steering[-100:]
vehicle_state = vehicle_state & 0x07
data_state.append(vehicle_state)
data_state = data_state[-100:]
data_error.append(error)
data_error = data_error[-100:]
#print(throttle)
#print("got data", data, " ", lastTime, "\n")
# print data
#curve.setData(fScale,data,_callSync='off')
curve.setData(data,_callSync='off')
curve2.setData(data_throttle,_callSync='off')
curve3.setData(data_brake,_callSync='off')
curve4.setData(data_steering,_callSync='off')
curve5.setData(data_state, _callSync='off')
curve6.setData(data_error, _callSync='off')
bottom_label = vehicle_state
now = time()
dt = now - lastTime
lastTime = now
app.processEvents() ## force complete redraw for every plot
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()

I was able to figure the solution by using TextItem inside a Plot
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from pyqtgraph.ptime import time
import struct
from struct import pack, unpack
import socket
app = QtGui.QApplication([])
data = []
data_throttle = []
data_brake = []
data_steering = []
data_state = []
data_error = []
pg.setConfigOption('background', (0,0,0))
#pg.setConfigOption(antialias=True)
win = pg.GraphicsWindow()
win.resize(1600,1000)
p1 = win.addPlot(title="Sequence",row=0, col=1)
p1.setWindowTitle('Sequence')
p1.setRange(QtCore.QRectF(0, 0, 100, 150))
p1.showGrid(True, True)
p2 = win.addPlot(title="Throttle",row=0, col=2)
p2.setWindowTitle('Throttle')
p2.setRange(QtCore.QRectF(0, 0, 100, 255))
p2.showGrid(True, True)
p3 = win.addPlot(title="Brake",row=0, col=3)
p3.setWindowTitle('Brake')
p3.setRange(QtCore.QRectF(0, 0, 100, 255))
p3.showGrid(True, True)
p4 = win.addPlot(title="Steering",row=1, col=1)
p4.setWindowTitle('Steering')
p4.setRange(QtCore.QRectF(0, -1, 100, 2))
p4.showGrid(True, True)
p5 = win.addPlot(title="Vehicle State",row=1, col=2)
p5.setWindowTitle('Vehicle State')
p5.setRange(QtCore.QRectF(0, 0, 100, 10))
p5.showGrid(True, True)
p6 = win.addPlot(title="Errors",row=1, col=3)
p6.setWindowTitle('Errors')
p6.setRange(QtCore.QRectF(0, 0, 100, 10))
p6.showGrid(True, True)
p7 = win.addPlot(title="Counter",row=0, col=4)
p8 = win.addPlot(title="Counter",row=1, col=4)
font=QtGui.QFont()
font.setPixelSize(300)
anchor = pg.TextItem()
anchor.setText("0")
anchor.setColor(QtGui.QColor(255, 255, 255))
anchor.setFont(font)
anchor1 = pg.TextItem()
anchor1.setText("0")
anchor1.setColor(QtGui.QColor(255, 255, 255))
anchor1.setFont(font)
p7.addItem(anchor)
p7.showGrid(False, False)
p7.hideAxis('bottom')
p7.hideAxis('left')
p8.addItem(anchor1)
p8.showGrid(False, False)
p8.hideAxis('bottom')
p8.hideAxis('left')
curve = p1.plot(pen='r')
curve2 = p2.plot(pen='b')
curve3 = p3.plot(pen='g')
curve4 = p4.plot(pen='y')
curve5 = p5.plot(pen='r')
curve6 = p6.plot(pen='b')
# Receive UDP packets transmitted by a broadcasting service
RECEIVE_IP = ''
RECEIVE_PORT = 2337
RECEIVE_ADDRESS = (RECEIVE_IP, RECEIVE_PORT)
recv_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recv_socket.bind(RECEIVE_ADDRESS)
JOY_CODE = '=HBBBhHQQB'
ACK_CODE = '=HHBBHBBhBqB'
ptr = 0
lastTime = time()
fps = None
def update():
global recv_socket, fScale
global curve, data, data_throttle, data_brake, data_steering, ptr, p, lastTime, fps, data_state, data_error
recv_message, address = recv_socket.recvfrom(22)
message_id, ack_payload, ack_seq, vehicle_state, vehicle_speed, throttle, brake, steering, error, timestamp, checksum = struct.unpack(ACK_CODE, recv_message)
#data = throttle
data.append(ack_seq)
data = data[-100:]
data_throttle.append(throttle)
data_throttle = data_throttle[-100:]
data_brake.append(brake)
data_brake = data_brake[-100:]
data_steering.append(steering / 32768)
data_steering = data_steering[-100:]
vehicle_state = vehicle_state & 0x07
data_state.append(vehicle_state)
data_state = data_state[-100:]
data_error.append(error)
data_error = data_error[-100:]
curve.setData(data,_callSync='off')
curve2.setData(data_throttle,_callSync='off')
curve3.setData(data_brake,_callSync='off')
curve4.setData(data_steering,_callSync='off')
curve5.setData(data_state, _callSync='off')
curve6.setData(data_error, _callSync='off')
#Updating Text Value
anchor.setText(str(vehicle_state))
anchor1.setText(str(vehicle_state))
now = time()
dt = now - lastTime
lastTime = now
app.processEvents() ## force complete redraw for every plot
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()

Related

Overlay a line plot and scatter plot in PyQtgraph but only the line plot is updating

I am making an audio frequency analyzer based on the script from this video.
https://www.youtube.com/watch?v=RHmTgapLu4s&t=84s
Basically, it takes the microphone input in real time and plots the waveform. Then, it performs a fourier transform of the waveform, and plots the transform on a second plot. This is updating constantly.
I wanted to add some peak finding to the code, and then highlight points where a peak is detected. I tried to do this by overlaying a scatter plot on the fft plot, but only the first scatter plot is generated and it never updates. I did some troubleshooting, and I can see my peak coordinates getting updated, but when "self.set_plotdata()" gets called, it only updates the line plot and not the scatter. Any advidce is appreciated.
Also, I would like to add data labels for the scatter points to show what frequency each peak is, but I can't find any documentation in PyQtGraph to show how to do this.
Here is the code.
# -*- coding: utf-8 -*-
"""
Created on Mon Jun 27 16:35:59 2022
#author: corn-
"""
import numpy as np
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import struct
import pyaudio
from scipy.fftpack import fft
from scipy.signal import find_peaks
import sys
import time
class AudioStream(object):
def __init__(self):
# pyqtgraph stuff
pg.setConfigOptions(antialias=True)
self.traces = dict()
self.app = QtGui.QApplication(sys.argv)
self.win = pg.GraphicsWindow(title='Spectrum Analyzer')
self.win.setWindowTitle('Spectrum Analyzer')
self.win.setGeometry(5, 115, 1910, 1070)
#X labels for time domain graph
wf_xlabels = [(0, '0'), (2048, '2048'), (4096, '4096')]
wf_xlabel2 = 'time'
wf_xaxis = pg.AxisItem(orientation='bottom')
wf_xaxis.setTicks([wf_xlabels])
wf_xaxis.setLabel(text = wf_xlabel2)
#Y labels for time domain graph
wf_ylabels = [(0, '0'), (127, '128'), (255, '255')]
wf_yaxis = pg.AxisItem(orientation='left')
wf_yaxis.setTicks([wf_ylabels])
#X labels for frequency domain graph
sp_xlabels = [
(np.log10(10), '10'), (np.log10(100), '100'),
(np.log10(1000), '1000'), (np.log10(22050), '22050')
]
sp_xlabel2 = 'log frequency'
sp_xaxis = pg.AxisItem(orientation='bottom')
sp_xaxis.setTicks([sp_xlabels])
sp_xaxis.setLabel(sp_xlabel2)
self.waveform = self.win.addPlot(
title='WAVEFORM', row=1, col=1, axisItems={'bottom': wf_xaxis, 'left': wf_yaxis},
)
self.spectrum = self.win.addPlot(
title='SPECTRUM', row=2, col=1, axisItems={'bottom': sp_xaxis},
)
# pyaudio stuff
self.FORMAT = pyaudio.paInt16
self.CHANNELS = 1
self.RATE = 44100
self.CHUNK = 1042 * 4
self.p = pyaudio.PyAudio()
self.stream = self.p.open(
format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
output=True,
frames_per_buffer=self.CHUNK,
)
# waveform and spectrum x points
self.x = np.arange(0, 2 * self.CHUNK, 2)
self.f = np.linspace(0, self.RATE / 2, self.CHUNK // 2)
def start(self):
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
def set_plotdata(self, name, data_x, data_y, peak_x, peak_y):
if name in self.traces:
self.traces[name].setData(data_x, data_y)
else:
if name == 'waveform':
self.traces[name] = self.waveform.plot(pen='c', width=3)
self.waveform.setYRange(0, 255, padding=0)
self.waveform.setXRange(0, 2 * self.CHUNK, padding=0.005)
if name == 'spectrum':
self.traces[name] = self.spectrum.plot(pen='m', width=50)
self.spectrum.setLogMode(x=True, y=True)
self.spectrum.setYRange(-4, 0, padding=0)
self.spectrum.setXRange(
np.log10(20), np.log10(self.RATE / 2), padding=0.005)
#plot the peak tips
self.peakTops = self.spectrum.plot()
self.peakTops.setData(peak_x, peak_y, pen=None, symbol='o')
#self.peakTops.setLogMode(x=True, y=True)
#self.PeakTops.setYRange(-4,0,padding=0)
#self.PeakTops.setXrange(np.log10(20), np.log10(self.RATE / 2), padding=0.005)
def get_peaks(self, name, data_x, data_y):
if name == 'spectrum':
peak_idx, _ = find_peaks(data_y, height=(0.1))
peak_height = data_y[peak_idx]
#print(peak_idx, peak_height)
return (peak_idx, peak_height)
def update(self):
wf_data = self.stream.read(self.CHUNK)
wf_data = struct.unpack(str(2 * self.CHUNK) + 'B', wf_data)
wf_data = np.array(wf_data, dtype='b')[::2] + 128
temp_x = 0 #placeholder to feed to set_plotdata
temp_y = 0 #placeholder to feed to set_plotdata
self.set_plotdata(name='waveform', data_x=self.x, data_y=wf_data, peak_x = temp_x, peak_y = temp_y)
sp_data = fft(np.array(wf_data, dtype='int8') - 128)
sp_data = np.abs(sp_data[0:int(self.CHUNK / 2)]
) * 2 / (128 * self.CHUNK)
[peak_idx, peak_height] = self.get_peaks(name = 'spectrum', data_x = self.f, data_y = sp_data)
self.set_plotdata(name='spectrum', data_x=self.f, data_y=sp_data, peak_x = peak_idx, peak_y = peak_height)
def animation(self):
timer = QtCore.QTimer()
timer.timeout.connect(self.update)
timer.start(20)
self.start()
if __name__ == '__main__':
audio_app = AudioStream()
audio_app.animation()

Updating the matplotlib with new data points without removing previous data points in quick way

I am trying to update plot with new data points. But the problem i am having is it is slow. I am using draw_now may be that is the problem as per this stack question: why is plotting with Matplotlib so slow?
I tried that approaches mentioned in that question and i still have same problems.
I recieve data from accelerometer and i take that data to update my plots.
from pyqtgraph.Qt import QtCore, QtGui
import threading
import pyqtgraph as pg
import socket
import psutil
import time
import struct
import sys
import collections
import os
import PySimpleGUI as sg
import easygui
import matplotlib.pyplot as plt
from mpl_toolkits
import mplot3d
BufferLength = 500 marker_size = 14
driver_name = 'sss.exe'
def get_pid_and_kill(process_name):
for proc in psutil.process_iter():
if proc.name() == process_name:
p = psutil.Process(proc.pid)
p.terminate()
print("Process " + process_name + " terminated") def run_the_driver(driver_exe_name):
from subprocess import Popen
get_pid_and_kill(driver_exe_name.split("/")[-1])
get_pid_and_kill(driver_exe_name.split("\\")[-1])
get_pid_and_kill("cmd.exe")
Popen([driver_exe_name])
time.sleep(3)
def create_tcp_ip_socket():
HOST = '145.0.0.1'
PORT = 7060
try:
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_connection.settimeout(3)
socket_connection.connect((HOST, PORT))
socket_connection.settimeout(1)
print("Socket Successfully created")
except socket.error as err:
raise SystemExit("Socket creation failed with error %s" % err)
def open_exit_button():
even_name = 'kill the driver'
layout = [[sg.Button(even_name, button_color=('white', 'springgreen4'))]]
window = sg.Window('Configurations', layout)
while True: # Event Loop
event, values = window.read(timeout=10)
if event == sg.WIN_CLOSED or event == even_name:
if 0 == visualize_recorded_msg:
get_pid_and_kill(driver_name.split(("/"))[-1])
get_pid_and_kill(driver_name.split(("\\"))[-1])
os._exit(1)
break
window.close()
class Visualizer(object):
def __init__(self):
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111, projection="3d")
self.ax.set_title('3D Points')
self.ax.set_xlabel('X')
self.ax.set_ylabel('Y')
self.ax.set_zlabel('Z')
self.ax.set_xlim(-2.5, 2.5)
self.ax.set_ylim(0, 3)
self.ax.set_zlim(-1.5, 1.5)
self.app = QtGui.QApplication(sys.argv)
self.view = pg.GraphicsLayoutWidget()
self.view.setWindowTitle('')
self.w1 = self.view.addPlot(row=0, col=0, title='Accelerometer 1')
self.w1.showGrid(x=True, y=True)
self.w1.addLegend()
self.w1.setLabel(axis='bottom', text='Time [s]')
self.w1.setLabel(axis='left', text='')
self.w1.curve2 = self.w1.plot(name='')
self.w1.curve3 = self.w1.plot(name='')
self.w2 = self.view.addPlot(row=1, col=0, title='')
self.w2.showGrid(x=True, y=True)
self.w2.addLegend()
self.w2.setLabel(axis='bottom', text='Time [s]')
self.w2.setLabel(axis='left', text='')
self.w2.curve2 = self.w2.plot(name='')
self.w2.curve3 = self.w2.plot(name='')
self.w3 = self.view.addPlot(row=2, col=0, title='Average')
self.w3.showGrid(x=True, y=True)
self.w3.setLabel(axis='bottom', text='Time [s]')
self.w3.setLabel(axis='left', text='')
self.w3.curve1 = self.w3.plot()
self.w4 = self.view.addPlot(row=3, col=0, title='result ')
self.w4.showGrid(x=True, y=True)
self.w4.setLabel(axis='bottom', text='Time [s]')
self.w4.setLabel(axis='left', text='')
self.w4.curve1 = self.w4.plot()
self.a = collections.deque(maxlen=BufferLength)
self.b = collections.deque(maxlen=BufferLength)
self.c = collections.deque(maxlen=BufferLength)
self.d = collections.deque(maxlen=BufferLength)
self.e = collections.deque(maxlen=BufferLength)
self.f = collections.deque(maxlen=BufferLength)
self.pos_x = collections.deque(maxlen=BufferLength)
self.pos_y = collections.deque(maxlen=BufferLength)
self.pos_z = collections.deque(maxlen=BufferLength)
self.pos_x_out = collections.deque(maxlen=BufferLength)
self.pos_y_out = collections.deque(maxlen=BufferLength)
self.pos_z_out = collections.deque(maxlen=BufferLength)
self.view.show()
self.fig.show()
self.fig.canvas.draw()
self.prevFrameCnt = 0
self.iteration_index = 0
self.li_det = 0
self.str_mot = 1
#staticmethod
def start():
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
def message_parser(self, data):
out1 = struct.unpack("<L", data[0:4])[0]
out2 = data[4]
out3 = data[5]
out4 = data[6]
out5 = struct.unpack("<h", data[7:9])[0]
out6 = struct.unpack("<H", data[9:11])[0]
out7 = struct.unpack("<H", data[11:13])[0]
out8 = struct.unpack("<H", data[17:19])[0]
out9 = struct.unpack("<H", data[19:21])[0]
out10 = struct.unpack("<H", data[19:21])[0]
out11 = struct.unpack("<H", data[21:23])[0]
out12 = struct.unpack("<H", data[23:25])[0]
return [out1, out2, out3, out4, out5, out6, out7, out8, out9,out10, out11, out12]
def update(self):
try:
data = socket_connection.recv(64)
except socket.timeout as e:
print(e)
except (ConnectionResetError, OSError):
raise SystemExit("server closed")
output = self.message_parser(data)
x = output[0]
y = output[4]
z = output[5]
x1 = output[6]
y1 = output[7]
z1 = output[8]
if self.prevFrameCnt == x:
MovDet = output[1]
LiDet = output[2]
MotDet = output[3]
self.a.append(y)
self.c.append(z1)
self.d.append(y1)
self.w2.curve2.setData(self.c, pen=None, symbol='t', symbolPen=None, symbolSize=marker_size,
symbolBrush=(0, 114, 189))
self.w2.curve3.setData(self.d, pen=None, symbol='t1', symbolPen=None, symbolSize=marker_size,
symbolBrush=(217, 83, 25))
self.w3.curve1.setData(self.a, pen=None, symbol='d', symbolPen=None, symbolSize=marker_size,
symbolBrush=('g'))
self.w4.curve1.setData(self.f, pen=None, symbol='o', symbolPen=None,
symbolSize=marker_size,
symbolBrush=(217, 83, 25))
if (1 == self.li_det) or (105 == LiDet):
self.li_det = 1
else:
MovDet = output[1]
LiDet = output[2]
MotDet = output[3]
pos_x = output[10]
pos_y = output[11]
pos_z = output[12]
is_in = pos_z 0.5
is_in = is_in and (pos_z < 0.6)
is_in = is_in and (pos_x < 0.7)
is_in = is_in and (pos_x 0.8)
is_in = is_in and (pos_y 0.7)
if is_in:
self.pos_x.append(pos_x)
self.pos_y.append(pos_x)
self.pos_z.append(pos_x)
self.ax.scatter3D(self.pos_x, self.pos_y, self.pos_z, color='green')
self.fig.canvas.draw_idle()
else:
self.pos_x_out.append(pos_x)
self.pos_y_out.append(pos_x)
self.pos_z_out.append(pos_x)
self.ax.scatter3D(self.pos_x_out, self.pos_y_out, self.pos_z_out, color='green')
self.fig.canvas.draw_idle()
#
self.b.append(z1)
self.d.append(y1)
self.w1.curve2.setData(self.b, pen=None, symbol='t', symbolPen=None, symbolSize=marker_size,
symbolBrush=(0, 114, 189))
self.w1.curve3.setData(self.d, pen=None, symbol='t1', symbolPen=None, symbolSize=marker_size,
symbolBrush=(217, 83, 25))
self.prevFrameCnt = x
self.view.show()
self.fig.show()
def animation(self):
timer = QtCore.QTimer()
timer.timeout.connect(self.update)
timer.start(1)
self.start()
def visualization():
v = Visualizer()
v.animation()
def main():
thread = threading.Thread(target=visualization)
thread.start()
open_exit_button()
if __name__ == '__main__':
main()
But problem is if i plot either matplot one or pyqt one it is working fast without any delay in FPS. But when i plot both then plot function is not that quickly updated in pyqt one?
Matplotlib is generally not so ideal for real time plotting based on several answers posted in different questions in stack Why Matplotlib is slow. So it is better to use vispy Vispy for real time plotting.
In my case, plotting with Vispy really solved the problem of updating the plots slow

Adding plots to GraphicsLayoutWidget using pyqt

I wanted to add plots to GraphicsLayoutWidget. However i tried with the code i have written which is below.
But now i wanted to changed i have two types of msgs one in live mode and in other recorded mode.
However i wanted to add one more plot item in live mode.
To be sure i also added some comments in the code to get some understanding for you.I only pasted some part of the code.
I searched already in stack but couldnt find answers which solves my thing.
from pyqtgraph.Qt import QtCore, QtGui
import threading
import pyqtgraph as pg
import socket
import psutil
import time
import struct
import sys
import collections
import os
import PySimpleGUI as sg
import easygui
visualize_recorded_msg = 1
driver_called_from_outside = 0
BufferLength = 500
marker_size = 14
if 0 == visualize_recorded_msg:
if 0 == driver_called_from_outside:
driver_name = 'sss'
else:
name_of_the_recorded_file = 'sss.bin'
########################################################################################################################
def get_pid_and_kill(process_name):
for proc in psutil.process_iter():
if proc.name() == process_name:
p = psutil.Process(proc.pid)
p.terminate()
print("Process " + process_name + " terminated")
if 0 == visualize_recorded_msg:
if 0 == driver_called_from_outside:
from subprocess import Popen
get_pid_and_kill(driver_name.split(("/"))[-1])
get_pid_and_kill(driver_name.split(("\\"))[-1])
get_pid_and_kill("cmd.exe")
Popen([driver_name])
print("The driver started")
time.sleep(1)
# TCP/IP Socket creation
HOST = '145.0.0.10'
PORT = 8085
try:
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_connection.settimeout(3)
socket_connection.connect((HOST, PORT))
socket_connection.settimeout(None)
print("Socket successfully created")
except socket.error as err:
raise SystemExit("Socket creation failed with error %s" % err)
else:
file_handle = open(name_of_the_recorded_file, 'rb')
all_msgs = file_handle.read()
file_handle.close()
def open_exit_button():
even_name = 'kill the driver'
layout = [[sg.Button(even_name, button_color=('white', 'springgreen4'))]]
window = sg.Window('Configurations', layout)
while True: # Event Loop
event, values = window.read(timeout=10)
if event == sg.WIN_CLOSED or event == even_name:
if 0 == visualize_recorded_msg:
get_pid_and_kill(driver_name.split(("/"))[-1])
get_pid_and_kill(driver_name.split(("\\"))[-1])
os._exit(1)
break
window.close()
class Visualizer(object):
def __init__(self):
self.app = QtGui.QApplication(sys.argv)
self.view = pg.GraphicsLayoutWidget()
self.view.setWindowTitle('')
self.w1 = self.view.addPlot(row=0, col=0, title='Accelerometer 1')
self.w1.showGrid(x=True, y=True)
self.w1.addLegend()
self.w1.setLabel(axis='bottom', text='Time [s]')
self.w1.setLabel(axis='left', text='')
self.w1.curve2 = self.w1.plot(name='')
self.w1.curve3 = self.w1.plot(name='')
self.w2 = self.view.addPlot(row=1, col=0, title='')
self.w2.showGrid(x=True, y=True)
self.w2.addLegend()
self.w2.setLabel(axis='bottom', text='Time [s]')
self.w2.setLabel(axis='left', text='')
self.w2.curve2 = self.w2.plot(name='')
self.w2.curve3 = self.w2.plot(name='')
self.w3 = self.view.addPlot(row=2, col=0, title='Average')
self.w3.showGrid(x=True, y=True)
self.w3.setLabel(axis='bottom', text='Time [s]')
self.w3.setLabel(axis='left', text='')
self.w3.curve1 = self.w3.plot()
self.w4 = self.view.addPlot(row=3, col=0, title='result ')
self.w4.showGrid(x=True, y=True)
self.w4.setLabel(axis='bottom', text='Time [s]')
self.w4.setLabel(axis='left', text='')
self.w4.curve1 = self.w4.plot()
self.a = collections.deque(maxlen=BufferLength)
self.b = collections.deque(maxlen=BufferLength)
self.c = collections.deque(maxlen=BufferLength)
self.d = collections.deque(maxlen=BufferLength)
self.e = collections.deque(maxlen=BufferLength)
self.f = collections.deque(maxlen=BufferLength)
self.view.show()
self.prevFrameCnt = 0
self.iteration_index = 0
self.li_det = 0
self.str_mot = 1
#staticmethod
def start():
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
def message_parser(self, data):
out1 = struct.unpack("<L", data[0:4])[0]
out2 = data[4]
out3 = data[5]
out4 = data[6]
out5 = struct.unpack("<h", data[7:9])[0]
out6 = struct.unpack("<H", data[9:11])[0]
out7 = struct.unpack("<H", data[11:13])[0]
out8 = struct.unpack("<H", data[17:19])[0]
out9 = struct.unpack("<H", data[19:21])[0]
return [out1, out2, out3, out4, out5, out6, out7, out8, out9]
def update(self):
if 0 == visualize_recorded_msg:
# Receive TCP/IP packet
try:
data = socket_connection.recv(64)
except socket.timeout as e:
print(e)
return
except (ConnectionResetError, OSError):
raise SystemExit("Remote server closed")
# Decode TCP/IP packet
output = self.message_parser(data)
else:
msg_length = 21
try:
data = all_msgs[self.iteration_index: self.iteration_index + msg_length]
decode_output = self.message_parser(data)
self.iteration_index += msg_length
except:
print('End of file')
x = decode_output[0]
y = decode_output[4]
z = decode_output[5]
x1 = decode_output[6]
y1 = decode_output[7]
z1 = decode_output[8]
if self.prevFrameCnt == x:
MovDet = decode_output[1]
LiDet = decode_output[2]
MotDet = decode_output[3]
self.a.append(y)
self.c.append(z1)
self.d.append(y1)
self.w2.curve2.setData(self.c, pen=None, symbol='t', symbolPen=None, symbolSize=marker_size,
symbolBrush=(0, 114, 189))
self.w2.curve3.setData(self.d, pen=None, symbol='t1', symbolPen=None, symbolSize=marker_size,
symbolBrush=(217, 83, 25))
self.w3.curve1.setData(self.a, pen=None, symbol='d', symbolPen=None, symbolSize=marker_size,
symbolBrush=('g'))
self.w4.curve1.setData(self.f, pen=None, symbol='o', symbolPen=None,
symbolSize=marker_size,
symbolBrush=(217, 83, 25))
if (1 == self.li_det) or (105 == LiDet):
self.li_det = 1
else:
MovDet = decode_output[1]
LiDet = decode_output[2]
MotDet = decode_output[3]
self.b.append(z1)
self.d.append(y1)
self.w1.curve2.setData(self.b, pen=None, symbol='t', symbolPen=None, symbolSize=marker_size,
symbolBrush=(0, 114, 189))
self.w1.curve3.setData(self.d, pen=None, symbol='t1', symbolPen=None, symbolSize=marker_size,
symbolBrush=(217, 83, 25))
self.prevFrameCnt = x
self.view.show()
def animation(self):
timer = QtCore.QTimer()
timer.timeout.connect(self.update)
timer.start(1)
self.start()
def visualization():
v = Visualizer()
v.animation()
def main():
if 0 == driver_called_from_outside:
thread = threading.Thread(target=visualization)
thread.start()
open_exit_button()
else:
visualization()
if __name__ == '__main__':
main()

How to select point in a line using vtk?

In VTK, I have a surface and a line, and the line is included by the surface. Then, I need to pick one point in the line. I implement myself interactor and get the world coordinate by a right button click. I hope the select point could be located in the line. I show the selected line in the renderer when right button release. However, I find I can not select a point in the line. My code is:
import vtk, os, sys
import numpy as np
from PyQt5.QtWidgets import *
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk
def numpyToVtk(data, type=vtk.VTK_FLOAT):
flat_data_array = data.transpose(2,1,0).flatten()
vtk_data_array = numpy_to_vtk(flat_data_array)
vtk_data = numpy_to_vtk(num_array=vtk_data_array, deep=True, array_type=type)
img = vtk.vtkImageData()
img.GetPointData().SetScalars(vtk_data)
img.SetDimensions(data.shape)
img.SetOrigin(0, 0, 0)
img.SetSpacing(1, 1, 1)
return img
class ourInteractor(vtk.vtkInteractorStyleTrackballCamera):
def __init__(self, renderer=None, renWindow=None):
super(ourInteractor, self).__init__()
self.AddObserver("RightButtonReleaseEvent", self.OnRightButtonUp)
self.ren = renderer
self.renWin = renWindow
def OnRightButtonUp(self, obj, event):
super(ourInteractor, self).OnRightButtonUp()
pos = self.GetInteractor().GetEventPosition()
coordinate = vtk.vtkCoordinate()
coordinate.SetCoordinateSystemToDisplay()
coordinate.SetValue(pos[0], pos[1], 0)
worldCoor = coordinate.GetComputedWorldValue(
self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer())
print('screen coor: ', pos, 'world coor: ', worldCoor)
points = vtk.vtkPoints()
vertices = vtk.vtkCellArray()
id = points.InsertNextPoint(worldCoor[0], worldCoor[1], worldCoor[2])
vertices.InsertNextCell(1)
vertices.InsertCellPoint(id)
point = vtk.vtkPolyData()
point.SetPoints(points)
point.SetVerts(vertices)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(point)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetPointSize(10)
actor.GetProperty().SetColor(0, 1, 0)
self.ren.AddActor(actor)
self.renWin.Render()
class AirwaySkeleton(QMainWindow):
def __init__(self, parent=None):
super(AirwaySkeleton, self).__init__(parent=parent)
self.setWindowTitle("Airway Skeleton")
widget = QWidget()
self.setCentralWidget(widget)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
widget.setLayout(layout)
self.mainLayout = layout
frame = QFrame()
vtkWidget = QVTKRenderWindowInteractor(frame)
self.mainLayout.addWidget(vtkWidget)
ren = vtk.vtkRenderer()
vtkWidget.GetRenderWindow().AddRenderer(ren)
iren = vtkWidget.GetRenderWindow().GetInteractor()
style = ourInteractor(renderer=ren, renWindow=vtkWidget.GetRenderWindow())
iren.SetInteractorStyle(style)
ren.SetBackground(0, 0, 0)
self.ren = ren
mask = np.zeros(shape=[200, 200, 200], dtype=np.uint8)
mask[20:80, 50:150, 50:150] = 1
mask[80:150, 80:120, 80:120] = 1
mask[150:170, 50:150, 50:150] = 1
xs = np.arange(20, 170, 0.1)
line = []
for x in xs:
line.append([x, 100, 100])
actors = self.createActorsForLines([np.array(line)])
vtkMask = numpyToVtk(data=mask, type=vtk.VTK_CHAR)
mesh = self.maskToMesh(vtkMask)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(mesh.GetOutputPort())
mapper.ScalarVisibilityOff()
actor = vtk.vtkLODActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(1, 1, 1)
actor.GetProperty().SetOpacity(0.4)
self.ren.AddActor(actor)
for lineActor in actors:
self.ren.AddActor(lineActor)
self.renWin = vtkWidget.GetRenderWindow()
iren.Initialize()
self.iren = iren
def maskToMesh(self, mask):
contour = vtk.vtkDiscreteMarchingCubes()
contour.SetInputData(mask)
contour.SetValue(0, 1)
contour.Update()
smoother = vtk.vtkWindowedSincPolyDataFilter()
smoother.SetInputConnection(contour.GetOutputPort())
smoother.SetNumberOfIterations(30)
smoother.BoundarySmoothingOff()
smoother.NonManifoldSmoothingOn()
smoother.NormalizeCoordinatesOn()
smoother.Update()
triangleCellNormals = vtk.vtkPolyDataNormals()
triangleCellNormals.SetInputConnection(smoother.GetOutputPort())
triangleCellNormals.ComputeCellNormalsOn()
triangleCellNormals.ComputePointNormalsOff()
triangleCellNormals.ConsistencyOn()
triangleCellNormals.AutoOrientNormalsOn()
triangleCellNormals.Update()
return triangleCellNormals
def createActorsForLines(self, lines):
actors = []
endPoints = vtk.vtkPoints()
for line in lines:
n = line.shape[0]
endPoints.InsertNextPoint(line[0, 0], line[0, 1], line[0, 2])
endPoints.InsertNextPoint(line[-1, 0], line[-1, 1], line[-1, 2])
points = vtk.vtkPoints()
vtkLines = vtk.vtkCellArray()
vtkLines.InsertNextCell(n)
for i in range(n):
points.InsertNextPoint(line[i, 0], line[i, 1], line[i, 2])
vtkLines.InsertCellPoint(i)
polygonPolyData = vtk.vtkPolyData()
polygonPolyData.SetPoints(points)
polygonPolyData.SetLines(vtkLines)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(polygonPolyData)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(1, 0, 0)
actors.append(actor)
polyData = vtk.vtkPolyData()
polyData.SetPoints(endPoints)
sphereSource = vtk.vtkSphereSource()
sphereSource.SetRadius(1)
glyph3D = vtk.vtkGlyph3D()
glyph3D.SetSourceConnection(sphereSource.GetOutputPort())
glyph3D.SetInputData(polyData)
glyph3D.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(glyph3D.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(0, 0, 1)
actors.append(actor)
return actors
if __name__ == '__main__':
app = QApplication(sys.argv)
window = AirwaySkeleton()
window.show()
sys.exit(app.exec_())
What's wrong with my code? Any suggestion is appreciated!
In addition, how can I pick the point in the surface?
Solution with vtkplotter is simply:
from vtkplotter import *
import numpy as np
mask = np.zeros(shape=[200,200,200], dtype=np.uint8)
mask[ 20:80, 50:150, 50:150] = 1
mask[ 80:150, 80:120, 80:120] = 1
mask[150:170, 50:150, 50:150] = 1
vol = Volume(mask) # returns vtkVolume
iso = vol.isosurface(threshold=1).c('grey').alpha(0.3).pickable(0)
smoothed_iso = iso.smoothLaplacian(niter=30)
aline = Line((20,100,100), (170,100,100), lw=10) # vtkActor
def onLeftClick(mesh):
printc("clicked 3D point:", mesh.picked3d, c='red')
vp.add(Sphere(pos=mesh.picked3d, r=2, c="green"))
vp = Plotter(verbose=0, axes=8, bg='black')
vp.mouseLeftClickFunction = onLeftClick
vp.show(smoothed_iso, aline)
can be embedded in Qt following examples here.

How to make a Grid in wxPython?

I want to make a grid like this:
Not the wx.Grid. Does anyone know how to do this, and could provide an example?
This would be for a GridSizer or GridBagSizer to separate the widgets.
use the drawing context of the frame wxWindow subclass(frame/panel/etc...really any wxObject almost).
one way of doing it is this
import wx
class MyCustomFrame(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id)
self.Bind(wx.EVT_PAINT,self.OnPaint)
def OnPaint(self,evt):
self.dc = dc = wx.PaintDC(self)
p1 = [0,0]
p2 = [500,0]
for i in range(100):
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
p1 = [p1[0],p1[1]+5]
p2 = [p2[0],p2[1]+5]
p1=[0,0]
p2 = [0,500]
for i in range(100):
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
p1 = [p1[0]+5,p1[1]]
p2 = [p2[0]+5,p2[1]]
if __name__ == "__main__":
a = wx.App(redirect=False)
f = MyCustomFrame(None,-1)
#f.OnPaint(None) --- dont do this!!!
f.Show()
a.MainLDop()
you could speed it up by using drawlines instead
def OnPaint(self,evt):
self.dc = dc = wx.PaintDC(self)
verticle_lines = [(i*5,0,i*5,500) for i in range(100)]
horizontal_lines = [(0,i*5,500,i*5) for i in range(100)]
dc.DrawLineList(horizontal_lines+verticle_lines)
In Order to do what you want with the grid sizer you could do this
import wx
class MyCustomPanel(wx.Panel):
def __init__(self,parent,id):
wx.Panel.__init__(self,parent,id)
self.sz = wx.GridSizer(5,5,0,0)
for i in range(25):
self.sz.Add(wx.StaticText(self,-1,str(i)))
self.SetSizer(self.sz)
self.Bind(wx.EVT_PAINT,self.OnPaint)
def OnPaint(self,evt):
self.dc = dc = wx.PaintDC(self)
w,h = self.sz.GetSize()
nr = self.sz.GetRows()
nc = self.sz.GetCols()
cell_w = float(w)/nc
cell_h = float(h)/nr
hlines = [(0,i*cell_h,w,i*cell_h)for i in range(nr+1)]
vlines = [(i*cell_w,0,i*cell_w,h)for i in range(nc+1)]
self.dc.DrawLineList(hlines+vlines)
if __name__ == "__main__":
a = wx.App(redirect=False)
f1 = wx.Frame(None,-1)
f = MyCustomPanel(f1,-1)
#f.OnPaint(None)
f1.Show()
a.MainLoop()
you could also accomplish this with styles like this
import wx
class SimplePanel(wx.Panel):
def __init__(self,parent,id,str_val):
wx.Panel.__init__(self,parent,id,style=wx.SIMPLE_BORDER)
self.sz = wx.BoxSizer()
self.sz.Add(wx.StaticText(self,-1,str_val),0,wx.ALIGN_CENTER)
self.SetSizer(self.sz)
class MyCustomPanel(wx.Panel):
def __init__(self,parent,id):
wx.Panel.__init__(self,parent,id)
self.sz = wx.GridSizer(5,5,0,0)
for i in range(25):
self.sz.Add(SimplePanel(self,-1,str(i)),0,wx.GROW)
self.SetSizer(self.sz)
if __name__ == "__main__":
a = wx.App(redirect=False)
f1 = wx.Frame(None,-1)
f = MyCustomPanel(f1,-1)
#f.OnPaint(None)
f1.Show()
a.MainLoop()

Categories