Create analysis tool

This commit is contained in:
Thibault Barnouin
2022-04-06 15:45:14 +02:00
parent c4311bbb4b
commit f6df92a1c2
15 changed files with 652 additions and 184 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/python3
#-*- coding:utf-8 -*- #-*- coding:utf-8 -*-
""" """
Main script where are progressively added the steps for the FOC pipeline reduction. Main script where are progressively added the steps for the FOC pipeline reduction.
@@ -19,12 +19,12 @@ import matplotlib.pyplot as plt
def main(): def main():
##### User inputs ##### User inputs
## Input and output locations ## Input and output locations
# globals()['data_folder'] = "../data/NGC1068_x274020/" globals()['data_folder'] = "../data/NGC1068_x274020/"
# infiles = ['x274020at.c0f.fits','x274020bt.c0f.fits','x274020ct.c0f.fits', infiles = ['x274020at.c0f.fits','x274020bt.c0f.fits','x274020ct.c0f.fits',
# 'x274020dt.c0f.fits','x274020et.c0f.fits','x274020ft.c0f.fits', 'x274020dt.c0f.fits','x274020et.c0f.fits','x274020ft.c0f.fits',
# 'x274020gt.c0f.fits','x274020ht.c0f.fits','x274020it.c0f.fits'] 'x274020gt.c0f.fits','x274020ht.c0f.fits','x274020it.c0f.fits']
# psf_file = 'NGC1068_f253m00.fits' psf_file = 'NGC1068_f253m00.fits'
# globals()['plots_folder'] = "../plots/NGC1068_x274020/" globals()['plots_folder'] = "../plots/NGC1068_x274020/"
# globals()['data_folder'] = "../data/NGC1068_x14w010/" # globals()['data_folder'] = "../data/NGC1068_x14w010/"
# infiles = ['x14w0101t_c0f.fits','x14w0102t_c0f.fits','x14w0103t_c0f.fits', # infiles = ['x14w0101t_c0f.fits','x14w0102t_c0f.fits','x14w0103t_c0f.fits',
@@ -63,10 +63,10 @@ def main():
# 'x3995202r_c0f.fits','x3995206r_c0f.fits'] # 'x3995202r_c0f.fits','x3995206r_c0f.fits']
# globals()['plots_folder'] = "../plots/PG1630+377_x39510/" # globals()['plots_folder'] = "../plots/PG1630+377_x39510/"
globals()['data_folder'] = "../data/IC5063_x3nl030/" # globals()['data_folder'] = "../data/IC5063_x3nl030/"
infiles = ['x3nl0301r_c0f.fits','x3nl0302r_c0f.fits','x3nl0303r_c0f.fits'] # infiles = ['x3nl0301r_c0f.fits','x3nl0302r_c0f.fits','x3nl0303r_c0f.fits']
psf_file = 'IC5063_f502m00.fits' # psf_file = 'IC5063_f502m00.fits'
globals()['plots_folder'] = "../plots/IC5063_x3nl030/" # globals()['plots_folder'] = "../plots/IC5063_x3nl030/"
# globals()['data_folder'] = "../data/MKN3_x3nl010/" # globals()['data_folder'] = "../data/MKN3_x3nl010/"
# infiles = ['x3nl0101r_c0f.fits','x3nl0102r_c0f.fits','x3nl0103r_c0f.fits'] # infiles = ['x3nl0101r_c0f.fits','x3nl0102r_c0f.fits','x3nl0103r_c0f.fits']
@@ -104,14 +104,14 @@ def main():
rebin = True rebin = True
if rebin: if rebin:
pxsize = 0.10 pxsize = 0.10
px_scale = 'arcsec' #pixel, arcsec or full px_scale = 'full' #pixel, arcsec or full
rebin_operation = 'sum' #sum or average rebin_operation = 'sum' #sum or average
# Alignement # Alignement
align_center = 'image' #If None will align image to image center align_center = 'image' #If None will align image to image center
display_data = False display_data = False
# Smoothing # Smoothing
smoothing_function = 'combine' #gaussian_after, gaussian or combine smoothing_function = 'combine' #gaussian_after, gaussian or combine
smoothing_FWHM = 0.20 #If None, no smoothing is done smoothing_FWHM = None #If None, no smoothing is done
smoothing_scale = 'arcsec' #pixel or arcsec smoothing_scale = 'arcsec' #pixel or arcsec
# Rotation # Rotation
rotate_stokes = True #rotation to North convention can give erroneous results rotate_stokes = True #rotation to North convention can give erroneous results
@@ -119,8 +119,8 @@ def main():
# Final crop # Final crop
crop = False #Crop to desired ROI crop = False #Crop to desired ROI
# Polarization map output # Polarization map output
figname = 'IC5063_FOC' #target/intrument name figname = 'NGC1068_FOC' #target/intrument name
figtype = '_combine_FWHM020' #additionnal informations figtype = '_full' #additionnal informations
SNRp_cut = 10. #P measurments with SNR>3 SNRp_cut = 10. #P measurments with SNR>3
SNRi_cut = 100. #I measurments with SNR>30, which implies an uncertainty in P of 4.7%. SNRi_cut = 100. #I measurments with SNR>30, which implies an uncertainty in P of 4.7%.
step_vec = 1 #plot all vectors in the array. if step_vec = 2, then every other vector will be plotted step_vec = 1 #plot all vectors in the array. if step_vec = 2, then every other vector will be plotted

62
src/analysis.py Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/python3
from getopt import getopt, error as get_error
from sys import argv
arglist = argv[1:]
options = "hf:p:i:o:"
long_options = ["help","fits=","snrp=","snri=","output="]
fits_path = None
SNRp_cut, SNRi_cut = 3, 30
out_txt = None
try:
arg, val = getopt(arglist, options, long_options)
for curr_arg, curr_val in arg:
if curr_arg in ("-h", "--help"):
print("python3 analysis.py -f <path_to_reduced_fits> -p <SNRp_cut> -i <SNRi_cut> -o <path_to_output_txt>")
elif curr_arg in ("-f", "--fits"):
fits_path = str(curr_val)
elif curr_arg in ("-p", "--snrp"):
SNRp_cut = int(curr_val)
elif curr_arg in ("-i", "--snri"):
SNRi_cut = int(curr_val)
elif curr_arg in ("-o", "--output"):
out_txt = str(curr_val)
except get_error as err:
print(str(err))
if not fits_path is None:
from astropy.io import fits
from lib.plots import pol_map
Stokes_UV = fits.open(fits_path)
p = pol_map(Stokes_UV, SNRp_cut=SNRp_cut, SNRi_cut=SNRi_cut)
if not out_txt is None:
import numpy as np
conv = p.Stokes[0].header['photflam']
I = p.Stokes[0].data*conv
Q = p.Stokes[1].data*conv
U = p.Stokes[2].data*conv
P = np.zeros(I.shape)
P[p.cut] = p.Stokes[5].data[p.cut]
PA = np.zeros(I.shape)
PA[p.cut] = p.Stokes[8].data[p.cut]
shape = np.array(I.shape)
center = (shape/2).astype(int)
cdelt_arcsec = p.wcs.wcs.cdelt*3600
xx, yy = np.indices(shape)
x, y = (xx-center[0])*cdelt_arcsec[0], (yy-center[1])*cdelt_arcsec[1]
data_list = []
for i in range(shape[0]):
for j in range(shape[1]):
data_list.append([x[i,j], y[i,j], I[i,j], Q[i,j], U[i,j], P[i,j], PA[i,j]])
data = np.array(data_list)
np.savetxt(out_txt,data)
else:
print("python3 analysis.py -f <path_to_reduced_fits> -p <SNRp_cut> -i <SNRi_cut> -o <path_to_output_txt>")

View File

@@ -118,6 +118,7 @@ def save_Stokes(I_stokes, Q_stokes, U_stokes, Stokes_cov, P, debiased_P, s_P,
exp_tot = np.array([header['exptime'] for header in headers]).sum() exp_tot = np.array([header['exptime'] for header in headers]).sum()
new_wcs = wcs.WCS(ref_header).deepcopy() new_wcs = wcs.WCS(ref_header).deepcopy()
if data_mask.shape != (1,1):
vertex = clean_ROI(data_mask) vertex = clean_ROI(data_mask)
shape = vertex[1::2]-vertex[0::2] shape = vertex[1::2]-vertex[0::2]
new_wcs.array_shape = shape new_wcs.array_shape = shape
@@ -138,6 +139,7 @@ def save_Stokes(I_stokes, Q_stokes, U_stokes, Stokes_cov, P, debiased_P, s_P,
header['PA_int_err'] = (ref_header['PA_int_err'], 'Integrated polarization angle error') header['PA_int_err'] = (ref_header['PA_int_err'], 'Integrated polarization angle error')
#Crop Data to mask #Crop Data to mask
if data_mask.shape != (1,1):
I_stokes = I_stokes[vertex[0]:vertex[1],vertex[2]:vertex[3]] I_stokes = I_stokes[vertex[0]:vertex[1],vertex[2]:vertex[3]]
Q_stokes = Q_stokes[vertex[0]:vertex[1],vertex[2]:vertex[3]] Q_stokes = Q_stokes[vertex[0]:vertex[1],vertex[2]:vertex[3]]
U_stokes = U_stokes[vertex[0]:vertex[1],vertex[2]:vertex[3]] U_stokes = U_stokes[vertex[0]:vertex[1],vertex[2]:vertex[3]]
@@ -156,7 +158,8 @@ def save_Stokes(I_stokes, Q_stokes, U_stokes, Stokes_cov, P, debiased_P, s_P,
new_Stokes_cov[i,j] = Stokes_cov[i,j][vertex[0]:vertex[1],vertex[2]:vertex[3]] new_Stokes_cov[i,j] = Stokes_cov[i,j][vertex[0]:vertex[1],vertex[2]:vertex[3]]
Stokes_cov = new_Stokes_cov Stokes_cov = new_Stokes_cov
data_mask = data_mask[vertex[0]:vertex[1],vertex[2]:vertex[3]].astype(float, copy=False) data_mask = data_mask[vertex[0]:vertex[1],vertex[2]:vertex[3]]
data_mask = data_mask.astype(float, copy=False)
#Create HDUList object #Create HDUList object
hdul = fits.HDUList([]) hdul = fits.HDUList([])

View File

@@ -13,8 +13,8 @@ from copy import deepcopy
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle from matplotlib.patches import Rectangle
from matplotlib.widgets import RectangleSelector, Button, Slider from matplotlib.path import Path
from matplotlib.transforms import Bbox from matplotlib.widgets import RectangleSelector, Button, Slider, TextBox, LassoSelector
import matplotlib.font_manager as fm import matplotlib.font_manager as fm
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar, AnchoredDirectionArrows from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar, AnchoredDirectionArrows
from astropy.wcs import WCS from astropy.wcs import WCS
@@ -682,44 +682,72 @@ class crop_map(object):
""" """
Class to interactively crop a map to desired Region of Interest Class to interactively crop a map to desired Region of Interest
""" """
def __init__(self, hdul): def __init__(self, hdul, fig=None, ax=None):
#Get data #Get data
self.cropped=False
self.hdul = hdul self.hdul = hdul
self.header = deepcopy(self.hdul[0].header) self.header = deepcopy(self.hdul[0].header)
self.wcs = WCS(self.header).deepcopy() self.wcs = WCS(self.header).deepcopy()
self.data = deepcopy(self.hdul[0].data) self.data = deepcopy(self.hdul[0].data)
try: try:
convert_flux = self.header['photflam'] self.convert_flux = self.header['photflam']
except KeyError: except KeyError:
convert_flux = 1. self.convert_flux = 1.
#Plot the map #Plot the map
plt.rcParams.update({'font.size': 16}) plt.rcParams.update({'font.size': 12})
plt.ioff()
if fig is None:
self.fig = plt.figure(figsize=(15,15)) self.fig = plt.figure(figsize=(15,15))
self.fig.suptitle("Click and drag to crop to desired Region of Interest.")
else:
self.fig = fig
if ax is None:
self.ax = self.fig.add_subplot(111, projection=self.wcs) self.ax = self.fig.add_subplot(111, projection=self.wcs)
self.ax.set_facecolor('k') self.mask_alpha=1.
self.fig.subplots_adjust(hspace=0, wspace=0, right=0.9) #Selection button
cbar_ax = self.fig.add_axes([0.95, 0.12, 0.01, 0.75]) self.axapply = self.fig.add_axes([0.80, 0.01, 0.1, 0.04])
self.bapply = Button(self.axapply, 'Apply')
self.axreset = self.fig.add_axes([0.60, 0.01, 0.1, 0.04])
self.breset = Button(self.axreset, 'Reset')
self.embedded = False
else:
self.ax = ax
self.mask_alpha = 0.75
self.rect_selector = RectangleSelector(self.ax, self.onselect_crop,
drawtype='box', button=[1], interactive=True)
self.embedded = True
self.display()
plt.ion()
self.ax.plot(*self.wcs.wcs.crpix, 'r+')
self.extent = np.array([0.,self.data.shape[0],0., self.data.shape[1]]) self.extent = np.array([0.,self.data.shape[0],0., self.data.shape[1]])
self.center = np.array(self.data.shape)/2 self.center = np.array(self.data.shape)/2
self.RSextent = deepcopy(self.extent) self.RSextent = deepcopy(self.extent)
self.RScenter = deepcopy(self.center) self.RScenter = deepcopy(self.center)
vmin, vmax = 0., np.max(self.data[self.data > 0.]*convert_flux) plt.show()
im = self.ax.imshow(self.data*convert_flux, vmin=vmin, vmax=vmax, aspect='auto', cmap='inferno', alpha=1., origin='lower')
cbar = plt.colorbar(im, cax=cbar_ax, label=r"$F_{\lambda}$ [$ergs \cdot cm^{-2} \cdot s^{-1} \cdot \AA^{-1}$]")
#Selection button def display(self, data=None, wcs=None, convert_flux=None):
self.axapply = self.fig.add_axes([0.80, 0.01, 0.1, 0.04]) if data is None:
self.bapply = Button(self.axapply, 'Apply crop') data = self.data
self.axreset = self.fig.add_axes([0.60, 0.01, 0.1, 0.04]) if wcs is None:
self.breset = Button(self.axreset, 'Reset') wcs = self.wcs
if convert_flux is None:
convert_flux = self.convert_flux
self.ax.set_title("Click and drag to crop to desired Region of Interest.") vmin, vmax = 0., np.max(data[data > 0.]*convert_flux)
if hasattr(self, 'im'):
self.im.remove()
self.im = self.ax.imshow(data*convert_flux, vmin=vmin, vmax=vmax, aspect='auto', cmap='inferno', alpha=self.mask_alpha, origin='lower')
if hasattr(self, 'cr'):
self.cr[0].set_data(*wcs.wcs.crpix)
else:
self.cr = self.ax.plot(*wcs.wcs.crpix, 'r+')
self.fig.canvas.draw_idle()
return self.im
@property
def crpix_in_RS(self): def crpix_in_RS(self):
crpix = self.wcs.wcs.crpix crpix = self.wcs.wcs.crpix
x_lim, y_lim = self.RSextent[:2], self.RSextent[2:] x_lim, y_lim = self.RSextent[:2], self.RSextent[2:]
@@ -729,36 +757,59 @@ class crop_map(object):
return False return False
def reset_crop(self, event): def reset_crop(self, event):
self.ax.reset_wcs(self.wcs)
if hasattr(self, 'hdul_crop'):
del self.hdul_crop, self.data_crop
self.display()
if self.fig.canvas.manager.toolbar.mode == '':
self.rect_selector = RectangleSelector(self.ax, self.onselect_crop,
drawtype='box', button=[1], interactive=True)
self.RSextent = deepcopy(self.extent) self.RSextent = deepcopy(self.extent)
self.RScenter = deepcopy(self.center) self.RScenter = deepcopy(self.center)
self.ax.set_xlim(*self.extent[:2]) self.ax.set_xlim(*self.extent[:2])
self.ax.set_ylim(*self.extent[2:]) self.ax.set_ylim(*self.extent[2:])
self.rect_selector.clear()
self.fig.canvas.draw_idle() self.fig.canvas.draw_idle()
def onselect_crop(self, eclick, erelease) -> None: def onselect_crop(self, eclick, erelease) -> None:
# Obtain (xmin, xmax, ymin, ymax) values # Obtain (xmin, xmax, ymin, ymax) values
self.RSextent = np.array(self.rect_selector.extents) self.RSextent = np.array(self.rect_selector.extents)
self.RScenter = np.array(self.rect_selector.center) self.RScenter = np.array(self.rect_selector.center)
if self.embedded:
self.apply_crop(erelease)
def apply_crop(self, event): def apply_crop(self, event):
if hasattr(self, 'hdul_crop'):
header = self.header_crop
data = self.data_crop
wcs = self.wcs_crop
else:
header = self.header
data = self.data
wcs = self.wcs
vertex = self.RSextent.astype(int) vertex = self.RSextent.astype(int)
shape = vertex[1::2] - vertex[0::2] shape = vertex[1::2] - vertex[0::2]
extent = np.array(self.im.get_extent())
shape_im = extent[1::2] - extent[0::2]
if (shape_im.astype(int) != shape).any() and (self.RSextent != self.extent).any():
#Update WCS and header in new cropped image #Update WCS and header in new cropped image
crpix = np.array(self.wcs.wcs.crpix) crpix = np.array(wcs.wcs.crpix)
self.wcs_crop = self.wcs.deepcopy() self.wcs_crop = wcs.deepcopy()
self.wcs_crop.array_shape = shape self.wcs_crop.array_shape = shape
if self.crpix_in_RS(): if self.crpix_in_RS:
self.wcs_crop.wcs.crpix = np.array(self.wcs_crop.wcs.crpix) - self.RSextent[::2] self.wcs_crop.wcs.crpix = np.array(self.wcs_crop.wcs.crpix) - self.RSextent[::2]
else: else:
self.wcs_crop.wcs.crval = self.wcs.wcs_pix2world([self.RScenter],1)[0] self.wcs_crop.wcs.crval = wcs.wcs_pix2world([self.RScenter],1)[0]
self.wcs_crop.wcs.crpix = self.RScenter-self.RSextent[::2] self.wcs_crop.wcs.crpix = self.RScenter-self.RSextent[::2]
# Crop dataset # Crop dataset
self.data_crop = self.data[vertex[2]:vertex[3], vertex[0]:vertex[1]] self.data_crop = deepcopy(data[vertex[2]:vertex[3], vertex[0]:vertex[1]])
#Write cropped map to new HDUList #Write cropped map to new HDUList
self.header_crop = deepcopy(self.header) self.header_crop = deepcopy(header)
self.header_crop.update(self.wcs_crop.to_header()) self.header_crop.update(self.wcs_crop.to_header())
self.hdul_crop = fits.HDUList([fits.PrimaryHDU(self.data_crop,self.header_crop)]) self.hdul_crop = fits.HDUList([fits.PrimaryHDU(self.data_crop,self.header_crop)])
@@ -767,26 +818,32 @@ class crop_map(object):
except KeyError: except KeyError:
convert_flux = 1. convert_flux = 1.
self.fig.clear() self.rect_selector.clear()
self.ax = self.fig.add_subplot(111,projection=self.wcs_crop) self.ax.reset_wcs(self.wcs_crop)
vmin, vmax = 0., np.max(self.data_crop[self.data_crop > 0.]*convert_flux) self.display(data=self.data_crop, wcs=self.wcs_crop, convert_flux=convert_flux)
im = self.ax.imshow(self.data_crop*convert_flux, vmin=vmin, vmax=vmax, aspect='auto', cmap='inferno', alpha=1., origin='lower')
self.ax.plot(*self.wcs_crop.wcs.crpix, 'r+')
cbar_ax = self.fig.add_axes([0.95, 0.12, 0.01, 0.75])
cbar = plt.colorbar(im, cax=cbar_ax, label=r"$F_{\lambda}$ [$ergs \cdot cm^{-2} \cdot s^{-1} \cdot \AA^{-1}$]")
xlim, ylim = self.RSextent[1::2]-self.RSextent[0::2] xlim, ylim = self.RSextent[1::2]-self.RSextent[0::2]
self.ax.set_xlim(0,xlim) self.ax.set_xlim(0,xlim)
self.ax.set_ylim(0,ylim) self.ax.set_ylim(0,ylim)
self.rect_selector.clear()
if self.fig.canvas.manager.toolbar.mode == '':
self.rect_selector = RectangleSelector(self.ax, self.onselect_crop,
drawtype='box', button=[1], interactive=True)
self.fig.canvas.draw_idle() self.fig.canvas.draw_idle()
def on_close(self, event) -> None:
if not hasattr(self, 'hdul_crop'):
self.hdul_crop = self.hdul
self.rect_selector.disconnect_events()
self.cropped = True
def crop(self) -> None: def crop(self) -> None:
if self.fig.canvas.manager.toolbar.mode == '': if self.fig.canvas.manager.toolbar.mode == '':
self.rect_selector = RectangleSelector(self.ax, self.onselect_crop, self.rect_selector = RectangleSelector(self.ax, self.onselect_crop,
drawtype='box', button=[1], interactive=True) drawtype='box', button=[1], interactive=True)
self.bapply.on_clicked(self.apply_crop) self.bapply.on_clicked(self.apply_crop)
self.breset.on_clicked(self.reset_crop) self.breset.on_clicked(self.reset_crop)
self.fig.canvas.mpl_connect('close_event', self.on_close)
plt.show() plt.show()
def writeto(self, filename): def writeto(self, filename):
@@ -802,17 +859,30 @@ class crop_Stokes(crop_map):
""" """
Redefine apply_crop method for the Stokes HDUList. Redefine apply_crop method for the Stokes HDUList.
""" """
self.hdul_crop = deepcopy(self.hdul) if hasattr(self, 'hdul_crop'):
hdul = self.hdul_crop
data = self.data_crop
wcs = self.wcs_crop
else:
hdul = self.hdul
data = self.data
wcs = self.wcs
vertex = self.RSextent.astype(int) vertex = self.RSextent.astype(int)
shape = vertex[1::2] - vertex[0::2] shape = vertex[1::2] - vertex[0::2]
extent = np.array(self.im.get_extent())
shape_im = extent[1::2] - extent[0::2]
if (shape_im.astype(int) != shape).any() and (self.RSextent != self.extent).any():
#Update WCS and header in new cropped image #Update WCS and header in new cropped image
crpix = np.array(self.wcs.wcs.crpix) self.hdul_crop = deepcopy(hdul)
self.wcs_crop = self.wcs.deepcopy() crpix = np.array(wcs.wcs.crpix)
self.wcs_crop = wcs.deepcopy()
self.wcs_crop.array_shape = shape self.wcs_crop.array_shape = shape
if self.crpix_in_RS(): if self.crpix_in_RS:
self.wcs_crop.wcs.crpix = np.array(self.wcs_crop.wcs.crpix) - self.RSextent[::2] self.wcs_crop.wcs.crpix = np.array(self.wcs_crop.wcs.crpix) - self.RSextent[::2]
else: else:
self.wcs_crop.wcs.crval = self.wcs.wcs_pix2world([self.RScenter],1)[0] self.wcs_crop.wcs.crval = wcs.wcs_pix2world([self.RScenter],1)[0]
self.wcs_crop.wcs.crpix = self.RScenter-self.RSextent[::2] self.wcs_crop.wcs.crpix = self.RScenter-self.RSextent[::2]
# Crop dataset # Crop dataset
@@ -821,10 +891,10 @@ class crop_Stokes(crop_map):
stokes_cov = np.zeros((3,3,shape[1],shape[0])) stokes_cov = np.zeros((3,3,shape[1],shape[0]))
for i in range(3): for i in range(3):
for j in range(3): for j in range(3):
stokes_cov[i,j] = dataset.data[i,j][vertex[2]:vertex[3], vertex[0]:vertex[1]] stokes_cov[i,j] = deepcopy(dataset.data[i,j][vertex[2]:vertex[3], vertex[0]:vertex[1]])
dataset.data = stokes_cov dataset.data = stokes_cov
else: else:
dataset.data = dataset.data[vertex[2]:vertex[3], vertex[0]:vertex[1]] dataset.data = deepcopy(dataset.data[vertex[2]:vertex[3], vertex[0]:vertex[1]])
dataset.header.update(self.wcs_crop.to_header()) dataset.header.update(self.wcs_crop.to_header())
try: try:
@@ -832,116 +902,341 @@ class crop_Stokes(crop_map):
except KeyError: except KeyError:
convert_flux = 1. convert_flux = 1.
data_crop = self.hdul_crop[0].data self.data_crop = self.hdul_crop[0].data
self.fig.clear() self.rect_selector.clear()
self.ax = self.fig.add_subplot(111,projection=self.wcs_crop) if not self.embedded:
vmin, vmax = 0., np.max(data_crop[data_crop > 0.]*convert_flux) self.ax.reset_wcs(self.wcs_crop)
im = self.ax.imshow(data_crop*convert_flux, vmin=vmin, vmax=vmax, aspect='auto', cmap='inferno', alpha=1., origin='lower') self.display(data=self.data_crop, wcs=self.wcs_crop, convert_flux=convert_flux)
self.ax.plot(*self.wcs_crop.wcs.crpix, 'r+')
cbar_ax = self.fig.add_axes([0.95, 0.12, 0.01, 0.75])
cbar = plt.colorbar(im, cax=cbar_ax, label=r"$F_{\lambda}$ [$ergs \cdot cm^{-2} \cdot s^{-1} \cdot \AA^{-1}$]")
xlim, ylim = self.RSextent[1::2]-self.RSextent[0::2] xlim, ylim = self.RSextent[1::2]-self.RSextent[0::2]
self.ax.set_xlim(0,xlim) self.ax.set_xlim(0,xlim)
self.ax.set_ylim(0,ylim) self.ax.set_ylim(0,ylim)
self.rect_selector.clear() else:
self.on_close(event)
if self.fig.canvas.manager.toolbar.mode == '':
self.rect_selector = RectangleSelector(self.ax, self.onselect_crop,
drawtype='box', button=[1], interactive=True)
self.fig.canvas.draw_idle() self.fig.canvas.draw_idle()
@property @property
def data_mask(self): def data_mask(self):
return self.hdul_crop[-1].data return self.hdul_crop[-1].data
class image_lasso_selector:
def __init__(self, img, fig=None, ax=None):
"""
img must have shape (X, Y)
"""
self.selected = False
self.img = img
self.vmin, self.vmax = 0., np.max(self.img[self.img>0.])
plt.ioff() # see https://github.com/matplotlib/matplotlib/issues/17013
if fig is None:
self.fig = plt.figure(figsize=(15,15))
else:
self.fig = fig
if ax is None:
self.ax = self.fig.gca()
self.mask_alpha = 1.
self.embedded = False
else:
self.ax = ax
self.mask_alpha = 0.1
self.embedded = True
self.displayed = self.ax.imshow(self.img, vmin=self.vmin, vmax=self.vmax, aspect='auto', cmap='inferno',alpha=self.mask_alpha)
plt.ion()
lineprops = {'color': 'grey', 'linewidth': 1, 'alpha': 0.8}
self.lasso = LassoSelector(self.ax, self.onselect,props=lineprops, useblit=False)
self.lasso.set_visible(True)
pix_x = np.arange(self.img.shape[0])
pix_y = np.arange(self.img.shape[1])
xv, yv = np.meshgrid(pix_y,pix_x)
self.pix = np.vstack( (xv.flatten(), yv.flatten()) ).T
self.fig.canvas.mpl_connect('close_event', self.on_close)
plt.show()
def on_close(self, event=None) -> None:
if not hasattr(self, 'mask'):
self.mask = np.zeros(self.img.shape[:2],dtype=bool)
self.lasso.disconnect_events()
self.selected = True
def onselect(self, verts):
self.verts = verts
p = Path(verts)
self.indices = p.contains_points(self.pix, radius=0).reshape(self.img.shape[:2])
self.update_mask()
def update_mask(self):
self.displayed.remove()
self.displayed = self.ax.imshow(self.img, vmin=self.vmin, vmax=self.vmax, aspect='auto', cmap='inferno',alpha=self.mask_alpha)
array = self.displayed.get_array().data
self.mask = np.zeros(self.img.shape[:2],dtype=bool)
self.mask[self.indices] = True
if hasattr(self, 'cont'):
for coll in self.cont.collections:
coll.remove()
self.cont = self.ax.contour(self.mask.astype(float),levels=[0.5], colors='white', linewidths=1)
if not self.embedded:
self.displayed.set_data(array)
self.fig.canvas.draw_idle()
else:
self.on_close()
class pol_map(object): class pol_map(object):
""" """
Class to interactively study polarization maps. Class to interactively study polarization maps.
""" """
def __init__(self,Stokes, SNRp_cut=3., SNRi_cut=30.): def __init__(self,Stokes, SNRp_cut=3., SNRi_cut=30., selection=None):
self.Stokes = Stokes self.Stokes = deepcopy(Stokes)
self.wcs = deepcopy(WCS(Stokes[0].header))
self.SNRp_cut = SNRp_cut self.SNRp_cut = SNRp_cut
self.SNRi_cut = SNRi_cut self.SNRi_cut = SNRi_cut
self.SNRi = deepcopy(self.SNRi_cut) self.SNRi = deepcopy(self.SNRi_cut)
self.SNRp = deepcopy(self.SNRp_cut) self.SNRp = deepcopy(self.SNRp_cut)
self.region = None self.region = None
self.data = None
self.display_selection = selection
#Get data #Get data
self.targ = self.Stokes[0].header['targname']
self.pivot_wav = self.Stokes[0].header['photplam'] self.pivot_wav = self.Stokes[0].header['photplam']
self.convert_flux = self.Stokes[0].header['photflam'] self.convert_flux = self.Stokes[0].header['photflam']
self.I = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='I_stokes' for i in range(len(Stokes))])].data
self.Q = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Q_stokes' for i in range(len(Stokes))])].data
self.U = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='U_stokes' for i in range(len(Stokes))])].data
self.IQU_cov = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='IQU_cov_matrix' for i in range(len(Stokes))])].data
self.P = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Pol_deg_debiased' for i in range(len(Stokes))])].data
self.s_P = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Pol_deg_err' for i in range(len(Stokes))])].data
self.PA = self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Pol_ang' for i in range(len(Stokes))])].data
#Create figure #Create figure
fontprops = fm.FontProperties(size=16) plt.rcParams.update({'font.size': 10})
self.fig = plt.figure(figsize=(15,15)) self.fig = plt.figure(figsize=(15,15))
self.fig.subplots_adjust(hspace=0, wspace=0, right=0.9) self.fig.subplots_adjust(hspace=0, wspace=0, right=0.88)
self.ax = self.fig.add_subplot(111,projection=self.wcs) self.ax = self.fig.add_subplot(111,projection=self.wcs)
self.ax.set_facecolor('black') self.ax_cosmetics()
self.cbar_ax = self.fig.add_axes([0.925, 0.12, 0.01, 0.75])
self.ax.coords.grid(True, color='white', ls='dotted', alpha=0.5) #Display selected data (Default to total flux)
self.ax.coords[0].set_axislabel('Right Ascension (J2000)') self.display()
self.ax.coords[0].set_axislabel_position('t')
self.ax.coords[0].set_ticklabel_position('t')
self.ax.coords[1].set_axislabel('Declination (J2000)')
self.ax.coords[1].set_axislabel_position('l')
self.ax.coords[1].set_ticklabel_position('l')
self.ax.axis('equal')
#Display total flux
im = self.ax.imshow(self.I*self.convert_flux, vmin=0., vmax=self.I[self.I > 0.].max()*self.convert_flux, aspect='auto', cmap='inferno')
cbar_ax = self.fig.add_axes([0.95, 0.12, 0.01, 0.75])
cbar = plt.colorbar(im, cax=cbar_ax, label=r"$F_{\lambda}$ [$ergs \cdot cm^{-2} \cdot s^{-1} \cdot \AA^{-1}$]")
#Display polarization vectors in SNR_cut #Display polarization vectors in SNR_cut
self.pol_vector() self.pol_vector()
#Display scales and orientation
px_size = self.wcs.wcs.cdelt[0]*3600.
px_sc = AnchoredSizeBar(self.ax.transData, 1./px_size, '1 arcsec', 3, pad=0.5, sep=5, borderpad=0.5, frameon=False, size_vertical=0.005, color='white', fontproperties=fontprops)
self.ax.add_artist(px_sc)
pol_sc = AnchoredSizeBar(self.ax.transData, 2., r"$P$= 100%", 4, pad=0.5, sep=5, borderpad=0.5, frameon=False, size_vertical=0.005, color='white', fontproperties=fontprops)
self.ax.add_artist(pol_sc)
north_dir = AnchoredDirectionArrows(self.ax.transAxes, "E", "N", length=-0.08, fontsize=0.025, loc=1, aspect_ratio=-1, sep_y=0.01, sep_x=0.01, back_length=0., head_length=10., head_width=10., angle=-self.Stokes[0].header['orientat'], color='white', text_props={'ec': None, 'fc': 'w', 'alpha': 1, 'lw': 0.4}, arrow_props={'ec': None,'fc':'w','alpha': 1,'lw': 1})
self.ax.add_artist(north_dir)
#Display integrated values in ROI #Display integrated values in ROI
self.pol_int self.pol_int()
#Set axes for sliders (SNRp_cut, SNRi_cut) #Set axes for sliders (SNRp_cut, SNRi_cut)
ax_I_cut = self.fig.add_axes([0.125, 0.080, 0.35, 0.01]) ax_I_cut = self.fig.add_axes([0.125, 0.080, 0.35, 0.01])
ax_P_cut = self.fig.add_axes([0.125, 0.055, 0.35, 0.01]) ax_P_cut = self.fig.add_axes([0.125, 0.055, 0.35, 0.01])
ax_reset = self.fig.add_axes([0.125, 0.020, 0.05, 0.02]) ax_snr_reset = self.fig.add_axes([0.125, 0.020, 0.05, 0.02])
SNRi_max = np.max(self.I[self.IQU_cov[0,0]>0.]/np.sqrt(self.IQU_cov[0,0][self.IQU_cov[0,0]>0.])) SNRi_max = np.max(self.I[self.IQU_cov[0,0]>0.]/np.sqrt(self.IQU_cov[0,0][self.IQU_cov[0,0]>0.]))
SNRp_max = np.max(self.P[self.s_P>0.]/self.s_P[self.s_P > 0.]) SNRp_max = np.max(self.P[self.s_P>0.]/self.s_P[self.s_P > 0.])
s_I_cut = Slider(ax_I_cut,r"$SNR^{I}_{cut}$",1.,SNRi_max,valstep=1,valinit=self.SNRi_cut) s_I_cut = Slider(ax_I_cut,r"$SNR^{I}_{cut}$",1.,int(SNRi_max*0.95),valstep=1,valinit=self.SNRi_cut)
s_P_cut = Slider(ax_P_cut,r"$SNR^{P}_{cut}$",1.,SNRp_max,valstep=1,valinit=self.SNRp_cut) s_P_cut = Slider(ax_P_cut,r"$SNR^{P}_{cut}$",1.,int(SNRp_max*0.95),valstep=1,valinit=self.SNRp_cut)
b_reset = Button(ax_reset,"Reset") b_snr_reset = Button(ax_snr_reset,"Reset")
def update_snri(val): def update_snri(val):
self.SNRi = val self.SNRi = val
self.quiver.remove()
self.pol_vector() self.pol_vector()
self.fig.canvas.draw_idle() self.fig.canvas.draw_idle()
def update_snrp(val): def update_snrp(val):
self.SNRp = val self.SNRp = val
self.quiver.remove()
self.pol_vector() self.pol_vector()
self.fig.canvas.draw_idle() self.fig.canvas.draw_idle()
def reset(event): def reset_snr(event):
s_I_cut.reset() s_I_cut.reset()
s_P_cut.reset() s_P_cut.reset()
s_I_cut.on_changed(update_snri) s_I_cut.on_changed(update_snri)
s_P_cut.on_changed(update_snrp) s_P_cut.on_changed(update_snrp)
b_reset.on_clicked(reset) b_snr_reset.on_clicked(reset_snr)
plt.show(block=True) #Set axe for ROI selection
ax_select = self.fig.add_axes([0.55, 0.070, 0.05, 0.02])
ax_roi_reset = self.fig.add_axes([0.605, 0.070, 0.05, 0.02])
b_select = Button(ax_select,"Select")
self.selected = False
b_roi_reset = Button(ax_roi_reset,"Reset")
def select_roi(event):
if self.data is None:
self.data = self.Stokes[0].data
if self.selected:
self.selected = False
self.region = deepcopy(self.select_instance.mask.astype(bool))
self.select_instance.displayed.remove()
for coll in self.select_instance.cont.collections:
coll.remove()
self.select_instance.lasso.set_active(False)
self.set_data_mask(deepcopy(self.region))
self.pol_int()
else:
self.selected = True
self.region = None
self.select_instance = image_lasso_selector(self.data, fig=self.fig, ax=self.ax)
self.select_instance.lasso.set_active(True)
k = 0
while not self.select_instance.selected and k<60:
self.fig.canvas.start_event_loop(timeout=1)
k+=1
select_roi(event)
self.fig.canvas.draw_idle()
def reset_roi(event):
self.region = None
self.pol_int()
self.fig.canvas.draw_idle()
b_select.on_clicked(select_roi)
b_roi_reset.on_clicked(reset_roi)
#Set axe for crop Stokes
ax_crop = self.fig.add_axes([0.70, 0.070, 0.05, 0.02])
ax_crop_reset = self.fig.add_axes([0.755, 0.070, 0.05, 0.02])
b_crop = Button(ax_crop,"Crop")
self.cropped = False
b_crop_reset = Button(ax_crop_reset,"Reset")
def crop(event):
if self.cropped:
self.cropped = False
self.crop_instance.im.remove()
self.crop_instance.cr.pop(0).remove()
self.crop_instance.rect_selector.set_active(False)
self.Stokes = self.crop_instance.hdul_crop
self.region = deepcopy(self.data_mask.astype(bool))
self.pol_int()
self.ax.reset_wcs(self.wcs)
self.ax_cosmetics()
self.display()
self.pol_vector()
else:
self.cropped = True
self.crop_instance = crop_Stokes(self.Stokes, fig=self.fig, ax=self.ax)
self.crop_instance.rect_selector.set_active(True)
k = 0
while not self.crop_instance.cropped and k<60:
self.fig.canvas.start_event_loop(timeout=1)
k+=1
crop(event)
self.fig.canvas.draw_idle()
def reset_crop(event):
self.Stokes = deepcopy(Stokes)
self.region = None
self.pol_int()
self.ax.reset_wcs(self.wcs)
self.ax_cosmetics()
self.display()
self.pol_vector()
b_crop.on_clicked(crop)
b_crop_reset.on_clicked(reset_crop)
#Set axe for saving plot
ax_save = self.fig.add_axes([0.850, 0.070, 0.05, 0.02])
b_save = Button(ax_save, "Save")
ax_text_save = self.fig.add_axes([0.3, 0.020, 0.5, 0.025],visible=False)
text_box = TextBox(ax_text_save, "Save to:", initial='')
def saveplot(event):
ax_text_save.set(visible=True)
ax_snr_reset.set(visible=False)
ax_save.set(visible=False)
self.fig.canvas.draw_idle()
b_save.on_clicked(saveplot)
def submit(expression):
ax_text_save.set(visible=False)
if expression != '':
save_fig = plt.figure(figsize=(15,15))
save_ax = save_fig.add_subplot(111, projection=self.wcs)
self.ax_cosmetics(ax=save_ax)
self.display(fig=save_fig,ax=save_ax)
self.pol_vector(fig=save_fig,ax=save_ax)
self.pol_int(fig=save_fig,ax=save_ax)
save_fig.suptitle(r"{0:s} with $SNR_{{p}} \geq$ {1:d} and $SNR_{{I}} \geq$ {2:d}".format(self.targ, int(self.SNRp), int(self.SNRi)))
if not expression[-4:] in ['.png', '.jpg']:
expression += '.png'
save_fig.savefig(expression, bbox_inches='tight', dpi=200)
plt.close(save_fig)
text_box.set_val('')
ax_snr_reset.set(visible=True)
ax_save.set(visible=True)
self.fig.canvas.draw_idle()
text_box.on_submit(submit)
#Set axes for display buttons
ax_tf = self.fig.add_axes([0.925, 0.085, 0.05, 0.02])
ax_pf = self.fig.add_axes([0.925, 0.065, 0.05, 0.02])
ax_p = self.fig.add_axes([0.925, 0.045, 0.05, 0.02])
ax_snri = self.fig.add_axes([0.925, 0.025, 0.05, 0.02])
ax_snrp = self.fig.add_axes([0.925, 0.005, 0.05, 0.02])
b_tf = Button(ax_tf,r"$F_{\lambda}$")
b_pf = Button(ax_pf,r"$F_{\lambda} \cdot P$")
b_p = Button(ax_p,r"$P$")
b_snri = Button(ax_snri,r"$I / \sigma_{I}$")
b_snrp = Button(ax_snrp,r"$P / \sigma_{P}$")
def d_tf(event):
self.display_selection = 'total_flux'
self.display()
b_tf.on_clicked(d_tf)
def d_pf(event):
self.display_selection = 'pol_flux'
self.display()
b_pf.on_clicked(d_pf)
def d_p(event):
self.display_selection = 'pol_deg'
self.display()
b_p.on_clicked(d_p)
def d_snri(event):
self.display_selection = 'snri'
self.display()
b_snri.on_clicked(d_snri)
def d_snrp(event):
self.display_selection = 'snrp'
self.display()
b_snrp.on_clicked(d_snrp)
plt.show()
@property
def wcs(self):
return deepcopy(WCS(self.Stokes[0].header))
@property
def I(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='I_stokes' for i in range(len(self.Stokes))])].data
@property
def Q(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Q_stokes' for i in range(len(self.Stokes))])].data
@property
def U(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='U_stokes' for i in range(len(self.Stokes))])].data
@property
def IQU_cov(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='IQU_cov_matrix' for i in range(len(self.Stokes))])].data
@property
def P(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Pol_deg_debiased' for i in range(len(self.Stokes))])].data
@property
def s_P(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Pol_deg_err' for i in range(len(self.Stokes))])].data
@property
def PA(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Pol_ang' for i in range(len(self.Stokes))])].data
@property
def data_mask(self):
return self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Data_mask' for i in range(len(self.Stokes))])].data
def set_data_mask(self, mask):
self.Stokes[np.argmax([self.Stokes[i].header['datatype']=='Data_mask' for i in range(len(self.Stokes))])].data = mask.astype(float)
@property @property
def cut(self): def cut(self):
@@ -951,17 +1246,105 @@ class pol_map(object):
SNRi_mask[s_I > 0.] = self.I[s_I > 0.] / s_I[s_I > 0.] > self.SNRi SNRi_mask[s_I > 0.] = self.I[s_I > 0.] / s_I[s_I > 0.] > self.SNRi
return np.logical_and(SNRi_mask,SNRp_mask) return np.logical_and(SNRi_mask,SNRp_mask)
def pol_vector(self): def ax_cosmetics(self, ax=None):
if ax is None:
ax = self.ax
ax.set_facecolor('black')
ax.coords.grid(True, color='white', ls='dotted', alpha=0.5)
ax.coords[0].set_axislabel('Right Ascension (J2000)')
ax.coords[0].set_axislabel_position('t')
ax.coords[0].set_ticklabel_position('t')
ax.coords[1].set_axislabel('Declination (J2000)')
ax.coords[1].set_axislabel_position('l')
ax.coords[1].set_ticklabel_position('l')
ax.axis('equal')
#Display scales and orientation
fontprops = fm.FontProperties(size=14)
px_size = self.wcs.wcs.cdelt[0]*3600.
if hasattr(self,'px_sc'):
self.px_sc.remove()
self.px_sc = AnchoredSizeBar(ax.transData, 1./px_size, '1 arcsec', 3, pad=0.5, sep=5, borderpad=0.5, frameon=False, size_vertical=0.005, color='white', fontproperties=fontprops)
ax.add_artist(self.px_sc)
if hasattr(self,'pol_sc'):
self.pol_sc.remove()
self.pol_sc = AnchoredSizeBar(ax.transData, 2., r"$P$= 100%", 4, pad=0.5, sep=5, borderpad=0.5, frameon=False, size_vertical=0.005, color='white', fontproperties=fontprops)
ax.add_artist(self.pol_sc)
if hasattr(self,'north_dir'):
self.north_dir.remove()
self.north_dir = AnchoredDirectionArrows(ax.transAxes, "E", "N", length=-0.08, fontsize=0.025, loc=1, aspect_ratio=-1, sep_y=0.01, sep_x=0.01, back_length=0., head_length=10., head_width=10., angle=-self.Stokes[0].header['orientat'], color='white', text_props={'ec': None, 'fc': 'w', 'alpha': 1, 'lw': 0.4}, arrow_props={'ec': None,'fc':'w','alpha': 1,'lw': 1})
ax.add_artist(self.north_dir)
def display(self, fig=None, ax=None):
if self.display_selection is None:
self.display_selection = "total_flux"
if self.display_selection.lower() in ['total_flux']:
self.data = self.I*self.convert_flux
vmin, vmax = 0., np.max(self.data[self.data > 0.])
label = r"$F_{\lambda}$ [$ergs \cdot cm^{-2} \cdot s^{-1} \cdot \AA^{-1}$]"
elif self.display_selection.lower() in ['pol_flux']:
self.data = self.I*self.convert_flux*self.P
vmin, vmax = 0., np.max(self.data[self.data > 0.])
label = r"$F_{\lambda} \cdot P$ [$ergs \cdot cm^{-2} \cdot s^{-1} \cdot \AA^{-1}$]"
elif self.display_selection.lower() in ['pol_deg']:
self.data = self.P*100.
vmin, vmax = 0., np.max(self.data[self.data > 0.])
label = r"$P$ [%]"
elif self.display_selection.lower() in ['snri']:
s_I = np.sqrt(self.IQU_cov[0,0])
SNRi = np.zeros(self.I.shape)
SNRi[s_I > 0.] = self.I[s_I > 0.]/s_I[s_I > 0.]
self.data = SNRi
vmin, vmax = 0., np.max(self.data[self.data > 0.])
label = r"$I_{Stokes}/\sigma_{I}$"
elif self.display_selection.lower() in ['snrp']:
SNRp = np.zeros(self.P.shape)
SNRp[self.s_P > 0.] = self.P[self.s_P > 0.]/self.s_P[self.s_P > 0.]
self.data = SNRp
vmin, vmax = 0., np.max(self.data[self.data > 0.])
label = r"$P/\sigma_{P}$"
if fig is None:
fig = self.fig
if ax is None:
ax = self.ax
if hasattr(self, 'im'):
self.im.remove()
self.im = ax.imshow(self.data, vmin=vmin, vmax=vmax, aspect='auto', cmap='inferno')
ax.set_xlim(0,self.data.shape[1])
ax.set_ylim(0,self.data.shape[0])
self.cbar = plt.colorbar(self.im, cax=self.cbar_ax, label=label)
fig.canvas.draw_idle()
return self.im
else:
im = ax.imshow(self.data, vmin=vmin, vmax=vmax, aspect='auto', cmap='inferno')
ax.set_xlim(0,self.data.shape[1])
ax.set_ylim(0,self.data.shape[0])
plt.colorbar(im, pad=0.025, aspect=80, label=label)
fig.canvas.draw_idle()
def pol_vector(self, fig=None, ax=None):
P_cut = np.ones(self.P.shape)*np.nan P_cut = np.ones(self.P.shape)*np.nan
P_cut[self.cut] = self.P[self.cut] P_cut[self.cut] = self.P[self.cut]
X, Y = np.meshgrid(np.arange(self.I.shape[1]),np.arange(self.I.shape[0])) X, Y = np.meshgrid(np.arange(self.I.shape[1]),np.arange(self.I.shape[0]))
XY_U, XY_V = P_cut*np.cos(np.pi/2. + self.PA*np.pi/180.), P_cut*np.sin(np.pi/2. + self.PA*np.pi/180.) XY_U, XY_V = P_cut*np.cos(np.pi/2. + self.PA*np.pi/180.), P_cut*np.sin(np.pi/2. + self.PA*np.pi/180.)
self.quiver = self.ax.quiver(X, Y, XY_U, XY_V, units='xy', scale=0.5, scale_units='xy', pivot='mid', headwidth=0., headlength=0., headaxislength=0., width=0.1, color='white') if fig is None:
fig = self.fig
if ax is None:
ax = self.ax
if hasattr(self, 'quiver'):
self.quiver.remove()
self.quiver = ax.quiver(X, Y, XY_U, XY_V, units='xy', scale=0.5, scale_units='xy', pivot='mid', headwidth=0., headlength=0., headaxislength=0., width=0.1, color='white')
fig.canvas.draw_idle()
return self.quiver return self.quiver
else:
ax.quiver(X, Y, XY_U, XY_V, units='xy', scale=0.5, scale_units='xy', pivot='mid', headwidth=0., headlength=0., headaxislength=0., width=0.1, color='white')
fig.canvas.draw_idle()
@property def pol_int(self, fig=None, ax=None):
def pol_int(self):
if self.region is None: if self.region is None:
n_pix = self.I.size n_pix = self.I.size
s_I = np.sqrt(self.IQU_cov[0,0]) s_I = np.sqrt(self.IQU_cov[0,0])
@@ -996,4 +1379,24 @@ class pol_map(object):
PA_reg = princ_angle((90./np.pi)*np.arctan2(U_reg,Q_reg)) PA_reg = princ_angle((90./np.pi)*np.arctan2(U_reg,Q_reg))
PA_reg_err = (90./(np.pi*(Q_reg**2+U_reg**2)))*np.sqrt(U_reg**2*Q_reg_err**2 + Q_reg**2*U_reg_err**2 - 2.*Q_reg*U_reg*QU_reg_err) PA_reg_err = (90./(np.pi*(Q_reg**2+U_reg**2)))*np.sqrt(U_reg**2*Q_reg_err**2 + Q_reg**2*U_reg_err**2 - 2.*Q_reg*U_reg*QU_reg_err)
return self.ax.annotate(r"$F_{{\lambda}}^{{int}}$({0:.0f} $\AA$) = {1} $ergs \cdot cm^{{-2}} \cdot s^{{-1}} \cdot \AA^{{-1}}$".format(self.pivot_wav,sci_not(I_reg*self.convert_flux,I_reg_err*self.convert_flux,2))+"\n"+r"$P^{{int}}$ = {0:.1f} $\pm$ {1:.1f} %".format(P_reg*100.,P_reg_err*100.)+"\n"+r"$\theta_{{P}}^{{int}}$ = {0:.1f} $\pm$ {1:.1f} °".format(PA_reg,PA_reg_err), color='white', fontsize=12, xy=(0.01, 0.90), xycoords='axes fraction') if hasattr(self, 'cont'):
for coll in self.cont.collections:
coll.remove()
del self.cont
if fig is None:
fig = self.fig
if ax is None:
ax = self.ax
if hasattr(self, 'an_int'):
self.an_int.remove()
self.an_int = ax.annotate(r"$F_{{\lambda}}^{{int}}$({0:.0f} $\AA$) = {1} $ergs \cdot cm^{{-2}} \cdot s^{{-1}} \cdot \AA^{{-1}}$".format(self.pivot_wav,sci_not(I_reg*self.convert_flux,I_reg_err*self.convert_flux,2))+"\n"+r"$P^{{int}}$ = {0:.1f} $\pm$ {1:.1f} %".format(P_reg*100.,P_reg_err*100.)+"\n"+r"$\theta_{{P}}^{{int}}$ = {0:.1f} $\pm$ {1:.1f} °".format(PA_reg,PA_reg_err), color='white', fontsize=12, xy=(0.01, 0.90), xycoords='axes fraction')
if not self.region is None:
self.cont = ax.contour(self.region.astype(float),levels=[0.5], colors='white', linewidths=0.8)
fig.canvas.draw_idle()
return self.an_int
else:
ax.annotate(r"$F_{{\lambda}}^{{int}}$({0:.0f} $\AA$) = {1} $ergs \cdot cm^{{-2}} \cdot s^{{-1}} \cdot \AA^{{-1}}$".format(self.pivot_wav,sci_not(I_reg*self.convert_flux,I_reg_err*self.convert_flux,2))+"\n"+r"$P^{{int}}$ = {0:.1f} $\pm$ {1:.1f} %".format(P_reg*100.,P_reg_err*100.)+"\n"+r"$\theta_{{P}}^{{int}}$ = {0:.1f} $\pm$ {1:.1f} °".format(PA_reg,PA_reg_err), color='white', fontsize=12, xy=(0.01, 0.94), xycoords='axes fraction')
if not self.region is None:
ax.contour(self.region.astype(float),levels=[0.5], colors='white', linewidths=0.8)
fig.canvas.draw_idle()

View File

@@ -2,7 +2,7 @@
from astropy.io import fits from astropy.io import fits
import numpy as np import numpy as np
from copy import deepcopy from copy import deepcopy
from plots import overplot_radio from lib.plots import overplot_radio
Stokes_UV = fits.open("../../data/IC5063_x3nl030/IC5063_FOC_combine_FWHM020.fits") Stokes_UV = fits.open("../../data/IC5063_x3nl030/IC5063_FOC_combine_FWHM020.fits")
Stokes_18GHz = fits.open("../../data/IC5063_x3nl030/radio/IC5063.18GHz.fits") Stokes_18GHz = fits.open("../../data/IC5063_x3nl030/radio/IC5063.18GHz.fits")