def test_equal_branches(self): ''' Ensure the filament arrays are equal with and without computing the RHT branches. ''' test1 = fil_finder_2D(img, header=hdr, beamwidth=10.0 * u.arcsec, flatten_thresh=95, distance=260 * u.pc, size_thresh=430, glob_thresh=20, save_name="test1") test1.create_mask(border_masking=False) test1.medskel() test1.analyze_skeletons() test1.exec_rht(branches=True) test_copy = deepcopy(test1) test_copy.exec_rht(branches=False) for arr1, arr2 in zip(test1.filament_arrays['final'], test_copy.filament_arrays['final']): assert np.allclose(arr1, arr2) for arr1, arr2 in zip(test1.filament_arrays['long path'], test_copy.filament_arrays['long path']): assert np.allclose(arr1, arr2)
def test_with_rht_branches(self): test1 = fil_finder_2D(img, hdr, 10.0, flatten_thresh=95, distance=260, size_thresh=430, glob_thresh=20, save_name="test1") test1.create_mask(border_masking=False) test1.medskel() test1.analyze_skeletons() test1.exec_rht(branches=True) test1.find_widths() test1.compute_filament_brightness() for i, param in enumerate(test1.width_fits["Names"]): assert np.allclose(test1.width_fits["Parameters"][:, i], np.asarray(table1[param])) assert np.allclose(test1.width_fits["Errors"][:, i], np.asarray(table1[param+" Error"])) assert np.allclose(test1.lengths, np.asarray(table1['Lengths'])) assert (test1.width_fits['Type'] == table1['Fit Type']).all() assert np.allclose(test1.total_intensity, np.asarray(table1['Total Intensity'])) assert np.allclose(test1.filament_brightness, np.asarray(table1['Median Brightness'])) assert np.allclose(test1.branch_properties["number"], np.asarray(table1['Branches']))
def test_without_header_distance(self): beamwidth = 10.0*u.pix test1 = fil_finder_2D(img, header=None, beamwidth=beamwidth, flatten_thresh=95, distance=None, size_thresh=430, glob_thresh=20, save_name="test1") beamwidth = beamwidth / FWHM_FACTOR imgscale = 1.0 npt.assert_equal(test1.imgscale, imgscale) npt.assert_equal(test1.beamwidth, beamwidth.value)
def test_without_distance(self): beamwidth = 10.0*u.arcsec test1 = fil_finder_2D(img, header=hdr, beamwidth=beamwidth, flatten_thresh=95, distance=None, size_thresh=430, glob_thresh=20, save_name="test1") beamwidth = (beamwidth.to(u.deg) / (hdr["CDELT2"] * u.deg)) / FWHM_FACTOR imgscale = 1.0 npt.assert_equal(test1.imgscale, imgscale) npt.assert_equal(test1.beamwidth, beamwidth.value)
def test_header_beam(self): beam_hdr = hdr.copy() # It only looks for BMAJ at the moment. beam_hdr["BMAJ"] = 10.0 test1 = fil_finder_2D(img, header=beam_hdr, beamwidth=None, flatten_thresh=95, distance=None, size_thresh=430, glob_thresh=20, save_name="test1") beamwidth = (10.0 * u.deg / (hdr["CDELT2"] * u.deg)) / FWHM_FACTOR imgscale = 1.0 npt.assert_equal(test1.imgscale, imgscale) npt.assert_equal(test1.beamwidth, beamwidth.value)
def test_without_rht_branches(self): # Non-branches test2 = fil_finder_2D(img, header=hdr, beamwidth=10.0 * u.arcsec, flatten_thresh=95, distance=260 * u.pc, size_thresh=430, glob_thresh=20, save_name="test2") test2.create_mask(border_masking=False) test2.medskel() test2.analyze_skeletons() test2.exec_rht(branches=False) test2.find_widths() test2.compute_filament_brightness() assert test2.number_of_filaments == len(table2["Lengths"]) for i, param in enumerate(test2.width_fits["Names"]): npt.assert_allclose(test2.width_fits["Parameters"][:, i], np.asarray(table2[param]), rtol=1e-4) npt.assert_allclose(test2.width_fits["Errors"][:, i], np.asarray(table2[param + " Error"]), rtol=1e-4) assert np.allclose(test2.lengths, np.asarray(table2['Lengths'])) assert (test2.width_fits['Type'] == table2['Fit Type']).all() assert np.allclose(test2.total_intensity, np.asarray(table2['Total Intensity'])) assert np.allclose(test2.filament_brightness, np.asarray(table2['Median Brightness'])) assert np.allclose(test2.branch_properties["number"], np.asarray(table2['Branches'])) assert np.allclose(test2.rht_curvature['Orientation'], np.asarray(table2['Orientation'])) assert np.allclose(test2.rht_curvature['Curvature'], np.asarray(table2['Curvature']))
def test_with_distance(self): distance = 260*u.pc beamwidth = 10.0*u.arcsec # Divide by FWHM factor width = beamwidth / (2*np.sqrt(2*np.log(2))) test1 = fil_finder_2D(img, header=hdr, beamwidth=beamwidth, flatten_thresh=95, distance=distance, size_thresh=430, glob_thresh=20, save_name="test1") imgscale = hdr['CDELT2'] * \ (np.pi / 180.0) * distance.to(u.pc).value beamwidth = (width.to(u.arcsec).value / 206265.) * distance.value npt.assert_equal(test1.imgscale, imgscale) npt.assert_equal(test1.beamwidth, beamwidth)
def make_fil_spine(self,beamwidth=None,verbose=False): """ Create filament spine using the FilFinder package 'shortest path' option Parameters: ---------- beamwidth: float A float in units of arcseconds indicating the beamwidth of the image array. When corresponding keys are in the header file, the header will be used to determine the beamwidth. Only when the header does not containt information regarding the beamwidth, is the input `beamwidth` used in the calculation. verbose: boolean A boolean indicating whether you want to enable FilFinder plotting of filament spine Attributes ---------- filspine : numpy.ndarray A 2D array of 1s and 0s defining the longest path through the filament mask """ # Read beamwidth if isinstance(beamwidth, numbers.Number): if (self.header is not None): self.beamwidth = beamwidth * u.arcsec else: self.beamwidth = beamwidth * u.pix else: self.beamwidth = None raise TypeError("A beamwidth is needed if the header does not contain the beam information.") # fil_finder ## Let fil_fineder deal with the beamwidth if (self.header is not None): fils = fil_finder_2D(self.image, header = self.header, beamwidth = self.beamwidth, distance = self.distance, mask = self.mask) ## scale-free else: fils = fil_finder_2D(self.image, beamwidth = self.beamwidth, skel_thresh = 15, mask = self.mask) ## 15 is chosen to be roughly 0.3 pc at the distance to Per B5 (260 pc). ## Consider allowing users to input in the future. # do the skeletonization fils.medskel(verbose=verbose) # Find shortest path through skeleton analysis = fils.analyze_skeletons(verbose=verbose) # Return the reults. self.filspine = fils.skeleton_longpath.astype(bool) if (self.header is not None): self.length = np.sum(analysis.lengths) * u.pc self.imgscale = fils.imgscale * u.pc else: self.length = np.sum(analysis.lengths) * u.pix self.imgscale = fils.imgscale * u.pix # Return a dictionary to store the key setup Parameters self._params['__init__']['imgscale'] = self.imgscale params = {'beamwidth': self.beamwidth} self._params['make_fil_spine'] = params # Return a dictionary to store the results self._results['make_fil_spine']['filspine'] = self.filspine self._results['make_fil_spine']['length'] = self.length return self
# Licensed under an MIT open source license - see LICENSE from fil_finder import fil_finder_2D from astropy.io.fits import getdata img, hdr = getdata("filaments_updatedhdr.fits", header=True) # This one uses RHT on branches test1 = fil_finder_2D(img, hdr, 10.0, flatten_thresh=95, distance=260, size_thresh=430, glob_thresh=20, save_name="test1") test1.create_mask(border_masking=False) test1.medskel() test1.analyze_skeletons() test1.exec_rht(branches=True) test1.find_widths() test1.compute_filament_brightness() test1.save_table(save_name="test1", branch_table_type='hdf5', table_type='hdf5') test1.save_fits(save_name="test1") # This one does not test2 = fil_finder_2D(img, hdr, 10.0, flatten_thresh=95, distance=260, size_thresh=430, glob_thresh=20, save_name="test2") test2.create_mask(border_masking=False) test2.medskel() test2.analyze_skeletons() test2.exec_rht(branches=False)
def make_fil_spine(self,beamwidth = None,verbose = False): """ Create filament spine using the FilFinder package 'longest path' option Parameters: ---------- verbose: boolean A boolean indicating whether you want to enable FilFinder plotting of filament spine Attributes ---------- filspine : numpy.ndarray A 2D boolean array defining the longest path through the filament mask length: float The length of the filament; only accessible if make_fil_spine is called """ try: from fil_finder import fil_finder_2D except ImportError: raise ImportError("To use this method, you must install the fil_finder package to continue.") # Read beamwidth if isinstance(beamwidth, numbers.Number): if (self.header is not None): self.beamwidth = beamwidth * u.arcsec else: self.beamwidth = beamwidth * u.pix else: self.beamwidth = None raise TypeError("A beamwidth is required") # fil_finder ## Let fil_fineder deal with the beamwidth if (self.header is not None): fils = fil_finder_2D(self.image, header = self.header, beamwidth = self.beamwidth, distance = self.distance, mask = self.mask) ## scale-free else: fils = fil_finder_2D(self.image, beamwidth = self.beamwidth, skel_thresh = 15, mask = self.mask) ## 15 is chosen to be roughly 0.3 pc at the distance to Per B5 (260 pc). ## Consider allowing users to input in the future. # do the skeletonization fils.medskel(verbose=verbose) # Find shortest path through skeleton analysis = fils.analyze_skeletons(verbose=verbose) # Return the reults. self.filspine = fils.skeleton_longpath.astype(bool) if (self.header is not None): self.length = np.sum(analysis.lengths) * u.pc self.imgscale = fils.imgscale * u.pc else: self.length = np.sum(analysis.lengths) * u.pix self.imgscale = fils.imgscale * u.pix # Return a dictionary to store the key setup Parameters self._params['__init__']['imgscale'] = self.imgscale params = {'beamwidth': self.beamwidth} self._params['make_fil_spine'] = params # Return a dictionary to store the results self._results['make_fil_spine']['filspine'] = self.filspine self._results['make_fil_spine']['length'] = self.length return self
# Licensed under an MIT open source license - see LICENSE from fil_finder import fil_finder_2D from astropy.io.fits import getdata img, hdr = getdata("chamaeleonI-250_normed.fits", header=True) # Utilize fil_finder_2D class # See filfind_class.py for inputs # , region_slice=[580,1620,470,1120]) test = fil_finder_2D(img, hdr, 15.1, 30, 5, 50, distance=170., glob_thresh=20) test.create_mask(verbose=False, border_masking=True) test.medskel(verbose=False) test.analyze_skeletons() test.compute_filament_brightness() test.exec_rht(verbose=True, branches=False) # test.find_widths(verbose=False) # Or run: # test.run(verbose=True, save_name="chamaeleonI-250", save_plots=False) ## # Run entire algorithm
cube = SpectralCube.read( paths.Fpath('12m/SgrB2_b3_12M.HC3N.image.pbcor.contsub.fits')) subcube = cube[100:155].minimal_subcube() newcube = np.empty_like(subcube, dtype='int16') for ii, imslice in enumerate(ProgressBar(subcube)): img = imslice.value hdr = header = imslice.header try: ff = fil_finder.fil_finder_2D( img, hdr, beamwidth=3.5, distance=8500, skel_thresh=20, branch_thresh=10, glob_thresh=65, adapt_thresh=10, pad_size=1, ) except ValueError: print("FilFinder creation failed on iter {0}".format(ii)) continue try: mask = ff.create_mask(verbose=True) except ValueError: print("Mask creation failed on iter {0}".format(ii)) continue try: skels = ff.medskel(verbose=True)
p.imshow(np.arctan(pipe_img / np.percentile(pipe_img[np.isfinite(pipe_img)], 95)), origin="lower", interpolation="nearest") p.subplot(122) p.imshow(np.arctan( pipe_degraded / np.percentile(pipe_degraded[np.isfinite(pipe_degraded)], 95)), origin="lower", interpolation="nearest") p.show() filfind = fil_finder_2D(pipe_degraded, pipe_hdr, 18.2, 30, 15, 30, distance=400, glob_thresh=20) filfind.run(verbose=False, save_name="degraded_pipe", save_plots=False) ## Analysis if output: from astropy.table import Table deg_pipe_analysis = Table.read("degraded_pipe_table.fits") pipe_analysis = Table.read( "pipeCenterB59-250/pipeCenterB59-250_table.fits") # Plot lengths, widths, orientation, curvature. Adjust for distance difference
# Add some noise import numpy as np np.random.seed(500) threshs = [75, 95, 99] patches = [7, 13, 26] figure, grid = p.subplots(3, 3, sharex=True, sharey=True, figsize=(12, 12)) for i, patch in enumerate(patches[::-1]): for j, thresh in enumerate(threshs): noiseimg = img + np.random.normal(0, 0.05, size=img.shape) test = fil_finder_2D(noiseimg, hdr, 0.0, 30, 5, 10, flatten_thresh=thresh, distance=260) test.create_mask(verbose=False, smooth_size=3.0, adapt_thresh=patch, size_thresh=180, regrid=False, border_masking=False, zero_border=True) test.medskel(verbose=False) test.analyze_skeletons(verbose=False) grid[i, j].imshow(test.mask[10:266, 10:266], cmap='binary', interpolation='nearest') grid[i, j].contour(test.skeleton[10:266, 10:266], colors='gray', linewidths=0.3) grid[i, j].set_xlim([0, 256]) grid[i, j].set_ylim([0, 256]) if i == 2:
# Licensed under an MIT open source license - see LICENSE from fil_finder import fil_finder_2D from astropy.io.fits import getdata img, hdr = getdata("filaments_updatedhdr.fits", header=True) # This one uses RHT on branches test1 = fil_finder_2D(img, hdr, 10.0, flatten_thresh=95, distance=260, size_thresh=430, glob_thresh=20, save_name="test1") test1.create_mask(border_masking=False) test1.medskel() test1.analyze_skeletons() test1.exec_rht(branches=True) test1.find_widths() test1.compute_filament_brightness() test1.save_table(save_name="test1", branch_table_type='hdf5', table_type='hdf5') test1.save_fits(save_name="test1") # This one does not
from astropy.utils.console import ProgressBar import fil_finder from spectral_cube import SpectralCube cube = SpectralCube.read(paths.Fpath('12m/SgrB2_b3_12M.HC3N.image.pbcor.contsub.fits')) subcube = cube[100:155].minimal_subcube() newcube = np.empty_like(subcube, dtype='int16') for ii,imslice in enumerate(ProgressBar(subcube)): img = imslice.value hdr = header = imslice.header try: ff = fil_finder.fil_finder_2D(img, hdr, beamwidth=3.5, distance=8500, skel_thresh=20, branch_thresh=10, glob_thresh=65, adapt_thresh=10, pad_size=1, ) except ValueError: print("FilFinder creation failed on iter {0}".format(ii)) continue try: mask = ff.create_mask(verbose=True) except ValueError: print("Mask creation failed on iter {0}".format(ii)) continue try: skels = ff.medskel(verbose=True) except ValueError: print("Skeleton creation failed on iter {0}".format(ii)) continue
Example of the new radial profiling code for FilFinder. This functionality is still in testing! ''' hdu = fits.open("filaments_updatedhdr.fits")[0] img, hdr = hdu.data, hdu.header # Add some noise np.random.seed(500) noiseimg = img + np.random.normal(0, 0.05, size=img.shape) # We need the finalized skeletons, so run the first few portions of the # normal algorithm. test = fil_finder_2D(noiseimg, header=hdr, beamwidth=10.0*u.arcsec, flatten_thresh=95, distance=260*u.pc, glob_thresh=20) test.create_mask(verbose=False, border_masking=False, size_thresh=430) test.medskel(verbose=False) test.analyze_skeletons(verbose=False) # Now choose one the longest path skeletons from the labeled array labels, num = nd.label(test.skeleton_longpath, eight_con()) # Number 3 isn't too long and is in a relatively uncrowded region. # We enable verbose, which will plot the profile normal to each pixel in the # skeleton. # The noise parameter allows an array, of the same shape as the image, to be # passed and used as weights in the fitting. # NOTE: If you don't want a million plots showing up, uncomment the next line:
# Licensed under an MIT open source license - see LICENSE from fil_finder import fil_finder_2D from astropy.io.fits import getdata img, hdr = getdata("filaments_updatedhdr.fits", header=True) # Add some noise import numpy as np np.random.seed(500) noiseimg = img + np.random.normal(0,0.05,size=img.shape) ## Utilize fil_finder_2D class ## See filfind_class.py for inputs test = fil_finder_2D(noiseimg, hdr, 10.0, flatten_thresh=95, distance=260) test.create_mask(verbose=True, smooth_size=3.0, adapt_thresh=13.0, size_thresh=180, regrid=False, border_masking=False, zero_border=True) test.medskel(verbose=False) test.analyze_skeletons(verbose=False) test.exec_rht(verbose=False) test.find_widths(verbose=False) # test.save_table(save_name="sim_filaments") # test.save_fits(save_name="sim_filaments")
#def run_filfinder(label='mycloud', cubefile=None, mom8file=None, mom0file=None, redo=False, #distpc=4.8e4): plotfiledir = label + ".plots" # NO TRAILING / ! filpropfile = label + ".filprops.pkl" # phys props # initial fil finding in mom8 image: fits_hdu = fits.open(mom8file)[0] bmwidth = np.sqrt( fits_hdu.header['BMIN'] * fits_hdu.header['BMAJ']) * 3600 # arcsec # setting beamwidth will have no effect if a fits header is given # beamwidth=bmwidth*u.arcsec, # it turns out it uses sigma not FWHM so later, nbeam=#sigma=1.6pix here fils = fil_finder_2D(fits_hdu, distance=distpc * u.pc, glob_thresh=50, flatten_thresh=90) # 30Dor: glob=72, flatten=100 # GMC1 1st time: 50, 85 fils.save_name = plotfiledir if not os.path.exists(plotfiledir): os.mkdir(plotfiledir) redo = True # give radial profiles more breathing room. fils.skeleton_pad_size = 5 # 30dor: adapt=75, size=800 # GMC1 first time: 50,500 # can lower glob_thresh, get more small things, then lower adapt_thresh to
# Remove the old outputs dir_path = os.path.dirname(__file__) test1_path = os.path.join(dir_path, "test1") for file in os.listdir(test1_path): if file.startswith("test1_"): os.remove(os.path.join(test1_path, file)) img, hdr = getdata("filaments_updatedhdr.fits", header=True) # This one uses RHT on branches test1 = fil_finder_2D(img, header=hdr, beamwidth=10.0 * u.arcsec, flatten_thresh=95, distance=260 * u.pc, size_thresh=430, glob_thresh=20, save_name="test1") test1.create_mask(border_masking=False) test1.medskel() test1.analyze_skeletons() test1.exec_rht(branches=True) test1.find_widths() test1.compute_filament_brightness() test1.save_table(save_name="test1", branch_table_type='hdf5', table_type='hdf5') test1.save_fits(save_name="test1")
def insert_rasterized_contour_plot(c, ax): collections = c.collections for _c in collections: _c.remove() cc = ListCollection(collections, rasterized=True) ax.add_artist(cc) return cc img, hdr = fits.getdata('pipeCenterB59-350.fits', header=True) beam = 24.9 img = img + 31.697 filfind = fil_finder_2D(img, hdr, beam, glob_thresh=20, distance=145.) filfind.create_mask()#size_thresh=400) filfind.medskel() filfind.analyze_skeletons() filfind.exec_rht() filfind.find_widths(verbose=False) r = 460. / 145. conv = np.sqrt(r ** 2. - 1) * \ (beam / np.sqrt(8*np.log(2)) / (np.abs(hdr["CDELT2"]) * 3600.)) kernel = convolution.Gaussian2DKernel(conv) good_pixels = np.isfinite(img) nan_pix = np.ones(img.shape) nan_pix[good_pixels == 0] = np.NaN conv_img = convolution.convolve(img, kernel, boundary='fill',
from astropy import units as u import os # Remove the old outputs dir_path = os.path.dirname(__file__) test1_path = os.path.join(dir_path, "test1") for file in os.listdir(test1_path): if file.startswith("test1_"): os.remove(os.path.join(test1_path, file)) img, hdr = getdata("filaments_updatedhdr.fits", header=True) # This one uses RHT on branches test1 = fil_finder_2D(img, header=hdr, beamwidth=10.0 * u.arcsec, flatten_thresh=95, distance=260 * u.pc, size_thresh=430, glob_thresh=20, save_name="test1") test1.create_mask(border_masking=False) test1.medskel() test1.analyze_skeletons() test1.exec_rht(branches=True) test1.find_widths() test1.compute_filament_brightness() test1.save_table(save_name="test1", branch_table_type='hdf5', table_type='hdf5') test1.save_fits(save_name="test1") # This one does not test2_path = os.path.join(dir_path, "test2")
from astropy.io import fits import astropy.units as u import numpy as np hdu = fits.open("filaments_updatedhdr.fits")[0] img, hdr = hdu.data, hdu.header # Add some noise np.random.seed(500) noiseimg = img + np.random.normal(0, 0.05, size=img.shape) # Utilize fil_finder_2D class # See filfind_class.py for inputs test = fil_finder_2D(noiseimg, header=hdr, beamwidth=10.0 * u.arcsec, flatten_thresh=95, distance=260 * u.pc, glob_thresh=20) test.create_mask(verbose=True, border_masking=False, size_thresh=430) # test = fil_finder_2D(noiseimg, hdr, 10.0, flatten_thresh=95, distance=260) # test.create_mask(verbose=True, smooth_size=3.0, adapt_thresh=13.0, # size_thresh=180, regrid=False, border_masking=False, # zero_border=True) test.medskel(verbose=False) test.analyze_skeletons(verbose=False) test.exec_rht(verbose=False) test.find_widths(verbose=False) # test.save_table(save_name="sim_filaments") # test.save_fits(save_name="sim_filaments")
import numpy as np np.random.seed(500) threshs = [75, 95, 99] patches = [7, 13, 26] figure, grid = p.subplots(3, 3, sharex=True, sharey=True, figsize=(12, 12)) for i, patch in enumerate(patches[::-1]): for j, thresh in enumerate(threshs): noiseimg = img + np.random.normal(0, 0.05, size=img.shape) test = fil_finder_2D(noiseimg, hdr, 0.0, 30, 5, 10, flatten_thresh=thresh, distance=260) test.create_mask(verbose=False, smooth_size=3.0, adapt_thresh=patch, size_thresh=180, regrid=False, border_masking=False, zero_border=True) test.medskel(verbose=False) test.analyze_skeletons(verbose=False) grid[i, j].imshow(test.mask[10:266, 10:266], cmap='binary',
# Licensed under an MIT open source license - see LICENSE from fil_finder import fil_finder_2D from astropy.io.fits import getdata img, hdr = getdata("filaments_updatedhdr.fits", header=True) # Add some noise import numpy as np np.random.seed(500) noiseimg = img + np.random.normal(0, 0.05, size=img.shape) ## Utilize fil_finder_2D class ## See filfind_class.py for inputs test = fil_finder_2D(noiseimg, hdr, 10.0, flatten_thresh=95, distance=260) test.create_mask(verbose=True, smooth_size=3.0, adapt_thresh=13.0, size_thresh=180, regrid=False, border_masking=False, zero_border=True) test.medskel(verbose=False) test.analyze_skeletons(verbose=False) test.exec_rht(verbose=False) test.find_widths(verbose=False) # test.save_table(save_name="sim_filaments") # test.save_fits(save_name="sim_filaments")
if compute: kernel = convolution.Gaussian2DKernel(conv) pipe_degraded = convolution.convolve(pipe_img, kernel, boundary='fill', fill_value=np.NaN) p.subplot(121) p.imshow(np.arctan(pipe_img/np.percentile(pipe_img[np.isfinite(pipe_img)], 95)), origin="lower", interpolation="nearest") p.subplot(122) p.imshow(np.arctan(pipe_degraded/np.percentile(pipe_degraded[np.isfinite(pipe_degraded)], 95)), origin="lower", interpolation="nearest") p.show() filfind = fil_finder_2D(pipe_degraded, pipe_hdr, 18.2, 30, 15, 30, distance=400, glob_thresh=20) filfind.run(verbose=False, save_name="degraded_pipe", save_plots=False) ## Analysis if output: from astropy.table import Table deg_pipe_analysis = Table.read("degraded_pipe_table.fits") pipe_analysis = Table.read("pipeCenterB59-250/pipeCenterB59-250_table.fits") # Plot lengths, widths, orientation, curvature. Adjust for distance difference # p.subplot2grid((4,2), (0,0)) p.subplot(411) num1 = int(np.sqrt(deg_pipe_analysis["FWHM"][np.isfinite(deg_pipe_analysis["FWHM"])].size))