2015年7月16日木曜日

astropy.coordinatesを用いた座標の取り扱い、その8 ― 作業実例: 観測計画の立案

ここでは、astropyのSkyCoordオブジェクトの活用例として、観測計画の立案に役立つ天体の高度角の計算をやってみます。(前提知識として、SkyCoordにおける座標変換の方法を知っておく必要があります。)

次のような状況を考えることにします。観測場所は、ニューヨークにあるBear Mountain State Park。そこに自前の望遠鏡を持ち込んで、M33を観望するとします。前後にスケジュールが詰まっているため、観望できるのは午後11時前後のみです。この時間にM33は観望できる高さまで上がっているでしょうか。このような問題は、例えば以下の様な方法で調べることができます。

まず、作業に必要なパッケージを読み込みます。

>>> import numpy as np
>>> from astropy import units as u
>>> from astropy.time import Time
>>> from astropy.coordinates import SkyCoord, EarthLocation, AltAz

次に、M33の座標値をネットから取得し、観測場所の座標値を指定します。天体の座標値は、(SIMBADに登録されているものであれば、SkyCoord.from_nameで以下のように所得することができます。)

>>> m33 = SkyCoord.from_name('M33')  
>>> bear_mountain = EarthLocation(lat=41.3*u.deg, lon=-74*u.deg, height=390*u.m)

次に、観測場所の時間を指定します。まず1行目で、世界標準時からのオフセットをしていし、2行目で、世界標準時からオフセットを差し引いて観測場所の時間を表すオブジェクトを作ります。

>>> utcoffset = -4*u.hour  # ニューヨークなのでアメリカ東部標準時(UTC-4h)を設定します。
>>> time = Time('2012-7-12 23:00:00') - utcoffset

設定した時間と場所の情報を使って、ICRSからAltAzへの座標変換を行い、フォーマットを整えて出力します。

>>> m33altaz = m33.transform_to(AltAz(obstime=time,location=bear_mountain))  
>>> "M33's Altitude = {0.alt:.2}".format(m33altaz)  
"M33's Altitude = 0.13 deg"

ここまでの流れをまとめておきます。

>>> import numpy as np
>>> from astropy import units as u
>>> from astropy.time import Time
>>> from astropy.coordinates import SkyCoord, EarthLocation, AltAz
>>> m33 = SkyCoord.from_name('M33')  
>>> bear_mountain = EarthLocation(lat=41.3*u.deg, lon=-74*u.deg, height=390*u.m)
>>> utcoffset = -4*u.hour  # Eastern Daylight Time
>>> time = Time('2012-7-12 23:00:00') - utcoffset
>>> m33altaz = m33.transform_to(AltAz(obstime=time,location=bear_mountain))  
>>> "M33's Altitude = {0.alt:.2}".format(m33altaz)  
"M33's Altitude = 0.13 deg"

とりあえず、観測したい場所と時間における高度角を求めることができました。しかし、この高度は観測するには低すぎるようです。もっといろいろな時間で計算して、観測に適切な時間の範囲を調べたいところです。そのような確認をするには、1つの場合を計算するだけでなく、時間に対して高度がどのように変化するか図にした方が分かりやすいでしょう。また、高度角だけでなくエアマスも合わせて計算するとより便利かもしれません。ではそのような作業を、実際にやってみましょう。まず、計算原点となる時刻のtimeオブジェクトを作ります。先ほど作った国際標準時への補正 utoffsetを利用します。

>>> midnight = Time('2012-7-13 00:00:00') - utcoffset

次に、-2時間から+7時間までを、100分割した時間のnumpy配列を作ります。この配列は、astropy.unitの単位を後ろにつけているので、単なる数値の配列ではなく、時間の単位を持っているところがポイントです。

>>> delta_midnight = np.linspace(-2, 7, 100)*u.hour

transform_toは配列を処理することができるので、今しがた作ったnumpy配列を使って、大量の変換を一括して行います。

>>> m33altazs = m33.transform_to(AltAz(obstime=midnight+delta_midnight, location=bear_mountain))  

出来上がった (Alt, Az) の数値ペアを100個含んだ配列を使って、まず、時間に対するエアマスの変化をプロットしてみましょう。matplotlibを利用して以下の様な方法で図を作ることができます。

>>> import matplotlib.pyplot as plt
>>> plt.plot(delta_midnight, m33altazs.secz)  
>>> plt.xlim(-2, 7)  
>>> plt.ylim(1, 4)  
>>> plt.xlabel('Hours from EDT Midnight')  
>>> plt.ylabel('Airmass [Sec(z)]')  


だいぶ情報を確認しやすくなりました。しかし、エアマスだけでは観測計画は立てられません。観測計画を立てるときは、高度角や方位角の情報も見たいですし、日の出日の入り時刻なども知りたいところです。そこで、今度は縦軸に高度角をとり、方位角は色で表現してみましょう。また、太陽の高度変化も同時にプロットし、日の出日の入り時刻をひと目で分かるようにしてみます。太陽の位置情報は、get_sun という関数を用いて得ることができます。

>>> from astropy.coordinates import get_sun
>>> delta_midnight = np.linspace(-12, 12, 1000)*u.hour
>>> times = midnight + delta_midnight
>>> altazframe = AltAz(obstime=times, location=bear_mountain)
>>> sunaltazs = get_sun(times).transform_to(altazframe)
>>> m33altazs = m33.transform_to(altazframe) 

以下各業ごとの説明です。
1行目: get_sunを読み込みます。
2行目: 時間のNumpy配列を作ります。-12時間から+12時間まで1時間刻みの配列にします。
3行目: midnightという変数に保存されている時間を起点に、-12時間から+12時間までの時間の配列を作り、timesという変数に保存します。
4行目: 時間と観測場所の情報を含んだAltAzオブジェクトを作り、altazframeという名前で保存します。
5行目: timesに保存された時間における太陽の位置情報をAltAzに変換して、sunaltazsという変数に保存します。
6行目: 観測天体の位置情報を、AltAz座標に変換して、m33altazsという変数に保存します。

上記のように必要な数値を計算した後は、matplotlibで図を描画します。

>>> plt.plot(delta_midnight, sunaltazs.alt, color='y', label='Sun')  
>>> plt.scatter(delta_midnight, m33altazs.alt, c=m33altazs.az, label='M33', lw=0, s=8)  
>>> plt.fill_between(delta_midnight, 0, 90, sunaltazs.alt < -0*u.deg, color='0.5', zorder=0)  
>>> plt.fill_between(delta_midnight, 0, 90, sunaltazs.alt < -18*u.deg, color='k', zorder=0)  
>>> plt.colorbar().set_label('Azimuth [deg]')  
>>> plt.legend(loc='upper left')
>>> plt.xlim(-12, 12)  
>>> plt.xticks(np.arange(13)*2 -12)  
>>> plt.ylim(0, 90)  
>>> plt.xlabel('Hours from EDT Midnight')  
>>> plt.ylabel('Altitude [deg]')  

2015年6月25日木曜日

astropy.coordinatesを用いた座標の取り扱い、その7 ― 座標変換

astropy.coordinatesは、座標変換を行うための様々な機能を装備しています。天文学で用いられる主な座標系は予めastropyの中に組み込まれていますが、ユーザーが定義した特殊な座標系についても、独自の座標をastropy内で定義することによって他の座標系との間の座標変換を取り扱うことができます。独自の座標系の定義については別の機会に取り扱うとして、ここではastropy.coordinatesの中でどのように座標変換を実行できるかを見てゆくことにします。astropy.coordinatesに予め組み込まれた座標系と座標変換は、ここで確認することができます。

まず、一番単純な座標変換を見てみましょう。

>>> import astropy.units as u
>>> from astropy.coordinates import SkyCoord
>>> gc = SkyCoord(l=0*u.degree, b=45*u.degree, frame='galactic')
>>> gc.fk5  
<SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
    (229.272514629, -1.12844288043)>

より一般的には、transform_to() で変換を表します。transform_to() 用いることで入力方法が柔軟になり、なおかつ、より細かいオプションの設定が可能となります。

>>> from astropy.coordinates import FK5
>>> gc.transform_to('fk5')  
<SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
    (229.272514629, -1.12844288043)>
>>> gc.transform_to(FK5)  
<SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
    (229.272514629, -1.12844288043)>
>>> gc.transform_to(FK5(equinox='J1980.0'))  
<SkyCoord (FK5: equinox=J1980.000): (ra, dec) in deg
    (229.014693505, -1.05560349378)>

transform_to() には、SkyCoordオブジェクトをそのまま指定することもできます。SkyCoordオブジェクトを指定すると、そのSkyCoordオブジェクトで指定されている座標系に変換されます。

>>> sc = SkyCoord(ra=1.0, dec=2.0, unit='deg', frame=FK5, equinox='J1980.0')
>>> gc.transform_to(sc)  
<SkyCoord (FK5: equinox=J1980.000): (ra, dec) in deg
    (229.014693505, -1.05560349378)>

また、FK5, FK4, FK4NoETermsなどの座標系においては、同じ座標系の中での変換(例えば、分点を変更する)を行うことができます。

>>> fk5c = FK5('02h31m49.09s', '+89d15m50.8s')
>>> fk5c.equinox
<Time object: scale='utc' format='jyear_str' value=J2000.000>
>>> fk5c  
<SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
    (37.9545416667, 89.2641111111)>
>>> fk5_2005 = FK5(equinox='J2005')  # 分点を変更します
>>> fk5c.transform_to(fk5_2005)  
<SkyCoord (FK5: equinox=J2005.000): (ra, dec) in deg
    (39.3931763878, 89.2858442155)>

分点の変更は、以下のようにTimeオブジェクトを用いて行うこともできます。

>>> from astropy.time import Time
>>> fk5c = FK5('02h31m49.09s', '+89d15m50.8s',
...            equinox=Time('J1970', scale='utc'))
>>> fk5_2000 = FK5(equinox=Time(2000, format='jyear', scale='utc'))
>>> fk5c.transform_to(fk5_2000)  
<SkyCoord (FK5: equinox=2000.0): (ra, dec) in deg
    (48.0231710002, 89.386724854)>

2015年6月18日木曜日

astropy.coordinatesを用いた座標の取り扱い、その6 ― SkyCoodクラスの使用法、実例2

実例1では、エイトフ図の上にランダムに点をプロットしましたが、今度はSkyCoordオブジェクトを使って、もう少し実際の星の分布に近い図を作ってみます。ここでは、多変量の正規分布(multivariate normal distribution)を用いて、銀河系のバルジとディスクの星の分布を再現してみます。まず最初に、作業に必要なパッケージを読み込みます。

>>> from astropy import units as u
>>> from astropy.coordinates import SkyCoord
>>> import numpy as np

ではまず、numpy.random.multivariate_normalを用いて、プロットするためのデータを作成します。生成されるデータは、直交座標系を用いて表されます。正規分布の、Z成分の幅を変えることで、銀河系のディスクとバルジを表現します。

>>> disk = np.random.multivariate_normal(mean=[0,0,0], cov=np.diag([1,1,0.5]), size=5000)
>>> bulge = np.random.multivariate_normal(mean=[0,0,0], cov=np.diag([1,1,1]), size=500)
>>> galaxy = np.concatenate([disk, bulge])

次に、生成したデータをSkycoordオブジェクトに変換し、直交座標系から赤道座標系に座標を変換します。

>>> c_gal = SkyCoord(galaxy, representation='cartesian', frame='galactic')
>>> c_gal_icrs = c_gal.icrs

実例1でやったのと同じように、角度の単位をラジアンに変換し、赤経を $-\pi$ から $\pi$ で表すように変換を行います。

>>> ra_rad = c_gal_icrs.ra.wrap_at(180 * u.deg).radian
>>> dec_rad = c_gal_icrs.dec.radian

最後に実例1と同じ設定で、matplotlibを用いてデータをプロットしてみます。

>>> import matplotlib.pyplot as plt
>>> plt.figure(figsize=(8,4.2))
>>> plt.subplot(111, projection="aitoff")
>>> plt.title("Aitoff projection of our random data")
>>> plt.grid(True)
>>> plt.plot(ra_rad, dec_rad, 'o', markersize=2, alpha=0.3)
>>> plt.subplots_adjust(top=0.95,bottom=0.0)
>>> plt.show()


実例2

2015年6月16日火曜日

astropy.coordinatesを用いた座標の取り扱い、その5 ― SkyCoodクラスの使用法、実例1

ここでは、SkyCoordオブジェクトを使って、ランダムに生成された座標値を、エイトフ図(Aitoff projection)上にプロットするという作業をやってみます。 

まず最初に必要なパッケージを読み込みます。ここでは、関連するastropyのパッケージ以外に、図を作成するためのパッケージである matplotlib、ランダムな数値データを生成するための numpy を読み込みます。

>>> from astropy import units as u
>>> from astropy.coordinates import SkyCoord
>>> import numpy as np

まず、座標値をランダムに生成し、プロットするためのデータを作成します。RA(赤経)は、0°から360°の間で値を生成し、ra_random という名前で保存します。赤緯(DEC)に関しては、-90°から+90°の間で値を生成し、dec_random という名前で保存します。

>>> ra_random = np.random.rand(100)*360.0 * u.degree
>>> dec_random = (np.random.rand(100)*180.0-90.0) * u.degree

次に ra_random、dec_random から、SkyCoordオブジェクトを生成します。

>>> c = SkyCoord(ra=ra_random, dec=dec_random, frame='icrs')

ここで使用する matplotlib という作図パッケージでは、単位として $-\pi$ から $\pi$ の間のラジアンが表記($0$ から $2 \pi$ ではない)が用いられるので、表記を変換する必要があります。この変換は、astropy.coordinate.Angle のラッピング機能を用いて行います。

>>> ra_rad = c.ra.wrap_at(180 * u.deg).radian
>>> dec_rad = c.dec.radian

最後に、matplotlibを用いて、エイトフ図法(Aitoff projection)でデータ点をプロットします。ここでは、タイトルを図の上に置き、座標を表すグリッドを加えます。データ点はサイズ2の塗りつぶした丸とします。(他にも細部の設定は、matplotlib のテキストを参照のこと。)

>>> import matplotlib.pyplot as plt
>>> plt.figure(figsize=(8,4.2))
>>> plt.subplot(111, projection="aitoff")
>>> plt.title("Aitoff projection of our random data")
>>> plt.grid(True)
>>> plt.plot(ra_rad, dec_rad, 'o', markersize=2, alpha=0.3)
>>> plt.subplots_adjust(top=0.95,bottom=0.0)
>>> plt.show()


出来上がり図

2015年6月10日水曜日

astropy.coordinatesを用いた座標の取り扱い、その4 ― SkyCoodクラスの使用法(上級編)

その4の最後で、SkyCoordオブジェクトの座標系を銀河座標系(galactic)へ変換する方法を紹介しました。一旦この変換を行うと、経度と緯度の座標値は、銀河座標系を表す際の慣習に従ってSkyCoordオブジェクト内で銀系と銀緯に対応した、、というラベルが付けられます。天文学の背景知識を持っているユーザーにとっては、(l, b) だけで何を意味しているか即座にわかると思いますが、SkyCoordオブジェクトには、(l, b) の意味も保存されており、状況に応じて適宜情報を取り出すことができます。

>>> sc_gal.representation_component_names
OrderedDict([(u'l', u'lon'), (u'b', u'lat'), (u'distance', u'distance')])

>>> sc_gal.representation_component_units
OrderedDict([(u'l', Unit("deg")), (u'b', Unit("deg"))])

>>> sc_gal.representation
<class 'astropy.coordinates.representation.SphericalRepresentation'>


上記のようなコマンドラインによって、(l, b) が経度と緯度を表していること、(l, b) の単位が度で有ること、直交座標系ではなく球面座標系であることが確認できます。また、上記で使用した representation_component_names という attribute を使うと、SkyCoodオブジェクトの中で使用する座標値の独自の呼称を定義することもできます。

別の重要な attribute としては、frame_attr_names があります。SkyCoordオブジェクトを作成する際、SkyCoordオブジェクトの中でどのようなパラメータが設定可能か確認したい場合があります。この attribute を使うと、簡単に未設定のパラメータを調べることができます。

>>> sc_fk4 = SkyCoord(1, 2, frame='fk4', unit='deg')
>>> sc_fk4.get_frame_attr_names()  
{u'equinox': 

明示的にパラメータを設定していない場合はデフォルト値が設定される場合もあります。上の例では、1行目でFK4座標系におけるSkyCoordオブジェクトを定義していますが、ユーザー側で完全に全パラメータを明示的に定義するには、equinoxobstime というパラメータに値を与える必要があることが分かります。

SkyCoordオブジェクトのパラメータ設定を行う際に若干ややこしのは、SkyCoordオブジェクトが、frameオブジェクトなど、いくつかの別のオブジェクトを土台として設計されていることです。このため、例えばSkyCoordオブジェクトの attribute で実行できる作業が、他の attribute に内包される別の attribute でも実行できてしまう場合があります。以下に例を示します。


>>> sc.frame
<ICRS Coordinate: (ra, dec) in deg
    (1.0, 2.0)>

>>> sc.has_data is sc.frame.has_data
True

>>> sc.frame.  
sc.frame.cartesian                           sc.frame.ra
sc.frame.data                                sc.frame.realize_frame
sc.frame.dec                                 sc.frame.represent_as
sc.frame.default_representation              sc.frame.representation
sc.frame.distance                            sc.frame.representation_component_names
sc.frame.frame_attr_names                    sc.frame.representation_component_units
sc.frame.frame_specific_representation_info  sc.frame.representation_info
sc.frame.get_frame_attr_names                sc.frame.separation
sc.frame.has_data                            sc.frame.separation_3d
sc.frame.is_frame_attr_default               sc.frame.shape
sc.frame.is_transformable_to                 sc.frame.spherical
sc.frame.isscalar                            sc.frame.time_attr_names
sc.frame.name                                sc.frame.transform_to
>>> sc.frame.name
'icrs'

この様に、has_data というSkyCoord自身の attribute でも frame という attribute以下に存在する、has_data でも全く同じ結果が得られます。このような性質は、知っておくと、利用方法によっては便利な場合もあります。

座標変換

座標変換については、実際に天文学のデータを扱う際に重要な項目でもあるので、場所を改めて詳しく紹介します。ここでは、SkyCoordクラスの概要の一部として、簡単な例をいくか紹介しておきます。

>>> from astropy.coordinates import FK5
>>> sc = SkyCoord(1, 2, frame='icrs', unit='deg')
>>> sc.galactic  
<SkyCoord (Galactic): (l, b) in deg
    (99.6378552814, -58.7096929334)>

>>> sc.transform_to('fk5')  # sc.fk5、sc.transform_to(FK5)としても同様の結果が得られます。  
<SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
        (1.00000655566, 2.00000243092)>

>>> sc.transform_to(FK5(equinox='J1975'))  # FK5において分点を変更しています。  
<SkyCoord (FK5: equinox=J1975.000): (ra, dec) in deg
        (0.679672818323, 1.86083014099)>

2つのSkyCoordオブジェクトがあった時、2つのオブジェクト間で座標系を一致させる操作は次のような方法で簡単に行えます。

>>> sc2 = SkyCoord(3, 4, frame='fk4', unit='deg', obstime='J1978.123', equinox='B1960.0')
>>> sc.transform_to(sc2) 
<SkyCoord (FK4: equinox=B1960.000, obstime=J1978.123): (ra, dec) in deg
    (0.48726331438, 1.77731617297)>

球面座標以外の座標の利用

ここまでの例では、ずっと球面座標を使ってきました。SkyCoordに組み込まれている座標系ではデフォルトが球面座標なので、球面座標の扱いを知っていれば、実際多くの天文学上の仕事を処理することができます。しかし、球面座標以外にも、直交座標や円柱座標の扱い方を知っておくと便利な場面は少なくありません。ここでは、SkyCoordオブジェクトで使用する座標をどうやって変更するのか簡単に紹介します。座標に関するより詳しい説明は、Using and Designing Coordinate Representationsを見て下さい。

初期化

SkyCoordオブジェクトの座標を扱う際に必要なことは、以下の実例を見ればほぼ十分だと思います。座標を初期化するのに必要なのは、representationというキーワードに、使用する座標を書き込むだけです。直交座標を使う場合の例は以下のとおりです。

>>> c = SkyCoord(x=1, y=2, z=3, unit='kpc', representation='cartesian')
>>> c
<SkyCoord (ICRS): (x, y, z) in kpc
    (1.0, 2.0, 3.0)>
>>> c.x, c.y, c.z
(<Quantity 1.0 kpc>, <Quantity 2.0 kpc>, <Quantity 3.0 kpc>)
他に、円柱座標を使ったり、各座標軸の単位を変更したりするには以下のようにします。
>>> SkyCoord(1, 2*u.deg, 3, representation='cylindrical')
<SkyCoord (ICRS): (rho, phi, z) in (, deg, )
    (1.0, 2.0, 3.0)>

>>> SkyCoord(rho=1*u.km, phi=2*u.deg, z=3*u.m, representation='cylindrical')
<SkyCoord (ICRS): (rho, phi, z) in (km, deg, m)
    (1.0, 2.0, 3.0)>

>>> SkyCoord(rho=1, phi=2, z=3, unit=(u.km, u.deg, u.m), representation='cylindrical')
<SkyCoord (ICRS): (rho, phi, z) in (km, deg, m)
    (1.0, 2.0, 3.0)>

>>> SkyCoord(1, 2, 3, unit=(None, u.deg, None), representation='cylindrical')
<SkyCoord (ICRS): (rho, phi, z) in (, deg, )
    (1.0, 2.0, 3.0)>

SkyCoordオブジェクトのフォーマットを一般的な形で書き下すと以下のようになります。

SkyCoord(COORD, [FRAME | frame=FRAME], [unit=UNIT], [representation=REPRESENTATION],
         keyword_args ...)
SkyCoord(COMP1, COMP2, [COMP3], [FRAME | frame=FRAME], [unit=UNIT],
         [representation=REPRESENTATION], keyword_args ...)
SkyCoord([FRAME | frame=FRAME], =COMP1, =COMP2,
         =COMP3, [representation=REPRESENTATION], [unit=UNIT],
         keyword_args ...)

2015年4月20日月曜日

astropy.coordinatesを用いた座標の取り扱い、その3 ― SkyCoodクラスの使用法

その1でも若干説明したようにSkyCoodクラスは、柔軟で使いやすいユーザーインターフェースを提供しており、天文座標の扱いや座標間の変換などを比較的簡単に取り扱うことができます。SkyCoodは、ICRSクラスやFK5クラス等の、特定の座標系を扱うクラスに比べてより多くの機能を備えており、ユーザーにやさしい設計となっていることから、「高水準クラス」と呼ばれています。一方で、ICRSクラスやFK5クラスなどは、どちらかというと機械よりの設計がなされており、使いづらい点はあるものの計算量の大きい作業などを効率よくこなすことができるため、「低水準クラス」と呼ばれています。

高水準クラスである SkyCoordと、ICRSクラスやFK5クラス等の低水準クラスの主な違いは次のとおりです。
  • SkyCoodオブジェクトには、観測時間や観測場所といった細かな観測の属性を保存することができ、このような属性は例え座標系の変換を行っても保持されます。一方で低水準クラスを用いて、異なるクラス間(例えば、ICRSクラスからFK5クラス)で変換を行うと、その作業に必要な情報は変換先のクラスに受け継がれますがそれ以外の情報は失われてしまいます。したがって、逆方向に再度変換しても完全にもとの状態には戻りません。SkyCoodクラスの場合は再び座標変換をすると完全に元の状態に戻ります。
  • SkyCoordクラスは、低水準クラスに比べると、座標値のフォーマットが柔軟で、さまざまな書式で座標値を定義することができます。
  • SkyCoordには、沢山のメソッドが付随しており、典型的な解析を簡単に取り扱うことができます。
  • SkyCoordオブジェクトは、現時点では(ver. 1.0.1)、astropy.coordinates.frame_transform_graph で定義された座標系のみを取り扱うことができます。

SkyCoordオブジェクトの作成

SkyCoordクラスでは、さまざまなフォーマットでSkyCoordオブジェクトを定義することができます。最低限必要なのは座標値と座標系ですが、場合によっては座標系の指定すら省略することも可能です。

SkyCoodオブジェクトの基本的なフォーマットは以下のとおりです。大文字で、COORDFRAMEと示しているパラメータについては、以下の***の項目で説明しています。[unit=UNIT] のように[...]内のパラメータはオプションです。

SkyCoord(COORD, [FRAME], keyword_args ...)
SkyCoord(LON, LAT, [frame=FRAME], [unit=UNIT], keyword_args ...)
SkyCoord([FRAME], =LON, =LAT, keyword_args ...)

SkyCoordオブジェクトの標準的な定義の例を以下に示します。ここに示す例は、全て球面座標の場合です。(球面座標は、全ての座標系においてデフォルトの座標となっています。) SkyCoordでは、必要に応じて直交座標系や円柱座標系なども用いることができます。他の座標系を用いる場合は、以下の***のセクションで説明します。SkyCoorオブジェクトを作成するには、まず必要なモジュールをインポートします。

>>> from astropy.coordinates import SkyCoord  # SkyCoodをインポートします。
>>> from astropy.coordinates import ICRS, Galactic, FK4, FK5  # その他低水準クラスもインポートします。
>>> from astropy.coordinates import Angle, Latitude, Longitude  # Angleクラスをインポートします。
>>> import astropy.units as u # astropy.unitをインポートします。
>>> import numpy as np # numpyをインポートします。

まず、赤道座標系(RA、Dec)でのSkyCoodオブジェクトの定義から見て行きましょう。

>>> SkyCoord(10, 20, unit='deg')  # デフォルトの座標系はICRSです。
<SkyCoord (ICRS): (ra, dec) in deg
    (10.0, 20.0)>

>>> SkyCoord([1, 2, 3], [-30, 45, 8], frame='icrs', unit='deg')
<SkyCoord (ICRS): (ra, dec) in deg
    [(1.0, -30.0), (2.0, 45.0), (3.0, 8.0)]>

最初の例では、座標系は明示的には定義していません。SkyCoodオブジェクトでは、デフォルトの座標系がICRSなので、座標系を明示的に定義しない場合は自動的にICRSが採用されます。しかし、基本的には使用する座標系を明示的に定義するほうが間違いが少ないでしょう。ICRS(国際天文基準座標系)は、元期J2000.0の赤道座標系と近似的にほぼ同じ座標値を与えます。

論文やカタログなどでよく使われる標準的なフォーマットにであれば、座標値を文字列としてそのままSkyCoordオブジェクトに読み込むことができます。座標系は、FK4と大文字で書くこともできますし、小文字で与えることもできます(小文字の場合は'fk4'とします)。以下具体例を示します。

>>> coords = ["1:12:43.2 +1:12:43", "1 12 43.2 +1 12 43"]
>>> sc = SkyCoord(coords, frame=FK4, unit=(u.hourangle, u.deg), obstime="J1992.21")
>>> sc = SkyCoord(coords, frame=FK4(obstime="J1992.21"), unit=(u.hourangle, u.deg))
>>> sc = SkyCoord(coords, frame='fk4', unit='hourangle,deg', obstime="J1992.21")

>>> sc = SkyCoord("1h12m43.2s", "+1d12m43s", frame=Galactic)  # 単位は文字列から認識
>>> sc = SkyCoord("1h12m43.2s +1d12m43s", frame=Galactic)  # 単位は文字列から認識
>>> sc = SkyCoord(l="1h12m43.2s", b="+1d12m43s", frame='galactic')
>>> sc = SkyCoord("1h12.72m +1d12.71m", frame='galactic')

他にも、様々なフォーマットで radec の値を書くことができます。

>>> sc = SkyCoord("15h17+89d15")
>>> sc = SkyCoord("275d11m15.6954s+17d59m59.876s")
>>> sc = SkyCoord("8 00 -5 00.6", unit=(u.hour, u.deg))
>>> sc = SkyCoord("J080000.00-050036.00", unit=(u.hour, u.deg))
>>> sc = SkyCoord("J1874221.31+122328.03", unit=u.deg)

前回登場したLongitudeオブジェクト、Latitudeオブジェクト、Angleオブジェクトを使ってSkyCoordオブジェクトを定義することもできます。astropyのunitを使って、普通のNumpy arrayなどからSkyCoordオブジェクトを定義することもできます。

>>> ra = Longitude([1, 2, 3], unit=u.deg)  # Angleオブジェクトも同様に使用可能
>>> dec = np.array([4.5, 5.2, 6.3]) * u.deg  # AstropyのUnitを使用してNumpy配列で定義
>>> sc = SkyCoord(ra, dec, frame='icrs')
>>> sc = SkyCoord(ra=ra, dec=dec, frame=ICRS, obstime='2001-01-02T12:34:56')

低水準クラスのオブジェクトを使ってSkyCoorオブジェクトを定義することもできます。

>>> c = FK4(1 * u.deg, 2 * u.deg)
>>> sc = SkyCoord(c, obstime='J2010.11', equinox='B1965')  # FK4のデフォルト設定を上書き

FK4などの低水準クラスは、それぞれに各種のデフォルト値を持っています。例えば、FK4の場合、equinox='B1950.0obstime=equinox がデフォルト値です。これらのデフォルト値は、低水準クラスをSkyCoordオブジェクトとして取り込む際に、別の値に書き換えても適切に処理されます。ただし、低水準クラスで明示的に値を与えている場合、例えば上の例で、c = FK4(1 * u.deg, 2 * u.deg, equinox='B1960') とした場合、異なる equinox でSkyCoordオブジェクトを定義しようとするとエラーの原因となります。


SkyCoordオブジェクトの書式

SkyCoordオブジェクトが扱うことのできるほとんどの座標系ではデフォルのと座標は球面座標です。球面座標を用いる場合、SkyCoordオブジェクトの書式は以下の形式になります。

SkyCoord(COORD, [FRAME | frame=FRAME], [unit=UNIT], keyword_args ...)
SkyCoord(LON, LAT, [DISTANCE], [FRAME | frame=FRAME], [unit=UNIT], keyword_args ...)
SkyCoord([FRAME | frame=FRAME], =LON, =LAT, [unit=UNIT],
         keyword_args ...)

上に示した書式の中で、大文字で書かれた要素(例えば、FRAME)はユーザーが与える情報です。括弧の中の要素はオプションなので必要に応じて与えます。(球面座表以外の場合の書式は***で説明します。)

LON、LAT

LON、LATでは球面座標における経度、緯度を指定します。経度、緯度を与えるとき、次のようなオプションを選択することができます。
  • 単独の値を与える場合は以下の方法がある。(1)Quantityオブジェクトを用いる、(2)数値を与え、astropy.unitで単位を指定する、(3)その2で説明したAngle文字列で指定する。
  • 複数の値を与える場合は、Pythonリスト、Quantityオブジェクトの配列、Numpy配列などが使用できる。
  • その2で説明した、Angleオブジェクト、Latitudeオブジェクト、Longitudeオブジェクトを使って指定することも可能。これらのオブジェクトは、スカラー(単独値)としても配列としても使用可能。

DISTANCE

オプションとして、天体までの距離をSkyCoordオブジェクトの中に書き込むことができます。距離は、次のような大きく2つの方法で与えることができます。
  • 単独の値として与える場合は、(1)Quantityオブジェクト、またはDistanceオブジェクトとして指定する、(2)無次元量としての距離を数値で与える、(3)数値で距離を与え、astropy.unitで単位を指定する。
  • Pythonリスト、Quantityオブジェクトの配列、Distanceオブジェクトの配列、Numpy配列などで与える。

COORD

SkyCoordオブジェクトの座標値の情報は、COORDという単一の情報として与えることもできます。球面座標系の場合は、経度緯度の値のペアを単位として、1つのペア、もしくは複数のペアをCOORDとして与えることができます。COORDの情報を与える場合に使える書式は以下のとおりです。

  • 経度と緯度の値をスペースで区切って並べた文字列。経度と緯度の書式は、その2の「角度の与え方」で説明した方法で与える。
  • 座標値の文字列からなるPythonリストもしくはNumpy配列。
  • (経度、緯度)の形のPythonタプルからなるリスト。ただし、経度、緯度はスカラーとして与える(つまり、配列では与えない)。
  • N x 2 型のNumpy配列もしくはQuantity配列。第1コラムに経度、第2コラムに緯度を与える。例えば、 [[270, -30], [355, +85]] * u.deg のような形。
  • (経度、緯度、距離)の形のタプルからなるPythonリスト。
  • N x 3 型のNumpy配列もしくはQuantity配列。第1コラムに経度、第2コラムに緯度、第3コラムに距離を与える。

上記のような書式に加えて、以下の様な、より柔軟な表記にも対応しています。

FRAME

ここでは座標系を指定します。 astropyには次のような座標系が用意されています、ICRSFK5FK4FK4NoETermsGalacticAltAz。パラメータとしてこれらの座標系を指定するときは小文字で書きます。

FRAMEを指定しない場合は、一応ICRSとして扱われます。ただし、具体的にFRAMEを指定しないと、異なった座標間における比較など、一部の機能が使用出来ません。

unit=UNIT

次のように単位を記法を指定することができます。

  • 角度を表すUnitオブジェクト
  • 角度の単位を表す文字列(スペースは含まない)。
  • UnitオブジェクトからなるPythonタプル、もしくは単位を表す文字列からなるPythonタプル。単位の並べ方は、LON、LATの順。例えば、 ('hourangle', 'degree')
  • 2つの単位を表す文字列をコンマで区切った単一の文字列。例えば、'hourangle,degree'

もし単位を一つだけ与えた場合は、LON、LATに同じ単位が指定されます。

その他の変数

経度、緯度を表すとき、一部の座標系ではその経度、緯度に対してその座標系特有の呼称を用いることができます。

例えば、ICRSFK5FK4FK4NoETermsといった座標系では、ra、decで経度、緯度を表すことができます。同様に、銀河系座標(Galactic)では、l、bで経度、緯度を表すことができます。

次のキーワードはどのような座標系でも用いることができます。

distance: 座標系の原点からの距離を与えます。(Distanceクラスの設定値を初期化します。)
obstime: 観測時間を与えます。(Timeクラスの設定値を初期化します。)
equinox: 座標家の分点を与えます。(Timeクラスの設定値を初期化します。)

配列を使った操作

SkyCoordオブジェクトでは、座標値を配列として与えることができます。配列として座標値を与えておくと、単独の座標値を与えたSkyCoordオブジェクトを繰り返し処理するのに比べて、格段に高速に各種の作業を行うことができます。例えば、1000個の座標値をICRSから銀河系座標(galactic)に変換する場合でその処理速度の違いを見てみましょう。

>>> ra = np.random.uniform(0, 360, size=1000) * u.deg
>>> dec = np.random.uniform(-90, 90, size=1000) * u.deg

>>> sc_list = [SkyCoord(r, d, frame='icrs') for r, d in zip(ra, dec)]
>>> timeit sc_gal_list = [c.galactic for c in sc_list]  
1 loops, best of 3: 7.66 s per loop

>>> sc = SkyCoord(ra, dec, frame='icrs')
>>> timeit sc_gal = sc.galactic  
100 loops, best of 3: 8.92 ms per loop

また、当然ながらPythonの配列と同様に選択やスライスなどの処理も行えます。

>>> north_mask = sc.dec > 0
>>> sc_north = sc[north_mask]
>>> len(sc_north)  
504
>>> sc[2:4]  
<SkyCoord (ICRS): (ra, dec) in deg
    [(304.304015..., 6.900282...),
     (322.560148..., 34.872244...)]>
>>> sc[2]  
<SkyCoord (ICRS): ra=304.304015... deg, dec=6.900282... deg>

SkyCoordの便利な機能

SkyCoordクラスには他にも多くの便利な機能(attribute、method)が備わっています。SkyCoordに備わった、attributeやmethodを使いこなすことで、より効率的に作業を進めることができます。

Attributeやmethodを使う際に知っておきたいのがtab補完(TAB-discovery)です。IPythonを使用している場合は、SkyCoordオブジェクトの名前を入力した後にピリオドをタイプしTABキーを押すと、どのようなattributeやmethodが使用可能が表示されます。

>>> sc = SkyCoord(1, 2, frame='icrs', unit='deg', obstime='2013-01-02 14:25:36')
>>> sc.  
sc.cartesian                           sc.match_to_catalog_3d
sc.data                                sc.match_to_catalog_sky
sc.dec                                 sc.name
sc.default_representation              sc.obstime
sc.distance                            sc.position_angle
sc.equinox                             sc.ra
sc.fk4                                 sc.realize_frame
sc.fk4noeterms                         sc.represent_as
sc.fk5                                 sc.representation
sc.frame                               sc.representation_component_names
sc.frame_attr_names                    sc.representation_component_units
sc.frame_specific_representation_info  sc.representation_info
sc.from_name                           sc.separation
sc.galactic                            sc.separation_3d
sc.get_frame_attr_names                sc.shape
sc.has_data                            sc.spherical
sc.icrs                                sc.time_attr_names
sc.is_frame_attr_default               sc.to_string
sc.is_transformable_to                 sc.transform_to
sc.isscalar

非常に多くの機能が表示されますが、attributeには比較的機能に準拠した名前が付けられているので、表示された文字列から機能は想像がつく場合が多いでしょう。簡単な例では、赤経、赤緯を表示するには、radec を用います。

>>> sc.ra
<Longitude 1.0 deg>
>>> sc.dec
<Latitude 2.0 deg>

他にもいろいろと使えそうなattribute名が目につくはずです。例えば、座標系の名前、icrs, galactic, fk5 fk4, fk4noeterms が目につくと思います。これらのattributeを使用すると、元の座標値を該当する座標系における座標値に変換した後、その座標系における新たなSkyCoordオブジェクトが作成されます。

>>> sc_gal = sc.galactic
>>> sc_gal  
<SkyCoord (Galactic): (l, b) in deg
    (99.6378552814, -58.7096929334)>

この他にも、distance, equinox, obstime, shape、などは覚えておくと便利でしょう。

2015年4月13日月曜日

astropy.coordinatesを用いた座標の取り扱い、その2 ― 角度の扱い

astropy.coordinatesの中で、座標系を表すオブジェクトは、Angle というクラスによって構成されています。Angle クラスはastropy.coordinatesの中で特に重要ですが、astropyの他のパッケージでも角度を扱うときに必ず出てくるクラスなのでその機能を知っておくことは重要です。

Angleオブジェクトの作成

Angleオブジェクトは様々な形で定義することができます。インプットとして与える角度は、単独の値はもちろんのこと、Python配列、タプル、文字列など様々な形をとることができます。Angleオブジェクトの定義の例を以下に示します。

>>> import numpy as np
>>> from astropy import units as u
>>> from astropy.coordinates import Angle

>>> Angle('10.2345d')              # d(°)を単位として文字列で定義
<Angle 10.2345 deg>
>>> Angle(['10.2345d', '-20d'])    # 文字列の配列で定義
<Angle [ 10.2345,-20.    ] deg>
>>> Angle('1:2:30.43 degrees')     # d(°)を60進数で定義
<Angle 1.0417861111111113 deg>
>>> Angle('1 2 0 hours')           # hoursを60進数で定義 
<Angle 1.0333333333333334 hourangle>
>>> Angle(np.arange(1., 8.), unit=u.deg)  # Numpy array from 1..7 in degrees
<Angle [ 1., 2., 3., 4., 5., 6., 7.] deg>
>>> Angle(u'1°2′3″')               # Unicodeの記号をそのまま使うこともできる
<Angle 1.0341666666666667 deg>
>>> Angle('1d2m3.4s')              # Degree, arcmin, arcsec.  
<Angle 1.0342777777777779 deg>
>>> Angle('-1h2m3s')               # Hour, minute, second  
<Angle -1.0341666666666667 hourangle>
>>> Angle((-1, 2, 3), unit=u.deg)  # (degree, arcmin, arcsec)  
<Angle -1.0341666666666667 deg>
>>> Angle(10.2345 * u.deg)         # From a Quantity object in degrees  
<Angle 10.2345 deg>
>>> Angle(Angle(10.2345 * u.deg))  # AngleオブジェクトでAngleオブジェクトを定義
<Angle 10.2345 deg>

角度の与え方

Angleオブジェクトは、様々な方法で角度の値を与えることができます。角度の値は文字列でも浮動小数点数のどちらでも構いません。

>>> a = Angle(1, u.radian)
>>> a
<Angle 1.0 rad>
>>> a.radian
1.0
>>> a.degree  
57.29577951308232
>>> a.hour  
3.8197186342054885
>>> a.hms  
hms_tuple(h=3.0, m=49.0, s=10.987083139758766)
>>> a.dms  
dms_tuple(d=57.0, m=17.0, s=44.806247096362313)
>>> a.signed_dms  
signed_dms_tuple(sign=1.0, d=57.0, m=17.0, s=44.806247096362313)
>>> (-a).dms  
dms_tuple(d=-57.0, m=-17.0, s=-44.806247096362313)
>>> (-a).signed_dms  
signed_dms_tuple(sign=-1.0, d=57.0, m=17.0, s=44.806247096362313)
>>> a.arcminute  
3437.7467707849396
>>> a.to_string()
u'1rad'
>>> a.to_string(unit=u.degree)
u'57d17m44.8062s'
>>> a.to_string(unit=u.degree, sep=':')
u'57:17:44.8062'
>>> a.to_string(unit=u.degree, sep=('deg', 'm', 's'))
u'57deg17m44.8062s'
>>> a.to_string(unit=u.hour)
u'3h49m10.9871s'
>>> a.to_string(unit=u.hour, decimal=True)
u'3.81972'

Angleオブジェクトの使用例

Angleオブジェクトは、直接Python内の各種演算に対応しています。

>>> a = Angle(1.0, u.radian)
>>> a + 0.5 * u.radian + 2 * a
<Angle 3.5 rad>
>>> np.sin(a / 2)  
<Quantity 0.479425538604203>
>>> a == a
array(True, dtype=bool)
>>> a == (a + a)
array(False, dtype=bool)

もちろんAngleオブジェクトは天体の座標を指定する際にも使われます。

>>> from astropy.coordinates import ICRS
>>> ICRS(Angle(1, u.radian), Angle(0.5, u.radian)) 
<ICRS Coordinate: (ra, dec) in deg (57.2957795131, 28.6478897565)>

角度値のラッピングと範囲内かどうかの判定

角度を扱う上で便利な機能を2つ紹介しておきます。1つは角度をラッピングするための wrap_at() 、もう1つは角度が特定の範囲内に収まっているかどうかを判断する is_within_bounds() です。

wrap_at() は次のような形式で使用します。wrap_at(wrap_angle, inplace=False) 

wrap_angleで、ラッピングする範囲を指定します。例えば、角度を0°から360°の範囲で表示したい場合、wrap_angleは360°、-180°から180°の範囲で表したい場合は wrap_angleは180°となります。(つまり数式で表すと、wrap_angle - 360d <= angle < wrap_angle ということになります。) inplaceでは、結果を別のAngleオブジェクトとして返すか入力として与えた角度を上書きするかを指定します。デフォルトでは inplace=Falseとなっており、結果を新たなAngleオブジェクトとしてして返します。入力した角度を上書きしたい場合は、inplace=True とします。以下、具体的な使用例を見てみましょう。

>>> from astropy.coordinates import Angle
>>> import astropy.units as u
>>> a = Angle([-20.0, 150.0, 350.0] * u.deg)

>>> a.wrap_at(360 * u.deg).degree  # 0°から360°の範囲でラッピング。inplaceはデフォルト値。
array([ 340.,  150.,  350.])

>>> a.wrap_at('180d', inplace=True)  # -180°から180°でラッピング。inplace=Trueなのでaが上書きされる。
>>> a.degree  # aをdegree単位で表示。
array([ -20.,  150.,  -10.])

is_within_bounds()は、インプットとして当てる角度が指定した範囲内に入っているかどうかを判定します。is_within_dounds()は、次の形式で使用します。is_within_bounds(lower=None, upper=None)

与えたlowerとupperの値に対して、与えたangleが、lower <= angle < upper を満たしているかどうかを判定します。もし、lower の値を指定しない場合(もしくは、None を指定した場合)は、upperのみが考慮されます。これは upper に対しても同じです。以下、使用例を見てみましょう。

>>> from astropy.coordinates import Angle
>>> import astropy.units as u
>>> a = Angle([-20, 150, 350] * u.deg)
>>> a.is_within_bounds('0d', '360d')
False
>>> a.is_within_bounds(None, '360d')
True
>>> a.is_within_bounds(-30 * u.deg, None)
True

LongitudeオブジェクトとLatitudeオブジェクト

LongitudeオブジェクトとLatitudeオブジェクトはAngleオブジェクトと類似したオブジェクトですが、球面座標系における座標値を表すことに特化したオブジェクトです。Longitudeオブジェクトは、例えば、赤道座標系における赤経、銀河座標系における銀系、Alt-Az座標系における方位角を表す場合に用います。一方、Latitudeオブジェクトは、赤道座標系における赤緯、銀河座標系における銀緯、Alt-Az座標系における仰角を表す場合に用いられます。

Longitudeオブジェクト

Longitudeオブジェクトは、wrap_angle というパラメータを設定することができる点が普通のAngleオブジェクトと異なるところです。wrap_angle を指定することによって、あらゆる角度の値を次のような一定の範囲内の角度値で表現します。

wrap_angle - 360 * u.deg <= angle(s) < wrap_angle

デフォルトの wrap_angle は360°です。wrap_angle=180 * u.deg と設定すると、値の範囲が-180°から+180°に変更されます。Longitudeオブジェクトは、wrap_angleを変更すると新しい値はインプットのAngleオブジェクトに上書きされます。以下で使用例を見てみましょう。

>>> from astropy.coordinates import Longitude
>>> a = Longitude([-20, 150, 350, 360] * u.deg)
>>> a.degree
array([ 340., 150., 350.,   0.])
>>> a.wrap_angle = 180 * u.deg
>>> a.degree
array([ -20., 150., -10.,   0.])

Latitudeオブジェクト

Latitudeオブジェクトは、値が以下のような範囲に限定される点で通常のAngleオブジェクトと異なります。

-90.0 * u.deg <= angle(s) <= +90.0 * u.deg

この範囲外で値を定義しようとするとエラーが返ってきます。

2015年2月22日日曜日

astropy.coordinatesを用いた座標の取り扱い、その1 ― パッケージの概要

astropy.coordinatesを用いた天文学上の座標の扱いについてまとめて行きます。ここでは、python(x,y) 2.7.9.0とそれに付随してくるastropyを使用することを前提にしています。

天文学用のPythonパッケージであるastropyには、座標を扱うためのパッケージである coordinatesが含まれています。coordinatesを用いると、様々な座標の相互変換を簡単に行うことができます。まず最初は、coordinatesパッケージを使っておおよそどのようなことができるのか概要を見ていくことにします。

coordinatesを使うときに基本となるのが、SkyCoordというオブジェクトです。SkyCoordオブジェクトは、様々な座標表記に柔軟に対応しています。では、具体例を見て行きましょう。

まず、必要なパッケージを読み込みます。以下の例では、単位を扱うパッケージ unitsも使用するので、SkyCoordクラスと合わせて importしておきます。

>>> from astropy import units as u
>>> from astropy.coordinates import SkyCoord

必要なパッケージを読み込んだら、SkyCoordオブジェクトを定義してみます。SkyCoordオブジェクトは同じ内容を様々な形式で定義することができます。以下の定義は全て同じ内容です。

>>> c = SkyCoord(ra=10.625*u.degree, dec=41.2*u.degree, frame='icrs')
>>> c = SkyCoord(10.625, 41.2, frame='icrs', unit='deg')
>>> c = SkyCoord('00h42m30s', '+41d12m00s', frame='icrs')
>>> c = SkyCoord('00h42.5m', '+41d12m', frame='icrs')
>>> c = SkyCoord('00 42 30 +41 12 00', frame='icrs', unit=(u.hourangle, u.deg))
>>> c = SkyCoord('00:42.5 +41:12', frame='icrs', unit=(u.hourangle, u.deg))

各定義を行った後で、実際に c の内容を表示し、全て同じ内容であることを確認しましょう。

>>> c
<SkyCoord (ICRS): (ra, dec) in deg (10.625, 41.2)>

上記のように、座標値は特に変数名を指定しなくても記述することができます。変数名を明示して値を記述するときは、赤経、赤緯は、ra、dec、銀経銀緯は、l、b で指定します。座標系の種類にデフォルト値は存在せず必ず値を指定しなくてはいけません(以下で見るように、異なる座標間の変換や比較を行わない場合は省略しても構いません)。座標系の種類も、変数を使わず指定できますが、変数を明示して指定する場合は、frame という変数名を用います。

数値を与えるときは単位を指定する必要があります。例えば、10.5*u.degree、+41d12m00s の様な感じです。単位の指定は astropy.unitsパッケージを用いて行います。
(astropy.unitsに関しては、ここ参照。)

赤道座標系(赤経、赤緯)を表すSkyCoordオブジェクトは、LongitudeオブジェクトとLatitudeオブジェクトから構成されており、個別に情報を取り出すことができます。LongitudeオブジェクトとLatitudeオブジェクは、角度を扱う Angleクラスの一種なので、下記の用例のように角度表示の方法を様々に変更することが可能です。

>>> c = SkyCoord(ra=10.68458*u.degree, dec=41.26917*u.degree)
>>> c.ra  
<Longitude 10.68458 deg>
>>> c.ra.hour  
0.7123053333333335
>>> c.ra.hms  
hms_tuple(h=0.0, m=42.0, s=44.299200000000525)
>>> c.dec  
<Latitude 41.26917 deg>
>>> c.dec.degree  
41.26917
>>> c.dec.radian  
0.7202828960652683

SkyCoordオブジェクトの値は、文字列として取り出すこともできます。文字列への変換は、to_sting() メソッドを用いて行います。

>>> c = SkyCoord(ra=10.68458*u.degree, dec=41.26917*u.degree)
>>> c.to_string('decimal')
'10.6846 41.2692'
>>> c.to_string('dms')
'10d41m04.488s 41d16m09.012s'
>>> c.to_string('hmsdms')
'00h42m44.2992s +41d16m09.012s'

to_string() メソッドでは、上記のフォーマット以外にも、LaTeX形式など様々なフォーマットを利用することができます。

>>> c.ra.to_string(decimal=True)
'10.6846'
>>> c.dec.to_string(format='latex')
'$41^\\circ16{}^\\prime09.012{}^{\\prime\\prime}$'
>>> msg = 'My coordinates are: ra="{0}"" dec="{1}"'
>>> msg.format(c.ra.to_string(sep=':'), c.dec.to_string(sep=':'))
'My coordinates are: ra="10:41:04.488"" dec="41:16:09.012"'

ここまでに示した例では、座標の変換や比較は行う必要がなかったので frameの指定は行いませんでしたが、基本的には SkyCoordオブジェクトを定義するときには frameの指定を行う必要があります。

>>> c_icrs = SkyCoord(ra=10.68458*u.degree, dec=41.26917*u.degree, frame='icrs')

frameの指定を含めてSkyCoordオブジェクトを定義すると、座標値を他の座標における値に変換することができるようになります。座標値の変換にはいくつかの方法がありますが、一番応用が利く方法は、transform_to メソッドを用いる方法です。

>>> from astropy.coordinates import FK5
>>> c_icrs.galactic  
<SkyCoord (Galactic): (l, b) in deg
    (121.174241811, -21.5728855724)>
>>> c_fk5 = c_icrs.transform_to('fk5')  # c_icrs.fk5 does the same thing
>>> c_fk5  
<SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
    (10.6845915393, 41.2691714591)>
>>> c_fk5.transform_to(FK5(equinox='J1975'))  # precess to a different equinox  
<SkyCoord (FK5: equinox=J1975.000): (ra, dec) in deg
    (10.3420913461, 41.1323211229)>

transform_to メソッドを用いると、天体座標を AltAz座標系に変換することもできるので、例えば観測計画をたてるとき等にも SkyCoord オブジェクトを活用することができます。実際に SkyCoordオブジェクトを用いた観測計画の検討方法については機会をあらためて解説したいと思います。

SkyCoordは、Pythonの配列に対応しています。SkyCoordを用いて天体カタログなどの大量のデータを処理するときには、ループを用いて処理するよりも配列を用いて処理する方が遥かに高速です。

>>> SkyCoord(ra=[10, 11]*u.degree, dec=[41, -5]*u.degree)
<SkyCoord (ICRS): (ra, dec) in deg
    [(10.0, 41.0), (11.0, -5.0)]>

ここまでの例では球面座標を使用してきました。SkyCoordオブジェクトではデフォルトが球面座標なので特に明示的に定義は行いませんでした。SkyCoordオブジェクトでは、球面座標以外にも直交座標と円柱座標を使用することができます。球面座標以外の座標を用いる場合は、representation という変数に使用する座標の種類を明示的に定義する必要があります。

>>> c = SkyCoord(x=1, y=2, z=3, unit='kpc', frame='icrs', representation='cartesian')
>>> c
<SkyCoord (ICRS): (x, y, z) in kpc
    (1.0, 2.0, 3.0)>
>>> c.x, c.y, c.z
(<Quantity 1.0 kpc>, <Quantity 2.0 kpc>, <Quantity 3.0 kpc>)

>>> c.representation = 'cylindrical'
>>> c  
<SkyCoord (ICRS): (rho, phi, z) in (kpc, deg, kpc)
    (2.2360679775, 63.4349488229, 3.0)>
>>> c.phi
<Angle 63.434948... deg>
>>> c.phi.to(u.radian)
<Angle 1.107148... rad>

>>> c.representation = 'spherical'
>>> c  
<SkyCoord (ICRS): (ra, dec, distance) in (deg, deg, kpc)
    (63.4349488229, 53.3007747995, 3.74165738677)>

>>> c.representation = 'unitspherical'
>>> c  
<SkyCoord (ICRS): (ra, dec) in deg
    (63.4349488229, 53.3007747995)>

SkyCoordオブジェクトを用いると、2つの天体の間の角距離の計算や、天体カタログどうしのクロスチェックなどを簡単に行うことができます。天体カタログどうしのクロスチェックについては別の機会に解説したいと思います。

>>> c1 = SkyCoord(ra=10*u.degree, dec=9*u.degree, frame='icrs')
>>> c2 = SkyCoord(ra=11*u.degree, dec=10*u.degree, frame='fk5')
>>> c1.separation(c2)  # c1とc2の間の各距離を求めています。  
<Angle 1.4045335865905868 deg>

Skycoordオブジェクトでは、天体までの距離も指定することができます。距離原点は座標系にもよりますが、基本的に地球からの距離を与えます。距離を指定すると空間における位置が決まるので、天体の位置をデカルト座標で表示することが可能となります。

>>> from astropy.coordinates import Distance
>>> c = SkyCoord(ra=10.68458*u.degree, dec=41.26917*u.degree, distance=770*u.kpc)
>>> c.cartesian.x  
<Quantity 568.7128654235232 kpc>
>>> c.cartesian.y  
<Quantity 107.3008974042025 kpc>
>>> c.cartesian.z  
<Quantity 507.88994291875713 kpc>

天体までの距離を与えると、2天体間の空間的な距離を計算するなど、SkyCoordオブジェクトを用いて、さらに様々な計算ができるようになります。

>>> c1 = SkyCoord(ra=10*u.degree, dec=9*u.degree, distance=10*u.pc, frame='icrs')
>>> c2 = SkyCoord(ra=11*u.degree, dec=10*u.degree, distance=11.5*u.pc, frame='icrs')
>>> c1.separation_3d(c2)  
<Distance 1.5228602415117989 pc>

インターネットへ接続できる環境があれば、from_nameというメソッドを使うことによって座標情報をネットから(おそらくSIMBAD)から取得することができます。

>>> SkyCoord.from_name("M42")  
<SkyCoord (ICRS): (ra, dec) in deg
    (83.82208, -5.39111)>

from_nameは便利ですが正確な位置情報の提供を必ずしも保証するものではないので信用できる位置情報を用いいる必要がある場合は主導で位置情報を与えるほうが無難です。