Provide a slice tuple equivalent to a coordinate constraint
✨ Feature Request
Functionality to generate a slice tuple that can be used to subset a cube with a given constraint. This could be a standalone function, or a method on iris.Constraint. Usage might look like this:
height_constraint = iris.Constraint(height=9000)
slices_tuple = height_constraint.as_slices_tuple(cube)
subset_cube = cube[slices_tuple]
# Equivalent to:
subset_cube = height_contstraint.extract(cube)
Motivation
This would allow for assigning data to a subset of a cube directly, rather than operating on a copy of the cube region. For example, setting all points at height=9000 to zero:
cube[slices_tuple] = 0
Additional context
Click to expand this section...
It looks like _ColumnIndexManager.as_slice already provides this functionality, but it is not part of the public API.
This is an interesting idea. In principle, shouldn't be too hard as the implementation of constraints does effectively convert everything into a binary yes/no array over the points of the relevant dimension. So, converting that to a slice object would seem entirely possible.
A couple of queries come to mind...
Firstly, there are also cases where the result is not equivalent to a simple slice.
I'd suggest that the API should offer to either treat that as an unexpected error, or return an array of booleans or list of indices which would also work.
Maybe something like this ? ... #6621
Interestingly, the capability is already "almost" there, but not public I think.
Interestingly, the capability is already "almost" there, but not public I think.
I think that's the point @jrackham-mo is making in the additional context part of the original comment? i.e. that there is existing private functionality in iris that may provide the functionality. As downstream users, we're reluctant to rely on private functionality though.
Note that Iris slicing in general returns copies rather than views, so you can't assign to a slice
import iris.cube
cube = iris.cube.Cube(range(5))
print(cube.data)
cube[1].data = 42
print(cube.data)
[0 1 2 3 4]
[0 1 2 3 4]
Though I think this would be OK if you use your returned slice like
cube.data[slices_tuple] = 0