使用matplotlib.widgets进行交互式绘图的绘图阻止问题

时间:2020-07-14 16:06:02

标签: python matplotlib matplotlib-widget

我正在编写一个代码,该代码绘制来自实验的原始数据,并且试图通过matplotlib.widget小部件使用Slider来操纵该图中的回归。小部件将更改回归的拟合参数,并在您更改参数时自动重新计算回归。一旦找到了理想的参数(通过直观检查回归),我便想接受该参数并继续执行我的代码。我遇到的问题是,无论我按 accept 按钮,整个代码都可以运行。在我看来,这正在阻止问题,并且尝试遵循一个非常类似的问题并未证明是成功的:

Continue code after closing matplotlib figure

我已经读到它可能是图形后端问题,但是我已经尝试了IDE(运行Python 3.7.6的Spyder 4.1.3)下拉列表中的所有内容:

  • 内联
  • 自动
  • Qt5
  • Qt4
  • Tkinter

我不知道这是图形后端问题(当前正在运行Qt5)还是代码错误。很有可能是代码错误,因为这是我第一次使用python,但是我没有收到任何错误,甚至像下面这样的简单伪代码也没有达到预期的效果:

from matplotlib.pyplot import plot,show
plot([1,2,3])
show(block=True)

show()

print ('continue computation after plot closes')

在这些链接中,我也尝试过答案,或者我猜是相反的答案:

Plotting in a non-blocking way with Matplotlib

Is there a way to detach matplotlib plots so that the computation can continue?

有什么想法可以在剧情结束后继续我的代码吗?

感谢您的帮助。


p.s。我的实际代码如下,尽管上面的伪代码应该足够了(请注意,95%的置信区间并不是我想要的reset,但这是另一场战斗)

import numpy as np
import matplotlib.pyplot as plt
import csv
import math

from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C
from matplotlib.widgets import Slider, Button

def kernreg(xx,yy,zz,aa):
    #Define the kernel regression function.
    #xx=Input x-data
    #yy=Input y-data
    #zz=Predicted x-values
    #aa=Passed value of alpha
    #Function outputs is the predicted y-values and mean squared error

    #Instantiate Gaussian Process model with a product-kernel consisting of a
    #radial-basis function kernel and a constant kernel
    kernel=C(1.0, (1e-3, 1e3))*RBF(10, (1e-2, 1e2))
    gp=GaussianProcessRegressor(kernel=kernel,alpha=aa,
                                optimizer='fmin_l_bfgs_b',
                                n_restarts_optimizer=25)
    #Fit to data using Maximum Likelihood Estimation of the parameters
    gp.fit(xx,yy)
    #Make the prediction on the meshed x-axis (ask for MSE as well)
    y_pred,sig=gp.predict(zz,return_std=True)
    return y_pred,sig


in2ft=1/12 #Convert inches to ft
fps2mph=1/1.4667 #Convert feet per second to miles per hour
fpsps2g=1/32.174049 #Convert feet per second squared to g
z_conf_int=1.96 #Z-score for a 95% confidence interval

#Import raw data; x [in], y[in], z[in]
with open('XYZ_data_20fps.csv','r') as datafile:
    readCSV=csv.reader(datafile, delimiter=',')
    
    x=[]
    y=[]
    z=[]
    
    for row in readCSV:
        x_i=float(row[0])
        y_i=float(row[1])
        z_i=float(row[2])
        
        x.append(x_i)
        y.append(y_i)
        z.append(z_i)

#Calculate the raw distance travelled
d=[] #Distance travelled [ft]
for i in range(len(x)-1):
    d_i=math.sqrt((x[i+1]-x[i])**2+(y[i+1]-y[i])**2+(z[i+1]-z[i])**2)*in2ft
    d.append(d_i)

#Sample frame queries 
frm_pred=np.atleast_2d(np.arange(1,len(x)+0.25,0.25)).T

#Frames analyzed (1=first frame)
frm=np.arange(1,len(x)+1)
frm_data=np.atleast_2d(frm[1:]).T


#Calling the kernel regression function for the initial guess
alpha_0=0.5
d_pred_0,sigma_0=kernreg(frm_data,d,frm_pred,alpha_0)

fig=plt.figure()
ax=fig.add_subplot(111)
fig.subplots_adjust(bottom=0.25)

#Draw the initial plot
plt.plot(frm_data,d,'o',color='black',label='Data')
[line]=plt.plot(frm_pred,np.array(kernreg(frm_data,d,frm_pred,alpha_0)  [0:1]).T,'b-',label='Prediction')
plt.xlabel("Frame")
plt.ylabel("Distance Travelled [ft]")
plt.legend(loc='best')

#Define an axes area and draw a slider in it
axis_color = 'lightgoldenrodyellow'
alph_slider_ax  = fig.add_axes([0.175, 0.1, 0.65, 0.03], facecolor=axis_color)
alph_slider = Slider(alph_slider_ax, chr(945), 0.01, 1.0, valinit=alpha_0)

#Define an action for modifying the line when any slider's value changes
def sliders_on_changed(val):
    line.set_ydata(kernreg(frm_data,d,frm_pred,alph_slider.val)[0:1])
    fig.canvas.draw_idle()
alph_slider.on_changed(sliders_on_changed)

#Add a button for resetting the parameters
reset_button_ax = fig.add_axes([0.175, 0.05, 0.1, 0.04])
reset_button = Button(reset_button_ax, 'Reset',color=axis_color,hovercolor='0.975')
def reset_button_on_clicked(mouse_event):
    alph_slider.reset()
reset_button.on_clicked(reset_button_on_clicked)

#Add a button for calculating the 95% confidence interval
conf_button_ax=fig.add_axes([0.175, 0.005, 0.35, 0.04])
conf_button=Button(conf_button_ax, 'Calculate Confidence Interval', color=axis_color,hovercolor='0.975')
def conf_button_on_click(mouse_event):
    ax.fill(np.concatenate([frm_pred,frm_pred[::-1]]),
         np.concatenate(
             [np.array(kernreg(frm_data,d,frm_pred,alph_slider.val)[0:1]).T-       z_conf_int*np.array(kernreg(frm_data,d,frm_pred,alph_slider.val)[1:2]).T,
                        (np.array(kernreg(frm_data,d,frm_pred,alph_slider.val)[0:1]).T+z_conf_int*np.array(kernreg(frm_data,d,frm_pred,alph_slider.val)[1:2]).T)[::-1]]),
         alpha=.5, fc='b', ec='None', label='95% Confidence Interval')
    ax.legend(loc='best') #Plot new legend with the confidence interval
conf_button.on_clicked(conf_button_on_click)

#Add a button to accept the chosen value of alpha
accept_button_ax=fig.add_axes([0.28, 0.05, 0.15, 0.04])
accept_button=Button(accept_button_ax,'Accept Value',color=axis_color,hovercolor='0.975')
mutable_object={}
def accept_button_on_click(mouse_event):
    alpha=alph_slider.val
    mutable_object['mouse_event']=alpha
    alpha=mutable_object['mouse_event']
    print(alpha)
    plt.close()
accept_button.on_clicked(accept_button_on_click)

print('THIS SHOULD RUN ONLY AFTER I PRESS ACCEPT')
print('REST OF COMPUTATIONS')

0 个答案:

没有答案