import matplotlib.pyplot as plt import numpy as np from .common import GraphCommand class Command(GraphCommand): def handle(self, *args, **options): infos = {} for i in range(7): for j in range(24): infos[(i, j)] = 0 def hour_shift(x): x = x - 4 if x < 0: x += 24 return x for commit in self.get_events(options): coords = ( self.get_event_datetime(commit, options).weekday(), hour_shift(self.get_event_datetime(commit, options)).hour)) infos[coords] = infos[coords] + 1 draw_punchcard(infos, ax2_ticks=list(range(4, 24)) + list(range(4))) self.plot(options) # 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)