From 77548a6de85222c68acc690c989a9d217f8cdaf3 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 1 Mar 2025 03:50:31 +0100 Subject: [PATCH] Add activity graph script --- activity_graph.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 activity_graph.py diff --git a/activity_graph.py b/activity_graph.py new file mode 100644 index 0000000..93518fd --- /dev/null +++ b/activity_graph.py @@ -0,0 +1,95 @@ +import argparse +import datetime +import json +from collections import Counter +from pathlib import Path + +import matplotlib.dates as mdates +import matplotlib.pyplot as plt +import pandas as pd + + +class Data: + def __init__(self): + self.by_day = Counter() + + def add_msg(self, msg): + dt = datetime.datetime.fromtimestamp(msg["time"], tz=datetime.UTC) + self.by_day[dt.date()] += 1 + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("json_logs", type=Path, nargs="+") + args = parser.parse_args() + + data = Data() + + for path in args.json_logs: + print(f"Reading {path}") + n = 0 + with open(path) as f: + for line in f: + data.add_msg(json.loads(line)) + n += 1 + if n % 100000 == 0: + print(f"{n:10}") + print(f"{n:10}") + + first_day = min(data.by_day.keys()) + last_day = max(data.by_day.keys()) + print(f"Got logs from {first_day} to {last_day}") + + # The following code was generated by ChatGPT and adjusted by me + + # Extract sorted dates and counts + dates = sorted(data.by_day.keys()) + counts = [data.by_day[date] for date in dates] + + # Convert to DataFrame for moving average calculation + df = pd.DataFrame({"date": dates, "count": counts}) + df.set_index("date", inplace=True) + df = df.asfreq("D", fill_value=0) # Fill missing dates with 0 + df["30_day_avg"] = df["count"].rolling(window="30D", center=True).mean() + + # Create the plot + fig, ax = plt.subplots(figsize=(10, 5)) + ax.plot( + df.index, + df["count"], + linestyle="-", + linewidth=0.5, + color="#348ceb", + label="Messages", + ) + ax.plot( + df.index, + df["30_day_avg"], + linestyle="-", + linewidth=0.5, + color="#a80303", + label="30-day moving average", + ) + + # Format x-axis for better readability + ax.xaxis.set_major_locator(mdates.YearLocator()) # Major ticks per year + ax.xaxis.set_minor_locator(mdates.MonthLocator()) # Minor ticks per month + ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y")) # Year labels + ax.set_xlabel("Time") + ax.set_ylabel("Messages") + ax.set_ylim(0) # Start y-axis at 0 + ax.set_title("Activity Graphâ„¢") + ax.legend() + ax.grid(True, which="both", linestyle="--", linewidth=0.5) + + # Rotate x-axis labels for clarity + plt.xticks(rotation=45) + plt.tight_layout() + + # Save the plot to a PNG file + plt.savefig("activity_graph.png", dpi=300) + plt.close() + + +if __name__ == "__main__": + main()