pymakeplots 0.2.1__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/PKG-INFO +1 -1
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots/pymakeplots.py +170 -107
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots.egg-info/PKG-INFO +1 -1
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/setup.py +1 -1
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/LICENSE.md +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/README.md +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots/__init__.py +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots/sauron_colormap.py +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots.egg-info/SOURCES.txt +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots.egg-info/dependency_links.txt +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots.egg-info/requires.txt +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots.egg-info/top_level.txt +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/pymakeplots.egg-info/zip-safe +0 -0
- {pymakeplots-0.2.1 → pymakeplots-0.2.3}/setup.cfg +0 -0
|
@@ -12,8 +12,8 @@ from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
|
12
12
|
from matplotlib.patches import Ellipse,Rectangle
|
|
13
13
|
from matplotlib import cm
|
|
14
14
|
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
|
|
15
|
-
from matplotlib.offsetbox import AnchoredText
|
|
16
|
-
from mpl_toolkits.axes_grid1.anchored_artists import
|
|
15
|
+
from matplotlib.offsetbox import AnchoredText,AuxTransformBox, AnchoredOffsetbox
|
|
16
|
+
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar
|
|
17
17
|
from astropy.coordinates import ICRS
|
|
18
18
|
import matplotlib.gridspec as gridspec
|
|
19
19
|
from astropy.table import Table
|
|
@@ -23,6 +23,8 @@ import warnings
|
|
|
23
23
|
from spectral_cube import SpectralCube
|
|
24
24
|
from spectral_cube.utils import SpectralCubeWarning
|
|
25
25
|
warnings.filterwarnings(action='ignore', category=SpectralCubeWarning, append=True)
|
|
26
|
+
from scipy.stats import mode
|
|
27
|
+
|
|
26
28
|
|
|
27
29
|
def running_mean(x, N):
|
|
28
30
|
cumsum = np.cumsum(np.insert(x, 0, 0))
|
|
@@ -38,7 +40,7 @@ def rotateImage(img, angle, pivot):
|
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
class pymakeplots:
|
|
41
|
-
def __init__(self,cube_flat=None,pb=None,cube=None):
|
|
43
|
+
def __init__(self,cube_flat=None,pb=None,cube=None,rest_value=None,velocity_convention='radio'):
|
|
42
44
|
self.galname=None
|
|
43
45
|
self.gal_distance=None
|
|
44
46
|
self.posang=None
|
|
@@ -56,6 +58,7 @@ class pymakeplots:
|
|
|
56
58
|
self.pbcorr_cube_trim=None
|
|
57
59
|
self.mask_trim=None
|
|
58
60
|
self.bmaj=None
|
|
61
|
+
self.smoothmask_spatial=1.5
|
|
59
62
|
self.bmin=None
|
|
60
63
|
self.bpa=None
|
|
61
64
|
self.xcoord,self.ycoord,self.vcoord = None, None, None
|
|
@@ -65,6 +68,7 @@ class pymakeplots:
|
|
|
65
68
|
self.silent=False # rig for silent running if true
|
|
66
69
|
self.bardist=None
|
|
67
70
|
self.rmsfac=3
|
|
71
|
+
self.velocity_convention=velocity_convention
|
|
68
72
|
self.restfreq=None
|
|
69
73
|
self.repfreq=None
|
|
70
74
|
self.obj_ra=None
|
|
@@ -88,24 +92,27 @@ class pymakeplots:
|
|
|
88
92
|
self.flipped=False
|
|
89
93
|
self.make_square=True
|
|
90
94
|
self.useallpixels = False
|
|
95
|
+
self.suppress_subbeam_artifacts=False
|
|
91
96
|
#self.wcs=None
|
|
92
97
|
|
|
93
98
|
if (cube != None)&(pb==None)&(cube_flat==None):
|
|
94
99
|
# only one cube given
|
|
95
|
-
self.input_cube_nopb(cube)
|
|
100
|
+
self.input_cube_nopb(cube,rest_value=rest_value)
|
|
96
101
|
|
|
97
102
|
if (cube != None)&(pb!=None):
|
|
98
103
|
# pbcorred cube and pb given
|
|
99
|
-
self.input_cube_pbcorr(cube,pb)
|
|
104
|
+
self.input_cube_pbcorr(cube,pb,rest_value=rest_value)
|
|
100
105
|
|
|
101
106
|
if (cube_flat != None)&(pb!=None):
|
|
102
107
|
# flat cube and pb given
|
|
103
|
-
if np.any(self.pbcorr_cube
|
|
104
|
-
self.input_cube_flat(cube_flat,pb)
|
|
108
|
+
if np.any(self.pbcorr_cube == None): #check if the user gave all three cubes, in which case this call is redundant
|
|
109
|
+
self.input_cube_flat(cube_flat,pb,rest_value=rest_value)
|
|
105
110
|
|
|
106
111
|
if (cube != None)&(pb==None)&(cube_flat!=None):
|
|
107
112
|
# pbcorred cube and flat cube given
|
|
108
|
-
self.input_cube_pbcorr_and_flat(cube,cube_flat)
|
|
113
|
+
self.input_cube_pbcorr_and_flat(cube,cube_flat,rest_value=rest_value)
|
|
114
|
+
|
|
115
|
+
self.cube_for_param_guesses=self.flat_cube
|
|
109
116
|
|
|
110
117
|
def vsystrans_inv(self,val):
|
|
111
118
|
return val +self.vsys
|
|
@@ -129,21 +136,21 @@ class pymakeplots:
|
|
|
129
136
|
def beam_area(self):
|
|
130
137
|
return (np.pi*(self.bmaj/self.cellsize)*(self.bmin/self.cellsize))/(4*np.log(2))
|
|
131
138
|
|
|
132
|
-
def input_cube_pbcorr(self,path_to_pbcorr_cube,path_to_pb):
|
|
139
|
+
def input_cube_pbcorr(self,path_to_pbcorr_cube,path_to_pb,rest_value=None):
|
|
133
140
|
|
|
134
|
-
self.pbcorr_cube = self.read_primary_cube(path_to_pbcorr_cube)
|
|
141
|
+
self.pbcorr_cube = self.read_primary_cube(path_to_pbcorr_cube,rest_value=rest_value)
|
|
135
142
|
|
|
136
|
-
pb,hdr,_= self.read_in_a_cube(path_to_pb)
|
|
143
|
+
pb,hdr,_= self.read_in_a_cube(path_to_pb,rest_value=rest_value)
|
|
137
144
|
if self.flipped: pb=np.flip(pb,axis=2)
|
|
138
145
|
|
|
139
146
|
self.flat_cube = self.pbcorr_cube*pb
|
|
140
147
|
|
|
141
148
|
|
|
142
|
-
def input_cube_flat(self,path_to_flat_cube,path_to_pb):
|
|
149
|
+
def input_cube_flat(self,path_to_flat_cube,path_to_pb,rest_value=None):
|
|
143
150
|
|
|
144
|
-
self.flat_cube = self.read_primary_cube(path_to_flat_cube)
|
|
151
|
+
self.flat_cube = self.read_primary_cube(path_to_flat_cube,rest_value=rest_value)
|
|
145
152
|
|
|
146
|
-
pb,hdr,_= self.read_in_a_cube(path_to_pb)
|
|
153
|
+
pb,hdr,_= self.read_in_a_cube(path_to_pb,rest_value=rest_value)
|
|
147
154
|
if self.flipped: pb=np.flip(pb,axis=2)
|
|
148
155
|
|
|
149
156
|
self.pbcorr_cube = self.flat_cube.copy()*0.0
|
|
@@ -151,36 +158,41 @@ class pymakeplots:
|
|
|
151
158
|
|
|
152
159
|
|
|
153
160
|
|
|
154
|
-
def input_cube_nopb(self,path_to_cube):
|
|
161
|
+
def input_cube_nopb(self,path_to_cube,rest_value=None):
|
|
155
162
|
|
|
156
|
-
self.pbcorr_cube = self.read_primary_cube(path_to_cube)
|
|
163
|
+
self.pbcorr_cube = self.read_primary_cube(path_to_cube,rest_value=rest_value)
|
|
157
164
|
|
|
158
165
|
self.flat_cube = self.pbcorr_cube
|
|
159
166
|
|
|
160
167
|
|
|
161
168
|
|
|
162
|
-
def input_cube_pbcorr_and_flat(self,path_to_pbcorr_cube,path_to_flat_cube):
|
|
169
|
+
def input_cube_pbcorr_and_flat(self,path_to_pbcorr_cube,path_to_flat_cube,rest_value=None):
|
|
163
170
|
|
|
164
|
-
self.pbcorr_cube = self.read_primary_cube(path_to_pbcorr_cube)
|
|
171
|
+
self.pbcorr_cube = self.read_primary_cube(path_to_pbcorr_cube,rest_value=rest_value)
|
|
172
|
+
|
|
173
|
+
self.flat_cube,hdr,_ = self.read_in_a_cube(path_to_flat_cube,rest_value=rest_value)
|
|
165
174
|
|
|
166
|
-
self.flat_cube,hdr,_ = self.read_in_a_cube(path_to_flat_cube)
|
|
167
175
|
if self.flipped: self.flat_cube=np.flip(self.flat_cube,axis=2)
|
|
168
176
|
|
|
169
177
|
def smooth_mask(self,cube):
|
|
170
178
|
"""
|
|
171
179
|
Apply a Gaussian blur, using sigma = 4 in the velocity direction (seems to work best), to the uncorrected cube.
|
|
172
|
-
The mode 'nearest' seems to give the best results.
|
|
173
180
|
:return: (ndarray) mask to apply to the un-clipped cube
|
|
174
181
|
"""
|
|
175
|
-
sigma =
|
|
182
|
+
sigma = self.smoothmask_spatial * self.bmaj / self.cellsize
|
|
176
183
|
smooth_cube = ndimage.uniform_filter(cube, size=[sigma, sigma,4], mode='constant') # mode='nearest'
|
|
177
184
|
newrms= self.rms_estimate(smooth_cube,0,1)
|
|
178
185
|
self.cliplevel=self.rms*self.rmsfac
|
|
179
186
|
self.maskcliplevel=newrms*self.rmsfac
|
|
180
187
|
mask=(smooth_cube > self.maskcliplevel)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
|
|
189
|
+
if self.suppress_subbeam_artifacts:
|
|
190
|
+
label,cnt=ndimage.label(mask)#.sum(axis=2))
|
|
191
|
+
hist,lab=np.histogram(label,bins=np.arange(cnt+1))
|
|
192
|
+
beampix=(self.bmaj*self.bmin)/(self.cellsize**2)
|
|
193
|
+
for thelabel in lab[0:-1][hist<(beampix*self.suppress_subbeam_artifacts)]:
|
|
194
|
+
mask[label == thelabel]=False
|
|
195
|
+
|
|
184
196
|
return mask
|
|
185
197
|
|
|
186
198
|
|
|
@@ -322,34 +334,37 @@ class pymakeplots:
|
|
|
322
334
|
|
|
323
335
|
return x1,y1,v1,np.abs(cd1),cd3
|
|
324
336
|
|
|
325
|
-
def read_in_a_cube(self,path):
|
|
326
|
-
|
|
337
|
+
def read_in_a_cube(self,path,rest_value=None,primary=False):
|
|
338
|
+
|
|
339
|
+
scube=SpectralCube.read(path).with_spectral_unit(u.km/u.s, velocity_convention=self.velocity_convention,rest_value=rest_value)
|
|
327
340
|
|
|
328
|
-
hdr=
|
|
329
|
-
cube = np.squeeze(
|
|
341
|
+
hdr=scube.header
|
|
342
|
+
cube = np.squeeze(scube.filled_data[:,:,:].T).value #squeeze to remove singular stokes axis if present
|
|
330
343
|
cube[np.isfinite(cube) == False] = 0.0
|
|
331
344
|
try:
|
|
332
|
-
beamtab=
|
|
345
|
+
beamtab=scube.beam
|
|
333
346
|
except:
|
|
334
347
|
try:
|
|
335
|
-
beamtab=
|
|
348
|
+
beamtab=scube.beams[np.floor(scube.beams.size/2).astype(int)]
|
|
336
349
|
except:
|
|
337
350
|
#try flipping them
|
|
338
351
|
try:
|
|
339
|
-
beamvals=[
|
|
352
|
+
beamvals=[scube.header['bmaj'],scube.header['bmin']]
|
|
340
353
|
beamtab=Beam(major=np.max(beamvals)*u.deg,minor=np.min(beamvals)*u.deg,pa=self.spectralcube.header['bpa']*u.deg)
|
|
341
354
|
except:
|
|
342
|
-
beamtab=False
|
|
343
|
-
|
|
355
|
+
beamtab=False
|
|
356
|
+
if primary:
|
|
357
|
+
self.spectralcube=scube
|
|
358
|
+
self.repfreq=np.median(self.spectralcube.with_spectral_unit(u.GHz).spectral_axis)
|
|
344
359
|
return cube, hdr, beamtab
|
|
345
360
|
|
|
346
361
|
|
|
347
362
|
|
|
348
|
-
def read_primary_cube(self,cube):
|
|
363
|
+
def read_primary_cube(self,cube,rest_value=None):
|
|
349
364
|
|
|
350
365
|
### read in cube ###
|
|
351
|
-
datacube,hdr,beam = self.read_in_a_cube(cube)
|
|
352
|
-
|
|
366
|
+
datacube,hdr,beam = self.read_in_a_cube(cube,rest_value=rest_value,primary=True)
|
|
367
|
+
|
|
353
368
|
self.bmaj=beam.major.to(u.arcsec).value
|
|
354
369
|
self.bmin=beam.minor.to(u.arcsec).value
|
|
355
370
|
self.bpa=beam.pa.value
|
|
@@ -359,15 +374,9 @@ class pymakeplots:
|
|
|
359
374
|
self.galname=hdr['OBJECT']
|
|
360
375
|
except:
|
|
361
376
|
self.galname="Galaxy"
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
377
|
+
|
|
365
378
|
self.xcoord,self.ycoord,self.vcoord,self.cellsize,self.dv = self.get_header_coord_arrays(hdr)
|
|
366
|
-
#breakpoint()
|
|
367
|
-
|
|
368
|
-
|
|
369
379
|
|
|
370
|
-
|
|
371
380
|
if self.dv < 0:
|
|
372
381
|
datacube = np.flip(datacube,axis=2)
|
|
373
382
|
self.dv*=(-1)
|
|
@@ -475,7 +484,6 @@ class pymakeplots:
|
|
|
475
484
|
y2 = s*xpv + c*ypv
|
|
476
485
|
ax2.scatter(0,0,facecolors='none',edgecolors='k')
|
|
477
486
|
ax2.plot(x2,y2,'k--')
|
|
478
|
-
#breakpoint()
|
|
479
487
|
|
|
480
488
|
###### make summary box
|
|
481
489
|
|
|
@@ -503,6 +511,7 @@ class pymakeplots:
|
|
|
503
511
|
|
|
504
512
|
if pdf:
|
|
505
513
|
plt.savefig(self.galname+"_allplots.pdf", bbox_inches = 'tight')
|
|
514
|
+
plt.close()
|
|
506
515
|
else:
|
|
507
516
|
plt.show()
|
|
508
517
|
|
|
@@ -512,14 +521,14 @@ class pymakeplots:
|
|
|
512
521
|
def make_moments(self,axes=None,mom=[0,1,2],pdf=False,fits=False):
|
|
513
522
|
mom=np.array(mom)
|
|
514
523
|
self.fits=fits
|
|
515
|
-
|
|
516
|
-
if np.any(self.xc
|
|
524
|
+
|
|
525
|
+
if np.any(self.xc == None):
|
|
517
526
|
self.prepare_cubes()
|
|
518
527
|
|
|
519
528
|
self.set_rc_params()
|
|
520
529
|
|
|
521
530
|
nplots=mom.size
|
|
522
|
-
if np.any(axes
|
|
531
|
+
if np.any(axes == None):
|
|
523
532
|
if self.make_square:
|
|
524
533
|
fig,axes=plt.subplots(1,nplots,sharey=True,figsize=(7*nplots,7), gridspec_kw = {'wspace':0, 'hspace':0})
|
|
525
534
|
else:
|
|
@@ -586,19 +595,27 @@ class pymakeplots:
|
|
|
586
595
|
|
|
587
596
|
|
|
588
597
|
|
|
589
|
-
if self.chans2do == None:
|
|
590
|
-
# use the mask to try and guess the channels with signal.
|
|
591
|
-
mask_cumsum=np.nancumsum((self.pbcorr_cube > self.rmsfac*self.rms).sum(axis=0).sum(axis=0))
|
|
592
|
-
w_low,=np.where(mask_cumsum/np.max(mask_cumsum) < 0.02)
|
|
593
|
-
w_high,=np.where(mask_cumsum/np.max(mask_cumsum) > 0.98)
|
|
598
|
+
if np.any(self.chans2do == None):
|
|
594
599
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
600
|
+
clip=4.0
|
|
601
|
+
vwidth=4000
|
|
602
|
+
while vwidth > 1500:
|
|
603
|
+
clip+=0.1
|
|
604
|
+
# use the mask to try and guess the channels with signal.
|
|
605
|
+
mask_cumsum=np.nancumsum((self.cube_for_param_guesses > clip*self.rms).sum(axis=0).sum(axis=0))
|
|
606
|
+
w_low,=np.where(mask_cumsum/np.nanmax(mask_cumsum) < 0.05)
|
|
607
|
+
w_high,=np.where(mask_cumsum/np.nanmax(mask_cumsum) > 0.95)
|
|
608
|
+
|
|
609
|
+
if w_low.size ==0: w_low=np.array([0])
|
|
610
|
+
if w_high.size ==0: w_high=np.array([self.vcoord.size])
|
|
611
|
+
#breakpoint()
|
|
612
|
+
self.chans2do=[np.clip(np.max(w_low)-7,0,self.vcoord.size-1),np.clip(np.min(w_high)+7,0,self.vcoord.size-1)]
|
|
613
|
+
vwidth=self.vcoord[self.chans2do[1]]-self.vcoord[self.chans2do[0]]
|
|
614
|
+
#print(clip)
|
|
615
|
+
|
|
599
616
|
if self.vsys == None:
|
|
600
617
|
# use the cube to try and guess the vsys
|
|
601
|
-
self.vsys=((self.
|
|
618
|
+
self.vsys=((self.cube_for_param_guesses*(self.cube_for_param_guesses > self.rmsfac*self.rms)).sum(axis=0).sum(axis=0)*self.vcoord).sum()/((self.cube_for_param_guesses*(self.cube_for_param_guesses > self.rmsfac*self.rms)).sum(axis=0).sum(axis=0)).sum()
|
|
602
619
|
|
|
603
620
|
if self.imagesize != None:
|
|
604
621
|
if np.array(self.imagesize).size == 1:
|
|
@@ -612,7 +629,7 @@ class pymakeplots:
|
|
|
612
629
|
|
|
613
630
|
if self.spatial_trim == None:
|
|
614
631
|
|
|
615
|
-
mom0=(self.
|
|
632
|
+
mom0=(self.cube_for_param_guesses > self.rmsfac*self.rms).sum(axis=2)
|
|
616
633
|
mom0[mom0>0]=1
|
|
617
634
|
|
|
618
635
|
cumulative_x = np.nancumsum(mom0.sum(axis=1),dtype=float)
|
|
@@ -662,19 +679,16 @@ class pymakeplots:
|
|
|
662
679
|
return cb
|
|
663
680
|
|
|
664
681
|
|
|
665
|
-
def add_beam(self,ax):
|
|
682
|
+
def add_beam(self,ax):
|
|
683
|
+
aux_tr_box = AuxTransformBox(ax.transData)
|
|
684
|
+
|
|
666
685
|
if self.all_axes_physical:
|
|
667
|
-
|
|
668
|
-
loc='lower left', pad=0.5, borderpad=0.4,
|
|
669
|
-
frameon=False)
|
|
686
|
+
aux_tr_box.add_artist(Ellipse((0, 0), width=self.ang2kpctrans(self.bmaj), height=self.ang2kpctrans(self.bmin), angle=self.bpa+90,edgecolor='black',facecolor='none',linewidth=1.5))
|
|
670
687
|
else:
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
ae.ellipse.set_facecolor('none')
|
|
676
|
-
ae.ellipse.set_linewidth(1.5)
|
|
677
|
-
ax.add_artist(ae)
|
|
688
|
+
aux_tr_box.add_artist(Ellipse((0, 0), width=self.bmaj, height=self.bmin, angle=self.bpa+90,edgecolor='black',facecolor='none',linewidth=1.5))
|
|
689
|
+
box = AnchoredOffsetbox(child=aux_tr_box, loc='lower left', pad=0.5, borderpad=0.4,frameon=False)
|
|
690
|
+
ax.add_artist(box)
|
|
691
|
+
|
|
678
692
|
|
|
679
693
|
|
|
680
694
|
|
|
@@ -819,12 +833,13 @@ class pymakeplots:
|
|
|
819
833
|
mom2[i,j]=np.sqrt(np.sum(np.abs(self.pbcorr_cube_trim[i,j,:]*self.mask_trim[i,j,:]) * (self.vcoord_trim - mom1[i,j]) ** 2, axis=0) / np.sum(abs(self.pbcorr_cube_trim[i,j]*self.mask_trim[i,j,:]), axis=0))
|
|
820
834
|
|
|
821
835
|
if self.maxvdisp == None:
|
|
822
|
-
self.maxvdisp=np.ceil(np.clip(np.nanstd(mom2)*4,
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
836
|
+
self.maxvdisp=np.ceil(np.clip(np.nanstd(mom2)*4,20,np.nanmax(mom2))/10.)*10.
|
|
837
|
+
else:
|
|
838
|
+
self.maxvdisp=np.ceil(np.clip(np.nanstd(mom2)*4,20,self.maxvdisp)/10.)*10.
|
|
839
|
+
if np.isfinite(self.maxvdisp)==False:
|
|
840
|
+
self.maxvdisp=50.
|
|
841
|
+
#breakpoint()
|
|
826
842
|
mom2levs=np.linspace(0,self.maxvdisp,10)
|
|
827
|
-
|
|
828
843
|
im1=ax1.contourf(self.xc,self.yc,mom2.T,levels=mom2levs,cmap=sauron,vmax=self.maxvdisp)
|
|
829
844
|
|
|
830
845
|
if self.all_axes_physical:
|
|
@@ -844,7 +859,7 @@ class pymakeplots:
|
|
|
844
859
|
vticks=np.arange(0,5)*dvticks
|
|
845
860
|
|
|
846
861
|
cb=self.colorbar(im1,ticks=vticks)
|
|
847
|
-
cb.set_label(
|
|
862
|
+
cb.set_label('$\\sigma_{obs}$ (km s$^{-1}$)')
|
|
848
863
|
|
|
849
864
|
|
|
850
865
|
self.add_beam(ax1)
|
|
@@ -955,10 +970,10 @@ class pymakeplots:
|
|
|
955
970
|
|
|
956
971
|
def make_pvd(self,axes=None,fits=False,pdf=False):
|
|
957
972
|
self.fits=fits
|
|
958
|
-
if np.any(self.xc
|
|
973
|
+
if np.any(self.xc == None):
|
|
959
974
|
self.prepare_cubes()
|
|
960
975
|
|
|
961
|
-
if np.any(axes
|
|
976
|
+
if np.any(axes == None):
|
|
962
977
|
self.set_rc_params(mult=0.75)
|
|
963
978
|
fig,axes=plt.subplots(1,figsize=(7,5))
|
|
964
979
|
outsideaxis=0
|
|
@@ -969,32 +984,67 @@ class pymakeplots:
|
|
|
969
984
|
if self.posang==None:
|
|
970
985
|
# try fitting the moment one to get the kinematic pa
|
|
971
986
|
if not self.silent: print("No position angle given, estimating using the observed moment one.")
|
|
972
|
-
mom0=(self.
|
|
987
|
+
mom0=(self.flat_cube_trim*self.mask_trim).sum(axis=2)
|
|
973
988
|
mom1=mom0.copy()*np.nan
|
|
974
|
-
mom1[mom0 != 0.0] = (((self.
|
|
975
|
-
mom1=mom1.T
|
|
989
|
+
mom1[mom0 != 0.0] = (((self.flat_cube_trim*self.mask_trim)*self.vcoord_trim).sum(axis=2))[mom0 != 0.0]/mom0[mom0 != 0.0]
|
|
990
|
+
mom1=mom1.T
|
|
976
991
|
|
|
977
|
-
|
|
992
|
+
# ### sigma clip
|
|
993
|
+
# mom1[np.abs(mom1/np.nanstd(mom1))>5]=np.nan
|
|
994
|
+
|
|
995
|
+
### select largest contigious structure
|
|
996
|
+
label,cnt=ndimage.label(self.mask_trim.sum(axis=2))
|
|
997
|
+
mode_label= mode(label[label>0])
|
|
998
|
+
|
|
999
|
+
hist,lab=np.histogram(label[label>0],bins=np.arange(cnt+1)+1)
|
|
1000
|
+
beampix=(self.bmaj*self.bmin)/(self.cellsize**2)
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
if len(lab[0:-1][hist<beampix]) != len(lab[0:-1]):
|
|
1004
|
+
|
|
1005
|
+
## remove beam size artifacts
|
|
1006
|
+
for thelabel in lab[0:-1][hist<beampix]:
|
|
1007
|
+
mom1[label.T == thelabel]=np.nan
|
|
1008
|
+
|
|
1009
|
+
## keep biggest structures that contain >80% of remaining pixels
|
|
1010
|
+
remainlab=lab[0:-1][hist>beampix]
|
|
1011
|
+
remainhist=hist[hist>beampix]
|
|
1012
|
+
st=np.argsort(remainhist)
|
|
1013
|
+
for thelabel in remainlab[st][np.nancumsum(remainhist[st]/np.sum(remainhist)) < 0.2]:
|
|
1014
|
+
mom1[label.T == thelabel]=np.nan
|
|
1015
|
+
|
|
1016
|
+
else:
|
|
1017
|
+
mom1[label.T != mode_label.mode]=np.nan
|
|
1018
|
+
|
|
1019
|
+
#self.useallpixels=True
|
|
1020
|
+
|
|
1021
|
+
### remove median
|
|
1022
|
+
mom1-=np.nanmedian(mom1)
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
#breakpoint()
|
|
978
1027
|
# if the cube is small, use it directly to estimate posang. If its large, then interpolate down to keep runtime low.
|
|
979
|
-
if (self.pbcorr_cube_trim[:,:,0].size < 50*50) or (self.useallpixels):
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
else:
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
self.posang,_,_ = fit_kinematic_pa(x[np.isfinite(v)],y[np.isfinite(v)],v[np.isfinite(v)],nsteps=36,plot=False,quiet=True)
|
|
1028
|
+
# if (self.pbcorr_cube_trim[:,:,0].size < 50*50) or (self.useallpixels):
|
|
1029
|
+
xv, yv = np.meshgrid(self.xc,self.yc)
|
|
1030
|
+
x,y,v = xv[np.isfinite(mom1)],yv[np.isfinite(mom1)],mom1[np.isfinite(mom1)]
|
|
1031
|
+
# else:
|
|
1032
|
+
# print("Downsampling the observed moment one in PA estimate for speed. Set `useallpixels` to override.")
|
|
1033
|
+
#mom1[np.isfinite(mom1) == False] = self.vsys
|
|
1034
|
+
#breakpoint()
|
|
1035
|
+
# interper = interpolate.RegularGridInterpolator((self.xc,self.yc),(mom1-self.vsys).T,bounds_error=False,fill_value=np.nan)
|
|
1036
|
+
# x=np.linspace(np.min(self.xc),np.max(self.xc),self.xc.size//2)
|
|
1037
|
+
# y=np.linspace(np.min(self.yc),np.max(self.yc),self.yc.size//2)
|
|
1038
|
+
# xv, yv = np.meshgrid(x,y)
|
|
1039
|
+
# v= interper((xv,yv))
|
|
1040
|
+
# x,y,v = xv.flatten(),yv.flatten(),v.flatten()
|
|
994
1041
|
|
|
1042
|
+
#breakpoint()
|
|
1043
|
+
self.posang,_,_ = fit_kinematic_pa(x[np.isfinite(v)],y[np.isfinite(v)],v[np.isfinite(v)],nsteps=36,plot=False,quiet=True)
|
|
1044
|
+
|
|
995
1045
|
if np.sin(np.deg2rad((self.posang+45)*2)) > 0:
|
|
996
1046
|
# do y axis cut
|
|
997
|
-
if np.
|
|
1047
|
+
if np.nansum(mom1[self.yc > 0,:])/(mom1[self.yc > 0,:]).size > np.nansum(mom1[self.yc < 0,:])/(mom1[self.yc < 0,:]).size:
|
|
998
1048
|
# posang should be gt 180
|
|
999
1049
|
if self.posang < 180: self.posang += 180
|
|
1000
1050
|
else:
|
|
@@ -1002,15 +1052,14 @@ class pymakeplots:
|
|
|
1002
1052
|
if self.posang > 180: self.posang -= 180
|
|
1003
1053
|
else:
|
|
1004
1054
|
# do x axis cut
|
|
1005
|
-
if np.
|
|
1055
|
+
if np.nansum(mom1[:,self.xc > 0])/(mom1[:,self.xc > 0]).size > np.nansum(mom1[:,self.xc < 0])/(mom1[:,self.xc < 0]).size:
|
|
1006
1056
|
# posang should be gt 180
|
|
1007
1057
|
if self.posang < 180: self.posang += 180
|
|
1008
1058
|
else:
|
|
1009
1059
|
# posang should be lt 180
|
|
1010
1060
|
if self.posang > 180: self.posang -= 180
|
|
1011
1061
|
if not self.silent: print("PA estimate (degrees): ",np.round(self.posang,1))
|
|
1012
|
-
|
|
1013
|
-
|
|
1062
|
+
|
|
1014
1063
|
centpix_x=np.where(np.isclose(self.xc,0.0,atol=self.cellsize/1.9))[0]
|
|
1015
1064
|
centpix_y=np.where(np.isclose(self.yc,0.0,atol=self.cellsize/1.9))[0]
|
|
1016
1065
|
|
|
@@ -1047,9 +1096,15 @@ class pymakeplots:
|
|
|
1047
1096
|
newcmp = ListedColormap(oldcmp(np.linspace(0.15, 1, 256)))
|
|
1048
1097
|
|
|
1049
1098
|
|
|
1099
|
+
if np.nanmax(pvd) < self.cliplevel:
|
|
1100
|
+
contour_levels=np.linspace(np.nanmax(pvd)/2.,np.nanmax(pvd),10)
|
|
1101
|
+
if np.sum(contour_levels)==0:
|
|
1102
|
+
contour_levels=np.array([self.cliplevel,self.cliplevel+0.1])
|
|
1103
|
+
else:
|
|
1104
|
+
contour_levels=np.linspace(self.cliplevel,np.nanmax(pvd),10)
|
|
1050
1105
|
|
|
1051
|
-
axes.contourf(pvdaxis,vaxis,pvd.T,levels=
|
|
1052
|
-
axes.contour(pvdaxis,vaxis,pvd.T,levels=
|
|
1106
|
+
axes.contourf(pvdaxis,vaxis,pvd.T,levels=contour_levels,cmap=newcmp)
|
|
1107
|
+
axes.contour(pvdaxis,vaxis,pvd.T,levels=contour_levels,colors='black')
|
|
1053
1108
|
|
|
1054
1109
|
if self.all_axes_physical:
|
|
1055
1110
|
axes.set_xlabel('Offset (kpc)')
|
|
@@ -1067,7 +1122,7 @@ class pymakeplots:
|
|
|
1067
1122
|
secax = axes.secondary_yaxis('right', functions=(self.vsystrans, self.vsystrans_inv))
|
|
1068
1123
|
secax.set_ylabel(r'V$_{\rm offset}$ (km s$^{-1}$)')
|
|
1069
1124
|
|
|
1070
|
-
anchored_text = AnchoredText("PA: "+str(round(self.posang,1))+
|
|
1125
|
+
anchored_text = AnchoredText("PA: "+str(round(self.posang,1))+'$^{\\circ}$', loc=loc1,frameon=False)
|
|
1071
1126
|
axes.add_artist(anchored_text)
|
|
1072
1127
|
|
|
1073
1128
|
if self.gal_distance != None and not self.all_axes_physical:
|
|
@@ -1078,24 +1133,31 @@ class pymakeplots:
|
|
|
1078
1133
|
|
|
1079
1134
|
if pdf:
|
|
1080
1135
|
plt.savefig(self.galname+"_pvd.pdf", bbox_inches = 'tight')
|
|
1136
|
+
plt.close()
|
|
1081
1137
|
else:
|
|
1082
1138
|
if not outsideaxis: plt.show()
|
|
1083
1139
|
|
|
1084
1140
|
def make_spec(self,axes=None,fits=False,pdf=False,onlydata=False,nsum=False,highlight=False):
|
|
1085
1141
|
self.fits=fits
|
|
1086
|
-
if np.any(self.xc
|
|
1142
|
+
if np.any(self.xc == None):
|
|
1087
1143
|
self.prepare_cubes()
|
|
1088
1144
|
|
|
1089
|
-
if axes == None:
|
|
1145
|
+
if np.any(axes == None):
|
|
1090
1146
|
self.set_rc_params(mult=0.75)
|
|
1091
1147
|
fig,axes=plt.subplots(1,figsize=(7,5))
|
|
1092
1148
|
outsideaxis=0
|
|
1093
1149
|
else:
|
|
1094
1150
|
outsideaxis=1
|
|
1095
|
-
|
|
1151
|
+
#spec=self.pbcorr_cube[self.spatial_trim[0]:self.spatial_trim[1],self.spatial_trim[2]:self.spatial_trim[3],:].sum(axis=0).sum(axis=0)
|
|
1152
|
+
|
|
1153
|
+
mask2d=self.mask_trim.sum(axis=2).reshape((self.mask_trim.shape[0],self.mask_trim.shape[1],1)).astype(bool)
|
|
1154
|
+
mask2d=ndimage.binary_dilation(mask2d,iterations=2)
|
|
1155
|
+
spec=(self.pbcorr_cube[self.spatial_trim[0]:self.spatial_trim[1],self.spatial_trim[2]:self.spatial_trim[3],:]*mask2d).sum(axis=0).sum(axis=0)
|
|
1156
|
+
|
|
1157
|
+
|
|
1096
1158
|
spec_mask=(self.pbcorr_cube_trim*self.mask_trim).sum(axis=0).sum(axis=0)
|
|
1097
1159
|
ylab="Unknown"
|
|
1098
|
-
|
|
1160
|
+
|
|
1099
1161
|
if (''.join(self.bunit.split())).lower() == "Jy/beam".lower():
|
|
1100
1162
|
|
|
1101
1163
|
spec*=1/self.beam_area()
|
|
@@ -1149,6 +1211,7 @@ class pymakeplots:
|
|
|
1149
1211
|
|
|
1150
1212
|
if pdf:
|
|
1151
1213
|
plt.savefig(self.galname+"_spec.pdf", bbox_inches = 'tight')
|
|
1214
|
+
plt.close()
|
|
1152
1215
|
else:
|
|
1153
1216
|
if not outsideaxis: plt.show()
|
|
1154
1217
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|