idlwrap API
idlwrap helps you port IDL code to python by providing an IDL-like interface to numpy
and scipy
.
You do not need IDL to use idlwrap!
usage
An IDL function or procedure corresponds to a lowercased function in idlwrap:
FINDGEN -> idlwrap.findgen
POLY_FIT -> idlwrap.poly_fit
All idlwrap-specific functions end with an underscore. They have no directly corresponding IDL functions, they rather map special IDL syntax:
A # B
-> idlwrap.operator_(A, "#", B)
A[1:4,*] = 4
-> idlwrap.set_subset_(A, "[1:4,*]", 4)
FOR I=0, 32000 DO J = I
-> for i in idlwrap.range_(0, 32000): j = i
arrays
In python, array indices work differently from IDL. When you are used to IDL's array subscripts,
idlwrap's subsetify_
function can be interesting for you.
Functions
findgen(*args)
Create a (multi-dimensional) range of float values.
Notes
Note that the shape of the output array is reversed compared to the
arguments passed (e.g. indgen(2,3,4)
→ shape 4,3,2). For 3D cubes, the
last argument to indgen is the number of frames, but the frame can be
accessed directly with result[n]
(first subset parameter.)
The keywords INCREMENT and START are not implemented.
Examples
FINDGEN(n) -> np.arange(n)
indgen(*shape)
Create a (multi-dimensional) range of integer values.
Notes
porting to python
If shape
is of one dimension only, you can use np.arange(n)
.
IDL accepts floats as dimension parameters, but applies int()
before
using them. While np.arange()
also accepts floats, be careful, as the
number of elements do not match any more!
INDGEN(5.2) -> [0,1,2,3,4]
INDGEN(5) -> [0,1,2,3,4]
np.arange(5.2) -> [0,1,2,3,4,5] ; !!
np.arange(int(5.2)) -> [0,1,2,3,4]
np.arange(5) -> [0,1,2,3,4]
dindgen(*shape)
Create a (multi-dimensional) range of double-precision float values.
fltarr(*shape)
Create a float array filled with zeros.
Parameters
- *shape : (multiple) ints, NOT a list
- the dimensions of the new array
- dtype : np.dtype, optional
- dtype object describing the tpe and precision of the values in the new
array. numpy's default is
float / np.float32
Notes
- the flag /nozero was omitted.
Porting to python
The core numpy function is np.zeros
. Pay attention when passing the
value 1
to FLTARR
(and its sister functions INTARR
and
DBLARR
), as the resulting shape is slightly different: IDL ignores any
final 1``s, so for IDL calling ``FLTARR(5, 1, 1, ...)
is the same as
FLTARR(5)
.
Examples
FLTARR(n) -> np.zeros(n)
FLTARR(a, b) -> np.zeros((b, a))
FLTARR(a, b, c) -> np.zeros((c, b, a))
FLTARR(a, b, 1, 1) -> np.zeros((b, a))
FLTARR(n)+1 -> np.ones(n)
intarr(*shape)
Create an integer array filled with zeros.
dblarr(*shape)
Create a double-precision float array filled with zeros.
shift(arr, *args)
WARNING
The Si
arguments can be either a single array containing the shift
parameters for each dimension, or a sequence of up to eight scalar shift
values. For arrays of more than one dimension, the parameter Sn
specifies
the shift applied to the n-th dimension
while this implementation supports lists as arr
argument, to match the
style of IDL, the IDLpy bridge does not support lists, and returns it
unchanged!
If SHIFT
is used in combination with FFT
, maybe you should look at
np.fft.fftshift
.
where(array_expression)
port of IDL's WHERE
function.
Parameters
- array_expression : ndarray / expression
- see examples.
Returns
- res : np.ndarray
- List of 'good' indices. If no index was found,
[-1]
is returned.
Notes
see also np.put(a, ind, v), which is roughly equivalent to a.flat[ind]=v
porting to python
Most of the time, you will use WHERE for subsetting arrays. While this works
only with indices in IDL (which are returned by WHERE), it work with both
indices (idlwrap.where
) and boolean masks (as returned by comparison
operators like array_a < array_b
). You can usually remove
idlwrap.where
entirely.
with 2d arrays a
, b
:
WHERE(a LT b)
-> idlwrap.where(idlwrap.operator_(a, "LT", b))
-> idlwrap.where(idlwrap.LT(a, b))
-> idlwrap.where(a < b)
# ... in fact, it could even be replaced directly by ``a < b`` (which
# returns a boolean array in np), if WHERE is used as array index!
Examples
array = FINDGEN(100)
B = WHERE(array GT 20)
values = array[B]
array = idlwrap.findgen(100)
b = idlwrap.where(idlwrap.GT(array, 20))
# equivalent to `idlwrap.where(a > 20)`
values = array[b]
# or even:
values = array[array > 20]
size(arr)
Size and type information for arrays.
Parameters
- arr : array_like
Returns
- ndim : int
- Number of dimensions.
- *shape : ints
- First, second, ... dimension.
- dtype : int or np.dtype
- Type of the array, as defined in the IDL Type Codes and Names, or as
np.dtype
object. - size : int
- Total number of elements.
median(array, width=None, even=False)
Parameters
- array : np.ndarray
- The array to be processed. Array can have only one or two dimensions. If Width is not given, Array can have any valid number of dimensions.
- width : np.ndarray
- The size of the one or two-dimensional neighborhood to be used for the median filter. The neighborhood has the same number of dimensions as array.
- even : bool, optional
- If the EVEN keyword is set when Array contains an even number of points (i.e. there is no middle number), MEDIAN returns the average of the two middle numbers. The returned value may not be an element of Array . If Array contains an odd number of points, MEDIAN returns the median value. The returned value will always be an element of Array --even if the EVEN keyword is set--since an odd number of points will always have a single middle value.
Notes
porting to python
As long as /EVEN
is passed to MEDIAN
, and no WIDTH
is present,
it can safely be replaced with np.median()
.
mean(x)
Parameters
- x : np.ndarray
Notes
The keyword parameters DIMENSION, DOUBLE and NAN are not implemented.
total(array, dimension=None, integer=False)
Parameters
- array : ndarray
- dimension : int, optional
- integer : bool, optional
Notes
To force ndim >= 1:
if res.ndim == 0:
return np.array([res])
else:
return res
Implementation differences
not implemented: /CUMULATIVE, /DOUBLE, /NAN, /PRESERVE_TYPE
porting to python
TOTAL corresponds to ndarray.sum(). The parameters /DOUBLE and /INTEGER can be replicated through the dtype=... parameter. DIMENSION needs more attention, as the dimensions are reversed. If no DIMENSION is passed, just use np.sum().
TOTAL(array) -> np.sum(array)
todo Does IDL support a list as DIMENSION? What happens?
finite(x, infinity=False, nan=False, sign=0)
Identifies whether or not a given argument is finite.
Parameters
- x : np.ndarray
- A floating-point, double-precision, or complex scalar or array expression. Strings are first converted to floating-point. ????
- infinity : bool, optional
- nan : bool, optional
- sign : int, optional
- Only 0, the default behaviour, is implemented.
Returns
- is_finite : bool / bool np.ndarray
- If the result is finite.
Notes
SIGN
is not implemented. One difficulty arrises from the fact that IDL
distinguishes between -!VALUES.F_NAN
and !VALUES.F_NAN
. In python,
there is no possibility to distinguish a negative from a positive
np.nan
:
a = -np.nan
b = np.nan
a == np.nan # -> False
b == np.nan # -> False
a < 0 # -> False
a > 0 # -> False
b < 0 # -> False
b > 0 # -> False
porting to python
if SIGN
is not set:
FINITE(..., /NAN) -> np.isnan(...)
FINITE(..., /INF) -> np.isinf(...)
FINITE(...) -> np.isfinite(...)
if SIGN
is set:
???
fft(array, direction=-1, inverse=False)
Parameters
- array : 2d (?????) np.ndarray
- direction : integer, optional
- Scalar indicating the direction fo the transform, which is negative by convention for the forward transform, and positive for the inverse transform. The value of direction is ignored if the inverse keyword is set.
- inverse : boolean, optional
- Set this keyword to perform an inverse transform. Setting this keyword
is equivalent to setting the
direction
argument to a positive value. Note, however, that settinginverse
results in an inverse transform even ifdirection
is specified as negative.
Notes
A normalization factor of 1/N, where N is the number of points, is applied during the forward transform.
Implementation details
The parameters CENTER
, DIMENSION
, DOUBLE
, OVERWRITE
and the thread pool
keywords are not implemented.
Examples
if you do not care about the normalization:
FFT(image2d, 1) -> np.fft.ifft2(image2d)
FFT(image2d, -1) -> np.fft.fft2(image2d)
randomn(seed=None, *shape)
Normal-distributed random numbers.
Parameters
- seed : int or 1-d array_like
- seed for random generator.
- *shape : list of int
- dimension of the returned array
Notes
RANDOMN
uses the Box-Muller method, based off of the gasdev
algorithm (section 7.2 Numerical Recipies in C, 1992) . The uniform random
numbers required for the Box-Miller method are generated using the Mersenne
Twister algorithm. [from the IDL documentation]
Note that the random numbers generated by python differ from the ones from IDL, as the seed is handled differently and the algorithms differ too.
abs(x)
absolute value
round(x)
round to the nearest integer (-> int type).
Parameters
- x : float or array
Returns
- x : np.int64 or int64-ndarray
Notes
ROUND
rounds to the nearest integer, unlike numpy's np.round
/ np.rint
,
which rounds to the nearest even value (defined in the standard IEEE 754)
https://stackoverflow.com/a/34219827/1943546
porting to python
No direct match. Use this workaround.
floor(x)
Parameters
- x : float or array
Returns
- x : np.int64 or int64-ndarray
Notes
The keyword L64 is not implemented.
porting to python
This is basically np.floor
, but IDL returns integer types (e.g. used as
array indices)
ceil(x)
Round upwards (towards infinity).
Returns
- x : np.int64 or int64-ndarray
fix(expression)
Round to nearest integer towards zero.
Returns
- x : np.int64 or int64-ndarray
complex(real, imaginary=0)
creates complex number. Same as idlwrap.dcomplex
Parameters
- real : float or array or list
- imaginary : float or array or list, optional
dcomplex(real, imaginary=0)
double-precision complex number
Parameters
- real : float or array or list
- Real part.
- imaginary : float or array or list, optional
- Imaginary part. Defaults to 0.
Returns
- complex_number : ndarray
Notes
This always returns a numpy array. Beware of that if you call e.g.
idlwrap.complex(1,2).real
, which results in an 0-dimension np.ndarray.
The second signature type, with Expression, Offset, D1, D2, ...
is not
supported.
real_part(z)
Parameters
- z : complex or ndarray
Notes
numpy .real
works with complex numbers and ndarray
.
imaginary(complex_expression)
imaginary part
conj(x)
complex conjugate
acos(x)
asin(x)
atan(x)
alog(x)
alog2(x)
alog10(x)
beta(z, w)
ibeta(a, b, z)
beselj(x, n)
Returns the J Bessel function of order N for the argument X.
Parameters
- x
- argument. A scalar or array specifying the values for which the Bessel function is required. IDL: Values for X must be in the range -108 to 108. If X is negative then N must be an integer (either positive or negative).
- n
- order. A scalar or array specifying the order of the Bessel function to calculate. Values for N can be integers or real numbers. If N is negative then it must be an integer.
Returns
- my_return_parameter
Notes
The output keyword ITER
, which returns the number of iterations, was
omitted. For J Bessel functions, scipy's jn
is just an alias for jv
(which is not the case for the other Bessel functions, e.g. yn and yv)
porting to python
Replace BESELJ(x, n)
with scipy.special.jv(n, x)
. Pay attention to
the inversed order of the arguments.
keyword_set(kw)
only true if kw
is defined AND different from zero.
here, None
is used for non-defined keyword.
range_(init, limit, increment=1)
Behaves like IDL's FOR i=init, limit DO statement
.
Parameters
- init : int, float
- limit : int, float
Notes
The endpoint stop
is included (<=
comparison instead of python's
<
). The increment
is not implemented.
Examples
FOR I=0, 32000 DO J = I
-> for i in range_(0, 3200): j = i
FOR K=100.0, 1.0, -1 DO BEGIN
PRINT, K
ENDFOR
-> for k in range_(100.0, 1.0, -1):
print(k)
range_int_(*args)
Like range_
, but returns integers which could then be used as list indices.
subsetify_(arr)
Transforms a numpy ndarray to an object which implements IDLs array subsetting. This is a
convenient alternative to the subset_
and set_subset_
functions.
Returns
- arr : object
- This object is like an
ndarray
, but behaves differently when subsetting with astr
.
Examples
# let's create a regular numpy ndarray:
>>> a = idlwrap.indgen(4, 5)
>>> a[2:3, 1:2]
array([[9]])
# transform b:
>>> b = idlwrap.subsetify_(a)
# b behaves like a regular numpy ndarray:
>>> b[2:3, 1:2]
array([[9]])
>>> b.mean()
9.5
# but when subsetting with a ``str``, it behaves like IDL's subset:
>>> b["2:3, 1:2"]
array([[ 6, 7],
[10, 11]])
>>> b["*"]
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
# it also works for setting elements:
>>> b["1:2,1:3"] = 0
>>> b
array([[ 0, 1, 2, 3],
[ 4, 0, 0, 7],
[ 8, 0, 0, 11],
[12, 0, 0, 15],
[16, 17, 18, 19]])
subset_(arr, subset, debug=False)
Get a subset of an array.
Parameters
- arr : ndarray
- The input array.
- subset : str
- Subset as it would have been passed to IDL, as string. See examples.
Returns
- res : ndarray
Notes
In IDL, subset ranges are inclusive: [1:3]
returns 3 elements, while it would only return 2
elements in python.
idlwrap.subsetify_
provides an alternative interface to the same functionality.
Examples
>>> a = idlwrap.indgen(4, 4)
>>> idlwrap.subset_(a, "*")
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
>>> idlwrap.subset_(a, "[14]")
14
>>> idlwrap.subset_(a, "[1:2]")
array([1, 2])
>>> idlwrap.subset_(a, "[1:2,2:3]")
array([[ 9, 10],
[13, 14]])
These are not yet implemented:
# idlwrap.subset_(a, "[-1]") # negative subset
# idlwrap.subset_(a, "[1.5]") # float-type subset
set_subset_(arr, subset, what)
Assign an array subset to a value. The arr
is modified in place. An alternative interface to
the same functionalities is provided by the idlwrap.subsetify_
function.
Parameters
- arr : ndarray
- The array to use.
- subset : str
- A string with the subset notation, as you would use it in IDL, e.g.
"[1:4,*]"
. You can also omit the brackets[]
. - what : ndarray, numeric
- The value(s) to assign to the selected subset.
Returns
- None
Examples
a = idlwrap.indgen(10, 10)
idlwrap.set_subset(a, "[1:4]", 0)
idlwrap.set_subset(a, "*", 0)
idlwrap.set_subset(a, "2:5,2:5", 0)
# the following are valid IDL, but are not yet implemented in idlwrap:
# idlwrap.set_subset(a, "[1.5]", 0) # float-type subset
# idlwrap.set_subset(a, "-1", 0) # negative subset
matrix_multiply_(a, b, atranspose=False, btranspose=False)
H(a, b)
matrix multiplication ("hash"), corresponds to IDL A # B
Parameters
- a : np.ndarray
- supported shapes: (n,) or (n,m)
- b : np.ndarray
- supported shapes: (n,) or (n,m)
Returns
- mat : ndarray
- Multiplication of the arrays, as defined by the IDL documentation.
Notes
porting to python
Quite complicated, as the numpy function depends on the dimensions of the inputs. Look at the source code.
HH(a, b)
matrix multiplication, corresponds to IDL A ## B
Parameters
- a : np.ndarray
- supported shapes: (n,) or (n,m)
- b : np.ndarray
- supported shapes: (n,) or (n,m)
Returns
- mat : ndarray
- Multiplication of the arrays, as defined by the IDL documentation.
Notes
porting to python
Quite complicated, as the numpy function depends on the dimensions of the inputs. Look at the source code.
LE(a, b)
less-than-or-equal-to relational operator, corresponds to IDL a LE b
GE(a, b)
greater-than-or-equal-to relational operator, corresponds to IDL a GE b
LT(a, b)
less-than relational operator, corresponds to IDL a LT b
GT(a, b)
greater-than relational operator, corresponds to IDL a GT b
EQ(a, b)
equals-to relational operator, corresponds to IDL a EQ b
NE(a, b)
not-equal-to relational operator, corresponds to IDL a NE b
operator_(a, operator, b)
Special IDL operations.
Parameters
- a : numeric or ndarray
- operator : str
Operation. The following IDL operations are supported:
- minimum and maximum operators:
'
: minimum operator'>'
: maximum operator
- relational operators:
'EQ'
: equal to'NE'
: not equal to'GE'
: greater than or equal to'GT'
: greater than'LE'
: less than or equal to'LT'
: less than
- matrix operators:
'#'
: multiplies columns ofa
with rows ofb
.b
must have the same number of columns asa
has rows. The resulting array has the same number of columns asa
and the same number of rows asb
.'##'
: multiplies rows ofa
with columns ofb
.b
must have the same number of rows asa
has columns. The resulting array has the same number of rows asa
and the same number of columns asb
.
Returns
- res : numeric / ndarray
Notes
In idlwrap, the relational operators (EQ
, NE
, GE
, GT
, LE
, LE
) are also
available as functions: EQ(a, b)
, ...
Porting to python
- the relational operators can be replaced with its python equivalent
- the minimum and maximum operators
<
and>
can be replaced withnp.minimum(a,b)
andnp.maximum(a,b)
, respectivelya < b
- the matrix operators are more complex. Please refer to the documentation of
H
andHH
Examples
A < B -> operator_(a, "<", b)
-> np.minimum(a, b)
A LE B -> operator_(a, "LE", b)
-> LE(a, b)
-> a <= b
A # B -> operator_(a, "#", b)
-> H(a, b)
A ## B -> operator_(a, "##", b)
-> HH(a, b)