plotastrodata 1.7.13__tar.gz → 1.8.0__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.
Files changed (25) hide show
  1. {plotastrodata-1.7.13/plotastrodata.egg-info → plotastrodata-1.8.0}/PKG-INFO +1 -1
  2. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/__init__.py +1 -1
  3. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/analysis_utils.py +2 -2
  4. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/fits_utils.py +2 -2
  5. plotastrodata-1.8.0/plotastrodata/noise_utils.py +197 -0
  6. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/other_utils.py +0 -125
  7. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/plot_utils.py +2 -1
  8. {plotastrodata-1.7.13 → plotastrodata-1.8.0/plotastrodata.egg-info}/PKG-INFO +1 -1
  9. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata.egg-info/SOURCES.txt +1 -0
  10. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/LICENSE +0 -0
  11. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/MANIFEST.in +0 -0
  12. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/README.md +0 -0
  13. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/const_utils.py +0 -0
  14. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/coord_utils.py +0 -0
  15. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/ext_utils.py +0 -0
  16. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/fft_utils.py +0 -0
  17. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/fitting_utils.py +0 -0
  18. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/los_utils.py +0 -0
  19. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata/matrix_utils.py +0 -0
  20. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata.egg-info/dependency_links.txt +0 -0
  21. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata.egg-info/not-zip-safe +0 -0
  22. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata.egg-info/requires.txt +0 -0
  23. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/plotastrodata.egg-info/top_level.txt +0 -0
  24. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/setup.cfg +0 -0
  25. {plotastrodata-1.7.13 → plotastrodata-1.8.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plotastrodata
3
- Version: 1.7.13
3
+ Version: 1.8.0
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
@@ -1,4 +1,4 @@
1
1
  import warnings
2
2
 
3
3
  warnings.simplefilter('ignore', FutureWarning)
4
- __version__ = '1.7.13'
4
+ __version__ = '1.8.0'
@@ -7,8 +7,8 @@ from scipy.signal import convolve
7
7
 
8
8
  from plotastrodata.coord_utils import coord2xy, xy2coord, rel2abs
9
9
  from plotastrodata.matrix_utils import Mfac, Mrot, dot2d
10
- from plotastrodata.other_utils import (estimate_rms, trim,
11
- gaussian2d, isdeg,
10
+ from plotastrodata.noise_utils import estimate_rms
11
+ from plotastrodata.other_utils import (trim, gaussian2d, isdeg,
12
12
  RGIxy, RGIxyv, to4dim)
13
13
  from plotastrodata.fits_utils import FitsData, data2fits, Jy2K
14
14
  from plotastrodata import const_utils as cu
@@ -4,8 +4,8 @@ from astropy import units, wcs
4
4
 
5
5
  from plotastrodata.coord_utils import coord2xy, xy2coord
6
6
  from plotastrodata.matrix_utils import dot2d
7
- from plotastrodata.other_utils import (estimate_rms, trim, isdeg,
8
- RGIxy)
7
+ from plotastrodata.noise_utils import estimate_rms
8
+ from plotastrodata.other_utils import trim, isdeg, RGIxy
9
9
  from plotastrodata import const_utils as cu
10
10
 
11
11
 
@@ -0,0 +1,197 @@
1
+ import warnings
2
+ import numpy as np
3
+ from scipy.special import erf
4
+
5
+ from plotastrodata.fitting_utils import EmceeCorner
6
+
7
+
8
+ def normalize(range: tuple = (-3.5, 3.5), bins: int = 100):
9
+ """Decorator factory to normalize a function over the given range."""
10
+ def decorator(f):
11
+ h = np.linspace(*range, bins + 1)
12
+ h = (h[1:] + h[:-1]) / 2
13
+ dh = (range[1] - range[0]) / 100
14
+
15
+ def wrapper(x, *args):
16
+ area = np.sum(f(h, *args)) * dh
17
+ if area == 0:
18
+ p = np.where(np.abs(x - args[1]) < dh / 2, 1 / dh, 0)
19
+ else:
20
+ p = f(x, *args) / area
21
+ return p
22
+
23
+ return wrapper
24
+ return decorator
25
+
26
+
27
+ def gauss(x: np.ndarray, s: float, m: float) -> np.ndarray:
28
+ """Probability density of Gaussian noise.
29
+
30
+ Args:
31
+ x (np.ndarray): Intensity. The variable of the probability density.
32
+ s (float): Standard deviation of the Gaussian noise.
33
+ m (float): Mean of the Gaussian noise.
34
+
35
+ Returns:
36
+ np.ndarray: Probability density.
37
+ """
38
+ x1 = (x - m) / np.sqrt(2) / s
39
+ p = np.exp(-x1**2)
40
+ p = p / (np.sqrt(2 * np.pi) * s)
41
+ return p
42
+
43
+
44
+ def gauss_pbcor(x: np.ndarray, s: float, m: float, R: float
45
+ ) -> np.ndarray:
46
+ """Probability density of Gaussian noise after primary-beam correction.
47
+
48
+ Args:
49
+ x (np.ndarray): Intensity. The variable of the probability density.
50
+ s (float): Standard deviation of the Gaussian noise.
51
+ m (float): Mean of the Gaussian noise.
52
+ R (float): The maximum radius scaled by the FWHM of the primary beam.
53
+
54
+ Returns:
55
+ np.ndarray: Probability density.
56
+ """
57
+ x1 = (x - m) / np.sqrt(2) / s
58
+ x0 = (x * 2**(-R**2) - m) / np.sqrt(2) / s
59
+ p = erf(x1) - erf(x0)
60
+ p = p / (2 * np.log(2) * x * R**2)
61
+ return p
62
+
63
+
64
+ def select_noise(data: np.ndarray, sigma: str) -> np.ndarray:
65
+ """Select data pixels to be used for noise estimation.
66
+
67
+ Args:
68
+ data (np.ndarray): Original data array.
69
+ sigma (str): Selection methods. Multiple options are possible. 'edge', 'out', 'neg', or 'iter'.
70
+
71
+ Returns:
72
+ np.ndarray: 1D array that includes only the selected pixels.
73
+ """
74
+ n = data * 1
75
+ if 'edge' in sigma:
76
+ if np.ndim(n) <= 2:
77
+ print('\'edge\' is ignored because ndim <= 2.')
78
+ else:
79
+ n = n[::len(n) - 1]
80
+ if 'out' in sigma and 'pbcor' in sigma:
81
+ print('\'out\' is ignored because of \'pbcor\'.')
82
+ elif 'out' in sigma:
83
+ nx = np.shape(n)[-1]
84
+ ny = np.shape(n)[-2]
85
+ ntmp = np.moveaxis(n, [-2, -1], [0, 1])
86
+ ntmp[ny // 5: ny * 4 // 5, nx // 5: nx * 4 // 5] = np.nan
87
+ if np.all(np.isnan(ntmp)):
88
+ print('\'out\' is ignored because'
89
+ + ' the outer region is filled with nan.')
90
+ else:
91
+ n = ntmp
92
+ n = n[~np.isnan(n)]
93
+ if 'neg' in sigma:
94
+ n = n[n < 0]
95
+ n = np.r_[n, -n]
96
+ if 'iter' in sigma:
97
+ for _ in range(5):
98
+ n = n[np.abs(n - np.mean(n)) < 3.5 * np.std(n)]
99
+ return n.ravel()
100
+
101
+
102
+ class Noise:
103
+ def __init__(self, data: np.ndarray, sigma: str):
104
+ """This class holds the data selected as noise, histogram, and best-fit function.
105
+ The following methods are acceptable for data selection. Multiple options are possible.
106
+ 'edge': use data[0] and data[-1].
107
+ 'out': exclude inner 60% about axes=-2 and -1.
108
+ 'neg': use only negative values.
109
+ 'iter': exclude outliers.
110
+ The following methods are acceptable for noise estimation. Only single option is possible.
111
+ 'med': calculate rms from the median of data^2 assuming Gaussian.
112
+ 'hist': fit histgram with Gaussian.
113
+ 'hist-pbcor': fit histgram with PB-corrected Gaussian.
114
+ '(no string)': calculate the mean and standard deviation.
115
+
116
+ Args:
117
+ data (np.ndarray): Original data array.
118
+ sigma (str): Methods above, like 'edge,neg,hist-pbcor'.
119
+ """
120
+ self.data = select_noise(data, sigma)
121
+ self.sigma = sigma
122
+ self.m0 = np.mean(self.data)
123
+ self.s0 = np.std(self.data)
124
+
125
+ def gen_histogram(self, **kwargs):
126
+ """Generage a pair of histogram and bins using numpy.histogram. The data values are shifted and scaled by the mean and standard deviation, respectively, to generate the histogram. The mean and standard deviation are stored as self.m0 and self.s0, respectively.
127
+ """
128
+ _kw = {'bins': 100, 'range': (-3.5, 3.5), 'density': True}
129
+ _kw.update(kwargs)
130
+ self.bins = _kw['bins']
131
+ self.range = _kw['range']
132
+ n = (self.data - self.m0) / self.s0
133
+ hist, hbin = np.histogram(n, **_kw)
134
+ hbin = (hbin[:-1] + hbin[1:]) / 2
135
+ self.hist = hist
136
+ self.hbin = hbin
137
+
138
+ def fit_histogram(self, **kwargs):
139
+ """kwargs is for plotastrodata.fitting_utils.EmceeCorner.
140
+ """
141
+ _kw = {'nwalkersperdim': 4, 'nsteps': 200, 'nburnin': 0}
142
+ _kw.update(kwargs)
143
+ f = gauss_pbcor if 'pbcor' in self.sigma else gauss
144
+ model = normalize(range=self.range, bins=self.bins)(f)
145
+ bounds = [[0.1, 2], [-2, 2]]
146
+ if 'pbcor' in self.sigma:
147
+ bounds.append([0.1, 2])
148
+ # curve_fit does not work for this fitting.
149
+ # 0.01 in sigma is set only to search the best-fit parameters.
150
+ # Thus, this sigma does not justify the parameter errors.
151
+ fitter = EmceeCorner(bounds=bounds, model=model,
152
+ xdata=self.hbin, ydata=self.hist,
153
+ sigma=np.max(self.hist) * 0.01)
154
+ fitter.fit(**_kw)
155
+ self.popt = fitter.popt
156
+ self.mean = float(self.popt[1] * self.s0 + self.m0)
157
+ self.std = float(self.popt[0] * self.s0)
158
+ self.model = model(self.hbin, *self.popt)
159
+
160
+
161
+ def estimate_rms(data: np.ndarray,
162
+ sigma: float | str | None = 'hist'
163
+ ) -> float:
164
+ """Estimate a noise level of a N-D array.
165
+ When a float number or None is given, this function just outputs it.
166
+
167
+ Args:
168
+ data (np.ndarray): Data array whose noise is estimated.
169
+ sigma (float or str): Methods for the Noise class, like 'edge,neg,hist-pbcor'. Defaults to 'hist'.
170
+
171
+ Returns:
172
+ float: The estimated standard deviation of noise.
173
+ """
174
+ nums = [float, int, np.float64, np.int64, np.float32, np.int32]
175
+ if sigma is None or type(sigma) in nums:
176
+ return sigma
177
+
178
+ if np.ndim(np.squeeze(data)) == 0:
179
+ print('sigma cannot be estimated from only one pixel.')
180
+ return 0.0
181
+
182
+ n = Noise(data, sigma)
183
+ if 'hist' in sigma:
184
+ n.gen_histogram()
185
+ n.fit_histogram()
186
+ ave = n.mean
187
+ noise = n.std
188
+ elif 'med' in sigma:
189
+ ave = 0
190
+ noise = np.sqrt(np.median(n.data**2) / 0.454936)
191
+ else:
192
+ ave = n.m0
193
+ noise = n.s0
194
+ if np.abs(ave) > 0.2 * noise:
195
+ s = 'Mean > 0.2 x standard deviation.'
196
+ warnings.warn(s, UserWarning)
197
+ return noise
@@ -1,9 +1,6 @@
1
- import warnings
2
1
  import numpy as np
3
- from scipy.special import erf
4
2
  from scipy.interpolate import RegularGridInterpolator as RGI
5
3
 
6
- from plotastrodata.fitting_utils import EmceeCorner
7
4
  from plotastrodata.matrix_utils import Mrot, dot2d
8
5
 
9
6
 
@@ -37,128 +34,6 @@ def isdeg(s: str) -> bool:
37
34
  return False
38
35
 
39
36
 
40
- def estimate_rms(data: np.ndarray, sigma: float | str | None = 'hist'
41
- ) -> float:
42
- """Estimate a noise level of a N-D array.
43
- When a float number or None is given, this function just outputs it.
44
- Following methos are acceptable.
45
- 'edge': use data[0] and data[-1].
46
- 'neg': use only negative values.
47
- 'med': use the median of data^2 assuming Gaussian.
48
- 'iter': exclude outliers.
49
- 'out': exclude inner 60% about axes=-2 and -1.
50
- 'hist': fit histgram with Gaussian. This option can be combined with 'edge' and/or 'neg'.
51
- 'hist-pbcor': fit histgram with PB-corrected Gaussian. This option can be combined with 'edge' and/or 'neg'.
52
-
53
- Args:
54
- data (np.ndarray): N-D array.
55
- sigma (float or str): One of the methods above. Defaults to 'hist'.
56
-
57
- Returns:
58
- float: the estimated standard deviation of noise.
59
- """
60
- if sigma is None:
61
- return None
62
-
63
- def warning_offset(ave, noise):
64
- if np.abs(ave) > 0.2 * noise:
65
- s = 'The intensity offset is larger than 0.2 sigma.'
66
- warnings.warn(s, UserWarning)
67
-
68
- nums = [float, int, np.float64, np.int64, np.float32, np.int32]
69
- if type(sigma) in nums:
70
- noise = sigma
71
- elif np.ndim(np.squeeze(data)) == 0:
72
- print('sigma cannot be estimated from only one pixel.')
73
- noise = 0.0
74
- elif sigma == 'edge':
75
- ave = np.nanmean(data[::len(data) - 1])
76
- noise = np.nanstd(data[::len(data) - 1])
77
- warning_offset(ave, noise)
78
- elif sigma == 'neg':
79
- noise = np.sqrt(np.nanmean(data[data < 0]**2))
80
- elif sigma == 'med':
81
- noise = np.sqrt(np.nanmedian(data**2) / 0.454936)
82
- elif sigma == 'iter':
83
- n = data.copy()
84
- for _ in range(5):
85
- ave, sig = np.nanmean(n), np.nanstd(n)
86
- n = n - ave
87
- n = n[np.abs(n) < 3.5 * sig]
88
- ave = np.nanmean(n)
89
- noise = np.nanstd(n)
90
- warning_offset(ave, noise)
91
- elif sigma == 'out':
92
- n, n0, n1 = data * 1, len(data), len(data[0])
93
- n = np.moveaxis(n, [-2, -1], [0, 1])
94
- n[n0//5: n0*4//5, n1//5: n1*4//5] = np.nan
95
- if np.all(np.isnan(n)):
96
- print('sigma=\'neg\' instead of \'out\' because'
97
- + ' the outer region is filled with nan.')
98
- noise = np.sqrt(np.nanmean(data[data < 0]**2))
99
- else:
100
- ave = np.nanmean(n)
101
- noise = np.nanstd(n)
102
- warning_offset(ave, noise)
103
- elif 'hist' in sigma:
104
- n = data * 1
105
- if 'edge' in sigma:
106
- n = n[::len(n) - 1]
107
- if 'neg' in sigma:
108
- n = n[n < 0]
109
- n = np.r_[n, -n]
110
- n = n[~np.isnan(n)]
111
- m0, s0 = np.mean(n), np.std(n)
112
- hist, hbin = np.histogram((n - m0) / s0,
113
- bins=100, density=True,
114
- range=(-3.5, 3.5))
115
- hbin = (hbin[:-1] + hbin[1:]) / 2
116
- h = np.linspace(-3.5, 3.5, 101)
117
- dh = 0.07
118
-
119
- def normalize(f, x, *args):
120
- # For normalization within (-3.5, 3.5), not (-inf, inf).
121
- area = np.sum(f(h, *args)) * dh
122
- if area == 0:
123
- p = np.where(np.abs(x - args[1]) < dh / 2, 1 / dh, 0)
124
- else:
125
- p = f(x, *args) / area
126
- return p
127
-
128
- if 'pbcor' in sigma:
129
- bounds = [[0.1, 2], [-2, 2], [0.1, 2]]
130
-
131
- def g(x, *p):
132
- s, m, R = p
133
- x1 = (x - m) / np.sqrt(2) / s
134
- x0 = (x * 2**(-R**2) - m) / np.sqrt(2) / s
135
- p = erf(x1) - erf(x0)
136
- p = p / (2 * np.log(2) * x * R**2)
137
- return p
138
- else:
139
- bounds = [[0.1, 2], [-2, 2]]
140
-
141
- def g(x, *p):
142
- s, m = p
143
- x1 = (x - m) / np.sqrt(2) / s
144
- p = np.exp(-x1**2)
145
- p = p / (np.sqrt(2 * np.pi) * s)
146
- return p
147
-
148
- def model(x, *p):
149
- return normalize(g, x, *p)
150
- # curve_fit does not work for this fitting.
151
- fitter = EmceeCorner(bounds=bounds, model=model,
152
- xdata=hbin, ydata=hist,
153
- sigma=np.max(hist) * 0.01)
154
- fitter.fit(nwalkersperdim=4, nsteps=200, nburnin=0)
155
- popt = fitter.popt
156
- ave = popt[1] * s0 + m0
157
- noise = popt[0] * s0
158
- warning_offset(ave, noise)
159
- return noise
160
-
161
-
162
37
  def trim(data: np.ndarray | None = None, x: np.ndarray | None = None,
163
38
  y: np.ndarray | None = None, v: np.ndarray | None = None,
164
39
  xlim: list[float, float] | None = None,
@@ -6,7 +6,8 @@ from matplotlib.patches import Ellipse, Rectangle
6
6
  from dataclasses import dataclass
7
7
 
8
8
  from plotastrodata.coord_utils import coord2xy, xy2coord
9
- from plotastrodata.other_utils import listing, estimate_rms
9
+ from plotastrodata.noise_utils import estimate_rms
10
+ from plotastrodata.other_utils import listing
10
11
  from plotastrodata.analysis_utils import AstroData, AstroFrame
11
12
 
12
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plotastrodata
3
- Version: 1.7.13
3
+ Version: 1.8.0
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
@@ -13,6 +13,7 @@ plotastrodata/fits_utils.py
13
13
  plotastrodata/fitting_utils.py
14
14
  plotastrodata/los_utils.py
15
15
  plotastrodata/matrix_utils.py
16
+ plotastrodata/noise_utils.py
16
17
  plotastrodata/other_utils.py
17
18
  plotastrodata/plot_utils.py
18
19
  plotastrodata.egg-info/PKG-INFO
File without changes
File without changes
File without changes
File without changes