Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reddit automatic posting #118

Merged
merged 3 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# secrets
*.pem*
.password
*.log
praw.ini
aws_login.sh

# playground notebooks
Expand Down
16 changes: 14 additions & 2 deletions Automation/data-refresh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,24 @@ handle_failure() {
then
# failure in preprocessing, bad data might have been written to file
git restore .
aws sns publish --topic-arn arn:aws:sns:us-east-2:637423600104:Armchair-Strategist --message file://./Automation/data-refresh.log --subject "Data Refresh Failure - $error_line: $error_command"
elif [[ "$error_command" == *readme_machine.py* ]]
then
# failure in making README graphics, withhold all graph updates only
git restore Docs/visuals/*
git add .
git commit -m "Partial data refresh (no visualizations)" || true # ignore non-zero exit status when there's no diff on main
./Automation/auto-push.exp -d 2>./Automation/auto-push.log
aws sns publish --topic-arn arn:aws:sns:us-east-2:637423600104:Armchair-Strategist --message file://./Automation/data-refresh.log --subject "Data Refresh Failure - $error_line: $error_command"
elif [[ "$error_command" == *reddit_machine.py* ]]
then
# failure in Reddit publishing, release all other data and emit warning
./Automation/auto-push.exp -d 2>./Automation/auto-push.log
aws sns publish --topic-arn arn:aws:sns:us-east-2:637423600104:Armchair-Strategist --message file://./Automation/data-refresh.log --subject "Reddit Publication Warning"
fi

# relaunch server
./Automation/start-server.sh

aws sns publish --topic-arn arn:aws:sns:us-east-2:637423600104:Armchair-Strategist --message file://./Automation/data-refresh.log --subject "Data Refresh Failure - $error_line: $error_command"
}
trap handle_failure ERR
trap handle_failure SIGTERM
Expand All @@ -40,6 +45,13 @@ python3 f1_visualization/preprocess.py
python3 f1_visualization/readme_machine.py --update-readme >/dev/null
git add .
git commit -m "Automatic data refresh" || true # ignore non-zero exit status when there's no diff on main

# post to Reddit when there is new graphics available
# -uno is not three separate options, rather it is really -u no which removes untracked files from output
if git status -uno | grep -q "Your branch is ahead"; then
python3 reddit_machine.py
fi

./Automation/auto-push.exp -d 2>./Automation/auto-push.log

# relaunch dash app
Expand Down
Binary file added Docs/visuals/driver_pace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/laptime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/podium_gap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/position.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/strategy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/team_pace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/teammate_box.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Docs/visuals/teammate_violin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ The dashboard and visualizations in this README are updated every Monday at midn
<summary>
<b>Podium Finishers Gap to Winner</b>
</summary>
<img src="Docs/visuals/podium_gap.png">
<img src="Docs/visuals/podium_gap.png" alt="podium gap">
<details>
<summary>
<b>Function call:</b>
</summary>
See <code>f1_visualization/readme_machine.py</code>
<code>driver_stats_lineplot(season, event, drivers=3)</code>
</details>
</details>

Expand All @@ -65,15 +65,15 @@ The dashboard and visualizations in this README are updated every Monday at midn
<b>Teammate Pace Comparisons</b>
</summary>
Boxplot visualization:
<img src="Docs/visuals/teammate_box.png">
<img src="Docs/visuals/teammate_box.png" alt="teammate pace boxplot">
<details>
<summary>
<b>Function call:</b>
</summary>
<code>driver_stats_distplot(season, event, violin=False, swarm=False, teammate_comp=True, drivers=20)</code>
</details>
Violinplot with all laptimes:
<img src="Docs/visuals/teammate_violin.png">
<img src="Docs/visuals/teammate_violin.png" alt="teammate pace violinplot">
<details>
<summary>
<b>Function call:</b>
Expand All @@ -84,9 +84,22 @@ The dashboard and visualizations in this README are updated every Monday at midn

<details>
<summary>
<b>Team Pace Comparisons</b>
<b>Driver Pace Comparison</b>
</summary>
<img src="Docs/visuals/driver_pace.png" alt="driver pace comparison">
<details>
<summary>
<b>Function call:</b>
</summary>
<code>driver_stats_distplot(season, event, violin=True, swarm=True, teammate_comp=False, drivers=20)</code>
</details>
</details>

<details>
<summary>
<b>Team Pace Ranking</b>
</summary>
<img src="Docs/visuals/team_pace.png">
<img src="Docs/visuals/team_pace.png" alt="team pace comparison">
<details>
<summary>
<b>Function call:</b>
Expand Down
17 changes: 17 additions & 0 deletions f1_visualization/readme_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,14 @@ def main(season: int, round_number: int, grand_prix: bool, update_readme: bool):
y=f"GapTo{race_winner}",
grid="both",
)
plt.tight_layout()
plt.savefig(dest / "podium_gap.png")

logger.info("Making lap time graph...")
viz.driver_stats_scatterplot(
season=season, event=round_number, session_type=session_type, drivers=10
)
plt.tight_layout()
plt.savefig(dest / "laptime.png")

logger.info("Making strategy graph...")
Expand All @@ -106,6 +108,7 @@ def main(season: int, round_number: int, grand_prix: bool, update_readme: bool):
event=round_number,
session_type=session_type,
)
plt.tight_layout()
plt.savefig(dest / "strategy.png")

logger.info("Making position change graph...")
Expand All @@ -114,6 +117,7 @@ def main(season: int, round_number: int, grand_prix: bool, update_readme: bool):
event=round_number,
session_type=session_type,
)
plt.tight_layout()
plt.savefig(dest / "position.png")

logger.info("Making teammate comparison boxplot...")
Expand All @@ -125,6 +129,7 @@ def main(season: int, round_number: int, grand_prix: bool, update_readme: bool):
swarm=False,
teammate_comp=True,
)
plt.tight_layout()
plt.savefig(dest / "teammate_box.png")

logger.info("Making teammate comp violinplot...")
Expand All @@ -135,8 +140,19 @@ def main(season: int, round_number: int, grand_prix: bool, update_readme: bool):
teammate_comp=True,
upper_bound=7,
)
plt.tight_layout()
plt.savefig(dest / "teammate_violin.png")

logger.info("Making driver pace plot...")
viz.driver_stats_distplot(
season=season,
event=round_number,
session_type=session_type,
upper_bound=7,
)
plt.tight_layout()
plt.savefig(dest / "driver_pace.png")

# use basic fastf1 to make team pace comparison plot
logger.info("Making team pace comparison graph...")
p.setup_mpl(misc_mpl_mods=False)
Expand Down Expand Up @@ -169,6 +185,7 @@ def main(season: int, round_number: int, grand_prix: bool, update_readme: bool):
plt.title(f"{CURRENT_SEASON} {event_name}")
plt.grid(visible=False)
ax.set(xlabel=None)
plt.tight_layout()
plt.savefig(dest / "team_pace.png")

# Copy the visualizations
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ build-backend = "setuptools.build_meta"
packages = ["f1_visualization"]

[tool.ruff]
include = ["f1_visualization/*.py", "app.py"]
include = ["f1_visualization/*.py", "./*.py"]
line-length = 96
indent-width = 4

Expand Down
114 changes: 114 additions & 0 deletions reddit_machine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""Automatically post to Reddit when new README graphics are made."""

import logging
import time

import fastf1 as f
import praw

from f1_visualization._consts import CURRENT_SEASON, ROOT_PATH
from f1_visualization.preprocess import get_last_round_number

logging.basicConfig(level=logging.INFO, format="%(levelname)s\t%(filename)s\t%(message)s")
logger = logging.getLogger(__name__)


VISUALS_PATH = ROOT_PATH / "Docs" / "visuals"


def main():
"""Submit posts and make one comment."""
reddit = praw.Reddit("armchair-strategist")
r_formula1 = reddit.subreddit("formula1")
r_f1technical = reddit.subreddit("f1technical")
formula1_flairs = r_formula1.flair.link_templates.user_selectable()
f1technical_flairs = r_f1technical.flair.link_templates.user_selectable()
formula1_flair_id = next(
flair for flair in formula1_flairs if "Statistics" in flair["flair_text"]
)["flair_template_id"]
f1technical_flair_id = next(
flair for flair in f1technical_flairs if "Strategy" in flair["flair_text"]
)["flair_template_id"]

session = f.get_session(CURRENT_SEASON, get_last_round_number(), "R")
session.load(laps=False, telemetry=False, weather=False, messages=False)
event_name = f"{session.event['EventName']} - {session.name}"

dashboard_link = "Check out more at armchair-strategist.dev!"
images = [
{
"image_path": VISUALS_PATH / "strategy.png",
"caption": (
"Tyre strategy recap. Stripped bar sections represent used tyre stints. "
f"{dashboard_link}"
),
},
{
"image_path": VISUALS_PATH / "podium_gap.png",
"caption": f"Podium finishers' gaps to winners. {dashboard_link}",
},
{
"image_path": VISUALS_PATH / "position.png",
"caption": f"Race position history. {dashboard_link}",
},
{
"image_path": VISUALS_PATH / "laptime.png",
"caption": (
"Point finishers' lap times. White vertical bars represent pitstops. ",
f"{dashboard_link}",
),
},
{
"image_path": VISUALS_PATH / "team_pace.png",
"caption": f"Team pace ranking. {dashboard_link}",
},
{
"image_path": VISUALS_PATH / "teammate_violin.png",
"caption": (
"Driver pace ranking (teammates vs teammates). Largest gap on the left. "
f"{dashboard_link}"
),
},
{
"image_path": VISUALS_PATH / "driver_pace.png",
"caption": (
"Driver pace ranking (finishing order). Highest finisher on the left. "
f"{dashboard_link}"
),
},
]

formula1_post = r_formula1.submit_gallery(
title=f"{event_name} Strategy & Performance Recap",
images=images,
flair_id=formula1_flair_id,
)
formula1_post.reply(
(
"What other graphics do you want to see and "
"how can these existing graphics be improved, quesion."
)
)
logger.info("Finished posting to r/formula1")

time.sleep(5)

f1technical_post = r_f1technical.submit_gallery(
title=f"{event_name} Strategy & Performance Recap",
images=images,
flair_id=f1technical_flair_id,
)
f1technical_post.reply(
(
"Check out the interactive version of these graphics and more "
"at my [strategy dashboard](https://armchair-strategist.dev/)"
"\n\n"
"Please let me know if you have suggestions for improving these graphics "
"or ideas for other graphics!"
)
)
logger.info("Finished posting to r/f1technical")


if __name__ == "__main__":
main()