plotastrodata 1.9.10__tar.gz → 1.9.12__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.
- {plotastrodata-1.9.10/plotastrodata.egg-info → plotastrodata-1.9.12}/PKG-INFO +1 -1
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/__init__.py +1 -1
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/analysis_utils.py +113 -101
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/coord_utils.py +1 -1
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/fft_utils.py +67 -23
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/fits_utils.py +1 -1
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/fitting_utils.py +99 -75
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/noise_utils.py +2 -2
- {plotastrodata-1.9.10 → plotastrodata-1.9.12/plotastrodata.egg-info}/PKG-INFO +1 -1
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/LICENSE +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/MANIFEST.in +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/README.md +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/const_utils.py +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/ext_utils.py +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/los_utils.py +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/matrix_utils.py +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/other_utils.py +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata/plot_utils.py +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata.egg-info/SOURCES.txt +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata.egg-info/dependency_links.txt +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata.egg-info/not-zip-safe +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata.egg-info/requires.txt +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/plotastrodata.egg-info/top_level.txt +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/setup.cfg +0 -0
- {plotastrodata-1.9.10 → plotastrodata-1.9.12}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plotastrodata
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.12
|
|
4
4
|
Summary: plotastrodata is a tool for astronomers to create figures from FITS files and perform fundamental data analyses with ease.
|
|
5
5
|
Home-page: https://github.com/yusukeaso-astron/plotastrodata
|
|
6
6
|
Download-URL: https://github.com/yusukeaso-astron/plotastrodata
|
|
@@ -33,18 +33,19 @@ def quadrantmean(data: np.ndarray, x: np.ndarray, y: np.ndarray,
|
|
|
33
33
|
print('data must be 2D.')
|
|
34
34
|
return
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
else
|
|
47
|
-
|
|
36
|
+
if quadrants not in ['13', '24']:
|
|
37
|
+
print("quadrants must be '13' or '24'.")
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
dx = x[1] - x[0]
|
|
41
|
+
dy = y[1] - y[0]
|
|
42
|
+
nx = int(np.ceil(np.max(np.abs(x)) / dx))
|
|
43
|
+
ny = int(np.ceil(np.max(np.abs(y)) / dy))
|
|
44
|
+
xnew = np.linspace(-nx, nx, 2 * nx + 1) * dx
|
|
45
|
+
ynew = np.linspace(-ny, ny, 2 * ny + 1) * dy
|
|
46
|
+
s = 1 if quadrants == '13' else -1
|
|
47
|
+
f = RGI((y, s * x), data, bounds_error=False, fill_value=np.nan)
|
|
48
|
+
datanew = f(np.meshgrid(ynew, xnew, indexing='ij'))
|
|
48
49
|
datanew = (datanew + datanew[::-1, ::-1]) / 2.
|
|
49
50
|
return datanew[ny:, nx:], xnew[nx:], ynew[ny:]
|
|
50
51
|
|
|
@@ -70,12 +71,12 @@ def filled2d(data: np.ndarray, x: np.ndarray, y: np.ndarray, n: int = 1,
|
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
def _need_multipixels(method):
|
|
73
|
-
def wrapper(
|
|
74
|
-
singlepixel =
|
|
74
|
+
def wrapper(cls, *args, **kwargs):
|
|
75
|
+
singlepixel = cls.dx is None or cls.dy is None
|
|
75
76
|
if singlepixel:
|
|
76
77
|
print('No pixel size.')
|
|
77
78
|
return
|
|
78
|
-
return method(
|
|
79
|
+
return method(cls, *args, **kwargs)
|
|
79
80
|
return wrapper
|
|
80
81
|
|
|
81
82
|
|
|
@@ -140,57 +141,60 @@ class AstroData():
|
|
|
140
141
|
self.beam_org = None
|
|
141
142
|
self.fitsheader = None
|
|
142
143
|
|
|
143
|
-
def
|
|
144
|
+
def _binning_one(self, t: str, width: float):
|
|
145
|
+
grid = getattr(self, t)
|
|
146
|
+
if width == 1 or grid is None:
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
dt = f'd{t}'
|
|
150
|
+
sep = getattr(self, dt)
|
|
151
|
+
if sep is None:
|
|
152
|
+
s = f'Skip binning in the {t}-axis because {dt} is None.'
|
|
153
|
+
warnings.warn(s, UserWarning)
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
i = {'v': 1, 'y': 2, 'x': 3}[t]
|
|
157
|
+
sizenew = self.size[i] // width
|
|
158
|
+
self.size[i] = sizenew
|
|
159
|
+
data = np.moveaxis(self.data, i, 0)
|
|
160
|
+
datanew = np.moveaxis(np.zeros(self.size), i, 0)
|
|
161
|
+
gridnew = np.zeros(sizenew)
|
|
162
|
+
for start in range(width):
|
|
163
|
+
stop = start + sizenew * width
|
|
164
|
+
datanew += data[start:stop:width]
|
|
165
|
+
gridnew += grid[start:stop:width]
|
|
166
|
+
self.data = np.moveaxis(datanew, 0, i) / width
|
|
167
|
+
setattr(self, t, gridnew / width)
|
|
168
|
+
setattr(self, dt, sep * width)
|
|
169
|
+
|
|
170
|
+
def binning(self, width: list[int] = [1, 1, 1]):
|
|
144
171
|
"""Binning up neighboring pixels in the v, y, and x domain.
|
|
145
172
|
|
|
146
173
|
Args:
|
|
147
174
|
width (list, optional): Number of channels, y-pixels, and x-pixels for binning. Defaults to [1, 1, 1].
|
|
148
175
|
"""
|
|
149
|
-
w = [1] * (
|
|
176
|
+
w = np.array([1] * (3 - len(width)) + list(width), dtype=int)
|
|
150
177
|
if self.pv:
|
|
151
|
-
w[
|
|
152
|
-
w[
|
|
153
|
-
|
|
154
|
-
size = np.array(np.shape(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
ws = ', '.join([f'{s:d}' for s in w[1:]])
|
|
178
|
+
w[1] = max(w[0], w[1])
|
|
179
|
+
w[2] = 1
|
|
180
|
+
self.data = to4dim(self.data)
|
|
181
|
+
size = np.array(np.shape(self.data))
|
|
182
|
+
if np.any(w > size[1:]):
|
|
183
|
+
w = np.minimum(w, size[1:])
|
|
184
|
+
ws = ', '.join([f'{s:d}' for s in w])
|
|
159
185
|
print(f'width was changed to [{ws}].')
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
width_v = w[2] if self.pv else w[1]
|
|
186
|
+
if (not self.pv and w[0] > 1) or (self.pv and w[1] > 1):
|
|
187
|
+
width_v = w[1] if self.pv else w[0]
|
|
163
188
|
print(f'sigma has been divided by sqrt({width_v:d})'
|
|
164
189
|
+ ' because of binning in the v-axis.')
|
|
165
190
|
self.sigma = self.sigma / np.sqrt(width_v)
|
|
166
|
-
if (not self.pv and w[
|
|
191
|
+
if (not self.pv and w[1] > 1) or w[2] > 1:
|
|
167
192
|
print('Binning in the x- or y-axis does not update sigma.')
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if dgrid[n] is None:
|
|
174
|
-
t = ['v', 'y', 'x'][n - 1]
|
|
175
|
-
s = f'Skip binning in the {t}-axis' \
|
|
176
|
-
+ f' because d{t} is None.'
|
|
177
|
-
warnings.warn(s, UserWarning)
|
|
178
|
-
continue
|
|
179
|
-
size[n] = newsize[n]
|
|
180
|
-
olddata = np.moveaxis(d, n, 0)
|
|
181
|
-
newdata = np.moveaxis(np.zeros(size), n, 0)
|
|
182
|
-
t = np.zeros(newsize[n])
|
|
183
|
-
for i in range(w[n]):
|
|
184
|
-
i_stop = i + newsize[n] * w[n]
|
|
185
|
-
i_step = w[n]
|
|
186
|
-
t += grid[n][i:i_stop:i_step]
|
|
187
|
-
newdata += olddata[i:i_stop:i_step]
|
|
188
|
-
grid[n] = t / w[n]
|
|
189
|
-
dgrid[n] = dgrid[n] * w[n]
|
|
190
|
-
d = np.moveaxis(newdata, 0, n) / w[n]
|
|
191
|
-
self.data = np.squeeze(d)
|
|
192
|
-
_, self.v, self.y, self.x = grid
|
|
193
|
-
_, self.dv, self.dy, self.dx = dgrid
|
|
193
|
+
self.size = size
|
|
194
|
+
for t, ww in zip(['v', 'y', 'x'], w):
|
|
195
|
+
self._binning_one(t, ww)
|
|
196
|
+
self.data = np.squeeze(self.data)
|
|
197
|
+
del self.size
|
|
194
198
|
if self.pv:
|
|
195
199
|
self.v = self.y
|
|
196
200
|
self.dv = self.dy
|
|
@@ -245,16 +249,14 @@ class AstroData():
|
|
|
245
249
|
nx = len(self.x) if len(self.x) % 2 == 1 else len(self.x) - 1
|
|
246
250
|
ny = len(self.y) if len(self.y) % 2 == 1 else len(self.y) - 1
|
|
247
251
|
y = np.linspace(-(ny-1) / 2, (ny-1) / 2, ny) * np.abs(self.dy)
|
|
248
|
-
g1 = np.exp(-4*np.log(2) * y**2 / (bmaj**2 - bmin**2))
|
|
252
|
+
g1 = np.exp(-4 * np.log(2) * y**2 / (bmaj**2 - bmin**2))
|
|
249
253
|
e = np.sqrt(1 - bmin**2 / bmaj**2)
|
|
250
254
|
g1 /= np.sqrt(np.pi / 4 / np.log(2) * bmin * e)
|
|
251
255
|
g = np.zeros((ny, nx))
|
|
252
256
|
g[:, (nx - 1) // 2] = g1
|
|
253
257
|
d = self.data.copy()
|
|
254
258
|
d[np.isnan(d)] = 0
|
|
255
|
-
|
|
256
|
-
d = [[convolve(c, g, mode='same') for c in cc] for cc in d]
|
|
257
|
-
self.data = np.squeeze(d)
|
|
259
|
+
self.data = np.squeeze(convolve(to4dim(d), [[g]], mode='same'))
|
|
258
260
|
self.rotate(bpa)
|
|
259
261
|
self.beam[1] = self.beam[0]
|
|
260
262
|
self.beam[2] = 0
|
|
@@ -272,8 +274,10 @@ class AstroData():
|
|
|
272
274
|
self.data = RGIxy(self.y, self.x, self.data, yxnew, **kwargs)
|
|
273
275
|
if None not in self.beam:
|
|
274
276
|
bmaj, bmin, bpa = self.beam
|
|
275
|
-
a, b = np.linalg.multi_dot([Mfac(1/bmaj, 1/bmin),
|
|
276
|
-
|
|
277
|
+
a, b = np.linalg.multi_dot([Mfac(1 / bmaj, 1 / bmin),
|
|
278
|
+
Mrot(pa - bpa),
|
|
279
|
+
Mfac(1, ci),
|
|
280
|
+
Mrot(-pa)]).T
|
|
277
281
|
alpha = (np.dot(a, a) + np.dot(b, b)) / 2
|
|
278
282
|
beta = np.dot(a, b)
|
|
279
283
|
gamma = (np.dot(a, a) - np.dot(b, b)) / 2
|
|
@@ -406,6 +410,21 @@ class AstroData():
|
|
|
406
410
|
if len(excludepix) == 2:
|
|
407
411
|
self.data[(excludepix[0] < mask) * (mask < excludepix[1])] = np.nan
|
|
408
412
|
|
|
413
|
+
def _gfit_profile(self, prof: list, gaussfit: bool):
|
|
414
|
+
if not gaussfit:
|
|
415
|
+
return {}
|
|
416
|
+
|
|
417
|
+
gfitres = {}
|
|
418
|
+
nprof = len(prof)
|
|
419
|
+
res = [None] * nprof
|
|
420
|
+
for i in range(nprof):
|
|
421
|
+
res[i] = gaussfit1d(xdata=self.v, ydata=prof[i],
|
|
422
|
+
sigma=None, show=True,
|
|
423
|
+
nwalkersperdim=8)
|
|
424
|
+
gfitres['best'] = [a['popt'][:3] for a in res]
|
|
425
|
+
gfitres['error'] = [a['perr'][:3] for a in res]
|
|
426
|
+
return gfitres
|
|
427
|
+
|
|
409
428
|
def profile(self, coords: list[str] = [],
|
|
410
429
|
xlist: list[float] = [], ylist: list[float] = [],
|
|
411
430
|
ellipse: list[float, float, float] | None = None,
|
|
@@ -430,13 +449,12 @@ class AstroData():
|
|
|
430
449
|
print('Data must be 3D with the v, y, and x axes.')
|
|
431
450
|
return
|
|
432
451
|
|
|
433
|
-
v = self.v
|
|
434
452
|
data, xf, yf = filled2d(self.data, self.x, self.y, ninterp)
|
|
435
453
|
x, y = np.meshgrid(xf, yf)
|
|
436
454
|
if len(coords) > 0:
|
|
437
455
|
xlist, ylist = coord2xy(coords, self.center) * 3600.
|
|
438
456
|
nprof = len(xlist)
|
|
439
|
-
prof = np.empty((nprof, len(v)))
|
|
457
|
+
prof = np.empty((nprof, len(self.v)))
|
|
440
458
|
ellipse = ellipse or [[0, 0, 0]] * nprof
|
|
441
459
|
calc = np.sum if flux else np.mean
|
|
442
460
|
for i, (xc, yc, e) in enumerate(zip(xlist, ylist, ellipse)):
|
|
@@ -455,16 +473,8 @@ class AstroData():
|
|
|
455
473
|
else:
|
|
456
474
|
Omega = np.pi * self.beam[0] * self.beam[1] / 4. / np.log(2.)
|
|
457
475
|
prof *= np.abs(self.dx * self.dy) / Omega
|
|
458
|
-
gfitres =
|
|
459
|
-
|
|
460
|
-
res = [None] * nprof
|
|
461
|
-
for i in range(nprof):
|
|
462
|
-
res[i] = gaussfit1d(xdata=v, ydata=prof[i],
|
|
463
|
-
sigma=None, show=True,
|
|
464
|
-
nwalkersperdim=8)
|
|
465
|
-
gfitres['best'] = [a['popt'][:3] for a in res]
|
|
466
|
-
gfitres['error'] = [a['perr'][:3] for a in res]
|
|
467
|
-
return v, prof, gfitres
|
|
476
|
+
gfitres = self._gfit_profile(prof, gaussfit)
|
|
477
|
+
return self.v, prof, gfitres
|
|
468
478
|
|
|
469
479
|
def rotate(self, pa: float = 0, **kwargs):
|
|
470
480
|
"""Counter clockwise rotation with respect to the center.
|
|
@@ -515,6 +525,31 @@ class AstroData():
|
|
|
515
525
|
'bunit': self.bunit}
|
|
516
526
|
return d
|
|
517
527
|
|
|
528
|
+
def _put_header(self, h: dict, t: str, crpix: int, crval: float,
|
|
529
|
+
cdelt: float | None = None) -> None:
|
|
530
|
+
fhd = self.fitsheader
|
|
531
|
+
axis = {'x': 1, 'y': 2, 'v': 2 if self.pv else 3}[t]
|
|
532
|
+
u = f'CUNIT{axis}'
|
|
533
|
+
indeg = fhd is None or u not in fhd or isdeg(fhd[u])
|
|
534
|
+
h[f'NAXIS{axis}'] = len(getattr(self, t))
|
|
535
|
+
h[f'CRPIX{axis}'] = int(crpix)
|
|
536
|
+
h[f'CRVAL{axis}'] = float(crval)
|
|
537
|
+
if cdelt is None:
|
|
538
|
+
cdelt = getattr(self, f'd{t}') / (3600 if indeg else 1)
|
|
539
|
+
h[f'CDELT{axis}'] = float(cdelt)
|
|
540
|
+
|
|
541
|
+
def _get_cvdv_in_freq(self, ck: int) -> tuple[float, float]:
|
|
542
|
+
cv = self.v[ck]
|
|
543
|
+
dv = self.dv
|
|
544
|
+
if self.restfreq is None or self.restfreq == 0:
|
|
545
|
+
s = 'No valid restfreq. The velocity axis is saved as is.'
|
|
546
|
+
warnings.warn(s, UserWarning)
|
|
547
|
+
return cv, dv
|
|
548
|
+
|
|
549
|
+
cv = (1 - cv / cu.c_kms) * self.restfreq
|
|
550
|
+
dv = -dv / cu.c_kms * self.restfreq
|
|
551
|
+
return cv, dv
|
|
552
|
+
|
|
518
553
|
@_need_multipixels
|
|
519
554
|
def writetofits(self, fitsimage: str = 'out.fits',
|
|
520
555
|
header: dict = {}) -> None:
|
|
@@ -524,7 +559,6 @@ class AstroData():
|
|
|
524
559
|
fitsimage (str, optional): Output FITS file name. Defaults to 'out.fits'.
|
|
525
560
|
header (dict, optional): Header dictionary. Defaults to {}.
|
|
526
561
|
"""
|
|
527
|
-
fhd = self.fitsheader
|
|
528
562
|
h = {}
|
|
529
563
|
ci = nearest_index(self.x)
|
|
530
564
|
cx = 0
|
|
@@ -536,35 +570,13 @@ class AstroData():
|
|
|
536
570
|
xy = [self.x[ci] / 3600, self.y[cj] / 3600]
|
|
537
571
|
cx, cy = coord2xy(xy2coord(xy, self.center))
|
|
538
572
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
h['NAXIS1'] = len(self.x)
|
|
544
|
-
h['CRPIX1'] = int(ci + 1)
|
|
545
|
-
h['CRVAL1'] = float(cx)
|
|
546
|
-
h['CDELT1'] = float(self.dx / (3600 if indeg('1') else 1))
|
|
573
|
+
self._put_header(h, 'x', crpix=ci + 1, crval=cx)
|
|
574
|
+
if not self.pv:
|
|
575
|
+
self._put_header(h, 'y', crpix=cj + 1, crval=cy)
|
|
547
576
|
if self.dv is not None:
|
|
548
|
-
vaxis = '2' if self.pv else '3'
|
|
549
577
|
ck = nearest_index(self.v)
|
|
550
|
-
cv = self.
|
|
551
|
-
|
|
552
|
-
if self.restfreq is None or self.restfreq == 0:
|
|
553
|
-
s = 'No valid restfreq.' \
|
|
554
|
-
+ f' Axis {vaxis} is saved as is.'
|
|
555
|
-
warnings.warn(s, UserWarning)
|
|
556
|
-
else:
|
|
557
|
-
cv = (1 - cv / cu.c_kms) * self.restfreq
|
|
558
|
-
dv = -dv / cu.c_kms * self.restfreq
|
|
559
|
-
h[f'NAXIS{vaxis}'] = len(self.v)
|
|
560
|
-
h[f'CRPIX{vaxis}'] = int(ck + 1)
|
|
561
|
-
h[f'CRVAL{vaxis}'] = float(cv)
|
|
562
|
-
h[f'CDELT{vaxis}'] = float(dv)
|
|
563
|
-
if not self.pv:
|
|
564
|
-
h['NAXIS2'] = len(self.y)
|
|
565
|
-
h['CRPIX2'] = int(cj + 1)
|
|
566
|
-
h['CRVAL2'] = float(cy)
|
|
567
|
-
h['CDELT2'] = float(self.dy / (3600 if indeg('2') else 1))
|
|
578
|
+
cv, dv = self._get_cvdv_in_freq(ck)
|
|
579
|
+
self._put_header(h, 'v', crpix=ck + 1, crval=cv, cdelt=dv)
|
|
568
580
|
if None not in self.beam:
|
|
569
581
|
beam = self.beam_org if self.pv else self.beam
|
|
570
582
|
h['BMAJ'] = float(beam[0] / 3600)
|
|
@@ -11,7 +11,7 @@ def shiftphase(F: np.ndarray, u: np.ndarray,
|
|
|
11
11
|
|
|
12
12
|
Args:
|
|
13
13
|
F (np.ndarray): 1D FFT.
|
|
14
|
-
u (np.ndarray): 1D array. The
|
|
14
|
+
u (np.ndarray): 1D array. The frequency coordinate.
|
|
15
15
|
xoff (float): From old to new center. Defaults to 0.
|
|
16
16
|
|
|
17
17
|
Returns:
|
|
@@ -27,7 +27,7 @@ def shiftphase2(F: np.ndarray, u: np.ndarray, v: np.ndarray,
|
|
|
27
27
|
Args:
|
|
28
28
|
F (np.ndarray): 2D FFT.
|
|
29
29
|
u (np.ndarray): 1D or 2D array. The first frequency coordinate.
|
|
30
|
-
v (np.ndarray): 1D or 2D array. The second frequency coordinate.
|
|
30
|
+
v (np.ndarray): 1D or 2D array. The second frequency coordinate.
|
|
31
31
|
xoff (float): From old to new center. Defaults to 0.
|
|
32
32
|
yoff (float): From old to new center. Defaults to 0.
|
|
33
33
|
|
|
@@ -39,7 +39,7 @@ def shiftphase2(F: np.ndarray, u: np.ndarray, v: np.ndarray,
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def fftcentering(f: np.ndarray, x: np.ndarray | None = None,
|
|
42
|
-
xcenter: float = 0
|
|
42
|
+
xcenter: float = 0, rfft: bool = False
|
|
43
43
|
) -> tuple[np.ndarray, np.ndarray]:
|
|
44
44
|
"""FFT with the phase referring to a specific point.
|
|
45
45
|
|
|
@@ -47,6 +47,7 @@ def fftcentering(f: np.ndarray, x: np.ndarray | None = None,
|
|
|
47
47
|
f (np.ndarray): 1D array for FFT.
|
|
48
48
|
x (np.ndarray, optional): 1D array. The spatial coordinate. Defaults to None.
|
|
49
49
|
xcenter (float, optional): x of phase reference. Defaults to 0.
|
|
50
|
+
rfft (bool, optional): True means using rFFT. Defaults to False.
|
|
50
51
|
|
|
51
52
|
Returns:
|
|
52
53
|
tuple: (F, u). F is FFT of f. u is a 1D array of the frequency coordinate.
|
|
@@ -56,15 +57,19 @@ def fftcentering(f: np.ndarray, x: np.ndarray | None = None,
|
|
|
56
57
|
x = np.arange(nx)
|
|
57
58
|
X = x[0, :] if np.ndim(x) == 2 else x
|
|
58
59
|
dx = X[1] - X[0]
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if rfft:
|
|
61
|
+
u = np.fft.rfftfreq(nx, d=dx)
|
|
62
|
+
F = np.fft.rfft(f)
|
|
63
|
+
else:
|
|
64
|
+
u = np.fft.fftshift(np.fft.fftfreq(nx, d=dx))
|
|
65
|
+
F = np.fft.fftshift(np.fft.fft(f))
|
|
61
66
|
F = shiftphase(F, u=u, xoff=xcenter - X[0])
|
|
62
67
|
return F, u
|
|
63
68
|
|
|
64
69
|
|
|
65
70
|
def fftcentering2(f: np.ndarray,
|
|
66
71
|
x: np.ndarray | None = None, y: np.ndarray | None = None,
|
|
67
|
-
xcenter: float = 0, ycenter: float = 0
|
|
72
|
+
xcenter: float = 0, ycenter: float = 0, rfft: bool = False
|
|
68
73
|
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
69
74
|
"""FFT with the phase referring to a specific point.
|
|
70
75
|
|
|
@@ -74,6 +79,7 @@ def fftcentering2(f: np.ndarray,
|
|
|
74
79
|
y (np.ndarray, optional): 1D or 2D array. The second spatial coordinate. Defaults to None.
|
|
75
80
|
xcenter (float, optional): x of phase reference. Defaults to 0.
|
|
76
81
|
ycenter (float, optional): y of phase reference. Defaults to 0.
|
|
82
|
+
rfft (bool, optional): True means using rFFT. Defaults to False.
|
|
77
83
|
|
|
78
84
|
Returns:
|
|
79
85
|
tuple: (F, u, v). F is FFT of f. u and v are 1D arrays of the frequency coordinates.
|
|
@@ -85,39 +91,60 @@ def fftcentering2(f: np.ndarray,
|
|
|
85
91
|
y = np.arange(ny)
|
|
86
92
|
X = x[0, :] if np.ndim(x) == 2 else x
|
|
87
93
|
Y = y[:, 0] if np.ndim(y) == 2 else y
|
|
88
|
-
dx
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
dx = X[1] - X[0]
|
|
95
|
+
dy = Y[1] - Y[0]
|
|
96
|
+
if rfft:
|
|
97
|
+
u = np.fft.rfftfreq(nx, d=dx)
|
|
98
|
+
v = np.fft.fftshift(np.fft.fftfreq(ny, d=dy))
|
|
99
|
+
F = np.fft.fftshift(np.fft.rfft2(f), axes=0)
|
|
100
|
+
else:
|
|
101
|
+
u = np.fft.fftshift(np.fft.fftfreq(nx, d=dx))
|
|
102
|
+
v = np.fft.fftshift(np.fft.fftfreq(ny, d=dy))
|
|
103
|
+
F = np.fft.fftshift(np.fft.fft2(f))
|
|
92
104
|
F = shiftphase2(F, u, v, xcenter - X[0], ycenter - Y[0])
|
|
93
105
|
return F, u, v
|
|
94
106
|
|
|
95
107
|
|
|
96
108
|
def ifftcentering(F: np.ndarray, u: np.ndarray | None = None,
|
|
97
|
-
xcenter: float = 0,
|
|
98
|
-
|
|
99
|
-
outreal: bool =
|
|
109
|
+
xcenter: float = 0, x0: float = None,
|
|
110
|
+
dx: float = 1,
|
|
111
|
+
outreal: bool = False, rfft: bool = False
|
|
100
112
|
) -> tuple[np.ndarray, np.ndarray]:
|
|
101
113
|
"""inverse FFT with the phase referring to a specific point.
|
|
102
114
|
|
|
103
115
|
Args:
|
|
104
|
-
F (np.ndarray): 1D array.
|
|
116
|
+
F (np.ndarray): 1D array. An FFT result in the frequency domain.
|
|
105
117
|
u (np.ndarray, optional): 1D array. The frequency coordinate. Defaults to None.
|
|
106
118
|
xcenter (float, optional): x of phase reference (used in fftcentering). Defaults to 0.
|
|
107
119
|
x0 (float, optional): spatial coordinate of x[0]. Defaults to None.
|
|
108
|
-
|
|
120
|
+
dx (float, optional): spatial interval. Defaults to 1.
|
|
121
|
+
outreal (bool, optional): whether output only the real part. Defaults to False.
|
|
122
|
+
rfft (bool, optional): True means using rFFT. Defaults to False.
|
|
109
123
|
|
|
110
124
|
Returns:
|
|
111
125
|
tuple: (f, x). f is iFFT of F. x is a 1D array of the spatial coordinate.
|
|
112
126
|
"""
|
|
113
127
|
nx = np.shape(F)[0]
|
|
114
128
|
if u is None:
|
|
115
|
-
|
|
129
|
+
if rfft:
|
|
130
|
+
nx = 2 * (nx - 1) # Follow numpy.fft.irfft behavior.
|
|
131
|
+
u = np.fft.rfftfreq(nx, d=dx)
|
|
132
|
+
else:
|
|
133
|
+
u = np.fft.fftshift(np.fft.fftfreq(nx, d=dx))
|
|
134
|
+
else:
|
|
135
|
+
if rfft:
|
|
136
|
+
if np.isclose(u[-1], 1 / (2 * dx)):
|
|
137
|
+
nx = 2 * (nx - 1)
|
|
138
|
+
else:
|
|
139
|
+
nx = 2 * (nx - 1) + 1
|
|
116
140
|
x = (np.arange(nx) - (nx-1)/2.) / (u[1]-u[0]) / nx + xcenter
|
|
117
141
|
if x0 is not None:
|
|
118
142
|
x = x - x[0] + x0
|
|
119
143
|
F = shiftphase(F, u=u, xoff=x[0] - xcenter)
|
|
120
|
-
|
|
144
|
+
if rfft:
|
|
145
|
+
f = np.fft.irfft(F, n=nx)
|
|
146
|
+
else:
|
|
147
|
+
f = np.fft.ifft(np.fft.ifftshift(F))
|
|
121
148
|
if outreal:
|
|
122
149
|
f = np.real(f)
|
|
123
150
|
return f, x
|
|
@@ -127,28 +154,42 @@ def ifftcentering2(F: np.ndarray,
|
|
|
127
154
|
u: np.ndarray | None = None, v: np.ndarray | None = None,
|
|
128
155
|
xcenter: float = 0, ycenter: float = 0,
|
|
129
156
|
x0: float | None = None, y0: float | None = None,
|
|
130
|
-
|
|
157
|
+
dx: float = 1, dy: float = 1,
|
|
158
|
+
outreal: bool = False, rfft: bool = False
|
|
131
159
|
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
132
160
|
"""inverse FFT with the phase referring to a specific point.
|
|
133
161
|
|
|
134
162
|
Args:
|
|
135
|
-
F (np.ndarray): 2D array.
|
|
163
|
+
F (np.ndarray): 2D array. An FFT result in the frequency domain.
|
|
136
164
|
u (np.ndarray, optional): 1D or 2D array. The first frequency coordinate. Defaults to None.
|
|
137
165
|
v (np.ndarray, optional): 1D or 2D array. The second frequency cooridnate. Defaults to None.
|
|
138
166
|
xcenter (float, optional): x of phase reference (used in fftcentering2). Defaults to 0.
|
|
139
167
|
ycenter (float, optional): y of phase reference (used in fftcentering2). Defaults to 0.
|
|
140
168
|
x0 (float, optional): spatial coordinate of x[0]. Defaults to None.
|
|
141
169
|
y0 (float, optional): spatial coordinate of y[0]. Defaults to None.
|
|
142
|
-
|
|
170
|
+
dx (float, optional): spatial interval. Defaults to 1.
|
|
171
|
+
dy (float, optional): spatial interval. Defaults to 1.
|
|
172
|
+
outreal (bool, optional): whether output only the real part. Defaults to False.
|
|
173
|
+
rfft (bool, optional): True means using rFFT. Defaults to False.
|
|
143
174
|
|
|
144
175
|
Returns:
|
|
145
176
|
tuple: (f, x, y). f is iFFT of F. x and y are 1D arrays of the spatial coordinates.
|
|
146
177
|
"""
|
|
147
178
|
ny, nx = np.shape(F)
|
|
148
179
|
if u is None:
|
|
149
|
-
|
|
180
|
+
if rfft:
|
|
181
|
+
nx = 2 * (nx - 1) # Follow numpy.fft.irfft behavior.
|
|
182
|
+
u = np.fft.rfftfreq(nx, d=dx)
|
|
183
|
+
else:
|
|
184
|
+
u = np.fft.fftshift(np.fft.fftfreq(nx, d=dy))
|
|
185
|
+
else:
|
|
186
|
+
if rfft:
|
|
187
|
+
if np.isclose(u[-1], 1 / (2 * dx)):
|
|
188
|
+
nx = 2 * (nx - 1)
|
|
189
|
+
else:
|
|
190
|
+
nx = 2 * (nx - 1) + 1
|
|
150
191
|
if v is None:
|
|
151
|
-
v = np.fft.fftshift(np.fft.fftfreq(ny, d=
|
|
192
|
+
v = np.fft.fftshift(np.fft.fftfreq(ny, d=dy))
|
|
152
193
|
x = (np.arange(nx) - (nx-1)/2.) / (u[1]-u[0]) / nx + xcenter
|
|
153
194
|
y = (np.arange(ny) - (ny-1)/2.) / (v[1]-v[0]) / ny + ycenter
|
|
154
195
|
if x0 is not None:
|
|
@@ -156,7 +197,10 @@ def ifftcentering2(F: np.ndarray,
|
|
|
156
197
|
if y0 is not None:
|
|
157
198
|
y = y - y[0] + y0
|
|
158
199
|
F = shiftphase2(F, u, v, x[0] - xcenter, y[0] - ycenter)
|
|
159
|
-
|
|
200
|
+
if rfft:
|
|
201
|
+
f = np.fft.irfft2(np.fft.ifftshift(F, axes=0), s=(ny, nx))
|
|
202
|
+
else:
|
|
203
|
+
f = np.fft.ifft2(np.fft.ifftshift(F))
|
|
160
204
|
if outreal:
|
|
161
205
|
f = np.real(f)
|
|
162
206
|
return f, x, y
|
|
@@ -376,7 +376,7 @@ def fits2data(fitsimage: str, Tb: bool = False, log: bool = False,
|
|
|
376
376
|
restfreq: float | None = None, center: str | None = None,
|
|
377
377
|
vsys: float = 0., pv: bool = False, **kwargs
|
|
378
378
|
) -> tuple[np.ndarray, tuple[np.ndarray, np.ndarray, np.ndarray],
|
|
379
|
-
|
|
379
|
+
np.ndarray, str, float]:
|
|
380
380
|
"""Extract data from a fits file. kwargs are arguments of FitsData.trim().
|
|
381
381
|
|
|
382
382
|
Args:
|
|
@@ -281,6 +281,29 @@ class EmceeCorner():
|
|
|
281
281
|
ax.set_xlabel('Step')
|
|
282
282
|
close_figure(fig, savefig, show)
|
|
283
283
|
|
|
284
|
+
def _set_results_posteriorongrid(self) -> None:
|
|
285
|
+
p = self.p
|
|
286
|
+
p1d = self.p1d
|
|
287
|
+
pargrid = self.pargrid
|
|
288
|
+
if np.all(p == 0):
|
|
289
|
+
print('All posterior is below pcut.')
|
|
290
|
+
self.popt = np.full(self.dim, np.nan)
|
|
291
|
+
self.plow = np.full(self.dim, np.nan)
|
|
292
|
+
self.pmid = np.full(self.dim, np.nan)
|
|
293
|
+
self.phigh = np.full(self.dim, np.nan)
|
|
294
|
+
else:
|
|
295
|
+
i_max = np.unravel_index(np.argmax(p), np.shape(p))[::-1]
|
|
296
|
+
self.popt = np.array([p[i] for p, i in zip(pargrid, i_max)])
|
|
297
|
+
|
|
298
|
+
def getpercentile(percent: float):
|
|
299
|
+
a = [np.percentile(g, percent, method='inverted_cdf', weights=p)
|
|
300
|
+
for g, p in zip(pargrid, p1d)]
|
|
301
|
+
return np.array(a)
|
|
302
|
+
|
|
303
|
+
self.plow = getpercentile(self.percent[0])
|
|
304
|
+
self.pmid = getpercentile(50)
|
|
305
|
+
self.phigh = getpercentile(self.percent[1])
|
|
306
|
+
|
|
284
307
|
def posteriorongrid(self, ngrid: list[int] | int = 100,
|
|
285
308
|
log: list[bool] | bool = False, pcut: float = 0):
|
|
286
309
|
"""Calculate the posterior on a grid of ngrid x ngrid x ... x ngrid.
|
|
@@ -297,8 +320,8 @@ class EmceeCorner():
|
|
|
297
320
|
pargrid = []
|
|
298
321
|
inzip = [self.bounds[:, 0], self.bounds[:, 1], ngrid, log]
|
|
299
322
|
for start, stop, num, uselog in zip(*inzip):
|
|
300
|
-
|
|
301
|
-
pargrid.append(
|
|
323
|
+
spacer = np.geomspace if uselog else np.linspace
|
|
324
|
+
pargrid.append(spacer(start, stop, num))
|
|
302
325
|
p = np.exp(self.logl(np.meshgrid(*pargrid[::-1], indexing='ij')[::-1]))
|
|
303
326
|
p[p < pcut] = 0
|
|
304
327
|
dpar = []
|
|
@@ -309,33 +332,74 @@ class EmceeCorner():
|
|
|
309
332
|
else:
|
|
310
333
|
dpar.append(pg * 0 + pg[1] - pg[0])
|
|
311
334
|
vol = np.prod(np.meshgrid(*dpar[::-1], indexing='ij')[::-1], axis=0)
|
|
312
|
-
|
|
313
|
-
|
|
335
|
+
arrdim = np.arange(self.dim)
|
|
336
|
+
arrdim_r = arrdim[::-1]
|
|
337
|
+
# arrdim[::-1] is becuase the 0th parameter is the innermost axis.
|
|
338
|
+
axlist = [tuple(np.delete(arrdim, i)) for i in arrdim_r]
|
|
314
339
|
p1d = [np.sum(p * vol, axis=a) / np.sum(vol, axis=a) for a in axlist]
|
|
315
340
|
evidence = np.sum(p * vol) / np.sum(vol)
|
|
316
|
-
if np.all(p == 0):
|
|
317
|
-
print('All posterior is below pcut.')
|
|
318
|
-
self.popt = np.full(self.dim, np.nan)
|
|
319
|
-
self.plow = np.full(self.dim, np.nan)
|
|
320
|
-
self.pmid = np.full(self.dim, np.nan)
|
|
321
|
-
self.phigh = np.full(self.dim, np.nan)
|
|
322
|
-
else:
|
|
323
|
-
i_max = np.unravel_index(np.argmax(p), np.shape(p))[::-1]
|
|
324
|
-
self.popt = np.array([p[i] for p, i in zip(pargrid, i_max)])
|
|
325
|
-
|
|
326
|
-
def getpercentile(percent: float):
|
|
327
|
-
a = [np.percentile(g, percent, method='inverted_cdf', weights=p)
|
|
328
|
-
for g, p in zip(pargrid, p1d)]
|
|
329
|
-
return np.array(a)
|
|
330
|
-
|
|
331
|
-
self.plow = getpercentile(self.percent[0])
|
|
332
|
-
self.pmid = getpercentile(50)
|
|
333
|
-
self.phigh = getpercentile(self.percent[1])
|
|
334
341
|
self.p = p
|
|
335
342
|
self.p1d = p1d
|
|
336
343
|
self.pargrid = pargrid
|
|
337
344
|
self.vol = vol
|
|
338
345
|
self.evidence = evidence
|
|
346
|
+
self.arrdim = arrdim
|
|
347
|
+
self.arrdim_r = arrdim_r
|
|
348
|
+
self._set_results_posteriorongrid()
|
|
349
|
+
|
|
350
|
+
def _i_eq_j(self, fig, ax, i: int, k: int) -> None:
|
|
351
|
+
x = self.pargrid
|
|
352
|
+
y = self.p1d
|
|
353
|
+
s0 = self.pmid[i]
|
|
354
|
+
s1 = self.phigh[i] - self.pmid[i]
|
|
355
|
+
s2 = self.pmid[i] - self.plow[i]
|
|
356
|
+
s0 = f'{s0:.2f}'
|
|
357
|
+
s1 = '^{+' + f'{s1:.2f}' + '}'
|
|
358
|
+
s2 = '_{-' + f'{s2:.2f}' + '}'
|
|
359
|
+
s0 = s0 + s1 + s2
|
|
360
|
+
ax[k] = fig.add_subplot(self.dim, self.dim, k + 1)
|
|
361
|
+
ax[k].plot(x[i], y[i], 'k-', drawstyle='steps-mid')
|
|
362
|
+
ax[k].axvline(self.popt[i])
|
|
363
|
+
ax[k].axvline(self.plow[i], linestyle='--', color='k')
|
|
364
|
+
ax[k].axvline(self.pmid[i], linestyle='--', color='k')
|
|
365
|
+
ax[k].axvline(self.phigh[i], linestyle='--', color='k')
|
|
366
|
+
ax[k].set_title(rf'{self.labels[i]}=${s0}$')
|
|
367
|
+
ax[k].set_xlim(self.cornerrange[i])
|
|
368
|
+
ax[k].set_ylim([0, np.max(y[i]) * 1.2])
|
|
369
|
+
ax[k].set_yticks([])
|
|
370
|
+
if i == self.dim - 1:
|
|
371
|
+
plt.setp(ax[k].get_xticklabels(), rotation=45)
|
|
372
|
+
ax[k].set_xlabel(self.labels[i])
|
|
373
|
+
else:
|
|
374
|
+
plt.setp(ax[k].get_xticklabels(), visible=False)
|
|
375
|
+
|
|
376
|
+
def _i_neq_j(self, fig, ax, i: int, j: int, k: int) -> None:
|
|
377
|
+
x = self.pargrid
|
|
378
|
+
sharex = ax[self.dim * (i - 1) + j]
|
|
379
|
+
sharey = ax[self.dim * i + (j - 1)] if j > 1 else None
|
|
380
|
+
ax[k] = fig.add_subplot(self.dim, self.dim, k + 1,
|
|
381
|
+
sharex=sharex, sharey=sharey)
|
|
382
|
+
axis = tuple(np.delete(self.arrdim_r, [i, j]))
|
|
383
|
+
yy = np.sum(self.p * self.vol, axis=axis) \
|
|
384
|
+
/ np.sum(self.vol, axis=axis)
|
|
385
|
+
ax[k].pcolormesh(x[j], x[i], yy, cmap=self.cmap)
|
|
386
|
+
ax[k].contour(x[j], x[i], yy, colors='k',
|
|
387
|
+
levels=self.levels * np.nanmax(yy))
|
|
388
|
+
ax[k].plot(self.popt[j], self.popt[i], 'o')
|
|
389
|
+
ax[k].axvline(self.popt[j])
|
|
390
|
+
ax[k].axhline(self.popt[i])
|
|
391
|
+
ax[k].set_xlim(self.cornerrange[j])
|
|
392
|
+
ax[k].set_ylim(self.cornerrange[i])
|
|
393
|
+
if j == 0:
|
|
394
|
+
ax[k].set_ylabel(self.labels[i])
|
|
395
|
+
plt.setp(ax[k].get_yticklabels(), rotation=45)
|
|
396
|
+
else:
|
|
397
|
+
plt.setp(ax[k].get_yticklabels(), visible=False)
|
|
398
|
+
if i == self.dim - 1:
|
|
399
|
+
ax[k].set_xlabel(self.labels[j])
|
|
400
|
+
plt.setp(ax[k].get_xticklabels(), rotation=45)
|
|
401
|
+
else:
|
|
402
|
+
plt.setp(ax[k].get_xticklabels(), visible=False)
|
|
339
403
|
|
|
340
404
|
def plotongrid(self, show: bool = False, savefig: str | None = None,
|
|
341
405
|
labels: list[str] = None,
|
|
@@ -352,70 +416,30 @@ class EmceeCorner():
|
|
|
352
416
|
cmap: (str, optional): cmap for matplotlib.pyplot.plt.pcolormesh(). Defaults to 'binary'.
|
|
353
417
|
levels: (list, optional): levels for matplotlib.pyplot.plt.contour() relative to the peak. Defaults to [exp(-0.5*3^2), exp(-0.5*2^2), exp(-0.5*1^2)].
|
|
354
418
|
"""
|
|
355
|
-
adim = np.arange(self.dim)
|
|
356
419
|
if labels is None:
|
|
357
|
-
labels = [f'Par {i:d}' for i in
|
|
420
|
+
labels = [f'Par {i:d}' for i in self.arrdim]
|
|
358
421
|
if cornerrange is None:
|
|
359
422
|
cornerrange = self.bounds
|
|
360
|
-
|
|
361
|
-
|
|
423
|
+
self.labels = labels
|
|
424
|
+
self.cornerrange = cornerrange
|
|
425
|
+
self.cmap = cmap
|
|
426
|
+
self.levels = np.array(levels)
|
|
362
427
|
fig = plt.figure(figsize=(2 * self.dim * 1.2, 2 * self.dim * 1.2))
|
|
363
428
|
fig.subplots_adjust(hspace=0.05, wspace=0.05, top=0.87, right=0.87)
|
|
364
429
|
ax = np.empty(self.dim * self.dim, dtype='object')
|
|
365
|
-
for i in
|
|
366
|
-
for j in
|
|
430
|
+
for i in self.arrdim:
|
|
431
|
+
for j in self.arrdim:
|
|
367
432
|
if i < j:
|
|
368
433
|
continue
|
|
369
434
|
k = self.dim * i + j
|
|
370
435
|
if i == j:
|
|
371
|
-
|
|
372
|
-
s1 = self.phigh[i] - self.pmid[i]
|
|
373
|
-
s2 = self.pmid[i] - self.plow[i]
|
|
374
|
-
s0 = f'{s0:.2f}'
|
|
375
|
-
s1 = '^{+' + f'{s1:.2f}' + '}'
|
|
376
|
-
s2 = '_{-' + f'{s2:.2f}' + '}'
|
|
377
|
-
s0 = s0 + s1 + s2
|
|
378
|
-
ax[k] = fig.add_subplot(self.dim, self.dim, k + 1)
|
|
379
|
-
ax[k].plot(x[i], y[i], 'k-', drawstyle='steps-mid')
|
|
380
|
-
ax[k].axvline(self.popt[i])
|
|
381
|
-
ax[k].axvline(self.plow[i], linestyle='--', color='k')
|
|
382
|
-
ax[k].axvline(self.pmid[i], linestyle='--', color='k')
|
|
383
|
-
ax[k].axvline(self.phigh[i], linestyle='--', color='k')
|
|
384
|
-
ax[k].set_title(rf'{labels[i]}=${s0}$')
|
|
385
|
-
ax[k].set_xlim(cornerrange[i])
|
|
386
|
-
ax[k].set_ylim([0, np.max(y[i]) * 1.2])
|
|
387
|
-
ax[k].set_yticks([])
|
|
388
|
-
if i == self.dim - 1:
|
|
389
|
-
plt.setp(ax[k].get_xticklabels(), rotation=45)
|
|
390
|
-
ax[k].set_xlabel(labels[i])
|
|
391
|
-
else:
|
|
392
|
-
plt.setp(ax[k].get_xticklabels(), visible=False)
|
|
436
|
+
self._i_eq_j(fig, ax, i, k)
|
|
393
437
|
else:
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
yy = np.sum(self.p * self.vol, axis=axis) \
|
|
400
|
-
/ np.sum(self.vol, axis=axis)
|
|
401
|
-
ax[k].pcolormesh(x[j], x[i], yy, cmap=cmap)
|
|
402
|
-
ax[k].contour(x[j], x[i], yy, colors='k',
|
|
403
|
-
levels=np.array(levels) * np.nanmax(yy))
|
|
404
|
-
ax[k].plot(self.popt[j], self.popt[i], 'o')
|
|
405
|
-
ax[k].axvline(self.popt[j])
|
|
406
|
-
ax[k].axhline(self.popt[i])
|
|
407
|
-
ax[k].set_xlim(cornerrange[j])
|
|
408
|
-
ax[k].set_ylim(cornerrange[i])
|
|
409
|
-
if j == 0:
|
|
410
|
-
ax[k].set_ylabel(labels[i])
|
|
411
|
-
plt.setp(ax[k].get_yticklabels(), rotation=45)
|
|
412
|
-
else:
|
|
413
|
-
plt.setp(ax[k].get_yticklabels(), visible=False)
|
|
414
|
-
if i == self.dim - 1:
|
|
415
|
-
ax[k].set_xlabel(labels[j])
|
|
416
|
-
plt.setp(ax[k].get_xticklabels(), rotation=45)
|
|
417
|
-
else:
|
|
418
|
-
plt.setp(ax[k].get_xticklabels(), visible=False)
|
|
438
|
+
self._i_neq_j(fig, ax, i, j, k)
|
|
439
|
+
del self.labels
|
|
440
|
+
del self.cornerrange
|
|
441
|
+
del self.cmap
|
|
442
|
+
del self.levels
|
|
419
443
|
close_figure(fig, savefig, show, tight=False)
|
|
420
444
|
|
|
421
445
|
def getDNSevidence(self, **kwargs):
|
|
@@ -74,7 +74,7 @@ def select_noise(data: np.ndarray, sigma: str) -> np.ndarray:
|
|
|
74
74
|
Returns:
|
|
75
75
|
np.ndarray: 1D array that includes only the selected pixels.
|
|
76
76
|
"""
|
|
77
|
-
n = np.array(data)
|
|
77
|
+
n = np.array(data).copy()
|
|
78
78
|
if 'edge' in sigma:
|
|
79
79
|
if np.ndim(n) <= 2:
|
|
80
80
|
print('\'edge\' is ignored because ndim <= 2.')
|
|
@@ -215,6 +215,6 @@ def estimate_rms(data: np.ndarray,
|
|
|
215
215
|
ave = n.m0
|
|
216
216
|
noise = n.s0
|
|
217
217
|
if np.abs(ave) > 0.2 * noise:
|
|
218
|
-
s = '
|
|
218
|
+
s = '|mean| > 0.2sigma.'
|
|
219
219
|
warnings.warn(s, UserWarning)
|
|
220
220
|
return noise
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plotastrodata
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.12
|
|
4
4
|
Summary: plotastrodata is a tool for astronomers to create figures from FITS files and perform fundamental data analyses with ease.
|
|
5
5
|
Home-page: https://github.com/yusukeaso-astron/plotastrodata
|
|
6
6
|
Download-URL: https://github.com/yusukeaso-astron/plotastrodata
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|