Skip to content

Conversation

@bjlittle
Copy link
Member

This PR addresses #3419.

@bjlittle
Copy link
Member Author

Happy to add more tests as a review action...

# NB. Returns the *same object* if result.ndim >= ndmin
result = np.array(result, ndmin=ndmin, copy=False)
func = ma.array if ma.isMaskedArray(result) else np.array
result = func(result, ndmin=ndmin, copy=False)
Copy link
Member Author

@bjlittle bjlittle Sep 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @rcomer points out, this is indeed the nub of the issue 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bit will applies to AuxCoords rather than DimCoords, which was the point of the original issue.
I'll try and remember to edit the squashed commit for that.

raise ValueError(emsg.format(self.name(), self.__class__.__name__))
if ma.isMaskedArray(points) and ma.count_masked(points):
emsg = 'A {!r} {} points array must not be masked.'
raise TypeError(emsg.format(self.name(), self.__class__.__name__))
Copy link
Member Author

@bjlittle bjlittle Sep 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raise a TypeError exceptions here to explicitly catch those masked points. Hence the need for the change here.

[ nan 494.44452 588.8889 683.33325 777.77783 872.2222
966.66675 1061.1111 1155.5554 nan]
[-- 494.44451904296875 588.888916015625 683.333251953125 777.77783203125
872.2222290039062 966.666748046875 1061.111083984375 1155.555419921875 --]
Copy link
Member Author

@bjlittle bjlittle Sep 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really makes sense to me now for coordinate behaviour...

We've asked for an extrapolation_mode=mask, so now we get a masked array for the altitude derived coordinate for the extrapolated points, and not just an array with nans injected.

If the extrapolation_mode=nan, then we (quite rightly) instead get:

[       nan  494.44452  588.8889   683.33325  777.77783  872.2222
  966.66675 1061.1111  1155.5554         nan]

@pp-mo pp-mo self-assigned this Sep 30, 2019
@pp-mo pp-mo self-requested a review September 30, 2019 14:49
@bjlittle
Copy link
Member Author

bjlittle commented Sep 30, 2019

@pp-mo Yup, I definitely want to add some extra test coverage here. I think that our masked array test coverage (in gerneral) is pretty poor (at least an after thought).

I just want to convince myself that I've not broken anything here for DimCoords and AuxCoords... as it's pretty fundamental to the core of iris 😟

raise ValueError('The points array must be numeric.')
emsg = 'The {!r} {} points array must be numeric.'
raise ValueError(emsg.format(self.name(), self.__class__.__name__))
if ma.isMaskedArray(points) and ma.count_masked(points):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

@bjlittle bjlittle Oct 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, thanks @pp-mo ... I always forget that pattern, and it gives us the same behaviour that we want, namely:

>>> import numpy as np
>>> import numpy.ma as ma
>>> a = np.arange(5)
>>> b = ma.arange(5)
>>> c = ma.arange(5)   
>>> c[0] = ma.masked
>>> ma.is_masked(a)
False
>>> ma.is_masked(b)
False
>>> ma.is_masked(c)
True

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pp-mo Done 👍

emsg = 'The {!r} {} bounds array must be numeric.'
raise ValueError(emsg.format(self.name(), self.__class__.__name__))
# Check not masked.
if ma.isMaskedArray(bounds) and ma.count_masked(bounds):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, use 'is_masked'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pp-mo Done 👍

@rcomer
Copy link
Member

rcomer commented Sep 30, 2019

One thought that springs to mind: do methods such as cube.extract and cube.aggregated_by behave sensibly if presented with masked points?

Copy link
Member

@pp-mo pp-mo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All makes good sense, but clearly we have no testing for these behaviours : e.g.

  • errors for bad creation / assignment
  • successful AuxCoord creation with masked data
  • error making DimCoord with masked points
  • success making DimCoord from masked array with no masked points.

Maybe we should address these, just as regression checks ?

# NB. Returns the *same object* if result.ndim >= ndmin
result = np.array(result, ndmin=ndmin, copy=False)
func = ma.array if ma.isMaskedArray(result) else np.array
result = func(result, ndmin=ndmin, copy=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bit will applies to AuxCoords rather than DimCoords, which was the point of the original issue.
I'll try and remember to edit the squashed commit for that.

@pp-mo
Copy link
Member

pp-mo commented Sep 30, 2019

One thought that springs to mind: do methods such as cube.extract and cube.aggregated_by behave sensibly if presented with masked points?

I think we have considered masking in most operations now, but it is not all tested.
Specifically, extract should be fine, aggregation does work (I just checked), but it is not tested.


from __future__ import (absolute_import, division, print_function)
from six.moves import (filter, input, map, range, zip) # noqa
import six

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F401 'six' imported but unused

@bjlittle bjlittle force-pushed the fix-sanitise-array branch from 3ea2f1f to 91ceae9 Compare October 1, 2019 09:50
@bjlittle
Copy link
Member Author

bjlittle commented Oct 1, 2019

All makes good sense, but clearly we have no testing for these behaviours : e.g.

* errors for bad creation / assignment

* successful AuxCoord creation with masked data

* error making DimCoord with masked points

* success making DimCoord from masked array with no masked points.

Maybe we should address these, just as regression checks ?

@pp-mo After pushing commits 9f9a553 and 91ceae9, I'm pretty satified that we've got reasonable test coverage for both DimCoords and AuxCoords given the areas you highlighted. But this is just for coordinate creation.

Did we want to extend this further?

Pragmatically, perhaps we create an issue with areas of the code base that require masking test coverage outside this PR? Kinda feels like slow, long burner...

@bjlittle
Copy link
Member Author

bjlittle commented Oct 1, 2019

This need a whatsnew entry...

Copy link
Member

@pp-mo pp-mo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some silly little points, but generally all GTG, OWOK, LGTM ...

@bjlittle
Copy link
Member Author

bjlittle commented Oct 2, 2019

@pp-mo Over to you 👍

@pp-mo pp-mo merged commit 3a6a2b9 into SciTools:master Oct 2, 2019
@pp-mo
Copy link
Member

pp-mo commented Oct 2, 2019

Nice @bjlittle
👍 for minimal fuss over this one !

@rcomer rcomer mentioned this pull request Oct 2, 2019
bjlittle added a commit to bjlittle/iris that referenced this pull request Oct 16, 2019
@bjlittle bjlittle deleted the fix-sanitise-array branch October 29, 2019 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants