Pythonとの連携

このページの内容はLinux版の IDL + Python を前提としているため、他のOSでは異なる場合があります。

Python Bridge

Python Bridge を用いることで、IDLでPythonのコードを実行 (IDL to Python Bridge)、PythonでIDLのコードを実行 (Python to IDL Bridge)し、データをやりとりすることができる。具体的な使用方法は公式マニュアルを参照。

対応するPythonのバージョンは次の通り。

Python 2.73.43.53.63.73.83.93.103.113.12
IDL 9.0 No No No No No YesYesYesYesNo
IDL 8.9 No No No No No YesYesYesNo No
IDL 8.8.2, 8.8.3 No No No No YesYesYesYesNo No
IDL 8.8.1 No No No YesYesYesYesNo No No
IDL 8.8 No No No YesYesYesNo No No No
IDL 8.7.1–8.7.3YesNo YesYesNo No No No No No
IDL 8.6.1, 8.7 YesYesYesYesNo No No No No No
IDL 8.5.2, 8.6 YesYesYesNo No No No No No No
IDL 8.5, 8.5.1 YesYesNo No No No No No No No

IDLから Python のコードを実行する (IDL to Python Bridge)

IDLから Python のコードを実行するために必要な条件:

python コマンドで起動される Python のバージョンは python --version として確認できる。python コマンドが定義されていなかったり、python コマンドで古いバージョンの Python が起動してしまう環境の場合、

などの方法で、目的の Python が起動するようにする。

IDLがlibpythonX.X.so を見つけられない場合には、libpythonX.X.so が置かれているパスをLD_LIBRARY_PATH環境変数に追加する必要がある。

RHEL/CentOS 7 の SCL (Software Collection) で提供される Python にはバージョン番号のsuffixが付加されていないライブラリ libpythonX.X.so が存在しないため、シンボリックリンクを張っておく必要がある。

  1. ln -s libpython3.6m.so /opt/rh/rh-python36/root/lib64/libpython3.6m.so.1.0
  2. ln -s libpython3.8.so.rh-python38-1.0 /opt/rh/rh-python38/root/lib64/libpython3.8.so.1.0

IDLに添付されているいくつかの共有ライブラリのバージョンと、Pythonや拡張モジュールが要求する共有ライブラリのバージョンに互換性がない場合には、LD_LIBRARY_PATH環境変数内でのディレクトリの順番を調整したり、Python開始時にLD_PRELOAD環境変数でOS標準のライブラリを指定する必要があるかもしれない。特に libstdc++.so.6 や libfreetype.so.6 などで問題が発生する可能性がある。

PythonからIDLのコードを実行する (Python to IDL Bridge)

PythonからIDLのコードを実行するために必要な条件:

Python がモジュールを検索するパスを追加するには、Python 起動前ならPYTHONPATH環境変数で、Python 起動後なら sys.path.append を使う。

共有ライブラリの探索パスを追加するには LD_LIBRARY_PATH環境変数を用いる。

IDLに添付されているいくつかの共有ライブラリのバージョンと、Pythonや拡張モジュールが要求する共有ライブラリのバージョンに互換性がない場合には、LD_LIBRARY_PATH環境変数内でのディレクトリの順番を調整したり、Python開始時にLD_PRELOAD環境変数でOS標準のライブラリを指定する必要があるかもしれない。特に libstdc++.so.6 や libfreetype.so.6 などで問題が発生する可能性がある。

カラーテーブル

matplotlib のカラーマップを IDL で使う方法IDL のカラーテーブルを matplotlib で使う方法については別ページを参照。

IDLのsaveファイルをPythonで読む

SciPy の scipy.io.readsav 関数を用いることで、IDLで作成されたsaveファイル(XDR: eXternal Data Representation 形式)をPythonで読み込むことができる。

例えば、次のようなsaveファイルを作成する。

  1. ; IDL
  2. IDL> a = dindgen(5)
  3. IDL> b = complex(1, 2)
  4. IDL> c = 'string'
  5. IDL> save, a, b, c, file = 'test1.sav'

readsave() は辞書(dict)を返すので、keys() で各要素のキー(=IDLでの変数名)を取得できる。

  1. # Python
  2. >>> import scipy.io as sio
  3. >>> sav_data = sio.readsav('test1.sav')
  4. >>> sav_data.keys()
  5. dict_keys(['a', 'b', 'c'])

各要素のキー(=IDLでの変数名)がわかれば、値を取得できる。IDLの数値型は、NumPy の対応する型になる。例: LONG=>numpy.int32, DOUBLE=>numpy.float64, DCOMPLEX=>numpy.complex128。IDLの文字列はバイト列 (bytes)になるので、decode() で文字列を得る。

  1. # Python
  2. >>> sav_data['a']
  3. array([0., 1., 2., 3., 4.])
  4. >>> sav_data['b']
  5. (1+2j)
  6. >>> sav_data['c']
  7. b'string'
  8. >>> sav_data['c'].decode()
  9. 'string'

IDLの構造体は構造化配列 (numpy.recarray)になる。

  1. ; IDL
  2. IDL> a = {key1: [1, 2, 3], key2: 'string'}
  3. IDL> b = [a, {key1: [4, 5, 6], key2: 'string2'}]
  4. IDL> save, a, b, file = 'test2.sav'
  1. # Python
  2. >>> import scipy.io as sio
  3. >>> sav_data2 = sio.readsav('test2.sav')
  4. >>> sav_data2['a']
  5. rec.array([(array([1, 2, 3], dtype=int16), b'string')],
    dtype=[(('key1', 'KEY1'), 'O'), (('key2', 'KEY2'), 'O')])
  6. >>> sav_data2['a'].key1[0]
  7. array([1, 2, 3], dtype=int16)
  8. >>> sav_data2['a'].key2[0]
  9. b'string'
  10. >>> sav_data2['b']
  11. rec.array([(array([1, 2, 3], dtype=int16), b'string'),
    (array([4, 5, 6], dtype=int16), b'string2')],
    dtype=[(('key1', 'KEY1'), 'O'), (('key2', 'KEY2'), 'O')])
  12. >>> sav_data2['b'].key1[1]
  13. array([4, 5, 6], dtype=int16)
  14. >>> sav_data2['b'].key2[1]
  15. b'string2'

LIST, HASH, ORDEREDHASH, DICTIONARY, BIGINTEGERなどのオブジェクトも構造化配列 (numpy.recarray)になる。LIST, HASH, ORDEREDHASH, DICTIONARY では _SR_PTR にキーと値が格納されている。以下は HASH の例。

  1. ; IDL
  2. IDL> a = HASH('key1', 1, 'key2', [2., 3.], 'key3', 'string')
  3. IDL> save, a, file = 'test3.sav'
  1. # Python
  2. >>> import scipy.io as sio
  3. >>> sav_data3 = sio.readsav('test3.sav')
  4. >>> sav_data3['a']
  5. rec.array([(0, None, 0, 0, 0, 0, 0, 0, None, 0, 32908864, array([array([b'key3', b'key2', b'key1'], dtype=object),
    array([b'string', array([2., 3.], dtype=float32), 1], dtype=object)],
    dtype=object)
    , 0)],
    dtype=[(('idl_object_top', 'IDL_OBJECT_TOP'), '>i8'), (('__obj__', '__OBJ__'), 'O'), (('idl_object_bottom', 'IDL_OBJECT_BOTTOM'), '>i8'), (('table_bits', 'TABLE_BITS'), '>u4'), (('table_size', 'TABLE_SIZE'), '>u4'), (('table_count', 'TABLE_COUNT'), '>u4'), (('table_remove', 'TABLE_REMOVE'), '>u4'), (('table_foreach', 'TABLE_FOREACH'), '>u4'), (('table_data', 'TABLE_DATA'), 'O'), (('flags', 'FLAGS'), '>u4'), (('_hashhandle', '_HASHHANDLE'), '>i8'), (('_sr_ptr', '_SR_PTR'), 'O'), (('idl_hashversion', 'IDL_HASHVERSION'), '>i2')])
  6. >>> sav_data3['a']._sr_ptr[0][0]
  7. array([b'key3', b'key2', b'key1'], dtype=object)
  8. >>> sav_data3['a']._sr_ptr[0][1]
  9. array([b'string', array([2., 3.], dtype=float32), 1], dtype=object)
  10. >>> # DICT に変換する
  11. >>> {k.decode(): v for k, v in zip(sav_data3['a']._sr_ptr[0][0], sav_data3['a']._sr_ptr[0][1])}
  12. {'key3': b'string', 'key2': array([2., 3.], dtype=float32), 'key1': 1}

BigInteger の場合、PDIGITS に下位の桁から32bitごとに区切られた値の配列が、負数のとき ISNEGATIVE に1が入っている。Python 3のint型は 2**63 を超える数も扱うことができる。

  1. ; IDL
  2. IDL> a = BigInteger('-123456789012345678901234567890')
  3. IDL> save, a, file = 'test4.sav'
  1. # Python
  2. >>> import scipy.io as sio
  3. >>> sav_data4 = sio.readsav('test4.sav')
  4. >>> sav_data4['a']
  5. rec.array([(0, None, 0, 1, 0, 0, array([1312754386, 3279151342, 2397638646, 1], dtype=uint32))],
    dtype=[(('idl_object_top', 'IDL_OBJECT_TOP'), '>i8'), (('__obj__', '__OBJ__'), 'O'), (('idl_object_bottom', 'IDL_OBJECT_BOTTOM'), '>i8'), (('isnegative', 'ISNEGATIVE'), 'u1'), (('isinfinite', 'ISINFINITE'), 'u1'), (('isnan', 'ISNAN'), 'u1'), (('pdigits', 'PDIGITS'), 'O')])
  6. >>> a = 0
  7. >>> for x in reversed(sav_data4['a'].pdigits[0]):
  8. ... a = (a << 32) + int(x)
  9. ...
  10. >>> if sav_data4['a'].isnegative[0] == 1:
  11. ... a = -a
  12. ...
  13. >>> a
  14. -123456789012345678901234567890
西田圭佑 (NISHIDA Keisuke)
nishida at kwasan.kyoto-u.ac.jp