-->

Calling matplotlib AFTER multiprocessing sometimes

2019-08-29 20:01发布

问题:

I'm doing some multiprocessing, and I'd like to understand why the following piece of code sometimes (but never at the first iteration of the loop) generates the following error :

   Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7f6c40d25ba8>>
    Traceback (most recent call last):
      File "/usr/lib/python3.5/tkinter/__init__.py", line 3359, in __del__
        self.tk.call('image', 'delete', self.name)
    RuntimeError: main thread is not in main loop
    Tcl_AsyncDelete: async handler deleted by the wrong thread
    Traceback (most recent call last):
      File "Analize0.py", line 94, in <module>
        Lambda = np.array(Rescal.multiprocess_loop_grouped(grouped_spatial_lambda, range(Nalti), Group_size, N_thread, *args))
      File "/home/gadal/PythonLib_perso/Rescal/Lib_Rescal.py", line 135, in multiprocess_loop_grouped
        return [dic[i] for i in sorted(dic.keys())]
      File "/home/gadal/PythonLib_perso/Rescal/Lib_Rescal.py", line 135, in <listcomp>
        return [dic[i] for i in sorted(dic.keys())]
      File "<string>", line 2, in __getitem__
      File "/usr/lib/python3.5/multiprocessing/managers.py", line 717, in _callmethod
        kind, result = conn.recv()
      File "/usr/lib/python3.5/multiprocessing/connection.py", line 250, in recv
        buf = self._recv_bytes()
      File "/usr/lib/python3.5/multiprocessing/connection.py", line 407, in _recv_bytes
        buf = self._recv(4)
      File "/usr/lib/python3.5/multiprocessing/connection.py", line 383, in _recv
        raise EOFError
    EOFError

Here is the code :

list_per = sorted(glob.glob('Plage*'))
Nper = len(list_per)
for simul_per in list_per :
    print(simul_per)
    path_small = os.getcwd()
    os.chdir(simul_per)
    list_alti = sorted(glob.glob('ALTI00*'))
    Nalti = len(list_alti)
    Group_size = Nalti // N_thread

    print('Reading files ...')
    Map = np.array(Rescal.multiprocess_loop_grouped(Rescal.read_file, list_alti, Group_size, N_thread))

    print('Processing data ...')

    ##################################################################################### Data analysis
    Y_simul = (100, 500)
    Deviation = np.empty((Nalti,Y_simul[1] - Y_simul[0], Map.shape[-1]))
    for i in range(Nalti):  ############### removing average beach topography
        Deviation[i,:,:] = Map[i,Y_simul[0]:Y_simul[1],:] - np.mean(Map[i,Y_simul[0]:Y_simul[1],:], axis = 0, keepdims = True)



    ############   Beach wavelength
    print('     Beach wavelength ...')

    X_beach = (300,650)

    args = [X_beach, Deviation]
    Temp = Rescal.multiprocess_loop_grouped(find_lambda_plage, range(Nalti), Group_size, N_thread, *args)
    Lambda_plage = np.array([i[0] for i in Temp])
    Orientation = np.array([i[1] for i in Temp])

    ############ Wavelength as a function of space
    print('     Wavelength as a function of space ...')

    args = [Deviation]
    Lambda = np.array(Rescal.multiprocess_loop_grouped(grouped_spatial_lambda, range(Nalti), Group_size, N_thread, *args))

    print('Saving data ...')

    Data = {}
    Data['Lambda_finger'] = Lambda_finger
    Data['Lambda_plage'] = Lambda_plage
    Data['Orientation'] = Orientation
    Data['Map'] = Map
    Data['Lambda'] = Lambda

    np.save('Data', Data)

    print('Saving figures ...')

    plt.figure()
    plt.plot(Lambda_finger)
    plt.ylim([0, 300])
    plt.savefig('Lambda_finger.pdf')

    plt.clf()
    plt.plot(Lambda_plage)
    plt.plot(Lambda_finger[:,10])
    plt.ylim([0, 300])
    plt.legend(('Lambda plage', 'Lambda finger'))
    plt.savefig('Lambda.pdf')

    plt.clf()
    plt.imshow(Lambda)
    cbar = plt.colorbar()
    plt.xlabel('x')
    plt.ylabel('Time')
    cbar.set_label('Lambda')
    plt.clim([0, 80])
    plt.savefig('Spatial_time_lambda.pdf')


    plt.close('all')

    os.chdir(path_small)

I'm multiprocessing some independent tasks over the files I have using a function I've written, and which is described here : Function that multiprocesses another function.

However, the functions called by the the one that multiprocesses them never call matplotlib, which is called by the main thread after that the last multiprocessing call is done.

For example, the function in the previous error grouped_spatial_lambda is made of :

def spatial_evolution_lambda(Map):
    Lambda = []
    for x in range(Map.shape[1]):
        Lambda.append(Anls.find_first_max(autocorr(Map[:,x])))
    return Lambda

def grouped_spatial_lambda(indexes,dic,Deviation):
    for i in indexes:
        dic[i] = spatial_evolution_lambda(Deviation[i,:,:])

def find_first_max(a, valmax = False):
    inds = find_peaks(a)[0]
    if len(inds) > 0:
        l = inds[inds > 5]
        if len(l) > 0:
            testerr = 0
            a_norm = a/np.max(a)
            x_fit = np.array([i for i in range(int(l[0]/2), int(3*l[0]/2))])
            x_fit = x_fit[x_fit < len(a)]
            y_fit = a_norm[x_fit]
            x_fit = x_fit[y_fit > 0]
            y_fit = a_norm[x_fit]
            if x_fit.size == 0 or len(x_fit) < 3 :
                lamb = np.nan
                amp = np.nan
            else:
                try:
    #                popt, pcov = curve_fit(gaus,x_fit.ravel(),y_fit.ravel(), p0=[np.max(y_fit),np.mean(x_fit),np.mean(x_fit)])
                    popt, pcov = curve_fit(gaus,x_fit,y_fit, p0=[np.max(y_fit),np.mean(x_fit),np.mean(x_fit)])

                except RuntimeError:
                    lamb =  np.nan
                    amp = np.nan
                    testerr = 1
                if testerr == 0:
                    lamb =  popt[1]
                    amp = popt[0]
        else:
            lamb = np.nan
            amp = np.nan
    else:
        lamb =  np.nan
        amp = np.nan
    if valmax == False:
        return lamb
    else:
        return lamb, amp, 1.96/np.sqrt(a.size)

From what I understand from the posted error, tkinter generates an exception that leads to EOF error ? How can this be as the call to matplotlib is done after the multiprocessing of the other functions ? Does it have something to do with the loop ? (Previous call to matplotlib .. ?) How do I force matplotlib to run in the main thread ?