def calibrate_samples(files,f2,cr=None,rotate=False,level=((1,1),False)): """create a dictionary ddic with calibrated and shape leveled Data2D for each file, key is the base filename. Uses display_diff. Level is a two element tuple containing (leveling_order,byline) see data2D.level_data.""" ddic={} for ff in files: #remove signature print("calibrating ",os.path.basename(ff)) d1,d2,diff=display_diff(ff,f2,dis=False,crd=cr) #level and rotate diff=diff.level(*level) if rotate: diff=diff.rot90() #plot and saves plt.clf() lrange=remove_outliers(diff.data,nsigma=3,itmax=1,span=True) diff.plot() plt.title(d1.name+' leveled' + (' rotated' if rotate else "")) plt.clim(*lrange) display(plt.gcf()) diff.printstats(os.path.basename(ff)) #add data to return dic ddic[os.path.basename(ff)]=diff return ddic
def plot_difference(p1t, p4, trim=None, dis=False): """plots and return difference of two Data2D objects, return difference. All data are plane leveled before plots, a common color scale is set after excluding outliers. Leveled difference is returned. If trim is other than None, plots are adjusted on valid data x and y range, if Trim = True empty borders are removed also from difference data.""" if trim is not None: if trim: p1t = p1t.remove_nan_frame() p4 = p4.remove_nan_frame() xr = span(np.array([span(d.remove_nan_frame().x) for d in [p1t, p4]])) yr = span(np.array([span(d.remove_nan_frame().y) for d in [p1t, p4]])) else: xr = span(np.array([span(d.x) for d in [p1t, p4]])) yr = span(np.array([span(d.y) for d in [p1t, p4]])) plt.clf() ax1 = plt.subplot(131) p1t.level((1, 1)).plot() #plt.title('PZT + IrC') plt.clim(*remove_outliers(p1t.level().data, nsigma=2, itmax=3, span=1)) plt.grid() ax2 = plt.subplot(132, sharex=ax1, sharey=ax1) p4.level((1, 1)).plot() #plt.title('PZT') plt.clim(*remove_outliers(p4.level().data, nsigma=2, itmax=3, span=1)) plt.grid() ax3 = plt.subplot(133, sharex=ax1, sharey=ax1) diff = (p1t - p4).level((1, 1)) diff.name = 'Difference 1-2' diff.plot() plt.clim(*remove_outliers(diff.level().data, nsigma=2, itmax=3, span=1)) plt.grid() plt.xlim(*xr) #this adjust all plots to common scale plt.ylim(*yr) if dis: display(plt.gcf()) return diff
def process_set2(flist,names,outname,crop=None,dis=True): # from C1S15_4D_DI_calibration_181031.ipynb # called with: ypix=None #0.127901442999 #mm ytox=220./200. zscale=None #0.6328 scale=(1000,-1000,0.001) outfolder=os.path.dirname(outname) outname=os.path.basename(outname) dlist=[Data2D(*matrix4D_reader(wf2,scale=scale,zscale=zscale, ypix=ypix,ytox=ytox,center=(0,0),strip=True),name=n,units=['mm','mm','um']) for wf2,n in zip(flist,names)] np.mean(dlist).save(os.path.join(outfolder,outname+'_avg.dat')) plt.close('all') sx,sy=find_grid_size(len(dlist),3) f,axes=plt.subplots(sx,sy,sharex=True,sharey=True) for ax,d in zip(axes.flatten(),dlist): plt.sca(ax) d.plot() plt.clim(*remove_outliers(d.data,nsigma=2,itmax=3,span=1)) for ax in axes.flatten()[:len(dlist)-1:-1]: f.delaxes(ax) maximize() plt.pause(0.1) plt.tight_layout(rect=[0,0,1,0.9]) plt.suptitle ('Surfaces') if dis: display(plt.gcf()) plt.savefig(os.path.join(outfolder,outname+'.png')) m_repr=[dcouples_plot([dd for dd in dlist])] if dis: display(plt.gcf()) plt.savefig(os.path.join(outfolder,'diff_'+outname+'.png')) if crop is not None: dc=[d.crop(*crop).level() for d in dlist] m_repr=[dcouples_plot([dd for dd in dc])] if dis: display(plt.gcf()) plt.savefig(os.path.join(outfolder,'diff_'+outname+'_crop.png')) return dlist
def process_set(flist,m_trans=None,m_arr=None,outfolder=None): rmslist=[] #plot surfaces, dlist is list of Data2D objects with raw data dlist=plot_repeat(flist, None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rms=[d.level(1,1).std() for d in dlist] if m_trans is None: tmp2=dlist else: tmp2=[d.apply_transform(t) for d,t in zip(dlist,m_trans)] if m_arr is not None: #plot transformed data for verification fig,axes=plt.subplots(xs,ys,sharex='all',sharey='all',squeeze=True) axes=axes.flatten() maximize() for d,ax,m,t in zip(tmp2,axes,m_arr,m_trans): plt.sca(ax) ll=d.level(4,byline=True) ll.plot() plt.clim(*remove_outliers(ll.data,nsigma=2,itmax=1,span=True)) plt.plot(*((t(m).T)),'xr') if outfolder is not None: plt.savefig(None if outfolder is None else os.path.join(outfolder,k+'_alignment.png')) #plot differences with various levelings difflist = plot_rep_diff(tmp2,None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rmslist.append([[dd.std() for dd in d] for d in difflist]) if columns is None: columns = pd.RangeIndex(0,np.size(rmslist)) if stats is None: stats = pd.DataFrame(columns=columns) pstats = pd.DataFrame(columns=stats.columns,data=np.array(rmslist).reshape(1,-1),index=[k]) return pstats
def add_markers(dlist): """interactively set markers, when ENTER is pressed, return markers as list of ndarray. It was align_active interactive, returning also trans, this returns only markers, transforms can be obtained by e.g. : m_trans=find_transform(m,mref) for m in m_arr] """ #set_alignment_markers(tmp) xs, ys = find_grid_size(len(dlist), 5)[::-1] fig, axes = subplot_grid(len(dlist), (xs, ys), sharex='all', sharey='all') axes = axes.flatten() #maximize() for i, (d, ax) in enumerate(zip(dlist, axes)): plt.sca(ax) ll = d.level(4, byline=True) ll.plot() plt.clim(*remove_outliers(ll.data, nsigma=2, itmax=1, span=True)) add_clickable_markers2(ax, hold=(i == (len(dlist) - 1))) return [np.array(ax.markers) for ax in axes]
def filtered_span(*args,**kwargs): from dataIO.outliers import remove_outliers warnings.warn('This routine was replaced by outliers.remove_outliers please update calling code, will be removed.',RuntimeWarning) return remove_outliers(*args,**kwargs) '''
def conf_stats(k,conf,columns=None,dis=True): """Analyzes a single configuration (as list of files + processing settings). returns repeatability statistics in form of pdDataFrame. """ rmslist=[] #outfile=os.path.join(outfolder,k) flist=[os.path.join(conf['infolder'],f)for f in conf['files']] transmode=conf.get('trans',None) #plot surfaces, dlist is list of Data2D objects with raw data dlist=plot_repeat(flist, None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rms=[d.level(1,1).std() for d in dlist] tmp2=[d if t is None else t(d) for d,t in zip(dlist,m_trans)] #align if necessary: if transmode=='none' or transmode == "": #do nothing tmp2=dlist else: plt.close('all') if transmode == 'interactive': print ("""interactively set markers on each axis with CTRL+LeftMouse. Remove markers with CTRL+right_mounse, ENTER when ready.""") #run interactive alignment m_arr,m_trans=align_interactive(dlist,find_transform=find_affine) #incorporate markers in config and save backup copy for the configuration. # This is just temporary ass saver in case of crash, final conf is anyway # saved outside for all configurations. conf['trans']='config' # alignment mode, read from config conf['mref']=m_arr[0].tolist() #reference markers to aligh to conf['markers']=[m.tolist() for m in m_arr] #markers saved as lists json.dump({k:conf},open(os.path.join(outfolder,k+'_out.json'),'w'),indent=0) else: if transmode == 'config': #gets markers from configfile pass #conf is already set elif transmode == 'file': d=json.load(open(conf['markers'],'r')) print(list(d.keys()),'\n\n',d[list(d.keys())[0]]) print(len(list(d.keys()))," datasets") k,conf=list(d.items())[0] else: raise ValueError m_arr=[np.array(m) for m in conf['markers']] mref=conf['mref'] m_trans=[find_transform(m,mref) for m in m_arr] #make and plots transformed (aligned) data to verify feature alignment tmp2=[d.apply_transform(t) for d,t in zip(dlist,m_trans)] #plot transformed data for verification fig,axes=plt.subplots(xs,ys,sharex='all',sharey='all',squeeze=True) axes=axes.flatten() maximize() for d,ax,m,t in zip(tmp2,axes,m_arr,m_trans): plt.sca(ax) ll=d.level(4,byline=True) ll.plot() plt.clim(*remove_outliers(ll.data,nsigma=2,itmax=1,span=True)) plt.plot(*((t(m).T)),'xr') plt.savefig(None if outfolder is None else os.path.join(outfolder,k+'_alignment.png')) #yield dlist #plot differences with various levelings difflist = plot_rep_diff(tmp2,None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rmslist.append([[dd.std() for dd in d] for d in difflist]) if columns is None: tags=['%02i-%02i'%(i,j) for i,j in itertools.combinations(range(1,nfiles+1),2)] columns=pd.MultiIndex.from_product([['raw','cyl','con','leg'],tags],names=['terms removed','files#']) #columns = pd.RangeIndex(0,np.size(rmslist)) #pdb.set_trace() cstats = pd.DataFrame(columns=columns,data=np.array(rmslist).reshape(1,-1),index=[k]) return cstats
def rep_stats(flist,columns=None,dis=True): """Analyzes a list of files with possible transformations. returns repeatability statistics in form of pdDataFrame. """ rmslist=[] #plot surfaces, dlist is list of Data2D objects with raw data dlist=plot_repeat(flist, None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rms=[d.level(1,1).std() for d in dlist] tmp2=[d if t is None else t(d) for d,t in zip(dlist,m_trans)] #align if necessary: if transmode=='none' or transmode == "": #do nothing tmp2=dlist else: plt.close('all') if transmode == 'interactive': print ("""interactively set markers on each axis with CTRL+LeftMouse. Remove markers with CTRL+right_mounse, ENTER when ready.""") #run interactive alignment m_arr,m_trans=align_interactive(dlist,find_transform=find_affine) else: if transmode == 'file': #read markers from file that some raise NotImplementedError else: raise ValueError m_arr=[np.array(m) for m in conf['markers']] mref=conf['mref'] m_trans=[find_transform(m,mref) for m in m_arr] #make and plots transformed (aligned) data to verify feature alignment tmp2=[d.apply_transform(t) for d,t in zip(dlist,m_trans)] #plot transformed data for verification fig,axes=plt.subplots(xs,ys,sharex='all',sharey='all',squeeze=True) axes=axes.flatten() maximize() for d,ax,m,t in zip(tmp2,axes,m_arr,m_trans): plt.sca(ax) ll=d.level(4,byline=True) ll.plot() plt.clim(*remove_outliers(ll.data,nsigma=2,itmax=1,span=True)) plt.plot(*((t(m).T)),'xr') plt.savefig(None if outfolder is None else os.path.join(outfolder,k+'_alignment.png')) #yield dlist #plot differences with various levelings difflist = plot_rep_diff(tmp2,None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rmslist.append([[dd.std() for dd in d] for d in difflist]) if columns is None: tags=['%02i-%02i'%(i,j) for i,j in itertools.combinations(range(1,nfiles+1),2)] columns=pd.MultiIndex.from_product([['raw','cyl','con','leg'],tags],names=['terms removed','files#']) #columns = pd.RangeIndex(0,np.size(rmslist)) #pdb.set_trace() cstats = pd.DataFrame(columns=columns,data=np.array(rmslist).reshape(1,-1),index=[k]) return cstats
def build_database(confdic,outfolder=None,columns=None,dis=False, find_transform=find_rototrans): """Process all files and return stats database in form of pd.DataFrame from confdic. plot_repeat and plot_rep_diff are used to read fits files and calculate rmss. If outfolder is provided, output plots are generated in functions. Expect an index for columns (can be multiindex.) If dis is set, display (set to True for single dataset, False for multiple config processing.""" def make_dates(stats): """returns a dataframe dates build with indices from stats and value """ dates=[] for k in stats.index: try: date=confdic[k]['date'] except KeyError: date=k.split('_')[0] dates.append(parse(date,yearfirst=True).date()) return pd.Series(data=dates,index=stats.index) #check existence of files before starting processing for k,conf in confdic.items(): flist=[os.path.join(conf['infolder'],f)for f in conf['files']] if not np.all([os.path.exists(f) for f in flist]): print (k," has some files that cannot be found:") print (conf['infolder']) print (conf['files']) for f in flist: open(f).close() #raise exception if file doesn't exist stats = None #real processing for i,(k,conf) in enumerate(confdic.items()): print("Process data %i/%i"%(i+1,len(confdic.items()))) ####### rmslist=[] #outfile=os.path.join(outfolder,k) flist=[os.path.join(conf['infolder'],f)for f in conf['files']] #plot surfaces, dlist is list of Data2D objects with raw data dlist=plot_repeat(flist, None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rms=[d.level(1,1).std() for d in dlist] #align if necessary: transmode=conf.get('trans',None) if transmode=='none' or transmode == "": #do nothing tmp2=dlist else: plt.close('all') if transmode == 'interactive': print ("""interactively set markers on each axis with CTRL+LeftMouse. Remove markers with CTRL+right_mounse, ENTER when ready.""") #run interactive alignment m_arr,m_trans=align_interactive(dlist,find_transform=find_transform) #incorporate markers in config and save backup copy conf['trans']='config' # alignment mode, read from config conf['mref']=m_arr[0].tolist() #reference markers to aligh to conf['markers']=[m.tolist() for m in m_arr] #markers saved as lists json.dump({k:conf},open(os.path.join(outfolder,k+'_out.json'),'w'),indent=0) else: if transmode == 'config': #gets markers from configfile pass #conf is already set elif transmode == 'file': d=json.load(open(conf['markers'],'r')) print(list(d.keys()),'\n\n',d[list(d.keys())[0]]) print(len(list(d.keys()))," datasets") k,conf=list(d.items())[0] else: raise ValueError m_arr=[np.array(m) for m in conf['markers']] mref=conf['mref'] m_trans=[find_transform(m,mref) for m in m_arr] #make and plots transformed (aligned) data to verify feature alignment tmp2=[d.apply_transform(t) for d,t in zip(dlist,m_trans)] #plot transformed data for verification fig,axes=plt.subplots(xs,ys,sharex='all',sharey='all',squeeze=True) axes=axes.flatten() maximize() for d,ax,m,t in zip(tmp2,axes,m_arr,m_trans): plt.sca(ax) ll=d.level(4,byline=True) ll.plot() plt.clim(*remove_outliers(ll.data,nsigma=2,itmax=1,span=True)) plt.plot(*((t(m).T)),'xr') plt.savefig(None if outfolder is None else os.path.join(outfolder,k+'_alignment.png')) #yield dlist #plot differences with various levelings difflist = plot_rep_diff(tmp2,None if outfolder is None else os.path.join(outfolder,k+'.png'),dis=dis) rmslist.append([[dd.std() for dd in d] for d in difflist]) if columns is None: columns = pd.RangeIndex(0,np.size(rmslist)) if stats is None: stats = pd.DataFrame(columns=columns) pstats = pd.DataFrame(columns=stats.columns,data=np.array(rmslist).reshape(1,-1),index=[k]) #### fuori routine stats=stats.append(pstats) dates=make_dates(stats) return stats, dates
def comp2(d1, d2, roi=None): #adapted (partially) to data2d """make 4 panel plot with data, differences and difference slope for two data sets on same x and y. Return four axis for plot customization. all data and all stats are leveled. roi: if passed, plot a corresponding rectangle.""" partial = False #not implemented, if a roi is defined, adds a legend with partial statistics if roi is not None: rect = np.array([(roi[0][0], roi[1][0]), (roi[0][0], roi[1][1]), (roi[0][1], roi[1][1]), (roi[0][1], roi[1][0]), (roi[0][0], roi[1][0])]) plt.figure(6) plt.clf() maximize() import pdb #pdb.set_trace() diff = d1 - d2 ax1 = plt.subplot(141) d1.level().plot(title='Data') plt.clim(*remove_outliers(d1.level().data, nsigma=2, itmax=3, span=True)) if roi is not None: plt.plot(rect[:, 0], rect[:, 1], '--', c='black', lw=2) legendbox(get_stats(d1.crop(*roi).level()()[0]), loc=4) ax2 = plt.subplot(142, sharex=ax1, sharey=ax1) d2.level().plot(title='Simulation') plt.clim(*remove_outliers(d2.level().data, nsigma=2, itmax=3, span=True)) if roi is not None: plt.plot(rect[:, 0], rect[:, 1], '--', c='black', lw=2) legendbox(get_stats(d2.crop(*roi).level()()[0]), loc=4) ax3 = plt.subplot(143, sharex=ax1, sharey=ax1) diff.level().plot(title='Difference') plt.clim(*remove_outliers(diff.level().data, nsigma=2, itmax=3, span=True)) if roi is not None: plt.plot(rect[:, 0], rect[:, 1], '--', c='black', lw=2) legendbox(get_stats(diff.crop(*roi).level()()[0]), loc=4) ax4 = plt.subplot(144, sharex=ax1, sharey=ax1) #2019/03/28 replaced with object #grad=np.gradient(diff.level().data) #dy=np.diff(diff.y)[0] #slopeax=grad[0]/1000.*206265/dy #x,y=diff.x,diff.y #plot_data(slopeax,x,y,units=['mm','mm','arcsec'],title='Axial Slope',stats=True) #, #vmin=-250,vmax=250) #plt.clim(*remove_outliers(slopeax,nsigma=2,itmax=3,span=True)) #if roi is not None: # plt.plot(rect[:,0], rect[:,1], '--',c='black', lw=2) # legendbox(get_stats(*crop_data(slopeax,x,y,*roi),units=['mm','mm','arcsec']),loc=4) slopeax = diff.slope(scale=(1., 1., 1000.))[1] slopeax.name = 'Axial Slope' slopeax.plot() if roi is not None: plt.plot(rect[:, 0], rect[:, 1], '--', c='black', lw=2) legendbox(get_stats(slopeax.crop(*roi).level()()[0]), loc=4) axes = [ax1, ax2, ax3, ax4] ''' if roi is not None: #update legend to include total and partial stats. for ax in axes: for art in ax.artists: if isinstance(art,matplotlib.legend.Legend): p = art.get_patches() t = art.get_texts() newleg=Legend(ax,p,t,loc=2,handletextpad=0, handlelength=0) ax.add_artist(newleg) art.remove() ''' return axes
def plot_surface_analysis(wdata,x,y,label="",outfolder=None,nsigma_crange=1,fignum=None, figsize=(9.6,6.7),psdrange=None,levelingfunc=None,frange=None): """Create two panel preview plots for data. This is two panels of raw and filtered data (second order removed) + histogram of height distribution + PSD. Label is typically the filename and is used to generate title and output filenames. fignum and figsize are for PSD2D figure (fignum=0 clear and reuse current figure, None create new). nsigma_crange and levelingfunc are used to evaluate color range for plot by iteratively leveling and removing outliers at nsigma until a convergence is reached. psdrange is used frange is used for plot of PSD2D """ from pySurf.psd2d import psd2d_analysis units=['mm','mm','$\mu$m'] order_remove=2 #remove sag, this is the order that is removed in leveled panel if np.size(units)==1: #unneded, put here just in case I decide to take units units=np.repeat(units,3) #as argument. However ideally should be put in plot psd function. if levelingfunc is None: levelingfunc=lambda x: x-legendre2d(x,1,1)[0] if outfolder is not None: os.makedirs(os.path.join(outfolder,'PSD2D'),exist_ok=True) else: print('OUTFOLDER is none') wdata=levelingfunc(wdata) #added 20181101 rms=np.nanstd(wdata) #crange=remove_outliers(wdata,nsigma=nsigma_crange,itmax=1,range=True) crange=remove_outliers(wdata,nsigma=nsigma_crange, flattening_func=levelingfunc,itmax=2,span=1) plt.clf() #FULL DATA plt.subplot(221) #plt.subplot2grid((2,2),(0,0),1,1) plot_data(wdata,x,y,units=units,title='leveled data',stats=True) plt.clim(*crange) #SUBTRACT LEGENDRE ldata=levellegendre(y,wdata,order_remove) plt.subplot(223) lrange=remove_outliers(ldata,nsigma=nsigma_crange,itmax=1,span=True) #plt.subplot2grid((2,2),(1,0),1,1) plot_data(ldata,x,y,units=units,title='%i orders legendre removed'%order_remove,stats=True) plt.clim(*lrange) #HISTOGRAM #plt.subplot2grid((2,2),(0,1),2,1) plt.subplot(222) plt.hist(wdata.flatten()[np.isfinite(wdata.flatten())],bins=100,label='full data') plt.hist(ldata.flatten()[np.isfinite(ldata.flatten())],bins=100,color='r',alpha=0.2,label='%i orders filtered'%order_remove) #plt.vlines(crange,*plt.ylim()) plt.vlines(crange,*plt.ylim(),label='plot range raw',linestyle='-.') plt.vlines(lrange,*plt.ylim(),label='plot range lev',linestyle=':') plt.legend(loc=0) #FREQUENCY AND PSD ANALYSIS if fignum==0: #this is the figure created by psd2d_analysis plt.clf() fig = plt.gcf() #pdb.set_trace() stax=plt.gca() #preserve current axis f,p=psd2d_analysis(ldata,x,y,title=label, wfun=np.hanning,fignum=fignum,vrange=lrange, prange=psdrange,units=units, rmsrange=frange)#,ax2f=[0,1,0,0]) plt.ylabel('slice rms ($\mu$m)') ps=projection(p,axis=1,span=True) #avgpsd2d(p,span=1) if outfolder: maximize() plt.savefig(os.path.join(outfolder,'PSD2D', fn_add_subfix(label,"_psd2d",'.png'))) save_data(os.path.join(outfolder,'PSD2D',fn_add_subfix(label,"_psd2d",'.txt')), p,x,f) np.savetxt(os.path.join(outfolder,fn_add_subfix(label,"_psd",'.txt')),np.vstack([f,ps[0],ps[1],ps[2]]).T, header='f(%s^-1)\tPSD(%s^2%s)AVG\tmin\tmax'%(units[1],units[2],units[1]),fmt='%f') #pdb.set_trace() plt.sca(stax) plt.subplot(224) plt.ylabel('axial PSD ('+units[2]+'$^2$ '+units[1]+')') plt.xlabel('Freq. ('+units[1]+'$^{-1}$)') plt.plot(f,ps[0],label='AVG') plt.plot(f,ps[1],label='point-wise min') plt.plot(f,ps[2],label='point-wise max') plt.plot(f,p[:,p.shape[1]//2],label='central profile') plt.ylim(psdrange) plt.loglog() plt.grid(1) plt.legend(loc=0) #ideally to be replaced by: """ plt.subplot(224) plot_psd(((f,ps[0]),(f,ps[1]),(f,ps[2),(f,p[:,p.shape[1]//2])), ['AVG','point-wise min','point-wise max','central profile']) plt.ylabel('axial '+plt.ylabel) plt.ylim(psdrange) """ plt.suptitle('%s: rms=%5.3f 10$^{-3}$'%(label,rms*1000)+units[2]) plt.tight_layout(rect=[0, 0.03, 1, 0.95]) if outfolder: plt.savefig(os.path.join(outfolder,fn_add_subfix(label,"",'.png'))) return (ldata,x,y),(f,p)
def display_diff(f1,f2,data=False,dis=True,crd=None): """calculates, plots and returns the difference of two data. It is just a diff-and-plot with a few added options and settings for color scale and reading files, can probably be replaced by more standard routines. f1 and f2 are file names, unless data is set, in that case they are interpreted as data. Data are plotted on common color scale, while range for difference crd can be imposed, otherwise is calculated on outlier removed difference.""" #set units units=['mm','mm','nm'] zscale=1000 #load data in d1 and d2 according if arguments are data or filenames if not(data): d1=Data2D(file=f1,units=units,scale=(1000,-1000,zscale),center=(0,0)) if f2 is not None: d2=Data2D(file=f2,units=units,scale=(1000,-1000,zscale),center=(0,0)) else: d2=cp.deepcopy(d1)*0 #d2.data=d2.data*0 else: d1=Data2D(f1.data,f1.x,f1.y,units=units) if f2 is not None: d2=Data2D(f2.data,f2.x,f2.y,units=units) else: d2=cp.deepcopy(d1)*0 #d2.data=d2.data*0 #plane level and diff d1=d1.level() d2=d2.level() diff=(d1-d2).level() #calculate common color range cr1=remove_outliers(d1.data,span=True) cr2=remove_outliers(d2.data,span=True) cr=[min([cr1[0],cr2[0]]),max([cr1[0],cr2[1]])] if crd is None: #color range for difference. crd=remove_outliers(diff.data,span=True) #plot on three panels, prints stats plt.clf() plt.subplot(311) maximize() d1.plot() plt.clim(*cr) d1.printstats() plt.subplot(312) d2.plot() plt.clim(*cr) d2.printstats() plt.subplot(313) diff.plot() plt.clim(*crd) print ("diff 2 - 1 = ") diff.printstats() plt.tight_layout() #plt.clim(*cr)#[-0.0001,0.0001]) if not(data): if f2 is not None: plt.title ('Difference %s - %s'%tuple(os.path.basename(ff) for ff in [f1,f2])) else: plt.title ('%s '%f2) plt.show() #print ("PV: ",span(diff.data,size=True),diff.units[-1]) #print ("rms: ",np.nanstd(diff.data),diff.units[-1]) return d1,d2,diff