Skip to content

Commit 8acef8e

Browse files
committed
Add in_frame_units kwarg and move unit shifting into frame represent_as()
Two coupled but significant changes. BaseCoordinateFrame.represent_as() is now capable of returning a representation that has the frame units which are specified in the representation_attrs[<ReprClass>]['frame_units'] dict. In other words the returned representation is in the frame units (e.g. degrees for ra,dec) instead of the native units (e.g. rad for Spherical). This unit shifting functionality was moved out of __repr__ into represent_as(). To achieve this a new "in_frame_units" kwarg was added which defaults to False (reproducing the previous behavior). Along with that the repr. cache is now keyed by the tuple (Repr class name, in_frame_units). This change solves a latent problem that was not apparent previously because all built-in frames have a default SphericalRepresentation. If instead you start from a CartesianRepresentation there is an issue:: >>> c = ICRS(x, y, z, representation=CartesianRepresentation) >>> c.spherical # Output is in radians, not degrees, giving a non-useful view # of the spherical representation With this commit the `spherical` property calls represent_as with in_frame_units=True and the desired units of degrees are returned.
1 parent 214f416 commit 8acef8e

1 file changed

Lines changed: 45 additions & 33 deletions

File tree

‎astropy/coordinates/baseframe.py‎

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def __init__(self, *args, **kwargs):
242242

243243
if self._data:
244244
self._rep_cache = dict()
245-
self._rep_cache[representation.__class__.__name__] = representation
245+
self._rep_cache[representation.__class__.__name__, False] = representation
246246

247247
@property
248248
def data(self):
@@ -300,7 +300,7 @@ def realize_frame(self, representation):
300300
if nm not in self._attr_names_with_defaults])
301301
return self.__class__(representation, **frattrs)
302302

303-
def represent_as(self, new_representation):
303+
def represent_as(self, new_representation, in_frame_units=False):
304304
"""
305305
Generate and return a new representation of this frame's `data`.
306306
@@ -310,6 +310,10 @@ def represent_as(self, new_representation):
310310
The type of representation to generate, as a *class* (not an
311311
instance).
312312
313+
in_frame_units : bool
314+
Force the representation units to match the specified units
315+
particular to this frame
316+
313317
Returns
314318
-------
315319
newrep : whatever `new_representation` is
@@ -328,11 +332,41 @@ def represent_as(self, new_representation):
328332
>>> coord.represent_as(CartesianRepresentation)
329333
<CartesianRepresentation x=1.0 , y=0.0 , z=0.0 >
330334
"""
331-
cached_repr = self._rep_cache.get(new_representation.__name__, None)
335+
cached_repr = self._rep_cache.get((new_representation.__name__, in_frame_units))
332336
if not cached_repr:
333-
rep = self.data.represent_as(new_representation)
334-
self._rep_cache[new_representation.__name__] = rep
335-
return self._rep_cache[new_representation.__name__]
337+
data = self.data.represent_as(new_representation)
338+
339+
# If the new representation is known to this frame and has a defined
340+
# set of names and units, then use that.
341+
new_attrs = self.representation_attrs.get(new_representation)
342+
if new_attrs and in_frame_units:
343+
new_attr_names = new_attrs['attr_names']
344+
new_attr_units = new_attrs['attr_units']
345+
346+
# if necessary, make a new representation with preferred units
347+
if new_attr_units:
348+
# first figure out how to map *representation* attribute
349+
# names to units
350+
comp_to_unit = {}
351+
for attnm, unit in new_attr_units.items():
352+
if attnm not in new_attr_names:
353+
msg = ('The attribute {0} in `preferred_attr_units`'
354+
' is not in `preferred_attr_names`')
355+
raise ValueError(msg.format(attnm))
356+
comp_to_unit[new_attr_names[attnm]] = unit
357+
358+
# Now actually create a new representation with the new units
359+
datakwargs = {}
360+
for comp in data.components:
361+
datakwargs[comp] = getattr(data, comp)
362+
newu = comp_to_unit.get(comp, None)
363+
if newu:
364+
datakwargs[comp] = datakwargs[comp].to(newu)
365+
data = data.__class__(**datakwargs)
366+
367+
self._rep_cache[new_representation.__name__, in_frame_units] = data
368+
369+
return self._rep_cache[new_representation.__name__, in_frame_units]
336370

337371
def transform_to(self, new_frame):
338372
"""
@@ -450,29 +484,9 @@ def __repr__(self):
450484
if self.representation:
451485
if (self.representation == SphericalRepresentation and
452486
isinstance(self.data, UnitSphericalRepresentation)):
453-
data = self.represent_as(UnitSphericalRepresentation)
487+
data = self.represent_as(UnitSphericalRepresentation, in_frame_units=True)
454488
else:
455-
data = self.represent_as(self.representation)
456-
# if necessary, make a new representation with preferred units
457-
if self.preferred_attr_units:
458-
# first figure out how to map *representation* attribute
459-
# names to units
460-
comp_to_unit = {}
461-
for attnm, unit in self.preferred_attr_units.items():
462-
if attnm not in self.preferred_attr_names:
463-
msg = ('The attribute {0} in `preferred_attr_units`'
464-
' is not in `preferred_attr_names`')
465-
raise ValueError(msg.format(attnm))
466-
comp_to_unit[self.preferred_attr_names[attnm]] = unit
467-
468-
#now actually create a new representation with the new units
469-
datakwargs = {}
470-
for comp in data.components:
471-
datakwargs[comp] = getattr(data, comp)
472-
newu = comp_to_unit.get(comp, None)
473-
if newu:
474-
datakwargs[comp] = datakwargs[comp].to(newu)
475-
data = data.__class__(**datakwargs)
489+
data = self.represent_as(self.representation, in_frame_units=True)
476490

477491
data_repr = repr(data)
478492
for nmpref, nmrepr in self.preferred_attr_names.items():
@@ -515,10 +529,8 @@ def __getattr__(self, attr):
515529
raise AttributeError("'{0}' object has no attribute '{1}'"
516530
.format(self.__class__.__name__, attr))
517531

518-
rep = self.represent_as(self.representation)
532+
rep = self.represent_as(self.representation, in_frame_units=True)
519533
val = getattr(rep, self.preferred_attr_names[attr])
520-
if attr in self.preferred_attr_units:
521-
val = val.to(self.preferred_attr_units[attr])
522534
return val
523535

524536
def __setattr__(self, attr, value):
@@ -611,7 +623,7 @@ def cartesian(self):
611623
"""
612624
# TODO: if representations are updated to use a full transform graph,
613625
# the representation aliases should not be hard-coded like this
614-
return self.represent_as(CartesianRepresentation)
626+
return self.represent_as(CartesianRepresentation, in_frame_units=True)
615627

616628
@property
617629
def spherical(self):
@@ -620,7 +632,7 @@ def spherical(self):
620632
"""
621633
# TODO: if representations are updated to use a full transform graph,
622634
# the representation aliases should not be hard-coded like this
623-
return self.represent_as(SphericalRepresentation)
635+
return self.represent_as(SphericalRepresentation, in_frame_units=True)
624636

625637

626638
class GenericFrame(BaseCoordinateFrame):

0 commit comments

Comments
 (0)