Skip to content

Instantly share code, notes, and snippets.

@ahojnnes
Last active December 24, 2015 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahojnnes/6805841 to your computer and use it in GitHub Desktop.
Save ahojnnes/6805841 to your computer and use it in GitHub Desktop.
import urllib
import json
import copy
from collections import OrderedDict
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import dateutil.parser
from dateutil.relativedelta import relativedelta
from datetime import datetime, timedelta
cache = '_pr_cache.txt'
# Obtain release dates using, e.g.,
#
# git log v0.4 -n 1 --format='%ai'
#
# The first two releases are commented out.
# This was in the era before PRs.
#
releases = OrderedDict([
#('0.1', u'2009-10-07 13:52:19 +0200'),
#('0.2', u'2009-11-12 14:48:45 +0200'),
('0.3', u'2011-10-10 03:28:47 -0700'),
('0.4', u'2011-12-03 14:31:32 -0800'),
('0.5', u'2012-02-26 21:00:51 -0800'),
('0.6', u'2012-06-24 21:37:05 -0700'),
('0.7', u'2012-09-29 18:08:49 -0700'),
('0.8', u'2013-03-04 20:46:09 +0100')])
month_duration = 24
for r in releases:
releases[r] = dateutil.parser.parse(releases[r])
def fetch_PRs(user='scikit-image', repo='scikit-image', state='open'):
params = {'state': state,
'per_page': 100,
'page': 1}
data = []
page_data = True
while page_data:
config = {'user': user,
'repo': repo,
'params': urllib.urlencode(params)}
fetch_status = 'Fetching page %(page)d (state=%(state)s)' % params + \
' from %(user)s/%(repo)s...' % config
print(fetch_status)
f = urllib.urlopen(
'https://api.github.com/repos/%(user)s/%(repo)s/pulls?%(params)s' \
% config
)
params['page'] += 1
page_data = json.loads(f.read())
if 'message' in page_data and page_data['message'] == "Not Found":
page_data = []
print('Warning: Repo not found (%(user)s/%(repo)s)' % config)
else:
data.extend(page_data)
return data
try:
PRs = json.loads(open(cache, 'r').read())
print('Loaded PRs from cache...')
except IOError:
PRs = fetch_PRs(user='stefanv', repo='scikits.image', state='closed')
PRs.extend(fetch_PRs(state='open'))
PRs.extend(fetch_PRs(state='closed'))
cf = open(cache, 'w')
cf.write(json.dumps(PRs))
cf.flush()
nrs = [pr['number'] for pr in PRs]
print('Processing %d pull requests...' % len(nrs))
dates = [dateutil.parser.parse(pr['created_at']) for pr in PRs]
epoch = datetime(2009, 1, 1, tzinfo=dates[0].tzinfo)
def seconds_from_epoch(dates):
seconds = [(dt - epoch).total_seconds() for dt in dates]
return seconds
dates_f = seconds_from_epoch(dates)
def date_formatter(value, _):
dt = epoch + timedelta(seconds=value)
return dt.strftime('%Y/%m')
plt.figure(figsize=(7, 5))
now = datetime.now(tz=dates[0].tzinfo)
this_month = datetime(year=now.year, month=now.month, day=1,
tzinfo=dates[0].tzinfo)
bins = [this_month - relativedelta(months=i) \
for i in reversed(range(-1, month_duration))]
bins = seconds_from_epoch(bins)
n, bins, _ = plt.hist(dates_f, bins=bins)
n_max = n.max()
ax = plt.gca()
ax.xaxis.set_major_formatter(FuncFormatter(date_formatter))
ax.set_xticks(bins[:-1])
labels = ax.get_xticklabels()
for l in labels:
l.set_rotation(40)
l.set_size(10)
seconds_per_day = 24 * 60 * 60
for version, date in releases.items():
date = seconds_from_epoch([date])[0]
plt.axvline(date, color='r')
plt.text(date + 15 * seconds_per_day, n_max - 0.9 * n_max, version,
rotation=90, color='red', fontsize=11, fontweight='bold')
ax.spines['left'].set_color('blue')
ax.yaxis.label.set_color('blue')
ax.tick_params(axis='y', colors='blue')
plt.title('Pull request activity').set_y(1.05)
plt.xlabel('Date')
plt.ylabel('PRs per month')
plt.subplots_adjust(top=0.875, bottom=0.225)
import numpy as np
cumulative = np.cumsum(n)
cumulative += len(dates) - cumulative[-1]
ax2 = plt.twinx()
ax2.plot(bins[:-1], cumulative, 'black', linewidth=2)
ax2.set_ylabel('Total PRs')
plt.savefig('PRs.png')
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment