Files

119 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# /// script
# requires-python = ">=3.11"
# dependencies = ["numpy", "matplotlib"]
# ///
"""Mostra o salva il grafico di T e ΔT di un CSV prodotto da genera.py."""
import argparse
import re
import sys
from pathlib import Path
import matplotlib
import numpy as np
CARTELLA_OUTPUT = Path("output")
class ParserIt(argparse.ArgumentParser):
"""ArgumentParser con i messaggi d'errore più comuni in italiano (exit 2)."""
TRADUZIONI = [
(r"the following arguments are required: (.*)", r"manca l'argomento obbligatorio: \1"),
(r"unrecognized arguments: (.*)", r"argomenti non riconosciuti: \1"),
(r"argument (.*): invalid int value: (.*)", r"argomento \1: \2 non è un numero intero"),
(r"argument (.*): expected one argument", r"argomento \1: manca il valore"),
]
def error(self, message):
for pattern, sostituzione in self.TRADUZIONI:
message = re.sub(pattern, sostituzione, message)
self.print_usage(sys.stderr)
print(f"{self.prog}: errore: {message}", file=sys.stderr)
sys.exit(2)
def errore(msg):
print(f"Errore: {msg}", file=sys.stderr)
sys.exit(1)
def ultimo_csv():
csv = sorted(CARTELLA_OUTPUT.glob("*.csv"), key=lambda p: p.stat().st_mtime)
if not csv:
errore(f"nessun CSV in '{CARTELLA_OUTPUT}': genera prima i dati con genera.py")
return csv[-1]
def main():
ap = ParserIt(
prog="grafico.py",
usage="grafico.py [-h] [-o FILE] [csv]",
description="Disegna T e dT = T - T_amb in funzione del tempo (due pannelli con asse comune)\n"
"da un CSV prodotto da genera.py.",
epilog="""\
esempi:
grafico.py finestra con l'ultimo CSV modificato in output/
grafico.py output/gen_42.csv un CSV preciso
grafico.py -o grafico.png salva l'immagine invece di aprire la finestra
(utile senza schermo, es. via SSH)
formato atteso del CSV: t_ms,T_C,dT_C (come scritto da genera.py).
codici di uscita:
0 ok
1 errore, con messaggio in italiano su stderr: nessun CSV in output/, file
illeggibile o con formato diverso, immagine non scrivibile
2 argomenti della riga di comando non validi
dipendenze: numpy, matplotlib.""",
formatter_class=argparse.RawDescriptionHelpFormatter,
add_help=False,
)
argomenti = ap.add_argument_group("argomenti")
opzioni = ap.add_argument_group("opzioni")
opzioni.add_argument("-h", "--help", action="help", help="mostra questo aiuto ed esce")
argomenti.add_argument("csv", nargs="?", type=Path, help="CSV da disegnare (default: l'ultimo modificato in output/)")
opzioni.add_argument(
"-o", "--output", type=Path, metavar="FILE",
help="salva l'immagine in FILE invece di aprire la finestra; il formato segue l'estensione (png, pdf, svg)",
)
args = ap.parse_args()
percorso = args.csv or ultimo_csv()
try:
t_ms, T, dT = np.loadtxt(percorso, delimiter=",", skiprows=1, unpack=True)
except OSError as e:
errore(f"impossibile leggere '{percorso}': {e.strerror}")
except ValueError:
errore(f"'{percorso}' non ha il formato t_ms,T_C,dT_C")
if args.output:
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, (ax_T, ax_dT) = plt.subplots(2, 1, sharex=True, figsize=(10, 6))
t_s = t_ms / 1000
ax_T.plot(t_s, T, lw=0.8)
ax_T.set_ylabel("T [°C]")
ax_dT.plot(t_s, dT, lw=0.8, color="tab:orange")
ax_dT.set_ylabel("ΔT = T − T_amb [°C]")
ax_dT.set_xlabel("tempo [s]")
for ax in (ax_T, ax_dT):
ax.grid(alpha=0.3)
fig.suptitle(percorso.name)
fig.tight_layout()
if args.output:
try:
fig.savefig(args.output, dpi=150)
except OSError as e:
errore(f"impossibile scrivere '{args.output}': {e.strerror}")
print(f"scritto: {args.output}", file=sys.stderr)
else:
plt.show()
if __name__ == "__main__":
main()