I'm teaching tides in a Waves and Tides course and, every now and then, I find myself creating new figures to show the students. This post is to show how I created a "moon phase path" using pyephem. The final plot was based on this example.
Just for fun I'll find the city we are in using the machine IP instead of specifying the longitude and latitude. The function below returns the IP.
import re
import urllib
def get_ip(url='http://checkip.dyndns.org'):
request = urllib.urlopen(url).read().decode('utf-8')
return re.findall(r"\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}", request)[0]
Now, to find the city, we need the GeoLiteCity database and the GeoIP module.
from pygeoip import GeoIP
def get_location(ip, fname='./data/GeoLiteCity.dat'):
"""Database can be downloaded at:
http://dev.maxmind.com/geoip/legacy/geolite/"""
gi = GeoIP(fname)
location = gi.record_by_addr(ip)
return location
ip = get_ip()
location = get_location(ip)
location
PyEphem main object is the Observer
class. We need to "feed it" with our
position and date. Also, since we are interested in Earth's natural satellite,
we will start a moon
object as well.
import ephem
import numpy as np
from datetime import datetime
date = datetime.utcnow()
moon = ephem.Moon()
obs = ephem.Observer()
obs.date = date
obs.lon = np.deg2rad(location['longitude'])
obs.lat = np.deg2rad(location['latitude'])
We can print some information like rising times, and next full moon date.
print("Next full Moon: %s" % ephem.next_full_moon(date))
print("Previous rising: %s" % obs.previous_rising(moon))
print("Next rising: %s" % obs.next_rising(moon))
Now let's loop over one day saving the azimuth, altitude, hour, and a symbol for the moon phase.
az, alt, symbols, times = [], [], [], []
for k in range(24):
moon.compute(obs)
nnm = ephem.next_new_moon(obs.date)
pnm = ephem.previous_new_moon(obs.date)
lunation = (obs.date - pnm) / (nnm - pnm)
symbol = lunation * 26
if symbol < 0.2 or symbol > 25.8:
symbol = '1'
else:
symbol = chr(ord('A') + int(symbol + 0.5) - 1)
times.append(ephem.localtime(obs.date).time().strftime("%H:%M"))
symbols.append(symbol)
alt.append(moon.alt)
az.append(moon.az)
obs.date += ephem.hour
az, alt = map(np.rad2deg, (az, alt))
Finally, we can plot the figure with the moon path.
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
prop = FontProperties(fname='./data/moon_phases.ttf', size=25)
fig, ax = plt.subplots()
offset = 20
ax.set_xlim(0-10, 360+30)
ax.set_ylim(-90-5, 90+5)
[ax.text(x, y, text, fontproperties=prop, alpha=0.3, zorder=1)
for x, y, text in zip(az, alt, symbols)]
[ax.text(x, y, hour, fontdict=dict(size=11, weight='bold'), zorder=0, color='r')
for x, y, hour in zip(az, alt, times)]
ax.set_xlabel("Azimuth (compass direction, in degrees)")
ax.set_ylabel("Elevation (degrees above horizon)")
The font moon_font.ttf
convert the symbol we crated into a nice moon phase
icon.
HTML(html)