From c48aa6f14f6b76774ec63b561551e1f284e0279c Mon Sep 17 00:00:00 2001 From: Salastil Date: Tue, 5 May 2026 23:53:20 -0400 Subject: [PATCH] Upload files to "/" --- 4stat2.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 4stat2.py diff --git a/4stat2.py b/4stat2.py new file mode 100644 index 0000000..eb8c73e --- /dev/null +++ b/4stat2.py @@ -0,0 +1,82 @@ +#!/bin/env python3 +import json +import numpy as np +import pandas as pd +import requests +import matplotlib.pyplot as plt +from datetime import datetime +from scipy.stats import linregress + +# === Step 1: Download JSON from 4stats.io === +print("๐Ÿ“ก Fetching data from 4stats.io...") +response = requests.get("https://api.4stats.io/history/day/tv", headers={ + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0", + "Accept": "application/json, text/plain, */*", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Origin": "https://4stats.io", + "DNT": "1", + "Connection": "keep-alive", + "Pragma": "no-cache", + "Cache-Control": "no-cache" +}) +if response.status_code != 200: + raise Exception(f"Failed to fetch data. Status code: {response.status_code}") +data = response.json() +print(f"โœ… Downloaded {len(data)} records.") + +# === Step 2: Filter from Jan 1, 2023 onward === +cutoff = datetime(2023, 1, 1).timestamp() * 1000 # in ms +filtered_data = [row for row in data if row[0] >= cutoff] +print(f"โœ‚๏ธ Trimmed to {len(filtered_data)} records from 2023 onward.") + +# === Step 3: Normalize "Posts Per Day" (column 3) === +filtered_data = [row for row in filtered_data if row[2] is not None] # drop None values +print(f"๐Ÿงน Dropped None rows, {len(filtered_data)} records remaining.") + +timestamps = np.array([row[0] for row in filtered_data]) +posts_per_day = np.array([row[2] for row in filtered_data], dtype=float) + +slope, intercept, *_ = linregress(timestamps, posts_per_day) +trendline = slope * timestamps + intercept +mean_value = posts_per_day.mean() +adjusted_posts_per_day = posts_per_day - (trendline - mean_value) +adjusted_data = [ + [row[0], row[1], float(round(adj, 2)), row[3]] + for row, adj in zip(filtered_data, adjusted_posts_per_day) +] + +# === Step 4: Convert adjusted data into DataFrame === +df = pd.DataFrame(adjusted_data, columns=["Timestamp", "Column_2", "Posts_Per_Day", "Column_4"]) +df["Date"] = pd.to_datetime(df["Timestamp"], unit="ms") + +# === Step 5: Define Season Ranges === +seasons = { + "Season 1": ("2023-04-18", "2023-05-30"), + "Season 2": ("2023-12-18", "2024-01-28"), + "Season 3": ("2024-10-27", "2024-12-07"), + "Season 4": ("2025-06-13", "2025-06-30"), + "Bloodgames-Bitchtank": ("2024-06-24", "2024-08-08"), + "Season 5": ("2026-03-15", "2026-04-13") +} +season_ranges = { + name: (datetime.strptime(start, "%Y-%m-%d"), datetime.strptime(end, "%Y-%m-%d")) + for name, (start, end) in seasons.items() +} + +# === Step 6: Plot the Graph === +styles = ['-', '--', '-.', ':', (0,(3,1,1,1)), (0,(5,1))] +plt.figure(figsize=(10, 6)) +for i, (season_name, (start_date, end_date)) in enumerate(season_ranges.items()): + season_df = df[(df["Date"] >= start_date) & (df["Date"] <= end_date)].copy() + season_df["Day_Index"] = (season_df["Date"] - start_date).dt.days + 1 + season_df = season_df[season_df["Day_Index"] <= 42] + plt.plot(season_df["Day_Index"], season_df["Posts_Per_Day"], label=season_name, linestyle=styles[i], linewidth=2) + + +plt.xlabel("Days (1 to 42)") +plt.ylabel("Posts Per Day") +plt.title("Posts Per Day Across Seasons (4chan /tv/)") +plt.legend() +plt.grid(True) +plt.tight_layout() +plt.show()