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

Attachment: 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

Reply via email to