def psd_analysis(*args,**kwargs): """ Convenience function to plot average psd. Wrapper around `psd2d analysis` analysis. Adds a plot of average PSD and return it. Accept parameters for psd2d_analysis and plot_psd, including `analysis=True`. Call it directly to obtain 2d psd. Use Use `plot_psd` from `pySurf.psd` to plot. """ #pdb.set_trace() tmp = strip_kw(kwargs,psd2d_analysis,title="",exclude=['units']) f,p2=psd2d_analysis(*args,**tmp) p=projection(p2,axis=1) plt.figure() #u = kwargs.get('units',None) #t = kwargs.get('title',None) kw = strip_kw(kwargs,plot_psd) #u = kw['units'] if 'units' in kw else None #pdb.set_trace() plot_psd(f,p,**kw) #plot_psd(f,p,units=[u[0],u[1]] if u else u, title= t, **kwargs) return f,p
def avgpsd2d(psddata,axis=1,span=False,expand=False): """ wrapper for backward compatibilty and tutorial, use directly pySurf.data2D.projection() with axis=1 to get same effect. return psd average along axis from 2d psd computed with same orientation. default axis is 1, because axial profiles are along axis 0, sum on axis 1. """ from pySurf.data2D import projection return projection(psddata,axis=axis,span=span,expand=expand)
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 avgpsd(self, *args, **kwargs): """avg, returns f and p. Can use data2D.projection keywords `span` and `expand` to return PSD ranges.""" return self.y, projection(self.data, axis=1, *args, **kwargs)
def psd_variability(psdlist,psdrange=None,rmsrange=None,fignum=None,units=None, outname=None,figsize=(15,5)): # to be removed """given a list of 2d psd files plot spans of all of them on same plot. TODO: replace input using data rather than files. Move to 2DPSD""" from plotting.fignumber import fignumber from pySurf.data2D import projection from pySurf.psd2d import rms_power from scipy.stats import ttest_ind units=['mm','mm','$\mu$m'] labels = [p.name for p in psdlist] #gestione rudimentale dell'output troppo stanco per pensare allo standard. if outname is not None: label=os.path.basename(outname) outfolder=os.path.dirname(outname) os.makedirs(outfolder,exist_ok=True) rms_v=[] fig=fignumber(fignum,figsize=figsize) plt.subplot(121) for (p,x,f),fn in zip(psdlist,labels): ps=projection(p,axis=1,span=True) rms_v.append(rms_power(f,p,rmsrange)) c=plt.plot(f,ps[0],label=os.path.basename(fn)+' AVG')[0].get_color() plt.plot(f,ps[1],'--',label='point-wise min',c=c) plt.plot(f,ps[2],'--',label='point-wise max',c=c) #pdb.set_trace() plt.ylabel('axial PSD ('+units[2]+'$^2$ '+units[1]+')') plt.xlabel('Freq. ('+units[1]+'$^{-1}$)') plt.vlines(rmsrange,*plt.ylim(),label='rms range',linestyle=':') plt.ylim(psdrange) plt.loglog() plt.grid(1) plt.legend(loc=0) print("Statistics for %s, rms range [%6.3g,%6.3g]:"%(label,*rmsrange)) for rms,fn in zip(rms_v,labels): print(os.path.basename(fn)+": rms=%6.3g +/- %6.3g (evaluated on %i profiles)"% (np.nanmean(rms),np.nanstd(rms),len(rms))) print ("--------------") print ("Distribution of rms: %6.3g +/- %6.3g"%(np.nanmean(rms_v,axis=1).mean(),np.nanmean(rms_v,axis=1).std())) print ("AGGREGATED: rms=%6.3g +/- %6.3g (evaluated on %i profiles)"% (np.nanmean(rms_v),np.nanstd(rms_v),np.size(rms_v))) if len(rms_v)==2: print ("Student T test t:%6.3g p:%6.3g"%ttest_ind(rms_v[0],rms_v[1])) l=[os.path.splitext(os.path.basename(f))[0]+" rms=%3.2g +/- %3.2g (N=%i)"% (np.nanmean(r),np.nanstd(r),len(r)) for f,r in zip(labels,rms_v)] plt.subplot(122) plt.hist([rr[np.isfinite(rr)] for rr in rms_v],density=True,bins=100,label=l) plt.legend(loc=0) plt.title(label+" distrib. of avg: %3.2g +/- %3.2g"% (np.nanmean(rms_v,axis=1).mean(),np.nanmean(rms_v,axis=1).std())) #handles = [Rectangle((0,0),1,1,color=c,ec="k") for c in [low,medium, high]] #labels= ["low","medium", "high"] #plt.legend(handles, labels) plt.tight_layout() if outname is not None: plt.savefig(fn_add_subfix(outname,'_stats','.jpg')) return rms_v