Skip to content

Commit

Permalink
Fix #524: array formatting for str/repr of lat/lon
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon-rhodes committed Jan 14, 2021
1 parent 006dcd4 commit 550c67e
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 22 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ Changelog
v1.36 — ?
---------

* The default ``str()`` and ``repr()`` strings
for geographic positions have been streamlined,
and no longer raise ``ValueError`` when elevation is an array.
They now show simple decimals
instead of splitting degrees of longitude and latitude
into minutes and seconds;
always show elevation, even if zero;
properly format NumPy arrays;
and abbreviate long arrays.
`#524 <https://github.com/skyfielders/python-skyfield/issues/524>`_

* Fixed
:meth:`Angle.dstr() <skyfield.units.Angle.dstr>`
and
Expand Down
2 changes: 1 addition & 1 deletion skyfield/documentation/earth-satellites.rst
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ to ask “where will the satellite be *relative to* my location?”
.. testoutput::

Sum of 2 vectors:
Reversed Geodetic WGS84 latitude 40deg 53' 38.0" N longitude -83deg 53' 30.1" E -> 399 EARTH
Reversed Geodetic WGS84 latitude +40.8939 N longitude -83.8917 E elevation 0.0 m -> 399 EARTH
EarthSatellite 399 EARTH -> ISS (ZARYA) catalog #25544 epoch 2014-01-20 22:23:04 UTC

Every time you call this vector sum’s ``at()`` method,
Expand Down
16 changes: 8 additions & 8 deletions skyfield/tests/test_strs_and_reprs.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ def test_satellite_without_name():
def test_geographic_position():
t = wgs84.latlon(42.2, -88.1)
expected = dedent("""\
WGS84 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E
WGS84 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m
""")
assert str(t) == expected
expected = dedent("""\
<GeographicPosition WGS84 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E>
<GeographicPosition WGS84 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m>
""")
assert repr(t) == expected

Expand All @@ -65,11 +65,11 @@ def test_geographic_position():
def test_topos():
t = Topos(latitude_degrees=42.2, longitude_degrees=-88.1)
expected = dedent("""\
IERS2010 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E
IERS2010 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m
""")
assert str(t) == expected
expected = dedent("""\
<Topos IERS2010 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E>
<Topos IERS2010 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m>
""")
assert repr(t) == expected

Expand Down Expand Up @@ -99,13 +99,13 @@ def test_geographic_position_and_earth_satellite_vector_sum(eph):
v = s - t
expected = dedent("""\
Sum of 2 vectors:
Reversed Geodetic WGS84 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E -> 399 EARTH
Reversed Geodetic WGS84 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m -> 399 EARTH
EarthSatellite 399 EARTH -> catalog #25544 epoch 2013-11-26 13:57:03 UTC
""")
assert str(v) == expected
expected = dedent("""\
<VectorSum of 2 vectors:
Reversed Geodetic WGS84 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E -> 399 EARTH
Reversed Geodetic WGS84 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m -> 399 EARTH
EarthSatellite 399 EARTH -> catalog #25544 epoch 2013-11-26 13:57:03 UTC>
""")
assert repr(v) == expected
Expand All @@ -116,13 +116,13 @@ def test_topos_and_earth_satellite_vector_sum(eph):
v = s - t
expected = dedent("""\
Sum of 2 vectors:
Reversed Geodetic IERS2010 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E -> 399 EARTH
Reversed Geodetic IERS2010 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m -> 399 EARTH
EarthSatellite 399 EARTH -> catalog #25544 epoch 2013-11-26 13:57:03 UTC
""")
assert str(v) == expected
expected = dedent("""\
<VectorSum of 2 vectors:
Reversed Geodetic IERS2010 latitude 42deg 12' 00.0" N longitude -88deg 06' 00.0" E -> 399 EARTH
Reversed Geodetic IERS2010 latitude +42.2000 N longitude -88.1000 E elevation 0.0 m -> 399 EARTH
EarthSatellite 399 EARTH -> catalog #25544 epoch 2013-11-26 13:57:03 UTC>
""")
assert repr(v) == expected
29 changes: 26 additions & 3 deletions skyfield/tests/test_topos.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from assay import assert_raises
from numpy import abs, sqrt
from numpy import abs, arange, sqrt

from skyfield import constants
from skyfield.api import Distance, load, wgs84, wms
Expand All @@ -12,14 +12,37 @@
def ts():
yield load.timescale()

def test_latitude_longitude_elevation_str_and_repr():
w = wgs84.latlon(36.7138, -112.2169, 2400.0)
assert str(w) == ('WGS84 latitude +36.7138 N'
' longitude -112.2169 E elevation 2400.0 m')
assert repr(w) == ('<GeographicPosition WGS84 latitude +36.7138 N'
' longitude -112.2169 E elevation 2400.0 m>')

w = wgs84.latlon([1.0, 2.0], [3.0, 4.0], [5.0, 6.0])
assert str(w) == (
'WGS84 latitude [+1.0000 +2.0000] N'
' longitude [3.0000 4.0000] E'
' elevation [5.0 6.0] m'
)
assert repr(w) == '<GeographicPosition {0}>'.format(w)

w = wgs84.latlon(arange(6.0), arange(10.0, 16.0), arange(20.0, 26.0))
assert str(w) == (
'WGS84 latitude [+0.0000 +1.0000 ... +4.0000 +5.0000] N'
' longitude [10.0000 11.0000 ... 14.0000 15.0000] E'
' elevation [20.0 21.0 ... 24.0 25.0] m'
)
assert repr(w) == '<GeographicPosition {0}>'.format(w)

def test_raw_itrs_position():
d = Distance(au=[1, 2, 3])
p = ITRSPosition(d)
ts = load.timescale()
t = ts.utc(2020, 12, 16, 12, 59)
p.at(t)

def test_velocity():
def test_wgs84_velocity_matches_actual_motion():
# It looks like this is a sweet spot for accuracy: presumably a
# short enough fraction of a second that the vector does not time to
# change direction much, but long enough that the direction does not
Expand All @@ -46,7 +69,7 @@ def test_lst():
difference_mas -= horizons_ra_offset_mas
assert abs(difference_mas) < 1.0

def test_itrf_vector():
def test_itrs_xyz_attribute_and_itrf_xyz_method():
top = wgs84.latlon(45.0, 0.0, elevation_m=constants.AU_M - constants.ERAD)

x, y, z = top.itrs_xyz.au
Expand Down
6 changes: 3 additions & 3 deletions skyfield/tests/test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@ def test_vectors():
Sum of 3 vectors:
'de421.bsp' segment 0 SOLAR SYSTEM BARYCENTER -> 3 EARTH BARYCENTER
'de421.bsp' segment 3 EARTH BARYCENTER -> 399 EARTH
Geodetic 399 EARTH -> IERS2010 latitude 38deg 55' 17.4" N longitude -77deg 04' 00.8" E elevation 92 m"""
Geodetic 399 EARTH -> IERS2010 latitude +38.9215 N longitude -77.0669 E elevation 92.0 m"""

assert repr(v) == """\
<VectorSum of 3 vectors:
'de421.bsp' segment 0 SOLAR SYSTEM BARYCENTER -> 3 EARTH BARYCENTER
'de421.bsp' segment 3 EARTH BARYCENTER -> 399 EARTH
Geodetic 399 EARTH -> IERS2010 latitude 38deg 55' 17.4" N longitude -77deg 04' 00.8" E elevation 92 m>"""
Geodetic 399 EARTH -> IERS2010 latitude +38.9215 N longitude -77.0669 E elevation 92.0 m>"""

assert str(v.at(t)) == """\
<Barycentric BCRS position and velocity at date t center=0 target=IERS2010 latitude 38deg 55' 17.4" N longitude -77deg 04' 00.8" E elevation 92 m>"""
<Barycentric BCRS position and velocity at date t center=0 target=IERS2010 latitude +38.9215 N longitude -77.0669 E elevation 92.0 m>"""

v = earth - mars

Expand Down
22 changes: 15 additions & 7 deletions skyfield/toposlib.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
# -*- coding: utf-8 -*-

from numpy import arctan2, array, cos, exp, sin, sqrt
from numpy import arctan2, array, array2string, cos, exp, sin, sqrt
from .constants import ANGVEL, AU_M, DAY_S, T0, pi, tau
from .earthlib import refract
from .framelib import itrs
from .functions import _T, mxm, mxv, rot_y, rot_z
from .functions import _T, _to_array, mxm, mxv, rot_y, rot_z
from .descriptorlib import reify
from .units import Angle, Distance, _ltude
from .vectorlib import VectorFunction

_lat_options = {'precision': 4, 'floatmode': 'fixed', 'sign': '+',
'threshold': 5, 'edgeitems': 2}
_lon_options = {'precision': 4, 'floatmode': 'fixed',
'threshold': 5, 'edgeitems': 2}
_elev_options = {'precision': 1, 'floatmode': 'fixed',
'threshold': 5, 'edgeitems': 2}

class ITRSPosition(VectorFunction):
"""An x,y,z position in the Earth-centered Earth-fixed (ECEF) ITRS frame."""

Expand Down Expand Up @@ -69,10 +76,11 @@ def __init__(self, model, latitude, longitude, elevation, itrs_xyz):

@reify # not @property, so users have the option of overwriting it
def target_name(self):
m = self.elevation.m
e = ' elevation {0:.0f} m'.format(m) if m else ''
return '{0} latitude {1} N longitude {2} E{3}'.format(
self.model.name, self.latitude, self.longitude, e)
return '{0} latitude {1} N longitude {2} E elevation {3} m'.format(
self.model.name,
array2string(self.latitude.degrees, **_lat_options),
array2string(self.longitude.degrees, **_lon_options),
array2string(self.elevation.m, **_elev_options))

def lst_hours_at(self, t):
"""Return this position’s Local Sidereal Time in hours at time ``t``."""
Expand Down Expand Up @@ -131,7 +139,7 @@ def latlon(self, latitude_degrees, longitude_degrees, elevation_m=0.0,
"""
latitude = Angle(degrees=latitude_degrees)
longitude = Angle(degrees=longitude_degrees)
elevation = Distance(m=elevation_m)
elevation = Distance(m=_to_array(elevation_m))

lat = latitude.radians
lon = longitude.radians
Expand Down

0 comments on commit 550c67e

Please sign in to comment.