Skip to content

Add replicate and replicate_without_data methods to frames#6182

Merged
mhvk merged 12 commits intoastropy:masterfrom
eteq:clone-frame
Jun 13, 2017
Merged

Add replicate and replicate_without_data methods to frames#6182
mhvk merged 12 commits intoastropy:masterfrom
eteq:clone-frame

Conversation

@eteq
Copy link
Member

@eteq eteq commented Jun 12, 2017

This is a straightforward PR that adds a clone_frame method to BaseCoordinateFrame. This method copies the frame and its attributes, without the data, optionally overriding frame attributes.

I'm not a huge fan of the specific name clone_frame, as it doesn't clearly convey that the data get removed. But I felt unrealize_frame doesn't convey the fact that this is also a good way to copy attributes (overwriting specific ones if desired). So this seemed like a compromise... But I'm willing to be convinced if someone has strong opinions.

This idiom is used in a variety of places, and this method can probably be used to clean things up. But for now just getting it in for 2.0 is a good starting point. (Note that it also makes some of the velocity work @adrn and I are finishing up easier).

cc @astrofrog or @Cadair (one of you I think originally suggested this in some form or another... I think?)

@eteq eteq added this to the v2.0.0 milestone Jun 12, 2017
@adrn
Copy link
Member

adrn commented Jun 12, 2017

Cool, sounds reasonable to me. I don't love the name though - just brainstorming:

  • .without_data()
  • .copy_without_data()
  • .no_data()

@bsipocz
Copy link
Member

bsipocz commented Jun 12, 2017

+1 to .copy_without_data()

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

How about just a new copy method? It could have **kwargs like here, but by default also include representation. Then, if you do not want a representation included, you put representation=None? (I think this would "just work"!).

A new object with the same frame attributes as this one, but
with no data and possibly new frame attributes.
"""
attrs_to_set = {nm:getattr(self, nm) for nm in self.frame_attributes}
Copy link
Contributor

Choose a reason for hiding this comment

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

This should exclude defaults (i.e., just copy frattrs definition from realize_frame)

Copy link
Member Author

Choose a reason for hiding this comment

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

will do

with no data and possibly new frame attributes.
"""
attrs_to_set = {nm:getattr(self, nm) for nm in self.frame_attributes}
for nm, val in kwargs.items():
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just frattrs.update(kwargs)?

Copy link
Member Author

Choose a reason for hiding this comment

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

oh, good point! Will do.

@mhvk
Copy link
Contributor

mhvk commented Jun 12, 2017

p.s. Note that currently copy is provided by ShapedLikeNDArray -- which actually does more like a deepcopy, copying all the attributes and the data...

@eteq
Copy link
Member Author

eteq commented Jun 12, 2017

@mhvk - #6182 (comment) is exactly why I didn't go with copy - copy actually copies the data because it's based on ShapedLikeNDArray, whereas this is about copying everything except the data. My thinking was that it would be more confusing to overload copy() with different functionality than pick a new name...

@eteq
Copy link
Member Author

eteq commented Jun 12, 2017

although... now that I think about it, I kind of like the representation=None idea. The question is what to do about the default, though - should be like the current copy to not break backwards-compatibility/consistency with other ShapedLikeNDArray. Will experiment to see if I can make something work naturally.

@mhvk
Copy link
Contributor

mhvk commented Jun 12, 2017

By analogy with Time, you could also create a replicate method (which needs some additions to _apply -- see the Time version). That also allows to override (though only one item, the format).

p.s. It is perhaps slightly unfortunate that our copy is usually deepcopy -- I think there was even an issue about this... -- but that is a ship that sailed long ago.

@eteq
Copy link
Member Author

eteq commented Jun 12, 2017

Hmm, a replicate might be a good idea, but I think it's a bit harder to see how that connects with the "drop data" element here. Having thought a bit more I think it's better to have this in its minimal form (in which case copy_without_data seems promising) as sort of the converse to realize_frame, mainly because it helps with the relatively confusing bit about frames that they are both frames and can carry data. It might be we also want replicate, though, for the with-data case.

@mhvk
Copy link
Contributor

mhvk commented Jun 12, 2017

How about dataless_frame, disregard_data, lose_data_frame? In any case, it may be an idea for both the new one and realize_frame to use replicate internally (possibly channeled via _apply).

@eteq
Copy link
Member Author

eteq commented Jun 13, 2017

OK, I went the route @mhvk suggested here, with the name choice of replicate_without_data (seems like a good compromise between @adrn and @bsipocz favorite and the implementation). It's quite different now in that everything goes through _apply (including realize_frame). I think that's better and more consistent, now that we've gone through this, but it's worth another look to make sure the _apply changes look right (probably by @mhvk...).

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

This looks very good, I'm happy it worked so well. Apart from the minor comments in-line, one question is whether one should just expose the possibility of setting the data, i.e., use representation explicitly instead of _framedata -- but obviously we can also add this later, so fine to keep as is too.

def apply_method(value):
if isinstance(value, ShapedLikeNDArray):
return value._apply(method, *args, **kwargs)
if method=='replicate' and not hasattr(value, method):
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: spaces around ==.

Copy link
Contributor

Choose a reason for hiding this comment

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

p.s. Nice future-proofing!

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, it wasn't just future-proofing (although that is indeed an important side-benefit!). It turns out this is necessary just to get the tests to pass because Quantity sub-classes like Angle/Latitude/Longitude don't have replicate.

But in the end it's good anyway this way, I think!

else:
return getattr(value, method)(*args, **kwargs)

if method=='replicate' and not hasattr(value, method):
Copy link
Contributor

Choose a reason for hiding this comment

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

Same nitpick.


def replicate(self, copy=False, **kwargs):
"""
Generates a new frame object that is a copy of this one, but possibly
Copy link
Contributor

Choose a reason for hiding this comment

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

It is mostly a matter of taste, but I prefer single-line "titles" of the docstring. E.g., inspired by Times:

Return a replicate of the frame, optionally overriding some attributes.


def replicate_without_data(self, copy=False, **kwargs):
"""
Generates a new frame object that is a copy of this one, but without
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, maybe

Return a replicate without data, optionally overriding some attributes.

(and then still some text like you have here, including the analogy with realize_frame)

@mhvk
Copy link
Contributor

mhvk commented Jun 13, 2017

p.s. Maybe edit the title of this PR.

@mhvk
Copy link
Contributor

mhvk commented Jun 13, 2017

(Approved changes, since really only small comments remain.)

@eteq eteq changed the title Add clone_frame method to frames Add replicate and replicate_without_data methods to frames Jun 13, 2017
@eteq
Copy link
Member Author

eteq commented Jun 13, 2017

Alright, I addressed @mhvk's comments, and I think this is ready to merge after the tests pass (or maybe even before, given that these are very minor changes).

@mhvk
Copy link
Contributor

mhvk commented Jun 13, 2017

Agreed that running the full tests is not necessary, especially since appveyor and circle already passed. So, I cancelled travis and will merge. Nice addition!

@mhvk mhvk merged commit bf7805d into astropy:master Jun 13, 2017
@eteq eteq deleted the clone-frame branch June 13, 2017 16:02
@Cadair
Copy link
Member

Cadair commented Jun 14, 2017

This seems to have broken SunPy master. It seems that our use of realize_frame is no longer valid: https://github.com/sunpy/sunpy/blob/master/sunpy/coordinates/frames.py#L364

https://travis-ci.org/sunpy/sunpy/jobs/242845641#L1123

Any bright ideas before I jump all the way into this?

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.

5 participants