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,
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:
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”
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
setup.py or install instructions:
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:
The Skyfield package offers a
that your code can use to test which version of Skyfield is running.
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.
http:in this URL to match papers already using it as an identifier): http://rhodesmill.org/skyfield/
oppositions_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
Trueif 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
Astrometricposition 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.datis downloaded, following a change in the domain for the University of Strasbourg from
.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. #739
load_comets_dataframe()so that parsing
CometEls.txtwith 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. #707
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. #662
to_skycoord()now sets the
frameattribute of the sky coordinate it returns, and for now only supports barycentric and geocentric positions. #577
timedeltawhich Skyfield interprets as TT days and seconds. #568
.itrs_xyzvector of the geographic position returned by the
de421.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.govFTP service is ever shut down — as happened earlier this year to FTP on NASA’s
planetary_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:
oppositions_conjunctions()routine, which was originally designed only for planets, can now also handle the Moon (which moves from opposition to conjunction much faster).
Angle.hstr()methods now accept a
format=argument that lets callers override Skyfield’s default angle formatting and supply their own; see Formatting angles. #513
planetary_magnitude()function now works not only when given a single position, but when given a vector of several positions.
TEMEreference 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.
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. #542
Creating 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.0where the resulting array needs a whole row of zeros. #536
hadec()position method that returns hour angle and declination. #510
repr()strings for geographic positions have been streamlined, and no longer raise
ValueErrorwhen 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
Angle.hstr()to return an array of strings when the angle itself is an array. #527
Toposclass, 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
wgs84object or the
iers2010object. Related discussion: #372
iers2010have also provided a happy new home for the
subpoint()method — which was previously stranded over on the
Geocentricclass, 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.)
utc_jpl()method now correctly designates its return value as
UTCinstead of the ambiguious
from_time_and_frame_vectors()that work with a new library
skyfield.framelibto 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. #476
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. #282
moon_nodes()to index into the
MOON_NODESlist that provides a name for each node. #486
magnitude_Gin the Minor Planet Center comets dataframe have been renamed
magnitude_kfollowing further research on the file format (which does not itself document which magnitude model is intended). #416
load.timescale(builtin=False)was raising an exception
finals2000A.allfile was not already on disk, instead of downloading the file automatically. #477
lunar_eclipses()routine finds lunar eclipses and determines their degree of totality. #445
meridian_transits()routine can find the moments at which a body transits the meridian and antimeridian. #460
find_minima()function was ignoring its
numarguments and always using the default values instead. #475
.epochattribute of Earth satellite objects that were built using
from_satrec()was, alas, a half-day off. #466
y, which never worked properly anyway, have been deprecated and are now ignored.
finals2000A.allfor updated ∆T and leap seconds. The USNO is no longer updating the files
deltat.predsthat previous versions of Skyfield used, and the
cddis.nasa.govserver from which they were fetched will discontinue anonymous FTP on 2020 October 31. See UT1 and downloading IERS data. #452 #464
CometEls.txtnow includes the
referencecolumn, 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. #463
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
%jday-of-year format code.
print()statement was stranded in
Timeobject, if manually instantiated without a Julian date fraction, now provides a fraction array with dimensions that match the Julian date argument. #458
hip_main.dat.gzHipparcos 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: #454
skyfield.named_starsthat broke because the Hipparcos catalog is no longer compressed; hopefully no one was using them.
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. #450
compute_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. #436
strftimemethods for the non-UTC timescales (#443). All four of them support
%ffor 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=Trueparameter 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
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 #424
planetary_magnitude()routine has been added with support for several planets. #210
utctimezone 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
pytzpackage merely to use its UTC object — which also means that the timezone returned by Skyfield longer offers the non-standard
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.dateobject as its argument. #409
Timescaleclass, to better advertise the ability to build a Skyfield time from a Python
datetime— an ability that was previously overloaded into the
yearparameter 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_periodsearch parameter with the conceptually simpler
step_daysparameter, 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=Trueturns this off if, for particular TLE files, this leads to unwanted text being saved.
build_url()that returns the URL from which Skyfield will download a file. #382
close()to support applications that need to do fine-grained resource management or whose testing framework check for dangling open files. #374
Module not founderror when importing
jplephem.exceptionsif a user had an old “jplephem” version already installed. #386
is_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
Timeobjects 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.utccan now be accessed by the attribute names
SSL: CERTIFICATE_VERIFY_FAILEDerrors 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
itrf_xyz()method that returns their raw ITRF coordinates. #354
load.tle()in favor of a simple list returned by the new
find_discrete()routine no longer returns extraneous values in its second return value if no changes of state were found. #339 #351
sgp4Python 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. #335
oppositions_conjunctions()for finding the dates when a planet is at opposition and conjunction with the sun.
position_angle_of()for computing astronomical position angles.
Loaderpointed at a Windows directory for which Python’s
os.makedirs()function returned a spurious error. #283
reverse_terra()routine can now be given an
iterations=0argument 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.
from_dataframe()now correctly pulls stellar parallax data from the dataframe if available. #266
find_discrete()was generating empty arrays of search dates, upsetting the astronomy code, if the start and end dates were very close together. #240
deltat.preds, whose change in format caused Skyfield to start throwing an exception for new users. #236
cirs_radec()have been contributed which provide support for rotating a position into the Celestial Intermediate Reference System (CIRS). #192
load()routine have been fixed. #193 #194
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.
subpoint()method now normalizes the longitude values it returns into the range −180° to 180° #182 and returns an actual elevation instead of zero. #185
ITRF_position_velocity_error()method that returns raw ITRF coordinates for users interested in them. #85
subpoint()method that computes the latitude and longitude of the point beneath that body.
Timescaletime constructor methods now accept arrays.
deltat.preds, since the file has gone out of date at the USNO site.
Starto be initialized with a tuple that breaks units into minutes and seconds (broke in version 1.2).
~now means “your home directory”.
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.
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
TypeErrorwhen its value is an array.
Timearray 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.
Timeobjects and other unrelated objects so that it no longer raises an exception.
Timescale object with methods
tdb() for building time objects, along with a
load.timescale() method for building a new
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.
Time and switched from
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
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:
Fix: removed inadvertent dependency on the Pandas library.
load() was raising a
PermissionError on Windows after a
successful download when it tried to rename the new file.
delta_tif 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.
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
skyfield==0.4 will get you up and running again until
you have time to edit your code and turn
a.hoursare now attributes instead of method calls.