This commit is contained in:
Daniel Langbein 2020-12-05 14:03:18 +01:00
commit a920d65b4b
2 changed files with 82 additions and 10 deletions

View File

@ -1,11 +1,15 @@
from pathlib import Path from pathlib import Path
from typing import List from typing import List
import matplotlib.pyplot as pyplot from datetime import date
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from langfingaz import loadData from langfingaz import loadData
from langfingaz import parseMeetings from langfingaz import parseMeetings
from langfingaz.parseMeetings import BbbStatus, Meeting from langfingaz.parseMeetings import BbbStatus, Meeting
from langfingaz.util import fileUtil from langfingaz.util import fileUtil
from langfingaz.util import util
def getDefaultPlotFolder() -> Path: def getDefaultPlotFolder() -> Path:
@ -40,25 +44,49 @@ def doPlotMeetings(bbbStati: List[BbbStatus]) -> Path:
videos.append(bbbStatus.videoCount) videos.append(bbbStatus.videoCount)
voices.append(bbbStatus.voiceParticipantCount) voices.append(bbbStatus.voiceParticipantCount)
# Note that even in the OO-style, we use `.pyplot.figure` to create the figure. _a, _b = plt.subplots() # Create a figure and an axes.
_a, _b = pyplot.subplots() # Create a figure and an axes. fig: plt.Figure = _a
fig: pyplot.Figure = _a
ax = _b # of type plt.axes.Axes ?? ax = _b # of type plt.axes.Axes ??
if not (issubclass(type(fig), pyplot.Figure)): if not (issubclass(type(fig), plt.Figure)):
raise ValueError("expected Figure") raise ValueError("expected Figure")
ax.plot(time, participants, label='participants') # Plot some data on the axes. ax.plot(time, participants, label='participants')
ax.plot(time, videos, label='video') # Plot more data on the axes... ax.plot(time, videos, label='video')
ax.plot(time, voices, label='voice') # ... and some more. ax.plot(time, voices, label='voice')
# format the ticks (on x-axis)
days = mdates.DayLocator()
hours = mdates.HourLocator(interval=6) # every 6 hours one minor tick
dateFmt = mdates.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_locator(days)
ax.xaxis.set_major_formatter(dateFmt)
ax.xaxis.set_minor_locator(hours)
# round to nearest day
dateMin = time[0].date() # round floor
dateMax = util.roundCeilingByDay(time[-1]) # round ceiling
ax.set_xlim(dateMin, dateMax)
ax.set_xlabel('time') # Add an x-label to the axes. ax.set_xlabel('time') # Add an x-label to the axes.
ax.set_ylabel('numbers') # Add a y-label to the axes. ax.set_ylabel('numbers') # Add a y-label to the axes.
ax.set_title("BigBlueButton Statistics") # Add a title to the axes. ax.set_title("BigBlueButton Statistics") # Add a title to the axes.
ax.legend() # Add a legend. ax.legend() # Add a legend.
# rotates and right aligns the x labels (dates), and moves the bottom of the
# axes up to make room for them
# https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.autofmt_xdate
fig.autofmt_xdate()
imgFormat = 'png'
image: Path = getDefaultPlotFolder().joinpath( image: Path = getDefaultPlotFolder().joinpath(
"{}_until_{}".format(fileUtil.asString(time[0]), fileUtil.asString(time[-1])) "{}_until_{}.{}".format(
fileUtil.asString(time[0]),
fileUtil.asString(time[-1]),
imgFormat
)
) )
fig.savefig(image) fig.savefig(image, format=imgFormat, dpi=400)
# plt.show() # plt.show()
return image return image

View File

@ -1,4 +1,5 @@
import time import time
import datetime
def sleep(seconds: float): def sleep(seconds: float):
@ -13,6 +14,49 @@ def indentMultilineStr(s: str, indentWith='\t'):
return indented return indented
# def roundFloorByDay(t) -> datetime.date:
# """
# rounds the (date)time up to the closest full day before or equal this point of time
# (round floor)
#
# :param t: datetime.date or datetime.datetime
# :return: the closest full day before or equal to (date)time t
# """
#
# # note: order of datetime and date type check matters
# # as datetime is a SUBCLASS of date
# if issubclass(type(t), datetime.datetime):
# return t.date()
# elif issubclass(type(t), datetime.date):
# return t
# else:
# raise ValueError("illegal argument")
def roundCeilingByDay(t) -> datetime.date:
"""
rounds the (date)time up to the closest full day after or equal to this point of time
(round ceiling)
:param t: datetime.date or datetime.datetime
:return: the closest full day after or equal to (date)time t
"""
# note: order of datetime and date type check matters
# as datetime is a SUBCLASS of date
if issubclass(type(t), datetime.datetime):
t: datetime.datetime # "cast" to datetime.datetime for IDE linting
if t.minute == 0 and t.second == 0 and t.microsecond == 0:
return t.date()
else:
return datetime.date(year=t.year, month=t.month, day=t.day + 1)
elif issubclass(type(t), datetime.date):
return t
else:
raise ValueError("illegal argument")
def asString(o: object): def asString(o: object):
attrs = vars(o) # attributes and their values attrs = vars(o) # attributes and their values
return '\n'.join("%s: %s" % item for item in attrs.items()) return '\n'.join("%s: %s" % item for item in attrs.items())