mirror of
https://codeberg.org/langfingaz/bbb-status
synced 2024-11-21 20:23:17 +01:00
rotate date-labels of plot; show ticks for days and 6-hour intervals
This commit is contained in:
parent
141582842a
commit
7faacc6e86
@ -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)
|
||||||
# plt.show()
|
# plt.show()
|
||||||
|
|
||||||
return image
|
return image
|
||||||
|
@ -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())
|
||||||
|
Loading…
Reference in New Issue
Block a user