このページの内容はLinux版の IDL + Python を前提としているため、他のOSでは異なる場合があります。
Python Bridge を用いることで、IDLでPythonのコードを実行 (IDL to Python Bridge)、PythonでIDLのコードを実行 (Python to IDL Bridge)し、データをやりとりすることができる。具体的な使用方法は公式マニュアルを参照。
対応するPythonのバージョンは次の通り。
Python 2.7 | 3.4 | 3.5 | 3.6 | 3.7 | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 | |
---|---|---|---|---|---|---|---|---|---|---|
IDL 9.0 | No | No | No | No | No | Yes | Yes | Yes | Yes | No |
IDL 8.9 | No | No | No | No | No | Yes | Yes | Yes | No | No |
IDL 8.8.2, 8.8.3 | No | No | No | No | Yes | Yes | Yes | Yes | No | No |
IDL 8.8.1 | No | No | No | Yes | Yes | Yes | Yes | No | No | No |
IDL 8.8 | No | No | No | Yes | Yes | Yes | No | No | No | No |
IDL 8.7.1–8.7.3 | Yes | No | Yes | Yes | No | No | No | No | No | No |
IDL 8.6.1, 8.7 | Yes | Yes | Yes | Yes | No | No | No | No | No | No |
IDL 8.5.2, 8.6 | Yes | Yes | Yes | No | No | No | No | No | No | No |
IDL 8.5, 8.5.1 | Yes | Yes | No | No | No | No | No | No | No | No |
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 が存在しないため、シンボリックリンクを張っておく必要がある。
ln -s libpython3.6m.so /opt/rh/rh-python36/root/lib64/libpython3.6m.so.1.0
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 がモジュールを検索するパスを追加するには、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 で使う方法については別ページを参照。
SciPy の scipy.io.readsav 関数を用いることで、IDLで作成されたsaveファイル(XDR: eXternal Data Representation 形式)をPythonで読み込むことができる。
例えば、次のようなsaveファイルを作成する。
; IDL
IDL> a = dindgen(5)
IDL> b = complex(1, 2)
IDL> c = 'string'
IDL> save, a, b, c, file = 'test1.sav'
readsave() は辞書(dict)を返すので、keys() で各要素のキー(=IDLでの変数名)を取得できる。
# Python
>>> import scipy.io as sio
>>> sav_data = sio.readsav('test1.sav')
>>> sav_data.keys()
dict_keys(['a', 'b', 'c'])
各要素のキー(=IDLでの変数名)がわかれば、値を取得できる。IDLの数値型は、NumPy の対応する型になる。例: LONG=>numpy.int32, DOUBLE=>numpy.float64, DCOMPLEX=>numpy.complex128。IDLの文字列はバイト列 (bytes)になるので、decode() で文字列を得る。
# Python
>>> sav_data['a']
array([0., 1., 2., 3., 4.])
>>> sav_data['b']
(1+2j)
>>> sav_data['c']
b'string'
>>> sav_data['c'].decode()
'string'
IDLの構造体は構造化配列 (numpy.recarray)になる。
; IDL
IDL> a = {key1: [1, 2, 3], key2: 'string'}
IDL> b = [a, {key1: [4, 5, 6], key2: 'string2'}]
IDL> save, a, b, file = 'test2.sav'
# Python
>>> import scipy.io as sio
>>> sav_data2 = sio.readsav('test2.sav')
>>> sav_data2['a']
rec.array([(array([1, 2, 3], dtype=int16), b'string')],
dtype=[(('key1', 'KEY1'), 'O'), (('key2', 'KEY2'), 'O')])
>>> sav_data2['a'].key1[0]
array([1, 2, 3], dtype=int16)
>>> sav_data2['a'].key2[0]
b'string'
>>> sav_data2['b']
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')])
>>> sav_data2['b'].key1[1]
array([4, 5, 6], dtype=int16)
>>> sav_data2['b'].key2[1]
b'string2'
LIST, HASH, ORDEREDHASH, DICTIONARY, BIGINTEGERなどのオブジェクトも構造化配列 (numpy.recarray)になる。LIST, HASH, ORDEREDHASH, DICTIONARY では _SR_PTR にキーと値が格納されている。以下は HASH の例。
; IDL
IDL> a = HASH('key1', 1, 'key2', [2., 3.], 'key3', 'string')
IDL> save, a, file = 'test3.sav'
# Python
>>> import scipy.io as sio
>>> sav_data3 = sio.readsav('test3.sav')
>>> sav_data3['a']
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')])
>>> sav_data3['a']._sr_ptr[0][0]
array([b'key3', b'key2', b'key1'], dtype=object)
>>> sav_data3['a']._sr_ptr[0][1]
array([b'string', array([2., 3.], dtype=float32), 1], dtype=object)
>>> # DICT に変換する
>>> {k.decode(): v for k, v in zip(sav_data3['a']._sr_ptr[0][0], sav_data3['a']._sr_ptr[0][1])}
{'key3': b'string', 'key2': array([2., 3.], dtype=float32), 'key1': 1}
BigInteger の場合、PDIGITS に下位の桁から32bitごとに区切られた値の配列が、負数のとき ISNEGATIVE に1が入っている。Python 3のint型は 2**63 を超える数も扱うことができる。
; IDL
IDL> a = BigInteger('-123456789012345678901234567890')
IDL> save, a, file = 'test4.sav'
# Python
>>> import scipy.io as sio
>>> sav_data4 = sio.readsav('test4.sav')
>>> sav_data4['a']
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')])
>>> a = 0
>>> for x in reversed(sav_data4['a'].pdigits[0]):
... a = (a << 32) + int(x)
...
>>> if sav_data4['a'].isnegative[0] == 1:
... a = -a
...
>>> a
-123456789012345678901234567890