# /// script # requires-python = ">=3.11" # dependencies = [ # "matplotlib", # "pandas", # "scipy", # ] # /// 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 avg = df["count"].rolling( window=30, min_periods=1, center=True, win_type="gaussian", ) df["30_day_avg"] = avg.mean(std=8) # 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()