#!/usr/bin/env python3 import pickle from matplotlib import pyplot as plt import requests import json from datetime import datetime from dataclasses import dataclass from collections import defaultdict from time import sleep from pathlib import Path api_url = r'https://review.video.fosdem.org/api/v1/event/1/overview' poll_rate = 10*60 # seconds pickle_file = Path(r'./talk_data.pickle') @dataclass class TimeSeries: "The object to pickle and unpickle" states: set[str] jobstates: set[str] data: dict[datetime, tuple[dict[str, int], dict[str, int]]] # time → (states(name → count), jobstates(ditto)) def get_data() -> tuple[datetime, dict[str, int], dict[str, int]]: resp = requests.get(api_url) # TODO: error handling? time = datetime.now().astimezone() data = json.loads(resp.content.decode()) states = defaultdict(lambda: 0) jobstates = defaultdict(lambda: 0) # should be an array/list for talk in data: states[talk['state']] += 1 jobstates[talk['progress']] += 1 return time, states, jobstates def main(): if pickle_file.exists(): with open(pickle_file, 'rb') as f: ts = pickle.load(f) else: print("New time series.") ts = TimeSeries(states=set(), jobstates=set(), data=dict()) while True: time, states, jobstates = get_data() assert time not in ts.data ts.data[time] = (states, jobstates) ts.states |= states.keys() ts.jobstates |= jobstates.keys() # Save the pickle # Should probably save elsewhere and do atomic rename, but whatever. with open(pickle_file, 'wb') as f: pickle.dump(ts, f) # Show the plot x = sorted(ts.data.keys()) # times # vvv should be a defaultdict anyway, but let's be defensive :-) ys = [tuple(ts.data[time][0].get(state, 0) for state in ts.states) for time in x] # numbers per state # We do not show jobstates atm. Too lazy. # ys are transposed – we need vectors by times, not by states. ys = list(zip(*ys)) plt.stackplot(x, *ys) plt.show(block=False) sleep(poll_rate) plt.close() plt.clf() main()