Created
January 6, 2012 23:24
-
-
Save monstermunchkin/1572974 to your computer and use it in GitHub Desktop.
Graph which shows sunrise and sunset times
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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