E allora, secondo noi, è il caso di procedere un po' per conto nostro. Prendiamo per esempio il digramma che ci propone qui e visualizziamolo (chart.py):
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
data = ((10, 9), (20, 22), (30, 21), (40, 30), (50, 41),
(60, 53), (70, 45), (80, 20), (90, 19), (100, 22),
(110, 42), (120, 62), (130, 43), (140, 71), (150, 89),
(160, 65), (170, 126), (180, 187), (190, 128), (200, 125),
(210, 150), (220, 129), (230, 133), (240, 134), (250, 165),
(260, 132), (270, 130), (280, 159), (290, 163), (300, 94))
years = ('2010', '2011', '2012')
class LineChart(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.SetBackgroundColour('WHITE')
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, event):
dc = wx.PaintDC(self)
dc.SetDeviceOrigin(40, 240)
dc.SetAxisOrientation(True, True)
dc.SetPen(wx.Pen('WHITE'))
dc.DrawRectangle(1, 1, 300, 200)
self.DrawAxis(dc)
self.DrawGrid(dc)
self.DrawTitle(dc)
self.DrawData(dc)
def DrawAxis(self, dc):
dc.SetPen(wx.Pen('#0AB1FF'))
font = dc.GetFont()
font.SetPointSize(8)
dc.SetFont(font)
dc.DrawLine(1, 1, 300, 1)
dc.DrawLine(1, 1, 1, 201)
for i in range(20, 220, 20):
dc.DrawText(str(i), -30, i+5)
dc.DrawLine(2, i, -5, i)
for i in range(100, 300, 100):
dc.DrawLine(i, 2, i, -5)
for i in range(3):
dc.DrawText(years[i], i*100-13, -10)
def DrawGrid(self, dc):
dc.SetPen(wx.Pen('#d5d5d5'))
for i in range(20, 220, 20):
dc.DrawLine(2, i, 300, i)
for i in range(100, 300, 100):
dc.DrawLine(i, 2, i, 200)
def DrawTitle(self, dc):
font = dc.GetFont()
font.SetWeight(wx.FONTWEIGHT_BOLD)
dc.SetFont(font)
dc.DrawText('Historical Prices', 90, 235)
def DrawData(self, dc):
dc.SetPen(wx.Pen('#0ab1ff'))
for i in range(10, 310, 10):
dc.DrawSpline(data)
class LineChartExample(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(390, 300))
panel = wx.Panel(self, -1)
panel.SetBackgroundColour('WHITE')
hbox = wx.BoxSizer(wx.HORIZONTAL)
linechart = LineChart(panel)
hbox.Add(linechart, 1, wx.EXPAND | wx.ALL, 15)
panel.SetSizer(hbox)
self.Centre()
self.Show(True)
app = wx.App()
LineChartExample(None, -1, 'A line chart')
app.MainLoop()
Tutto OK, ma un po' rigido, i dati che plotta sono inseriti nello script e se vogliamo visualizzarne altri dobbiamo modificare lo script ogni volta.
L'idea che propongo è di memorizzare i dati in un file che lo script legge (leggi.py):
#!/usr/bin/python
# -*- coding: utf-8 -*-
fdati = 'dati.dat'
fd = open(fdati, 'r')
txt = fd.readlines()
#print txt
fd.close()
arr_x = []
arr_y = []
for line in txt:
riga = line.strip()
#print riga
if len(riga) > 0:
p = riga.find(' ')
x = float(riga[:p])
y = float(riga[p:])
arr_x.append(x)
arr_y.append(y)
Lcoppie = zip(arr_x, arr_y)
coppie = tuple(Lcoppie)
print coppie
xmax = max(arr_x)
ymax = max(arr_y)
print xmax, ymax
OK? legge un file di dati di tipo text con le coppie di valori x y, come questo (dati.dat):
Siccome sono pigro il file dati.dat l'ho creato con un script bash, di quelli per cui Bit3Lux è maestro e saprebbe fare molto meglio di me. Comnunque è questo:
#!/bin/sh
sed 's/),/\n/g;s/(//g;s/,//g;s/))//g;' dati.or > dati.tmp
sed 's/^ //g;/^$/d' dati.tmp > dati.dat
rm dati.tmp-----------------
come input usa il file dati.or che è la tupla preso da chart.py:
((10, 9), (20, 22), (30, 21), (40, 30), (50, 41),
(60, 53), (70, 45), (80, 20), (90, 19), (100, 22),
(110, 42), (120, 62), (130, 43), (140, 71), (150, 89),
(160, 65), (170, 126), (180, 187), (190, 128), (200, 125),
(210, 150), (220, 129), (230, 133), (240, 134), (250, 165),
(260, 132), (270, 130), (280, 159), (290, 163), (300, 94))
A
questo punto lo script chart.py può essere modificato cambiando la riga
data = ((10, 9), .... con l'istruzione di leggere il file, cioè
inserire leggi.py nello script.Anche il nome del file dei dati non deve essere fisso e inserito nello script. Considerate il seguente snippet (finp.py):
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, os.path
if len(sys.argv) == 1:
print "uso:", sys.argv[0], "file-dei-dati"
sys.exit(1)
elif not os.path.isfile(sys.argv[1]):
print "file", sys.argv[1], "non trovato"
sys.exit(2)
print "processo", sys.argv[1]
OK, da mettere in chart.py anche questo.
Ah! un'ultima cosa ancora: per quelli abituati all'ambiente grafico si può utilizzate la funzione wx.FileDialog(). Così (opfd.py):
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx, os.path
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"wx.FileDialog Tutorial")
panel = wx.Panel(self, wx.ID_ANY)
btn = wx.Button(panel, label="Open File Dialog")
btn.Bind(wx.EVT_BUTTON, self.onOpenFile)
def onOpenFile(self, event):
dlg = wx.FileDialog(
self, message = "Scegli un file",
defaultDir = os.path.curdir,
defaultFile = "*.*",
wildcard = "File di dati (*.dat)|*.dat|" \
"File di testo (*.txt)|*.txt|" \
"Tutti i file (*.*)|*.*",
style = wx.OPEN | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
paths = dlg.GetPaths()
print "hai scelto:", paths
dlg.Destroy()
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
Da mettere anche questo in chart.py.
Ecco, avete presente l'Ikea? o da piccoli avete certamente giocato con il Lego. Vi ho fornito tutti i componenti (i mattoncini del Lego) lasciando a voi il piacere di assemblarli. Buon lavoro!
L'indice di Mission Python lo trovate qui
Nessun commento:
Posta un commento