Skip to content

Commit 2d64f92

Browse files
Fix #493 by reworking GOCE reentry plot
* Move the plot into its own Python file for faster iteration. * Switch the x-axis from ordinal dates to datetime objects, to dodge a breaking change in matplotlib: its default epoch for floating point days moved from the year AD 1 to the year AD 1970. * Upgrade Pandas to 1.0.0 to avoid: matplotlib/matplotlib#12310 pandas-dev/pandas#22859 * Switch to relying on `message` to determine if SGP4 failed. * Spruce up the axis labelling, just for fun. * Use the same plot in both places it’s discussed in the docs.
1 parent 9f31521 commit 2d64f92

File tree

6 files changed

+80
-59
lines changed

6 files changed

+80
-59
lines changed

examples/goce_reentry_chart.py

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import numpy as np
2+
from matplotlib import pyplot as plt
3+
from matplotlib.dates import HourLocator, DateFormatter
4+
5+
from skyfield.api import load, EarthSatellite
6+
7+
# Labels for both date and hour on the x axis, and km on y.
8+
9+
def label_dates_and_hours(axes):
10+
axes.xaxis.set_major_locator(HourLocator([0]))
11+
axes.xaxis.set_minor_locator(HourLocator([0, 6, 12, 18]))
12+
axes.xaxis.set_major_formatter(DateFormatter('0h\n%Y %b %d\n%A'))
13+
axes.xaxis.set_minor_formatter(DateFormatter('%Hh'))
14+
for label in ax.xaxis.get_ticklabels(which='both'):
15+
label.set_horizontalalignment('left')
16+
axes.yaxis.set_major_formatter('{x:.0f} km')
17+
axes.tick_params(which='both', length=0)
18+
19+
# Load the satellite's final TLE entry.
20+
21+
sat = EarthSatellite(
22+
'1 34602U 09013A 13314.96046236 .14220718 20669-5 50412-4 0 930',
23+
'2 34602 096.5717 344.5256 0009826 296.2811 064.0942 16.58673376272979',
24+
'GOCE',
25+
)
26+
27+
# Build the time range `t` over which to plot, plus other values.
28+
29+
ts = load.timescale()
30+
t = ts.tt_jd(np.arange(sat.epoch.tt - 2.0, sat.epoch.tt + 2.0, 0.005))
31+
reentry = ts.utc(2013, 11, 11, 0, 16)
32+
earth_radius_km = 6371.0
33+
34+
# Compute geocentric positions for the satellite.
35+
36+
g = sat.at(t)
37+
valid = [m is None for m in g.message]
38+
39+
# Start a new figure.
40+
41+
fig, ax = plt.subplots()
42+
43+
# Draw the blue curve.
44+
45+
x = t.utc_datetime()
46+
y = np.where(valid, g.distance().km - earth_radius_km, np.nan)
47+
ax.plot(x, y)
48+
49+
# Label the TLE epoch.
50+
51+
x = sat.epoch.utc_datetime()
52+
y = sat.at(sat.epoch).distance().km - earth_radius_km
53+
ax.plot(x, y, 'k.')
54+
ax.text(x, y - 9, 'Epoch of TLE data ', ha='right')
55+
56+
# Label the official moment of reentry.
57+
58+
x = reentry.utc_datetime()
59+
y = sat.at(reentry).distance().km - earth_radius_km
60+
ax.plot(x, y, 'r.')
61+
ax.text(x, y + 6, ' Moment of re-entry', c='r')
62+
63+
# Grid lines and labels.
64+
65+
ax.grid(which='both')
66+
ax.set(title='GOCE satellite: altitude above sea level', xlabel='UTC')
67+
label_dates_and_hours(ax)
68+
69+
# Render the plot to a PNG file.
70+
71+
fig.savefig('goce-reentry.png', bbox_inches='tight')

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ lxml==4.4.1
55
mock==2.0.0
66
numpy==1.15.4
77
matplotlib==3.3.0
8-
pandas==0.23.3
8+
pandas==1.0.0
99
pyflakes==2.1.1
1010
python-dateutil>=2.5.0
1111
pytz
-25.6 KB
Binary file not shown.
3.21 KB
Loading

skyfield/documentation/earth-satellites.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -687,18 +687,18 @@ At that point, the satellite will return a position and velocity
687687
are the special floating-point value ``nan`` which means *not-a-number*.
688688

689689
When a propagation error occurs and you get ``nan`` values,
690-
you can examine the ``sgp4_error`` attribute of the returned position
690+
you can examine the ``message`` attribute of the returned position
691691
to learn the error that the SGP4 propagator encountered.
692692

693693
We can take as an example the satellite elements above.
694694
They are the last elements ever issued for GOCE,
695-
about one day before the satellite re-entered the atmosphere
695+
just before the satellite re-entered the atmosphere
696696
after an extended and successful mission.
697697
Because of the steep decay of its orbit,
698698
the elements are valid over an unusually short period —
699699
from just before noon on Saturday to just past noon on Tuesday:
700700

701-
.. image:: _static/goce-decay.png
701+
.. image:: _static/goce-reentry.png
702702

703703
By asking for GOCE’s position just before or after this window,
704704
we can learn about the propagation errors
@@ -727,7 +727,7 @@ that are limiting this TLE set’s predictions:
727727
mrt is less than 1.0 which indicates the satellite has decayed
728728

729729
If you use a ``Time`` array to ask about an entire range of dates,
730-
then ``sgp4_error`` will be a sequence filled in with ``None``
730+
then ``message`` will be a sequence filled in with ``None``
731731
whenever the SGP4 propagator was successful
732732
and otherwise recording the propagator error:
733733

skyfield/documentation/example-plots.rst

+4-54
Original file line numberDiff line numberDiff line change
@@ -75,62 +75,12 @@ The code to produce the diagram using `matplotlib`_,
7575
including custom tick marks that are based on the date,
7676
is:
7777

78-
.. testcode::
79-
80-
from matplotlib import pyplot as plt
81-
from matplotlib.dates import HourLocator, DateFormatter
82-
83-
from numpy import arange
84-
85-
def label_dates_and_hours(axes):
86-
axes.xaxis.set_major_locator(HourLocator([0]))
87-
axes.xaxis.set_minor_locator(HourLocator([0, 12]))
88-
axes.xaxis.set_major_formatter(DateFormatter('\n%a %d'))
89-
axes.xaxis.set_minor_formatter(DateFormatter('%Hh'))
90-
91-
from skyfield.api import load, EarthSatellite
92-
93-
# Load the satellite's final TLE entry.
94-
95-
sat = EarthSatellite(
96-
'1 34602U 09013A 13314.96046236 .14220718 20669-5 50412-4 0 930',
97-
'2 34602 096.5717 344.5256 0009826 296.2811 064.0942 16.58673376272979',
98-
'GOCE',
99-
)
100-
101-
# Build the time range `t` over which to plot, plus other values.
102-
103-
ts = load.timescale()
104-
t = ts.tt_jd(arange(sat.epoch.tt - 1.0, sat.epoch.tt + 3.0, 0.01))
105-
reentry = ts.utc(2013, 11, 11, 0, 16)
106-
earth_radius_km = 6371.
107-
108-
# Start a new figure.
109-
110-
fig, ax = plt.subplots()
111-
112-
# Draw the blue curve.
113-
114-
x = t.toordinal()
115-
y = sat.at(t).distance().km - earth_radius_km
116-
ax.plot(x, y)
117-
118-
# Label the official moment of reentry.
119-
120-
x = reentry.toordinal()
121-
y = sat.at(reentry).distance().km - earth_radius_km
122-
ax.plot(x, y, 'ro')
123-
ax.text(x, y + 10, 'Moment of re-entry')
124-
125-
# Grid lines and labels.
126-
127-
label_dates_and_hours(ax)
128-
ax.grid()
129-
ax.set(title='GOCE satellite altitude', ylabel='km above sea level')
78+
.. testsetup::
13079

131-
# Render the plot to a PNG file.
80+
import goce_reentry_chart
13281

133-
fig.savefig('goce-reentry.png', bbox_inches='tight')
82+
.. include:: ../../examples/goce_reentry_chart.py
83+
:literal:
13484

13585
.. testcleanup::
13686

0 commit comments

Comments
 (0)