Skip to content

Commit 02aca3e

Browse files
committed
fix #234 : implemented support for np.__array_ufunc__
- renamed npufuncs.py as npfuncs.py
1 parent 300ae4f commit 02aca3e

File tree

9 files changed

+419
-321
lines changed

9 files changed

+419
-321
lines changed

doc/source/changes/version_0_30.rst.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ Miscellaneous improvements
223223

224224
* implemented :py:obj:`LArray.reverse()` method to reverse one or several axes of an array (closes :issue:`631`).
225225

226+
* made it possible to pass LArray objects to Numpy ufuncs directly (e.g. np.sqrt(ndtest(3)), closes :issue:`234`).
227+
226228

227229
Fixes
228230
-----

larray/__init__.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@
1212
from larray.core.session import Session, local_arrays, global_arrays, arrays
1313
from larray.core.constants import nan, inf, pi, e, euler_gamma
1414
from larray.core.metadata import Metadata
15-
from larray.core.ufuncs import maximum, minimum, where
16-
from larray.core.npufuncs import (sin, cos, tan, arcsin, arccos, arctan, hypot, arctan2, degrees,
17-
radians, unwrap, sinh, cosh, tanh, arcsinh, arccosh, arctanh,
18-
angle, real, imag, conj,
19-
round, around, round_, rint, fix, floor, ceil, trunc,
20-
exp, expm1, exp2, log, log10, log2, log1p, logaddexp, logaddexp2,
21-
i0, sinc, signbit, copysign, frexp, ldexp,
22-
convolve, clip, sqrt, absolute, fabs, sign, fmax, fmin, nan_to_num,
23-
real_if_close, interp, isnan, isinf, inverse)
15+
from larray.core.npfuncs import (where, clip, degrees, radians, unwrap, angle, real, imag,
16+
round, around, round_, fix, i0, sinc, convolve, nan_to_num,
17+
real_if_close, inverse, interp, )
18+
from larray.core.ufuncs import (sin, cos, tan, arcsin, arccos, arctan, hypot, arctan2, sinh, cosh,
19+
tanh, arcsinh, arccosh, arctanh, conj, rint, floor, ceil, trunc,
20+
exp, expm1, exp2, log, log10, log2, log1p, logaddexp, logaddexp2,
21+
signbit, copysign, frexp, ldexp, sqrt, absolute, fabs, sign,
22+
fmax, fmin, isnan, isinf, maximum, minimum)
2423

2524
from larray.inout.misc import from_lists, from_string
2625
from larray.inout.pandas import from_frame, from_series
@@ -56,15 +55,17 @@
5655
# metadata
5756
'Metadata',
5857
# ufuncs
59-
'maximum', 'minimum', 'where',
58+
'maximum', 'minimum',
6059
'sin', 'cos', 'tan', 'arcsin', 'arccos', 'arctan', 'hypot', 'arctan2', 'degrees', 'radians',
6160
'unwrap', 'sinh', 'cosh', 'tanh', 'arcsinh', 'arccosh', 'arctanh',
6261
'angle', 'real', 'imag', 'conj',
6362
'round', 'around', 'round_', 'rint', 'fix', 'floor', 'ceil', 'trunc',
6463
'exp', 'expm1', 'exp2', 'log', 'log10', 'log2', 'log1p', 'logaddexp', 'logaddexp2',
6564
'i0', 'sinc', 'signbit', 'copysign', 'frexp', 'ldexp',
66-
'convolve', 'clip', 'sqrt', 'absolute', 'fabs', 'sign', 'fmax', 'fmin', 'nan_to_num',
65+
'convolve', 'sqrt', 'absolute', 'fabs', 'sign', 'fmax', 'fmin', 'nan_to_num',
6766
'real_if_close', 'interp', 'isnan', 'isinf', 'inverse',
67+
# npfuncs
68+
'where', 'clip',
6869
# inout
6970
'from_lists', 'from_string', 'from_frame', 'from_series', 'read_csv', 'read_tsv',
7071
'read_eurostat', 'read_excel', 'read_hdf', 'read_sas', 'open_excel', 'Workbook',

larray/core/array.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
from larray.core.constants import nan
6060
from larray.core.metadata import Metadata
6161
from larray.core.expr import ExprNode
62+
from larray.core.ufuncs import SupportsNumpyUfuncs
6263
from larray.core.group import (Group, IGroup, LGroup, remove_nested_groups, _to_key, _to_keys,
6364
_translate_sheet_name, _translate_group_key_hdf)
6465
from larray.core.axis import Axis, AxisReference, AxisCollection, X, _make_axis
@@ -560,7 +561,7 @@ def _handle_deprecated_argument_title(meta, title):
560561
return meta
561562

562563

563-
class LArray(ABCLArray):
564+
class LArray(ABCLArray, SupportsNumpyUfuncs):
564565
"""
565566
A LArray object represents a multidimensional, homogeneous array of fixed-size items with labeled axes.
566567
@@ -5326,7 +5327,7 @@ def eq(self, other, rtol=0, atol=0, nans_equal=False):
53265327
if not nans_equal:
53275328
return self == other
53285329
else:
5329-
from larray.core.npufuncs import isnan
5330+
from larray.core.ufuncs import isnan
53305331

53315332
def general_isnan(a):
53325333
if np.issubclass_(a.dtype.type, np.inexact):
@@ -6076,7 +6077,7 @@ def clip(self, minval=None, maxval=None, out=None):
60766077
a1 0 1 2
60776078
a2 2 2 2
60786079
"""
6079-
from larray.core.npufuncs import clip
6080+
from larray.core.npfuncs import clip
60806081
return clip(self, minval, maxval, out)
60816082

60826083
@deprecate_kwarg('transpose', 'wide')

larray/core/npfuncs.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# numpy ufuncs -- this module is excluded from pytest
2+
# http://docs.scipy.org/doc/numpy/reference/routines.math.html
3+
4+
import numpy as np
5+
6+
from larray.core.ufuncs import _broadcastify, _copy_npfunc_doc
7+
8+
9+
def broadcastify(npfunc, copy_doc=True):
10+
# intentionally not using functools.wraps, because it does not work for wrapping a function from another module
11+
def wrapper(*args, **kwargs):
12+
return _broadcastify(npfunc, *args, **kwargs)
13+
if copy_doc:
14+
_copy_npfunc_doc(wrapper, npfunc)
15+
return wrapper
16+
17+
# Trigonometric functions
18+
19+
degrees = broadcastify(np.degrees)
20+
radians = broadcastify(np.radians)
21+
unwrap = broadcastify(np.unwrap)
22+
23+
# Handling complex numbers
24+
25+
angle = broadcastify(np.angle)
26+
real = broadcastify(np.real)
27+
imag = broadcastify(np.imag)
28+
29+
# Rounding
30+
31+
# all 3 are equivalent, I am unsure I should support around and round_
32+
round = broadcastify(np.round)
33+
around = broadcastify(np.around)
34+
round_ = broadcastify(np.round_)
35+
fix = broadcastify(np.fix)
36+
37+
# Sums, products, differences
38+
39+
# prod = broadcastify(np.prod)
40+
# sum = broadcastify(np.sum)
41+
# nansum = broadcastify(np.nansum)
42+
# cumprod = broadcastify(np.cumprod)
43+
# cumsum = broadcastify(np.cumsum)
44+
45+
# cannot use a simple wrapped ufunc because those ufuncs do not preserve
46+
# shape or dimensions so labels are wrong
47+
# diff = broadcastify(np.diff)
48+
# ediff1d = broadcastify(np.ediff1d)
49+
# gradient = broadcastify(np.gradient)
50+
# cross = broadcastify(np.cross)
51+
# trapz = broadcastify(np.trapz)
52+
53+
54+
# Other special functions
55+
56+
i0 = broadcastify(np.i0)
57+
sinc = broadcastify(np.sinc)
58+
59+
# Miscellaneous
60+
61+
where = broadcastify(np.where, copy_doc=False)
62+
where.__doc__ = r"""
63+
Return elements, either from `x` or `y`, depending on `condition`.
64+
65+
If only `condition` is given, return ``condition.nonzero()``.
66+
67+
Parameters
68+
----------
69+
condition : boolean LArray
70+
When True, yield `x`, otherwise yield `y`.
71+
x, y : LArray
72+
Values from which to choose.
73+
74+
Returns
75+
-------
76+
out : LArray
77+
If both `x` and `y` are specified, the output array contains
78+
elements of `x` where `condition` is True, and elements from
79+
`y` elsewhere.
80+
81+
Examples
82+
--------
83+
>>> from larray import LArray
84+
>>> arr = LArray([[10, 7, 5, 9],
85+
... [5, 8, 3, 7],
86+
... [6, 2, 0, 9],
87+
... [9, 10, 5, 6]], "a=a0..a3;b=b0..b3")
88+
>>> arr
89+
a\b b0 b1 b2 b3
90+
a0 10 7 5 9
91+
a1 5 8 3 7
92+
a2 6 2 0 9
93+
a3 9 10 5 6
94+
95+
Simple use
96+
97+
>>> where_(arr <= 5, 0, arr)
98+
a\b b0 b1 b2 b3
99+
a0 10 7 0 9
100+
a1 0 8 0 7
101+
a2 6 0 0 9
102+
a3 9 10 0 6
103+
104+
With broadcasting
105+
106+
>>> mean_by_col = arr.mean('a')
107+
>>> mean_by_col
108+
b b0 b1 b2 b3
109+
7.5 6.75 3.25 7.75
110+
>>> # for each column, set values below the mean value to the mean value
111+
>>> where_(arr < mean_by_col, mean_by_col, arr)
112+
a\b b0 b1 b2 b3
113+
a0 10.0 7.0 5.0 9.0
114+
a1 7.5 8.0 3.25 7.75
115+
a2 7.5 6.75 3.25 9.0
116+
a3 9.0 10.0 5.0 7.75
117+
"""
118+
119+
clip = broadcastify(np.clip)
120+
convolve = broadcastify(np.convolve)
121+
nan_to_num = broadcastify(np.nan_to_num)
122+
real_if_close = broadcastify(np.real_if_close)
123+
inverse = broadcastify(np.linalg.inv)
124+
125+
# XXX: create a new LArray method instead ?
126+
# TODO: should appear in the API doc if it actually works with LArrays,
127+
# which I have never tested (and I doubt is the case).
128+
# Might be worth having specific documentation if it works well.
129+
# My guess is that we should rather make a new LArray method for that one.
130+
interp = broadcastify(np.interp)

larray/core/npufuncs.py

Lines changed: 0 additions & 135 deletions
This file was deleted.

0 commit comments

Comments
 (0)