-
-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding a new explode_along_axis function inside NDCube #118
Adding a new explode_along_axis function inside NDCube #118
Conversation
Hello @BaptistePellorceAstro! Thanks for updating the PR.
Comment last updated on May 18, 2018 at 15:08 Hours UTC |
ndcube/ndcube.py
Outdated
def explode_along_axis(self, axis): | ||
""" | ||
Separates slices of NDCubes in sequence along a given cube axis into a NDCubeSequence | ||
of (N-1)DCubes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring should reflect that this is an NDCube
method, not an NDCubeSequence
. So replace with something like:
Separates slices of the NDCube along a given cube axis into a NDCubeSequence of (N-1)DCubes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, of course !
ndcube/ndcube.py
Outdated
meta=self.meta, mask=self[i].mask, missing_axis=[False, False, True], | ||
extra_coords=extra_coords_formated) | ||
result_cubes.append(cube) | ||
return NDCubeSequence(result_cubes, meta=self.meta) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this method could be rewritten with the following:
result_cubes = []
cube_slices = [slice(None, None, None)] * len(self.data.ndim)
for i in range(self.data.shape[axis]):
cube_slices[axis] = i
result_cubes.append(self[cube_slices])
return NDCubeSequence(result_cubes, common_axis=axis)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You make me understand these lines just now ! Of course, this is the best way.
Thanks so much for this PR @BaptistePellorceAstro. I've left a couple comments. As well as those, this method should be in |
ndcube/ndcube.py
Outdated
@@ -542,34 +539,24 @@ def explode_along_axis(self, axis): | |||
result : `ndcube_sequence.NDCubeSequence` | |||
|
|||
""" | |||
# If axis is -ve then calculate the axis from the length of the dimensions of one cube | |||
# is axis is -ve then calculate the axis from the length of the dimensions of one cube |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: Should be If.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified it but I copy the previous line ... a little mistake.
ndcube/ndcube.py
Outdated
# Setting the slice value to the index so that the slices are done correctly. | ||
cube_slices[axis] = i | ||
# Appending the sliced cubes in the result_cube list | ||
result_cubes.append(self[cube_slices]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way this is arranged now, the metadata of the Cube will be copied for each slice. Really, the metadata still applies to all the data and isn't specific to the slices. So I think the metadata should be moved from the cube level, to the sequence level. This could be done by doing something like:
sliced_cube = self[cube_slices]
sliced_cube.meta = None
result_cubes.append(self[cube_slices])
return NDCubeSequence(result_cubes, common_axis=axis, meta=self.meta)
Hi @BaptistePellorceAstro. This is looking very good now. Now, as well as the tiny changes I just requested, this PR needs tests! :) |
ndcube/ndcube.py
Outdated
sliced_cube.meta = None | ||
# Appending the sliced cubes in the result_cube list | ||
result_cubes.append(self[cube_slices]) | ||
result_cubes.append(self[item]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self[item]
here should be sliced_cube
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course, I forget to modify this one when I created item
to solve a bug.
ndcube/tests/test_ndcube.py
Outdated
(cubem.explode_along_axis(1), (3*u.pix, 2*u.pix, 4*u.pix)), | ||
(cubem.explode_along_axis(-2), (3*u.pix, 2*u.pix, 4*u.pix)) | ||
]) | ||
def test_explode_along_axis(test_input, expected): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As part of this test, could you also check the type of the output, and also that the meta is None
for the sub-cubes and the the sequence meta is the same as the original cube meta?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes ! I was thinking that this test (taken from ndcube_sequence
) is not relevant at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have an idea why NDCube.explode_along_axis(axis=0)[0].meta
is an OrderedDict()
?
It should not be None
?
Where NDCube.explode_along_axis(axis=0)
is a NDCubeSequence
and NDCube.explode_along_axis(axis=0)[0]
the first NDCube
of the previous NDCubeSequence
.
ndcube/tests/test_ndcube.py
Outdated
(cubem.explode_along_axis(0).dimensions, (2*u.pix, 3*u.pix, 4*u.pix)), | ||
(cubem.explode_along_axis(1).dimensions, (3*u.pix, 2*u.pix, 4*u.pix)), | ||
(cubem.explode_along_axis(-2).dimensions, (3*u.pix, 2*u.pix, 4*u.pix)), | ||
(cubem.explode_along_axis(0)[0].meta, OrderedDict()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is really an OrderedDict()
???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it should be an NDCubeSequence
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I am speaking about the NDCube.meta
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Well I think recently in Python, dictionaries now default to OrderedDict
. So I think that's fine.
@@ -910,3 +912,15 @@ def test_axis_world_coords_without_input(test_input, expected): | |||
for i in range(len(all_coords)): | |||
np.testing.assert_allclose(all_coords[i].value, expected[i].value) | |||
assert all_coords[i].unit == expected[i].unit | |||
|
|||
|
|||
@pytest.mark.parametrize("test_input,expected", [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can put in more than one expected output by making expected
a tuple
and then unpacking that tuple in the test. The test should be testing the same thing(s) in the same way. You can test multiple things in one test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I know. Do you want I regroup types test ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine to have something like:
def test_():
expected_dimensions, expected_type, ... = *expected
assert expected_dimensions == test_input.dimensions
assert isinstance(test_input, expected_type)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I go change that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must add and other test for the metadata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I clearly understand why you want to regroup tests but I didn't find a better than seperate NDCubeSequence
and sub-NDCube
. Like that, we can have a better understanding about which test is about which types. But I think that will be interesting to modify the quantity of list for the sub-NDCube.dimensions
to a tuple of quantity as for NDCubeSequence
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, you're saying NDCube.dimensions
should give (<Quantity x pix>, <Quantity x pix>, <Quantity x pix>)
instead of what it current gives which is <Quantity [x, x, x] pix>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think this should be better, as we try to have the same functions for each class.
But maybe be the list is used in some other functions ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be open to considering that. Having a Quantity of multiple numbers is obviously handier. But you can't do that for NDCubeSequence
as if there's a common axis, the length of the cubes along that axis many not be the same length. On the other hand, you could turn a tuple of single value quantities into a single quantity of multiple values by doing u.Quantity((0*u.pix, 1*u.pix), unit=u.pix)
. Although it's probably not very fast.
Like I said, I'm open to it. I'll think about it a little more. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Cadair could we have your thoughts on this proposed change to the NDCube.dimensions
API? The proposed change is that the output will become a tuple of length-one Quantities, rather than a Quantity of length>1. You can see @BaptistePellorceAstro's original arguments above. I am open to it for a couple of reasons:
- It is more consistent with the output of
ndarray.shape
and other such attributes; - It makes
NDCube.dimensions
consistent withNDCubeSequence.dimensions
. The latter is a tuple of Quantities so if the sub-cubes' along the common axis are of differing lengths, that can be expressed by the common axis Quantity in the tuple having length > 1 which gives the length of each cube. - It can be easily converted to a single Quantity by doing
>>> Quantity(my_cube.dimensions, unit="pix")
This may however, have repercussion for APE 14? If so, perhaps there are arguments to escalate this change there too?
I succeed to do only one test for |
ndcube/tests/test_ndcube.py
Outdated
def test_explode_along_axis_meta(test_input, expected): | ||
expected_type, expected_meta = expected | ||
def test_explode_along_axis_v2(test_input, expected): | ||
expected_dimensions, expected_type, expected_meta = expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original NDCube
and the axis along which is should be exploded should be in the parameterisation and the the method on them, explode_along_axis
should be called in the test:
output = test_input[0].explode_along_axis(test_input[1])
ndcube/tests/test_ndcube.py
Outdated
]) | ||
def test_explode_along_axis_meta(test_input, expected): | ||
expected_type, expected_meta = expected | ||
def test_explode_along_axis_v2(test_input, expected): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for a _v2
in the test name here. That's what version control is for :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was an old test in my local repo =)
ndcube/tests/test_ndcube.py
Outdated
assert isinstance(test_input, expected_type) | ||
assert isinstance(test_input.meta, expected_meta) | ||
def test_explode_along_axis(test_input, expected): | ||
output = test_input[0].explode_along_axis(test_input[1]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An optional change: Since you now have 3 inputs, you could do the same thing as you did with the expected outputs and unpack them into sensible variables like:
input_cube, input_axis, test_slice = *test_input
But this a matter of your personal preference in coding style and so optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is clearer as you said so I modified.
Hi @BaptistePellorceAstro. I'm happy with these changes. The PR looks great. Let me know if you want to make any further optional additions, like the one I mentioned in the most recent comment. If not, I'll merge the PR :) |
If you are OK with the new version, I am ready to merge. |
I think this PR is almost ready to go. It just has to be altered so the tests pass. |
I don't understand what is this problem. In my local repo, the test succeeded. |
I succeeded to solve Travis error, I am ready to merge. |
@BaptistePellorceAstro, I just merged a bugfix PR from @Cadair . Could you pull the latest version of master in your explode_along_axis branch and push it to this PR. Once that's done and there are no test failures, I'll merge. |
I am not at the office, can I do it from the website ? |
Update of explode_along_axis before a PR
I tried something, it is what you want ? |
Yep! That looks good! 👍 |
Another PR merged!!! |
Here the first version of
explode_along_axis
inside NDCube.ping @DanRyanIrish