Hello, I have a script that display text to study participants while delivering heat stimulation. The script also reads the temperature from the thermal device in the background. I would like to plot in real-time the temperatures from the thermal device using matplotlib, and display this to the laptop screen (not to the secondary monitor displayed to study participant).
I saw some posts with similar question as mine here and here2. In the latter, there is a suggestion to not use plt.show()
.
Below is an example of a working python script that creates a real-time data plot, which I tried to adapt as custom code part of my Psychopy script. What are your suggestion(s) so that I can display a matplotlib graph showing real time data along with the Psychopy script? Thank you.
# importing all necessary libraries
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from random import randrange
# fMRI run variables
nvols=351
TR_value=0.8
# Graph time length (s), Round up the value
graph_timelength=int(np.ceil(nvols*TR_value))
# create lists to get store element
# after every iteration
x_data = []
y_TCStherm1, y_TCStherm2, y_TCStherm3, y_TCStherm4, y_TCStherm5 = [], [], [], [], []
y_pain1 = []
# Variables to set limit for x and y axis
# x-axis min, max, major and minor intervals
xmin=0;xmax=graph_timelength; xint1=20; xint2=10
# Primary y-axis min, max, major and minor intervals
ymin=30;ymax=50.001; yint1=1; yint2=0.5
# Secondary y-axis min, max
y2min=0;y2max=100.001; y2int1=10; y2int2=5
# subplots() function you can draw
# multiple plots in one figure
figure, axes = plt.subplots(figsize=(12,6))
# Primary y-axis lines
line1, = plt.plot(x_data, y_TCStherm1, color="gray", linestyle='solid')
line2, = plt.plot(x_data, y_TCStherm2, color="orange", linestyle='solid')
line3, = plt.plot(x_data, y_TCStherm3, color="green", linestyle='solid')
line4, = plt.plot(x_data, y_TCStherm4, color="blue", linestyle='solid')
line5, = plt.plot(x_data, y_TCStherm5, color="black", linestyle='solid')
# Secondary y-axis line
# using the twinx() for creating another
# axes object for secondary y-Axis
axes2 = axes.twinx()
line6, = axes2.plot(x_data, y_pain1, color="red", linestyle='solid')
# Plot title
plt.title('TSP_01a_PhasicHeat_REAL')
# Labels for axes
axes.set_xlabel('Time (s)', color = 'black')
axes.set_ylabel('Thermal probe temperature (°C)', color = 'black')
# Secondary y-axis label
axes2.set_ylabel('Pain rating (VAS 0-100)', color = 'black', rotation=270)
# x-axis and y-axis major and minor ticks
x_major_ticks = np.arange(xmin, xmax, xint1)
x_minor_ticks = np.arange(xmin, xmax, xint2)
y_major_ticks = np.arange(ymin, ymax, yint1)
y_minor_ticks = np.arange(ymin, ymax, yint2)
y2_major_ticks = np.arange(y2min, y2max, y2int1)
y2_minor_ticks = np.arange(y2min, y2max, y2int2)
# Plot grid
axes.set_xticks(x_major_ticks)
axes.set_xticks(x_minor_ticks, minor=True)
axes.set_yticks(y_major_ticks)
axes.set_yticks(y_minor_ticks, minor=True)
axes2.set_yticks(y2_major_ticks)
axes2.set_yticks(y2_minor_ticks, minor=True)
# Tick settings for the grids:
axes.grid(which='minor', alpha=0.2)
axes.grid(which='major', alpha=0.5)
# Range for x-axis and primary and secondary y-axes
axes.set_xlim(xmin, xmax)
axes.set_ylim(ymin, ymax)
axes2.set_ylim(y2min, y2max)
def init():
return line1, line2, line3, line4, line5, line6,
def fig_update(frame):
# Check if data is not NA. If so, change it to "nan" so matplotlib can handle it by ignoring the data point
if TCStherm1[frame] == 'NA':
y1=np.nan
else:
y1=TCStherm1[frame]
if TCStherm2[frame] == 'NA':
y2=np.nan
else:
y2=TCStherm2[frame]
if TCStherm3[frame] == 'NA':
y3=np.nan
else:
y3=TCStherm3[frame]
if TCStherm4[frame] == 'NA':
y4=np.nan
else:
y4=TCStherm4[frame]
if TCStherm5[frame] == 'NA':
y5=np.nan
else:
y5=TCStherm5[frame]
if pain1[frame] == 'NA':
y6=np.nan
else:
y6=pain1[frame]
x_data.append(frame)
y_TCStherm1.append(y1)
y_TCStherm2.append(y2)
y_TCStherm3.append(y3)
y_TCStherm4.append(y4)
y_TCStherm5.append(y5)
y_pain1.append(y6)
line1.set_data(x_data, y_TCStherm1)
line2.set_data(x_data, y_TCStherm2)
line3.set_data(x_data, y_TCStherm3)
line4.set_data(x_data, y_TCStherm4)
line5.set_data(x_data, y_TCStherm5)
line6.set_data(x_data, y_pain1)
#figure.gca().relim()
#figure.gca().autoscale_view()
return line1, line2, line3, line4, line5, line6,
# Data sources for graph
TCStherm1=[randrange(38, 50) for points in range(0, 390, 1)]
TCStherm2=[randrange(38, 50) for points in range(0, 390, 1)]
TCStherm3=[randrange(38, 50) for points in range(0, 390, 1)]
TCStherm4=[randrange(38, 50) for points in range(0, 390, 1)]
TCStherm5=[randrange(38, 50) for points in range(0, 390, 1)]
pain1=[randrange(0, 100) for points in range(0, 390, 1)]
animation = FuncAnimation(figure, fig_update, interval=200, frames=graph_timelength, repeat = False, init_func=init, blit=True)
plt.show()