Un argomento che mi ha sempre affascinato (ma non so davvero perchè!) è la visualizzazione di grafici di funzione. Ricordo un vecchio programma BASIC (forse era GW-BASIC o forse era il BASIC della Commodore) che tracciava il grafico di una funzione definita da codice (per cambiare la funzione bisognava modificare una riga del programma); il BASIC a quei tempi offriva delle primitive per tracciare linee o stampare punti a video, permettendo così di creare grafici anche con poche righe di codice.
Partendo da un esercizio trovato su un forum vediamo come fare tutto questo con Python: scopriamo il modulo pyplot.

pyplotmodule 

Il testo dell'esercizio è il seguente:

Dati due punti trovare la retta passante per i due punti dati e tracciarla a video.

Qui ci sono due questioni da risolvere:
a) determinazione dell'equazione della retta passante per due punti;
b) rappresentazione grafica.

EQUAZIONE DELLA RETTA PASSANTE PER DUE PUNTI

In rete ho trovato questo https://forum.ubuntu-it.org/viewtopic.php?t=369168 contenente una soluzione molto elegante (o dovrei dire molto "pythonica"): una funzione che ritorna una funzione!
In sostanza: da programmatore tradizionale mi aspetteri una funzione che mi ritorna i valori m e q dell'equazione y=mx+q ma con Python possiamo ritornare direttamente la funzione f(x) che restituisce mx+q dato x in input.

Per quanto riguarda il lato matematico della questione bisogna considerare due situazioni particolari:
a) se i due punti coincidono vi sono infinite rette, quindi non procediamo con la visualizzazione;
b) se le due coordinate y coincidono la retta non può essere espressa y=mx+q ma bensì come x=q, e questo caso va trattato diversamente (qui ho preferito non gestire il caso).
Da notare che se le due coordinate x coincidono non ci sono problemi particolari, la funzione sarà sempre y=mx+q ma con m=0.

Ecco qui il codice della funzione ed un esempio d'uso:

def crea_retta(x1,y1,x2,y2):
if x1==x2 and y1==y2:
raise ValueError("Infinite rette")
elif x1==x2:
raise ValueError("Equazione nella forma x=q")
else:
m=float(y2-y1)/(x2-x1)
q=y1-(m*x1)
def retta(x):
return m*x+q
return retta

x1=1
y1=3
x2=2
y2=5

try:
r=crea_retta(x1,y1,x2,y2)
except ValueError as err:
print(format(err))
r=None
if r!=None:
for x in range(-10,11,1):
print("x="+str(x)+" y="+str(r(x)))

Se lanciamo lo script otteniamo il seguente output, in pratica i dati per la successiva rappresentazione grafica:

x=-10 y=-19.0
x=-9 y=-17.0
x=-8 y=-15.0
x=-7 y=-13.0
x=-6 y=-11.0
x=-5 y=-9.0
x=-4 y=-7.0
x=-3 y=-5.0
x=-2 y=-3.0
x=-1 y=-1.0
x=0 y=1.0
x=1 y=3.0
x=2 y=5.0
x=3 y=7.0
x=4 y=9.0
x=5 y=11.0
x=6 y=13.0
x=7 y=15.0
x=8 y=17.0
x=9 y=19.0
x=10 y=21.0

Questo codice necessita di qualche spiegazione.
La funzione crea_retta() riceve in input le due coordinate (x1,y1) e (x2,y2) e verifica subito i casi particolari illustrati in precedenza: se le coordinate non sono gestibili viene sollevata un'eccezione di tipo ValueError.
Se le coordinate sono gestibili allora vengono calcolati m e q dell'equazione y=mx+q; invece di restituire questi due valori viene definita la funzione retta(x) che viene restituita al chiamante.
Se crea_retta() non ha sollevato alcuna eccezione allora utilizziamo la funzione che ci ha restituito per creare una tabella dei valori, per x da -10 a 10.

RAPPRESENTAZIONE GRAFICA

Per la rappresentazione grafica possiamo utilizzare il modulo pyplot che va installato separatamente; ci sono principalmente due opzioni:
a) creare un virtual environment come spiegato qui https://sebcosta.altervista.org/joomla/articles/24-python-creare-eseguibile-windows.html e installarvi il modulo matplotlib, di cui pyplot fa parte; vedi https://matplotlib.org/users/installing.html;
b) installare un ambiente come Anaconda https://www.anaconda.com/download/ che contiene già il modulo in questione preinstallato.
Io ho scelto la soluzione più semplice e mi sono installato Anaconda; tra l'altro in Anaconda è presente anche l'editor Spyder, molto comodo per la presenza di una console per testare il proprio programma.

Prendendo quindi il codice scritto in precedenza aggiungiamo l'importazione di pyplot:

import matplotlib.pyplot as plt

poi andiamo ad aggiungere in coda il codice necessario per stampare il grafico:

if r!=None: 
for x in range(-10,11,1):
print("x="+str(x)+" y="+str(r(x)))

# stampa funzione
plt.plot([n for n in range(-10,11)],[r(n) for n in range(-10,11)], color="blue")

# assi
plt.plot([n for n in range(-10,11)],[0 for n in range(-10,11)], color="black")
plt.plot([0 for n in range(-10,11)],[n for n in range(-10,11)], color="black")
plt.axis([-10, 10, -10, 10])

# stampa i due punti
plt.plot([x1], [y1], marker='o', markersize=9, color="red")
plt.plot([x2], [y2], marker='o', markersize=9, color="green")

# descrizione assi
plt.xlabel("asse x")
plt.ylabel("asse y")

# visualizza
plt.show()

La visualizzazione vera e propria avviene con la chiamata del metodo show(); prima di questo dobbiamo aver preparato i vari elementi.
Con il metodo plot() possiamo tracciare la retta, i due assi x e y, e pure i due punti (x1,y1) e (x2,y2); con xlabel() e ylabel() possiamo abbellire il grafico fornendo una descrizione degli assi mentre la chiamata al metodo axis() permette di specificare i limiti di visualizzazione.

E questo è il risultato:

pyplot

Suggerisco di dare un'occhiata al tutorial di pyplot https://matplotlib.org/tutorials/introductory/pyplot.html#sphx-glr-tutorials-introductory-pyplot-py per eventualmente apportare le proprie modifiche al grafico.

Un miglioramento interessante potrebbe essere quello di determinare automaticamente la scala da utilizzare in base alla posizione dei due punti definiti (qui lavoro fisso da -10 a +10): questo potrebbe essere un valido esercizio per mettersi alla prova!

CONCLUSIONI

In questo articolo abbiamo visto come creare un grafico di funzione in Python utilizzando il modulo pyplot.
Il codice presentato può essere migliorato in diversi modi per cui non mi resta che augurarvi... buon divertimento!!!

NOTA: A conclusione di questo esercizio, sono poi andato alla ricerca del programma BASIC di cui parlavo all'inizio e l'ho trovato qui http://ready64.org/ccc/pagina.php?ccc=55&pag=100.jpg (l'articolo va da pagina 100 a pagina 104): si tratta della scannerizzazione di un articolo della gloriosa rivista Commodore Computer Club (il numero 55 dell'estate '88, 30 anni fa!!!), in cui appunto si presentava questo programma scritto in GW-BASIC per Commodore 64 (eh sì, c'era un interprete GW-BASIC anche per Commodore 64).