add punchcard graphic
Graphing code adapted from https://stackoverflow.com/a/14850998
This commit is contained in:
parent
cb4a7ef263
commit
7c3fdf5007
|
@ -0,0 +1,92 @@
|
|||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.dateparse import parse_date
|
||||
|
||||
from eodb.events.models import Commit
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--username', metavar='USERNAME')
|
||||
parser.add_argument('--datemin', metavar='DATEMIN')
|
||||
parser.add_argument('--datemax', metavar='DATEMAX')
|
||||
parser.add_argument('--committime', action='store_true',
|
||||
help='use commit datetime instead of author datetime')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
infos = {}
|
||||
for i in range(7):
|
||||
for j in range(24):
|
||||
infos[(i, j)] = 0
|
||||
|
||||
filters = {'author_email__endswith': '@entrouvert.com'}
|
||||
|
||||
title = 'Git activity'
|
||||
|
||||
if options.get('username'):
|
||||
filters['author_email__startswith'] = options['username'] + '@'
|
||||
title += ' for %s' % options['username']
|
||||
|
||||
datetime_var = 'author_datetime'
|
||||
if options.get('committime'):
|
||||
datetime_var = 'commit_datetime'
|
||||
if options.get('datemin'):
|
||||
filters[datetime_var + '__gte'] = parse_date(options['datemin'])
|
||||
title += ' from %s' % options['datemin']
|
||||
if options.get('datemax'):
|
||||
filters[datetime_var + '__lt'] = parse_date(options['datemax'])
|
||||
title += ' until %s' % options['datemax']
|
||||
|
||||
for commit in Commit.objects.filter(**filters):
|
||||
coords = (getattr(commit, datetime_var).weekday(), getattr(commit, datetime_var).hour)
|
||||
infos[coords] = infos[coords] + 1
|
||||
|
||||
draw_punchcard(infos)
|
||||
plt.title(title)
|
||||
plt.show()
|
||||
|
||||
# https://stackoverflow.com/a/14850998
|
||||
def draw_punchcard(infos,
|
||||
ax1=range(7),
|
||||
ax2=range(24),
|
||||
ax1_ticks=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
ax2_ticks=range(24),
|
||||
ax1_label='Day',
|
||||
ax2_label='Hour'):
|
||||
# - infos: Dictionary of quantities to display.
|
||||
# They are indexed by key of type (val1,val2) with
|
||||
# val1 included in ax1 and val2 included in ax2.
|
||||
|
||||
# build the array which contains the values
|
||||
data = np.zeros((len(ax1),len(ax2)))
|
||||
for key in infos:
|
||||
data[key[0],key[1]] = infos[key]
|
||||
data = data/float(np.max(data))
|
||||
|
||||
# shape ratio
|
||||
r = float(data.shape[1])/data.shape[0]
|
||||
|
||||
# Draw the punchcard (create one circle per element)
|
||||
# Ugly normalisation allows to obtain perfect circles instead of ovals....
|
||||
for y in range(data.shape[0]):
|
||||
for x in range(data.shape[1]):
|
||||
circle = plt.Circle((x/float(data.shape[1]-1)*(data.shape[0]-1),y/r),
|
||||
data[y][x]/float(data.shape[1])*data.shape[0]/2)
|
||||
plt.gca().add_artist(circle)
|
||||
|
||||
plt.ylim(0-0.5, data.shape[0]-0.5)
|
||||
plt.xlim(0, data.shape[0])
|
||||
plt.yticks(np.arange(0,len(ax1)/r-.1,1/r), ax1_ticks)
|
||||
xt = np.linspace(0, len(ax1)-1, len(ax2))
|
||||
plt.xticks(xt, ax2_ticks)
|
||||
plt.xlabel(ax2_label)
|
||||
plt.ylabel(ax1_label)
|
||||
plt.gca().invert_yaxis()
|
||||
|
||||
# make sure the axes are equal, and resize the canvas to fit the plot
|
||||
plt.axis('equal')
|
||||
plt.axis([-1, 7, 7/r, -1])
|
||||
scale = 1 #0.5
|
||||
plt.gcf().set_size_inches(data.shape[1]*scale,data.shape[0]*scale, forward=True)
|
Reference in New Issue