import io from collections.__init__ import defaultdict from datetime import timedelta import numpy as np from django.http import HttpResponse from django.views.generic import DetailView from web.models import User, ActivityLog, Activity class UserChartsPie(DetailView): model = User pk_url_kwarg = 'user_id' def render_to_response(self, context, **response_kwargs): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt fig = plt.figure(figsize=(6, 6), dpi=100) ax = fig.add_subplot(111) total_time = defaultdict(float) logs = ActivityLog.objects.filter(user=self.object).all() for log in logs: total_time[str(log.activity)] += (log.end_time - log.start_time).total_seconds() sectors = sorted(list(total_time.items()), key=lambda x: x[1]) ax.pie(x=[i[1] for i in sectors], labels=[i[0] for i in sectors]) buf = io.BytesIO() fig.savefig(buf, format='png') b = buf.getvalue() return HttpResponse(b, content_type='image/png') class UserChartsActivityAll(DetailView): model = User pk_url_kwarg = 'user_id' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['activity'] = Activity.objects.filter(id=self.kwargs['activity_id']).first() return context def bar_chart(self, plt, ax, logs, day_l, day_r, day_count, days): day_seconds = np.zeros(day_count) for log in logs: for i, day in enumerate(days): l = max(log.start_time, day) r = min(log.end_time, day + timedelta(days=1)) if r > l: day_seconds[i] += (r - l).total_seconds() day_hours = day_seconds / timedelta(hours=1).total_seconds() ax.bar(days, day_hours) plt.xticks(days, [f'{i:%m-%d}' for i in days], rotation=60) plt.ylabel('кол-во часов') def tracker_chart(self, plt, ax, logs, day_l, day_r, day_count, days): ys = [] widths = [] lefts = [] for log in logs: for i, day in enumerate(days): l = max(log.start_time, day) r = min(log.end_time, day + timedelta(days=1)) if r > l: ys.append(day) widths.append((r - l) / timedelta(hours=1)) lefts.append((l - day) / timedelta(hours=1)) ax.barh(y=ys, width=widths, left=lefts, zorder=2) plt.xlim(0, 24) plt.xticks(range(24), [f'{i:02d}:00' for i in range(24)]) plt.yticks(days, [f'{i:%m-%d}' for i in days]) plt.grid(True, zorder=1) def render_to_response(self, context, **response_kwargs): logs = list(ActivityLog.objects.filter(user=self.object, activity=context['activity']).order_by('start_time').all()) day_r = logs[-1].end_time.replace(hour=0, minute=0, second=0, microsecond=0) day_l = max( logs[0].start_time.replace(hour=0, minute=0, second=0, microsecond=0), day_r - timedelta(days=14) ) day_count = (day_r - day_l) // timedelta(days=1) + 1 days = [day_l + timedelta(days=1) * i for i in range(day_count)] import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt fig = plt.figure(figsize=(16, 12), dpi=100) ax = fig.add_subplot(211) self.bar_chart(plt, ax, logs, day_l, day_r, day_count, days) ax = fig.add_subplot(212) self.tracker_chart(plt, ax, logs, day_l, day_r, day_count, days) buf = io.BytesIO() fig.savefig(buf, format='png') b = buf.getvalue() return HttpResponse(b, content_type='image/png') class UserActivityChartsTracker(DetailView): model = User pk_url_kwarg = 'user_id' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['activity'] = Activity.objects.filter(id=self.kwargs['activity_id']).first() return context def render_to_response(self, context, **response_kwargs): print('start_tracker') import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt fig = plt.figure(figsize=(16, 6), dpi=100) ax = fig.add_subplot(111) logs = list(ActivityLog.objects.filter(user=self.object, activity=context['activity']).order_by('start_time').all()) day_r = logs[-1].end_time.replace(hour=0, minute=0, second=0, microsecond=0) day_l = max( logs[0].start_time.replace(hour=0, minute=0, second=0, microsecond=0), day_r - timedelta(days=14) ) day_count = (day_r - day_l) // timedelta(days=1) + 1 days = [day_l + timedelta(days=1) * i for i in range(day_count)] buf = io.BytesIO() fig.savefig(buf, format='png') b = buf.getvalue() return HttpResponse(b, content_type='image/png')