Python - wprowadzenie

08 - Biblioteka `pandas` cz. 4: wizualizacja danych

Dotychczas używaliśmy biblioteki pandas w celu prostej selekcji i analizy danych, teraz przyszedł czas na podstawy wizualizacji danych. Najpierw użyjemy w tym celu metod dostarczonych przez pakiet pandas, później przyjrzymy się bliżej bibliotece matplotlib a w końcu nieco dłużej popracujemy z seaborn. Poniżej przedstawię jedynie wybrane typy wykresów oferowanych przez wymienione biblioteki i niektóre możliwości ich modyfikacji. W razie potrzeby warto się przyjrzeć im bliżej.

Zacznijmy od zaimportowania danych (patrz poprzednia lekcja) i ich lekkiej modyfikacji

import pandas as pd
dane = pd.read_csv('organelles.csv')
# Tworzymy kolumnę dla poszczególnych grup organizmów
# Zob. zadanie z poprzedniej lekcji
dane['Grupy'] = dane['Organism Groups'].str.split(';').str[1]
# Zmieniamy wartości "chloroplast" na "plastid" -
# chloroplasty to przecież plastydy
dane['Type'] = ['plastid' if row == 'chloroplast' else row for row in dane['Type']]
# Sprawdzenie wartości w kolumnie "Type"
print(dane['Type'].unique())
# Operacja groupby - grupujemy po typie organelli
# oraz grupie organizmów
grupy = dane.groupby(['Type', 'Grupy'])
['mitochondrion' 'plastid' 'apicoplast' 'kinetoplast' 'cyanelle'
 'chromatophore']

Teraz obliczmy średnie i wybierzmy dane dla mitochondriów dla wybranych grup organizmów:

# Obliczamy średnie
srednie_Size = grupy[['Size(Mb)', 'Genes']].mean()
# Selekcja danych dla mitochondriów i grup organizmów:
mitochondria_Srednie_size = srednie_Size.loc['mitochondrion']\
                            .loc[['Animals','Fungi','Plants']]
print(mitochondria_Srednie_size)
         Size(Mb)      Genes
Grupy                       
Animals  0.016406  25.926091
Fungi    0.066471  34.237454
Plants   0.308913  71.170270

Wygenerujmy prosty wykres słupkowy z użyciem metod dostępnych dla ramki danych:

mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)')

png

Uwaga jeśli używasz jupyter-lab, to powyższy wykres pokaże się automatycznie. Jeśli natomiast uruchamiasz kod z zapisanego pliku z kodem Pythona powinieneś najpierw zaimportować odpowiedni moduł z biblioteki matplotlib:

import matplotlib.pyplot as plt

a na końcu użyć polecenia:

plt.show()

Możemy zmieniać pewne parametry np. kolor wykresu:

mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)', color = 'green')

png

Można też zastosować listę z nazwami kolorów:

mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)', 
                                   color = ['red','green','blue'])

png

Legendę można łatwo usunąć ustawiając dodatkowy parametr (legend):

mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)', 
                                   color = ['brown','red','orange'],
                                  legend = False)

png

Teraz będziemy chcieli dołożyć do wykresu słupki pokazujące odchylenie standardowe, najpierw trzeba je obliczyć:

size_sd = grupy[['Size(Mb)', 'Genes']].std()
mitochondria_Srednie_sd = size_sd.loc['mitochondrion'].loc[['Animals','Fungi','Plants']]
print(mitochondria_Srednie_sd)
         Size(Mb)       Genes
Grupy                        
Animals  0.001457   12.497448
Fungi    0.038090   26.790855
Plants   0.292444  120.637200

Stwórzmy ponownie wykres słupkowy uzupełniony o wartości odchyleń standardowych:

mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)', 
                                   yerr = mitochondria_Srednie_sd['Size(Mb)'])

png

Wykres można także przedstawić poziomo, w takim przypadku należy użyć metody barh() zamiast bar() i zastosować parametr xerr:

mitochondria_Srednie_size.plot.barh(y = 'Size(Mb)', 
                                   xerr = mitochondria_Srednie_sd['Size(Mb)'])

png

Możemy też z uzyskanych zestawień uzyskać łatwo wykres dla liczby genów:

mitochondria_Srednie_size.plot.bar(y = 'Genes', 
                                   yerr = mitochondria_Srednie_sd['Genes'])

png

Zauważ, że dolna granica odchylenia standardowego dla roślin sięga znacznie poniżej 0. Sprawdźmy, jak wygląda rozkład wartości liczby opisanych genów dla mitochondriów roślinnych. W tym celu przyda nam się histogram. Najpierw dokonajmy selekcji danych:

# Selekcja danych dla mitochondriów roślinnych:
mitochondria_roslinne = dane[(dane['Type'] == 'mitochondrion')
                             & (dane['Grupy'] == 'Plants')]

Utwórzmy teraz histogram. W tym celu użyjemy metody hist() podając wartość bins, która określa interwały wartości.

mitochondria_roslinne['Genes'].plot.hist(bins=100)

png

Jak widać, są genomy o bardzo wysokiej liczbie genów (lub genom). Możemy łatwo sprawdzić ile ich jest, jakich organizmów dotyczą i ile mają opisanych genów:

# Selekcja danych dla mitochondriów roślinnych:
mit_rosl_duzo_genow = dane[(dane['Type'] == 'mitochondrion')
                           & (dane['Grupy'] == 'Plants')
                           & (dane['Genes'] > 500)]
print(mit_rosl_duzo_genow[['Organism Name', 'Genes', 'Replicons']])
                Organism Name  Genes               Replicons
18287  Utricularia reniformis   2299  NC_034982.1/KY774314.1

Jak widać, jest to jeden organizm, który znacznie odstaje od pozostałych. Można znaleźć w bazie GenBank dane tego genomu używając np. numeru dostępowego, który widzimy w kolumnie Replicons: https://www.ncbi.nlm.nih.gov/nuccore/NC_034982.

Przyjrzyjmy się dokładniej niższym wartościom, w tym celu wybierzmy genomy o liczbie opisanych genów do 500:

# Selekcja danych dla mitochondriów roślinnych:
mit_rosl_reszta = dane[(dane['Type'] == 'mitochondrion')
                       & (dane['Grupy'] == 'Plants')
                       & (dane['Genes'] <= 500)]
mit_rosl_reszta['Genes'].plot.hist(bins=500)

png

Widać, że są tu genomy, dla których nie opisano w ogóle genów lub opisano ich kilka. Odrzućmy te najniższe wartości:

# Selekcja danych dla mitochondriów roślinnych:
mit_rosl_wybrane = dane[(dane['Type'] == 'mitochondrion')
                       & (dane['Grupy'] == 'Plants')
                       & (dane['Genes'] <= 500)
                       & (dane['Genes'] > 10)]
mit_rosl_wybrane['Genes'].plot.hist(bins=500)

png

Stwórzmy teraz histogram pokazujący jak liczne są genomy w poszczególnych zakresach wielkości. Najpierw wybierzmy dane:

# Selekcja danych dla mitochondriów roślinnych:
mitochondria_roslinne = dane[(dane['Type'] == 'mitochondrion')
                             & (dane['Grupy'] == 'Plants')]

Teraz użyjemy metody hist:

mitochondria_roslinne['Size(Mb)'].plot.hist(bins=100)

png

Powyżej pokazałem pewne możliwości, choć nie wszystkie, modyfikacji wykresów. Więcej można osiągnąć wspierając się biblioteką matplotlib, której się niebawem przyjrzyjmy bliżej. Na razie wykorzystajmy ją do modyfikacji wykresów uzyskanych dzięki metodom ramki danych. Zacznijmy od odtworzenia jednego z wcześniejszych wykresów, ale najpierw odpowiednio wybierzmy dane.

# Obliczamy średnie
srednie_Size = grupy[['Size(Mb)', 'Genes']].mean()
# Selekcja danych dla mitochondriów i grup organizmów:
mitochondria_Srednie_size = srednie_Size.loc['mitochondrion']\
                             .loc[['Animals','Fungi','Plants']]
print(mitochondria_Srednie_size)
         Size(Mb)      Genes
Grupy                       
Animals  0.016406  25.926091
Fungi    0.066471  34.237454
Plants   0.308913  71.170270
  • Teraz wykres:
# Obliczamy średnie
srednie_Size = grupy['Size(Mb)'].mean()
# Selekcja danych dla mitochondriów i grup organizmów:
mitochondria_Srednie_size = srednie_Size.loc['mitochondrion']\
                           .loc[['Animals','Fungi','Plants']]
mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)', legend = False)

png

Zaimportujmy teraz odpowiedni moduł z biblioteki matplotlib i dodajmy tytuł, własne opisy osi, własne opisy słupków oraz zapiszmy plik w formacie pdf:

# Import modułu z matplotlib
from matplotlib import pyplot as plt
mitochondria_Srednie_size.plot.bar(y = 'Size(Mb)', legend = False)
plt.title('Rozmiary genomów mitochondrialnych', fontsize=14)
# Opis osi x
plt.xlabel('organizmy',fontsize=12)
# Opis osi y
plt.ylabel('Rozmiar genomu (Mb)',fontsize=12)
# Opisy słupków
plt.xticks([0, 1, 2],['Zwierzęta', 'Grzyby', 'Rośliny'])
# Zapis pliku
plt.savefig('rozmiar_mitochondriow.pdf', bbox_inches='tight')

png

Oczywiście nie wyczerpaliśmy możliwości oferowanych bezpośrednio przez bibliotekę pandas, więcej na ten temat można poczytać np. w dokumentacji Teraz jednak przejdziemy do bardziej zaawansowanej biblioteki służącej wizualizacji: matplotlib.

Biblioteka matplotlib

Z biblioteką matplotlib spotkaliśmy się już w pierwszej części kursu, kiedy użyliśmy jej do utworzenia prostych wykresów na podstawie wygenerowanych danych. Teraz użyjemy jej do wizualizacji danych analizowanych z pomocą biblioteki pandas.

Jeżeli to konieczne, zacznijmy od importu i wstępnych modyfikacji danych:

import pandas as pd
# Import danych, parsujemy kolumnę Release Date do typu datetime64
dane = pd.read_csv('organelles.csv', parse_dates = ['Release Date'])
# Tworzymy kolumnę dla poszczególnych grup organizmów
# Zob. zadanie z poprzedniej lekcji
dane['Grupy'] = dane['Organism Groups'].str.split(';').str[1]
# Zmieniamy wartości "chloroplast" na "plastid" -
# chloroplasty to przecież plastydy
dane['Type'] = ['plastid' if row == 'chloroplast' else row for row in dane['Type']]

Teraz odtwórzmy wykres słupkowy obrazujący wielkość genomów mitochondriów u zwierząt, grzybów i roślin:

# Import modułu z matplotlib
from matplotlib import pyplot as plt
# Obliczamy średnie
srednie_Size = grupy['Size(Mb)'].mean()
# Selekcja danych dla mitochondriów i grup organizmów:
mitochondria_Srednie_size = srednie_Size.loc['mitochondrion']\
                            .loc[['Animals','Fungi','Plants']]
print(mitochondria_Srednie_size)
plt.bar(mitochondria_Srednie_size.index, 
        mitochondria_Srednie_size)
plt.title('Rozmiary genomów mitochondrialnych', fontsize=14)
# Opis osi x
plt.xlabel('organizmy',fontsize=12)
# Opis osi y
plt.ylabel('Rozmiar genomu (Mb)',fontsize=12)
# Opisy słupków
plt.xticks([0, 1, 2],['Zwierzęta', 'Grzyby', 'Rośliny'])
Grupy
Animals    0.016406
Fungi      0.066471
Plants     0.308913
Name: Size(Mb), dtype: float64

png

Poszczególne słupki można pokolorować:

plt.bar(mitochondria_Srednie_size.index, 
        mitochondria_Srednie_size,
        color = ['brown', 'red', 'darkorange'])
plt.title('Rozmiary genomów mitochondrialnych', fontsize=14)
# Opis osi x
plt.xlabel('organizmy',fontsize=12)
# Opis osi y
plt.ylabel('Rozmiar genomu (Mb)',fontsize=12)
# Opisy słupków
plt.xticks([0, 1, 2],['Zwierzęta', 'Grzyby', 'Rośliny'])

png

Stwórzmy teraz kolumnę zawierająca wyłącznie rok publikacji genomów:

dane['Rok'] = dane['Release Date'].dt.year
print(dane['Rok'].unique())
[2018 2013 2009 2016 2020 2015 2014 2019 2017 2021 2011 2008 2004 2007
 1994 2006 2012 2010 2003 2005 2002 1999 1996 2001 2000 1998 1997 1995
 1993 1986 1989 1990]

Zgrupujmy dane wg. typu i roku. Sprawdźmy ile zostało opublikowanych genomów mitochondrialnych w poszczególnych latach:

lata = dane.groupby(['Type', 'Rok'])
lata_liczba = lata.count()
print(lata_liczba.loc['mitochondrion']['Size(Mb)'])
Rok
1990       3
1993       2
1994       3
1995       1
1996       1
1997       1
1998       3
1999      94
2000      45
2001     105
2002      92
2003      91
2004     185
2005     126
2006     275
2007     203
2008     317
2009     425
2010     281
2011     405
2012     515
2013     886
2014    1016
2015    1203
2016    1097
2017    1131
2018    1021
2019    1018
2020    1210
2021     557
Name: Size(Mb), dtype: int64

Przedstawmy te dane na wykresie:

plt.plot(lata_liczba.loc['mitochondrion']['Size(Mb)'])
plt.title('Liczba opublikowanych genomów mitochondrialnych w latach ', fontsize=12)
# Opis osi x
plt.xlabel('Lata',fontsize=10)
# Opis osi y
plt.ylabel('L. opubl. genomów mitochondrialnych',fontsize=10)
Text(0, 0.5, 'L. opubl. genomów mitochondrialnych')

png

Teraz pogrupujmy dodatkowo dane wg. grup organizmów a następnie umieśćmy na wykresie dane dla mitochondriów zwierzęcych i roślinnych:

lata = dane.groupby(['Grupy','Type', 'Rok'])
lata_liczba = lata.count()['Size(Mb)']
print(lata_liczba)
Grupy     Type           Rok 
Animals   mitochondrion  1998     2
                         1999    88
                         2000    32
                         2001    96
                         2002    85
                                 ..
Protists  plastid        2017     4
                         2018    17
                         2019    16
                         2020     2
                         2021     1
Name: Size(Mb), Length: 204, dtype: int64
# Wykres dla zwierząt, dodajemy etykietę
plt.plot(lata_liczba.loc['Animals'].loc['mitochondrion'], 
         label='Zwierzęta')
# Wykres dla roślin, dodajemy etykietę
plt.plot(lata_liczba.loc['Plants'].loc['mitochondrion'], 
         label='Rośliny')
plt.title('Liczba opublikowanych genomów mitochondrialnych w latach ', fontsize=12)
# Opis osi x
plt.xlabel('Lata',fontsize=10)
# Opis osi y
plt.ylabel('L. opubl. genomów',fontsize=10)
# Dodanie legendy
plt.legend()

png

Oczywiście można zmieniać różne parametry wykresu, takie jak styl i kolor:

# Wykres dla zwierząt
plt.plot(lata_liczba.loc['Animals'].loc['mitochondrion'], 
         '-.b', # styl i kolor linii: kropka, kreska - niebieska
         label='Zwierzęta')
# Wykres dla roślin
plt.plot(lata_liczba.loc['Plants'].loc['mitochondrion'], 
         '--ro', # styl i kolor linii: linia przerywana z punktami, czerwona
         label='Rośliny')
plt.title('Liczba opublikowanych genomów mitochondrialnych w latach ',
          fontsize=12)
# Opis osi x
plt.xlabel('Lata',fontsize=10)
# Opis osi y
plt.ylabel('L. opubl. genomów',fontsize=10)
# Dodanie legendy
plt.legend()

png

Możliwych jest wiele innych modyfikacji, warto przejrzeć dokumentację.

Teraz pogrupujmy dane wg. typu organelli i organizmów.

organelle = dane.groupby(['Type', 'Grupy'])
organelle_liczba = organelle.count()['Size(Mb)']
print(organelle_liczba)
Type           Grupy   
apicoplast     Protists       61
chromatophore  Protists        2
cyanelle       Protists        1
kinetoplast    Protists        3
mitochondrion  Animals     10770
               Fungi         817
               Other         159
               Plants        370
               Protists      196
plastid        Other         193
               Plants       6161
               Protists       79
Name: Size(Mb), dtype: int64

Następnie utwórzmy wykres kołowy z kilkoma ozdobnikami:

plt.pie(organelle_liczba.loc['mitochondrion'],
       # etykiety 
       labels=organelle_liczba.loc['mitochondrion'].index,
       # Wyświetlenie wartości % do dwu miejsc po przecinku
       autopct = '%1.2f%%', 
       # cień
       shadow = True,
       # rozsunięcie wycinków
       explode = (0.1, 0.2, 0.3, 0.4, 0.5))
plt.title('Liczby genomów mitochondrialnych grup organizmów')

png

Biblioteka seaborn

Nieco więcej czasu i uwagi poświęcimy bibliotece seaborn, która zresztą bazuje na matplotlib ale poszerza jej możliwości a także pozwala uzyskać bardziej estetyczne wizualizacje danych (choć to rzecz gustu).

Jeśli to konieczne wczytaj ponownie dane:

import pandas as pd
# Import danych, parsujemy kolumnę Release Date do typu datetime64
dane = pd.read_csv('organelles.csv', parse_dates = ['Release Date'])
# Tworzymy kolumnę dla poszczególnych grup organizmów
# Zob. zadanie z poprzedniej lekcji
dane['Grupy'] = dane['Organism Groups'].str.split(';').str[1]
# Zmieniamy wartości "chloroplast" na "plastid" -
# chloroplasty to przecież plastydy
dane['Type'] = ['plastid' if row == 'chloroplast' else row for row in dane['Type']]
dane['Rok'] = dane['Release Date'].dt.year

Zacznijmy od odtworzenia znanego nam wykresu słupkowego, tym razem używając seaborn:

# Import seaborn
import seaborn as sns
# Import modułu z matplotlib
from matplotlib import pyplot as plt
# Obliczamy średnie
srednie_Size = grupy.mean()['Size(Mb)']
# Selekcja danych dla mitochondriów i grup organizmów:
mitochondria_Srednie_size = srednie_Size.loc['mitochondrion']\
                            .loc[['Animals','Fungi','Plants']]
print(mitochondria_Srednie_size)
sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size)
Grupy
Animals    0.016406
Fungi      0.066471
Plants     0.308913
Name: Size(Mb), dtype: float64

png

Jak widać, domyślnie słupki mają różne kolory. Można je oczywiście dostosować. Jednym ze sposobów jest zastosowanie palet:

sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
           palette = 'CMRmap_r')

png

Więcej na temat palet można poczytać m. in w dokumentacji a także np. tutaj. Listę dostępnych nazw palet można uzyskać podając nazwę, która nie jest nazwą żadnej palety, wtedy pojawi się informacja o błędzie zawierająca m. in. wymienione dostępne nazwy palet:

sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
           palette = 'Nie_ma_takiej_palety')
...
ValueError: 'Nie_ma_takiej_palety' is not a valid value for name;
supported values are 'Accent', 'Accent_r', 'Blues', 'Blues_r', 'BrBG',
'BrBG_r', 'BuGn', 'BuGn_r', 'BuPu', 'BuPu_r', 'CMRmap', 'CMRmap_r',
'Dark2', 'Dark2_r', 'GnBu', 'GnBu_r', 'Greens', 'Greens_r', 'Greys',
'Greys_r', 'OrRd', 'OrRd_r', 'Oranges', 'Oranges_r', 'PRGn', 'PRGn_r',
'Paired', 'Paired_r', 'Pastel1', 'Pastel1_r', 'Pastel2', 'Pastel2_r',
'PiYG', 'PiYG_r', 'PuBu', 'PuBuGn', 'PuBuGn_r', 'PuBu_r', 'PuOr',
'PuOr_r', 'PuRd', 'PuRd_r', 'Purples', 'Purples_r', 'RdBu', 'RdBu_r',
'RdGy', 'RdGy_r', 'RdPu', 'RdPu_r', 'RdYlBu', 'RdYlBu_r', 'RdYlGn',
'RdYlGn_r', 'Reds', 'Reds_r', 'Set1', 'Set1_r', 'Set2', 'Set2_r', 'Set3'
, 'Set3_r', 'Spectral', 'Spectral_r', 'Wistia', 'Wistia_r', 'YlGn',
'YlGnBu', 'YlGnBu_r', 'YlGn_r', 'YlOrBr', 'YlOrBr_r', 'YlOrRd',
'YlOrRd_r', 'afmhot', 'afmhot_r', 'autumn', 'autumn_r', 'binary',
'binary_r', 'bone', 'bone_r', 'brg', 'brg_r', 'bwr', 'bwr_r', 'cividis', 'cividis_r', 'cool', 'cool_r', 'coolwarm', 'coolwarm_r', 'copper',
'copper_r', 'crest', 'crest_r', 'cubehelix', 'cubehelix_r', 
...

Poniżej wykorzystamy niektóre z nich.

Można też podać wybrane kolory:

sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
           palette = ['brown', 'red', 'darkorange'])

png

Możemy też ustawić styl, który wpływa m.in. na tło wykresu:

sns.set_style('whitegrid')
sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
           palette = 'CMRmap_r')

png

sns.set_style('dark')
sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
           palette = 'CMRmap_r')

png

sns.set_style('darkgrid')
sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
           palette = 'CMRmap_r')

png

Ustawmy teraz tytuł, opisy osi i podpisy pod słupkami:

sns.set_style('darkgrid')
sns.barplot(x = mitochondria_Srednie_size.index,
            y = mitochondria_Srednie_size,
            palette = 'CMRmap_r')
plt.title('Rozmiary genomów mitochondrialnych', fontsize=14)
# Opis osi x
plt.xlabel('organizmy',fontsize=12)
# Opis osi y
plt.ylabel('Rozmiar genomu (Mb)',fontsize=12)
# Opisy słupków
plt.xticks([0, 1, 2],['Zwierzęta', 'Grzyby', 'Rośliny'])

png

Wybierzmy teraz ponownie zestaw danych do dalszych analiz, tym razem nie grupując ich. Pozwoli nam to m.in. dokładniej przyjrzeć się rozkładowi wartości.

mito = dane[ (dane['Grupy'].isin(['Animals','Fungi','Plants']))
           & (dane['Type'] == 'mitochondrion')
           & (dane['Genes'] <= 500)
           & (dane['Genes'] > 10)
           ]
print(mito['Genes'])
0        37
1        35
2        13
3        37
4        37
         ..
18803    37
18805    67
18808    40
18809    35
18811    43
Name: Genes, Length: 11393, dtype: int64

Utwórzmy wykres słupkowy z zaznaczeniem odchylenia standardowego:

sns.barplot(data = mito,
            x = 'Grupy',
            y = 'Size(Mb)',
            palette = 'RdBu',
            # Słupki błędu wyznaczające odchylenie standardowe
            errorbar='sd')

png

Jeśli nie podamy wartości parametru ci domyślnie rysowany jest 95% zakres ufności dla średniej liczony za pomocą metody bootstrap:

sns.barplot(data = mito,
            x = 'Grupy',
            y = 'Size(Mb)',
            palette = 'cividis')

png

Można też podać własny zakres ufności:

sns.barplot(data = mito,
            x = 'Grupy',
            y = 'Size(Mb)',
            palette = 'cool',
            # Słupki błędu wyznaczające przedział ufności
            errorbar=('ci', 99))

png

Do słupków błędu można dodać poprzeczne linie a także zmienić ich grubość:

sns.barplot(data = mito,
            x = 'Grupy',
            y = 'Size(Mb)',
            # Linie poprzeczne na słupkach
            capsize = 0.2,
            # Grubość linii na słupkach będu
            errwidth = 5,
            palette = 'dark')

png

Sprawdźmy jaką wielkość mają poszczególne genomy, w grupach organizmów. W tym celu wykorzystamy kolejny typ wykresu:

sns.set_style('whitegrid')
sns.catplot(data = mito,
            x = 'Grupy',
            y = 'Size(Mb)',
            palette = 'afmhot_r',
            hue = 'Grupy')

W powyższym przykładzie argument hue służy do określenia danych, które będą użyte do kolorowania. Tu każda z grup otrzyma oddzielny kolor. Sprawdź jak zmieni się wykres jeśli zamiast Grupy użyjesz Size(Mb) albo Genes. Wrócimy jeszcze do tego zagadnienia.

png

Sprawdźmy jeszcze liczby genów (ucięliśmy skrajne wartości przy selekcji danych):

sns.catplot(data = mito,
            x = 'Grupy',
            y = 'Genes',
            palette = 'copper',
            hue = 'Grupy'
	    )

png

Możemy ustawić parametr kind = 'box aby uzyskać wykres pudełkowy. O tym, jak go interpretować można przeczytać np. tu.

sns.catplot(data = mito,
            x = 'Grupy',
            y = 'Genes',
            kind = 'box',
            palette = 'autumn')

png

Z kolei wykres wiolinowy uzyskamy ustawiając kind = violin (tym razem użyjemy kolumny GC%):

sns.catplot(data = mito,
            x = 'Grupy',
            y = 'GC%',
            kind = 'violin',
            palette = 'brg')

png

Można też użyć parametru kind do uzyskania wykresu słupkowego:

sns.catplot(data = mito,
            x = 'Grupy',
            y = 'Size(Mb)',
            kind = 'bar',
            capsize = 0.1,
            palette = 'coolwarm')

png

Sprawdźmy teraz jak rozłożone są wartości wielkości genomów i liczby genów u zwierząt i roślin:

sns.relplot(data = mito[mito['Grupy'].isin(['Animals','Plants'])],
            x = 'Genes',
            y = 'Size(Mb)',
            # Grupy organizmów traktowane oddzielnie - w różnych kolorach 
            hue = 'Grupy',
            # Wysokość wykresu (w calach)
            height = 6,
            # Proporcja szerokości do wysokości:
            # height * aspect
            aspect = 2,
            palette = 'cubehelix',
            alpha = 0.5 # przeźroczystość
           )

png

Ten typ wykresu pozwala także zróżnicować wielkość kół, w zależności od wartości:

sns.relplot(data = mito[mito['Grupy'].isin(['Animals','Plants'])],
            x = 'Genes',
            y = 'Size(Mb)',
            hue = 'Grupy',
            # Wysokość wykresu (w calach)
            height = 6,
            aspect = 2,
            # Wartości zestawu danych wyrażone w wielkości symboli (tu: kółek)
            size = 'Pseudogene',
            # Zakres wielkości symboli
            sizes = (10, 300),
            palette = 'flare',
            alpha = 0.5)

png

Ustawienie parametru kind = 'line' pozwala uzyskać wykres liniowy. Można uzyskać przy tym przedział ufności lub odchylenie standardowe dla wartości ustawiając odpowiednio parametr ci (zob. powyżej). Sprawdźmy na przykład liczby genów opisywanych dla genomów mitochondrialnych roślin, zwierząt i grzybów w ostatnich 12 latach wraz z odchyleniami standardowymi.

sns.relplot(data = mito[(mito['Rok'] > pd.Timestamp.now().year-12)
                        & mito['Grupy'].isin(['Plants', 'Animals', 'Fungi'])],
            x = 'Rok',
            y = 'Genes',
            hue = 'Grupy',
            height = 6,
            aspect = 2,
            kind = 'line',
            errorbar='sd',
            palette = 'gnuplot2')

png

Parametr hue pozwala także na przedstawienie na innych typach wykresów kilku serii danych. Utwórzmy na przykład wykres słupkowy przedstawiający średnią liczbę genów opisanych dla genomów mitochondrialnych opublikowanych w ostatnim dziesięcioleciu, wliczając bieżący rok:

sns.catplot(data = mito[mito['Rok'] > pd.Timestamp.now().year-5],
            x = 'Rok',
            y = 'Size(Mb)',
            hue = 'Grupy',
            kind = 'bar',
            height = 6,
            aspect = 2,
            palette = 'Oranges_r')

png

Dystrybucję wartości można zwizualizować za pomocą m.in. funkcji displot(), argument kde = True powoduje wygenerowanie krzywej dopasowanej do wartości z użyciem jądrowego estymatora gęstości - KDE (ang. kernel density estimation).

dane = mito[(mito['Rok'] > pd.Timestamp.now().year-5)
                        & mito['Grupy'].isin(['Fungi', 'Plants'])]
sns.displot(dane,
            x = 'Genes',
            kde = True,
            hue = 'Grupy',
            palette = 'viridis')

png

Kilka serii danych można także przedstawić w postaci serii wykresów np. z użyciem argumentu col:

sns.catplot(data = mito[mito['Rok'] > pd.Timestamp.now().year-5],
            x = 'Rok',
            y = 'Size(Mb)',
            col = 'Grupy',
            kind = 'bar',
            errorbar=('ci', False),
            col_order=['Animals', 'Fungi', 'Plants'],
            height = 4,
            aspect = 1,
            palette = 'dark')

png

Klasa FacetGrid pozwala na tworzenie zestawu wykresów z użyciem zmiennych. Poniżej przykład zestawienia wartości rozmiarów genomów i liczby opisanych genów w mitochondriach, dla grzybów i roślin w latach 2018-2020 (zwróć uwagę na metodę between()).

# Import modułu z matplotlib
from matplotlib import pyplot as plt
# Selekcja danych: metoda between() pozwala wybrać wartości 
# wg. wskazanego zakresu
dane = mito[(mito['Rok'].between(2018, 2020))
                        & mito['Grupy'].isin(['Fungi', 'Plants'])]
f = sns.FacetGrid(data = dane, 
                  row = 'Grupy', # Wartości w kolejnych rzędach
                  col='Rok', # Wartości w kolejnych kolumnach
                  height = 4, aspect = 1)
f = f.map(plt.scatter, # typ wykresu
          'Genes','Size(Mb)')

png

Możemy też wykresy umieścić w jednym rzędzie a wartości dla grzybów i roślin. Przy okazji poznamy sposób modyfikacji poszczególnych wykresów, tu dodamy do nich legendy:

dane = mito[(mito['Rok'].between(2018, 2020))
                        & mito['Grupy'].isin(['Fungi', 'Plants'])]
f = sns.FacetGrid(data = dane, 
                  col = 'Rok', 
                  hue = 'Grupy', 
                  height = 4, 
                  aspect = 1, 
                  palette = 'gnuplot2')
f = f.map(plt.scatter, 
          'Genes', 'Size(Mb)',  
          alpha=0.2 
         )
# Poszczególne wykresy są przechowywane w obiekcie typu ndarray
# metoda ravel() zwraca "spłaszczony", jednowymiarowy obiekt 
# ndarray, który możemy iterować, np. w celu modyfikacji
# wykresów
for ax in f.axes.ravel():
    ax.legend() #Dodajemy legendę

png

Zadanie

  1. Zbadaj, jak w ciągu ostatnich 10 lat zmieniła się liczba umieszczonych genomów mitochondrialnych dla różnych grup zwierząt.
  2. Porównaj wielkość genomu mitochondrialnego i liczbę opisanych genów w różnych grupach zwierząt.
Last updated on 3 Apr 2024
Published on 3 Apr 2024