stats: Add histogram generator

An SVG histogram can now be generated into a configurable path
(static/histogram.svg by default) by using the `hist` CLI command.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2023-09-09 21:08:12 -07:00
parent b036a51cfb
commit 6eb48ff0d2
4 changed files with 49 additions and 0 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
histogram.svg
cache cache
bans bans
thumbs thumbs

View File

@@ -4,6 +4,7 @@ import logging
from .pull import pull from .pull import pull
from .http import run_app from .http import run_app
from .hist import generate_histogram_svg
def parse_args(): def parse_args():
@@ -30,6 +31,14 @@ def parse_args():
"pull", "pull",
help="Pull bans from 4chan, save thumbnails, update the database, and exit", help="Pull bans from 4chan, save thumbnails, update the database, and exit",
) )
_histogram_parser = add_subcommand(
"hist",
help="Generate histogram file.",
# This doesn't work as expected for some reason. Doesn't get parsed correctly
#aliases=["histogram"],
)
_serve_parser = add_subcommand("serve", help="Start HTTP server") _serve_parser = add_subcommand("serve", help="Start HTTP server")
_help_parser = add_subcommand("help", help="Show this help message") _help_parser = add_subcommand("help", help="Show this help message")
@@ -57,6 +66,8 @@ def main():
asyncio.run(pull()) asyncio.run(pull())
case "serve": case "serve":
run_app() run_app()
case "hist":
generate_histogram_svg()
case command: case command:
assert ( assert (
False False

View File

@@ -47,3 +47,5 @@ STATIC_LOCAL_FOLLOW_SYMLINKS = one_of_default(
"STATIC_LOCAL_FOLLOW_SYMLINKS", ("yes", "true", "1", "no", "false", "0"), "true" "STATIC_LOCAL_FOLLOW_SYMLINKS", ("yes", "true", "1", "no", "false", "0"), "true"
) in ("yes", "true", "1") ) in ("yes", "true", "1")
STATIC_ROOT = default("STATIC_ROOT", "/static") STATIC_ROOT = default("STATIC_ROOT", "/static")
HISTOGRAM_PATH = Path(default("HISTOGRAM_PATH", "static/histogram.svg"))

35
chanbans/hist.py Normal file
View File

@@ -0,0 +1,35 @@
from .db import get_db
from .config import HISTOGRAM_PATH
from pathlib import Path
def histogram_svg():
db = get_db()
cursor = db.cursor()
cursor.execute("SELECT board, COUNT(*) AS count FROM bans GROUP BY board")
data = list(cursor.fetchall())
max_count = max(data, key=lambda x: x["count"])["count"]
scale_factor = 200 / max_count
bar_width = 30
bar_padding = 5
svg_width = (bar_width + bar_padding) * len(data)
svg = f'<svg width="{svg_width}" height="300" xmlns="http://www.w3.org/2000/svg">'
for i, row in enumerate(data):
board = row["board"]
count = row["count"]
x = i * (bar_width + bar_padding)
y = 250 - (count * scale_factor)
svg += f'<rect x="{x}" y="{y}" width="{bar_width}" height="{count * scale_factor}" fill="blue" />'
svg += f'<text x="{x + 15}" y="280" font-size="12" text-anchor="middle">{board}</text>'
svg += f'<text x="{x + 15}" y="{y - 5}" font-size="12" text-anchor="middle">{count}</text>'
svg += "</svg>"
return svg
def generate_histogram_svg(path: Path = HISTOGRAM_PATH):
svg = histogram_svg()
path = path.write_text(svg)