Skip to content

Instantly share code, notes, and snippets.

@adryd325
Forked from lunasorcery/twitter-scatter-plot.py
Last active July 17, 2024 16:24
Show Gist options
  • Save adryd325/f811e975bf8240fb6e6555e57c3db7d2 to your computer and use it in GitHub Desktop.
Save adryd325/f811e975bf8240fb6e6555e57c3db7d2 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# Download your data dump and place this file in the "messages" folder of your data dump.
# Run it using python
from datetime import datetime, timedelta, timezone
import dateutil.parser
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.dates as mdates
import csv
import json
import os
# User parameters
root = os.path.dirname(os.path.realpath(__file__))
# root = "." # Uncomment to use PWD rather than script location
yourNameHere = "@your.name.here"
renderHorizontal = True
dates = []
for dir in os.listdir(root):
if (os.path.isdir(dir)):
print(f"reading messages for channel: {dir}")
if "messages.csv" not in os.listdir(dir):
with open(dir + '/messages.json', 'r', encoding="utf-8") as json_file:
json2 = json.load(json_file)
for message in json2:
dates.append(datetime.fromisoformat(message["Timestamp"]))
json_file.close()
else:
with open(dir + '/messages.csv', 'r', encoding="utf-8") as csv_file:
reader = csv.reader(csv_file)
for row in reader:
if (row[1] != "Timestamp"):
dates.append(datetime.fromisoformat(row[1]))
csv_file.close()
print(f"total messages: {len(dates)}")
now = datetime.utcnow()
days=[]
times=[]
print("processing dates")
for date in dates:
timeNoDate = datetime(1970, 1, 1, date.hour, date.minute, date.second)
dateNoTime = datetime(date.year, date.month, date.day)
days.append(dateNoTime)
times.append(timeNoDate)
print("processing graph")
hoursMajorLocator = mdates.HourLocator(interval=6)
hoursMinorLocator = mdates.HourLocator(interval=1)
hoursMajorFormatter = mdates.DateFormatter('%H:%M')
daysMajorLocator = mdates.YearLocator(base=1)
daysMinorLocator = mdates.MonthLocator()
daysMajorFormatter = mdates.DateFormatter('%Y')
daysMinorFormatter = mdates.DateFormatter('%b')
if renderHorizontal:
fig, ax = plt.subplots(figsize=((max(days)-min(days)).days / 200, 3))
plt.scatter(days, times, s=1, linewidths=0, color='#1f77b4c0')
plt.xlim(min(days), max(days))
plt.ylim(0, 1)
dateAxis = ax.xaxis
hoursAxis = ax.yaxis
daysMinorFormatter = mdates.DateFormatter('')
else:
fig, ax = plt.subplots(figsize=(3, (max(days)-min(days)).days / 200))
plt.scatter(times, days, s=1, linewidths=0, color='#1f77b4c0')
plt.ylim(min(days), max(days))
plt.xlim(0, 1)
dateAxis = ax.yaxis
hoursAxis = ax.xaxis
ax.tick_params(axis='y', which='minor', labelsize=5, color='#777')
# time goes downwards and to the right
plt.gca().invert_yaxis()
hoursAxis.set_major_locator(hoursMajorLocator)
hoursAxis.set_minor_locator(hoursMinorLocator)
hoursAxis.set_major_formatter(hoursMajorFormatter)
dateAxis.set_major_locator(daysMajorLocator)
dateAxis.set_minor_locator(daysMinorLocator)
dateAxis.set_major_formatter(daysMajorFormatter)
dateAxis.set_minor_formatter(daysMinorFormatter)
hoursAxis.set_label('Time of day')
dateAxis.set_label('Date')
plt.title(f"When does {yourNameHere} post on Discord (UTC)")
print("rendering png")
plt.savefig('out.png', bbox_inches='tight', pad_inches=0.3, dpi=300)
print("rendering svg")
plt.savefig('out.svg', bbox_inches='tight', pad_inches=0.3)
@megamaz
Copy link

megamaz commented Mar 14, 2024

  • You can just do datetime.fromisoformat() (datetime.datetime.fromisoformat()) instead of using dateutils.parser.parse
  • Please do open(..., encoding="utf-8") because I'm getting charmap errors.

@adryd325
Copy link
Author

  • You can just do datetime.fromisoformat() (datetime.datetime.fromisoformat()) instead of using dateutils.parser.parse

    • Please do open(..., encoding="utf-8") because I'm getting charmap errors.

Updated c:

@TheSaltyGaming
Copy link

Traceback (most recent call last):
File "c:\Users\Anders\Downloads\package\messages\discord-scatter-plot.py", line 62, in
fig, ax = plt.subplots(figsize=((max(days)-min(days)).days / 200, 3))
ValueError: max() arg is an empty sequence

@teiraaa
Copy link

teiraaa commented Mar 21, 2024

Getting the same error as above 😅

Traceback (most recent call last): File "c:\Users\[username]\Downloads\package\messages\discord-scatter-plot.py", line 62, in <module> fig, ax = plt.subplots(figsize=((max(days)-min(days)).days / 200, 3)) ^^^^^^^^^ ValueError: max() arg is an empty sequence

@megamaz
Copy link

megamaz commented Mar 21, 2024

Getting the same error as above 😅

Traceback (most recent call last): File "c:\Users\[username]\Downloads\package\messages\discord-scatter-plot.py", line 62, in <module> fig, ax = plt.subplots(figsize=((max(days)-min(days)).days / 200, 3)) ^^^^^^^^^ ValueError: max() arg is an empty sequence

How many total messages did it say there were? It looks like the days list is empty for some reason, though I can't understand why it would do that looking at the code. Do your subfolders have a messages.csv or a messages.json? It looks like the code supports both but I'm pretty sure it should be csv only. And what python version are you using? I doubt this is the cause, but you never know.

@2394425147
Copy link

It might be due to the dir variable in for dir in os.listdir(root): (Line 21) being the folder name for the message instead of the full path
Doing a os.path.join(root, dir) worked for me, if that helps!

@TheSaltyGaming
Copy link

Fixed the issue and put together a GUI (and a .exe file) for it which can be found here:

https://github.com/TheSaltyGaming/Discord-Scatterplot-GUI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment