plotastrodata 1.9.5__tar.gz → 1.9.7__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.5/plotastrodata.egg-info → plotastrodata-1.9.7}/PKG-INFO +1 -1
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/__init__.py +1 -1
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/analysis_utils.py +157 -141
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/fits_utils.py +1 -1
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/plot_utils.py +60 -48
- {plotastrodata-1.9.5 → plotastrodata-1.9.7/plotastrodata.egg-info}/PKG-INFO +1 -1
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/LICENSE +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/MANIFEST.in +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/README.md +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/const_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/coord_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/ext_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/fft_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/fitting_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/los_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/matrix_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/noise_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata/other_utils.py +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata.egg-info/SOURCES.txt +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata.egg-info/dependency_links.txt +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata.egg-info/not-zip-safe +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata.egg-info/requires.txt +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/plotastrodata.egg-info/top_level.txt +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/setup.cfg +0 -0
- {plotastrodata-1.9.5 → plotastrodata-1.9.7}/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.7
|
|
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
|
|
@@ -575,6 +575,26 @@ class AstroData():
|
|
|
575
575
|
fitsimage=fitsimage)
|
|
576
576
|
|
|
577
577
|
|
|
578
|
+
def _as_list(value, n: int, isbeam: bool = False):
|
|
579
|
+
if isbeam:
|
|
580
|
+
return [value] * n if np.ndim(value) == 1 else value
|
|
581
|
+
else:
|
|
582
|
+
return value if isinstance(value, list) else [value] * n
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def _scalar_if_single(value, n: int):
|
|
586
|
+
return value[0] if n == 1 else value
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
def _get_gridsep(axis: np.ndarray | None):
|
|
590
|
+
return axis[1] - axis[0] if axis is not None and len(axis) > 1 else None
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
ASTRODATA_ARGS = ["fitsimage", "data", "Tb", "sigma", "center", "restfreq",
|
|
594
|
+
"cfactor", "bunit", "fitsimage_org", "sigma_org",
|
|
595
|
+
"beam_org", "fitsheader", "pv", "pvpa"]
|
|
596
|
+
|
|
597
|
+
|
|
578
598
|
@dataclass
|
|
579
599
|
class AstroFrame():
|
|
580
600
|
"""Parameter set to limit and reshape the data in the AstroData format.
|
|
@@ -666,6 +686,135 @@ class AstroFrame():
|
|
|
666
686
|
x[i], y[i] = rel2abs(*p, self.Xlim, self.Ylim)
|
|
667
687
|
return np.array([x, y])
|
|
668
688
|
|
|
689
|
+
def _get_restfreq(self, header: dict):
|
|
690
|
+
"""Extract rest frequency from FITS header."""
|
|
691
|
+
if "NAXIS3" in header and header["NAXIS3"] == 1 and not self.pv:
|
|
692
|
+
return header["CRVAL3"]
|
|
693
|
+
if "RESTFRQ" in header:
|
|
694
|
+
return header["RESTFRQ"]
|
|
695
|
+
if "RESTFREQ" in header:
|
|
696
|
+
return header["RESTFREQ"]
|
|
697
|
+
return None
|
|
698
|
+
|
|
699
|
+
def _read_fitsimage(self, d: AstroData, i: int, grid: list) -> list:
|
|
700
|
+
"""Read FITS-derived values into d and return the FITS grid."""
|
|
701
|
+
if d.fitsimage[i] is None:
|
|
702
|
+
return grid
|
|
703
|
+
|
|
704
|
+
fd = FitsData(d.fitsimage[i])
|
|
705
|
+
if d.fitsheader[i] is None:
|
|
706
|
+
d.fitsheader[i] = fd.get_header()
|
|
707
|
+
if d.center[i] is None and not self.pv:
|
|
708
|
+
d.center[i] = fd.get_center()
|
|
709
|
+
if d.restfreq[i] is None:
|
|
710
|
+
d.restfreq[i] = self._get_restfreq(d.fitsheader[i])
|
|
711
|
+
d.data[i] = fd.get_data()
|
|
712
|
+
grid = fd.get_grid(center=d.center[i], dist=self.dist,
|
|
713
|
+
restfreq=d.restfreq[i], vsys=self.vsys,
|
|
714
|
+
pv=self.pv)
|
|
715
|
+
if fd.wcsrot:
|
|
716
|
+
d.center[i] = fd.get_center()
|
|
717
|
+
d.beam[i] = fd.get_beam(dist=self.dist)
|
|
718
|
+
d.bunit[i] = fd.get_header("BUNIT")
|
|
719
|
+
return grid
|
|
720
|
+
|
|
721
|
+
def _no_newcenter(self, center: str | None):
|
|
722
|
+
return (self.pv
|
|
723
|
+
or self.center is None
|
|
724
|
+
or center is None
|
|
725
|
+
or center == self.center)
|
|
726
|
+
|
|
727
|
+
def _shift_center(self, d: AstroData, i: int, grid: list) -> list:
|
|
728
|
+
if self._no_newcenter(d.center[i]):
|
|
729
|
+
return grid
|
|
730
|
+
|
|
731
|
+
cx, cy = coord2xy(d.center[i], self.center) * 3600
|
|
732
|
+
grid[0] = grid[0] + cx # Don't use += cx.
|
|
733
|
+
grid[1] = grid[1] + cy # Don't use += cy.
|
|
734
|
+
d.center[i] = self.center
|
|
735
|
+
return grid
|
|
736
|
+
|
|
737
|
+
def _ascending_v(self, d: AstroData, i: int, v: np.ndarray | None):
|
|
738
|
+
if v is not None and len(v) > 1 and v[1] < v[0]:
|
|
739
|
+
d.data[i], v = d.data[i][::-1], v[::-1]
|
|
740
|
+
print('Velocity has been inverted.')
|
|
741
|
+
d.v = v
|
|
742
|
+
|
|
743
|
+
def _xyskip(self, d: AstroData, i: int,
|
|
744
|
+
x: np.ndarray | None, y: np.ndarray | None):
|
|
745
|
+
d.x = x[::self.xskip]
|
|
746
|
+
d.y = y[::self.yskip]
|
|
747
|
+
data = np.moveaxis(d.data[i], [-2, -1], [0, 1])
|
|
748
|
+
data = data[::self.yskip, ::self.xskip]
|
|
749
|
+
d.data[i] = np.moveaxis(data, [0, 1], [-2, -1])
|
|
750
|
+
|
|
751
|
+
def _trim_skip(self, d: AstroData, i: int, grid: list):
|
|
752
|
+
d.data[i], grid = trim(data=d.data[i],
|
|
753
|
+
x=grid[0], y=grid[1], v=grid[2],
|
|
754
|
+
xlim=self.xlim, ylim=self.ylim,
|
|
755
|
+
vlim=self.vlim, pv=self.pv)
|
|
756
|
+
self._ascending_v(d, i, v=grid[2])
|
|
757
|
+
grid = [grid[0], d.v] if self.pv else [grid[0], grid[1]]
|
|
758
|
+
if self.swapxy:
|
|
759
|
+
grid = [grid[1], grid[0]]
|
|
760
|
+
d.data[i] = np.moveaxis(d.data[i], 1, 0)
|
|
761
|
+
self._xyskip(d, i, x=grid[0], y=grid[1])
|
|
762
|
+
for axis in ['x', 'y', 'v']:
|
|
763
|
+
setattr(d, f"d{axis}", _get_gridsep(getattr(d, axis)))
|
|
764
|
+
|
|
765
|
+
def _convert_to_Tb(self, d: AstroData, i: int):
|
|
766
|
+
"""Convert Jy/beam data to brightness temperature if requested."""
|
|
767
|
+
if not d.Tb[i]:
|
|
768
|
+
return
|
|
769
|
+
|
|
770
|
+
dx = d.dy if self.swapxy else d.dx
|
|
771
|
+
header = {"CDELT1": dx / 3600,
|
|
772
|
+
"CUNIT1": "DEG",
|
|
773
|
+
"RESTFREQ": d.restfreq[i]}
|
|
774
|
+
if None not in d.beam[i]:
|
|
775
|
+
header["BMAJ"] = d.beam[i][0] / 3600 / self.dist
|
|
776
|
+
header["BMIN"] = d.beam[i][1] / 3600 / self.dist
|
|
777
|
+
factor = Jy2K(header=header)
|
|
778
|
+
d.data[i] = d.data[i] * factor
|
|
779
|
+
if d.sigma[i] is not None:
|
|
780
|
+
d.sigma[i] = d.sigma[i] * factor
|
|
781
|
+
|
|
782
|
+
def _set_pv_beam(self, d: AstroData, i: int):
|
|
783
|
+
"""Set effective PV beam."""
|
|
784
|
+
if not self.pv or d.pv[i] or None in d.beam[i]:
|
|
785
|
+
return
|
|
786
|
+
|
|
787
|
+
bmaj, bmin, bpa = d.beam_org[i] = d.beam[i]
|
|
788
|
+
if d.pvpa[i] is None:
|
|
789
|
+
d.pvpa[i] = bpa
|
|
790
|
+
print("pvpa is not specified. pvpa=bpa is assumed.")
|
|
791
|
+
angle = np.radians(bpa - d.pvpa[i])
|
|
792
|
+
beam_incut = 1 / np.hypot(np.cos(angle) / bmaj, np.sin(angle) / bmin)
|
|
793
|
+
d.beam[i] = np.array([np.abs(d.dv), beam_incut, 0])
|
|
794
|
+
|
|
795
|
+
def _read_one(self, d: AstroData, i: int):
|
|
796
|
+
if d.center[i] == 'common':
|
|
797
|
+
d.center[i] = self.center
|
|
798
|
+
d.sigma_org[i] = d.sigma[i]
|
|
799
|
+
grid = self._read_fitsimage(d, i, grid=[d.x, d.y, d.v])
|
|
800
|
+
if d.data[i] is not None:
|
|
801
|
+
d.sigma[i] = estimate_rms(d.data[i], d.sigma[i])
|
|
802
|
+
grid = self._shift_center(d, i, grid)
|
|
803
|
+
self._trim_skip(d, i, grid)
|
|
804
|
+
if self.quadrants is not None:
|
|
805
|
+
d.data[i], d.x, d.y \
|
|
806
|
+
= quadrantmean(d.data[i], d.x, d.y, self.quadrants)
|
|
807
|
+
d.data[i] = d.data[i] * d.cfactor[i]
|
|
808
|
+
if d.sigma[i] is not None:
|
|
809
|
+
d.sigma[i] = d.sigma[i] * d.cfactor[i]
|
|
810
|
+
self._convert_to_Tb(d, i)
|
|
811
|
+
self._set_pv_beam(d, i)
|
|
812
|
+
d.pv[i] = self.pv
|
|
813
|
+
d.Tb[i] = False
|
|
814
|
+
d.cfactor[i] = 1
|
|
815
|
+
d.fitsimage_org[i] = d.fitsimage[i]
|
|
816
|
+
d.fitsimage[i] = None
|
|
817
|
+
|
|
669
818
|
def read(self, d: AstroData, xskip: int = 1, yskip: int = 1):
|
|
670
819
|
"""Get data, grid, sigma, beam, and bunit from AstroData, which is a part of the input of add_color, add_contour, add_segment, and add_rgb.
|
|
671
820
|
|
|
@@ -673,145 +822,12 @@ class AstroFrame():
|
|
|
673
822
|
d (AstroData): Dataclass for the add_* input.
|
|
674
823
|
xskip, yskip (int): Spatial pixel skip. Defaults to 1.
|
|
675
824
|
"""
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
d
|
|
680
|
-
|
|
681
|
-
d.beam = [d.beam] * d.n
|
|
682
|
-
if type(d.Tb) is not list:
|
|
683
|
-
d.Tb = [d.Tb] * d.n
|
|
684
|
-
if type(d.sigma) is not list:
|
|
685
|
-
d.sigma = [d.sigma] * d.n
|
|
686
|
-
if type(d.center) is not list:
|
|
687
|
-
d.center = [d.center] * d.n
|
|
688
|
-
if type(d.restfreq) is not list:
|
|
689
|
-
d.restfreq = [d.restfreq] * d.n
|
|
690
|
-
if type(d.cfactor) is not list:
|
|
691
|
-
d.cfactor = [d.cfactor] * d.n
|
|
692
|
-
if type(d.bunit) is not list:
|
|
693
|
-
d.bunit = [d.bunit] * d.n
|
|
694
|
-
if type(d.fitsimage_org) is not list:
|
|
695
|
-
d.fitsimage_org = [d.fitsimage_org] * d.n
|
|
696
|
-
if type(d.sigma_org) is not list:
|
|
697
|
-
d.sigma_org = [d.sigma_org] * d.n
|
|
698
|
-
if type(d.beam_org) is not list:
|
|
699
|
-
d.beam_org = [d.beam_org] * d.n
|
|
700
|
-
if type(d.fitsheader) is not list:
|
|
701
|
-
d.fitsheader = [d.fitsheader] * d.n
|
|
702
|
-
if type(d.pv) is not list:
|
|
703
|
-
d.pv = [d.pv] * d.n
|
|
704
|
-
if type(d.pvpa) is not list:
|
|
705
|
-
d.pvpa = [d.pvpa] * d.n
|
|
706
|
-
grid0 = [d.x, d.y, d.v]
|
|
825
|
+
self.xskip = xskip
|
|
826
|
+
self.yskip = yskip
|
|
827
|
+
for name in ASTRODATA_ARGS:
|
|
828
|
+
setattr(d, name, _as_list(getattr(d, name), d.n))
|
|
829
|
+
d.beam = _as_list(d.beam, d.n, isbeam=True)
|
|
707
830
|
for i in range(d.n):
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if d.fitsimage[i] is not None:
|
|
712
|
-
fd = FitsData(d.fitsimage[i])
|
|
713
|
-
if d.fitsheader[i] is None:
|
|
714
|
-
d.fitsheader[i] = fd.get_header()
|
|
715
|
-
if d.center[i] is None and not self.pv:
|
|
716
|
-
d.center[i] = fd.get_center()
|
|
717
|
-
if d.restfreq[i] is None:
|
|
718
|
-
h = d.fitsheader[i]
|
|
719
|
-
if 'NAXIS3' in h and h['NAXIS3'] == 1 and not self.pv:
|
|
720
|
-
d.restfreq[i] = h['CRVAL3']
|
|
721
|
-
elif 'RESTFRQ' in h:
|
|
722
|
-
d.restfreq[i] = h['RESTFRQ']
|
|
723
|
-
elif 'RESTFREQ' in h:
|
|
724
|
-
d.restfreq[i] = h['RESTFREQ']
|
|
725
|
-
d.data[i] = fd.get_data()
|
|
726
|
-
grid = fd.get_grid(center=d.center[i], dist=self.dist,
|
|
727
|
-
restfreq=d.restfreq[i], vsys=self.vsys,
|
|
728
|
-
pv=self.pv)
|
|
729
|
-
if fd.wcsrot:
|
|
730
|
-
d.center[i] = fd.get_center() # for WCS rotation
|
|
731
|
-
d.beam[i] = fd.get_beam(dist=self.dist)
|
|
732
|
-
d.bunit[i] = fd.get_header('BUNIT')
|
|
733
|
-
if d.data[i] is not None:
|
|
734
|
-
d.sigma_org[i] = d.sigma[i]
|
|
735
|
-
d.sigma[i] = estimate_rms(d.data[i], d.sigma[i])
|
|
736
|
-
diffcent = (not self.pv
|
|
737
|
-
and self.center is not None
|
|
738
|
-
and d.center[i] is not None
|
|
739
|
-
and d.center[i] != self.center)
|
|
740
|
-
if diffcent:
|
|
741
|
-
cx, cy = coord2xy(d.center[i], self.center) * 3600
|
|
742
|
-
grid[0] = grid[0] + cx # Don't use += cx.
|
|
743
|
-
grid[1] = grid[1] + cy # Don't use += cy.
|
|
744
|
-
d.center[i] = self.center
|
|
745
|
-
d.data[i], grid = trim(data=d.data[i],
|
|
746
|
-
x=grid[0], y=grid[1], v=grid[2],
|
|
747
|
-
xlim=self.xlim, ylim=self.ylim,
|
|
748
|
-
vlim=self.vlim, pv=self.pv)
|
|
749
|
-
v = grid[2]
|
|
750
|
-
has_v = v is not None and len(v) > 1
|
|
751
|
-
if has_v and v[1] < v[0]:
|
|
752
|
-
d.data[i], v = d.data[i][::-1], v[::-1]
|
|
753
|
-
print('Velocity has been inverted.')
|
|
754
|
-
d.v = v
|
|
755
|
-
d.dv = v[1] - v[0] if has_v else None
|
|
756
|
-
grid = grid[:3:2] if self.pv else grid[:2]
|
|
757
|
-
if self.swapxy:
|
|
758
|
-
grid = [grid[1], grid[0]]
|
|
759
|
-
d.data[i] = np.moveaxis(d.data[i], 1, 0)
|
|
760
|
-
grid[0] = grid[0][::xskip]
|
|
761
|
-
grid[1] = grid[1][::yskip]
|
|
762
|
-
a = d.data[i]
|
|
763
|
-
a = np.moveaxis(a, [-2, -1], [0, 1])
|
|
764
|
-
a = a[::yskip, ::xskip]
|
|
765
|
-
a = np.moveaxis(a, [0, 1], [-2, -1])
|
|
766
|
-
d.data[i] = a
|
|
767
|
-
x, y = d.x, d.y = grid
|
|
768
|
-
has_x = x is not None and len(x) > 1
|
|
769
|
-
d.dx = x[1] - x[0] if has_x else None
|
|
770
|
-
has_y = y is not None and len(y) > 1
|
|
771
|
-
d.dy = y[1] - y[0] if has_y else None
|
|
772
|
-
if self.quadrants is not None:
|
|
773
|
-
d.data[i], d.x, d.y \
|
|
774
|
-
= quadrantmean(d.data[i], d.x, d.y, self.quadrants)
|
|
775
|
-
d.data[i] = d.data[i] * d.cfactor[i]
|
|
776
|
-
if d.sigma[i] is not None:
|
|
777
|
-
d.sigma[i] = d.sigma[i] * d.cfactor[i]
|
|
778
|
-
if d.Tb[i]:
|
|
779
|
-
dx = d.dy if self.swapxy else d.dx
|
|
780
|
-
header = {'CDELT1': dx / 3600,
|
|
781
|
-
'CUNIT1': 'DEG',
|
|
782
|
-
'RESTFREQ': d.restfreq[i]}
|
|
783
|
-
if None not in d.beam[i]:
|
|
784
|
-
header['BMAJ'] = d.beam[i][0] / 3600 / self.dist
|
|
785
|
-
header['BMIN'] = d.beam[i][1] / 3600 / self.dist
|
|
786
|
-
d.data[i] = d.data[i] * Jy2K(header=header)
|
|
787
|
-
d.sigma[i] = d.sigma[i] * Jy2K(header=header)
|
|
788
|
-
if self.pv and not d.pv[i] and None not in d.beam[i]:
|
|
789
|
-
bmaj, bmin, bpa = d.beam_org[i] = d.beam[i]
|
|
790
|
-
if d.pvpa[i] is None:
|
|
791
|
-
d.pvpa[i] = bpa
|
|
792
|
-
print('pvpa is not specified. pvpa=bpa is assumed.')
|
|
793
|
-
p = np.radians(bpa - d.pvpa[i])
|
|
794
|
-
b = 1 / np.hypot(np.cos(p) / bmaj, np.sin(p) / bmin)
|
|
795
|
-
d.beam[i] = np.array([np.abs(d.dv), b, 0])
|
|
796
|
-
d.pv[i] = self.pv
|
|
797
|
-
d.Tb[i] = False
|
|
798
|
-
d.cfactor[i] = 1
|
|
799
|
-
if d.fitsimage[i] is not None:
|
|
800
|
-
d.fitsimage_org[i] = d.fitsimage[i]
|
|
801
|
-
d.fitsimage[i] = None
|
|
802
|
-
if d.n == 1:
|
|
803
|
-
d.data = d.data[0]
|
|
804
|
-
d.beam = d.beam[0]
|
|
805
|
-
d.fitsimage = d.fitsimage[0]
|
|
806
|
-
d.Tb = d.Tb[0]
|
|
807
|
-
d.sigma = d.sigma[0]
|
|
808
|
-
d.center = d.center[0]
|
|
809
|
-
d.restfreq = d.restfreq[0]
|
|
810
|
-
d.cfactor = d.cfactor[0]
|
|
811
|
-
d.bunit = d.bunit[0]
|
|
812
|
-
d.fitsimage_org = d.fitsimage_org[0]
|
|
813
|
-
d.sigma_org = d.sigma_org[0]
|
|
814
|
-
d.beam_org = d.beam_org[0]
|
|
815
|
-
d.fitsheader = d.fitsheader[0]
|
|
816
|
-
d.pv = d.pv[0]
|
|
817
|
-
d.pvpa = d.pvpa[0]
|
|
831
|
+
self._read_one(d, i)
|
|
832
|
+
for name in ASTRODATA_ARGS + ["beam"]:
|
|
833
|
+
setattr(d, name, _scalar_if_single(getattr(d, name), d.n))
|
|
@@ -29,7 +29,7 @@ def Jy2K(header=None, bmaj: float | None = None, bmin: float | None = None,
|
|
|
29
29
|
else:
|
|
30
30
|
print('Use CDELT1^2 for Tb conversion.')
|
|
31
31
|
todiameter = np.sqrt(4 * np.log(2) / np.pi) * 3600
|
|
32
|
-
bmaj = bmin = header['CDELT1'] * todiameter
|
|
32
|
+
bmaj = bmin = np.abs(header['CDELT1']) * todiameter
|
|
33
33
|
if header['CUNIT1'] == 'arcsec':
|
|
34
34
|
bmaj, bmin = bmaj / 3600, bmin / 3600
|
|
35
35
|
if 'RESTFREQ' in header:
|
|
@@ -366,65 +366,77 @@ class PlotAxes2D():
|
|
|
366
366
|
grid: dict | None = None
|
|
367
367
|
aspect: dict | float | None = None
|
|
368
368
|
|
|
369
|
-
def
|
|
369
|
+
def _set_scale(self):
|
|
370
|
+
ax = self.ax
|
|
370
371
|
if self.loglog is not None:
|
|
371
|
-
self.xscale = 'log'
|
|
372
|
-
self.yscale = 'log'
|
|
372
|
+
self.xscale = self.yscale = 'log'
|
|
373
373
|
self.samexy = True
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
374
|
+
for axis in ["x", "y"]:
|
|
375
|
+
attr = f"{axis}lim"
|
|
376
|
+
lim = getattr(self, attr)
|
|
377
|
+
if lim is not None:
|
|
378
|
+
lim[0] = lim[1] / self.loglog
|
|
379
|
+
setattr(self, attr, lim)
|
|
378
380
|
ax.set_xscale(self.xscale)
|
|
379
381
|
ax.set_yscale(self.yscale)
|
|
382
|
+
|
|
383
|
+
def _init_ticks(self, axis):
|
|
384
|
+
ax = self.ax
|
|
385
|
+
ticks_attr = f"{axis}ticks"
|
|
386
|
+
ticklabels_attr = f"{axis}ticklabels"
|
|
387
|
+
scale = getattr(self, f"{axis}scale")
|
|
388
|
+
lim = getattr(self, f"{axis}lim")
|
|
389
|
+
ticks = getattr(self, ticks_attr)
|
|
390
|
+
if ticks is None:
|
|
391
|
+
ticks = getattr(ax, f"get_{axis}ticks")()
|
|
392
|
+
if scale == "log":
|
|
393
|
+
ticks, ticklabels = logticks(ticks, lim)
|
|
394
|
+
setattr(self, ticklabels_attr, ticklabels)
|
|
395
|
+
setattr(self, ticks_attr, ticks)
|
|
396
|
+
|
|
397
|
+
def _make_ticks(self, ticks, ticksminor):
|
|
398
|
+
dt = ticks[1] - ticks[0]
|
|
399
|
+
t = np.r_[ticks[0] - dt, ticks, ticks[-1] + dt]
|
|
400
|
+
num = ticksminor * (len(t) - 1) + 1
|
|
401
|
+
return np.linspace(t[0], t[-1], num)
|
|
402
|
+
|
|
403
|
+
def _set_ticks(self, axis):
|
|
404
|
+
ax = self.ax
|
|
405
|
+
attr = f"{axis}ticks"
|
|
406
|
+
ticks = getattr(self, attr)
|
|
407
|
+
getattr(ax, f"set_{attr}")(ticks)
|
|
408
|
+
ticksminor = getattr(self, f"{attr}minor")
|
|
409
|
+
if ticksminor is not None:
|
|
410
|
+
if isinstance(ticksminor, int):
|
|
411
|
+
ticksminor = self._make_ticks(ticks, ticksminor)
|
|
412
|
+
getattr(ax, f"set_{attr}")(ticksminor, minor=True)
|
|
413
|
+
|
|
414
|
+
def _apply_if_not_none(self, axis, attr):
|
|
415
|
+
ax = self.ax
|
|
416
|
+
method = getattr(ax, f"set_{axis}{attr}")
|
|
417
|
+
value = getattr(self, f"{axis}{attr}")
|
|
418
|
+
if value is not None:
|
|
419
|
+
if attr == "lim":
|
|
420
|
+
method(*value)
|
|
421
|
+
else:
|
|
422
|
+
method(value)
|
|
423
|
+
|
|
424
|
+
def set_xyaxes(self, ax):
|
|
425
|
+
self.ax = ax
|
|
426
|
+
self._set_scale()
|
|
380
427
|
if self.samexy:
|
|
381
428
|
ax.set_xticks(ax.get_yticks())
|
|
382
429
|
ax.set_yticks(ax.get_xticks())
|
|
383
430
|
ax.set_aspect(1)
|
|
384
|
-
|
|
385
|
-
self.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if self.yticks is None:
|
|
390
|
-
self.yticks = ax.get_yticks()
|
|
391
|
-
if self.yscale == 'log':
|
|
392
|
-
self.yticks, self.yticklabels \
|
|
393
|
-
= logticks(self.yticks, self.ylim)
|
|
394
|
-
ax.set_xticks(self.xticks)
|
|
395
|
-
ax.set_yticks(self.yticks)
|
|
396
|
-
if self.xticksminor is not None:
|
|
397
|
-
if type(self.xticksminor) is int:
|
|
398
|
-
t = ax.get_xticks()
|
|
399
|
-
dt = t[1] - t[0]
|
|
400
|
-
t = np.r_[t[0] - dt, t, t[-1] + dt]
|
|
401
|
-
num = self.xticksminor * (len(t) - 1) + 1
|
|
402
|
-
self.xticksminor = np.linspace(t[0], t[-1], num)
|
|
403
|
-
ax.set_xticks(self.xticksminor, minor=True)
|
|
404
|
-
if self.yticksminor is not None:
|
|
405
|
-
if type(self.yticksminor) is int:
|
|
406
|
-
t = ax.get_yticks()
|
|
407
|
-
dt = t[1] - t[0]
|
|
408
|
-
t = np.r_[t[0] - dt, t, t[-1] + dt]
|
|
409
|
-
num = self.yticksminor * (len(t) - 1) + 1
|
|
410
|
-
self.yticksminor = np.linspace(t[0], t[-1], num)
|
|
411
|
-
ax.set_yticks(self.yticksminor, minor=True)
|
|
412
|
-
if self.xticklabels is not None:
|
|
413
|
-
ax.set_xticklabels(self.xticklabels)
|
|
414
|
-
if self.yticklabels is not None:
|
|
415
|
-
ax.set_yticklabels(self.yticklabels)
|
|
416
|
-
if self.xlabel is not None:
|
|
417
|
-
ax.set_xlabel(self.xlabel)
|
|
418
|
-
if self.ylabel is not None:
|
|
419
|
-
ax.set_ylabel(self.ylabel)
|
|
420
|
-
if self.xlim is not None:
|
|
421
|
-
ax.set_xlim(*self.xlim)
|
|
422
|
-
if self.ylim is not None:
|
|
423
|
-
ax.set_ylim(*self.ylim)
|
|
431
|
+
for axis in ["x", "y"]:
|
|
432
|
+
self._init_ticks(axis)
|
|
433
|
+
self._set_ticks(axis)
|
|
434
|
+
for attr in ["ticklabels", "label", "lim"]:
|
|
435
|
+
self._apply_if_not_none(axis, attr)
|
|
424
436
|
if self.grid is not None:
|
|
425
437
|
ax.grid(**({} if self.grid is True else self.grid))
|
|
426
438
|
if self.aspect is not None:
|
|
427
|
-
if
|
|
439
|
+
if isinstance(self.aspect, dict):
|
|
428
440
|
ax.set_aspect(**self.aspect)
|
|
429
441
|
else:
|
|
430
442
|
ax.set_aspect(self.aspect)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plotastrodata
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.7
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|