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:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
histogram.svg
|
||||
cache
|
||||
bans
|
||||
thumbs
|
||||
|
||||
@@ -4,6 +4,7 @@ import logging
|
||||
|
||||
from .pull import pull
|
||||
from .http import run_app
|
||||
from .hist import generate_histogram_svg
|
||||
|
||||
|
||||
def parse_args():
|
||||
@@ -30,6 +31,14 @@ def parse_args():
|
||||
"pull",
|
||||
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")
|
||||
_help_parser = add_subcommand("help", help="Show this help message")
|
||||
|
||||
@@ -57,6 +66,8 @@ def main():
|
||||
asyncio.run(pull())
|
||||
case "serve":
|
||||
run_app()
|
||||
case "hist":
|
||||
generate_histogram_svg()
|
||||
case command:
|
||||
assert (
|
||||
False
|
||||
|
||||
@@ -47,3 +47,5 @@ STATIC_LOCAL_FOLLOW_SYMLINKS = one_of_default(
|
||||
"STATIC_LOCAL_FOLLOW_SYMLINKS", ("yes", "true", "1", "no", "false", "0"), "true"
|
||||
) in ("yes", "true", "1")
|
||||
STATIC_ROOT = default("STATIC_ROOT", "/static")
|
||||
|
||||
HISTOGRAM_PATH = Path(default("HISTOGRAM_PATH", "static/histogram.svg"))
|
||||
|
||||
35
chanbans/hist.py
Normal file
35
chanbans/hist.py
Normal 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)
|
||||
Reference in New Issue
Block a user