PYTHON
Grafici con tkinter
La libreria tkinter
La libreria grafica tk, di cui tkinter rappresenta l’interfaccia per Python, è relativamente semplice da usare, si trova già inclusa nelle distribuzioni Python per Windows, dispone delle funzionalità di base per creare una GUI, e il canvas grafico ha diverse cose molto interessanti.
In particolare il canvas non è una superficie bitmap (come quelle di pygame o pillow), ma si tratta di una superficie su cui “disegnare” oggetti vettoriali. Ogni oggetto grafico del canvas può essere spostato, cancellato, modificato, ha un suo Z-order e dispone di molte proprietà modificabili a runtime.
Ad esempio un grafico può essere formato da molte curve diverse, ogni curva può essere modificata in un colpo solo passandole una nuova sequenza di coordinate, o un nuovo colore ecc.
MyGraph
Per sfruttare le formule di
traslazione di scala ho scritto una classe ‘MyGraph’, che permette di disegnare semplici grafici a partire da una serie di parametri (sfondo, assi, didascalie, colori, tipo di scala ecc). Basta descrivere i parametri tramite una classe, istanziare il grafico (passandogli i parametri), e creare una o più curve.
La classe usa due canvas uno dentro l’altro. Il canvas interno è quello su cui vengono rappresentate le curve. Fondamentalmente se ne sfrutta l’auto clipping in modo che nulla possa “sbordare” al di fuori di esso. Attorno ad esso vi è il canvas esterno dove vengono scritti i valori delle scale e le didascalie degli assi. Opzionalmente può essere disegnato il bordo del canvas interno.
La classe è molto semplice, tuttavia già con le poche combinazioni dei parametri disponibili permette di ottenere risultati visivamente interessanti:
La classe parametri
L’aspetto base di un grafico con MyGraph si definisce con una classe di parametri, che in Python è il modo sintatticamente più compatto per raggruppare delle variabili:
class Gra:
wid = 256 #larghezza in pixel
hei = 192 #altezza in pixel
margin_left = 48 #margini attorno al canvas
margin_top = 50
margin_right = 16
margin_bottom = 60
xmin = 0.1 #coordinate relative grafico
xmax = 1000
ymin = -1.5
ymax = 3.5
xlog = True #scala X logaritmica
ylog = False #scala Y lineare
paper = '#f0f0ff' #colore sfondo grafico
title='Y = log10(X)' #Didascalia asse Y
xtext='X' #Didascalia asse X
lsegm = 8 #segmenti estremi assi tratteggiati
border = 1 #bordo visibile 0=invisibile
axis = 1 #assi visibili 0=invisibili
axis_color = 'gray'
text = 1 #didascalie visibili
origin = 1 #assi origine visibili
origin_color = 'black'
origin_arrow = 0 #origini senza frecce
#assi orizzontali, 0 finale = tratteggiati
oriz_axis = [-1., 0., 1., 2., 3.], 0
#assi verticali, 1 finale = pieni
vert_axis = [
0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 200, 300, 400, 500, 600, 700, 800, 900], 1
#maschere per formattazione valori didascalie su assi
ymask = '{:.1f}' #float una cifra dopo virgola
xmask = '{}' #stringa generica
#valori da riportare sugli assi
txt_y = -1, 0, 1, 2, 3
txt_x = (0.1, 0.1), (1, 1), (10, 10), (100, 100), (1000, '1k')
Utilizzo
#-----------------------------------------------------------
# Test classe MyGraph - By C.Fin 2018
#-----------------------------------------------------------
try: import tkinter as tk
except: import Tkinter as tk
from mygraph import MyGraph
import math
#-----------------------------------------------------------
class Gra:
#dimensioni canvas grafico
wid = 256
hei = 192
margin_left = 48
margin_top = 50
margin_right = 16
margin_bottom = 60
#coordinate relative grafico
xmin = 0
xmax = 360
ymin = -1.5
ymax = 1.5
xlog = False
ylog = False
paper = 'white'
title='Y = sen(2X)'
xtext='X'
lsegm = 8
border = 1
axis = 1
axis_color = '#D0D0D0'
text = 1
origin = 1
origin_arrow = 0
origin_color = 'black'
oriz_axis = [-1, 1], 0
vert_axis = [], 1
ymask = '{:d}'
xmask = '{:d}'
txt_y = -1, 0, 1
txt_x = (
(0, 0), (90, 90), (180, 180),
(270, 270), (360, 360)
)
#-----------------------------------------------------------
root = tk.Tk();
gra = MyGraph(root, Gra)
gra.pack(expand=1)
minf = 0
maxf = 360
punti = 256
step = (maxf - minf) / (punti - 1.)
data = []
for punto in range(punti):
x = minf + step*punto
y = math.sin(math.radians(2*x))
data.append((x, y))
gra.create_curve(data, fill='navy')
root.mainloop()
Chiamando diverse volte il metodo ‘create_curve’ si possono disegnare più curve. Ogni volta viene restituito un valore che identifica l’oggetto curva nel canvas. Con il metodo ‘update_curve’ si può modificare la forma di una curva preesistente passando l’identificatore e la nuova sequenza di coordinate. Questo permette di creare animazioni o effettuare aggiornamenti senza bisogno di ridisegnare tutto.