plotastrodata 1.1.4__tar.gz → 1.2.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 (20) hide show
  1. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/PKG-INFO +1 -1
  2. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/__init__.py +1 -1
  3. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/analysis_utils.py +5 -0
  4. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/const_utils.py +1 -1
  5. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/fits_utils.py +1 -1
  6. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/plot_utils.py +56 -25
  7. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata.egg-info/PKG-INFO +1 -1
  8. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/LICENSE +0 -0
  9. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/README.md +0 -0
  10. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/fft_utils.py +0 -0
  11. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/fitting_utils.py +0 -0
  12. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/los_utils.py +0 -0
  13. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata/other_utils.py +0 -0
  14. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata.egg-info/SOURCES.txt +0 -0
  15. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata.egg-info/dependency_links.txt +0 -0
  16. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata.egg-info/not-zip-safe +0 -0
  17. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata.egg-info/requires.txt +0 -0
  18. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/plotastrodata.egg-info/top_level.txt +0 -0
  19. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/setup.cfg +0 -0
  20. {plotastrodata-1.1.4 → plotastrodata-1.2.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plotastrodata
3
- Version: 1.1.4
3
+ Version: 1.2.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', UserWarning)
4
- __version__ = '1.1.4'
4
+ __version__ = '1.2.0'
@@ -161,6 +161,7 @@ class AstroData():
161
161
  center (str, optional): Text coordinates. 'common' means initialized value. Defaults to 'common'.
162
162
  restfreq (float, optional): Used for velocity and brightness T. Defaults to None.
163
163
  cfactor (float, optional): Output data times cfactor. Defaults to 1.
164
+ pvpa (float, optional): Position angle of the PV cut. Defaults to None.
164
165
  """
165
166
  data: np.ndarray | None = None
166
167
  x: np.ndarray | None = None
@@ -173,6 +174,7 @@ class AstroData():
173
174
  center: str = 'common'
174
175
  restfreq: float | None = None
175
176
  cfactor: float = 1
177
+ pvpa: float | None = None
176
178
 
177
179
  def __post_init__(self):
178
180
  n = 0
@@ -707,6 +709,8 @@ class AstroFrame():
707
709
  d.fitsheader = [d.fitsheader] * d.n
708
710
  if type(d.pv) is not list:
709
711
  d.pv = [d.pv] * d.n
712
+ if type(d.pvpa) is not list:
713
+ d.pvpa = [d.pvpa] * d.n
710
714
  grid0 = [d.x, d.y, d.v]
711
715
  for i in range(d.n):
712
716
  if d.center[i] == 'common':
@@ -791,3 +795,4 @@ class AstroFrame():
791
795
  d.sigma_org = d.sigma_org[0]
792
796
  d.fitsheader = d.fitsheader[0]
793
797
  d.pv = d.pv[0]
798
+ d.pvpa = d.pvpa[0]
@@ -81,4 +81,4 @@ quecto = 1e-30
81
81
  # Others
82
82
  mumol = 2.37 * m_p # kg; Kauffmann et al. 2008, for sound speed
83
83
  muH2 = 2.8 * m_p # kg; Kauffmann et al. 2008, for mass-H2 conversion
84
- c_kms = constants.c.to('km*s**(-1)').value
84
+ c_kms = constants.c.to('km*s**(-1)').value
@@ -255,7 +255,7 @@ class FitsData:
255
255
  print(f'Unknown CUNIT3 {cunitv} found.'
256
256
  + ' v is read as is.')
257
257
  s = s - vsys
258
-
258
+
259
259
  self.v, self.dv = s, s[1] - s[0]
260
260
 
261
261
  if h['NAXIS'] > 0 and h['NAXIS1'] > 1:
@@ -356,12 +356,11 @@ class PlotAstroData(AstroFrame):
356
356
  else:
357
357
  v = v[:k1]
358
358
  if self.pv or v is None or len(v) == 1:
359
- nv = nrows = ncols = npages = nchan = nchanplot = 1
359
+ nv = nrows = ncols = npages = nchan = 1
360
360
  else:
361
361
  nv = len(v := v[::vskip])
362
362
  npages = int(np.ceil(nv / nrows / ncols))
363
363
  nchan = npages * nrows * ncols
364
- nchanplot = len(v)
365
364
  v = np.r_[v, v[-1] + (np.arange(nchan-nv)+1) * (v[1] - v[0])]
366
365
  if type(channelnumber) is int:
367
366
  nchan = npages = 1
@@ -379,15 +378,15 @@ class PlotAstroData(AstroFrame):
379
378
  fontsize = 18 if nchan == 1 else 12
380
379
  set_rcparams(fontsize=fontsize, nancolor=nancolor, dpi=dpi)
381
380
  ax = np.empty(nchan, dtype='object') if internalax else [ax]
381
+ if figsize is None:
382
+ sqrt_a = (self.ymax - self.ymin) / (self.xmax - self.xmin)
383
+ sqrt_a = np.sqrt(np.abs(sqrt_a))
384
+ if nchan == 1:
385
+ figsize = (7 / sqrt_a, 5 * sqrt_a)
386
+ else:
387
+ figsize = (ncols * 2 / sqrt_a, max(nrows*2, 3) * sqrt_a)
382
388
  for ch in range(nchan):
383
389
  n, i, j = ch2nij(ch)
384
- if figsize is None:
385
- sqrt_a = (self.ymax - self.ymin) / (self.xmax - self.xmin)
386
- sqrt_a = np.sqrt(np.abs(sqrt_a))
387
- if nchan == 1:
388
- figsize = (7 / sqrt_a, 5 * sqrt_a)
389
- else:
390
- figsize = (ncols * 2 / sqrt_a, max(nrows*2, 3) * sqrt_a)
391
390
  if internalfig:
392
391
  fig = plt.figure(n, figsize=figsize)
393
392
  sharex = ax[nij2ch(n, i - 1, j)] if i > 0 else None
@@ -397,8 +396,8 @@ class PlotAstroData(AstroFrame):
397
396
  sharex=sharex, sharey=sharey)
398
397
  if nchan > 1 or type(channelnumber) is int:
399
398
  fig.subplots_adjust(hspace=0, wspace=0, right=0.87, top=0.87)
400
- vellabel = v[ch] if channelnumber is None else v[channelnumber]
401
- if ch < nchanplot:
399
+ if ch < nv:
400
+ vellabel = v[ch] if channelnumber is None else v[channelnumber]
402
401
  ax[ch].text(0.9 * self.rmax, 0.7 * self.rmax,
403
402
  rf'${vellabel:.{veldigit:d}f}$', color='black',
404
403
  backgroundcolor='white', zorder=20)
@@ -406,7 +405,7 @@ class PlotAstroData(AstroFrame):
406
405
  self.ax = ax
407
406
  self.rowcol = nrows * ncols
408
407
  self.npages = npages
409
- self.allchan = np.arange(nchan if channelnumber is None else nv)
408
+ self.allchan = np.arange(nv)
410
409
  self.bottomleft = nij2ch(np.arange(npages), nrows - 1, 0)
411
410
  self.channelnumber = channelnumber
412
411
 
@@ -484,25 +483,62 @@ class PlotAstroData(AstroFrame):
484
483
  def add_beam(self,
485
484
  beam: list[float | None, float | None, float | None] = [None, None, None],
486
485
  beamcolor: str = 'gray',
487
- poslist: list[str | list[float, float]] | None = None) -> None:
486
+ poslist: list[str | list[float, float]] | None = None,
487
+ dv: float | None = None, pvpa: float | None = None) -> None:
488
488
  """Use add_region().
489
489
 
490
490
  Args:
491
491
  beam (list, optional): [bmaj, bmin, bpa]. Defaults to [None, None, None].
492
492
  beamcolor (str, optional): matplotlib color. Defaults to 'gray'.
493
493
  poslist (list, optional): text or relative. Defaults to None.
494
+ dv (float, optional): velocity resolution for a PV diagram. Defaults to None.
495
+ pvpa (float, optional): position angle of the PV cut in the unit of degrees. Defaults to None.
494
496
  """
495
497
  if None in beam:
496
498
  print('No beam to plot.')
497
499
  return False
498
500
 
499
- if poslist is None:
500
- poslist = [max(0.35 * beam[0] / self.rmax, 0.1)] * 2
501
501
  include_chan = self.bottomleft if self.channelnumber is None else self.allchan
502
- self.add_region('ellipse', poslist, *beam,
502
+ if self.pv:
503
+ if pvpa is None:
504
+ pvpa = beam[0]
505
+ print('pvpa is not specified. pvpa=bmaj is assumed.')
506
+ p = np.radians(beam[2] - pvpa)
507
+ b = 1 / np.hypot(np.cos(p) / beam[0], np.sin(p) / beam[1]) / self.rmax
508
+ b = np.array([b, dv])
509
+ if poslist is None:
510
+ poslist = [max(0.35 * b[0], 0.1), 0.1]
511
+ if self.swapxy:
512
+ poslist = np.transpose(poslist)
513
+ b = np.transpose(b)
514
+ b = np.append(b, 0)
515
+ patch = 'rectangle'
516
+ else:
517
+ if poslist is None:
518
+ poslist = [max(0.35 * beam[0] / self.rmax, 0.1)] * 2
519
+ b = beam
520
+ patch = 'ellipse'
521
+ self.add_region(patch, poslist, *b,
503
522
  include_chan=include_chan,
504
523
  facecolor=beamcolor, edgecolor=None)
505
524
 
525
+ def _beam(self, show_beam: bool, beamcolor: str | list[str], d: AstroData):
526
+ """Internal wrapper of add_beam().
527
+
528
+ Args:
529
+ show_beam (bool): Whether to show the beam(s).
530
+ beamcolor (str | list[str]): Color name.
531
+ d (AstroData): For reading the velocity resolution, beam, and pvpa.
532
+ """
533
+ if show_beam:
534
+ dv = d.v[1] - d.v[0] if self.pv else None
535
+ c = type(beamcolor) is list
536
+ beam = d.beam if c else [d.beam]
537
+ bc = beamcolor if c else [beamcolor]
538
+ pvpa = d.pvpa if c else [d.pvpa]
539
+ for i in range(len(bc)):
540
+ self.add_beam(beam=beam[i], beamcolor=bc[i], dv=dv, pvpa=pvpa[i])
541
+
506
542
  def add_marker(self, poslist: list[str | list[float, float]] = [],
507
543
  include_chan: list[int] | None = None, **kwargs) -> None:
508
544
  """Use Axes.plot of matplotlib.
@@ -715,8 +751,7 @@ class PlotAstroData(AstroFrame):
715
751
  ticklin = 1 + (1 - stretchpower) * np.log(10) * t
716
752
  ticklin = cmin_org * ticklin**(1 / (1 - stretchpower))
717
753
  cb.set_ticklabels([f'{d:{cbformat[1:]}}' for d in ticklin])
718
- if show_beam and not self.pv:
719
- self.add_beam(beam, beamcolor)
754
+ self._beam(show_beam, beamcolor, d)
720
755
 
721
756
  def add_contour(self, xskip: int = 1, yskip: int = 1,
722
757
  levels: list[float] = [-12, -6, -3, 3, 6, 12, 24, 48, 96, 192, 384],
@@ -742,8 +777,7 @@ class PlotAstroData(AstroFrame):
742
777
  c = [c[self.channelnumber]]
743
778
  for axnow, cnow in zip(self.ax, c):
744
779
  axnow.contour(x, y, cnow, np.sort(levels) * sigma, **_kw)
745
- if show_beam and not self.pv:
746
- self.add_beam(beam, beamcolor)
780
+ self._beam(show_beam, beamcolor, d)
747
781
 
748
782
  def add_segment(self, ampfits: str = None, angfits: str = None,
749
783
  Ufits: str = None, Qfits: str = None,
@@ -809,8 +843,7 @@ class PlotAstroData(AstroFrame):
809
843
  _kw['scale'] = 1 if len(x) == 1 else 1. / np.abs(x[1] - x[0])
810
844
  for axnow, unow, vnow in zip(self.ax, U, V):
811
845
  axnow.quiver(x, y, unow, vnow, **_kw)
812
- if show_beam and not self.pv:
813
- self.add_beam(beam, beamcolor)
846
+ self._beam(show_beam, [beamcolor] * 2, d)
814
847
 
815
848
  def add_rgb(self, xskip: int = 1, yskip: int = 1,
816
849
  stretch: list[str, str, str] = ['linear'] * 3,
@@ -860,9 +893,7 @@ class PlotAstroData(AstroFrame):
860
893
  im.putpixel((i, j), value)
861
894
  axnow.imshow(im, extent=[x[0], x[-1], y[0], y[-1]])
862
895
  axnow.set_aspect(np.abs((x[-1]-x[0]) / (y[-1]-y[0])))
863
- if show_beam and not self.pv:
864
- for i in range(3):
865
- self.add_beam(beam[i], beamcolor[i])
896
+ self._beam(show_beam, beamcolor, d)
866
897
 
867
898
  def set_axis(self, title: dict | str | None = None, **kwargs) -> None:
868
899
  """Use Axes.set_* of matplotlib. kwargs can include the arguments of PlotAxes2D to adjust x and y axis.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plotastrodata
3
- Version: 1.1.4
3
+ Version: 1.2.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
File without changes
File without changes
File without changes
File without changes