cove-scripts/activity_graph.py

110 lines
2.8 KiB
Python

# /// 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()