On Fri, 2021-02-12 at 11:13 +0100, Ralf Gommers wrote: > On Fri, Feb 12, 2021 at 3:32 AM Juan Nunez-Iglesias > <j...@fastmail.com> > wrote: > > > both napari and scikit-image use atleast_ a few times. I don’t have > > many > > examples of where I used nd because it didn’t exist. But I have the > > very > > distinct impression of needing it repeatedly. In some places, I’ve > > used > > `np.broadcast_to` to signal the same intention, where `atleast_nd` > > would > > have been the more readable solution. > > > > I don’t buy the argument that it’s just a way to mask errors. NumPy > > broadcasting also has that same potential but I hope no one would > > seriously > > consider deprecating it. Indeed, even if we accept that we (library > > authors) should force users to provide an array of the right > > dimensionality, that still argues for making it convenient for > > users to do > > that! > > > > I don’t feel super strongly about this. But I think atleast_nd is a > > move > > in a positive direction and I’d prefer it to what’s there now: > > > > In [1]: import numpy as np > > In [2]: np.atleast_3d(np.ones(4)).shape > > Out[2]: (1, 4, 1) > > > > There might be some linear algebraic reason why those axis > > positions make > > sense, but I’m not aware of it... > > > > Yes that's pretty weird. I'm also not sure there's a reason. > > It would be good that, if atleast_nd is not going to replicate this > behavior, atleast_3d was deprecated (perhaps a release or two after > introduction of atleast_nd). >
Planning to replace `atleast_3d` (not right now but soon), sounds like a good way forward. "1, 2, nd" is pretty good. `atleast_3d` seems not used all that much and is an odd one out. Having the `nd` version should make a future deprecation painless, so long term we will be better off. - Sebastian > Not having `atleast_3d(x) == atleast_nd(x, pos=3)` is unnecessarily > confusing. > > Ralf > > > > Juan. > > > > On 12 Feb 2021, at 5:32 am, Eric Wieser < > > wieser.eric+nu...@gmail.com> > > wrote: > > > > I did a quick search of matplotlib, and found a few uses of all > > three > > functions: > > > > * > > https://github.com/matplotlib/matplotlib/blob/fed55c63a314351cd39a12783f385009782c06e1/lib/matplotlib/_layoutgrid.py#L441-L446 > > This one isn't really numpy at all, and is really just a > > shorthand for > > normalizing an argument `x=n` to `x=[n, n]` > > * > > https://github.com/matplotlib/matplotlib/blob/dd249744270f6abe3f540f81b7a77c0cb728ddbb/lib/matplotlib/mlab.py#L888 > > This one is the classic "either multivariate or single-variable > > data" > > thing endemic to the SciPy ecosystem. > > * > > https://github.com/matplotlib/matplotlib/blob/1eef019109b64ee4085732544cb5e310e69451ab/lib/matplotlib/cbook/__init__.py#L1325-L1326 > > Matplotlib has their own `_check_1d` function for input > > sanitization, > > although github says it's only used to parse the arguments to > > `plot`, which > > at this point are fairly established as being flexible. > > * > > https://github.com/matplotlib/matplotlib/blob/f72adc49092fe0233a8cd21aa0f317918dafb18d/lib/matplotlib/transforms.py#L631 > > This just looks like "defensive programming", and if the argument > > isn't > > already 3d then something is probably wrong. > > > > This isn't an exhaustive list, just a handful of different > > situations the > > functions were used. > > > > Eric > > > > > > > > On Thu, 11 Feb 2021 at 18:15, Stephan Hoyer <sho...@gmail.com> > > wrote: > > > > > On Thu, Feb 11, 2021 at 9:42 AM Benjamin Root < > > > ben.v.r...@gmail.com> > > > wrote: > > > > > > > for me, I find that the at_least{1,2,3}d functions are useful > > > > for > > > > sanitizing inputs. Having an at_leastnd() function can be > > > > viewed as a step > > > > towards cleaning up the API, not cluttering it (although, > > > > deprecations of > > > > the existing functions probably should be long given how long > > > > they have > > > > existed). > > > > > > > > > > I would love to see examples of this -- perhaps in matplotlib? > > > > > > My thinking is that in most cases it's probably a better idea to > > > keep the > > > interface simpler, and raise an error for lower-dimensional > > > arrays. > > > Automatic conversion is convenient (and endemic within the SciPy > > > ecosystem), but is also a common source of bugs. > > > > > > On Thu, Feb 11, 2021 at 1:56 AM Stephan Hoyer <sho...@gmail.com> > > > wrote: > > > > > > > > > On Wed, Feb 10, 2021 at 9:48 PM Juan Nunez-Iglesias < > > > > > j...@fastmail.com> > > > > > wrote: > > > > > > > > > > > I totally agree with the namespace clutter concern, but > > > > > > honestly, I > > > > > > would use `atleast_nd` with its `pos` argument (I might > > > > > > rename it to > > > > > > `position`, `axis`, or `axis_position`) any day over > > > > > > `at_least{1,2,3}d`, > > > > > > for which I had no idea where the new axes would end up. > > > > > > > > > > > > So, I’m in favour of including it, and optionally > > > > > > deprecating > > > > > > `atleast_{1,2,3}d`. > > > > > > > > > > > > > > > > > I appreciate that `atleast_nd` feels more sensible than > > > > > `at_least{1,2,3}d`, but I don't think "better" than a pattern > > > > > we would not > > > > > recommend is a good enough reason for inclusion in NumPy. It > > > > > needs to stand > > > > > on its own. > > > > > > > > > > What would be the recommended use-cases for this new > > > > > function? > > > > > Have any libraries building on top of NumPy implemented a > > > > > version of > > > > > this? > > > > > > > > > > > > > > > > Juan. > > > > > > > > > > > > On 11 Feb 2021, at 9:48 am, Sebastian Berg < > > > > > > sebast...@sipsolutions.net> > > > > > > wrote: > > > > > > > > > > > > On Wed, 2021-02-10 at 17:31 -0500, Joseph Fox-Rabinovitz > > > > > > wrote: > > > > > > > > > > > > I've created PR#18386 to add a function called atleast_nd > > > > > > to numpy and > > > > > > numpy.ma. This would generalize the existing atleast_1d, > > > > > > atleast_2d, > > > > > > and > > > > > > atleast_3d functions. > > > > > > > > > > > > I proposed a similar idea about four and a half years ago: > > > > > > > > > > > > https://mail.python.org/pipermail/numpy-discussion/2016-July/075722.html > > > > > > , > > > > > > PR#7804. The reception was ambivalent, but a couple of > > > > > > folks have > > > > > > asked me > > > > > > about this, so I'm bringing it back. > > > > > > > > > > > > Some pros: > > > > > > > > > > > > - This closes issue #12336 > > > > > > - There are a couple of Stack Overflow questions that would > > > > > > benefit > > > > > > - Been asked about this a couple of times > > > > > > - Implementation of three existing atleast_*d functions > > > > > > gets easier > > > > > > - Looks nicer that the equivalent broadcasting and > > > > > > reshaping > > > > > > > > > > > > Some cons: > > > > > > > > > > > > - Cluttering up the API > > > > > > - Maintenance burden (but not a big one) > > > > > > - This is just a utility function, which can be achieved > > > > > > through > > > > > > broadcasting and reshaping > > > > > > > > > > > > > > > > > > My main concern would be the namespace cluttering. I can't > > > > > > say I use > > > > > > even the `atleast_2d` etc. functions personally, so I would > > > > > > tend to be > > > > > > slightly against the addition. But if others land on the > > > > > > "useful" side here > > > > > > (and it seemed a bit at least on github), I am also not > > > > > > opposed. It is a > > > > > > clean name that lines up with existing ones, so it doesn't > > > > > > seem like a big > > > > > > "mental load" with respect to namespace cluttering. > > > > > > > > > > > > Bike shedding the API is probably a good idea in any case. > > > > > > > > > > > > I have pasted the current PR documentation (as html) below > > > > > > for quick > > > > > > reference. I wonder a bit about the reasoning for having > > > > > > `pos` specify a > > > > > > value rather than just a side? > > > > > > > > > > > > > > > > > > > > > > > > numpy.atleast_nd(*ary*, *ndim*, *pos=0*) > > > > > > View input as array with at least ndim dimensions. > > > > > > New unit dimensions are inserted at the index given by > > > > > > *pos* if > > > > > > necessary. > > > > > > Parameters*ary *array_like > > > > > > The input array. Non-array inputs are converted to arrays. > > > > > > Arrays that > > > > > > already have ndim or more dimensions are preserved. > > > > > > *ndim *int > > > > > > The minimum number of dimensions required. > > > > > > *pos *int, optional > > > > > > The index to insert the new dimensions. May range from - > > > > > > ary.ndim - 1 > > > > > > to +ary.ndim (inclusive). Non-negative indices indicate > > > > > > locations > > > > > > before the corresponding axis: pos=0 means to insert at the > > > > > > very > > > > > > beginning. Negative indices indicate locations after the > > > > > > corresponding axis: > > > > > > pos=-1 means to insert at the very end. 0 and -1 are > > > > > > always > > > > > > guaranteed to work. Any other number will depend on the > > > > > > dimensions of the > > > > > > existing array. Default is 0. > > > > > > Returns*res *ndarray > > > > > > An array with res.ndim >= ndim. A view is returned for > > > > > > array inputs. > > > > > > Dimensions are prepended if *pos* is 0, so for example, a > > > > > > 1-D array > > > > > > of shape (N,) with ndim=4becomes a view of shape (1, 1, 1, > > > > > > N). > > > > > > Dimensions are appended if *pos* is -1, so for example a 2- > > > > > > D array of > > > > > > shape (M, N) becomes a view of shape (M, N, 1, 1)when > > > > > > ndim=4. > > > > > > *See also* > > > > > > atleast_1d > > > > > > < > > > > > > https://18298-908607-gh.circle-artifacts.com/0/doc/build/html/reference/generated/numpy.atleast_1d.html#numpy.atleast_1d > > > > > > > > > > > > > , atleast_2d > > > > > > < > > > > > > https://18298-908607-gh.circle-artifacts.com/0/doc/build/html/reference/generated/numpy.atleast_2d.html#numpy.atleast_2d > > > > > > > > > > > > > , atleast_3d > > > > > > < > > > > > > https://18298-908607-gh.circle-artifacts.com/0/doc/build/html/reference/generated/numpy.atleast_3d.html#numpy.atleast_3d > > > > > > > > > > > > > *Notes* > > > > > > This function does not follow the convention of the other > > > > > > atleast_*d functions > > > > > > in numpy in that it only accepts a single array argument. > > > > > > To process > > > > > > multiple arrays, use a comprehension or loop around the > > > > > > function call. See > > > > > > examples below. > > > > > > Setting pos=0 is equivalent to how the array would be > > > > > > interpreted by > > > > > > numpy’s broadcasting rules. There is no need to call this > > > > > > function for > > > > > > simple broadcasting. This is also roughly (but not exactly) > > > > > > equivalent to > > > > > > np.array(ary, copy=False, subok=True, ndmin=ndim). > > > > > > It is easy to create functions for specific dimensions > > > > > > similar to the > > > > > > other atleast_*d functions using Python’s functools.partial > > > > > > < > > > > > > https://docs.python.org/dev/library/functools.html#functools.partial > > > > > > > > > > > > > function. An example is shown below. > > > > > > *Examples* > > > > > > > > > > > > > > > np.atleast_nd(3.0, 4)array([[[[ 3.]]]]) > > > > > > > > > > > > > > > x = np.arange(3.0)>>> np.atleast_nd(x, 2).shape(1, 3) > > > > > > > > > > > > > > > x = np.arange(12.0).reshape(4, 3)>>> np.atleast_nd(x, > > > > > > > > > 5).shape(1, 1, 1, 4, 3)>>> np.atleast_nd(x, 5).base > > > > > > > > > is x.baseTrue > > > > > > > > > > > > > > > [np.atleast_nd(x) for x in ((1, 2), [[1, 2]], [[[1, > > > > > > > > > 2]]])]:[array([[1, 2]]), array([[1, 2]]), array([[[1, > > > > > > > > > 2]]])] > > > > > > > > > > > > > > > np.atleast_nd((1, 2), 5, pos=0).shape(1, 1, 1, 1, > > > > > > > > > 2)>>> np.atleast_nd((1, 2), 5, pos=-1).shape(2, 1, 1, > > > > > > > > > 1, 1) > > > > > > > > > > > > > > > from functools import partial>>> atleast_4d = > > > > > > > > > partial(np.atleast_nd, ndim=4)>>> atleast_4d([1, 2, > > > > > > > > > 3])[[[[1, 2, 3]]]] > > > > > > > > > > > > > > > > > > _______________________________________________ > > > > > > NumPy-Discussion mailing list > > > > > > NumPy-Discussion@python.org > > > > > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > > > > > > > > > > > > > > > > _______________________________________________ > > > > > > NumPy-Discussion mailing list > > > > > > NumPy-Discussion@python.org > > > > > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > > > > > > > > > _______________________________________________ > > > > > NumPy-Discussion mailing list > > > > > NumPy-Discussion@python.org > > > > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > > > > > > > _______________________________________________ > > > > NumPy-Discussion mailing list > > > > NumPy-Discussion@python.org > > > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > > > > > _______________________________________________ > > > NumPy-Discussion mailing list > > > NumPy-Discussion@python.org > > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > > > _______________________________________________ > > NumPy-Discussion mailing list > > NumPy-Discussion@python.org > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > > > > _______________________________________________ > > NumPy-Discussion mailing list > > NumPy-Discussion@python.org > > https://mail.python.org/mailman/listinfo/numpy-discussion > > > _______________________________________________ > NumPy-Discussion mailing list > NumPy-Discussion@python.org > https://mail.python.org/mailman/listinfo/numpy-discussion
signature.asc
Description: This is a digitally signed message part
_______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@python.org https://mail.python.org/mailman/listinfo/numpy-discussion