Programowanie Fizyka Medyczna Wykład VII 8 maja 2012 Ściąga z obsługi plików Przypomnienie modułu Matplotlib:
Klasa Figure i moduł matplotlib.figure
Klasa Axes i moduł matplotlib.axes
Klasa Line2D i moduł matplotlib.lines
Klasa Annotate i moduł matplotlib.text Tkinter proste okienka w Pythonie Ściąga z obsługi plików Podstawą czytania i zapisywania do dowolnego pliku jest utworzenie obiektu, który będzie go reprezentował w programie tzw. "uchwytu" (handle). fp = open('nazwapliku', 'rb') # tworzy obiekt fp, przez który następuje odwołanie do pliku Wszystkie operacje na pliku dokonywane są poprzez metody związane z obiektem fp. 'nazwapliku' jest nazwą pliku 'rb' tryb dostępu do pliku. Składa się maksymalnie z 3 grup znaków: ['r' odczyt | 'w' zapis | 'a' append/dopisanie] ['b' dostęp w trybie binarnym (ignoruje znaki specjalne) | 't' tekst ] [ '+' - dopisanie | ' ' ] fp.close() # Zamknięcie pliku (zwolnienie uchwytu) fp.flush() # Wymuszenie zapisu z cache systemu na dysk linia = fp.read() # odczyt jednej linii z pliku tekstowego lista_linii = fp.readlines() #Odczyt aż do końca pliku i umieszczenie w liście n_znakow = fp.read(n) #Odczyt n znaków do listy fp.seek(numerznaku) #Ustawienie się w dowolnym miejscu w pliku fp.tell() #Odczyt miejsca w pliku, w którym jesteśmy fp.write("abrakadabra") #Zapis ciągu znaków 'abrakadabra' (bez nowej linii) #Proszę pamiętać o znakach CR, CR/LF, aby zmienić linię # Poprawny znak końca linii jest zapisany w module os fp.write(os.linesep) # Przechodzi do nowej linii Programowanie FizMed, wykład 7 2 Matplotlib - http://matplotlib.sourceforge.net/ Matplotlib jest zbiorem bibliotek i procedur umożliwiającym wykonywanie wykresów i rysunków w Pythonie. Używany jest także przez Sage. matplotlib.pylab (MatLab) matplotlib.patches pyplot+numpy matplotlib.axes matplotlib.collections matplotlib.lines matplotlib.cm matplotlib matplotlib.color matplotlib.figure matplotlib.ticker matplotlib.artist matplotlib.text matplotlib.image Programowanie FizMed, wykład 7 3 Matplotlib Importowanie biblioteki: import numpy as np # numpy nie jest częścią matplotlib, ale bez #niego nie da się używać import matplotlib.pyplot as mpl Jeżeli nie chcemy za każdym razem odwoływać się poprzez pełną ścieżkę matplotlib.pyplot lub numpy możemy utworzyć swoją skróconą nazwę - alias. Tworzymy w ten sposób oddzielną przestrzeń nazw (namespace) o nazwie mpl dla matplotlib.pyplot i np dla numpy. Jest to zalecane podejście w przypadku pisania osobnego programu, tak jak robiliśmy to na zajęciach. Możemy też skorzystać z modułu pylab, który łączy w sobie obie przestrzenie nazw: pyplot i numpy. import pylab as pl Programowanie FizMed, wykład 7 4 Matplotlib składniki rysunku figure i axes figure - jest centralnym obiektemnależącym do klasy matplotlib.figure.Figure, który "przechowuje" wykresy lub obrazki (container). import matplotlib.pyplot as mpl f1 = mpl.figure() mpl.show() # wyświetla puste "ramy" axes - są obiektami klasy matplotlib.axes.Axes, które "przechowują" wykresy lub obrazki f1 = mpl.figure() ax1= f1.add_subplot(121) ax2 = f1.add_subplot(122) mpl.show() # wyświetla "ramy" z "osiami" ax1 ax2 1 2 F.add_subplot(2,2,1) F.add_subplot(2,2,2) 4 #F.add_subplot(2,2,3) #brak!! F.add_subplot(2,2,4) Programowanie FizMed, wykład 7 5 Matplotlib podstawowe składniki (primitives) http://matplotlib.sourceforge.net/users/artists.html Rysunki oraz obiekty na nich umieszczone składają się z mniejszych i prostszych obiektów (Line2D, Patch, Circle, Rectangle, Text), z których wiele ma podobne znaczenie (na przykład o.patch zwykle odnosi się do prostokąta będącego tłem obiektu o). P1 = o.patch # o może być np. typu figure lub axes P1.set(facecolor = 'green') # ustawia kolor tła obiektu o na zielony Wszystkie opcje związane z danym składnikiem rysunku tworzą słownik, do którego mamy dostęp poprzez metodę matplotlib.artist.getp(P1) Figura przechowuje też listy swoich składników. axes lista obiektów typu Axes images lista obrazków legends lista opisów figury (osie mają swoje kolekcje) lines lista linii należących do figury patches lista figur geometrycznych na wykresie texts lista napisów Podobne listy przechowują też obiekty klasy Axes. Programowanie FizMed, wykład 7 6 Metody klasy axes Klasa matplotlib.axes. Axes posiada wiele różnych metod, które służą do rysowania wykresów, histogramów, obrazków itd. http://matplotlib.sourceforge.net/gallery.html http://www.scipy.org/Cookbook/Matplotlib import matplotlib import numpy as np import matplotlib.pyplot as plt f1 = plt.figure() # tworzymy Figurę f1 ax1= f1.add_subplot(121) # na f1 tworzymy rysunek (axes) ax1 ax1.plot([1,2,3,4],[0,-1,-2,5],'g>')# metoda plot rysuje wykres na podstawie 2 obiektów klasy iterable ax1.fill([-0.1, 0.1, 0],[-1,-1,1],'r', alpha = 0.4) # fill rysuje wielokąt (trójkąt) o współrzędnych (-0.1,-1), (0.1,-1), (0,1), kolorze czerwonym i 40% przezroczystości #koniec pierwszego wykresu moj_obr =plt.imread("klocki_lego.jpg") #wczytujemy obrazek jako tablicę 2D ax2 = f1.add_subplot(122) # tworzymy rysunek (axes) ax2 ax2.imshow(moj_obr) # metoda imshow wyświetla tablicę plt.show() # finalizuje obrazek Programowanie FizMed, wykład 7 7 "Dekoracje" Każdy z tworzonych właśnie wykresów/obrazków możemy opisać ax1= f1.add_subplot(121) ax1.set_xlabel("Opis osi x") ax1.set_title("Tytuł wykresu") #Lub dopisać dowolny tekst plt.text(0.1,0.1,"Tu jest tekst w punkcie (0.1, 0.1)") # na rysunku ax1.annotate("Tekst", (0.5,0.5), xycoords="axes fraction", va="center", ha="center", bbox=dict(boxstyle="round, pad=1", fc="w")) # na konkretnej osi Możemy też zmienić kolor tła Pat = ax1.patch # dostęp do obiektu tła konkretnej osi Pat.set_facecolor('green') Możemy dodawać linie ax1= f1.add_subplot(121) x = np.arange(0,5,0.1) ax1.plot(x,2*x) # Ta instrukcja już tworzy listę linii. Tak więc każdą kolejną musimy dołożyć do naszej listy instrukcją extend. #Tworzymy najpierw nową linię L1 i podajemy, że ma być na figurze f1 L1 = matplotlib.lines.Line2D([0, 1], [0, 1], transform=f1.transFigure, figure=f1) #dodajemy ją do listy linii figury f1 jako element listy f1.lines.extend( [L1] ) Możemy też dodawać całe figury rect = matplotlib.patches.Rectangle( (1,1), width=5, height=12) ax.add_patch(rect) Programowanie FizMed, wykład 7 8 Matplotlib w sesji interaktywnej i nieinteraktywnej Sesja interaktywna po każdej instrukcji możemy odświeżyć rysunek import matplotlib as mpl import matplotlib.pyplot as plt plt.ion() # metoda ion() włącza tryb interaktywny, # ioff() wyłącza F = plt.figure() ax1 = F.add_subplot(111) plt.draw() # odświeża obrazek, ale nie blokuje konsoli #itd Sesja nieinteraktywna obraz musi zostać przygotowany w całości zanim zostanie wyświetlony np w programie. import matplotlib as mpl import matplotlib.pyplot as plt F = plt.figure() ax1 = F.add_subplot(111) plt.draw() # nic nie pojawia się plt.show() # obrazek się pojawia, ale nie można wydać # nowych poleceń Programowanie FizMed, wykład 7 9 Skąd biorą się okienka w programie - backends Grafika wyświetlana przez matplotlib pojawia się w oknie, które tworzone jest przez manadżera okien (WindowManager) i zależy od środowiska w jakim pracujemy. Backend, to biblioteka elementów odpowiedzialna za obsługę i rysowanie okien. Standardowo Python obsługuje okna poprzez bibliotekę Tkinter czyli "backend Tk". import matplotlib as mpl mpl.use('TkAgg') # informuje matplotlib, że rysuje używając Tk import mpl.backends.backend_tkagg Uwaga, nie musi to być konieczne, jeżeli backend ma poprawnie ustawioną domyślną wartość! Domyślny backend możemy sprawdzić poprzez funkcję mpl.get_backend() 'TkAgg' Programowanie FizMed, wykład 7 10 Backend Canvas - Figure Wcześniej, przy omawianiu matplotlib, powiedziane było, że Figure jest podstawowym elementem rysunku. Jest to stwierdzenie prawdziwe z punktu widzenia matplotlib. W związku z istnieniem różnych backendów konieczne było utworzenie jeszcze jednego, pośredniego etapu pomiędzy menadżerem okien a matplotlib tzw. Canvas ("Płótno"). System operacyjny Menadżer okien Backend - Matplotlib - Canvas Figure Programowanie FizMed, wykład 7 11 Backend Canvas - Figure Tak więc system operacyjny poprzez menadżera okien, tworzy okno. Wybrany przez nas backend jest pośrednikiem pomiędzy oknem a matplotlib poprzez Canvas ("płótno"). Wcześniej, gdy używaliśmu funkcji show() z konsoli Python odbywało się to automatycznie, przy użyciu domyślnych ustawień. W przypadku pisania niezależnego programu należy to zrobić samodzielnie. Aby wyświetlić puste okno potrzebujemy 2 elementy: Canvas oraz Toolbar, które musimy osadzić na oknie dostarczonym przez Tkinter. import matplotlib matplotlib.use('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg FigureCanvasTkAgg NavigationToolbar2TkAgg Programowanie FizMed, wykład 7 12 Python 2 czy 3? Moduł Tkinter, a co za tym idzie backend TkAgg, jest obecny w każdej dystrybucji Pythona i jest niezależny od modułu matplotlib. Obecny jest standardowo w Pythonie 2 i 3, z tym, że zmienione zostały nazwy głównych obiektów oraz modułów. Można jednak w prosty sposób ominąć ten problem i stworzyć kod, który będzie działał w obu wersjach Pythona. Kod na następnym slajdzie: 1/ Załaduje matplotlib z odpowiednim backendem. 2/ Musi to być zrobione przed wczytaniem innych modułów z matplotlib 3/ Sprawdzi, która wersja Pythona go wykonuje. 4/ W zależności od wersji Pythona, załaduje odpowiednie moduły z Tkinter Na końcu zostanie utworzony przkładowy wykres. Programowanie FizMed, wykład 7 13 Prosty program z oknem "od zera" - początek import matplotlib as mpl mpl.use('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg import matplotlib.pyplot as plt import sys if sys.hexversion >= 0x03000000: inPy3 = True import tkinter as Tkinter import tkinter.scrolledtext as ScrolledText import tkinter.messagebox as tkmb import tkinter.simpledialog as SimpleDialog import tkinter.filedialog as FileDialog else: inPy3 = False import Tkinter as Tkinter import ScrolledText as ScrolledText import tkMessageBox as tkmb import tkSimpleDialog as SimpleDialog import tkFileDialog as FileDialog Programowanie FizMed, wykład 7 14 Osadzanie matplotlib w Tkinter Następnie musimy: 1/ Utworzyć okno w menadżerze okien 2/ Utworzyć rysunek (Figure) pyplot 3/ Związać z tym oknem Canvas i NavigationToolbar. 4/ Rozmieścić elementy w oknie 5/ Narysować rysunek w Canvas. T = Tkinter.Tk() # tworzymy puste okno na bazie Tkinter.Tk() T.grid() # wybieramy sposób organizacji elementów w oknie Myfig = plt.figure() # tworzymy Figurę pyplot Canvas = FigureCanvasTkAgg(Myfig, master=T) Toolbar = NavigationToolbar2TkAgg(Canvas, T) Toolbar.update() Toolbar.grid(column=0,row=0, sticky=Tkinter.W+ Tkinter.N+Tkinter.S) Canvas._tkcanvas.grid(column=0,row=1, sticky = Tkinter.W+Tkinter.E+ Tkinter.N+ Tkinter.S) ax1 = Myfig.add_subplot(111) ax1.plot([1,2,3,4]) Canvas.show() ax1.clear() Canvas.show() Programowanie FizMed, wykład 7 15 #itd Tkinter = okienka w Pythonie http://docs.python.org/release/3.1.5/library/tkinter.html http://fossies.org/dox/Python-3.2.3/namespacetkinter.html Moduł Tkinter służy do obsługi "okienek" w Pythonie. Najprostsze z nich to okienka dialogowe, które pozwalają np. podać liczbę całkowitą, wybrać nazwę pliku do odczytu lub zapisu, zarządać od użytkownika potwierdzenia jakiejś akcji. Możemy je zrealizować poprzez 3 główne moduły (nazwy z Python3) import tkinter.messagebox as MessageBox import tkinter.simpledialog as SimpleDialog import tkinter.filedialog as FileDialog import tkinter.colorchooser as ColorDialog Jeżeli nie zostało to zrobione wcześniej, utworzenie takiego okienka powoduje pojawienie się również domyślnego głównego okna. Najlepiej jest go utworzyć samemu i zaraz schować. root = tkinter.Tk() root.withdraw() Programowanie FizMed, wykład 7 16 tkinter.messagebox http://docs.python.org/release/3.1.5/library/tkinter.html import tkinter.messagebox as tkmb #Python 3 import Tkinter.tkMessageBox as tkmb #Python 2 Okna, których wynikiem jest odpowiedz dająca się przedstawić w postaci "Tak", "Nie" lub "Nie wiem" możemy utworzyć korzystając z następujących metod. Wartości, które zwracają w zależności od wciśniętego przycisku znajdują sie po znaku '#' tkmb.askokcancel("Tytuł okna", "Wiadomość") #OK=True, Cancel=False tkmb.askretrycancel("Tytuł okna", "Wiadomość") #True, False tkmb.askyesno("Tytuł okna", "Wiadomość") #True, False tkmb.askyesnocancel("Tytuł okna", "Wiadomość") #True, False, None tkmb.askquestion("Tytuł okna", "Wiadomość") # "yes", "no" Okna, które wymagają tylko prostego potwierdzenia tworzymy poprzez: tkmb.showerror("Tytuł okna", "Wiadomość") tkmb.showinfo("Tytuł okna", "Wiadomość") Przykłady tkmb.showwarning("Tytuł okna", "Wiadomość") Programowanie FizMed, wykład 7 17 tkinter.simpledialog import tkinter.simpledialog as SD #Python 3 import Tkinter.tkSimpleDialog as SD #Python 2 Okna, których wynikiem jest odpowiedz dająca się przedstawić w postaci liczby lub ciągu znaków tworzymy przy pomocy klasy simpledialog. Argumenty title i prompt moga wystąpić jako argumenty pozycyjne. SD.askinterger(title="Tytuł okna", prompt="Wiadomość", initialvalue= domyślna_wartość_str) SD.askfloat("Tytuł okna", "Wiadomość", initialvalue= domyślna_wartość_str) SD.askstring("Tytuł okna", "Wiadomość", initialvalue= domyślna_wartość_str) Uwaga! Domyślna wartość we wszystkich przypadkach powinna być konwertowana na typ str, bo taka jest zawartość okna dialogowego. SD.askfloat("Pytanie", "Podaj liczbę", initialvalue=0.0) # ! nie wyświetli się! SD.askfloat("Pytanie", "Podaj liczbę", initialvalue=str(0.0)) # OK! Przykłady Programowanie FizMed, wykład 7 18 tkinter.filedialog import tkinter.filedialog as FD #Python 3 import Tkinter.tkFileDialog as FD #Python 2 http://tkinter.unpythonic.net/wiki/tkFileDialog Okna, których celem jest znalezienie istniejącego pliku, katalogu lub podanie nazwy pliku do zapisu tworzymy przy pomocy klasy filedialog. Niektóre jej metody: #zwraca str z nazwą katalogu FD.askdirectory(title="Tytuł okna", initialdir="początkowy_katalog") # zwraca obiekt file ('uchwyt' na plik) FD.askopenfile(title="Tytuł okna", mode="tryb_otwarcia", initialdir="." ) # zwraca nazwę pliku FD.askopenfilename(title="Tytuł okna", initialdir= ".") FD.asksaveasfile(title="Tytuł okna", prompt="Wiadomość", initialvalue= domyślna_wartość_str) FD.asksaveasfilename(title="Tytuł okna", prompt="Wiadomość", initialvalue= domyślna_wartość_str) Okna typu save lub open moga mieć dodatkową opcję wskazującą na rozszerzenia plików, których można użyć. filetypes = lista 2-krotek ("opis", "*.rozszerzenie") filetypes = [("Word","*.doc"), ("RTF", "*.rtf")] Przykłady Programowanie FizMed, wykład 7 19 Widgety Tkinter Widgety są elementarnymi składnikami okna. Sa nimi np przyciski (Button), etykiety (Label), pola tekstowe (Text, scrolledtext). tkinter.Label lblTmin = tkTkinter.Label(text = str(10.0)) lblTmax = tkTkinter.Label() lblTmax["text"] = "100.0" tkinter.Button QUIT = tkinter.Button(text = "QUIT", fg = "blue", command = _quit) hi_there = tkinter.Button(text = "Instructions", command = say_hi) tkinter.Text mojtext = tkinter.Text(text = "Opis", fg = "blue") tkinter.scrolledtext txtInfo = scrolledtext.ScrolledText(wrap="word", width=40, height = 5) Widgetem jest również obiekt Canvas, na którym możemy umieścić obrazek z matplotlib Programowanie FizMed, wykład 7 20 Tkinter.Button Button(Przycisk) służy do wywołania pewnej akcji (funkcji) po jego naciśnięciu. QUIT = tkinter.Button(text = "QUIT", fg = "blue", command = _quit) hi_there = tkinter.Button(text = "Instructions", command = say_hi) Możemy go zablokować poprzez zmianę stanu na "nieaktywny" QUIT.config(state = "disabled") Lub ponownie aktywować QUIT.config(state = "normal") Aby przycisk mógł poprawnie działać musimy zdefiniować funkcję, która będzie wywołana przy jego wciśnięciu, tzw. Callback. W powyższym przykładzie potrzebujemy dwie funkcje: def _quit(): print("wychodzę z aplikacji") quit() def say_hi(): print("Hi!") Programowanie FizMed, wykład 7 21 Menadżery geometrii pack i grid Menadżery geometrii służą do rozmieszczania widgetów w oknie. Grid działa podobnie do sposobu tworzenia tabeli w HTML. Chcemy utworzyć następujące okno - rodzaj kontrolek nie gra roli. Programowanie FizMed, wykład 7 22 Menadżery geometrii grid Pierwszym krokiem jest wirtualne podzielenie tego okna na równe kawałki. columns = kolumny el1 el2 el3 el4 el5 el6 el7 el8 el9 el10 el11 Programowanie FizMed, wykład 7 23 rows = rzędy Menadżery geometrii grid Elementy w naszym szkielecie umieszczamy przy pomocy zmiennych column i row el1.grid(column=0, row=0, sticky=Tkinter.W+Tkinter.E) el2.grid(column=1, row=0, sticky=Tkinter.W+Tkinter.E) el3.grid(column=2, row=0, sticky=Tkinter.W+Tkinter.E) el4.grid(column=3, row=0, sticky=Tkinter.W+Tkinter.E) el5.grid(column=4, row=0, sticky=Tkinter.W+Tkinter.E) el6.grid(column=0, row=1, sticky=Tkinter.W+Tkinter.E) Elementy, które zajmują więcej miejsca musimy "rozciągnąć" parametrami colspan i rowspan. el7.grid(column=1, row=1, colspan = 4, rowspan= 3, sticky=Tkinter.W+Tkinter.E+Tkinter.S+Tkinter.N) el11.grid(column=1, row=4, colspan = 4, rowspan= 1, sticky=Tkinter.W+Tkinter.E+Tkinter.S+Tkinter.N) Parametr "sticky" określa w jaki sposób kontrolka wypełnia przeznaczone jej miejsce. Programowanie FizMed, wykład 7 24 Tkinter w programie Okienek bazujących na Tkinter możemy używać w sesji interaktywnej jak i w programie nieinteraktywnym. W tym drugim przypadku zwykle tworzymy nową klasę, która tworzy nam okno (o tworzeniu klas już mówiliśmy). # Tu się zaczyna definicja klasy (jeszcze nie kompletna) class clsMoja(Tkinter.Tk): # klasa dziedziczy po obiekcie Tk z modułu Tkinter def __init__(self, parent): # metoda __init__ inicjalizuje okno Tkinter.Tk.__init__(self, parent) # można przez super. self.parent=parent #wybieramy menadżer geometrii self.grid() # następnie tworzymy elementy okna self.hi_there = Tkinter.Button(self,text = "Instructions", command = self.say_hi) # Tu się zaczyna główny program if __name__ == "__main__": app = clsMoja(None) app.title('Tytuł aplikacji') app.mainloop() Programowanie FizMed, wykład 7 25 Program z jednym przyciskiem #/usr/bin/python3 import tkinter as Tkinter # Tu się zaczyna definicja class clsMoja(Tkinter.Tk): def __init__(self, parent): Tkinter.Tk.__init__(self, parent) self.parent=parent self.grid() self.hi_there = Tkinter.Button(self,text = "Mówię hi", command = self.say_hi) self.hi_there.grid(column=0, row=0, sticky=Tkinter.E+Tkinter.S+Tkinter.W+Tkinter.N) def say_hi(self): Tkinter.messagebox.showinfo("Ważna informacja", "Hi !") # Tu się zaczyna główny program if __name__ == "__main__": app = clsMoja(None) app.title('Tytuł aplikacji') app.mainloop() Programowanie FizMed, wykład 7 26 Koniec na dzisiaj! Programowanie FizMed, wykład 7 27