def do_work(): prefix = './%s-figs-ti_vs_tj' % gu.str_tstamp( fmt='%Y-%m-%d', time_sec=None) # '%Y-%m-%dT%H:%M:%S%z' gu.create_directory(prefix, mode=0o775) path = os.path.abspath(os.path.dirname(__file__)) print('path to npy flies dir:', path) ti_vs_tj = np.load('%s/ti_vs_tj.npy' % path) t_all = np.load('%s/t_all.npy' % path) trange = (1400., 2900.) print_ndarr(ti_vs_tj, 'ti_vs_tj:\n') print_ndarr(t_all, 't_all:\n') sum_bkg = t_all.sum() sum_cor = ti_vs_tj.sum() print('sum_bkg:', sum_bkg) print('sum_cor:', sum_cor) imrange = trange + trange # (1400., 2900., 1400., 2900.) axim = gr.plotImageLarge(ti_vs_tj, img_range=imrange, amp_range=(0,500), figsize=(11,10),\ title='ti_vs_tj', origin='lower', window=(0.10, 0.08, 0.88, 0.88), cmap='inferno') gr.save('%s/fig-ti_vs_tj.png' % prefix) bkg = np.outer(t_all, t_all) / sum_bkg print_ndarr(bkg, 'bkg:\n') axim = gr.plotImageLarge(bkg, img_range=imrange, amp_range=(0,500), figsize=(11,10),\ title='bkg', origin='lower', window=(0.10, 0.08, 0.88, 0.88), cmap='inferno') gr.save('%s/fig-ti_vs_tj-bkg.png' % prefix) harr = t_all nbins = harr.size ht = HBins(trange, nbins, vtype=np.float32) # ht.binedges() fig, axhi, hi = gr.hist1d(ht.bincenters(), bins=nbins, amp_range=ht.limits(), weights=harr, color='b', show_stat=True,\ log=True, figsize=(7,6), axwin=(0.10, 0.10, 0.88, 0.85), title='1-d bkg',\ xlabel='time of all hits (ns)', ylabel='number of hits', titwin='1-d bkg') gr.save('%s/fig-time-hits.png' % prefix) gr.show()
class HPolar(): def __init__(self, xarr, yarr, mask=None, radedges=None, nradbins=100, phiedges=(0, 360), nphibins=32): """Parameters - mask - n-d array with mask - xarr - n-d array with pixel x coordinates in any units - yarr - n-d array with pixel y coordinates in the same units as xarr - radedges - radial bin edges for corrected region in the same units of xarr; default=None - all radial range - nradbins - number of radial bins - phiedges - phi angle bin edges for corrected region. default=(0,360) Difference of the edge limits should not exceed +/-360 degree - nphibins - number of angular bins default=32 - bin size equal to 1 rhumb for default phiedges """ self.rad, self.phi0 = cart2polar(xarr, yarr) self.shapeflat = (self.rad.size, ) self.rad.shape = self.shapeflat self.phi0.shape = self.shapeflat self.mask = mask phimin = min(phiedges[0], phiedges[-1]) self.phi = np.select((self.phi0 < phimin, self.phi0 >= phimin), (self.phi0 + 360., self.phi0)) self._set_rad_bins(radedges, nradbins) self._set_phi_bins(phiedges, nphibins) npbins = self.pb.nbins() nrbins = self.rb.nbins() self.ntbins = npbins * nrbins # total number of bins in r-phi array self.irad = self.rb.bin_indexes(self.rad, edgemode=1) self.iphi = self.pb.bin_indexes(self.phi, edgemode=1) self.cond = np.logical_and(\ np.logical_and(self.irad > -1, self.irad < nrbins), np.logical_and(self.iphi > -1, self.iphi < npbins) ) if mask is not None: self.cond = np.logical_and(self.cond, mask.astype(np.bool).ravel()) # index ntbins stands for overflow bin self.iseq = np.select((self.cond, ), (self.iphi * nrbins + self.irad, ), self.ntbins).ravel() #self.npix_per_bin = np.bincount(self.iseq, weights=None, minlength=None) self.npix_per_bin = np.bincount(self.iseq, weights=None, minlength=self.ntbins + 1) self.griddata = None def _set_rad_bins(self, radedges, nradbins): rmin = math.floor(np.amin( self.rad)) if radedges is None else radedges[0] rmax = math.ceil(np.amax( self.rad)) if radedges is None else radedges[-1] if rmin < 1: rmin = 1 self.rb = HBins((rmin, rmax), nradbins) def _set_phi_bins(self, phiedges, nphibins): if phiedges[-1] > phiedges[0]+360\ or phiedges[-1] < phiedges[0]-360: raise ValueError('Difference between angular edges should not exceed 360 degree;'\ ' phiedges: %.0f, %.0f' % (phiedges[0], phiedges[-1])) self.pb = HBins(phiedges, nphibins) phi1, phi2 = self.pb.limits() self.is360 = math.fabs(math.fabs(phi2 - phi1) - 360) < 1e-3 def info_attrs(self): return '%s attrbutes:' % self.__class__.__name__\ + self.pb.strrange(fmt='\nPhi bins: min:%8.1f max:%8.1f nbins:%5d')\ + self.rb.strrange(fmt='\nRad bins: min:%8.1f max:%8.1f nbins:%5d') def print_attrs(self): print(self.info_attrs()) def print_ndarrs(self): print('%s n-d arrays:' % self.__class__.__name__) print_ndarr(self.rad, ' rad') print_ndarr(self.phi, ' phi') print_ndarr(self.mask, ' mask') #print('Phi limits: ', phiedges[0], phiedges[-1]) def obj_radbins(self): """Returns HBins object for radial bins.""" return self.rb def obj_phibins(self): """Returns HBins object for angular bins.""" return self.pb def pixel_rad(self): """Returns 1-d numpy array of pixel radial parameters.""" return self.rad def pixel_irad(self): """Returns 1-d numpy array of pixel radial indexes [-1,nrbins] - extended edgemode.""" return self.irad def pixel_phi0(self): """Returns 1-d numpy array of pixel angules in the range [-180,180] degree.""" return self.phi0 def pixel_phi(self): """Returns 1-d numpy array of pixel angules in the range [phi_min, phi_min+360] degree.""" return self.phi def pixel_iphi(self): """Returns 1-d numpy array of pixel angular indexes [-1,npbins] - extended edgemode.""" return self.iphi def pixel_iseq(self): """Returns 1-d numpy array of sequentially (in rad and phi) numerated pixel indexes [0,ntbins]. WARNING: pixels outside the r-phi region of interest marked by the index ntbins, ntbins - total number of r-phi bins, which exceeds allowed range of r-phi indices... """ return self.iseq def bin_number_of_pixels(self): """Returns 1-d numpy array of number of accounted pixels per bin.""" return self.npix_per_bin def _ravel_(self, nda): if len(nda.shape) > 1: #nda.shape = self.shapeflat return nda.ravel( ) # return ravel copy in order to preserve input array shape return nda def bin_intensity(self, nda): """Returns 1-d numpy array of total pixel intensity per bin for input array nda.""" #return np.bincount(self.iseq, weights=self._ravel_(nda), minlength=None) return np.bincount(self.iseq, weights=self._ravel_(nda), minlength=self.ntbins + 1) # +1 for overflow bin def bin_avrg(self, nda): """Returns 1-d numpy array of averaged in r-phi bin intensities for input image array nda. WARNING array range [0, nrbins*npbins + 1], where +1 bin intensity is for all off ROI pixels. """ num = self.bin_intensity(self._ravel_(nda)) den = self.bin_number_of_pixels() #print_ndarr(nda, name='ZZZ bin_avrg: nda', first=0, last=5) #print_ndarr(num, name='ZZZ bin_avrg: num', first=0, last=5) #print_ndarr(den, name='ZZZ bin_avrg: den', first=0, last=5) return divide_protected(num, den, vsub_zero=0) def bin_avrg_rad_phi(self, nda, do_transp=True): """Returns 2-d (rad,phi) numpy array of averaged in bin intensity for input array nda.""" arr_rphi = self.bin_avrg( self._ravel_(nda))[:-1] # -1 removes off ROI bin arr_rphi.shape = (self.pb.nbins(), self.rb.nbins()) return np.transpose(arr_rphi) if do_transp else arr_rphi def pixel_avrg(self, nda, subs_value=0): """Makes r-phi histogram of intensities from input image array and projects r-phi averaged intensities back to image. Returns ravel 1-d numpy array of per-pixel intensities taken from r-phi histogram. - nda - input (2-d or 1-d-ravel) pixel array. - subs_value - value sabstituted for pixels out of ROI defined by the min/max in r-phi. """ bin_avrg = self.bin_avrg(self._ravel_(nda)) return np.select((self.cond, ), (bin_avrg[self.iseq], ), subs_value).ravel() #return np.array([bin_avrg[i] for i in self.iseq]) # iseq may be outside the bin_avrg range def pixel_avrg_interpol(self, nda, method='linear', verb=False, subs_value=0): # 'nearest' 'cubic' """Makes r-phi histogram of intensities from input image and projects r-phi averaged intensities back to image with per-pixel interpolation. Returns 1-d numpy array of per-pixel interpolated intensities taken from r-phi histogram. - subs_value - value sabstituted for pixels out of ROI defined by the min/max in r-phi. """ #if not is360: raise ValueError('Interpolation works for 360 degree coverage ONLY') if self.griddata is None: from scipy.interpolate import griddata self.griddata = griddata # 1) get values in bin centers binv = self.bin_avrg_rad_phi(self._ravel_(nda), do_transp=False) # 2) add values in bin edges if verb: print('binv.shape: ', binv.shape) vrad_a1, vrad_a2 = binv[0, :], binv[-1, :] if self.is360: vrad_a1 = vrad_a2 = 0.5 * (binv[0, :] + binv[-1, :] ) # [iphi, irad] nodea = np.vstack((vrad_a1, binv, vrad_a2)) vang_rmin, vang_rmax = nodea[:, 0], nodea[:, -1] vang_rmin.shape = vang_rmax.shape = (vang_rmin.size, 1 ) # it should be 2d for hstack val_nodes = np.hstack((vang_rmin, nodea, vang_rmax)) if verb: print('nodear.shape: ', val_nodes.shape) # 3) extend bin-centers by limits bcentsr = self.rb.bincenters() bcentsp = self.pb.bincenters() blimsr = self.rb.limits() blimsp = self.pb.limits() rad_nodes = np.concatenate(((blimsr[0], ), bcentsr, (blimsr[1], ))) phi_nodes = np.concatenate(((blimsp[0], ), bcentsp, (blimsp[1], ))) if verb: print('rad_nodes.shape', rad_nodes.shape) if verb: print('phi_nodes.shape', phi_nodes.shape) # 4) make point coordinate and value arrays points_rad, points_phi = np.meshgrid(rad_nodes, phi_nodes) if verb: print('points_phi.shape', points_phi.shape) if verb: print('points_rad.shape', points_rad.shape) points = np.vstack((points_phi.ravel(), points_rad.ravel())).T values = val_nodes.ravel() if verb: #print('points:', points) print('points.shape', points.shape) print('values.shape', values.shape) # 5) return interpolated data on (phi, rad) grid grid_vals = self.griddata(points, values, (self.phi, self.rad), method=method) return np.select((self.iseq < self.ntbins, ), (grid_vals, ), default=subs_value)
class HPolar(): def __init__(self, xarr, yarr, mask=None, radedges=None, nradbins=100, phiedges=(0, 360), nphibins=32): """Parameters - mask - n-d array with mask - xarr - n-d array with pixel x coordinates in any units - yarr - n-d array with pixel y coordinates in the same units as xarr - radedges - radial bin edges for corrected region in the same units of xarr; default=None - all radial range - nradbins - number of radial bins - phiedges - phi ange bin edges for corrected region. default=(0,360) Difference of the edge limits should not exceed +/-360 degree - nphibins - number of angular bins default=32 - bin size equal to 1 rhumb for default phiedges """ self.rad, self.phi0 = cart2polar(xarr, yarr) self.shapeflat = (self.rad.size, ) self.rad.shape = self.shapeflat self.phi0.shape = self.shapeflat self.mask = mask phimin = min(phiedges[0], phiedges[-1]) self.phi = np.select((self.phi0 < phimin, self.phi0 >= phimin), (self.phi0 + 360., self.phi0)) self._set_rad_bins(radedges, nradbins) self._set_phi_bins(phiedges, nphibins) npbins = self.pb.nbins() nrbins = self.rb.nbins() ntbins = npbins * nrbins self.irad = self.rb.bin_indexes(self.rad, edgemode=1) self.iphi = self.pb.bin_indexes(self.phi, edgemode=1) cond = np.logical_and(\ np.logical_and(self.irad > -1, self.irad < nrbins), np.logical_and(self.iphi > -1, self.iphi < npbins) ) if mask is not None: cond = np.logical_and(cond, mask.astype(np.bool).flatten()) self.iseq = np.select((cond, ), (self.iphi * nrbins + self.irad, ), ntbins).flatten() self.npix_per_bin = np.bincount(self.iseq, weights=None, minlength=None) self.griddata = None self.print_ndarr = None def _set_rad_bins(self, radedges, nradbins): rmin = math.floor(np.amin( self.rad)) if radedges is None else radedges[0] rmax = math.ceil(np.amax( self.rad)) if radedges is None else radedges[-1] if rmin < 1: rmin = 1 self.rb = HBins((rmin, rmax), nradbins) def _set_phi_bins(self, phiedges, nphibins): if phiedges[-1] > phiedges[0]+360\ or phiedges[-1] < phiedges[0]-360: raise ValueError('Difference between angular edges should not exceed 360 degree;'\ ' phiedges: %.0f, %.0f' % (phiedges[0], phiedges[-1])) self.pb = HBins(phiedges, nphibins) phi1, phi2 = self.pb.limits() self.is360 = math.fabs(math.fabs(phi2 - phi1) - 360) < 1e-3 def print_attrs(self): print('%s attrbutes:' % self.__class__.__name__) print( self.pb.strrange(fmt='Phi bins: min:%8.1f max:%8.1f nbins:%5d')) print( self.rb.strrange(fmt='Rad bins: min:%8.1f max:%8.1f nbins:%5d')) def print_ndarrs(self): print('%s n-d arrays:' % self.__class__.__name__) if self.print_ndarr is None: from psana.pyalgos.generic.NDArrUtils import print_ndarr self.print_ndarr = print_ndarr self.print_ndarr(self.rad, ' rad') self.print_ndarr(self.phi, ' phi') self.print_ndarr(self.mask, ' mask') #print('Phi limits: ', phiedges[0], phiedges[-1]) def obj_radbins(self): """Returns HBins object for radial bins.""" return self.rb def obj_phibins(self): """Returns HBins object for angular bins.""" return self.pb def pixel_rad(self): """Returns 1-d numpy array of pixel radial parameters.""" return self.rad def pixel_irad(self): """Returns 1-d numpy array of pixel radial indexes.""" return self.irad def pixel_phi0(self): """Returns 1-d numpy array of pixel angules in the range [-180,180] degree.""" return self.phi0 def pixel_phi(self): """Returns 1-d numpy array of pixel angules in the range [phi_min, phi_min+360] degree.""" return self.phi def pixel_iphi(self): """Returns 1-d numpy array of pixel angular indexes.""" return self.iphi def pixel_iseq(self): """Returns 1-d numpy array of sequentially (in rad and phi) numerated pixel indexes.""" return self.iseq def bin_number_of_pixels(self): """Returns 1-d numpy array of number of accounted pixels per bin.""" return self.npix_per_bin def _flatten_(self, nda): if len(nda.shape) > 1: #nda.shape = self.shapeflat return nda.flatten( ) # return flatten copy in order to preserve input array shape return nda def bin_intensity(self, nda): """Returns 1-d numpy array of total pixel intensity per bin for input array nda.""" return np.bincount(self.iseq, weights=self._flatten_(nda), minlength=None) def bin_avrg(self, nda): """Returns 1-d numpy array of averaged in bin intensity for input array nda.""" num = self.bin_intensity(self._flatten_(nda)) den = self.bin_number_of_pixels() return divide_protected(num, den, vsub_zero=0) def bin_avrg_rad_phi(self, nda, do_transp=True): """Returns 2-d (rad,phi) numpy array of averaged in bin intensity for input array nda.""" arr_rphi = self.bin_avrg(self._flatten_(nda))[:-1] arr_rphi.shape = (self.pb.nbins(), self.rb.nbins()) return np.transpose(arr_rphi) if do_transp else arr_rphi def pixel_avrg(self, nda): """Returns 1-d numpy array of per-pixel background for input array nda.""" bin_avrg = self.bin_avrg(self._flatten_(nda)) return np.array([bin_avrg[i] for i in self.iseq]) def pixel_avrg_interpol(self, nda, method='linear', verb=False): # 'nearest' 'cubic' """Returns 1-d numpy array of per-pixel interpolated background for averaged input data.""" #if not is360 : raise ValueError('Interpolation works for 360 degree coverage ONLY') if self.griddata is None: from scipy.interpolate import griddata self.griddata = griddata # 1) get values in bin centers binv = self.bin_avrg_rad_phi(self._flatten_(nda), do_transp=False) # 2) add values in bin edges if verb: print('binv.shape: ', binv.shape) vrad_a1, vrad_a2 = binv[0, :], binv[-1, :] if self.is360: vrad_a1 = vrad_a2 = 0.5 * (binv[0, :] + binv[-1, :] ) # [iphi, irad] nodea = np.vstack((vrad_a1, binv, vrad_a2)) vang_rmin, vang_rmax = nodea[:, 0], nodea[:, -1] vang_rmin.shape = vang_rmax.shape = (vang_rmin.size, 1 ) # it should be 2d for hstack val_nodes = np.hstack((vang_rmin, nodea, vang_rmax)) if verb: print('nodear.shape: ', val_nodes.shape) # 3) extend bin-centers by limits bcentsr = self.rb.bincenters() bcentsp = self.pb.bincenters() blimsr = self.rb.limits() blimsp = self.pb.limits() rad_nodes = np.concatenate(((blimsr[0], ), bcentsr, (blimsr[1], ))) phi_nodes = np.concatenate(((blimsp[0], ), bcentsp, (blimsp[1], ))) if verb: print('rad_nodes.shape', rad_nodes.shape) if verb: print('phi_nodes.shape', phi_nodes.shape) # 4) make point coordinate and value arrays points_rad, points_phi = np.meshgrid(rad_nodes, phi_nodes) if verb: print('points_phi.shape', points_phi.shape) if verb: print('points_rad.shape', points_rad.shape) points = np.array(zip(points_phi.flatten(), points_rad.flatten())) if verb: print('points.shape', points.shape) values = val_nodes.flatten() if verb: print('values.shape', values.shape) # 4) return interpolated data on (phi, rad) grid grid_vals = self.griddata(points, values, (self.phi, self.rad), method=method) return np.select((self.iseq < self.pb.nbins() * self.rb.nbins(), ), (grid_vals, ), default=0)