diff --git a/docker-compose.jsonnet b/docker-compose.jsonnet index 51742fd..8a3a7ac 100644 --- a/docker-compose.jsonnet +++ b/docker-compose.jsonnet @@ -39,7 +39,6 @@ prizebot: false, youtubebot: false, bus_analyzer: false, - graphs: false, }, // Twitch channels to capture. The first one will be used as the default channel in the editor. @@ -372,9 +371,6 @@ channel_id: "UCz5-PNQxaT4WtB_OMAwD85g", // DesertBusForHope }, - // template for donation data urls - donation_url_template:: "https://example.com/DB{}/DB{}.json", - // Extra options to pass via environment variables, // eg. log level, disabling stack sampling. env:: { @@ -760,14 +756,6 @@ environment: $.env, }, - [if $.enabled.graphs then "graphs"]: { - image: $.get_image("graphs"), - restart: "always", - command: [$.donation_url_template, "--base-dir", "/mnt/graphs"], - volumes: ["%s:/mnt" % $.segments_path], - environment: $.env, - }, - local bot_service(name, config, args=[], subcommand=null, mount_segments=false) = { image: $.get_image("zulip_bots"), restart: "always", diff --git a/graphs/Dockerfile b/graphs/Dockerfile deleted file mode 100644 index c43f156..0000000 --- a/graphs/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM python:3.11 - -RUN pip install bokeh - -COPY graphs /tmp/graphs -RUN pip install /tmp/graphs && rm -r /tmp/graphs - -LABEL org.opencontainers.image.source https://github.com/dbvideostriketeam/wubloader -ENTRYPOINT ["python3", "-m", "graphs"] diff --git a/graphs/graphs/__init__.py b/graphs/graphs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graphs/graphs/__main__.py b/graphs/graphs/__main__.py deleted file mode 100644 index c530099..0000000 --- a/graphs/graphs/__main__.py +++ /dev/null @@ -1,13 +0,0 @@ -import gevent.monkey -gevent.monkey.patch_all() - -import logging - -import argh - -from graphs.main import main - -LOG_FORMAT = "[%(asctime)s] %(levelname)8s %(name)s(%(module)s:%(lineno)d): %(message)s" - -logging.basicConfig(level='INFO', format=LOG_FORMAT) -argh.dispatch_command(main) diff --git a/graphs/graphs/main.py b/graphs/graphs/main.py deleted file mode 100644 index 1bc13de..0000000 --- a/graphs/graphs/main.py +++ /dev/null @@ -1,180 +0,0 @@ -import gevent.monkey -gevent.monkey.patch_all() - -import datetime -import logging -import json -import os - -import argh -import bokeh.plotting -import bokeh.models -import bokeh.palettes -import bokeh.settings -import numpy as np -import requests - -def format_year(year): - if year > 10: - year += 2006 - return 'DBfH {}'.format(year) - -def parse_json(json_donations, start_date, end_hour=np.inf, every_five=True): - - end_hour = float(end_hour) - times = [] - donations = [] - for entry in json_donations: - times.append(datetime.datetime(*entry[:5]).isoformat()) - donations.append(entry[5]) - - times = np.array(times, dtype=np.datetime64) - donations = np.asarray(donations) - - start_time = np.datetime64(start_date) - bustimes = np.array(times - start_time, dtype=np.int_) - - trimmed_bustimes = bustimes[(bustimes <= 60 * 60 * end_hour) & (bustimes >= 0)] - trimmed_donations = donations[(bustimes <= 60 * 60 * end_hour) & (bustimes >= 0)] - - if every_five: - five_bustimes = trimmed_bustimes[::5] - five_donations = trimmed_donations[::5] - return five_bustimes, five_donations - else: - return trimmed_bustimes, trimmed_donations - -def load_previous_donations(start_end_times, donation_url_template, timeout): - - all_years = {} - for year in start_end_times: - start, end = start_end_times[year] - if not end: - current_year = year - continue - - url = donation_url_template.format(year, year) - logging.info('Loading {}'.format(url)) - year_json = requests.get(url, timeout=timeout).json() - all_years[year] = parse_json(year_json, start, end, year >= 5) - - return all_years, current_year - -def all_years_donations_graph(start_end_times, all_years, current_year, current_json, base_dir): - - logging.info('Generating all years donation graph') - p = bokeh.plotting.figure(x_axis_label='Bus Time', y_axis_label='Donations', x_range=(0, 60 * 60 * 172), - width=1280, height=720, active_scroll='wheel_zoom', - tools='pan,wheel_zoom,box_zoom,reset') - - p.add_tools(bokeh.models.HoverTool(tooltips=[('', '$name'), ('Bustime', '@Bustime{00:00:00}'), - ('Donations', '$@Donations{0,0.00}')])) - for year in start_end_times: - label = format_year(year) - if year != current_year: - times, donations = all_years[year] - line_width = 2 - else: - times, donations = parse_json(current_json, start_end_times[year][0], every_five=False) - line_width = 3 - model = bokeh.models.ColumnDataSource(data={'Bustime':times, 'Donations':donations}) - p.line(x='Bustime', y='Donations', source=model, line_width=line_width, - line_color=bokeh.palettes.Category20[20][current_year - year], - legend_label=label, name=label) - - - p.xaxis.ticker = bokeh.models.AdaptiveTicker(mantissas=[60, 120, 300, 600, 1200, 3600, 7200, 10800, 43200, 86400], base=10000000) - p.xaxis.formatter = bokeh.models.NumeralTickFormatter(format='00:00:00') - p.yaxis.formatter = bokeh.models.NumeralTickFormatter(format='$0,0') - - p.legend.location = "top_left" - p.legend.click_policy="hide" - - output_path = os.path.join(base_dir, 'all_years_donations.html') - bokeh.plotting.output_file(filename=output_path, title='DBfH All Years Donations') - bokeh.plotting.save(p, filename=output_path) - logging.info('{} Saved'.format(output_path)) - -def shifts_graph(start_end_times, current_year, current_json, base_dir, shifts): - - logging.info('Generating DBfH {} shifts graph'.format(current_year)) - times, donations = parse_json(current_json, start_end_times[current_year][0], every_five=False) - start_hour = int(start_end_times[current_year][0][11:13]) - - hours = times / 3600 + start_hour - mod_hours = hours % 24 - n_days = int(hours.max() / 24) + 1 - - p = bokeh.plotting.figure(x_axis_label='Hour of Day', y_axis_label='Donations', x_range=(0, 24 * 3600), - width=1280, height=720, active_scroll='wheel_zoom', - tools='pan,wheel_zoom,box_zoom,reset') - p.add_tools(bokeh.models.HoverTool(tooltips=[('', '$name'), ('Hour of Day', '@Hours{00:00:00}'), - ('Donations', '$@Donations{0,0.00}')])) - - for day in range(n_days): - - for shift in shifts: - in_range = (hours >= day * 24 + shift[1]) & (hours <= day * 24 + shift[2]) - hours_in_range = mod_hours[in_range] - if mod_hours[in_range].size: - - if hours_in_range[-1] == 0.: - hours_in_range[-1] = 24 - model = bokeh.models.ColumnDataSource(data={'Hours':hours_in_range * 3600, 'Donations':donations[in_range] - donations[in_range][0]}) - p.line(x='Hours', y='Donations', source=model, line_color=bokeh.palettes.Category10[10][day], - line_width=2, legend_label='Day {}'.format(day + 1), name='Day {} {}'.format(day + 1, shift[0])) - - p.xaxis.ticker = bokeh.models.AdaptiveTicker(mantissas=[60, 120, 300, 600, 1200, 3600, 7200, 10800, 43200, 86400], base=10000000) - p.xaxis.formatter = bokeh.models.NumeralTickFormatter(format='00:00:00') - p.yaxis.formatter = bokeh.models.NumeralTickFormatter(format='$0,0') - - p.legend.location = "top_left" - p.legend.click_policy="hide" - - output_path = os.path.join(base_dir, 'DBfH_{}_shifts_graph.html'.format(current_year)) - bokeh.plotting.output_file(filename=output_path, title='{} Shift Donations'.format(format_year(current_year))) - bokeh.plotting.save(p, filename=output_path) - logging.info('{} Saved'.format(output_path)) - - -@argh.arg('--base-dir', help='Directory where graphs are output. Default is current working directory.') -def main(donation_url_template, base_dir='.'): - - stopping = gevent.event.Event() - - logging.getLogger('bokeh').setLevel(logging.WARNING) - - delay = 60 * 1 - timeout = 15 - - shifts = [['Zeta Shift', 0, 6], - ['Dawn Guard', 6, 12], - ['Alpha Flight', 12, 18], - ['Night Watch', 18, 24]] - - # First load data required - logging.info('Loading start and end times') - start_end_path = os.path.join(base_dir, 'start_end_times.json') - start_end_times = json.load(open(start_end_path)) - start_end_times = {int(year):start_end_times[year] for year in start_end_times} - - all_years, current_year = load_previous_donations(start_end_times, donation_url_template, timeout) - current_url = donation_url_template.format(current_year, current_year) - - while not stopping.is_set(): - - try: - - logging.info('Loading {}'.format(current_url)) - current_json = requests.get(current_url, timeout=timeout).json() - - all_years_donations_graph(start_end_times, all_years, current_year, current_json, base_dir) - - shifts_graph(start_end_times, current_year, current_json, base_dir, shifts) - - - except Exception: - logging.exception('Plotting failed. Retrying') - - stopping.wait(delay) - diff --git a/graphs/setup.py b/graphs/setup.py deleted file mode 100644 index 8a98eb6..0000000 --- a/graphs/setup.py +++ /dev/null @@ -1,14 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name = 'graphs', - version = '0.0.0', - packages = find_packages(), - install_requires = [ - 'argh', - 'bokeh', - 'gevent', - 'numpy', - 'requests' - ], -)