Lab 03 - Wykresy
Lab 03 - Wykresy w Python (matplotlib
)
Matplotlib
jest najpopularniejszą na dzień dzisiejszy biblioteką do tworzenia wykresów dla języka programowania Python
. Składnię poleceń matplotlib
zaprojektowano tak, aby przypominała tę znaną z MATLAB
. Matplotlib
jest w pełni kompatybilny z biblioteką numeryczną NumPy
oraz Pandas
.
W wcześniejszej części kursu korzystaliśmy z metody plot()
obiektu typu DataFrame
, która korzysta bezpośrednio z matplotlib
i pozwala automatycznie tworzyć podstawowe i dobrze wyglądające wykresy. Jednakże, matplotlib
pozwala na konfigurowanie w zasadzie każdego pojedynczego elementu wchodzącego w skład rysowanego obrazu, a dane do niego dostarczone niekoniecznie muszą pochodzić z Pandas
- może to być macierz NumPy
lub zwykła Pythonowa
lista.
Pełna dokumentacja matplotlib
wraz z przykładami i tutorialami dostępna jest na stronie projektu: https://matplotlib.org/
Aby zacząć korzystać z matplotlib
należy załączyć w odpowiedni sposób bibliotekę, zwyczajowo pod aliasem plt
:
import matplotlib.pyplot as plt
Pamiętaj, że żądany wykres nie wyświetli się dopóki nie wywołasz komendy:
plt.show()
wszystkie instrukcje matplotlib
wywołane przed rysują wykres w tle. Wywołanie show()
zatrzyma wykonywanie skryptu, aż do momentu zamknięcia okna z wykresem.
Figure oraz Axes
W matplotlib
istnieją dwa podstawowe pojęcia reprezentujące składowe rysowanego wykresu:
Figure - cały obraz wykresu (okno), na którym rysowane są poszczególne wykresy, legendy, opisy itd. Figure możemy traktować jako płótno na którym będziemy rysować. Do danego figure może być przypisane wiele axes.
Axes - reprezentuje osie danego wykresu i umieszczone w przestrzeni rysowania figure. Dany figure może zawierać wiele axes (często jest to tylko jeden zestaw osi rysowany w danym oknie), natomiast axes może być przypisane tylko do jednego figure.
Aby utworzyć pusty figure, bez axes należy wywołać:
= plt.figure() fig
gdzie zmienna fig
będzie reprezentować obiekt całego okna wykresu.
Subplot
W matplotlib
przez pojęcie subplot rozumiany jest automatycznie utworzone axes w obrębie figure. Korzystanie z subplot ułatwia tworzenie wykresów, gdyż axes rozmieszczane są automatycznie w obrębie okna. Utworzenie najprostszego figure z pojedynczym umieszczonym na całym obszarze axes wykonujemy:
= plt.subplots() fig, ax
gdzie fig
jest oknem wykresu, a ax
reprezentuje osie rysowania wykresu (axes). Możliwe jest także szybkie utworzenie nowego figure z zdefiniowaną siatką wielu obszarów rysowania (axes), np.:
= plt.subplots(2, 2) fig, axs
gdzie axs
jest macierzą obszarów rysowania (axes) w ramach zwróconego fig
.
Pamiętaj, że wszystkie wykresy rysowane są w ramach axes, a nie w ramach figure. Wszystkie metody rysujące (np. plot
, scatter
) i większość metod modyfikujących wykres wywołujemy w ramach obiektu reprezentującego osie (obszar rysowania).
plot
Podstawowym i najczęściej wykorzystywanym wykresem jest plot
(https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html), który wyświetla wartości y
względem wartości x
jako linie lub jako punkty. Wielokrotne wywołanie funkcji rysującej w ramach danego axes powoduje wykreślenie wielu wykresów jeden na drugim:
= np.linspace(0, 2, 100)
x
= plt.subplots()
fig, ax
ax.plot(x, x)**2)
ax.plot(x, x**3) ax.plot(x, x
Jako pierwszy parametr podajemy wartości osi odciętych (x), jako drugi parametr osi rzędnych (y).
Często wykorzystywanym trzecim, nieobowiązkowym, parametrem jest ciąg formatujący wygląd wykresu, określa rodzaj markera, rodzaj linii oraz kolor. Format ciągu jest następujący '[marker][linia][kolor]'
, pola nie są obowiązkowe, można wyspecyfikować tylko wybrane. Wybrane ciągi formatujące:
- marker:
Znak | Opis |
---|---|
'.' |
punkt |
'o' |
kółko |
'^' |
trójkąt |
'*' |
gwizdka |
'x' |
krzyżyk |
... | ... |
- linia
Znak | Opis |
---|---|
'-' |
linia ciągła |
'--' |
linia przerywana |
'-.' |
linia przerywana, kropkowana |
':' |
linia kropkowana |
- kolor
Znak | Opis |
---|---|
'b' |
niebieski |
'g' |
zielony |
'r' |
czerwony |
'c' |
cyjan |
'm' |
magenta |
'y' |
żółty |
'k' |
czarny |
'w' |
biały |
Przykładowo:
= np.linspace(0, 2, 100)
x
= plt.subplots(2,2)
fig, axs 0][0].plot(x, np.random.random(len(x)), 'or')
axs[0][1].plot(x, np.random.random(len(x)), 'x--b')
axs[1][0].plot(x, np.random.random(len(x)), ':k')
axs[1][1].plot(x, np.random.random(len(x)), '*-.') axs[
Pełną listę modyfikatorów można znaleźć w dokumentacji metody plot
: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html
🔥 Zadanie 1 🔥
Funkcja gęstości prawdopodobieństwa rozkładu normalnego ze średnią μ i odchyleniem standardowym σ dana jest wzorem:
,
co możemy zapisać w Python jako:
= (1/(std_dev*np.sqrt(np.pi)))*np.exp((-(x-mean)**2)/(2*std_dev)) f
Korzystając z matplotlib
, wygeneruj poniższy wykres:
,
Opis wykresu
Każdy wykres aby być czytelny musi zostać dobrze opisany. Poniżej przedstawiono część metod dla axes, które pozwalają na łatwą modyfikację i opis zawartości wykresu.
Tytuł
Do ustawienia tytułu pojedynczego wykresy (axes) korzystamy z metody Axes.set_title
, np.:
'Rozkład Gaussa', fontsize=16) ax.set_title(
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_title.html
W przypadku umieszczenia wielu axes, w jednym figure, może istnieć konieczność ustawienia głównego tytułu, za pomocą metody wykonywanej dla figure suptitle
, np.:
'TYTUŁ') fig.suptitle(
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.suptitle.html
uzyskując następujący efekt:
Opisy osi
Opisy osi ustawiamy korzystając z:
Axes.set_xlabel
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_xlabel.htmlAxes.set_ylabel
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_ylabel.html
Legenda
W celu umieszczenia na danym wykresie (axes) legendy opisujące poszczególne linie wykresu korzystamy z metody Axes.legend
, gdzie jako parametr podajemy listę napisów, np.:
'Opis 1', 'Opis 2', 'Opis 3']) ax.legend([
Legenda jest w pełni konfigurowalna, pełną listę opcji znajdziemy w dokumentacji: https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.legend.html
Warto zwrócić uwagę na parametr loc
pozwalający umieścić legendę w innej lokalizacji, niż ta wygenerowana automatycznie. Parametr loc
przyjmuje następujące wartości:
'best'
'upper right'
'upper left'
'lower left'
'lower right'
'right'
'center left'
'center right'
'lower center'
'upper center'
'center'
Siatka
Do załączenia siatki na wykresie używamy metody Axes.grid
: https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.grid.html. Warto zwrócić uwagę, że w przypadku bardziej zaawansowanych scenariuszy można wykorzystać dwa poziomy gęstości siatki: major (główna) i minor (pomocnicza)
Zakresy osi
Istnieje możliwość ustawienia zakresu osi. Korzystamy z:
Axes.set_xlim
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_xlim.htmlAxes.set_ylim
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_ylim.html
Często wykorzystujemy tę możliwość, gdy chcemy ograniczyć zakres aktualnego wyświetlania wykresu, lub kiedy automatycznie wygenerowany zakres nie jest satysfakcjonujący. Zwróć uwagę, że wykres rozkładu prawdopodobieństwa wykonany w ramach wcześniejszego zadania kończy się na około 0.58, przestawienie zakresu wyświetlania na <0, 1> zwiększy czytelność prezentowanych danych:
0, 1) ax.set_ylim(
Etykiety osi
Zmiana etykiet osi może być konieczna gdy chcemy na przykład zwiększyć lub zmniejszyć liczebność wyświetlanych etykiet (ich gęstość), lub gdy automatycznie wygenerowane etykiety nie spełniają naszych oczekiwań. Korzystamy z:
Axes.set_xticks
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_xticks.htmlAxes.set_yticks
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_yticks.html
W przypadku wykresu rozkładu prawdopodobieństwa z wcześniejszego zadania etykiety osi X zostały wygenerowane w zakresie <-4, 4>. Ponieważ dane wejściowe dla osi X są z zakresu <-5, 5) lepszą czytelność uzyskamy ustawiając taki właśnie zakres:
-5, 6, 1)) ax.set_xticks(np.arange(
Metody ustawiające etykiety osi posiadają parametr minor
domyślnie ustawiony na False
, przekazując do powyższych metod wartość parametru True
zamiast ustawiać główne etykiety osi, ustawiamy etykiety pomocnicze, np.:
-5, 5, 0.5), minor=True) ax.set_xticks(np.arange(
Różnicę pomiędzy etykietami głównymi, a pomocniczymi przedstawiono na poniższym rysunku:
Wygląd etykiet możemy modyfikować korzystając z metody Axes.tick_params
- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.tick_params.html, możliwa jest na przykład zmiana orientacji, koloru, czy wielkości wygenerowanych etykiet.
🔥 Zadanie 2 🔥
Korzystając z powyższych instrukcji zmodyfikuj wykres z poprzedniego zadania, tak aby nadać mu następujący wygląd:
bar
bar
(https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.bar.html) pozwala utworzyć wykres słupkowy. Każdy słupek umieszczany jest w punkcie określony listą/macierzą x
, posiada wysokość i szerokość określoną przez height
i width
. Np.:
= plt.subplots()
fig, ax
= [30, 12, 40, 50, 13, 14, 45, 2]
values = np.arange(len(values))
x = 0.8
width
ax.bar(x, values, width)
Grupowanie wykresów słupkowych
W bardzo prosty sposób możemy na jednym wykresie umieścić wiele wykresów słupkowych, które reprezentować będą dodatkowy, trzeci wymiar informacji na naszym wykresie. Przygotowując taki wykres należy zwrócić uwagę, na rozmieszczenie słupków w osi x
, musimy wziąć pod uwagę szerokość rysowanego słupka i odpowiednio przesunąć punkt jego rysowania, np.:
= plt.subplots()
fig, ax
= [30, 12, 40, 50, 13, 14, 45, 2]
values1 = [14, 10, 30, 12, 80, 2, 33, 2]
values2 = np.arange(len(values1))
x = 0.3
width
-width/2, values1, width, label='Value 1')
ax.bar(x+width/2, values2, width, label='Value 2')
ax.bar(x
ax.legend()
Tekstowe etykiety osi
matplotlib
daje możliwość nadpisania liczbowych etykiet za pomocą ciągów znaków, tak aby wprowadzić bardziej czytelny opis. Szczególnie sprawdza się to w połączeniu z wykresami słupkowymi. Do utworzenia opisów tekstowych służy metoda Axes.set_xticklabels
(https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_xticklabels.html) i Axes.set_yticklabels
(https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_yticklabels.html).
UWAGA: Axes.set_xticklabels
powinna zostać zawsze poprzedzona wywołaniem metody Axes.set_xticks
, która ustali rozmieszczenie etykiet, w przeciwnym wypadku opisy mogą trafić w nieokreślone miejsce na osi x
. Podobnie w przypadku Axes.set_yticklabels
.
Przykładowa modyfikacja wykresu z przedstawionego wyżej:
= ['Group: ' + str(i) for i in range(len(values1))]
labels
ax.set_xticks(x)
ax.set_xticklabels(labels)
='x', labelrotation=20) ax.tick_params(axis
🔥 Zadanie 3 🔥
Dany jest plik w formacie JSON, zamierający informacje o procencie osób, które przeżyły raka w populacji USA (324 mln) według płci i wieku w 2016 roku: cancer_survival_in_us.json (źródło: https://cebp.aacrjournals.org/content/25/7/1029).
Korzystając z wczytanych danych wygeneruj poniższy wykres:
PODPOWIEDŹ: w przypadku problemu z siatką rysowaną na wykresie, użyj polecenia: ax.set_axisbelow(True)
.
errorbar
errorbar
(https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.errorbar.html) pozwala w bardzo prosty sposób wygenerować paski błędów, które często wykorzystywane są do prezentacji niepewności pomiarowej, odchylenia/wariancji przedstawionych na wykresie danych. errorbar
jest niezależnym wykresem i można go stosować z każdym innym wykresem, w tym z plot
i bar
.
Jako parametry errorbar
przyjmuje wektory położeń x
i y
znaczników, oraz ich rozmiar w kierunku osi x i y: xerr
oraz yerr
. Pominięcie jedno z parametrów rozmiaru znacznika spowoduje wykreślenie pasków błędów tylko w jednej osi. Zależnie od formatu przekazanych parametrów xerr
i yerr
paski błędów będą przyjmować następujące konfiguracje:
- skalar - symetryczne wartości +/- takie same dla wszystkich punktów,
- wektor długości N - symetryczne wartości +/-,
- macierz 2xN - oddzielne wartości + i - dla wszystkich punktów,
- brak - brak paska błędu.
Do formatowania wyglądu errorbar
wykorzystywany jest parametr fmt
, przyjmuje on taki sam string formatujący jak funkcja plot
. Warto zwrócić uwagę na parametr capsize
, którego ustawienie spowoduje wygenerowanie charakterystycznych dla pasków błędów "daszków". Np.:
= np.linspace(0, 10, 20)
x = np.sin(x)
y_sin = np.cos(x)
y_cos
= plt.subplots(2, 1)
fig, axs
0].plot(x, y_sin)
axs[0].errorbar(x, y_sin, yerr=0.5, fmt='.k', capsize=2)
axs[
1].plot(x, y_cos)
axs[1].errorbar(x, y_cos, xerr=0.2, yerr=np.random.random(len(x)), fmt='.r', capsize=2) axs[
🔥 Zadanie 4 🔥
Do wykresu słupkowego z poprzedniego zadania dodaj paski błędów, zarówno dla wykresu reprezentującego mężczyzn, jak i kobiety. Pamiętaj, że w przypadku tego wykresu błąd może występować tylko w osi y. Wartości błędów wylosuj. Przykład formatowania:
hist
Funkcja hist
(https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hist.html) automatycznie, bez pisania dodatkowego kodu, oblicza histogram danych wejściowych i go wykreśla. Jako parametr podajemy dane wejściowe x
, oraz określamy liczebność zakresów bins
. bins
może być także wektorem, jeżeli chcemy ręcznie określić zakresy. Ustawienie parametru density
na True
powoduje wykreślenie histogramu gęstości prawdopodobieństwa. Przykładowo:
= np.random.randn(10000)
x1 = np.random.rand(10000)
x2
= plt.subplots(1, 2)
fig, axs 0].hist(x1, 20, density=True, facecolor='g')
axs[1].hist(x2, 20, density=True, facecolor='r') axs[
🔥 Zadanie 5 🔥
Wczytaj plik: wyniki głosowania w wyborach prezydenckich w Rosji 2020
- Stwórz w wczytanym dataframe nową kolumnę zawierająca względną liczbę głosów za. Jest to iloraz wartości liczby głosów za (kolumna
yes
) do liczby głosów oddanych (kolumnagiven
) - Wyświetl histogram względnej liczby głosów za dla domyślnych ustawień
- Zmień liczbę binów histogramu na 100. Czy możesz zauważyć jakieś anomalie?
Autorzy: Tomasz Mańkowski, Piotr Kaczmarek