diff options
-rwxr-xr-x | calc_radial_psd.py | 131 |
1 files changed, 69 insertions, 62 deletions
diff --git a/calc_radial_psd.py b/calc_radial_psd.py index 4c1d85b..3f3508a 100755 --- a/calc_radial_psd.py +++ b/calc_radial_psd.py @@ -13,9 +13,11 @@ # # Aaron LI <aaronly.me@gmail.com> # Created: 2015-04-22 -# Updated: 2016-05-01 +# Updated: 2016-05-09 # -# Changelog: +# Change log: +# 2016-05-09: +# * PEP8 fixes # 2016-05-01: # * Adjust plot axis limits # 2016-04-28: @@ -38,16 +40,15 @@ # * Encapsulate the functions within class 'PSD' # * Update docs/comments # +# TODO/FIXME: +# * subtract background with normalization factor (w.r.t particle background) +# considered +# """ Compute the radially averaged power spectral density (i.e., power spectrum). """ -__version__ = "0.5.1" -__date__ = "2016-05-01" - - -import sys import os import argparse @@ -58,6 +59,9 @@ import matplotlib.pyplot as plt from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas from matplotlib.figure import Figure +__version__ = "0.5.2" +__date__ = "2016-05-01" + plt.style.use("ggplot") @@ -75,8 +79,8 @@ class PSD: # 2D power spectral density psd2d = None # 1D (radially averaged) power spectral density - freqs = None - psd1d = None + freqs = None + psd1d = None psd1d_err = None def __init__(self, img, pixel=(1.0, "pixel"), normalize=True): @@ -101,9 +105,9 @@ class PSD: """ if verbose: print("Calculating 2D power spectral density ... ", - end="", flush=True) + end="", flush=True) rows, cols = self.img.shape - ## Compute the power spectral density (i.e., power spectrum) + # Compute the power spectral density (i.e., power spectrum) imgf = np.fft.fftshift(np.fft.fft2(self.img)) if self.normalize: norm = rows * cols * self.pixel[0]**2 @@ -128,37 +132,36 @@ class PSD: """ if verbose: print("Calculating radial (1D) power spectral density ... ", - end="", flush=True) + end="", flush=True) if verbose: print("padding ... ", end="", flush=True) - psd2d = self.pad_square(self.psd2d, value=np.nan) - dim = psd2d.shape[0] + psd2d = self.pad_square(self.psd2d, value=np.nan) + dim = psd2d.shape[0] dim_half = (dim+1) // 2 # NOTE: # The zero-frequency component is shifted to position of index # (0-based): (ceil((n-1) / 2), ceil((m-1) / 2)) - px = np.arange(dim_half-dim, dim_half) - x, y = np.meshgrid(px, px) + px = np.arange(dim_half-dim, dim_half) + x, y = np.meshgrid(px, px) rho, phi = self.cart2pol(x, y) - rho = np.around(rho).astype(np.int) - radial_psd = np.zeros(dim_half) + rho = np.around(rho).astype(np.int) + radial_psd = np.zeros(dim_half) radial_psd_err = np.zeros(dim_half) if verbose: - print("radially averaging ... ", - end="", flush=True) + print("radially averaging ... ", end="", flush=True) for r in range(dim_half): # Get the indices of the elements satisfying rho[i,j]==r ii, jj = (rho == r).nonzero() # Calculate the mean value at a given radii - data = psd2d[ii, jj] - radial_psd[r] = np.nanmean(data) + data = psd2d[ii, jj] + radial_psd[r] = np.nanmean(data) radial_psd_err[r] = np.nanstd(data) # Calculate frequencies f = np.fft.fftfreq(dim, d=self.pixel[0]) freqs = np.abs(f[:dim_half]) # - self.freqs = freqs - self.psd1d = radial_psd + self.freqs = freqs + self.psd1d = radial_psd self.psd1d_err = radial_psd_err if verbose: print("DONE", end="", flush=True) @@ -193,35 +196,34 @@ class PSD: mat = data.copy() rows, cols = mat.shape dim_diff = abs(rows - cols) - dim_max = max(rows, cols) if rows > cols: # pad columns if dim_diff // 2 == 0: - cols_left = np.zeros((rows, dim_diff/2)) - cols_left[:] = value - cols_right = np.zeros((rows, dim_diff/2)) + cols_left = np.zeros((rows, dim_diff/2)) + cols_left[:] = value + cols_right = np.zeros((rows, dim_diff/2)) cols_right[:] = value - mat = np.hstack((cols_left, mat, cols_right)) + mat = np.hstack((cols_left, mat, cols_right)) else: - cols_left = np.zeros((rows, np.floor(dim_diff/2))) - cols_left[:] = value - cols_right = np.zeros((rows, np.floor(dim_diff/2)+1)) + cols_left = np.zeros((rows, np.floor(dim_diff/2))) + cols_left[:] = value + cols_right = np.zeros((rows, np.floor(dim_diff/2)+1)) cols_right[:] = value - mat = np.hstack((cols_left, mat, cols_right)) + mat = np.hstack((cols_left, mat, cols_right)) elif rows < cols: # pad rows if dim_diff // 2 == 0: - rows_top = np.zeros((dim_diff/2, cols)) - rows_top[:] = value - rows_bottom = np.zeros((dim_diff/2, cols)) + rows_top = np.zeros((dim_diff/2, cols)) + rows_top[:] = value + rows_bottom = np.zeros((dim_diff/2, cols)) rows_bottom[:] = value - mat = np.vstack((rows_top, mat, rows_bottom)) + mat = np.vstack((rows_top, mat, rows_bottom)) else: - rows_top = np.zeros((np.floor(dim_diff/2), cols)) - rows_top[:] = value - rows_bottom = np.zeros((np.floor(dim_diff/2)+1, cols)) + rows_top = np.zeros((np.floor(dim_diff/2), cols)) + rows_top[:] = value + rows_bottom = np.zeros((np.floor(dim_diff/2)+1, cols)) rows_bottom[:] = value - mat = np.vstack((rows_top, mat, rows_bottom)) + mat = np.vstack((rows_top, mat, rows_bottom)) return mat def plot(self, ax=None, fig=None): @@ -237,8 +239,7 @@ class PSD: ymin = np.min(self.psd1d) / 3.0 ymax = np.max(self.psd1d[mask] + self.psd1d_err[mask]) * 1.2 # - eb = ax.errorbar(self.freqs, self.psd1d, yerr=self.psd1d_err, - fmt="none") + ax.errorbar(self.freqs, self.psd1d, yerr=self.psd1d_err, fmt="none") ax.plot(self.freqs, self.psd1d, "ko") ax.set_xscale("log") ax.set_yscale("log") @@ -266,7 +267,7 @@ class AstroImage: # background map (e.g., stowed background) bkgmap = None # exposure time of the input image - exposure = None + exposure = None # exposure time of the background map exposure_bkg = None @@ -332,18 +333,21 @@ class AstroImage: if rows > rows_ref: img_fixed = img[:rows_ref, :] else: - img_fixed = np.row_stack((img, + img_fixed = np.row_stack(( + img, np.zeros((rows_ref-rows, cols), dtype=img.dtype))) # columns if cols > cols_ref: img_fixed = img_fixed[:, :cols_ref] else: - img_fixed = np.column_stack((img_fixed, + img_fixed = np.column_stack(( + img_fixed, np.zeros((rows_ref, cols_ref-cols), dtype=img.dtype))) return img_fixed else: - raise ValueError("shape difference exceeds tolerance: " + \ - "(%d, %d) vs. (%d, %d)" % (img.shape + ref.shape)) + raise ValueError("shape difference exceeds tolerance: " + + "(%d, %d) vs. (%d, %d)" % + (img.shape + ref.shape)) # if self.bkgmap is not None: if verbose: @@ -377,7 +381,7 @@ class AstroImage: with np.errstate(divide="ignore", invalid="ignore"): self.image /= self.expmap # set invalid values to ZERO - self.image[ ~ np.isfinite(self.image) ] = 0.0 + self.image[~ np.isfinite(self.image)] = 0.0 if verbose: print("DONE", flush=True) if cut is not None: @@ -385,7 +389,7 @@ class AstroImage: if verbose: print("Clipping image (%s) ... " % cut, end="", flush=True) threshold = cut * np.max(self.expmap) - self.image[ self.expmap < threshold ] = 0.0 + self.image[self.expmap < threshold] = 0.0 if verbose: print("DONE", flush=True) @@ -395,22 +399,25 @@ def main(): description="Compute the radially averaged power spectral density", epilog="Version: %s (%s)" % (__version__, __date__)) parser.add_argument("-V", "--version", action="version", - version="%(prog)s " + "%s (%s)" % (__version__, __date__)) + version="%(prog)s " + + "%s (%s)" % (__version__, __date__)) parser.add_argument("-v", "--verbose", dest="verbose", - action="store_true", help="show verbose information") + action="store_true", + help="show verbose information") parser.add_argument("-C", "--clobber", dest="clobber", - action="store_true", - help="overwrite the output files if already exist") - parser.add_argument("-i", "--infile", dest="infile", - required=True, help="input image") + action="store_true", + help="overwrite the output files if already exist") + parser.add_argument("-i", "--infile", dest="infile", required=True, + help="input image") parser.add_argument("-b", "--bkgmap", dest="bkgmap", default=None, - help="background map (for background subtraction)") + help="background map (for background subtraction)") parser.add_argument("-e", "--expmap", dest="expmap", default=None, - help="exposure map (for exposure correction)") - parser.add_argument("-o", "--outfile", dest="outfile", - required=True, help="output file to store the PSD data") + help="exposure map (for exposure correction)") + parser.add_argument("-o", "--outfile", dest="outfile", required=True, + help="output file to store the PSD data") parser.add_argument("-p", "--png", dest="png", default=None, - help="plot the PSD and save (default: same basename as outfile)") + help="plot the PSD and save " + + "(default: same basename as outfile)") args = parser.parse_args() if args.png is None: @@ -442,7 +449,7 @@ def main(): # Make and save a plot fig = Figure(figsize=(10, 8)) - canvas = FigureCanvas(fig) + FigureCanvas(fig) ax = fig.add_subplot(111) psd.plot(ax=ax, fig=fig) fig.savefig(args.png, format="png", dpi=150) |