def heatmap(self, request: Request) -> Response: """Get the data to generate a heatmap for the volunteer. This includes one entry for every weekday and every hour containing the number of transcriptions made in that time slot. For example, there will be an entry for Sundays at 13:00 UTC, counting how many transcriptions the volunteer made in that time. The week days are numbered Monday=1 through Sunday=7. """ utc_offset = int(request.GET.get("utc_offset", "0")) # Construct a timezone from the offset tzinfo = datetime.timezone(datetime.timedelta(seconds=utc_offset)) heatmap = ( self.filter_queryset(Submission.objects).filter(complete_time__isnull=False) # Extract the day of the week and the hour the transcription was made in .annotate( day=ExtractIsoWeekDay("complete_time", tzinfo=tzinfo), hour=ExtractHour("complete_time", tzinfo=tzinfo), ) # Group by the day and hour .values("day", "hour") # Count the transcription made in each time slot .annotate(count=Count("id")) # Return the values .values("day", "hour", "count") # Order by day first, then hour .order_by("day", "hour") ) return Response(heatmap)
def values_by_direction(self): # Get all the count details for section and the year qs = CountDetail.objects.filter( id_lane__id_section__id=self.section_id, timestamp__year=self.year, # id_category__code__in=[1, 2], import_status=definitions.IMPORT_STATUS_DEFINITIVE, ) # Total by day of the week (0->monday, 7->sunday) and by direction result = qs.annotate(weekday=ExtractIsoWeekDay('timestamp')) \ .values('weekday') \ .annotate(total=Sum('times')) \ .values('weekday', 'id_lane__direction', 'total')
def values_by_day_of_week(self): # Get all the count details for section and the year qs = CountDetail.objects.filter( id_lane__id_section__id=self.section_id, timestamp__year=self.year, ) # TODO: don't divide by 51 but actually aggregate first by the # real days (with sum) and then aggregate by weekday (with average) # Group by day of the week (0->monday, 7->sunday) result = qs.annotate(weekday=ExtractIsoWeekDay('timestamp')) \ .values('weekday') \ .annotate(tjm=Sum('times') / 51) \ .values('weekday', 'tjm') return result
def values_by_day_and_month(self): # Get all the count details for section and the year qs = CountDetail.objects.filter( id_lane__id_section__id=self.section_id, timestamp__year=self.year, import_status=definitions.IMPORT_STATUS_DEFINITIVE, ) # TODO: don't divide by 12 but actually aggregate first by the # real days (with sum) and then aggregate by weekday (with average) # Total by day of the week (0->monday, 6->sunday) and by month (1->12) result = qs.annotate(weekday=ExtractIsoWeekDay('timestamp')) \ .annotate(month=ExtractMonth('timestamp')) \ .values('weekday', 'month') \ .annotate(tjm=Sum('times') / 12) \ .values('weekday', 'month', 'tjm') return result
def stats_order_heatmap(request): try: from_year = int(request.GET.get('from_year', 2022)) # TODO: improve filtering except ValueError: raise Http404("Året finns inte") orders = models.Order.objects.filter( accepted=True, put_at__year__gte=from_year).annotate( weekday=ExtractIsoWeekDay('put_at'), hour=ExtractHour("put_at"), minute=ExtractMinute("put_at"), ).annotate(quarter=Case( When(minute__gte=0, minute__lt=15, then=Value(0)), When(minute__gte=15, minute__lt=30, then=Value(15)), When(minute__gte=30, minute__lt=45, then=Value(30)), When(minute__gte=45, then=Value(45)), output_field=IntegerField(), )).filter(weekday__lt=6, hour__gte=8, hour__lte=16).values("weekday", "hour", "quarter").annotate( count=Count("id")).order_by("weekday", "hour", "quarter") data = DataFrame() weekdays = ["Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag"] for timepoint in orders: data.at[weekdays[timepoint["weekday"] - 1], time(timepoint["hour"], timepoint["quarter"])] = int( timepoint["count"]) sns.set_theme() plt.figure(figsize=(16, 9)) plot = sns.heatmap(data, cbar=False, cmap="YlGnBu") plot.figure.autofmt_xdate() buffer = BytesIO() plot.get_figure().savefig(buffer, format='png') buffer.seek(0) return FileResponse(buffer, filename='heatmap.png')
def get_queryset(self): calendar = self.request.GET.get('calendar', '') actual = self.request.GET.get('current', None) option = self.request.GET.get('option', '') hoy = datetime.today() optica = self.request.user.get_opticuser() if (calendar == 'month'): self.label = 'Mes' if not actual: self.current_year = hoy.year self.current = MESES[hoy.month] else: self.current_year = int( self.request.GET.get('current_year', None)) actual_num = list(MESES.keys())[list( MESES.values()).index(actual)] if option == 'next': if not (actual_num + 1 > hoy.month and self.current_year == hoy.year): if actual_num + 1 <= 12: self.current = MESES[actual_num + 1] else: if self.current_year + 1 <= hoy.year: self.current = MESES[1] self.current_year += 1 else: self.current = MESES[actual_num] else: self.current = MESES[actual_num] elif option == 'previus': if actual_num - 1 > 0: self.current = MESES[actual_num - 1] else: self.current = MESES[12] self.current_year -= 1 self.size = c.monthrange( self.current_year, list(MESES.keys())[list(MESES.values()).index( self.current)])[1] query = Prescription.objects.filter( optic=optica, date__month=list(MESES.keys())[list(MESES.values()).index( self.current)], date__year=self.current_year).annotate( dato=Day('date')).values('dato').annotate( total=Count('date')).order_by('dato') elif calendar == 'year': self.size = 12 self.label = 'Año' if not actual: self.current = hoy.year else: if option == 'next': if int(actual) + 1 <= hoy.year: self.current = int(actual) + 1 else: self.current = hoy.year elif option == 'previus': self.current = int(actual) - 1 query = Prescription.objects.filter( optic=optica, date__year=self.current).annotate( dato=Month('date')).values('dato').annotate( total=Count('date')).order_by('dato') elif calendar == 'week': self.size = 7 self.label = 'Semana' if not actual: self.current = hoy.isocalendar().week #int(hoy.strftime('%W')) self.current_year = hoy.year else: self.current_year = int( self.request.GET.get('current_year', None)) self.current = int(actual) if option == 'next': if not (self.current + 1 > hoy.isocalendar().week and self.current_year == hoy.year): if self.current + 1 <= 53: self.current += 1 else: self.current = 1 self.current_year += 1 else: self.current = hoy.isocalendar().week elif option == 'previus': if self.current - 1 > 0: self.current -= 1 else: self.current = 53 self.current_year -= 1 query = Prescription.objects.filter( optic=optica, date__week=self.current, date__year=self.current_year).annotate( dato=ExtractIsoWeekDay('date')).values('dato').annotate( total=Count('date')).order_by('dato') query2 = Prescription.objects.filter( optic=optica, date__week=self.current, date__year=self.current_year).annotate( dato=ExtractIsoWeekDay('date')).values( 'dato', 'date__iso_week_day') print("lllllllllllllllllllllllll", query2) for i in query2: print(i) elif calendar == 'day': self.size = 24 self.label = 'Dia' if not actual: self.current = hoy.day self.current_year = hoy.year self.current_month = hoy.month else: self.current_year = int( self.request.GET.get('current_year', None)) self.current = int(actual) self.current_month = int( self.request.GET.get('current_month', None)) cant_dias_mes = c.monthrange(self.current_year, self.current_month)[1] if option == 'next': if not (self.current + 1 > hoy.day and self.current == hoy.day): if self.current + 1 <= cant_dias_mes: self.current += 1 else: if self.current_month + 1 <= 12: self.current_month += 1 else: self.current_month = 1 self.current_year += 1 self.current = 1 elif option == 'previus': if self.current - 1 > 0: self.current -= 1 else: if self.current_month - 1 > 0: self.current_month -= 1 else: self.current_month = 12 self.current_year -= 1 self.current = c.monthrange(self.current_year, self.current_month)[1] query = Prescription.objects.filter( optic=optica, date__day=self.current, date__year=self.current_year, date__month=self.current_month).annotate( dato=Hour('time')).values('dato').annotate( total=Count('time')).order_by('dato') return query
def get_context_data(self, **kwargs): """ OPTIONAL Override parent method to get context data for template (add JSON - format data about current user) :param kwargs: captured named param from url_dispatcher path() :return: additional context for template rendering """ current_user = self.object context = super().get_context_data(**kwargs) context['json'] = serializers.serialize( 'json', users.models.CustomUser.objects.filter(pk=self.kwargs['pk']), fields=('username', 'first_name', 'last_name', 'Email')) if self.request.user.pk != self.kwargs.get('pk'): games = Games.objects.prefetch_related('sessions').filter( sessions__scores__user__pk=self.kwargs['pk'], sessions__is_private=False, ).distinct().annotate(total_score=Sum("sessions__scores__score"), times_played=Count("sessions")) else: games = Games.objects.prefetch_related('sessions').filter( sessions__scores__user__pk=self.kwargs['pk'], ).distinct().annotate(total_score=Sum("sessions__scores__score"), times_played=Count("sessions")) games_data = [] for game in games: if self.request.user.pk != self.kwargs['pk']: sessions_data = list( game.sessions.filter( is_private=False, scores__user=current_user, ).annotate(date=F('created_at'), score=Sum('scores__score')).values( 'date', 'score')) # Expensive realization with 'for' loop: each iteration = db calls # for session in game.sessions.filter(scores__user=current_user, is_private=False).distinct(): # session_data = { # "date": session.created_at, # "score": GameScores.objects.filter( # user=current_user, # game_session=session # ).aggregate(Sum('score'))['score__sum'], # } # sessions_data.append(session_data) else: sessions_data = list( game.sessions.filter(scores__user=current_user).annotate( date=F('created_at'), score=Sum('scores__score')).values('date', 'score')) # Expensive realization with 'for' loop: each iteration = db calls # for session in game.sessions.filter(scores__user=current_user).distinct(): # session_data = { # "date": session.created_at, # Realization with access through related GameSession object # "score": session.scores.filter( # user=current_user, # ).aggregate(Sum('score'))['score__sum'], # Realization with raw access to GameScores object # "score": GameScores.objects.filter( # user=current_user, # game_session=session # ).aggregate(Sum('score'))['score__sum'], # } # sessions_data.append(session_data) if not sessions_data: continue if bool( game.cover_art ): # checks for associated file for "cover_art" field (model attr) game_data = { "name": game.name, "cover": game.cover_art.url, "total_score": game.total_score, "times_played": game.times_played, "sessions": sessions_data } else: game_data = { "name": game.name, "total_score": game.total_score, "times_played": game.times_played, "sessions": sessions_data } games_data.append(game_data) context["games"] = games_data if self.request.user.pk == self.kwargs['pk']: context["last_five_games_played"] = Games.objects.prefetch_related( 'sessions').filter( sessions__scores__user__pk=self.kwargs['pk']).distinct( ).annotate(player_score=Sum("sessions__scores__score")) else: context["last_five_games_played"] = Games.objects.prefetch_related( 'sessions').filter( sessions__scores__user__pk=self.kwargs['pk'], sessions__is_private=False).distinct().annotate( player_score=Sum("sessions__scores__score")) context["self_sessions"] = GameSession.objects.prefetch_related( 'scores').filter(scores__user__id=self.kwargs["pk"]) if self.request.user.pk == self.kwargs['pk']: self_game_sessions = GameSession.objects.filter(scores__user__pk=self.kwargs["pk"]).\ annotate(weekday=ExtractIsoWeekDay("created_at")) else: self_game_sessions = GameSession.objects.filter( scores__user__pk=self.kwargs["pk"], is_private=False).annotate( weekday=ExtractIsoWeekDay("created_at")) context['sessions'] = self_game_sessions # unclaimed yet context['most_active_day'] = get_the_most_played_day( self_game_sessions) context["frequency"] = get_player_calendar_with_week_day_name( self_game_sessions) return context