This is part two of a post for Naas-Sallins Coder Dojo about the International Space Station. We assume you have worked through part one and in particular have successfully installed the python libraries required. The install instructions for basemap and its dependencies are here and maybe here if you are on a Mac. Our intention is to use this library to plot the position of the ISS on a map using python. As the introduction to basemap says “the matplotlib basemap toolkit is a library for plotting 2D data on maps in Python.” It comes with a whole set of projections which are listed here. A projection is a way of representing the curved surface of the earth on a 2d map. If you click on any of the linked projections you will see the python code required to produce it and the map itself. The first thing we need to do is make sure that everything is installed ok, as is the tradition we will do this with a hello world program.
""" Hello World Check basemap is ok""" from mpl_toolkits.basemap import Basemap import numpy as np import matplotlib.pyplot as plt # lon_0, lat_0 are the center point of the projection. # resolution = 'l' means use low resolution coastlines. m = Basemap(projection='ortho',lon_0=-6,lat_0=53,resolution='l') m.drawcoastlines() m.fillcontinents(color='coral',lake_color='aqua') # draw parallels and meridians. m.drawparallels(np.arange(-90.,120.,30.)) m.drawmeridians(np.arange(0.,420.,60.)) m.drawmapboundary(fill_color='aqua') plt.title("Hello") plt.show()
This code is straight from the example for orthographic projections with the title changed to give us ‘Hello’ with the world underneath, and the latitude and longitude changed to center the map over Naas. Our next step is to find a way to plot a point on the map.
from mpl_toolkits.basemap import Basemap import numpy as np import matplotlib.pyplot as plt # use example cassini projection from basemap website map = Basemap(width=891185,height=1115557,resolution='i',projection='cass',lon_0=-4.36,lat_0=54.7) map.drawcoastlines() map.fillcontinents(color='coral',lake_color='aqua') # draw parallels and meridians. map.drawparallels(np.arange(-40,61.,2.)) map.drawmeridians(np.arange(-20.,21.,2.)) map.drawmapboundary(fill_color='aqua') plt.title("We are Here") x,y = map(-6.67, 53.22) map.plot(x, y, 'bo', markersize=12) plt.show()
So using the example cassini projection we added x,y = map(-6.67, 53.22) map.plot(x, y, ‘bo’, markersize=12) which sets the coordinates for the point we want to plot and then plots it on a map as a blue circle sized 12. This gives us
Now that we can plot a point, we want to use our code from before to get the current position of the ISS so that we have something like
""" plot the ISS""" import numpy as np from mpl_toolkits.basemap import Basemap import matplotlib.pyplot as plt from datetime import datetime import urllib2 import json def getiss(): """ call opennotify api""" response = urllib2.urlopen('http://api.open-notify.org/iss-now.json') mydata = response.read() return(mydata) iss = getiss() pos = json.loads(iss) lat = pos['iss_position']['latitude'] lon = pos['iss_position']['longitude'] # miller projection map = Basemap(projection='mill',lon_0=0) # plot coastlines, draw label meridians and parallels. map.drawcoastlines() map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0]) map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1]) # fill continents 'coral' (with zorder=0), color wet areas 'aqua' map.drawmapboundary(fill_color='aqua') map.fillcontinents(color='coral',lake_color='aqua') x,y = map(lon, lat) map.plot(x, y, 'bo', markersize=12) plt.show()
So this time we are using the json values returned by our getiss() function to plot the point on the map. At this stage we have an application which can draw the current position of the ISS on a map of the world which shows the power of the available python libraries. All that remains is to add some bells and whistles to our map and get it to update the position of the ISS. The code for this is below and it is mainly taken from the examples on the basemap website. We can discuss all this and play around with the various map projection options at the next few dojo sessions.
""" plot the ISS and update every 60 seconds""" import numpy as np from mpl_toolkits.basemap import Basemap import matplotlib.pyplot as plt from datetime import datetime import time import urllib2 import json def getiss(): """ call opennotify api""" response = urllib2.urlopen('http://api.open-notify.org/iss-now.json') mydata = response.read() return(mydata) while True: iss = getiss() pos = json.loads(iss) lat = pos['iss_position']['latitude'] lon = pos['iss_position']['longitude'] # miller projection map = Basemap(projection='mill',lon_0=0) # plot coastlines, draw label meridians and parallels. map.drawcoastlines() map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0]) map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1]) # fill continents 'coral' (with zorder=0), color wet areas 'aqua' map.drawmapboundary(fill_color='aqua') map.fillcontinents(color='coral',lake_color='aqua') # shade the night areas, with alpha transparency so the # map shows through. Use current time in UTC. date = datetime.now() CS=map.nightshade(date) plt.title('ISS Location For for %s Lat: %.2f Long: %.2f' % (date.strftime("%d %b %Y %H:%M:%S"),lat,lon)) x,y = map(lon, lat) map.plot(x, y, 'bo', markersize=12) plt.ion() plt.draw() plt.show(block=False) time.sleep(60) # --only update once per minute - dont be greedy with api plt.clf()
This code gives us a real time ISS tracker showing a map of the world with day/night shown that updates every minute.
To stop the app hit crtl-c in the command window where you started the application.
If the ISS is over land and it is daytime then you can have a look at a video stream of what it can see here.