#!/usr/bin/env python3
"""Plot reproduce/liars.csv into ../strong-liar-ratio.svg.

    gcc -O2 -Wall -Wextra -o liars liars.c && ./liars 20000 > liars.csv
    /tmp/mplenv/bin/python plot_liars.py
"""
import csv
import pathlib

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt  # noqa: E402

HERE = pathlib.Path(__file__).resolve().parent
BG, FG, HI, DIM, GRID = "#2d333b", "#adbac7", "#cdd9e5", "#768390", "#444c56"
BLUE, GREEN, ORANGE, RED = "#388bfd", "#3fb950", "#f0883e", "#f85149"

rows = list(csv.DictReader(open(HERE / "liars.csv")))
n = [int(r["n"]) for r in rows]
phi = [int(r["phi"]) for r in rows]
fer = [int(r["fermat_liars"]) / p for r, p in zip(rows, phi)]
strong = [int(r["strong_liars"]) / p for r, p in zip(rows, phi)]
carm = [i for i, r in enumerate(rows) if int(r["fermat_liars"]) == int(r["phi"])]

plt.rcParams.update({
    "font.family": "DejaVu Sans Mono",
    "font.size": 11,
    "text.color": FG,
    "axes.labelcolor": FG,
    "xtick.color": FG,
    "ytick.color": FG,
    "axes.edgecolor": DIM,
})
fig, (top, bot) = plt.subplots(2, 1, figsize=(8.4, 6.6), dpi=100, sharex=True)
fig.patch.set_facecolor(BG)
for ax in (top, bot):
    ax.set_facecolor(BG)
    ax.grid(True, color=GRID, lw=0.6)

top.scatter(n, fer, s=4, color=BLUE, alpha=0.55, lw=0, label="odd composite n",
            rasterized=True)
top.scatter([n[i] for i in carm], [fer[i] for i in carm], s=36, color=RED,
            marker="D", label="Carmichael (every coprime a lies)")
top.set_ylabel("Fermat liars / phi(n)")
top.set_ylim(-0.03, 1.08)
top.set_title("Fraction of bases that wrongly vote 'prime', odd composites 9..19999",
              color=HI, fontsize=12)

bot.scatter(n, strong, s=4, color=GREEN, alpha=0.55, lw=0, label="odd composite n",
            rasterized=True)
bot.scatter([n[i] for i in carm], [strong[i] for i in carm], s=36, color=RED,
            marker="D", label="Carmichael")
bot.axhline(0.25, color=ORANGE, lw=1.5, ls="--", label="Monier-Rabin bound 1/4")
for x, y in zip(n, strong):
    if x in (9, 15, 8911):
        bot.annotate(str(x), (x, y), textcoords="offset points", xytext=(6, 4),
                     color=HI, fontsize=9)
bot.set_ylabel("strong liars / phi(n)")
bot.set_xlabel("n")
bot.set_ylim(-0.02, 0.36)

for ax, loc in ((top, "center right"), (bot, "upper right")):
    leg = ax.legend(loc=loc, facecolor=BG, edgecolor=DIM, fontsize=9,
                    markerscale=1.5)
    for t in leg.get_texts():
        t.set_color(FG)
fig.tight_layout()
fig.savefig(HERE.parent / "strong-liar-ratio.svg", facecolor=BG, dpi=150)
print("wrote", HERE.parent / "strong-liar-ratio.svg")
