Skip to content

Instantly share code, notes, and snippets.

@monstermunchkin
Created January 6, 2012 23:24
Show Gist options
  • Save monstermunchkin/1572974 to your computer and use it in GitHub Desktop.
Save monstermunchkin/1572974 to your computer and use it in GitHub Desktop.
Graph which shows sunrise and sunset times
# This program plots a graph with sunrises and sunsets.
#
# Copyright (C) 2012 Thomas Hipp
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
import calendar
import datetime
import re
import urllib.parse
import urllib.request
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
def yaxis_fmt(y, pos=None):
"""Return format %H:%M.
Positional arguments:
y -- y position on graph
Keyword arguments:
pos -- position
"""
dm = divmod(int(y), 100)
return datetime.time(dm[0], round(dm[1] * .6)).strftime('%H:%M')
def get_sun_table(place, year, longitude, latitude, timezone, months):
"""Return sun table.
Positional arguments:
place -- name of the place
longitude -- 3-tuple containing ([E|W], degrees, minutes)
latitude -- 3-tuple containing ([N|S], degrees, minutes)
timezone -- x hours from GMT
"""
data = urllib.request.urlopen(''.join([
'http://aa.usno.navy.mil/cgi-bin/aa_rstablew.pl?FFX=2&xxy={0}&type=0',
'&place={1}&xx0={2}&xx1={3[0]}&xx2={3[1]}&yy0={4}&yy1={5[0]}',
'&yy2={5[1]}&zz1={6}&zz0={7}&ZZZ=END']).format(
year,
urllib.parse.quote(place),
1 if longitude[0] == 'E' else 0,
longitude[1:],
1 if latitude[0] == 'N' else 0,
latitude[1:],
abs(timezone),
1 if timezone > 0 else -1
)).read().decode('ISO-8859-1').split('\n')
data = [x[4:] for x in list(filter(lambda x: re.match('\d{2}', x), data))]
tab = [0] * 12
for i in range(12):
sridx = i * 11
ssidx = sridx + 5
tab[i] = [0] * months[i]
for k in range(months[i]):
# map 0..60 to 0..100
dmsr = divmod(int(data[k][sridx:sridx + 4]), 100)
dmss = divmod(int(data[k][ssidx:ssidx + 4]), 100)
tab[i][k] = (dmsr[0] * 100 + (dmsr[1] * 10 / 6),
dmss[0] * 100 + (dmss[1] * 10 / 6))
return tab
def plot_year(suntab, location, year, months):
"""Plot sunrises and sunsets over a year.
Positional arguments:
suntab -- sun table returned by get_sun_table
location -- location string which will be the image's title
year -- year
"""
def xaxis_fmt(x, pos=None):
"""Return format %b.
Positional arguments:
x -- x position on graph
Keyword arguments:
pos -- position
"""
return (datetime.date(year, 1, 1) +
datetime.timedelta(days=int(x))).strftime('%b')
xticks = [sum(months[:x]) for x in range(13)]
# round to full hour
earliest = int(min([int(y[0]) for x in suntab for y in x]) / 100) * 100
latest = int(max([int(y[1]) for x in suntab for y in x]) / 100 + 1) * 100
ax1 = plt.subplot2grid(
(3, 6),
(0, 0),
colspan=6,
xticks=xticks,
yticks=range(earliest, latest, 100))
ax1.axis([0, sum(months) - 1, earliest, latest])
ax1.set_color_cycle(['b', 'g'])
ax1.grid(True)
ax1.set_title('{0} - {1}\n\n'.format(location, year), size=30,
weight='bold')
ax1.xaxis.set_major_formatter(tick.FuncFormatter(xaxis_fmt))
ax1.yaxis.set_major_formatter(tick.FuncFormatter(yaxis_fmt))
# make graph continuous
for i in range(11):
ax1.plot(range(xticks[i], xticks[i + 1] + 1),
suntab[i] + [suntab[i + 1][0]])
ax1.plot(range(xticks[11], xticks[12]), suntab[11])
return ax1
def plot_month(suntab, month):
"""Plot sunrises and sunsets over a month.
Positional arguments:
suntab -- sun table returned by get_sun_table
month -- month as int where 0 and 11 are January and December respectively
"""
xticks = range(1, len(suntab[month]) + 1)
# sunrise
earliest = min([int(x[0]) for x in suntab[month]])
latest = max([int(x[0]) for x in suntab[month]])
pos = divmod(month, 6)
ax1 = plt.subplot2grid(
(3, 6),
(pos[0] + 1, pos[1]),
xticks=xticks,
yticks=range(earliest, latest, 5))
ax1.axis([1, len(suntab[month]), earliest, latest])
ax1.grid(True)
ax1.set_title(
'{0}\n'.format(datetime.date(1970, month + 1, 1).strftime('%B')),
size=20)
ax1.set_ylabel('sunrise', color='b')
ax1.xaxis.set_major_formatter(tick.FuncFormatter(lambda x, y: x))
ax1.yaxis.set_major_formatter(tick.FuncFormatter(yaxis_fmt))
for tl in ax1.get_yticklabels():
tl.set_color('b')
ax1.plot(xticks, [x[0] for x in suntab[month]], 'b-')
# sunset
ax2 = ax1.twinx()
earliest = min([int(x[1]) for x in suntab[month]])
latest = max([int(x[1]) for x in suntab[month]])
ax2.set_xticks(xticks)
ax2.set_yticks(range(earliest, latest, 5))
ax2.axis([1, len(suntab[month]), earliest, latest])
ax2.grid(True)
ax2.set_ylabel('sunset', color='g')
ax2.xaxis.set_major_formatter(tick.FuncFormatter(lambda x, y: x))
ax2.yaxis.set_major_formatter(tick.FuncFormatter(yaxis_fmt))
for tl in ax2.get_yticklabels():
tl.set_color('g')
ax2.plot(xticks, [x[1] for x in suntab[month]], 'g-')
return ax1
def main(**kwargs):
year = kwargs.get('year')
location = kwargs.get('location')
longitude = kwargs.get('longitude')
latitude = kwargs.get('latitude')
timezone = kwargs.get('timezone')
size = kwargs.get('size')
output = kwargs.get('output')
if calendar.isleap(year):
months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
else:
months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
data = get_sun_table(location, year, longitude, latitude, timezone,
months)
ax = [plot_year(data, location, year, months)]
for i in range(12):
ax.append(plot_month(data, i))
fig = plt.gcf()
fig.title = '{0} - {1}'.format(location, year)
fig.set_size_inches(size[0], size[1])
plt.savefig(output, dpi=size[2],
orientation='landscape', bbox_inches='tight')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=' '.join(
['Generate graph which shows the sunrises',
'and sunsets over a year']))
parser.add_argument('--year', default=datetime.date.today().year,
type=int)
parser.add_argument('--location', default='Unknown location',
type=str, help='Name of the location')
parser.add_argument('--longitude', nargs=3,
required=True, help='Longitude, e.g. E 18 25',
metavar=('orientation', 'minute', 'second'))
parser.add_argument('--latitude', nargs=3,
required=True, help='Latitude, e.g. S 33 55',
metavar=('orientation', 'minute', 'second'))
parser.add_argument('--timezone', type=int, required=True,
help='GMT timezone, e.g. 3 or -4')
parser.add_argument('--size', nargs=3, default=[75, 25, 80], type=int,
help='height and width in inches',
metavar=('height', 'width', 'dpi'))
parser.add_argument('--output', default='sungraph.png', type=str,
help='Output')
args = parser.parse_args()
main(**vars(args))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment