Skip to content

Instantly share code, notes, and snippets.

@donno
Last active May 11, 2020 14:41
Show Gist options
  • Save donno/c17dd5bb2d1a06f2e54dcaf6fd0bc82c to your computer and use it in GitHub Desktop.
Save donno/c17dd5bb2d1a06f2e54dcaf6fd0bc82c to your computer and use it in GitHub Desktop.
Generate plots of my Internet usage
"""Generate monthly usage graphs for Internet usage.
Usage is classified as metered and unmetered.
Known issues
- There is excess padding before the first bar and after the last bar.
TODO
- Support quarterly and yearly graphs
"""
import calendar
import csv
import datetime
import itertools
import matplotlib.pyplot as plt
"""Our monthly billing period was the 7th which is when our quota would reset.
"""
month_start = 7
DEBUG = False
def read_usage():
with open('OurFullHistoryUsage.csv') as reader:
reader.readline()
for record in csv.reader(reader):
record[0] = datetime.date.fromisoformat(record[0])
record[1:] = [int(field) for field in record[1:]]
yield record
def month_key(record):
"""Treats records between the day that is the start of the month to the
day before that day of the next month as being in the month."""
adjusted_start = record[0] - datetime.timedelta(days=(month_start - 1))
return (adjusted_start.month, adjusted_start.year)
def plot(when, days, daily_usage_metered, daily_usage_unmetered):
"""Generate a plot of the usage for the period.
when: Describes when the data is for and is used as the tile.
days: List of days that appear on the plot.
daily_usage_metered: The daily metered usage in bytes.
daily_usage_unmetered: The daily unmetered usage in bytes.
days, daily_usage_metered and daily_usage_unmetered should all be the
same length.
"""
assert len(daily_usage_metered) == len(daily_usage_unmetered)
metered_colour = (254 / 255, 179 / 255, 118 / 255, 1.0)
unmetered_colour = (127 / 255, 165 / 255, 253 / 255, 1.0)
figure = plt.figure(figsize=(10, 5))
ax = figure.add_axes([0.09, 0.09, 1 - 0.08 - 0.02, 1 - 0.08 * 2])
if days:
# This assumes the day is for hte whole month, the first period will be
# wrong.
ind = list(range(month_start, month_start + len(daily_usage_metered)))
else:
ind = list(range(len(days)))
ax.bar(ind, daily_usage_metered, color=metered_colour)
ax.bar(ind, daily_usage_unmetered, bottom=daily_usage_metered,
color=unmetered_colour)
ax.set_ylabel('Mbytes')
ax.set_xlabel('Day')
ax.set_title('Mbytes per day for %s' % when)
ax.legend(labels=['Metred', 'Unmetred'])
plt.xticks(ind, days)
if DEBUG:
plt.show()
plt.savefig('charts/Usage ' + when + '.png')
plt.close(figure)
if __name__ == '__main__':
for (month, year), days in itertools.groupby(read_usage(), month_key):
when = calendar.month_name[month] + ' ' + str(year)
day_of_weeks = []
daily_usage_metered = []
daily_usage_unmetered = []
for day in days:
day_of_weeks.append(day[0].day)
daily_usage_metered.append(day[1] / 1024 / 1024)
daily_usage_unmetered.append(day[2] / 1024 / 1024)
plot(when, day_of_weeks, daily_usage_metered, daily_usage_unmetered)
if DEBUG:
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment