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
|
cache
|
||||||
bans
|
bans
|
||||||
thumbs
|
thumbs
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
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