Skyfield: Home • Table of Contents • Changelog • API Reference
Skyfield has only a single binary dependency, the NumPy vector library, and is designed to install cleanly with a single invocation of the standard Python package tool:
pip install skyfield
This should install Skyfield, NumPy,
and the small collection of pure-Python astronomy libraries
that Skyfield depends on.
If you lack pip
and need to install each dependency by hand,
consult Skyfield’s setup.py
file for the full list.
If trying to install Skyfield gives you errors about NumPy, there are several other ways to get NumPy installed:
It is best to simply use a science-ready version of Python that comes with NumPy built-in, like the Anaconda distribution.
You can download and run an official NumPy installer.
You can try to get the plain pip
-powered install working
by giving your system a functioning C compiler
that matches the compiler used to build Python.
On Windows with Python 2.7, try installing the free
Visual Studio Express 2008.
Mac users should install the “Xcode Command Line Tools”
to give pip
the superpower of being able to build and install
binary Python dependencies like NumPy.
Read the Changelog below to learn about recent fixes, changes,
and improvements to Skyfield.
You can protect your project from any abrupt API changes
by pinning a specific version of Skyfield
in your requirements.txt
or setup.py
or install instructions:
skyfield==1.34
By preventing Skyfield from getting accidentally upgraded until you are ready to advance the version number yourself, you can avoid even slight changes in behavior and output coordinates that might result from an upgrade. If you find any problems or would like to suggest an improvement, simply create an issue on the project’s GitHub page:
Good luck!
The Skyfield package offers a VERSION
tuple
that your code can use to test which version of Skyfield is running.
For example,
this code checks whether Skyfield is at least at version 1.24:
import skyfield
if skyfield.VERSION < (1, 24):
print('Too old')
A new featured added in Skyfield 1.36 (released January 2021)
is that you can invoke the skyfield
module from the command line
to display its version:
$ python -m skyfield
Skyfield version: 1.37
jplephem version: 2.14
sgp4 version: 2.17
Built-in leap seconds table ends with leap second at: 2016-12-31 23:59:60 UTC
Built-in ∆T table from finals2000A.all covers: 1973-01-01 to 2022-01-29
Also displayed are the versions of the libraries Skyfield depends on, and the start and end dates of its built-in timescale tables.
If Skyfield has proven useful in your research, the project welcomes your citation to bring it to the attention of other academics who might benefit from it.
https:
but remains http:
in this URL to match papers already using it as an identifier):
http://rhodesmill.org/skyfield/from_omm()
Earth
Satellite constructor has been added to load satellite elements from
modern OMM data instead of from old TLE data. The Earth satellite
documentation now describes two OMM formats and shows how to load satellites
from each one. #763PlanetaryConstants
class to the screen,
it will list all of the segments that it has loaded from binary kernels.
#952<
operator, so Python can sort them.wgs84
have a
new attribute polar_radius
..center
. Otherwise, a ValueError
is raised. This check has
always been performed when you subtract vector functions, but it was
missing from the position subtraction routine.False
not only for sunrise but also for sunset.find_risings()
and
find_settings()
and
find_transits()
functions.
#662load_constellation_map()
table and the
load_constellation_names()
list. Previously,
CVn
and TrA
had been mis-capitalized in the list as Cvn
and Tra
.
#906oppositions_conjunctions()
routine now
measures ecliptic longitude using the ecliptic of each specific date,
rather than always using the J2000 ecliptic, which should improve its
accuracy by several seconds.is_behind_earth()
method was incorrectly returning True
if the Earth was on the line
that joins the two satellites, but over on the far side of the other
satellite where it wasn’t really in the way.altaz()
method now
lives on the main position class instead of in two specific
subclasses. If the user mistakenly tries to call .altaz()
on an
instance of the Astrometric
position
subclass — which previously lacked the method — then a friendly
exception is raised explaining their error.d = Distance.km(5.0)
and
v = Velocity.km_per_s(0.343)
.hip_main.dat
is
downloaded, following a change in the domain for the University of
Strasbourg from u-strasbg.fr
to unistra.fr
.setup.py
in its .tar.gz
; within an hour, a
Python 2.7 user had reported that Skyfield could no longer install.
This release is identical to 1.43 but (hopefully) installs correctly
for everyone!planetary_magnitude()
so it works
for Saturn even when the time is an array rather than a single time;
also, improved its calculation slightly with respect to Uranus.
#739load_comets_dataframe()
so that
parsing CometEls.txt
with the most recent version of Pandas
doesn’t stumble over the commas in the final field of (for example)
Halley’s Comet and give the error ParserError: Error tokenizing
data. C error: Expected 12 fields…saw 13
.
#707phase_angle()
and
fraction_illuminated()
that, given an illuminator (usually the Sun) as their argument,
compute whether the observer is looking at the bright side or the dark
side of the target body.
They replace a pair of old functions in the almanac module.moon_nodes()
would
sometimes skip nodes that were closer together than 14.0 days. It has
been tightened down and should now detect all lunar nodes.
#662to_astropy()
method.to_skycoord()
now
sets the frame
attribute of the sky coordinate it returns, and for
now only supports barycentric and geocentric positions.
#577timedelta
which Skyfield interprets as TT days and seconds.
#568.itrs_xyz
vector of the geographic position returned
by the subpoint_of()
method.
#673de421.bsp
. This does risk raising an error for users whose
machines have out-of-date root certificates. But it protects the
connection from outside tampering, and will keep working if the
ssd.jpl.nasa.gov
FTP service is ever shut down — as happened
earlier this year to FTP on NASA’s cddis.nasa.gov
server.
#666planetary_magnitude()
routine to work with all the major planets, which upgrades it from a
prototype feature to a production feature of Skyfield.subpoint()
method has been
deprecated, because users reported that its name was a poor match for
its behavior. Four new methods have replaced it:
latlon_of()
,
height_of()
,
geographic_position_of()
, and
subpoint_of()
.
#644linspace()
.
#617oppositions_conjunctions()
routine,
which was originally designed only for planets, can now also handle
the Moon (which moves from opposition to conjunction much faster).Angle.dstr()
and
Angle.hstr()
methods now accept a format=
argument
that lets callers override Skyfield’s default angle formatting
and supply their own; see Formatting angles.
#513planetary_magnitude()
function now works not only when given a single position, but when
given a vector of several positions.TEME
reference frame
used by SGP4 Earth satellite elements.frame_latlon_and_rates()
method
that can compute the rates at which angles like altitude and azimuth,
or right ascension and declination,
are changing.Time
tuple utc
and method utc_strftime()
are now backed by the same math,
so they always advance to the next calendar day at the same moment.
This makes it safe to mix values returned by one of them
with values returned by the other.
#542Creating an ndarray from ragged nested sequences
(which is a list-or-tuple of lists-or-tuples-or ndarrays
with different lengths or shapes) is deprecated
.
NumPy no longer wants to accept a simple constant like 0.0
where the resulting array needs a whole row of zeros.
#536hadec()
position method that
returns hour angle and declination.
#510str()
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.
#524Angle.dstr()
and
Angle.hstr()
to return an array of strings when the angle itself is an array.
#527Topos
class,
which not only featured a clunky interface
but hid from users the fact that Skyfield was generating IERS2010 positions
from latitude and longitude
when in fact nearly all users want WGS84 positions.
Users are now encouraged to supply latitude and longitude
to the latlon()
method
of either the wgs84
object
or the iers2010
object.
Related discussion:
#372wgs84
and iers2010
have also provided a happy new home
for the subpoint()
method —
which was previously stranded
over on the Geocentric
class,
where it couldn’t be used with positions of other classes
that might be centered at the geocenter.
(The old method will remain in place to support legacy code,
but is discouraged in new applications.)load_constellation_names()
.utc_jpl()
method now correctly
designates its return value as UTC
instead of the ambiguious UT
.
#515frame_xyz()
,
frame_xyz_and_velocity()
,
frame_latlon()
, and
from_time_and_frame_vectors()
that work with a new library skyfield.framelib
to offer a number of familiar reference frames.
These replace the existing ad-hoc position methods
for ecliptic and galactic coordinates,
which are now deprecated (but will continue to be supported).
See Coordinates in other reference frames.
#476itrs
reference frame.lst_hours_at()
that computes Local Sidereal Time.moon_phase()
returns
the Moon phase as an angle where 0° is New Moon, 90° is First Quarter,
180° is Full, and 270° is Last Quarter.
#282moon_nodes()
to
index into the MOON_NODES
list that provides a name for each node.
#486magnitude_H
and magnitude_G
in the
Minor Planet Center comets dataframe have been renamed magnitude_g
and magnitude_k
following further research on the file format
(which does not itself document which magnitude model is intended).
#416load.timescale(builtin=False)
was raising an
exception FileNotFoundError
if the finals2000A.all
file was
not already on disk, instead of downloading the file automatically.
#477lunar_eclipses()
routine finds
lunar eclipses and determines their degree of totality.
#445meridian_transits()
routine can find the moments at which a body transits the meridian and
antimeridian.
#460find_minima()
function was
ignoring its epsilon
and num
arguments and always using the
default values instead.
#475.epoch
attribute of Earth satellite objects that were
built using from_satrec()
was, alas, a half-day off.
#466Topos
constructor arguments x
and y
,
which never worked properly anyway,
have been deprecated and are now ignored.finals2000A.all
for updated ∆T and leap seconds. The USNO is no
longer updating the files deltat.data
and deltat.preds
that
previous versions of Skyfield used, and the cddis.nasa.gov
server
from which they were fetched will discontinue anonymous FTP on 2020
October 31. See UT1 and downloading IERS data.
#452
#464CometEls.txt
now
includes the reference
column, so users can tell which orbit is
most recent if there are several orbits for a single comet. (For
example, the file currently lists two C/2020 F3 (NEOWISE) orbits.)
The comet examples in the documentation now build a dataframe that
only includes the most recent orbit for each comet.
#463days_old()
and
download()
make it simple to download a
fresh copy of a file if the copy on disk is older than you would like.strftime()
Skyfield methods now support the %j
day-of-year format code.print()
statement was stranded in t.dut1
.
#455Time
object, if manually instantiated
without a Julian date fraction, now provides a fraction array with
dimensions that match the Julian date argument.
#458tt_calendar()
if
the time object was in fact an array of times.
#450ut1()
.hip_main.dat.gz
Hipparcos catalog
file, the old URL now returns a 404 error. As an emergency fix, this
version of Skyfield switches to their uncompressed hip_main.dat
.
Hopefully they don’t compress it again and break the new URL! A more
permanent solution is discussed at:
#454skyfield.hipparcos
and skyfield.named_stars
that broke because the Hipparcos catalog is no longer compressed;
hopefully no one was using them.Timescale()
and Time()
objects now offer support for the
Julian calendar that’s used by historians for dates preceding the
adoption of the Gregorian calendar in 1582. See Ancient and modern dates
if you want to turn on Julian dates in your application.
#450compute_calendar_date()
which lets the
caller choose the Julian calendar for ancient dates instead of always
using the proleptic Gregorian calendar. This should be particularly
useful for historians.J()
that builds a time array
from an array of floating point years.
#436strftime
methods for the non-UTC timescales
(#443).
All four of them support %f
for microseconds,
and provide a reasonable default format string
for callers who don’t wish to concoct their own:
planetary_magnitude()
can
now return magnitudes for Uranus without raising an exception. The
routine does not yet take into account whether the observer is facing
the equator or poles of Uranus, so the magnitude predicted for the
planet will only be accurate to within about 0.1 magnitudes.timescale()
is called
(unless the builtin=True
parameter is provided). To make Skyfield
less fragile going forward:timescale()
method now
defaults to builtin=True
, telling it to use the ∆T and leap
second files that ship with Skyfield internally. To download new
∆T files from NASA and the leap second file from the International
Earth Rotation Service, specify builtin=False
.load()
.
Skyfield is now much simpler: if a file with the correct name
exists, Skyfield uses it. See UT1 and downloading IERS data
if you still want your application to check the age of your
timescale files and automatically download new ones.ICRF.separation_from()
method now officially supports the
combination of an array of positions with a single reference position!
Its previous support for that combination was, alas, accidental, and
was broken with the 1.23 release.
#414
#424planetary_magnitude()
routine has been added with support for several planets.
#210utc
timezone that Skyfield returns in Python datetimes is now
either the Python Standard Library’s own UTC object, if it supplies
one, or else is defined by Skyfield itself. Skyfield no longer
silently tries importing the whole pytz
package merely to use its
UTC object — which also means that the timezone returned by Skyfield
longer offers the non-standard localize()
method.
#413parse_constellations()
and parse_star_names()
to load Stellarium star names and constellation lines.
Constellation lines are featured in a new example script
Drawing a finder chart for comet NEOWISE that produces a finder chart
for comet C/2020 F3 NEOWISE.utc()
to
accept a Python datetime.date
object as its argument.
#409from_datetime()
and
from_datetimes()
to the
Timescale
class, to better advertise the
ability to build a Skyfield time from a Python datetime
— an ability
that was previously overloaded into the year
parameter of the
utc()
method (where it is still
supported for backwards compatibility, but no longer documented).is_behind_earth()
to
determine whether a celestial object is blocked from an Earth
satellite’s view by the Earth itself.rough_period
search
parameter with the conceptually simpler step_days
parameter, and
updated the instructions in Searching for the dates of astronomical events to match.tle_file()
import method less
strict about Earth satellite names: any text on the line before two
lines of TLE data is now saved as the satellite name. A parameter
skip_names=True
turns this off if, for particular TLE files, this
leads to unwanted text being saved.Time
array.build_url()
that returns the URL
from which Skyfield will download a file.
#382close()
to support
applications that need to do fine-grained resource management or whose
testing framework check for dangling open files.
#374Module not found
error
when importing jplephem.exceptions
if a user had an old “jplephem”
version already installed.
#386is_sunlit()
to determine
whether Earth satellites in orbit are in Earth’s shadow or not, thanks
to a pull request from Jesse Coffey.position_of_radec()
to replace the poorly designed position_from_radec()
.Time
objects now have microsecond
internal accuracy, so round trips to and from Python datetimes should
now preserve all the microsecond digits.utc_strftime()
method now rounds to
the nearest minute or second if it sees that either minutes or seconds
are the smallest unit of time in the format string.t.utc
can now be accessed by the
attribute names year
, month
, day
, hour
, minute
,
and second
.elevation_m
argument to
build_latlon_degrees()
.SSL: CERTIFICATE_VERIFY_FAILED
errors that
some users encounter when downloading timescale files, Skyfield has
taken the risk of switching away from your system’s SSL certificates
to the certificate bundle from the certifi
package.
#317itrf_xyz()
method that returns their raw ITRF coordinates.
#354load.tle()
in favor of a simple list returned by the new
tle_file()
routine.
#345find_discrete()
routine no
longer returns extraneous values in its second return value if no
changes of state were found.
#339
#351sgp4
Python library that, when
possible, uses the fast official C++ implementation of SGP4.find_events()
Earth
satellite method that finds the times at which a satellite rises,
culminates, and sets.utc_strftime()
method so it
does not report that every day in all of recorded history is a Monday.
#335oppositions_conjunctions()
for finding
the dates when a planet is at opposition and conjunction with the sun.position_angle_of()
for computing
astronomical position angles.dark_twilight_day()
function that
not only handles sunrise and sunset but also all three kinds of
twilight.
#225risings_and_settings()
function for
computing rising and setting times.
#271load_constellation_map()
.position_from_radec()
function.apparent()
method in the case where a single observer
position is observing an entire vector of target positions.
#229Loader
pointed
at a Windows directory for which Python’s os.makedirs()
function
returned a spurious error.
#283reverse_terra()
routine can now be given an
iterations=0
argument if the caller wants geocentric latitude and
longitude.load.timescale(builtin=True)
to use time scale
files that Skyfield carries internally, instead of downloading them.
Note that the time scale files distributed with any given version of
Skyfield will gradually fall out of date.Star
method from_dataframe()
now correctly pulls
stellar parallax data from the dataframe if available.
#266find_discrete()
was generating empty
arrays of search dates, upsetting the astronomy code, if the start and
end dates were very close together.
#240deltat.preds
, whose change in format caused Skyfield to start
throwing an exception for new users.
#236seasons()
to the Almanac Computation module
that can be used to predict solstices and equinoxes.ValueError:
too many values to unpack
if they are passed a time array.
#207
#208cirs_xyz()
and
cirs_radec()
have been contributed
which provide support for rotating a position into the Celestial
Intermediate Reference System (CIRS).
#192ecliptic_latlon()
method.osculating_elements_of()
.load()
routine have been fixed.
#193
#194open()
and
tle()
now accept not just URLs but also plain local file paths;
they correctly re-download a remote file if “reload=True” is
specified; and they allow specifying a different local “filename=”
than the one at the end of the URL.…_jd()
.subpoint()
method
now normalizes the longitude values it returns
into the range −180° to 180°
#182
and returns an actual elevation instead of zero.
#185ITRF_position_velocity_error()
method that returns raw ITRF coordinates for users interested in them.
#85Time
objects as .J
.Time
objects as .dut1
.
#176subpoint()
method that computes the latitude and longitude
of the point beneath that body.Timescale
time constructor methods now accept arrays.deltat.preds
,
since the file has gone out of date at the USNO site.Star
to be initialized with a tuple that breaks units into minutes and seconds
(broke in version 1.2).load_file()
a leading ~
now means “your home directory”.Velocity(km_per_s=...)
.to_skycoord()
.EarthSatellite()
instead of having it trying to load one itself.topos()
method in favor of vector addition.satellite()
method in favor of vector addition.geometry_of()
method in favor of vector subtraction.load.tle(url_or_filename)
.observe()
method of an observer on the Earth’s surface now
correctly accounts for the way that the Earth’s gravity will deflect
the apparent position of objects that are not exactly overhead,
bringing Skyfield’s agreement with the Naval Observatory’s NOVAS
library to within half a milliarcsecond.tt_calendar()
method no longer raises a
TypeError
when its value is an array.repr()
on a Time
array now produces a more compact
string that only mentions the start and end of the time period.api.load()
call no longer attempts to animate a progress bar
if the user is running it under IDLE, which would try to accumulate
the updates as a single long line that eventually hangs the window.ICRF.separation_from()
computes the angular separation
between two positions.==
between Time
objects and other unrelated objects so
that it no longer raises an exception.Introduced the Timescale
object with methods utc()
, tai()
,
tt()
, and tdb()
for building time objects, along with a
load.timescale()
method for building a new Timescale
. The
load method downloads ∆T and leap second data from official data
sources and makes sure the files are kept up to date. This replaces
all former techniques for building and specifying dates and times.
Renamed JulianDate
to Time
and switched from jd
to t
as the typical variable used for time in the documentation.
Deprecated timescale keyword arguments like utc=(…)
for both the
Time
constructor and also for all methods that take time as
an argument, including Body.at()
and Topos.at()
.
Users who want to specify a target directory when downloading a file will now create their own loader object, instead of having to specify a special keyword argument for every download:
load = api.Loader('~/ephemeris-files')
load('de421.bsp')
Users can now supply a target directory
when downloading a file:
load('de421.bsp', directory='~/ephemerides')
Fix: removed inadvertent dependency on the Pandas library.
Fix: load()
was raising a PermissionError
on Windows after a
successful download when it tried to rename the new file.
delta_t
if the user
does not supply their own delta_t=
keyword when specifying a date.
This should make altitude and azimuth angles much more precise.Skyfield has dropped the 16-megabyte JPL ephemeris DE421 as an install
dependency, since users might choose another ephemeris, or might not
need one at all. You now ask for a SPICE ephemeris to be downloaded
at runtime with a call like planets = load('de421.bsp')
.
Planets are no longer offered as magic attributes, but are looked up
through the square bracket operator. So instead of typing
planets.mars
you should now type planets['mars']
. You can run
print(planets)
to learn which bodies an ephemeris supports.
body.at(t)
instead of body(t)
.Per IAU 2012 Resolution B2, Skyfield now uses lowercase au for the
astronomical unit, and defines it as exactly 149 597 870 700 meters.
While this API change is awkward for existing users, I wanted to make
the change while Skyfield is still pre-1.0. If this breaks a program
that you already have running, please remember that a quick pip
install
skyfield==0.4
will get you up and running again until
you have time to edit your code and turn AU
into au
.
astimezone()
and utc_datetime()
methods
have been changed to return only a datetime
object.
If you also need a leap second flag returned,
call the new methods
astimezone_and_leap_second()
and utc_datetime_and_leap_second()
.a.radians
, a.degrees
, and a.hours
are now attributes instead of method calls.