s05_multi/server.py

"""Create and manage multiple charts with multiple controls."""

from flask import Flask, request
from flask_cors import CORS
import htpy as h
from pathlib import Path

from static.shared import datagen, util


TITLE = "Doris"


def create_app(data):
    """Create Flask application."""
    app = Flask(TITLE, static_folder=Path("static").resolve(), static_url_path="/static")
    CORS(app)

    @app.get("/")
    def get_root():
        """Display home page."""
        return str(h.html[
            make_head(),
            h.body(onload="displayAll()")[
                h.h1[TITLE],
                make_chart("top"),
                make_controls(data, "top"),
                make_chart("bottom"),
                make_controls(data, "bottom"),
            ],
        ])

    @app.get("/data")
    def get_data():
        """Get weight and length by sex as JSON."""
        datasets = [
            {"label": key, "data": util.select_data(data, "sex", key, x="weight", y="length")}
            for key in util.interesting_keys(request)
        ]
        return {
            "_chart": request.args["_chart"],
            "data": {
                "datasets": datasets
            },
            "options": {
                "dataColors": util.select_colors(data, "sex", [d["label"] for d in datasets])
            }
        }

    return app


def make_chart(name):
    """Create placeholder for chart."""
    return h.div(".chart-container")[
        h.svg(f"#chart-{name}", class_="chart"),
    ]


def make_controls(data, name):
    """Create form controls for chart."""
    buttons = []
    for sex in util.ordered_unique(data, "sex"):
        buttons.append(h.label(for_=sex)[sex])
        buttons.append(
            h.input(type="checkbox", id=f"check-{name}-{sex}", name=sex, value=sex, checked=True)
        )

    callback = f"display('#controls-{name}'); return false;"
    return h.form(f"#controls-{name}", class_="controls", onsubmit=callback)[
        *buttons,
        h.button(type="submit")["submit"],
        h.input(type="hidden", name="_chart", value=f"chart-{name}"),
    ]


def make_head():
    """Make head of page."""
    return h.head[
        h.title[TITLE],
        h.link(rel="icon", type="image/x-icon", href="/static/shared/favicon.ico"),
        h.link(rel="stylesheet", href="/static/shared/dashboard.css"),
        h.script(src="/static/shared/runtime.js"),
        h.script(src="/static/shared/chart.xkcd.min.js"),
        h.script(src="/static/dashboard.js"),
    ]


if __name__ == "__main__":
    options = util.parse_args()
    data = datagen.generate(options.seed)
    app = create_app(data)
    app.run()