예제 #1
0
def internal_nan_mask(a, x=None, y=None):
    """return a mask with True on internal nans."""

    if x is None:
        x = np.arange(np.shape(a)[1])
    if y is None:
        y = np.arange(np.shape(a)[0])

    sx = [np.min(x), np.max(x)]
    sy = [np.min(y), np.max(y)]

    # b is 1 where a is nan, 0 othewise
    #used to detect when a region is made of nans
    aisnan = np.where(np.isnan(a), True, False)
    #plt.figure(); plot_data(b,x,y)
    #plt.title('b')

    # s is different integer for each contiguous region, can be
    s = label(aisnan)[0]
    #plt.figure()
    #plot_data(s)

    #m_int mask of internal nan regions of a
    m_int = np.zeros(a.shape).astype(bool)
    for i in range(np.max(s) + 1):
        c = s == i
        if aisnan[c].all():
            #plt.figure()
            #plot_data(c,x,y)
            #for each one find hull and check if it touches borders
            p = matrix_to_points2(c, x, y)
            p = p[p[:, 2] != 0, :]  #keep only points of current region
            ssx = span(p[:, 0])  #ranges of points in region
            ssy = span(p[:, 1])
            #print(i,sx,sy,ssx,ssy)
            if (ssx[0] > sx[0] and ssx[1] < sx[1] and ssy[0] > sy[0]
                    and ssy[1] < sy[1]):
                #print(i,'internal')
                import pdb
                #pdb.set_trace()
                m_int = np.logical_or(m_int, c != 0)
            #print(len(np.where(m_int!=0)[0]))
            #plt.figure()
            #plot_points(p,scatter=1)
            #p=p[~np.isnan(p[:,2]),:]
            #h=points_find_hull(p)
            #plot_poly(h,'bo')
            '''
            if not(((h[0,:] <= min(x)).any() or 
                    (h[0,:] >= max(x)).any() or 
                    (h[1,:] <= min(y)).any() or 
                    (h[1,:] >= max(y))).any()):
                print(i,'internal')
                m_int=np.logical_or(m_int,c==1)    
            '''
    return m_int
예제 #2
0
def remove_outliers2d(data,x=None,y=None,nsigma=3,fignum=None,name='',includenan=True):
    """remove outliers line by line by interpolation (along vertical lines).
    If fignum is set, plot comparison in corresponding figure."""

    ldata= data.copy()
    mask=np.apply_along_axis( remove_profile_outliers, axis=0, arr=ldata, 
        nsigma=nsigma ,includenan=includenan) #this modifies ldata and return a mask

    #these are used only to determine min and max.
    if x is None:
        x=np.arange(data.shape[1])
    if y is None:
        y=np.arange(data.shape[0])
              
    if fignum:
        #plot data before and after removal of outliers
        plt.figure(fignum)
        plt.clf()
        plt.suptitle('Effects of outliers removal - %s'%name).set_size('large')
        
        
        ax1=plt.subplot(221)
        plt.title('data')
        plt.xlabel('X (mm)')
        plt.ylabel('Y (mm)')
        axim=plt.imshow(data,interpolation='None',aspect='auto',
                        clim=span(ldata),extent=np.hstack([span(x),span(y)]))
        plt.colorbar()

        ax2=plt.subplot(222,sharex=ax1,sharey=ax1)
        plt.title('data outliers removed')
        plt.xlabel('X (mm)')
        plt.ylabel('Y (mm)')
        axim=plt.imshow(ldata,interpolation='None',aspect='auto',
                        clim=span(ldata),extent=np.hstack([span(x),span(y)]))
        plt.colorbar()

        ax3=plt.subplot(223,sharex=ax1,sharey=ax1)
        plt.title('outliers')
        outliers=ldata-data
        plt.imshow(outliers,interpolation='None',aspect='auto',
                        clim=span(ldata),extent=np.hstack([span(x),span(y)]))
        plt.colorbar()
        
        if mask.any():
            ax4=plt.subplot(224)
            plt.title('outliers height distribution')
            #plt.hist(outliers[mask].flatten(),bins=20,label='$\Delta$ correction',alpha=0.5)
            plt.hist(data[np.isfinite(data)].flatten(),bins=20,label='before',alpha=0.3,color='b')
            plt.hist(ldata[np.isfinite(ldata)].flatten(),bins=20,label='after',alpha=0.3,color='r')
            ax4b=ax4.twinx()
            ax4b.hist((data-ldata)[np.isfinite(data-ldata)].flatten(),bins=20,label='difference',alpha=0.3,color='r')
            plt.xlabel('Height (um)')
            plt.ylabel('N')
            plt.legend(loc=0)
        plt.show()
        
    return ldata
예제 #3
0
def get_stats(x, y=None, units=None):
    """"""
    if units is None:
        u = ["", ""]
    elif np.size(units) == 1:
        u = [units, units]
    else:
        u = units
    assert np.size(u) == 2

    stats = [
        'RMS:%3.3g %s' % (np.nanstd(y), u[1]),
        'PV_X:%3.3g %s, PV_Y:%3.3g %s' %
        (span(x, size=1), u[0], span(y, size=1), u[1])
    ]
    return stats
예제 #4
0
def ax_update2(ax):
    ax.set_autoscale_on(False)  # Otherwise, infinite loop

    # Get the number of points from the number of pixels in the window
    #dims = ax.axesPatch.get_window_extent().bounds

    # Get the range for the new area
    xstart, ystart, xdelta, ydelta = ax.viewLim.bounds
    xend = xstart + xdelta
    yend = ystart + ydelta

    # Update the image object with our new data and extent
    xl=[xstart,xend]
    yl=[ystart,yend]

    # Update the image object with our new data and extent
    im = ax.images[-1]
    cdata=mandel(xstart, xend, ystart, yend)
    im.set_data(cdata)
    crange=span(cdata)
    im.set_extent((xstart, xend, ystart, yend))
    if not (im.colorbar is None):
        fig=ax.get_figure()
        s = copy.copy( fig.canvas.toolbar._views )  
        #this store and restore is made to preserve the zooming history, 
        p = copy.copy( fig.canvas.toolbar._positions )
        im.colorbar.remove()
        plt.clim(crange)
        plt.colorbar()
        fig.canvas.toolbar._views = s
        fig.canvas.toolbar._positions = p  
예제 #5
0
def test_with_plot(outfolder=None):
    """Apply scale to a line plot, it should work the same as an image."""

    N = 100  #nr. of points in plot
    L = 20.  #length of x axis
    x = np.arange(N) * L / (N - 1)
    y = np.random.random(N)
    plt.clf()
    plt.plot(x, y)

    #fix pixsize: 300 um is 810 units of axis (pixels).
    #visible is set, scale should be immediately plotted.
    s = Scale(L / span(plt.xlim(), True), 'units of x',
              True)  #The entire axis span is L

    if outfolder is not None:
        plt.savefig(os.path.join(outfolder, 'test_with_plot_01.png'))

    #zoom 3x
    #plt.xlim(plt.xlim()[0]/3.,plt.xlim()[1]/3)
    #plt.ylim(plt.ylim()[0]/3.,plt.ylim()[1]/3)
    s.t.set_color('black')
    s.l.set_color('black')
    s.draw()

    plt.grid(1)

    if outfolder is not None:
        plt.savefig(os.path.join(outfolder, 'test_with_plot_02.png'))
    return s
예제 #6
0
 def printstats(self, label=None, fmt='%3.2g'):
     if label is not None:
         print(label)
     s = ("%s PV: " + fmt + ", rms: " +
          fmt) % (self.name, span(self.y, size=True), np.nanstd(self.y))
     print(s)
     return s
예제 #7
0
def xplot_sig_psd(x, y, label="", **kwargs):
    """plot signal, fft and psd on three panels.
    dft sets how the fft is plotted 
    'realim': real and im parts,
    'euler' argument and phase
    'both' uses two panels (four in total).
    """
    N = len(y)
    L = span(x, True)

    ax1 = plt.subplot(211)
    plt.title('Signal')
    plt.plot(x, y, **kwargs)
    ax1.set_xlabel('mm')
    plt.grid(1)

    ax4 = plt.subplot(212)
    plt.title('PSD')
    f, PSD = psd(x, y)
    plt.plot(f, PSD, label=label, **kwargs)
    plt.loglog()
    ax4.set_xlabel('mm^-1')
    plt.grid(1)
    plt.show()

    return ax1, ax4
예제 #8
0
def psd(x, y, retall=False, wfun=None, norm=1, rmsnorm=False):
    """return frequencies and PSD of a profile.
    
    If retall is set, also the phase is returned.
    PSD is squared FFT divided by step size. Profile is assumed real, so only positive freqs are used, doubling PSD values. Return value has ceil(N/2) elements (always odd).
    See `np.fft.rfftfreq` for details.
    wfun is a function that given the number of points return a vector with values for the window. Note that normalization is quite arbitrary, usually it's rescaled later with rmsnorm.
    2017/07/30 if rmsnorm is set True, PSD is normalized to (multiplied by) rms calculated from profile (must be same if no window applied). 
    2016/03/26 this psd i return to old normalizaiton "time-integral squared magnitude", multiplying by dx.
    """

    if wfun is None:
        win = np.ones(len(y))
    else:
        win = wfun(len(x))
    N = len(y)
    L = span(x, True)

    yfft = np.fft.rfft(
        y * win
    )  #note that rfft return exact values as fft (needs to be doubled after squaring amplitude)

    normfactor = normPSD(N, L, form=norm)
    if rmsnorm:  #normalize to rms of non windowed function. This is independent on 0 constant term,
        # but also alter its meaning
        normfactor = normfactor * np.nanstd(y)**2 / np.nanstd(y * win)**2

    psd = 2 * normfactor * np.abs(yfft)**2
    psd[0] = psd[0] / 2  #the first component is not doubled

    freqs = np.fft.rfftfreq(N, np.float(L) / (N - 1))
    if retall:
        return freqs, psd, np.angle(yfft)
    else:
        return freqs, psd
예제 #9
0
def test_HEW():
    #datafile=r'test\01_mandrel3_xscan_20140706.txt'
    print("uses Spizzichino's formula to predict PSF on sinusoidal ")
    x = np.linspace(0, 300., 100)
    y = np.cos(6 * np.pi * x / span(x, size=True)) / 60000.
    xout = np.linspace(-5, 5, 1000) / 206265.
    #x,y=np.genfromtxt(datafile,unpack=True,delimiter=',')
    #y=y-line(x,y)
    plt.figure('profile')
    plt.clf()
    plt.title('profile')
    plt.plot(x, y)
    plt.plot(x, line(x, y))
    plt.xlabel('Axial Position (mm)')
    plt.ylabel('Profile height (mm)')
    plt.figure('PSF')
    plt.clf()
    alpha = 89.79
    plt.title('PSF, alpha=%f6.2' % alpha)
    xout, yout = PSF_spizzichino(x, y, alpha=alpha, xout=xout)
    plt.xlabel('angular position around alpha (arcsec)')
    plt.ylabel('Intensity (a.u.)')
    plt.plot(xout * 206265., yout)
    plt.show()
    print('done!')
    return xout, yout
예제 #10
0
def external_roi_rect(points):
    """
    finds the smallest (straight to axis) rectangle containing all points.
    
    Points are passed as N x 2 array, returns two couples (x0,x1) (y0,y1)
    """
    return span(points, axis=0)
예제 #11
0
def FFTtransform(x, y):
    yfft = np.fft.rfft(
        y
    )  #note that rfft return exact values as fft (needs to be doubled after squaring amplitude)
    N = len(y)
    L = span(x, True)
    f = np.fft.rfftfreq(N, L / N)
    return f, yfft
예제 #12
0
def PSF_raimondiSR(x, y, alpha=0, xout=None, energy=1.):
    """Try to use theory from Raimondi and Spiga A&A2015 to calculate the PSF for single reflection,
    return a vector of same length as xout.
    alpha is incidence angle from normal in degrees, alpha= 90 - shell slope for tilt removed profiles.
    Tilt can be included in the profile, in that case alpha is left to 0
       (total slope must be <0 and alpha>0, this means that profile with tilt is expected to be <0).
    xout can set the output intervals in theta on the focal plane (from specular angle), if not set 512 points are used.
    Lambda is wavelength in keV.
    """
    """
    R0 e' necessario ma solo per normalizzare la PSF.  In realtaà se nella formula all'ultima riga sostituisci dr1 = L*sin(alpha) = L*R0/2f (usi la singola riflessione, giusto?) vedrai che R0 se ne va e non serve saperlo. f a questo punto sara' semplicemente la distanza alla quale si valuta il campo, non necessariamente la focale.
    
    dr1 = L*sin(alpha) = L*R0/2f
    
    """

    lambda_mm = 12.398425 / energy / 10**7

    if xout is None:
        lout = 1001
    else:
        lout = len(xout)
    L = span(x, size=True)
    deltax = L / (len(x))

    #calculate and remove slope as alpha. Profile after tilt removal is yl
    slope = line(x, y)
    yl = y - slope
    #adjust incidence angle to include the slope removed frorm profile leveling.
    # Increasing profile is positive slope angle:
    alpha = alpha * np.pi / 180 - np.arctan2(y[-1] - y[0], x[-1] - x[0])
    if alpha <= 0: raise ValueError

    thmax = lambda_mm / (2 * deltax * (np.pi / 2 - alpha))
    #xout is the array of theta for the output
    if xout is None:
        xout = np.linspace(alpha - thmax, alpha + thmax, lout)
    else:
        xout = xout + alpha

    dR1 = L * np.sin(alpha)  #L1
    R0 = 1  #F*np.tan(4*alpha)
    d20 = 1  #randdomly set things to 1
    z1 = 1

    PSF = 1 / 2 * F / (L * lambda_mm) * np.abs([
        np.sqrt(y / d20) * np.exp(-2 * np.pi * 1.j / lambda_mm *
                                  (d20 - z1 + x**2 / (2 * (S - x))))
    ].sum() * deltax)**2  #L1
    """ spizzichino original:
    scale=np.sqrt(2.)
    I=[np.abs((deltax/L*(np.exp(2*np.pi*1.j/lambda_mm*(x*(np.sin(alpha)-np.sin(theta))-scale*yl*(np.cos(alpha)+np.cos(theta)))))).sum())**2 for theta in xout]
    """
    """
    The above is equivalent to (iterate on all theta in xout):
    I[theta]=np.abs((deltax/L*(np.exp(2*np.pi*1.j/lambda_mm*(x*(np.sin(alpha)-np.sin(theta))-scale*yl*(np.cos(alpha)+np.cos(theta)))))).sum())**2
    """
    return xout - alpha, I
예제 #13
0
def PSF_spizzichino(x, y, alpha=0, xout=None, energy=1., level=True, HEW=True):
    """Try to use spizzichino theory as in PR notes to calculate Hthe PSF,
    return a vector of same length as xout.
    alpha is incidence angle from normal in degrees, alpha= 90 - shell slope for tilt removed profiles.
        Tilt can be included in the profile, in that case alpha is left to 0
       (total slope must be <0 and alpha>0, this means that profile with tilt is expected to be <0).
    xout can set the output intervals in theta on the focal plane (from specular angle), if not set 512 points are used.
    Lambda is wavelength in keV."""

    lambda_mm = 12.398425 / energy / 10**7

    if xout is None:
        lout = 1001
    else:
        lout = len(xout)
    L = span(x, size=True)
    deltax = L / (len(x))

    #calculate and remove slope as alpha. Profile tilt removed is yl
    if level:
        slope = line(x, y)
        yl = y - slope
        #adjust incidence angle to include the slope removed from profile leveling.
        # Increasing profile is positive slope angle:
        alpha = alpha * np.pi / 180 - np.arctan2(y[-1] - y[0], x[-1] - x[0])
    else:
        yl = y

    if alpha <= 0: raise ValueError

    thmax = lambda_mm / (2 * deltax * (np.pi / 2 - alpha))
    #xout is the array of theta for the output
    if xout is None:
        xout = np.linspace(alpha - thmax, alpha + thmax, lout)
    else:
        xout = xout + alpha

    scale = np.sqrt(2.)
    I = np.array([
        np.abs((deltax / L *
                (np.exp(2 * np.pi * 1.j / lambda_mm *
                        (x * (np.sin(alpha) - np.sin(theta)) - scale * yl *
                         (np.cos(alpha) + np.cos(theta)))))).sum())**2
        for theta in xout
    ])
    """
    The above is equivalent to (iterate on all theta in xout):
    I[theta]=np.abs((deltax/L*(np.exp(2*np.pi*1.j/lambda_mm*(x*(np.sin(alpha)-np.sin(theta))-scale*yl*(np.cos(alpha)+np.cos(theta)))))).sum())**2
    """

    #if HEW:
    #    calculate_HEW(xout-alpha,I,center=None,fraction=0.5)

    return xout - alpha, I
예제 #14
0
def make_sag(nx, ny):
    """ create surface with sag along y with peak-to-valley 1.
    Note that this is the range of data, not of the surface (i.e. if 
    number of points in y is even, the analytical minimum of the surface lies
    between the two central pixels and it is not included in data)"""

    ss = (np.arange(ny) - (ny - 1) / 2.)**2  #makes a parabola centered on 0
    ss = ss / span(ss, size=1) - np.min(ss)  #rescale height to 1
    sag = np.repeat(ss[np.newaxis, :], nx,
                    axis=0).T  #np.tile(ss,nx).reshape(ny,nx)

    return sag, np.arange(nx), np.arange(ny)
예제 #15
0
def test_make_Signal():  # test make_signal

    x = np.linspace(-0.5, 0.5, 100)
    plt.clf()

    print("X span: %s N: %i" % (span(x), len(x)))
    #plt.plot(*make_signal(2.,x,nwaves=3))

    #plt.plot(*make_signal(1.,x,nwaves=3,phase=np.pi/2),'o')
    plt.plot(*make_signal(1., nwaves=3, L=10, N=100), 'o')
    plt.plot(*make_signal(2., nwaves=3, L=[1, 11], N=100), 'x')
    plt.plot(*make_signal(2., nwaves=3, L=[1, 11], N=100, phase=np.pi / 2))
    plt.plot(*make_signal(2., x, nwaves=3, L=100, phase=np.pi / 2))
예제 #16
0
def test_psd_normalization(x, y, wfun=None, norm=1, **kwargs):
    """Calculate PSD with a given normalization and
    compare its integral over frequency and sum to
    rms square and standard deviation (they differ for rms including also offset, while stddev being referred to mean."""

    f, p = psd(x, y, wfun=wfun, norm=norm, **kwargs)

    print("== Quantities calculated from profile ==")
    print("Profile Height PV %6.3g (min: %6.3g, max: %6.3g)" %
          (np.nanmax(y) - np.nanmin(y), np.nanmin(y), np.nanmax(y)))
    print("Profile Height avg.: ", np.nanmean(y))
    print("devstd**2=", np.std(y)**2, '(devstd=%f5.3)' % np.std(y))
    print("rms**2=", (y**2 / len(x)).sum())  #, '(rms=%f5.3)'%np.std(y)
    print("\n== Quantities calculated from PSD ==")
    print("sum of PSD is ", p[1:].sum())
    print("integral of PSD (as sum*deltaf) is ",
          p[1:].sum() / span(x, 1))  #span(x,size=1)=1/L
    print("integral trapz: ", np.trapz(p[1:], f[1:]))
    print("psd[0]*deltaf=%f (integral including:%f)" %
          (p[0] * f[1], p.sum() / span(x, 1)))
    print("#--------\n")

    return f, p
예제 #17
0
def radial_slice(x,y,angle,xyc,plot=False,
                    *args,**kwargs):
    """Gives extreme points of a segment passing by xc, yc with slope angle in radians inside the span of points x and y.
    works in all four quadrants."""
    
    if len(np.shape(angle))==0:
        angle = [angle]

    xx = x - xyc[0]
    yy = y - xyc[1]
    xs = span(xx)
    ys = span(yy)
    
    xxs = []
    for a in angle:
        cx = np.cos(a)
        cy = np.sin(a)

        t = xs/cx #parameter that brings to the x limits
        t2 = ys/cy #parameter that brings to the y limits
        # they are one negative and one positive if center in rectangle.
        tmin = max(min(t),min(t2))
        tmax = min(max(t),max(t2))
        p1 = (xyc[0]+tmin*cx,xyc[1]+tmin*cy)
        p2 = (xyc[0]+tmax*cx,xyc[1]+tmax*cy)
        xxs.append((p1,p2))
        
        if plot:
            l = plt.plot(*zip(p1,p2),*args,**kwargs)
            c = l[-1].get_color()
            plt.plot(*p1,'x',color = c)
            plt.plot(*p2,'^', color = c)
            #plt.arrow(*p1,*(np.array(p2)-np.array(p1)),*args,**kwargs)
    plt.show()
        
    return np.array(xxs)
예제 #18
0
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
예제 #19
0
def line(x, y=None):
    """return line through end points of x,y.
	x and y are vectors, can be of different length (e.g. y can be a 2-elements vector).
    If only one vector is provided, it is assumend as equally spaced points.
"""
    x = np.array(x)
    if y is None:
        y = x
        x = np.arange(len(y))
    y = np.array(y)

    #account for nan
    sel = ~np.isnan(y)
    if sel.any():
        y0 = [y[sel][0], y[sel][-1]]
        if len(x) == len(y):
            x0 = x[sel]
        else:
            x0 = x
        L = span(x0, size=1)
        return (x - x0[0]) * (y0[-1] - y0[0]) / L + y0[0]
    else:
        return y
예제 #20
0
def psd2d(data, x, y, wfun=None, norm=1, rmsnorm=False):
        """Calculate the 2d psd. return freq and psd.
        
        doesnt work with nan.
        use 2d function for psd np.fft.rfft2 for efficiency and mimics
            what done in pySurf.psd.psd
        norm defines the normalization, see function psd.normPSD.
        2017/01/11 broken interface from (x,y,data..),
        added check to correct on the base of sizes."""
        #2017/08/01 complete refactoring, this was internal _psd2d,
        # now is made analogous of 1d pySurf.psd.psd
        # The previous psd2d was including a lot of plotting and output,
        #    it was renamed in plot_psd2d

        #attention, normalization doesn't really work with
        # window, the rms is the rms of the windowed function.
        
        #assert data.shape[0]==data.shape[1]
        if wfun is None:
            win=np.ones(data.shape[0])[:,None]
        else:
            win=wfun(data.shape[0])[:,None]
        N=data.shape[0]
        L=span(y,True)
        yfft=np.fft.rfft2(data*win,axes=[0])

        normfactor=normPSD(N,L,form=norm)
        if rmsnorm:  #normalize to rms of non windowed function
            normfactor=normfactor*np.nanstd(data,axis=0)**2/np.nanstd(data*win,axis=0)**2

        psd=2*normfactor*(np.abs(yfft))**2
        psd[0,:]=psd[0,:]/2.

        freqs = np.fft.rfftfreq(N,np.float(L)/(N-1))

        return freqs,psd
예제 #21
0
def trioptimize(d1,
                d2,
                fom,
                testvals=None,
                rois=None,
                outfile=None,
                noplot=False,
                dis=True):
    """run optimizations using scale_fit2 over a set of cases
    defined by the values in matching lists of testvals (array of scaling test values) 
    and rois ([[xmin,xmax],[ymin,ymax]]). 
    
    Returns a pandas data structure with parameters and best scaling values for each case,
        with fields ['tbest','testval','roi','fom_roi'].
    
    Plot 
 
    d1 and d2 are Data2D objects.
    testvals: list of vectors to use as test values for each of the ROI
    rois:    list of rois (same len as testvals), in form [[xmin,xmax],[ymin,ymax]], 
        set to None to use for range.
    outfile:
    noplot:
    dis:
    """

    if outfile is not None:
        outname = os.path.basename(outfile)
        outfolder = os.path.dirname(outfile)
    else:
        outname = None

    plt.close('all')
    res = pd.DataFrame(
        index=['tbest', 'testval', 'roi', 'fom_roi', 'fom_initial'
               ]).transpose()

    if any_is_none(testvals):
        if fom != fom_rms:
            raise ValueError(
                'analytical fit (without testval) supported only for fom_rms')
        if testvals is None: testvals = [None] * len(rois)

    #Minimizes on each subaperture
    for i, (roi, testval) in enumerate(zip(rois, testvals)):
        name = 'crop%02i' % (
            i + 1) if outname is None else outname + '_crop%02i' % (i + 1)
        #if dis print optimization parameters
        if dis:
            print("\n\n\n===   CASE %i: %s  ===\n" % (i + 1, name))
            if roi is None:
                print('FULL APERTURE')
            else:
                print("CROP: [%.2f:%.2f] [%.2f:%.2f]" % tuple(roi[0] + roi[1]))
            print("TEST RANGE:", span(testval))
            dtest = (d1 - d2).crop(*roi) if roi is not None else d1 - d2
            fom0 = fom(*dtest())
            print("INITIAL FOM:", fom0)

        #do optimization, plot bestfit on ROI, displaying plot if dis is True
        s = scale_fit2(
            d1,
            d2,
            testval,
            dis=dis
            if roi is not None else False,  #it will plot later if no roi 
            fom=fom,
            outfile='' if outname is None else fn_add_subfix(
                outfile, '_crop%02i' % (i + 1)),
            roi=roi,
            crop=dis)  #if dis is set, plot roi, otherwise skip

        #calculate and store best fit
        ftest = fom(*((d1 - d2 * s).crop(*roi))()) if roi is not None else fom(
            *(d1 - d2 * s)())
        b = pd.Series(
            [s, testval, roi, ftest, fom0],
            index=['tbest', 'testval', 'roi', 'fom_roi',
                   'fom_initial'],  #fom_initial added 04/02
            name=name)
        res = res.append(b)

        #plot best fit case full range unless noplot
        if not noplot:
            plt.close('all')
            comp2(d1, d2 * s, roi=roi)  # plots entire area with rectangle
            dtest = (d1 - d2 * s)
            plt.tight_layout(rect=[0, 0.03, 1, 0.95])
            plt.suptitle('best factor:%6.3f, FOM surf:%6.3f' %
                         (s, fom(*dtest())))
            if outname:
                plt.savefig(
                    fn_add_subfix(outfile, '_croproi_%02i' % (i + 1), '.png'))
            if dis: display(plt.gcf())
        if dis: print("BEST SCALE: %.3f" % s, " FOM:", ftest)

    if dis: print("\n===\nSUMMARY:")
    #a=pd.DataFrame(index=['tbest','testval','roi','fom_roi']).transpose()
    for roi, r in zip(rois, res.iterrows()):
        if dis:
            if roi is None:
                print('FULL APERTURE--> BEST SCALE: ', r[1]['tbest'])
            else:
                #pdb.set_trace()
                #not sure why this is needed, but r[0] is the dataseries name, r[1] the dataseries
                print("CROP: [%.2f:%.2f] [%.2f:%.2f]" % tuple(roi[0] + roi[1]),
                      "--> BEST SCALE: ", r[1]['tbest'])
    print("=======================")

    return res
예제 #22
0
def plotFEA(FEAfile, FEAreader, datafile=None, outname=None, markers=None):
    """ read FEA and resample/rebin both points and FEA on the grid defined by steps, subtract gravity from pts 
    and plot and returns the corrected points. Simulation and data are also plotted if valid. 
    If datafile is not passed only simulation data are plotted and returned.
    FEA reader is a function that accept a single argument FEAfile and return an array of points describing 
    changes in shape (x,y,dz)."""
    rebin = False

    fpts = FEAreader(FEAfile)
    if trans is not None:
        fpts = trans(fpts)
    if datafile is not None:
        pts = get_points(datafile, delimiter=' ')

        if rebin:
            pts = rebin_points(pts, steps=steps)
            fp = rebin_points(fpts, steps=steps)
        else:
            xl, yl = span(pts, axis=0)[:2, :]
            xg = np.arange(xl[0], xl[1], steps[0])
            yg = np.arange(yl[0], yl[1], steps[1])
            pts = resample_grid(pts, xg, yg)
            fp = resample_grid(fpts, xg, yg)

        pts0 = subtract_points(pts, fp)
    else:
        pts0 = pts
        pts = None

    #diagnostic plots for gravity subtraction
    if pts is not None:
        plt.figure('pts0')  #corrected
        plt.clf()
        plot_points(pts0, scatter=1, aspect='equal')
        plt.title('points from file')
        if markers is not None:
            plt.plot(markers[:, 0], markers[:, 1], '+w', label='support')

    if datafile is not None:
        plt.figure('pts')  #data
        plt.clf()
        plot_points(pts, scatter=1, aspect='equal')
        plt.title('resampled and gravity corrected')
        plt.savefig(fn_add_subfix(outname, '_corrected', '.png'))
        if markers is not None:
            plt.plot(markers[:, 0], markers[:, 1], '+w', label='support')

    plt.figure('fp')  #simulation
    plt.clf()
    plot_points(fp, scatter=1, aspect='equal')
    plt.title('gravity effect from FEA')
    if markers is not None:
        plt.plot(markers[:, 0], markers[:, 1], '+',
                 label='support')  #here x and y inverted
    plt.savefig(fn_add_subfix(outname, '_FEA', '.png'))

    if outname is not None:
        save_points(pts0, fn_add_subfix(outname, '', '.dat'))
        save_points(pts0, fn_add_subfix(outname, '_matrix', '.dat'), matrix=1)
        save_points(pts0, fn_add_subfix(outname, '_matrix', '.fits'), matrix=1)

    return pts0
예제 #23
0
def plot_transform(f,
                   yfft,
                   label="",
                   euler=False,
                   units=None,
                   includezerofreq=False,
                   **kwargs):
    """units is a 2 element vector."""
    #pdb.set_trace()
    ax3 = plt.gca()
    ##PLOT TRANSFORM AS EULER REPRESENTATION
    unitstr = psd_units(units)

    if not includezerofreq:
        if f[0] == 0:
            f = f[1:]
            yfft = yfft[1:, ...]

    if euler:
        plt.title('DFT - Module and phase')
        plt.plot(f, np.abs(yfft), label=label, **kwargs)
        #plt.loglog()
        ax3.legend(loc=2)
        #string for x is set to '' as default:
        plt.xlabel('Freq (' + (unitstr[0] if unitstr[0] else '[X]') + '$^-1$)')
        plt.ylabel('Module' + ((' (' + unitstr[1]) if unitstr[1] else '[Y]') +
                   '$^2$)')

        ax3b = ax3.twinx()
        ax3.twin = ax3b
        ax3b.plot(f,
                  np.angle(yfft) / np.pi,
                  '--',
                  label=label + ' Phase',
                  **kwargs)
        ax3b.set_ylabel('Phase /$\pi$')
        ax3b.set_ylim(-1., 1.)
        plt.grid(1)
        ax3b.legend(loc=1)

    ##PLOT TRANSFORM AS COMPLEX NUMBER
    else:
        #pdb.set_trace()
        plt.title('DFT - Real and imaginary parts')
        ax3.plot(f, np.real(yfft), label=label + ' Re', **kwargs)
        #plt.loglog()
        s = span(np.real(yfft))
        plt.ylim([s[0], s[1]])  # needed to expland scale if very small
        #ax3.set_xlabel(unitstr[0]+'$^-1$')
        #string for x is set to '' as default:
        plt.xlabel('Freq. (' + (unitstr[0] if unitstr[0] else '[X]') +
                   '$^-1$)')
        ax3.set_ylabel('Re')
        #for tl in ax2.get_yticklabels():
        #tl.set_color('b')
        ax3.legend(loc=2)

        ax2b = ax3.twinx()
        ax2b.plot(f, np.imag(yfft), '--', label=label + ' Im', **kwargs)
        s = span(np.imag(yfft))
        plt.ylim([s[0], s[1]])  # needed to expland scale if very small
        ax2b.set_ylabel('Im')
        #for tl in ax2b.get_yticklabels():
        #tl.set_color('r')
        plt.grid(True)
        ax2b.legend(loc=1)
        ax3.twin = ax2b
    plt.tight_layout
예제 #24
0
def compare_images(datalist,
                   x=None,
                   y=None,
                   fignum=None,
                   titles=None,
                   vmin=None,
                   vmax=None,
                   commonscale=False,
                   axis=0,
                   axmax=0,
                   *args,
                   **kwargs):
    """return a generator that plots n images in a list in subplots with shared
    zoom and axes. datalist is a list of data in format (data, x, y).
    x and y provide plot range (temporarily, ideally want to be able to 
    plot same scale).
    fignum window where to plot, if fignnum is 0 current figure is cleared,
    if None new figure is created.
    axis defines the axis with larger number of plots (default ncols >= nrows)
    axmax maximum nr of plots along shorter dim.
    """
    #modified again 2018/06/05 to accept list of data,x,y triplets. x and y are
    # accepted as range.
    # old docstring was:
    # return a generator that plots n images in a list in subplots with shared
    # zoom and axes. datalist is a list of 2d data on same x and y.
    # fignum window where to plot, if fignnum is 0 current figure is cleared,
    # if None new figure is created.

    # this was changed a couple of times in interface, for example in passing
    # ((data,x,y),...) rather than (data1,data2),x,y
    # it can be tricky in a general way if data don't have all same size,
    # at the moment it is assumed they have.
    # in any case x and y are used only to generate the extent,
    # that is then adapted to the size of data.

    gridsize = find_grid_size(len(datalist), axmax)
    if axis == 1: gridsize = gridsize[::-1]

    fig = fignumber(fignum)

    plt.clf()
    ax = None

    # this is to set scale if not fixed
    d1std = [np.nanstd(data[0]) for data in datalist]
    std = min(d1std)

    for i, d in enumerate(datalist):
        """adjust to possible input formats"""
        data, x, y = d
        if x is None:
            x = np.arange(data.shape[1])
        if y is None:
            y = np.arange(data.shape[0])
        ax = plt.subplot(gridsize[0], gridsize[1], i + 1, sharex=ax, sharey=ax)
        if titles is not None:
            print("titles is not none, it is ", titles)
            plt.title(titles[i])
        # plt.xlabel('X (mm)')
        # plt.ylabel('Y (mm)')
        s = (std if commonscale else d1std[i])
        d1mean = np.nanmean(data)
        aspect = kwargs.pop('aspect', None)
        axim = plt.imshow(data,
                          extent=np.hstack([span(x), span(y)]),
                          interpolation='none',
                          aspect=aspect,
                          vmin=kwargs.get('vmin', d1mean - s),
                          vmax=kwargs.get('vmax', d1mean + s),
                          *args,
                          **kwargs)
        plt.colorbar()
        yield ax
예제 #25
0
def psd2d_analysis(wdata,x,y,title=None,wfun=None,vrange=None,
    rmsrange=None,prange=None,fignum=5,rmsthr=None, 
    aspect='auto', ax2f=None, units=None,outname=None,norm=1,rmsnorm=True):
    """ Calculates 2D PSD as image obtained combining all profile PSDS calculated along vertical slices of data. Resulting image has size 
    If title is provided rms slice power is also calculated and plotted on three panels with figure and PSD.
    
    Return PSD as PSD2D object. 

    uses plot_rms_power(f,p,rmsrange=None) to calculate rms power.
    fignum window where to plot, if fignnum is 0 current figure is cleared,
    if None new figure is created. Default to figure 5.
    rmsrange is one or a list of frequency ranges for plotting integrated rms. Can contain None to use max or min.
    If axf2 is set to boolean or array of boolean, plot slice rms for the frequencies
    associated to rmsrange on second axis. rmsrange must be set accordingly (same number of elements).
    
    rmsthr sets a threshold for data inclusion. If rms is above the value, the line is considered to contain invalid data and is removed from output PSD.
    This makes it easy to average the returned PSDs.
    Corresponding data are still visualized in central panel, but are marked with a red cross at top of y axes.
    If multiple rms range intervals are provided, line is removed if any of them is over the threshold, but this might change in future, e.g. TODO: make it possible to add vector threshold with as many elements as rms range intervals.

    Set outname to empty string to plot without generating output.

    typical values:
    rmsrange=[[None,0.1],[0.1,0.2],[0.2,1],[1,None]]  #list of frequency intervals for rms
    ax2f=[0,1,1,0,0]             #   axis where to plot rms corresponding to intervals in rmsrange: 1 right, 0 left
    wfun  = np.hanning           #   type of windows for fourier transform
    units = ("mm","mm","$\mu$m") #   units of surface data from which PSD is calculated

    vrange_surf=([-0.5,0.5])  #color scale of surface map
    vrange_leg=([-0.05,0.05])   #color scale of legendre removed map
    prange=np.array((1e-8,1.e-1))#np.array((5e-8,1.e-5))  #color scale of 2d psd plot

    fs,ps=psd2d_analysis(levellegendre(y,wdata,2),x,y,outname="",wfun=np.hanning,
    rmsrange=rmsrange,prange=prange,ax2f=ax2f,units=units)
    """
    #2018/04/05
    # -critical renaming of plot_psd2d(wdata,x,y..) -> psd2d_analysis
    # and _plot_psd2d(f,p,x) -> plot_psd2d consistently with other routines.
    # -added title to determine if generating plot, with the intent of replacing outname.
    plt.pause(1)
    #print('cane',fignum) 
    if outname is not None:  #handle backcompatibility
        print ('psd2d_analysis WARNING: `title` replaced `outname` and output figure will be no more generated.'+
            'OUTNAME will be removed in next version, use title and save the plot after returning from routine.')
        if title is not None:
            print('outname should be not used together with title, it will be ignored.')
        else:
            title=outname
    
    if vrange is not None:
        if prange is None:
            print("""WARNING:  older versions of psd2d use vrange as range of psdvalue.
                    In updated version prange is range of psd and vrange is range for surface
                    plots. Update your code.""")

    #check compatibility with old interface
    if len(wdata.shape)==1:
        if len(y.shape)==2:
            print("WARNING: your code calling psd2d uses old call")
            print("psd2d(x,y,data), automaticly adjusted, but")
            print("update IMMEDIATELY your code to call")
            print("psd2d(data,x,y)")
            x,y,wdata=wdata,x,y

    f, p = psd2d(wdata, x, y, wfun=wfun, norm=norm, rmsnorm=rmsnorm)  # calculate PSD 2D
       
    # GENERATE OUTPUT
    if title is not None:

        if np.size(units)==1:
            units=np.repeat(units,3)

        if prange is None:
            if f[0] == 0:
                prange=span(p[1:,:])
            else:
                prange=span(p)
                if prange[0]<1e-20:  #arbitrary small value
                    print("WARNING: low limit detected in prange, can cause problems with log color scale.")
        if vrange is None:
            vrange=span(wdata)

        #plot surface map, who knows why on figure 5       
        fig=fignumber(fignum)
        #pdb.set_trace()
        #
        plt.clf()
        maximize()
        plt.draw()

        plt.suptitle(title)

        ################
        #plot Surface
        ax1=plt.subplot(311)
        plot_data(wdata,x,y,aspect=aspect,vmin=vrange[0],vmax=vrange[1],units=units,title='Surface',stats=True)
        plt.xlabel(None)
        plt.grid(1)

        ################
        #plot 2D PSD
        ax2=plt.subplot(312,sharex=ax1)
        plot_psd2d(f,p,x,prange=prange,units=units)
        if rmsrange is not None:      #plot horizontal lines to mark frequency ranges for rms extraction,
        #rms is tranformed to 2D array
            if len(np.array(rmsrange).shape)==1:  #if only one interval, make it 2D anyway
                rmsrange=[rmsrange]
            rmsrange=np.array(rmsrange)
            for fr in np.array(rmsrange):  #I want fr to be array type, even if I don't care about rmsrange this does the job
                ax2.hlines(fr[fr != None],*((span(x)-x.mean())*1.1+x.mean()))
        ax2.set_xlabel("")
        plt.xlabel(None)
        #plt.subplots_adjust(top=0.85)

        ################
        #plot rms slice
        ax3=plt.subplot(313,sharex=ax1)
        if f[0]==0: #ignore component of 0 frequency in rms calculation if present
            ff,pp=f[1:],p[1:]
        else:
            ff,pp=f,p

        rms=plot_rms_power(ff,pp,x,rmsrange=rmsrange,ax2f=ax2f,units=units)
        #pdb.set_trace()
        mask=np.isfinite(rms) #True if good. it is an array
        if rmsthr is not None:
            mask = mask & (rms  < rmsthr)
            ax3.hlines(rmsthr,*ax2.get_xlim()) #plot markers on rms chart
            ax2.plot(x[~mask],np.repeat(ax2.get_ylim()[1],len(x[~mask])),'rx') #plot markers on psd2d chart
        
        #pdb.set_trace()
        #questa era qui, ma dava errore perche' mask e' lineare
        #mask = np.all(mask,axis =0) # if any of mask is False -> False
        p[:,~mask]=np.nan
        ax3.grid(1)
        #plt.tight_layout(rect=(0, 0.03, 1, 0.95) if title else (0, 0, 1, 1))
        
        # replaced with more evolved interactive resize:
        #  plt.colorbar().remove() #dirty trick to adjust size to other panels
        def resize(event):
            box1 = ax1.get_position()
            box2 = ax2.get_position()
            box3 = ax3.get_position()
            ax2.set_position([box1.x0, box2.y0, box1.width , box2.height])
            ax2.set_adjustable("box",share=True)
            ax3.set_position([box1.x0, box3.y0, box1.width , box3.height])
            ax3.set_adjustable("box",share=True)

        cid = fig.canvas.mpl_connect('draw_event', resize)
        cid2 = fig.canvas.mpl_connect('resize_event', resize)

        resize(None)

        #plt.tight_layout()

        if outname:    #kept for compatibility, will be removed in next version
            plt.savefig(fn_add_subfix(outname,'_2dpsd','.png'))

    return f,p
예제 #26
0
def xdiff_images(data1,
                 data2,
                 x=None,
                 y=None,
                 fignum=None,
                 titles=None,
                 vmin=None,
                 vmax=None,
                 commonscale=False,
                 direction=0,
                 *args,
                 **kwargs):
    """plots two data sets with common axis and their difference. Return the three axis.
    Colorbars are formatted to be same height as plot.
    """

    fig = fignumber(fignum)

    plt.clf()
    ax = None

    aspect = kwargs.pop('aspect', 'auto')
    #this is to set scale if not fixed
    d1std = [np.nanstd(data) for data in (data1, data2)]
    std = min(d1std)

    if x is None:
        x = np.arange(data1.shape[1])
    if y is None:
        y = np.arange(data1.shape[0])

    ax1 = plt.subplot(131, sharex=ax, sharey=ax)

    s = (std if commonscale else d1std[0])
    d1mean = np.nanmean(data1)
    axim = plt.imshow(data1,
                      extent=np.hstack([span(x), span(y)]),
                      interpolation='None',
                      aspect=aspect,
                      vmin=kwargs.get('vmin', d1mean - s),
                      vmax=kwargs.get('vmax', d1mean + s),
                      *args,
                      **kwargs)
    plt.colorbar(fraction=0.046, pad=0.04)

    ax2 = plt.subplot(132, sharex=ax, sharey=ax)

    s = (std if commonscale else d1std[1])
    d2mean = np.nanmean(data2)
    axim = plt.imshow(data2,
                      extent=np.hstack([span(x), span(y)]),
                      interpolation='None',
                      aspect=aspect,
                      vmin=kwargs.get('vmin', d2mean - s),
                      vmax=kwargs.get('vmax', d2mean + s),
                      *args,
                      **kwargs)
    plt.colorbar(fraction=0.046, pad=0.04)

    ax3 = plt.subplot(133, sharex=ax, sharey=ax)
    plt.title('Difference (2-1)')
    diff = data2 - data1
    axim = plt.imshow(diff,
                      extent=np.hstack([span(x), span(y)]),
                      interpolation='None',
                      aspect=aspect,
                      *args,
                      **kwargs)
    plt.colorbar(fraction=0.046, pad=0.04)

    axes = [ax1, ax2, ax3]
    if titles is not None:
        for ax, tit in zip(axes, titles):
            if tit is not None:
                ax.set_title(tit)

    return axes
예제 #27
0
    def __init__(self,
                 x=None,
                 y=None,
                 file=None,
                 reader=None,
                 units=None,
                 name=None,
                 *args,
                 **kwargs):
        """can be initialized with data; x,y; file; file, x
        if x is provided, they override x from data if matching number of elements, 
           or used as range if two element (error is raised in case of ambiguity)."""

        #from pySurf.readers.instrumentReader import reader_dic
        from pyProfile.profile import register_profile

        #pdb.set_trace()

        if isinstance(y, str):
            print('first argument is string, use it as filename')
            file = y
            y = None
        else:
            y = np.array(y)  #onvert to array if not
        #pdb.set_trace()
        self.file = file  #initialized to None if not provided
        if file is not None:
            assert y is None
            # passed file AND xrange, overrides x because only range matters.
            #store in xrange values for x if were passed
            xrange = span(x) if x is not None else None
            #pdb.set_trace()

            if reader is not None:
                raise NotImplementedError(
                    "readers are not implemented yet for profiles," +
                    "\tPass data or read from two column text file in compatible format."
                )

            self.load(file, *args, **kwargs)
            """
            if reader is None:
                reader=auto_reader(file) #returns a reader
            """
            from pyProfile.profile import load_profile
            x, y = load_profile(
                file, *args, **kwargs
            )  #calling without arguments skips register, however skips also reader argumnets, temporarily arranged with pop in read_data to strip all arguments for
            #register data and pass the rest to reader
            #pdb.set_trace()
            #TODO: Cleanup this part and compare with pySurf. Consider centering
            # of axis coordinates as in grid example.
            if np.size(xrange) == np.size(y):
                # x is compatible with data size
                if np.size(xrange) == 2:
                    print(
                        'WARNING: You passed both data and x, with size 2. There may be some ambiguity in how coordinates are handled'
                    )
                self.x = xrange
            elif np.size(xrange) == 2:
                #here it must be intended as a range. Should check also interval centerings.
                #it was considered somewhere in pySurf.
                x = np.linspace(*xrange, np.size(y))
            elif xrange is not None:
                print(
                    "wrong number of elements for x (must be 2 or xsize_data), it is instead",
                    np.size(xrange))
                raise ValueError

            # set self.header to file header if implemented in reader, otherwise set to empty string""
            #questo dovrebbe sempre fallire
            try:
                #kwargs['header']=True
                self.header = reader(file, header=True, *args, **kwargs)
            except TypeError:  #unexpected keyword if header is not implemented
                self.header = ""
                #raise
        else:
            if y is not None:
                if len(y.shape) != 1:
                    #pdb.set_trace()
                    print(
                        'WARNING: data are not uniidimensional, results can be unpredictable!'
                    )
                if x is None:
                    x = np.arange(np.size(y))

            #if data is not None:
                x, y = register_profile(
                    x, y, *args,
                    **kwargs)  # se load_profile calls register, this
                #goes indented.

        self.x, self.y = x, y

        if np.size(units) == 1:
            units = [units, units]
        self.units = units
        if name is not None:
            self.name = name
        elif file is not None:
            self.name = os.path.basename(file)
        else:
            self.name = ""
예제 #28
0
    def __init__(
        self,
        data=None,
        x=None,
        y=None,
        file=None,
        reader=None,
        units=None,
        name=None,
        *args,
        **kwargs
    ):
        """
        A class for 2D data with coordinates and their analysis.
        
        Can be initialized with data | data, x, y | file | file, x, y.
        if x and y are coordinates if match number of elements, 
            or used as range if two element. 
        If provided together with file, they override x and y 
            read from file.
        
        Function methods return a copy with new values and don't alter original
           object. Reassign to variable to use as modifier:
           e.g. a=a.level( ... )

        Args:
            data (2D array or string): 2D data or file name (suitable reader must 
            provided).
            
            x, y (array): coordinates or ranges.
            
            file (str): alternative way to provide a data file.
            
            units (str array): 3-element array with units symbols for `x`, `y`, `data`  
            
            reader (function): reader function (see `pySurf.readers.instrumentReader`).
            
            name (str): sets the name of created object.  

            *args, **kwargs: optional arguments for `pySurf.data2D.register_data`. 
        """

        # from pySurf.readers.instrumentReader import reader_dic

        # pdb.set_trace()

        if isinstance(data, str):
            print("first argument is string, use it as filename")
            file = data
            data = None
        # pdb.set_trace()
        self.file = file  # initialized to None if not provided
        if file is not None:
            assert data is None
            # store in xrange values for x if were passed
            xrange = span(x) if x is not None else None
            yrange = span(y) if y is not None else None

            # pdb.set_trace()
            if reader is None:
                reader = auto_reader(file)  # returns a reader
            # calling without arguments skips register, however skips also reader argumnets, temporarily arranged with pop in read_data to strip all arguments for
            data, x, y = read_data(file, reader, *args, **kwargs)
            # register data and pass the rest to reader
            # pdb.set_trace()

            if np.size(x) == data.shape[1]:
                self.x = x
            elif np.size(x) == 2:
                # y and yrange are identical
                print("WARNING: 2 element array provided for X, uses as range.")
                x = np.linspace(*xrange, data.shape[1])
            elif xrange is not None:
                print(
                    "wrong number of elements for x (must be 2 or xsize_data [%i]), it is instead %i"
                    % (np.size(data)[1], np.size(x))
                )
                raise ValueError

            if np.size(y) == data.shape[0]:
                self.y = y
            elif np.size(y) == 2:
                # y and yrange are identical
                print("WARNING: 2 element array provided for Y, uses as range.")
                x = np.linspace(*yrange, data.shape[0])
            elif yrange is not None:
                print(
                    "wrong number of elements for y (must be 2 or ysize_data [%i]), it is instead %i"
                    % (np.size(data)[0], np.size(y))
                )
                raise ValueError

            # set self.header to file header if implemented in reader, otherwise set to empty string""
            try:
                # kwargs['header']=True
                # self.header=reader(file,header=True,*args,**kwargs)
                self.header = reader(file, header=True, *args, **kwargs)
            except TypeError:  # unexpected keyword if header is not implemented
                self.header = ""
                # raise
        else:
            if data is not None:
                if len(data.shape) != 2:
                    # pdb.set_trace()
                    print(
                        "WARNING: data are not bidimensional, results can be unpredictable!"
                    )
                if x is None:
                    x = np.arange(data.shape[1])
                if y is None:
                    y = np.arange(data.shape[0])

                # if data is not None:
                # se read_data calls register, this
                data, x, y = register_data(data, x, y, *args, **kwargs)
                # goes indented.

        self.data, self.x, self.y = data, x, y

        self.units = units
        if name is not None:
            self.name = name
        elif file is not None:
            self.name = os.path.basename(file)
        else:
            self.name = ""
예제 #29
0
    def on_lims_change(ax):
        nsigma = 1.5

        ax.set_autoscale_on(False)
        #ax.figure.canvas.draw_idle(self)
        xl = ax.xaxis.get_view_interval(
        )  #range of plot in data coordinates, sorted lr
        yl = ax.yaxis.get_view_interval()  #sorted bottom top
        #print xl,yl

        im = ax.images[-1]
        imdata = im.get_array(
        )  #.filled(np.nan)  #this helps when a masked array is returned, for some reason it doesn't work
        dims = imdata.shape  #number of pixels
        #print dims
        extent = im.get_extent()  #this is the range for axis of  full data.
        #ixl=np.interp(xl,extent[0:2],[0,dims[1]])  #pixel indices for plotted data
        #iyl=np.interp(yl,extent[2:],[0,dims[0]])
        ixl = interp1d(extent[0:2], [0, dims[1]],
                       assume_sorted=False,
                       bounds_error=False)(xl).astype(
                           int)  #pixel indices for plotted data
        iyl = interp1d(extent[2:], [0, dims[0]],
                       assume_sorted=False,
                       bounds_error=False)(yl).astype(int)
        #prevent empty array
        if np.abs(ixl[1] - ixl[0]) < 1:
            ixl[1] = ixl[0] + 1
        if np.abs(iyl[1] - iyl[0]) < 1:
            iyl[1] = iyl[0] + 1
        #print ixl[0],ixl[1],iyl[0],iyl[1]
        cdata = imdata[ixl[0]:ixl[1], iyl[0]:iyl[1]]
        #crange=np.nanmean(cdata)+[-np.nanstd(cdata),np.nanstd(cdata)] #this is a more sensitive view.
        if nsigma:
            crange = np.nanmean(cdata) + np.nanstd(cdata) * np.array(
                [-1., 1.]) * nsigma
        else:
            crange = span(cdata)
        #print ax.__repr__(),cdata

        #make a copy of zoom history
        fig = ax.figure
        s = copy.copy(fig.canvas.toolbar._views)
        p = copy.copy(fig.canvas.toolbar._positions)

        title = "min:%4.1f max:%4.1f rms:%4.3f" % (
            np.nanmin(cdata), np.nanmax(cdata), np.nanstd(cdata))
        #print crange
        ax.set_title(title)
        if not (im.colorbar is None):
            im.colorbar.remove()
        #if not (title is None):
        #    if title=="":
        #these commands resets colorbar
        plt.colorbar()
        plt.clim(crange)

        #restore zoom history
        fig.canvas.toolbar._views = s
        fig.canvas.toolbar._positions = p

        ax.figure.canvas.draw_idle()
예제 #30
0
def scale_fit2(d1,
               d2,
               testval=None,
               fom=fom_rms,
               outfile='',
               roi=None,
               crop=False,
               dis=True):
    """d1 and d2 are Data2D objects. Returns value for scaling tbest of d2
    that minimizes fom(d1-d2*tbest). e.g. fom = rms of surface/slope.
    Plot rms as a function of scale factor (if testval are passed for raster scan) 
        and 4 panel plot of best result (use comp2) either cropped (if crop is True) 
        or full.
    
    if testval is set to None, best fit is determined by analytical formula (minimizing
        rms of surface difference). If tesval is array, all values are tested. 
    
    if `roi` is passed, fom is calculated on the roi only.
    `crop` flag controls the plotting. If True, only the roi is plotted and 
    color scale is adjusted accordingly. Otherwise, entire region is plotted and
    a rectangle around the roi is plotted.
    dis=True print information and display plots in notebook.
    
    all fom and stats are calculated on leveled data, ideally I want to have stats in 
    roi unleveled, but it is safer this way for now.
    """

    #dy=np.diff(d1.y)[0]
    d2 = d2.resample(d1)

    res = []
    if roi is None:
        diff = d1 - d2
        roi = [span(diff.x), span(diff.y)]  #stupid way of doing it

    if testval is None:
        #use analytical formula
        tbest = simple_regressor(d1.crop(*roi).data, d2.crop(*roi).data)
        dtest = (d1 - (d2 * tbest)).crop(*roi).level()
        rbest = fom(*dtest())
    else:
        #test all values
        for i, t in enumerate(testval):
            #test each testval, create a plot (on file only). If dis is True, print vals
            diff = d1 - d2 * t
            f = fom(*(diff.crop(*roi))())
            res.append(f)
            axes = comp2(d1, d2 * t, roi=roi)
            plt.tight_layout(rect=[0, 0.03, 1, 0.95])
            plt.suptitle('factor: %s' % t)
            if outfile:
                plt.savefig(fn_add_subfix(outfile, '_%03i' % (i + 1), '.jpg'))
            if dis: print(i, t, f)
        #select best value
        res = np.array(res)
        ibest = np.argmin(res)
        tbest = testval[np.argmin(res)]
        rbest = res[ibest]
        #make plot with rms as a function of testval
        plt.figure(5)
        plt.clf()
        plt.plot(testval, res)
        plt.title('best factor:%6.3f, FOM surf:%6.3f' % (tbest, res[ibest]))
        plt.grid()
        if outfile:
            plt.savefig((fn_add_subfix(outfile, '', '.jpg', pre='FOMtrend_')))
        if dis: display(plt.gcf())

    #plot and display (if dis) best fit data (cropped if crop is selected, full otherwise).
    if crop:
        d1 = d1.crop(*roi).level()
        d2 = d2.crop(*roi).level()
    plt.figure()
    a = comp2(d1, d2 * tbest, roi=roi)
    plt.tight_layout(rect=[0, 0.03, 1, 0.95])
    plt.suptitle('best factor:%6.3f, FOM surf:%6.3f' % (tbest, rbest))
    if dis: display(plt.gcf())
    if outfile: plt.savefig(fn_add_subfix(outfile, '_fit', '.jpg'))

    return tbest