This map tracks the real time position of the International Space Station (ISS). It updates every 15 seconds.
Fanny Kassapian
2019/06/05
The ISS is the largest human-made body in low Earth orbit. It has been inhabited continously since November 2000. It currently counts ? residents:
All the data used to produce this map is retrieved dynamically thanks to the Open Notify APIs, a collection of NASA and space APIs for public use, developped by Nathan Bergey.
The country, sea or ocean names corresponding to the latitude and longitude coordinates returned by Open Notify are retrieved via the GeoNames APIs. The GeoNames geographical database covers all countries and contains over eleven million placenames that can be downloaded or accessed via their web services.
The source code behind this project (HTML, CSS, jQuery, JavaScript), can be found in my GitHub repository (iss.html).
For the same in Python, please refer to this Notebook (GitHub).
The map is built with Leaflet.js. For a basic setup, you can follow their quick start guide.
I used the World Imagery Basemap from ESRI as a tile layer on top of the map. All the free tile providers along with previews of the layers are available here.
I used a custom image (hand drawn with procreate) for the ISS marker, on top of a larger circle marker.
The map and markers are initialized with [0,0]
coordinates. These are updated with the latitude and longitude returned by the iss-now.json endpoint of the Open Notify API.
In these examples, Open Notify provides jQuery primers to make requests to its APIs.
I used the countrycode and ocean REST webservices to retrieve the country name or ocean/sea name of a given set of coordinates.
GeoNames data is free. The credit daily limit per application (identified by the parameter 'username') is of 20,000 requests. The hourly limit is of 1,000 requests.
The countryCode API takes the following parameters: lat (latitude), lng (longitude), type, lang, radius (buffer in km for closest country in coastal areas. Lang (to specify the language the country name should be in) and type (JSON or XML) are optional.
When we make a request to countrycode, the API returns a JSON with the countryCode
, countryName
, distance
and languages
as keys. If the API does not find a country name corresponding to the given set of coordinates, it returns the following: {'status': {'message': 'no country code found', 'value': 15}}
. Which is bound to happen a lot, since only 29% of Earth is land...
In this case, we make a request to the ocean API. It takes lat, lng and radius (optional) as parameters. It returns a JSON with ocean
as key, and a nested dictionary with distance
and name
as keys.
Again, we have to make sure that this is the actual response we get from the API (without raising an error), and if not, return a custom message to the user. Either the API cannot retrieve the corresponding country/ocean name based on the given coordinates, or the application has reached the rate limit.
// Request parameters
var parameters = {'lat': lat, 'lng': lon, 'type': 'JSON', 'radius':50, 'username':'user'};
// Request to countryCode endpoint
$.getJSON('http://api.geonames.org/countryCode?', parameters, function(data) {
// Initialize country variable
var country = '';
// Check if 'countryName' is a key in API response
if ('countryName' in data) {
// Extract value
country = data['countryName'];
// Update html
$("#country").html('The ISS is above ' + country + '!');
}
// If 'countryName' is NOT a key in data, make a request to the Ocean endpoint
else {
// Request parameters
var parameters = {'lat': lat, 'lng': lon, 'radius':1, 'username':'user'};
// Request to Ocean endpoint
$.getJSON('http://api.geonames.org/oceanJSON?', parameters, function(data) {
// Create ocean variable
var ocean = '';
// Check if 'ocean' is a key in API response
if ('ocean' in data) {
// Extract value
ocean = data['ocean']['name'];
// Update html
$("#country").html('The ISS is above the '+ ocean + '!');
}
// If the API response does not include 'ocean' as a key, return an error message
else {
$("#country").html("Oups! It looks like the GeoNames API is not responding.");
}
});
}
});