plotastrodata 1.9.20__tar.gz → 1.9.21__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.9.20/plotastrodata.egg-info → plotastrodata-1.9.21}/PKG-INFO +2 -2
  2. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/__init__.py +1 -1
  3. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/fitting_utils.py +45 -18
  4. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/other_utils.py +2 -2
  5. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/plot_utils.py +18 -19
  6. {plotastrodata-1.9.20 → plotastrodata-1.9.21/plotastrodata.egg-info}/PKG-INFO +2 -2
  7. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata.egg-info/requires.txt +1 -1
  8. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/setup.cfg +1 -1
  9. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/LICENSE +0 -0
  10. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/MANIFEST.in +0 -0
  11. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/README.md +0 -0
  12. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/analysis_utils.py +0 -0
  13. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/const_utils.py +0 -0
  14. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/coord_utils.py +0 -0
  15. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/ext_utils.py +0 -0
  16. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/fft_utils.py +0 -0
  17. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/fits_utils.py +0 -0
  18. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/los_utils.py +0 -0
  19. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/matrix_utils.py +0 -0
  20. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata/noise_utils.py +0 -0
  21. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata.egg-info/SOURCES.txt +0 -0
  22. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata.egg-info/dependency_links.txt +0 -0
  23. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata.egg-info/not-zip-safe +0 -0
  24. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/plotastrodata.egg-info/top_level.txt +0 -0
  25. {plotastrodata-1.9.20 → plotastrodata-1.9.21}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plotastrodata
3
- Version: 1.9.20
3
+ Version: 1.9.21
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
@@ -14,7 +14,7 @@ License-File: LICENSE
14
14
  Requires-Dist: astropy>=7.2
15
15
  Requires-Dist: corner
16
16
  Requires-Dist: dynesty
17
- Requires-Dist: emcee
17
+ Requires-Dist: emcee>=3.0
18
18
  Requires-Dist: matplotlib
19
19
  Requires-Dist: numpy>=2.0
20
20
  Requires-Dist: pillow
@@ -1,4 +1,4 @@
1
1
  import warnings
2
2
 
3
3
  warnings.simplefilter('ignore', FutureWarning)
4
- __version__ = '1.9.20'
4
+ __version__ = '1.9.21'
@@ -2,9 +2,11 @@ import corner
2
2
  import emcee
3
3
  import matplotlib.pyplot as plt
4
4
  import numpy as np
5
+ import pickle
5
6
  import ptemcee
6
7
  import warnings
7
8
  from dynesty import DynamicNestedSampler as DNS
9
+ from functools import partial
8
10
  from multiprocessing import Pool
9
11
  from tqdm import tqdm
10
12
  from typing import Any, Callable
@@ -18,6 +20,25 @@ bar = None
18
20
  global_progressbar = True
19
21
 
20
22
 
23
+ def _gaussian_log_likelihood(x: np.ndarray, model: Callable,
24
+ xdata: np.ndarray, ydata: np.ndarray,
25
+ sigma: float | np.ndarray) -> float:
26
+ """Return a Gaussian log likelihood using pickleable arguments."""
27
+ chi2 = np.sum((ydata - model(xdata, *x))**2 / sigma**2)
28
+ return chi2 / (-2)
29
+
30
+
31
+ def _bounded_log_probability(x: np.ndarray, log_likelihood: Callable,
32
+ bounds: np.ndarray,
33
+ update_progress: bool = False) -> float:
34
+ """Combine a bounded uniform prior with a log likelihood."""
35
+ if update_progress:
36
+ bar.update(1)
37
+ if np.all((bounds[:, 0] < x) & (x < bounds[:, 1])):
38
+ return log_likelihood(x)
39
+ return -np.inf
40
+
41
+
21
42
  def logp(x: np.ndarray) -> float:
22
43
  """Log prior function made from the boundary (global_bounds) of fitting parameters.
23
44
 
@@ -95,9 +116,8 @@ class EmceeCorner():
95
116
  if logl is None and (model is not None
96
117
  and xdata is not None
97
118
  and ydata is not None):
98
- def logl(x: np.ndarray) -> float:
99
- chi2 = np.sum((ydata - model(xdata, *x))**2 / sigma**2)
100
- return chi2 / (-2)
119
+ logl = partial(_gaussian_log_likelihood, model=model,
120
+ xdata=xdata, ydata=ydata, sigma=sigma)
101
121
  self.bounds = global_bounds
102
122
  self.dim = len(self.bounds)
103
123
  self.logl = logl
@@ -125,21 +145,27 @@ class EmceeCorner():
125
145
  'logl': self.logl, 'logp': self.logp}
126
146
  else:
127
147
  if ncores > 1:
128
- print('Use logl as log_prob_fn to avoid function-in-function.')
129
- log_prob_fn = self.logl
130
- else:
131
- def log_prob_fn(x: np.ndarray) -> float:
132
- return self.logp(x) + self.logl(x)
148
+ try:
149
+ pickle.dumps(self.logl)
150
+ except (pickle.PicklingError, AttributeError, TypeError) as exc:
151
+ raise TypeError(
152
+ 'logl and model must be pickleable when ncores > 1. '
153
+ 'Define them at module scope instead of inside another '
154
+ 'function.') from exc
133
155
 
134
156
  sampler_cls = emcee.EnsembleSampler
135
157
  sampler_kwargs = {'nwalkers': nwalkers, 'ndim': self.dim,
136
- 'log_prob_fn': log_prob_fn}
158
+ 'log_prob_fn': _bounded_log_probability,
159
+ 'args': (self.logl, self.bounds,
160
+ global_progressbar and ncores == 1)}
137
161
  if ncores > 1:
138
162
  with Pool(ncores) as pool:
139
163
  sampler = sampler_cls(**sampler_kwargs, pool=pool)
164
+ # This run_mcmc is duplicated so sampling finishes before the pool closes.
165
+ sampler.run_mcmc(pos0, nsteps)
140
166
  else:
141
167
  sampler = sampler_cls(**sampler_kwargs, pool=None)
142
- sampler.run_mcmc(pos0, nsteps)
168
+ sampler.run_mcmc(pos0, nsteps)
143
169
  return sampler
144
170
 
145
171
  def _get_samples(self, sampler: Any, nburnin: int,
@@ -190,7 +216,7 @@ class EmceeCorner():
190
216
  ntry (int, optional): Number of trials for the Gelman-Rubin check. Defaults to 1.
191
217
  pos0 (np.nparray, optional): Initial parameter set in the shape of (ntemps, nwalkers, dim). Defaults to None.
192
218
  savechain (str, optional): File name of the chain in format of .npy. Existing files with the same name are overwritten by ``numpy.save``. Defaults to None.
193
- ncores (int, optional): Number of cores for multiprocessing.Pool. ncores=1 does not use multiprocessing. Defaults to 1.
219
+ ncores (int, optional): Number of cores for multiprocessing.Pool. ncores=1 does not use multiprocessing. For ncores > 1, user-supplied logl and model functions must be pickleable, such as functions defined at module scope. Defaults to 1.
194
220
  grcheck (bool, optional): Whether to check Gelman-Rubin statistics. Defaults to False.
195
221
  pt (bool, optional): Whether to use ptemcee; otherwise, emcee is used. Defaults to False.
196
222
  """
@@ -243,13 +269,14 @@ class EmceeCorner():
243
269
  labels = [f'Par {i:d}' for i in range(self.dim)]
244
270
  if cornerrange is None:
245
271
  cornerrange = self.bounds
246
- corner.corner(np.reshape(self.samples, (-1, self.dim)),
247
- truths=self.popt,
248
- quantiles=[self.percent[0] / 100,
249
- 0.5,
250
- self.percent[1] / 100],
251
- show_titles=True, labels=labels, range=cornerrange)
252
- close_figure(plt, savefig, show, tight=False)
272
+ fig = corner.corner(np.reshape(self.samples, (-1, self.dim)),
273
+ truths=self.popt,
274
+ quantiles=[self.percent[0] / 100,
275
+ 0.5,
276
+ self.percent[1] / 100],
277
+ show_titles=True, labels=labels,
278
+ range=cornerrange)
279
+ close_figure(fig, savefig, show, tight=False)
253
280
 
254
281
  def plotchain(self, labels: list | None = None, ylim: list | None = None,
255
282
  savefig: dict | str | None = None,
@@ -296,7 +296,7 @@ def close_figure(fig: object, savefig: dict | str | None = None,
296
296
  show: bool = False, tight: bool = True) -> None:
297
297
  """Save, show, and close the figure.
298
298
 
299
- If ``savefig`` is provided, the figure is saved with Matplotlib ``Figure.savefig``. Existing files with the same name are overwritten by Matplotlib. After optional saving/showing, the figure is closed with ``plt.close()``.
299
+ If ``savefig`` is provided, the figure is saved with Matplotlib ``Figure.savefig``. Existing files with the same name are overwritten by Matplotlib. After optional saving/showing, the figure is closed with ``plt.close(fig)``.
300
300
 
301
301
  Default keyword values:
302
302
  Figure.savefig: ``bbox_inches='tight'`` and ``transparent=True``. Values in ``savefig`` override these defaults.
@@ -316,4 +316,4 @@ def close_figure(fig: object, savefig: dict | str | None = None,
316
316
  fig.savefig(**savefig0)
317
317
  if show:
318
318
  plt.show()
319
- plt.close()
319
+ plt.close(fig)
@@ -564,13 +564,18 @@ class PlotAstroData(AstroFrame):
564
564
  figsize=figsize,
565
565
  ncols=ncols, nrows=nrows, nchan=nchan)
566
566
  need_vlabel = nchan > 1 or animation
567
+ figs = []
567
568
  for ch in range(nchan):
568
569
  n, i, j = ch2nij(ch)
569
- if internalfig and n not in plt.get_fignums():
570
- fig = plt.figure(n, figsize=figsize)
570
+ if n == len(figs):
571
+ if internalfig:
572
+ fig = plt.figure(figsize=figsize)
573
+ figs.append(fig)
571
574
  if need_vlabel:
572
575
  fig.subplots_adjust(hspace=0, wspace=0,
573
576
  right=0.87, top=0.87)
577
+ else:
578
+ fig = figs[n]
574
579
  if internalax:
575
580
  sharex = ax[nij2ch(n, i - 1, j)] if i > 0 else None
576
581
  sharey = ax[nij2ch(n, i, j - 1)] if j > 0 else None
@@ -582,6 +587,7 @@ class PlotAstroData(AstroFrame):
582
587
  rf'${vlabel:.{veldigit}f}$', color='black',
583
588
  backgroundcolor='white', zorder=20)
584
589
  self.fig = None if internalfig else fig
590
+ self.figs = figs
585
591
  self.ax = ax
586
592
  self.rowcol = nrows * ncols
587
593
  self.npages = npages
@@ -657,8 +663,6 @@ class PlotAstroData(AstroFrame):
657
663
  for ch, axnow in enumerate(self.ax):
658
664
  if ch not in self._validchan(include_chan):
659
665
  continue
660
- if self.fig is None:
661
- plt.figure(ch // self.rowcol)
662
666
  if patch == 'rectangle':
663
667
  a = np.radians(angle)
664
668
  xp = x - (width*np.cos(a) + height*np.sin(a)) / 2.
@@ -857,16 +861,13 @@ class PlotAstroData(AstroFrame):
857
861
  if not show_cbar:
858
862
  return
859
863
 
860
- if self.fig is None:
861
- fig = plt.figure(ch // self.rowcol)
862
- else:
863
- fig = self.fig
864
+ fig = self.figs[ch // self.rowcol]
864
865
  if len(self.ax) == 1:
865
866
  ax = self.ax[ch]
866
867
  cb = fig.colorbar(mappable[ch], ax=ax, label=cblabel,
867
868
  format=cbformat, location=cblocation)
868
869
  else:
869
- cax = plt.axes([0.88, 0.105, 0.015, 0.77])
870
+ cax = fig.add_axes([0.88, 0.105, 0.015, 0.77])
870
871
  cb = fig.colorbar(mappable[ch], cax=cax, label=cblabel,
871
872
  format=cbformat)
872
873
  cb.ax.tick_params(labelsize=cbtickfontsize)
@@ -1104,14 +1105,13 @@ class PlotAstroData(AstroFrame):
1104
1105
  axnow.set_ylabel('')
1105
1106
  if len(self.ax) == 1:
1106
1107
  if self.fig is None:
1107
- plt.figure(0).tight_layout()
1108
+ self.figs[0].tight_layout()
1108
1109
  if title is not None:
1109
1110
  if len(self.ax) > 1:
1110
1111
  t = {'y': 0.9}
1111
1112
  t_in = {'t': title} if isinstance(title, str) else title
1112
1113
  t.update(t_in)
1113
- for i in range(self.npages):
1114
- fig = plt.figure(i)
1114
+ for fig in self.figs:
1115
1115
  fig.suptitle(**t)
1116
1116
  else:
1117
1117
  t = {'label': title} if isinstance(title, str) else title
@@ -1249,13 +1249,13 @@ class PlotAstroData(AstroFrame):
1249
1249
  show: bool = False, **kwargs: Any) -> None:
1250
1250
  """Use savefig of matplotlib.
1251
1251
 
1252
- If ``filename`` is provided, existing files with the same name are overwritten by Matplotlib. This method closes all Matplotlib figures with ``plt.close('all')`` after optional saving/showing.
1252
+ If ``filename`` is provided, existing files with the same name are overwritten by Matplotlib. After optional saving/showing, figures managed by this instance are closed.
1253
1253
 
1254
1254
  Default keyword values:
1255
1255
  Figure.savefig: ``transparent=True`` and ``bbox_inches='tight'``. User-supplied keyword arguments override these values.
1256
1256
 
1257
1257
  Args:
1258
- filename (str, optional): Output image file name. Existing files may be overwritten, and all Matplotlib figures are closed after saving/showing. Defaults to None.
1258
+ filename (str, optional): Output image file name. Existing files may be overwritten, and figures managed by this instance are closed after saving/showing. Defaults to None.
1259
1259
  show (bool, optional): True means doing plt.show(). Defaults to False.
1260
1260
  """
1261
1261
  _kw = {'transparent': True, 'bbox_inches': 'tight'}
@@ -1265,15 +1265,15 @@ class PlotAstroData(AstroFrame):
1265
1265
  axnow.set_ylim(*self.Ylim)
1266
1266
  if isinstance(filename, str):
1267
1267
  ext = filename.split('.')[-1]
1268
- for i in range(self.npages):
1268
+ for i, fig in enumerate(self.figs):
1269
1269
  ver = '' if self.npages == 1 else f'_{i:d}'
1270
- fig = plt.figure(i)
1271
1270
  fig.patch.set_alpha(0)
1272
1271
  fname = filename.replace(f'.{ext}', f'{ver}.{ext}')
1273
1272
  fig.savefig(fname, **_kw)
1274
1273
  if show:
1275
1274
  plt.show()
1276
- plt.close('all')
1275
+ for fig in self.figs:
1276
+ plt.close(fig)
1277
1277
 
1278
1278
  def get_figax(self) -> tuple[object, object] | None:
1279
1279
  """Output the external fig and ax after plotting.
@@ -1286,8 +1286,7 @@ class PlotAstroData(AstroFrame):
1286
1286
  + ' with channel maps')
1287
1287
  return
1288
1288
 
1289
- fig = plt.figure(0) if self.fig is None else self.fig
1290
- return fig, self.ax[0]
1289
+ return self.figs[0], self.ax[0]
1291
1290
 
1292
1291
 
1293
1292
  def _get_ylabel_profile(_kw: dict, Tb: bool, flux: bool, bunit: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plotastrodata
3
- Version: 1.9.20
3
+ Version: 1.9.21
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
@@ -14,7 +14,7 @@ License-File: LICENSE
14
14
  Requires-Dist: astropy>=7.2
15
15
  Requires-Dist: corner
16
16
  Requires-Dist: dynesty
17
- Requires-Dist: emcee
17
+ Requires-Dist: emcee>=3.0
18
18
  Requires-Dist: matplotlib
19
19
  Requires-Dist: numpy>=2.0
20
20
  Requires-Dist: pillow
@@ -1,7 +1,7 @@
1
1
  astropy>=7.2
2
2
  corner
3
3
  dynesty
4
- emcee
4
+ emcee>=3.0
5
5
  matplotlib
6
6
  numpy>=2.0
7
7
  pillow
@@ -19,7 +19,7 @@ install_requires =
19
19
  astropy >= 7.2
20
20
  corner
21
21
  dynesty
22
- emcee
22
+ emcee >= 3.0
23
23
  matplotlib
24
24
  numpy >= 2.0
25
25
  pillow
File without changes
File without changes
File without changes