• Nie Znaleziono Wyników

Programowanie¶ Wykład 6 - Przegląd bibliotek naukowych: matplotlib

N/A
N/A
Protected

Academic year: 2022

Share "Programowanie¶ Wykład 6 - Przegląd bibliotek naukowych: matplotlib"

Copied!
51
0
0

Pełen tekst

(1)

Programowanie ¶

Wykład 6 - Przegląd bibliotek naukowych: matplotlib

Plan wykładu:

Wprowadzenie Prawie jak Matlab

Matplotlib i obiektowe API Wybrane typy wykresów 2D Jeszcze o układzie wykresów Mapy kolorów i wykresy konturowe Wykresy 3D

Animacje

Materiały do wykładu:

http://matplotlib.org/ (http://matplotlib.org/)

wykład J.R. Johanssona "Scientific Python" dostępny pod adresem

http://github.com/jrjohansson/scientific-python-lectures (http://github.com/jrjohansson/scientific-python- lectures)

In [5]:

Wprowadzenie

Matplotlib to biblioteka do wykresów 2D i 3D:

łatwa w obsłudze

zainspirowana Matlabem różne typy wykresów

"publikacyjna" jakość

formatowanie etykiet i tekstów przy pomocy -a

duża kontrola nad wszystkimi elementami wykresu, z DPI włącznie

GUI do interaktywnej pracy z wykresem lub przetwarzanie wsadowe z zapisem wykresu do pliku wsparcie dla wielu formatów wyjściowych (m.in. PNG, PDF, SVG, EPS i PGF)

możliwość osadzania wykresów we własnych GUI współpracuje z NumPY

Aby móc używać Matplotlib z poziomu programu napisanego w Pythonie, musimy zaimportować bibliotekę.

Możemy to zrobić na dwa sposoby. Albo korzystając z modułu pylab:

LT X

A

E

# Poniższe polecenie skonfiguruje matplotlib w taki sposób, aby

# wygenerowane rysunki były wstawiane bezpośrednio do notatnika IPythona,

%matplotlib inline

(2)

albo importując matplotlib.pyplot:

In [7]:

Moduł pylab łączy ze sobą funkcjonalność pyplot (tworzenie wykresów) z numpy (operacje na macierzach) w jednej przestrzeni nazw. Praca z (I)Pythonem przypomina wówczas pracę w Matlabie. Natomiast ten drugi sposób jest preferowany jako bardziej przejrzysty, mimo że z reguły jest trochę bardziej uciążliwy w

użytkowaniu. Jeżeli planujemy osadzać wykresy we własnych GUI, pracujemy z modułem matplotlib i kilkoma jego podmodułami.

Prawie jak Matlab

Moduł pylab zaprojektowano w taki sposób, aby polecenia rysowania funkcji były kompatybilne z poleceniami Matlaba (ma to ułatwić rozpoczęcie pracy z Pythonem ludziom znającym Matlaba).

In [8]:

Najprostszy wykres:

In [9]:

Wykres zależności funkcyjnej:

Out[9]:

[<matplotlib.lines.Line2D at 0x7ff7583cdb70>]

from pylab import *

import matplotlib.pyplot as plt

from pylab import *

plot([1,2,3,4])

(3)

In [11]:

Większość matlabowych poleceń działa:

Out[11]:

<matplotlib.text.Text at 0x7ff758329e10>

x = linspace(0, 5, 10) y = x ** 2

figure()

plot(x, y, 'r') #'r' to czerwona linia xlabel('x') # opis osi x

ylabel('y') # opis osi y

title('$y=x^2$') # tytuł wykresu, formatowanie LaTeX-a

(4)

In [13]:

Typy linii i punktów:

Symbol Znaczenie

- linia ciągła (domyślny styl) -- linia przerywana

-. linia przerywana (kreska-kropka-kreska) Out[12]:

[<matplotlib.lines.Line2D at 0x7ff758291e48>]

Out[13]:

[<matplotlib.lines.Line2D at 0x7ff7583aa080>]

subplot(1,2,1) #jeden wiersz, dwie kolumny, rysunek pierwszy plot(x, y, 'r--') #czerwona linia przerywana

subplot(1,2,2) #jeden wiersz, dwie kolumny, rysunek drugi plot(y, x, 'g*-') #zielona linia+punkty w formie gwiazdek

#zmiana zakresów axis([-1,6,-1,26])

plot(x, y, 'ro-') #czerwona linia + punkty w formie dysków

(5)

: linia kropkowana . punkty

, piksele o dyski

^ trójkąty skierowane do góry v trójkąty skierowane w dół

< trójkąty skierowane w lewo

> trójkąty skierowane w prawo s kwadraty

D diamenty

d "odchudzone" diamenty + symbole +

x symbole x

* symbole *

1 trójnogi skierowane w dół 2 trójnogi skierowane w górę 3 trójnogi skierowane w lewo 4 trójnogi skierowane w prawo

h sześciokąty (wierzchołkiem do góry) H sześciokąty (bokiem do góry) p pięciokąty

| linie pionowe _ linie poziome

steps styl steps z Gnuplota Kolory:

Symbol Znaczenie

b niebieski (domyślny) g zielony

r czerwony c cyjan m magenta y żółty k czarny

(6)

In [14]:

Właściwości linii:

In [15]:

Out[14]:

[<matplotlib.lines.Line2D at 0x7ff758159be0>, <matplotlib.lines.Line2D at 0x7ff758159d68>, <matplotlib.lines.Line2D at 0x7ff75815f6d8>]

t = arange(0.0,5.2,0.2)

plot(t,t,'ro',t,t**2,'bs',t,t**3,'g^')

lines = plot([1,2,3,4])

(7)

agg_filter: unknown

alpha: float (0.0 transparent through 1.0 opaque) animated: [True | False]

antialiased or aa: [True | False]

axes: an :class:`~matplotlib.axes.Axes` instance

clip_box: a :class:`matplotlib.transforms.Bbox` instance clip_on: [True | False]

clip_path: [ (:class:`~matplotlib.path.Path`, :class:`~matplotlib.t ransforms.Transform`) | :class:`~matplotlib.patches.Patch` | None ]

color or c: any matplotlib color contains: a callable function

dash_capstyle: ['butt' | 'round' | 'projecting']

dash_joinstyle: ['miter' | 'round' | 'bevel']

dashes: sequence of on/off ink in points

drawstyle: ['default' | 'steps' | 'steps-pre' | 'steps-mid' | 'step s-post']

figure: a :class:`matplotlib.figure.Figure` instance

fillstyle: ['full' | 'left' | 'right' | 'bottom' | 'top' | 'none']

gid: an id string

label: string or anything printable with '%s' conversion.

linestyle or ls: ['solid' | 'dashed', 'dashdot', 'dotted' | (offse t, on-off-dash-seq) | ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'No ne'`` | ``' '`` | ``''``]

linewidth or lw: float value in points

marker: :mod:`A valid marker style <matplotlib.markers>`

markeredgecolor or mec: any matplotlib color markeredgewidth or mew: float value in points markerfacecolor or mfc: any matplotlib color

markerfacecoloralt or mfcalt: any matplotlib color markersize or ms: float

markevery: [None | int | length-2 tuple of int | slice | list/array of int | float | length-2 tuple of float]

path_effects: unknown

picker: float distance in points or callable pick function ``fn(art ist, event)``

pickradius: float distance in points rasterized: [True | False | None]

sketch_params: unknown snap: unknown

solid_capstyle: ['butt' | 'round' | 'projecting']

solid_joinstyle: ['miter' | 'round' | 'bevel']

transform: a :class:`matplotlib.transforms.Transform` instance url: a url string

visible: [True | False]

xdata: 1D array ydata: 1D array zorder: any number setp(lines)

(8)

In [18]:

Wybrane własności:

Własność Znaczenie

alpha przezroczystość (od 0. do 1.) Out[17]:

[<matplotlib.lines.Line2D at 0x7ff7580ae0b8>, <matplotlib.lines.Line2D at 0x7ff7580ae358>]

Out[18]:

[<matplotlib.lines.Line2D at 0x7ff758089cc0>, <matplotlib.lines.Line2D at 0x7ff758089f60>]

x = arange(0,2*pi,pi/100) si = sin(x)

co = cos(x)

plot(x,si,'b-.',x,co,'r--')

x = arange(0,2*pi,pi/100) si = sin(x)

co = cos(x)

plot(x,si,'b-.',x,co,'r--',linewidth=3.0)

(9)

antialiased antyaliasing (True lub False)

color kolor

data_cliping obcinanie danych (True lub False) label łańcuch znaków używany jako legenda linestyle styl linii

linewidth grubość linii

marker symbol przy wykreślaniu danych dyskretnych markeredgewidth grubość krawędzi symbolu

makeredgecolor kolor krawędzi symbolu makerfacecolor kolor symbolu

markersize wielkość symbolu

Jeszcze o trybie wielowykresowym:

In [19]:

In [20]:

Out[19]:

<matplotlib.figure.Figure at 0x7ff758024710>

<matplotlib.figure.Figure at 0x7ff758024710>

figure(1) #aktywny rysunek

t1 = arange(0.0,5.0,0.1) t2 = arange(0.0,2.0,0.01) def f(t):

return cos(t*t)

(10)

Na wykresie możemy również umieszczać tekst. Możliwości jest kilka:

opisy osi tytuł wykresu legenda

tekst wstawiany "ręcznie"

Coś prostego na początek, czyli opisy osi i tytuł wykresu:

Out[21]:

[<matplotlib.lines.Line2D at 0x7ff757ffa978>]

#tworzymy rysunek złożonych z dwóch wykresów położonych jeden nad drugim subplot(211)

plot(t1,f(t1),linewidth=3.0) subplot(212)

plot(t2,f(t2),'r--',linewidth=8.0)

(11)

Dodajemy legendę:

Out[22]:

<matplotlib.text.Text at 0x7ff757f92080>

x = arange(0.0,2*pi,pi/100) si = sin(x)

co = cos(x)

plot(x,si,'g-',x,co,'r--',linewidth=3.0)

#opis osi x xlabel('x')

ylabel('sin(x), cos(x)')

#tytuł wykresu

title('Funkcje trygonometryczne')

(12)

Dodajemy do wykresu dowolny tekst:

Out[23]:

<matplotlib.legend.Legend at 0x7ff757e94f28>

#dodajemy legendę

plot(x,si,'g-',x,co,'r--',linewidth=3.0)

#opis osi x xlabel('x')

ylabel('sin(x), cos(x)')

#tytuł wykresu

title('Funkcje trygonometryczne')

legend(('sin(x)','cos(x)')) #etykiety w kolejności wywołań w funkcji plot

(13)

W pewnych przypadkach warto jest skorzystać z formatowania $\LaTeX$-a:

Out[24]:

<matplotlib.text.Text at 0x7ff757e89550>

plot(x,si,'g-',x,co,'r--',linewidth=3.0) xlabel('x')

ylabel('sin(x), cos(x)')

title('Funkcje trygonometryczne') legend(('sin(x)','cos(x)'))

#tekst o początku w punkcie (3,0.5) text(3,0.5,'trajektoria')

(14)

Matplotlib i obiektowe API

Pylab ma z pewnością dwie zalety:

ułatwia rozpoczęcie pracy osobom mającym doświadczenie z Matlaba i GNU Octave redukuje ilość kodu niezbędną do stworzenia prostego wykresu do minimum.

Mimo to warto jest poświęcić trochę uwagi obiektowemu API oferowanemu przez matplotlib, które

wprawdzie nie jest zgodne z Matlabem i wymaga większego nakładu pracy przy kodowaniu, ale za to pozwala na dużo większą kontrolę nad tworzonymi wykresami.

Dla przypomnienia, matplotlib importujemy teraz w następujący sposób:

In [26]:

In [27]:

Stwórzmy teraz prosty wykres. W przeciwieństwie do pylab, będzie on miał charakter lokalny, a referencję do niego możemy przypisać pewnej zmiennej:

Out[25]:

<matplotlib.text.Text at 0x7ff757ec5940>

def f(x):

return (x**3)*exp(-x**2/4.) x = arange(0.0,10.0,0.5)

y = f(x)

plot(x,y,'ro')

xlabel('$x$',fontsize=24)

ylabel('$x^{3}e^{-x^2/4}$',fontsize=24)

%matplotlib inline

import matplotlib.pyplot as plt

(15)

Rozważmy teraz trochę bardziej skomplikowany przykład - wykres w wykresie. Dzięki pyplot mamy pełną kontrolę nad tym, gdzie wstawiać poszczególne układy współrzędnych i jak je opisać:

Figure(432x288)

fig = plt.figure() #tworzymy instancję obiektu Figure print(fig)

#dodajemy do rysunku osie układu współrzędnych

axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # lewy, dolny, szerokość, wysokość (zakre

#do osi dodajemy wykres axes.plot(x, y, 'ro')

#opisujemy wykres axes.set_xlabel('x') axes.set_ylabel('y')

axes.set_title('$x^{3}e^{-x^2/4}$',fontsize=24);

(16)

Jeżeli mamy do wykonania wiele wykresów na jednym rysunku, ale nie interesuje nas za bardzo, gdzie każdy z nich powinien być wstawiony, możemy skorzystać z funkcji zarządzających ich układem na stronie. Jedną z nich jest subplots:

x = linspace(0,5,10) y = x**2

fig = plt.figure()

axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # główny układ współrzędnych

axes2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # układ współrzędnych wstawionego wykres

# główny wykres

axes1.plot(x, y, 'r') axes1.set_xlabel('x') axes1.set_ylabel('y')

axes1.set_title(u'Główny wykres')

# wstawka

axes2.plot(y, x, 'g') axes2.set_xlabel('y') axes2.set_ylabel('x')

axes2.set_title('Wstawka');

(17)

In [31]:

Jedyny problem, jaki tutaj się pojawił, to nachodzenie etykiety osi jednego wykresu na drugi. Możemy to naprawić przy pomocy metody fig.tight_layout:

fig, axes = plt.subplots() axes.plot(x, y, 'r')

axes.set_xlabel('x') axes.set_ylabel('y') axes.set_title('title');

#dwa wykresy obok siebie

fig, axes = plt.subplots(nrows=1, ncols=2) for ax in axes:

ax.plot(x, y, 'r') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title(u'Tytuł')

(18)

In [33]:

fig, axes = plt.subplots(nrows=1, ncols=2) for ax in axes:

ax.plot(x, y, 'r') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title(u'Tytuł')

fig.tight_layout()

#i jeszcze raz to samo, tylko teraz jeden wykres nad drugim:

fig, axes = plt.subplots(nrows=2, ncols=1) for ax in axes:

ax.plot(x, y, 'r') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title(u'Tytuł')

fig.tight_layout()

(19)

Tworząc instancję obiektu Figure możemy określić, jak duży ma być rysunek (w calach), oraz w jakiej rozdzielczości narysowany. Np. aby stworzyć wykres o rozmiarze 800x400 pikseli w rozdzielczości 100 dpi, wykonamy polecenie:

In [34]:

Tych samych argumentów możemy użyć w funkcjach zarządzających układem wykresów:

In [35]:

Zapisywanie wykresów

Wykres zapiszemy do pliku przy pomocy metody savefig:

In [36]:

Opcjonalnie, możemy podać rozdzielczość oraz zmienić format wyjściowy:

In [37]:

Dostępne formaty:

Figure(800x400)

<matplotlib.figure.Figure at 0x7ff757d2d9e8>

fig = plt.figure(figsize=(8,4), dpi=100) # (szerokość, wysokość) print(fig)

fig, axes = plt.subplots(figsize=(12,3)) axes.plot(x, y, 'r')

axes.set_xlabel('x') axes.set_ylabel('y') axes.set_title(u'Tytuł');

fig.savefig("filename.png")

fig.savefig("filename.pdf", dpi=200)

(20)

SVG PGF PDF

W zastosowaniach naukowych ciągle chyba najbardziej popularny jest format EPS ("naturalny" format

$\LaTeX$-a), jednak coraz częściej stosuje się PDF jako formatu zapisu wykresów. Jest to związane również z tym, że pdflatex pozwala na bezpośrednie wstawianie wykresów PDF.

Legenda, opisy osi oraz tutył wykresu

Tytuł rysunku może być dodany oddzielnie do każdej instancji osi na rysunku:

In [38]:

Podobnie dodajemy opisy osi:

Out[38]:

<matplotlib.text.Text at 0x7ff7926e7b38>

fig, ax = plt.subplots() ax.plot(x, x**2)

ax.plot(x, x**3)

ax.set_title('Dwie funkcje na jednym wykresie')

(21)

Legendę możemy dodać na dwa sposoby. Pierwszy z nich, to metoda legend obiektu axis, składnią przypominająca funkcję z pylaba. Jako argument podajemy krotkę etykiet dla wcześniej zdefiniowanych krzywych (w porządku definiowania):

Out[39]:

<matplotlib.text.Text at 0x7ff75758ef28>

fig, ax = plt.subplots() ax.plot(x, x**2)

ax.plot(x, x**3) ax.set_xlabel('x') ax.set_ylabel('y')

ax.set_title('Dwie funkcje na jednym wykresie')

(22)

Lepszy sposób to użycie argumentu label="label text" w funkcji plot:

/usr/local/lib/python3.5/dist-packages/matplotlib/axes/_axes.py:531:

UserWarning: No labelled objects found. Use label='...' kwarg on indi vidual plots.

warnings.warn("No labelled objects found. "

fig, ax = plt.subplots() ax.plot(x, x**2)

ax.plot(x, x**3)

ax.legend(loc=2); # lewy górny róg ax.set_xlabel('x')

ax.set_ylabel('y') ax.set_title('title');

ax.legend(("y = x**2","y = x**3"));

(23)

Zaletą tej drugiej metody jest automatyczna aktualizacja legendy w przypadku dodawania lub usuwania krzywych z wykresu.

Funkcja legend przyjmuje opcjonalny argument określający położenie legendy na wykresie:

Out[41]:

<matplotlib.legend.Legend at 0x7ff757b524e0>

fig, ax = plt.subplots()

ax.plot(x, x**2, label="y = x**2") ax.plot(x, x**3, label="y = x**3") ax.set_xlabel('x')

ax.set_ylabel('y') ax.set_title('title');

ax.legend() #tego ciągle potrzebujemy

(24)

Więcej na temat legendy można znaleźć pod adresem http://matplotlib.org/users/legend_guide.html#legend- location (http://matplotlib.org/users/legend_guide.html#legend-location).

Formatowanie tekstu

Kilka prostych przykładów formatowania tekstu przy pomocy $\LaTeX$-a zostało już omówionych powyżej.

Formatowanie to jest w zasadzie bezproblemowe, z jednym wyjątkiem - stosowany często w $\LaTeX$-u znak

\ ma również znaczenie w Pythonie (stanowi znak ucieczki. Problem rozwiążemy, wskazując Pythonowi, że wyrażenie tekstowe ma interpretować dosłownie:

x = linspace(0,5,10)

fig, axes = plt.subplots(nrows=4,ncols=3,figsize=(16,12), dpi=100) lok = 0 #lokalizacja legendy

for ax in axes.ravel(): #musimy spłaszczyć tablicę osi ax.plot(x, x**2, label="y = x**2")

ax.plot(x, x**3, label="y = x**3") ax.set_xlabel('x')

ax.set_ylabel('y')

ax.set_title('loc=%d'%lok);

ax.legend(loc=lok) lok = lok + 1

if lok > 10: break fig.tight_layout()

(25)

Rozmiar czcionki możemy zmienić globalnie:

In [44]:

fig, ax = plt.subplots()

ax.plot(x, x**2, label=r"$y = \alpha^2$") # r jak "raw"

ax.plot(x, x**3, label=r"$y = \alpha^3$") ax.legend(loc=2) # lewy górny róg

ax.set_xlabel(r'$\alpha$', fontsize=18) ax.set_ylabel(r'$y$', fontsize=18)

ax.set_title('Backslash w wyrażeniach LaTeX-a');

# zmiana parametrów konfiguracji matplotlib

matplotlib.rcParams.update({'font.size': 16, 'font.family': 'serif'})

(26)

W pracach naukowych bardzo dobrze prezentują się czcionki STIX:

In [46]:

fig, ax = plt.subplots()

ax.plot(x, x**2, label=r"$y = \alpha^2$") # r jak "raw"

ax.plot(x, x**3, label=r"$y = \alpha^3$") ax.legend(loc=2) # lewy górny róg

ax.set_xlabel(r'$\alpha$', fontsize=18) ax.set_ylabel(r'$y$', fontsize=18)

ax.set_title('Backslash w wyrażeniach LaTeX-a');

matplotlib.rcParams.update({'font.size': 12, 'font.family': 'STIXGeneral', 'mathtex

(27)

Kolor, grubość i typ linii

Jednym ze sposobów zmiany koloru linii albo symbolu jest ten znany z pylab (zgodny z Matlabem).

fig, ax = plt.subplots()

ax.plot(x, x**2, label=r"$y = \alpha^2$") # r jak "raw"

ax.plot(x, x**3, label=r"$y = \alpha^3$") ax.legend(loc=2) # lewy górny róg

ax.set_xlabel(r'$\alpha$', fontsize=18) ax.set_ylabel(r'$y$', fontsize=18)

ax.set_title('Backslash w wyrażeniach LaTeX-a');

(28)

Inna możliwość to klucz color. Przy tym, oprócz predefiniowanych kolorów, możemy używać kodów RGB:

In [51]:

Out[51]:

[<matplotlib.lines.Line2D at 0x7ff756dafe10>]

fig, ax = plt.subplots()

ax.plot(x, x**2,'g-', label=r"$y = \alpha^2$") # r jak "raw"

ax.plot(x, x**3,'b-', label=r"$y = \alpha^3$") ax.legend(loc=2) # lewy górny róg

ax.set_xlabel(r'$\alpha$') ax.set_ylabel(r'$y$')

ax.set_title('LaTeX w akcji');

fig, ax = plt.subplots()

ax.plot(x, x+1, color="red", alpha=0.5) # półprzezroczysty czerwony ax.plot(x, x+2, color="#1155dd") # (jakiś) niebieski

ax.plot(x, x+3, color="#15cc55") # (jakiś) zielony

(29)

In [52]:

Formatowanie osi

Jednym z elementów osi układu współrzędnych, który możemy modyfikować, jest zakres wartości zmiennej:

fig, ax = plt.subplots(figsize=(12,6))

ax.plot(x, x+1, color="blue", linewidth=0.25) ax.plot(x, x+2, color="blue", linewidth=0.50) ax.plot(x, x+3, color="blue", linewidth=1.00) ax.plot(x, x+4, color="blue", linewidth=2.00)

# możliwe typy linii to ‘-‘, ‘–’, ‘-.’, ‘:’, ‘steps’

ax.plot(x, x+5, color="red", lw=2, linestyle='-') ax.plot(x, x+6, color="red", lw=2, ls='-.')

ax.plot(x, x+7, color="red", lw=2, ls=':')

# własna linia przerywana

line, = ax.plot(x, x+8, color="black", lw=1.50)

line.set_dashes([5, 10, 15, 10]) # format: długość kreski, długość przerwy, ...

# możliwe typy symboli: marker = '+', 'o', '*', 's', ',', '.', '1', '2', '3', '4', ax.plot(x, x+ 9, color="green", lw=2, ls='', marker='+')

ax.plot(x, x+10, color="green", lw=2, ls='', marker='o') ax.plot(x, x+11, color="green", lw=2, ls='', marker='s') ax.plot(x, x+12, color="green", lw=2, ls='', marker='1')

# rozmiar i kolor symbolu

ax.plot(x, x+13, color="purple", lw=1, ls='-', marker='o', markersize=2) ax.plot(x, x+14, color="purple", lw=1, ls='-', marker='o', markersize=4)

ax.plot(x, x+15, color="purple", lw=1, ls='-', marker='o', markersize=8, markerface ax.plot(x, x+16, color="purple", lw=1, ls='-', marker='s', markersize=8,

markerfacecolor="yellow", markeredgewidth=2, markeredgecolor="blue");

(30)

Skalę logarytmiczną włączymy przy pomocy metod set_xscale i set_yscale z wartością log:

In [54]:

fig, axes = plt.subplots(1, 3, figsize=(12, 4)) axes[0].plot(x, x**2, x, x**3)

axes[0].set_title(u"zakresy domyślne") axes[1].plot(x, x**2, x, x**3)

axes[1].axis('tight') #ciasne upakowanie axes[1].set_title("ciasne upakowanie") axes[2].plot(x, x**2, x, x**3)

axes[2].set_ylim([0, 60]) #zakres y axes[2].set_xlim([2, 5]) #zakres x

axes[2].set_title(u"zakresy użytkownika");

fig, axes = plt.subplots(1, 2, figsize=(10,4))

axes[0].plot(x, x**2, x, exp(x)) axes[0].set_title("Skala liniowa") axes[1].plot(x, x**2, x, exp(x)) axes[1].set_yscale("log")

axes[1].set_title("Skala logarytmiczna (y)");

(31)

In [49]:

Więcej na temat podziałki pod adresem http://matplotlib.org/api/ticker_api.html (http://matplotlib.org/api/ticker_api.html).

Jeżeli na osiach mamy do przedstawienia duże wartości liczbowe, warto jest skorzystać z notacji naukowej:

fig, ax = plt.subplots(figsize=(10, 4)) ax.plot(x, x**2, x, x**3, lw=2)

ax.set_xticks([1, 2, 3, 4, 5]) #wartości podziałki na osi

#i odpowiadające im etykiety

ax.set_xticklabels([r'$\alpha$', r'$\beta$', r'$\gamma$', r'$\delta$', r'$\epsilon$

yticks = [0, 50, 100, 150]

ax.set_yticks(yticks)

ax.set_yticklabels(["$%.1f$" % y for y in yticks], fontsize=18); #wartości sformato

(32)

Odległość między osiami, a etykietami podziałki możemy również zmieniać:

fig, ax = plt.subplots(1, 1)

ax.plot(x, x**2, x, exp(x)) ax.set_title("Notacja naukowa")

ax.set_yticks([0, 50, 100, 150]) #wartości na osi y

from matplotlib import ticker #zaawansowane api do kontroli podziałki formatter = ticker.ScalarFormatter(useMathText=True)

formatter.set_scientific(True) #włączamy notację naukową formatter.set_powerlimits((-1,1))

ax.yaxis.set_major_formatter(formatter)

(33)

In [52]:

Metoda grid pozwoli włączyć siatkę na wykresie. Jej wygląd możemy zmieniać tymi samymi argumentami kluczowymi, które stosowaliśmy w metodzie plot:

# odległość wartości od osi rcParams['xtick.major.pad'] = 15 rcParams['ytick.major.pad'] = 15 fig, ax = plt.subplots(1, 1)

ax.plot(x, x**2, x, exp(x)) ax.set_yticks([0, 50, 100, 150])

ax.set_title(u"Odległość wartości od osi")

# padding between axis label and axis numbers ax.xaxis.labelpad = 5

ax.yaxis.labelpad = 5 ax.set_xlabel("x") ax.set_ylabel("y");

# powrót do ustawień domyślnych rcParams['xtick.major.pad'] = 3 rcParams['ytick.major.pad'] = 3

(34)

Wygląd osi również można zmieniać:

In [54]:

Czasami warto jest mieć 2 różne osie x lub y:

fig, axes = plt.subplots(1, 2, figsize=(10,3))

# siatka domyślna

axes[0].plot(x, x**2, x, x**3, lw=2) axes[0].grid(True)

# siatka po zmianach

axes[1].plot(x, x**2, x, x**3, lw=2)

axes[1].grid(color='b', alpha=0.5, linestyle='dashed', linewidth=1.5)

fig, ax = plt.subplots(figsize=(6,2))

ax.spines['bottom'].set_color('blue') # dolna oś niebieska ax.spines['top'].set_color('blue') # górna oś niebieska ax.spines['left'].set_color('red') # lewa oś czerwona ax.spines['left'].set_linewidth(2) # i o grubości 2

# wyłączamy prawą oś

ax.spines['right'].set_color("none")

ax.yaxis.tick_left() # podziałka tylko po lewej stronie

(35)

Poniższy przykład pozwoli nam przedstawić układ współrzędnych w formie znanej z kursu matematyki:

fig, ax1 = plt.subplots()

ax1.plot(x, x**2, lw=2, color="blue")

ax1.set_ylabel(r"area $(m^2)$", fontsize=18, color="blue") for label in ax1.get_yticklabels():

label.set_color("blue")

ax2 = ax1.twinx() #oś x jest taka sama dla obu krzywych ax2.plot(x, x**3, lw=2, color="red")

ax2.set_ylabel(r"volume $(m^3)$", fontsize=18, color="red") for label in ax2.get_yticklabels():

label.set_color("red")

(36)

Wybrane typy wykresów 2D

In [57]:

fig, ax = plt.subplots()

#wyłączamy oś prawą i górną

ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.xaxis.set_ticks_position('bottom')

ax.spines['bottom'].set_position(('data',0)) # ax.yaxis.set_ticks_position('left')

ax.spines['left'].set_position(('data',0)) # xx = np.linspace(-0.75, 1., 100)

ax.plot(xx, xx**3);

xx = np.linspace(-0.75, 1., 100) n = array([0,1,2,3,4,5])

(37)

In [59]:

fig, axes = plt.subplots(1, 4, figsize=(12,3)) axes[0].scatter(xx, xx + 0.25*randn(len(xx))) axes[0].set_title("scatter")

axes[1].step(n, n**2, lw=2) axes[1].set_title("step")

axes[2].bar(n, n**2, align="center", width=0.5, alpha=0.5) axes[2].set_title("bar")

axes[3].fill_between(x, x**2, x**3, color="green", alpha=0.5);

axes[3].set_title("fill_between");

# wykres we współrzędnych biegunowych fig = plt.figure()

ax = fig.add_axes([0.0, 0.0, .6, .6], polar=True) t = linspace(0, 2 * pi, 100)

ax.plot(t, t, color='blue', lw=3);

(38)

Jeszcze o układzie wykresów

subplots

# histogram

n = np.random.randn(100000)

fig, axes = plt.subplots(1, 2, figsize=(12,4)) axes[0].hist(n)

axes[0].set_title(u"Domyślny histogram") axes[0].set_xlim((min(n), max(n)))

axes[1].hist(n, cumulative=True, bins=50) axes[1].set_title(u"Wartości skumulowane") axes[1].set_xlim((min(n), max(n)));

(39)

subplot2grid

fig, ax = plt.subplots(2, 3) fig.tight_layout()

(40)

gridspec In [63]:

fig = plt.figure()

ax1 = plt.subplot2grid((3,3), (0,0), colspan=3) ax2 = plt.subplot2grid((3,3), (1,0), colspan=2) ax3 = plt.subplot2grid((3,3), (1,2), rowspan=2) ax4 = plt.subplot2grid((3,3), (2,0))

ax5 = plt.subplot2grid((3,3), (2,1)) fig.tight_layout()

import matplotlib.gridspec as gridspec

(41)

add_axes

Ręczne układanie wykresów ma w zasadzie sens jedynie w przypadku wstawiania jednego wykresu w drugi:

fig = plt.figure()

gs = gridspec.GridSpec(2, 3, height_ratios=[2,1], width_ratios=[1,2,1]) for g in gs:

ax = fig.add_subplot(g)

fig.tight_layout()

(42)

Mapy kolorów i wykresy konturowe

Mapy kolorów oraz wykresy konturowe to jeden z użytecznych sposobów na przedstawienie funkcji dwóch zmiennych.

Rozważmy następujący przykład:

fig, ax = plt.subplots() ax.plot(xx, xx**2, xx, xx**3) fig.tight_layout()

# mniejszy wykres

inset_ax = fig.add_axes([0.2, 0.55, 0.35, 0.35]) # X, Y, szer, wys inset_ax.plot(xx, xx**2, xx, xx**3)

inset_ax.set_title(u'W pobliżu (0,0)')

# zakres

inset_ax.set_xlim(-.2, .2) inset_ax.set_ylim(-.005, .01)

# podziałka

inset_ax.set_yticks([0, 0.005, 0.01]) inset_ax.set_xticks([-0.1,0,.1]);

(43)

Przed sporządzeniem wykresu funkcji dwóch zmiennych musimy najpierw wygenerować siatkę (polecenie meshgrid), w punktach której wyznaczymy wartości funkcji:

In [67]:

pcolor In [68]:

imshow alpha = 0.7

phi_ext = 2 * pi * 0.5

def flux_qubit_potential(phi_m, phi_p):

return 2 + alpha - 2 * cos(phi_p)*cos(phi_m) - alpha * cos(phi_ext - 2*phi_p)

phi_m = linspace(0, 2*pi, 100) phi_p = linspace(0, 2*pi, 100) X,Y = meshgrid(phi_p, phi_m) Z = flux_qubit_potential(X, Y).T

fig, ax = plt.subplots()

#argument cmap to mapa kolorów

#więcej na ten temat w dokumentacji matplotlib

p = ax.pcolor(X/(2*pi), Y/(2*pi), Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).m cb = fig.colorbar(p, ax=ax) #wyjaśnienie znaczenia kolorów

(44)

contour

fig, ax = plt.subplots()

im = ax.imshow(Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).max(), extent=[0, 1, im.set_interpolation('bilinear')

cb = fig.colorbar(im, ax=ax)

(45)

Wykresy 3D

Wykresy 3D wymagają stworzenia instancji klasy Axes3D:

In [71]:

Wykresy powierzchniowe:

fig, ax = plt.subplots()

cnt = ax.contour(Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).max(), extent=[0,

from mpl_toolkits.mplot3d.axes3d import Axes3D

(46)

Wykres szkieletowy

fig = plt.figure(figsize=(14,6))

# projection='3d' powoduje, że ax jest układem współrzędnych 3D ax = fig.add_subplot(1, 2, 1, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)

# wykres powierzchniowy z gradientem kolorów i legendą ax = fig.add_subplot(1, 2, 2, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, a cb = fig.colorbar(p, shrink=0.5)

(47)

Wykres powierzchniowy z rzutami fig = plt.figure(figsize=(8,6))

ax = fig.add_subplot(1, 1, 1, projection='3d')

p = ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4)

(48)

Zmiana perspektywy

fig = plt.figure(figsize=(8,6))

ax = fig.add_subplot(1,1,1, projection='3d')

ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)

cset = ax.contour(X, Y, Z, zdir='z', offset=-pi, cmap=cm.coolwarm) cset = ax.contour(X, Y, Z, zdir='x', offset=-pi, cmap=cm.coolwarm) cset = ax.contour(X, Y, Z, zdir='y', offset=3*pi, cmap=cm.coolwarm) ax.set_xlim3d(-pi, 2*pi);

ax.set_ylim3d(0, 3*pi);

ax.set_zlim3d(-pi, 2*pi);

(49)

Animacje

W bibliotece matplotlib znajdziemy również narzędzia do tworzenia prostych animacji złożonych z sekwencji rysunków. Funkcja FuncAnimation pozwala np. na stworzenie filmu złożonego z klatech stanowiących

poszczególne wykresy. Funkcja ta wymaga następujących argumentów na wejściu: fig, czyli kanwę rysunku, func - funkcję do aktualizacji rysunku, init_func - funkcję inicjalizującą rysunek, frame - liczbę klatek, i blit - aktualizowanie tylko tych części rysunku, które uległy zmianie:

def init():

# sporządź rysunek def update(frame_counter):

# zaktualizuj rysunek do następnej klatki

anim = animation.FuncAnimation(fig, update, init_func=init, frames=200, bli t=True)

anim.save('animation.mp4', fps=30) # fps = klatki na sekundę Narzędzia do animacji znajdują w module matplotlib.animation:

In [76]:

fig = plt.figure(figsize=(12,6))

ax = fig.add_subplot(1,2,1, projection='3d')

ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25) ax.view_init(30, 45)

ax = fig.add_subplot(1,2,2, projection='3d')

ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25) ax.view_init(70, 30) # wysokość i azymut (w kątach)

fig.tight_layout()

(50)

Tworzymy animację ruchu wahadła:

In [78]:

Zapisany plik możemy podglądnąć bezpośrednio w IPythonie:

# wahadło podwójne (patrz wcześniejsze wykłady) from scipy.integrate import odeint

g = 9.82; L = 0.5; m = 0.1 def dx(x, t):

x1, x2, x3, x4 = x[0], x[1], x[2], x[3]

dx1 = 6.0/(m*L**2) * (2 * x3 - 3 * cos(x1-x2) * x4)/(16 - 9 * cos(x1-x2)**2) dx2 = 6.0/(m*L**2) * (8 * x4 - 3 * cos(x1-x2) * x3)/(16 - 9 * cos(x1-x2)**2) dx3 = -0.5 * m * L**2 * ( dx1 * dx2 * sin(x1-x2) + 3 * (g/L) * sin(x1)) dx4 = -0.5 * m * L**2 * (-dx1 * dx2 * sin(x1-x2) + (g/L) * sin(x2)) return [dx1, dx2, dx3, dx4]

x0 = [pi/2, pi/2, 0, 0] # stan początkowy t = linspace(0, 10, 250) # czas ruchu

x = odeint(dx, x0, t) # rozwiązanie równania

fig, ax = plt.subplots(figsize=(5,5)) ax.set_ylim([-1.5, 0.5])

ax.set_xlim([1, -1])

pendulum1, = ax.plot([], [], color="red", lw=2) pendulum2, = ax.plot([], [], color="blue", lw=2) def init():

pendulum1.set_data([], []) pendulum2.set_data([], []) def update(n):

# n = numer klatki # położenia wahadła x1 = + L * sin(x[n, 0]) y1 = - L * cos(x[n, 0]) x2 = x1 + L * sin(x[n, 1]) y2 = y1 - L * cos(x[n, 1])

# aktualizuj położenie

pendulum1.set_data([0 ,x1], [0 ,y1]) pendulum2.set_data([x1,x2], [y1,y2])

anim = animation.FuncAnimation(fig, update, init_func=init, frames=len(t), blit=Fal

#zapisujemy animację do pliku (wymaga zainstalowanego programu avconv) anim.save('animation.mp4', fps=20, writer="avconv", codec="libx264") plt.close(fig)

(51)

In [ ]:

Out[79]:

0:00

import base64

from IPython.display import HTML

video = open("animation.mp4", "r+b").read() video_encoded = base64.b64encode(video) HTML(data='''<video alt="test" controls>

<source src="data:video/mp4;base64,{0}" type="video/mp4" />

</video>'''.format(video_encoded.decode('ascii')))

Cytaty

Powiązane dokumenty

Analogia ta pokazuje, że przyjęcie skrajnie konserwatywnego stanowiska w kwestii statusu moralnego wczesnych embrionów (czyli uznanie ich za byty, które mają pełny

Na podstawie powyższej tabeli można wysnuć następujące wnioski: w języ- ku polskim z 60 zbadanych wyrazów 26 to zapożyczenia z języka angielskiego, np. kliknąć, kodować,

Starałam się również dowieść zdolności propriów do precyzowania pory dnia w  prozie, przedstawiłam także nazwy własne jako środek przyśpieszający lub zwalniający

chrane’a Herodot uznał, że sprawiedliwość, zgodnie z którą toczą się ludzkie dzie ­ je, pochodzi od opatrzności boskiej i polega nie tylko na Heraklitowej

Znaleźć tor po jakim w płaszczyźnie xy leci ze stałą prędkością v samolotem ponaddźwiękowym pilot, który chce, aby jego koledzy stojący na lotnisku usłyszeli w tym

Czy nie przeczy to tezie, że pierwszy wyraz ciągu nie może mieć wpływu na

63ºC), zbadanie stopnia utlenienia mieszanin olejów podczas 12-tygodniowego testu przechowalniczego, porównanie zmian oksydacyjnych w mieszaninach olejów bez

Przenoszenie zakażenia COVID-19 z matki na dziecko rzadkie Wieczna zmarzlina może zacząć uwalniać cieplarniane gazy Ćwiczenia fizyczne pomocne w leczeniu efektów długiego