27 novembre, 2020

Gnuplot per grafici al volo

 Alle volte capita che non mi trovo d'accordo con qualche nerd che peraltro ammiro moltissimo. Proprio in questi giorni un prof davvero tosto twitta sulla necessità di dover scrivere dozzine di istruzioni quando [programma-esoso] fa tutto in una riga. Vero, probabilmente, ma io la penso diversamente. E, dai! non è difficile, come forse si vedrà da quanto segue.

Invece di usare dati sul virus (lo sto vivendo male, con apprensione) elaboro un caso completamente diverso, e senza usare Excel!
Dillon (rockz! 💥) anticamente ha twittato: √2 raised to itself infinitely many times is 2. Sarà vero? verifico.

Uso Python (sì, vanno bene anche (quasi) tutti gli altri linguaggi ma... la standardizzazione) per costruire il file dei dati (r2.py, 13 righe):

#!/usr/bin/python3

from math import sqrt, pow
r2 = sqrt(2)
ap2 = r2
c = 0
while True:
    delta = 2 - ap2
    print('{:3d} {:.5f} {:.5f}'.format(c, ap2, delta))
    ap2 = pow (r2, ap2)
    if delta < 1e-5:
        break
    c += 1 


eseguo:

$ py3 r2.py > r2.out

Il file che ottengo consta di 31 righe come queste:

  0 1.41421 0.58579
  1 1.63253 0.36747
  2 1.76084 0.23916
....
....
 28 1.99998 0.00002
 29 1.99999 0.00001
 30 1.99999 0.00001

Ok, si vede che Dillon ha ragione, ma il grafico...
Qui entra in gioco Gnuplot, una vecchia conoscenza --almeno per me-- ne avevo trattato anticamente (qui, qui e qui).

Siccome Gnuplot è "grosso" non è che uno è costretto a ricordarsi tutto quanto: c'è una vagonata di esempi, tutti quelli immaginabili e altri ancora, qui.

Nel mio caso voglio i grafici del variare del valore approssimato della radice (seconda colonna) e quello della differenza tra questi e il valore reale. Cioè, per farla semplice mi conviene costruire due files contenenti rispettivamente la seconda e la terza colonna come y oltre alla prima quale x. Quando si dice la combinazione! c'è AWK che fa (anche) proprio quello:

$ awk '{print $1 " " $2}' r2.out > r2-1-2
$ awk '{print $1 " " $3}' r2.out > r2-1-3

Ah! aggiungo una terza linea, anzi no una serie di punti (file r2-p), questo

 0 1.41421
30 2

Con queste premesse posso compilare il file per Gnuplot (in realtà modifico un template da anni):

#set term pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 600, 450 #x11 size 400, 300
 set term pngcairo enhanced font "arial,20" fontscale 1.0 size 600, 450 #set term x11 size 400, 300
 set output 'r2.png'
TITLE = "Limite via radice di 2"
set style line 1 lt 2 lc rgb "red" lw 3
set style line 2 lt 2 lc rgb "blue" lw 3
set title TITLE offset char 0, char -1
set xrange [0:30]
set yrange [-0.2:2.2]
unset key #toglie la legenda
 
plot "r2-1-2" with lines ls 1, \
     "r2-1-3" with lines ls 2, \
     "r2-p" with points lt 1 pt 7 ps 3
     
# pause -1 ">>> return per finire "

$ gnuplot p-r2

e ottengo, con 16 righe di codice (nota: ho lasciato commentate le istruzioni per visualizzare il grafico a video, la versione riportata produce il file r2.png, tanti altri formati sono possibili)


E per chi non ha AWK, per dire chi usa Windows Peggio per lui!  beh, sempre con Python è un attimo (m12.py, 33 righe):

#!/usr/bin/python3

from sys import argv
from os.path import basename, isfile

if len(argv) != 4:
    print('ARRGGHHHH!')
    print('Uso:', basename(argv[0]), 
          'input-file colonna-1 colonna-2'
          '\n(la prima colonna è la numero 0)')   
    exit(1)

filein = argv[1]
colonna1 = argv[2]
colonna2 = argv[3]

if not isfile(filein): 
    print('Manca il file', filein)
    exit(2)

#leggo il file di input
with open(filein, 'r') as f:
    lines = f.readlines()

#creo l'output
dataout = ''
icol1 = int(colonna1)
icol2 = int(colonna2)
for line in lines:
    ele = line.strip().split(' ')
    dataout += ele[icol1] + ' ' + ele[icol2] + '\n'
with open(filein+'-'+colonna1+'-'+colonna2, 'w') as f:
    print(dataout)  

visto che non serve tirar fuori un $acco di $oldi?
visto quant'è facile?

Nota: mi dicono che le risposte scatenate dal tweet approfondiscono; tanto 🤓
🔴🔵

Nessun commento:

Posta un commento