{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# [NTDS'18] tutorial 2: build a graph from an edge list\n", "[ntds'18]: https://github.com/mdeff/ntds_2018\n", "\n", "[Benjamin Ricaud](https://people.epfl.ch/benjamin.ricaud), [EPFL LTS2](https://lts2.epfl.ch)\n", "\n", "* Dataset: [Open Tree of Life](https://tree.opentreeoflife.org)\n", "* Tools: [pandas](https://pandas.pydata.org), [numpy](http://www.numpy.org), [networkx](https://networkx.github.io), [gephi](https://gephi.org/)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tools" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The below line is a [magic command](https://ipython.readthedocs.io/en/stable/interactive/magics.html) that allows plots to appear in the notebook." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first thing is always to import the packages we'll use." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import networkx as nx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tutorials on pandas can be found at:\n", "* \n", "* \n", "\n", "Tutorials on numpy can be found at:\n", "* \n", "* \n", "* \n", "\n", "A tutorial on networkx can be found at:\n", "* " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import the data\n", "\n", "We will play with a excerpt of the Tree of Life, that can be found together with this notebook. This dataset is reduced to the first 1000 taxons (starting from the root node). The full version is available here: [Open Tree of Life](https://tree.opentreeoflife.org/about/taxonomy-version/ott3.0).\n", "\n", "![Public domain, https://en.wikipedia.org/wiki/File:Phylogenetic_tree.svg](figures/phylogenetic_tree.png)\n", "![Public Domain, https://commons.wikimedia.org/w/index.php?curid=3633804](figures/tree_of_life.png)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "tree_of_life = pd.read_csv('data/taxonomy_small.tsv', sep='\\t\\|\\t?', encoding='utf-8', engine='python')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you do not remember the details of a function:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "pd.read_csv?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more info on the separator, see [regex](https://docs.python.org/3.6/library/re.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, what is the object `tree_of_life`? It is a Pandas DataFrame." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uidparent_uidnameranksourceinfouniqnameflagsUnnamed: 7
0805080NaNlifeno ranksilva:0,ncbi:1,worms:1,gbif:0,irmng:0NaNNaNNaN
193302805080.0cellular organismsno rankncbi:131567NaNNaNNaN
299642193302.0Archaeadomainsilva:D37982/#1,ncbi:2157,worms:8,gbif:2,irmng:12Archaea (domain silva:D37982/#1)NaNNaN
35246114996421.0Marine Hydrothermal Vent Group 1(MHVG-1)no rank - terminalsilva:AB302039/#2NaNNaNNaN
4102415996421.0Thaumarchaeotaphylumsilva:D87348/#2,ncbi:651137,worms:559429,irmng...NaNNaNNaN
55246628102415.0terrestrial groupno rank - terminalsilva:AB600373/#3NaNNaNNaN
64795965102415.0Marine Group Ino ranksilva:D87348/#3,ncbi:905826NaNNaNNaN
752056494795965.0uncultured marine crenarchaeote 'Gulf of Maine'speciessilva:AGBE01001967,ncbi:1089683NaNsibling_higherNaN
852080504795965.0uncultured marine archaeon DCM858speciessilva:AF121992,ncbi:105567NaNsibling_higherNaN
952050924795965.0uncultured marine group I thaumarchaeotespeciessilva:JF715361,ncbi:360837NaNsibling_higherNaN
1052050724795965.0uncultured Nitrosopumilaceae archaeonspeciessilva:JN591993,ncbi:1118069NaNsibling_higherNaN
1152087654795965.0uncultured marine archaeon DCM874speciessilva:AF122001,ncbi:105576NaNsibling_higherNaN
121797054795965.0Cenarchaealesordersilva:AY192631/#4,ncbi:205948,worms:573555,irm...NaNNaNNaN
13189165179705.0Cenarchaeaceaefamilysilva:AY192631/#5,ncbi:205957,worms:573556,gbi...NaNNaNNaN
14888219189165.0Cenarchaeumgenussilva:AY192631/#6,ncbi:46769,worms:573557,gbif...NaNNaNNaN
155207306888219.0Thermoplasmatales archaeon Gplspeciessilva:JN881616,ncbi:261391NaNNaNNaN
16376618888219.0Cenarchaeum symbiosum Ano rank - terminalsilva:DQ397549,ncbi:414004NaNNaNNaN
174796244888219.0crenarchaeote symbiont of Axinella sp.speciessilva:AF421159,ncbi:173517NaNNaNNaN
184796252888219.0crenarchaeote symbiont of Axinella verrucosaspeciessilva:AF420237,ncbi:171716NaNNaNNaN
195204995888219.0uncultured Cenarchaeaceae thaumarchaeotespeciessilva:DQ299278,ncbi:375545NaNNaNNaN
20363497888219.0Cenarchaeum symbiosumspeciessilva:AF083072,ncbi:46770,worms:573558,gbif:59...NaNNaNNaN
21376617363497.0Cenarchaeum symbiosum Bno rank - terminalncbi:414005NaNinfraspecificNaN
225204996888219.0Cenarchaeum environmental samplesno rank - terminalncbi:355925NaNwas_containerNaN
235204994189165.0Cenarchaeaceae environmental samplesno rank - terminalncbi:375544NaNwas_containerNaN
245204998179705.0Cenarchaeales environmental samplesno rank - terminalncbi:260466NaNwas_containerNaN
255204999179705.0uncultured Cenarchaeales thaumarchaeotespeciesncbi:260467NaNsibling_higher,not_otuNaN
2652053984795965.0uncultured crenarchaeote ODPB-A18speciessilva:AF121098,ncbi:95930NaNsibling_higherNaN
2752056254795965.0uncultured crenarchaeote ODPB-A3speciessilva:AF121093,ncbi:95925NaNsibling_higherNaN
2852050194795965.0uncultured marine crenarchaeote KM3-86-C1speciessilva:EU686625,ncbi:526685NaNsibling_higherNaN
2952050584795965.0uncultured Nitrosopumilales archaeonspeciessilva:EF069380,ncbi:171534NaNsibling_higherNaN
...........................
9695205123102415.0thaumarchaeote enrichment culture clone Ec.FBa...speciesncbi:1238031NaNenvironmentalNaN
9705205150102415.0thaumarchaeote enrichment culture clone Ec.FBa...speciesncbi:1237975NaNenvironmentalNaN
9715571747102415.0uncultured marine thaumarchaeote KM3_158_B05speciesncbi:1456024NaNenvironmental,not_otuNaN
9725571649102415.0uncultured marine thaumarchaeote KM3_84_D12speciesncbi:1456311NaNenvironmental,not_otuNaN
9735572006102415.0uncultured marine thaumarchaeote AD1000_60_A11speciesncbi:1455927NaNenvironmental,not_otuNaN
9745205251102415.0thaumarchaeote enrichment culture clone Ec.FBa...speciesncbi:1237979NaNenvironmentalNaN
9755571794102415.0uncultured marine thaumarchaeote KM3_201_H03speciesncbi:1456096NaNenvironmental,not_otuNaN
9765571869102415.0uncultured marine thaumarchaeote KM3_82_D05speciesncbi:1456304NaNenvironmental,not_otuNaN
9775571712102415.0uncultured marine thaumarchaeote AD1000_24_H07speciesncbi:1455902NaNenvironmental,not_otuNaN
9785571961102415.0uncultured marine thaumarchaeote KM3_75_F06speciesncbi:1456280NaNenvironmental,not_otuNaN
9795571926102415.0uncultured marine thaumarchaeote KM3_71_E12speciesncbi:1456258NaNenvironmental,not_otuNaN
9805205222102415.0thaumarchaeote enrichment culture clone Ec.MTa...speciesncbi:1238100NaNenvironmentalNaN
9815571900102415.0uncultured marine thaumarchaeote KM3_06_B06speciesncbi:1455974NaNenvironmental,not_otuNaN
9825205166102415.0thaumarchaeote enrichment culture clone Ec.FBb...speciesncbi:1238069NaNenvironmentalNaN
9835571740102415.0uncultured marine thaumarchaeote KM3_193_A03speciesncbi:1456081NaNenvironmental,not_otuNaN
9845205235102415.0thaumarchaeote enrichment culture clone Ec.MTa...speciesncbi:1238126NaNenvironmentalNaN
9855571679102415.0uncultured marine thaumarchaeote KM3_23_E01speciesncbi:1456099NaNenvironmental,not_otuNaN
9865571865102415.0uncultured marine thaumarchaeote SAT1000_48_A08speciesncbi:1456414NaNenvironmental,not_otuNaN
9875571850102415.0uncultured marine thaumarchaeote SAT1000_10_G06speciesncbi:1456374NaNenvironmental,not_otuNaN
9885571611102415.0uncultured marine thaumarchaeote AD1000_26_G12speciesncbi:1455904NaNenvironmental,not_otuNaN
9895572016102415.0uncultured marine thaumarchaeote KM3_65_D04speciesncbi:1456224NaNenvironmental,not_otuNaN
9905571969102415.0uncultured marine thaumarchaeote KM3_186_C08speciesncbi:1456070NaNenvironmental,not_otuNaN
9915571667102415.0uncultured marine thaumarchaeote KM3_41_H02speciesncbi:1456146NaNenvironmental,not_otuNaN
9925571890102415.0uncultured marine thaumarchaeote KM3_52_F05speciesncbi:1456177NaNenvironmental,not_otuNaN
9935571807102415.0uncultured marine thaumarchaeote AD1000_54_F09speciesncbi:1455926NaNenvironmental,not_otuNaN
9945571591102415.0uncultured marine thaumarchaeote KM3_175_A05speciesncbi:1456051NaNenvironmental,not_otuNaN
9955571756102415.0uncultured marine thaumarchaeote KM3_46_E07speciesncbi:1456159NaNenvironmental,not_otuNaN
9965571888102415.0uncultured marine thaumarchaeote KM3_02_A10speciesncbi:1455955NaNenvironmental,not_otuNaN
9975205131102415.0thaumarchaeote enrichment culture clone Ec.FBa...speciesncbi:1238015NaNenvironmentalNaN
9985572032102415.0uncultured marine thaumarchaeote KM3_53_B02speciesncbi:1456180NaNenvironmental,not_otuNaN
\n", "

999 rows × 8 columns

\n", "
" ], "text/plain": [ " uid parent_uid name \\\n", "0 805080 NaN life \n", "1 93302 805080.0 cellular organisms \n", "2 996421 93302.0 Archaea \n", "3 5246114 996421.0 Marine Hydrothermal Vent Group 1(MHVG-1) \n", "4 102415 996421.0 Thaumarchaeota \n", "5 5246628 102415.0 terrestrial group \n", "6 4795965 102415.0 Marine Group I \n", "7 5205649 4795965.0 uncultured marine crenarchaeote 'Gulf of Maine' \n", "8 5208050 4795965.0 uncultured marine archaeon DCM858 \n", "9 5205092 4795965.0 uncultured marine group I thaumarchaeote \n", "10 5205072 4795965.0 uncultured Nitrosopumilaceae archaeon \n", "11 5208765 4795965.0 uncultured marine archaeon DCM874 \n", "12 179705 4795965.0 Cenarchaeales \n", "13 189165 179705.0 Cenarchaeaceae \n", "14 888219 189165.0 Cenarchaeum \n", "15 5207306 888219.0 Thermoplasmatales archaeon Gpl \n", "16 376618 888219.0 Cenarchaeum symbiosum A \n", "17 4796244 888219.0 crenarchaeote symbiont of Axinella sp. \n", "18 4796252 888219.0 crenarchaeote symbiont of Axinella verrucosa \n", "19 5204995 888219.0 uncultured Cenarchaeaceae thaumarchaeote \n", "20 363497 888219.0 Cenarchaeum symbiosum \n", "21 376617 363497.0 Cenarchaeum symbiosum B \n", "22 5204996 888219.0 Cenarchaeum environmental samples \n", "23 5204994 189165.0 Cenarchaeaceae environmental samples \n", "24 5204998 179705.0 Cenarchaeales environmental samples \n", "25 5204999 179705.0 uncultured Cenarchaeales thaumarchaeote \n", "26 5205398 4795965.0 uncultured crenarchaeote ODPB-A18 \n", "27 5205625 4795965.0 uncultured crenarchaeote ODPB-A3 \n", "28 5205019 4795965.0 uncultured marine crenarchaeote KM3-86-C1 \n", "29 5205058 4795965.0 uncultured Nitrosopumilales archaeon \n", ".. ... ... ... \n", "969 5205123 102415.0 thaumarchaeote enrichment culture clone Ec.FBa... \n", "970 5205150 102415.0 thaumarchaeote enrichment culture clone Ec.FBa... \n", "971 5571747 102415.0 uncultured marine thaumarchaeote KM3_158_B05 \n", "972 5571649 102415.0 uncultured marine thaumarchaeote KM3_84_D12 \n", "973 5572006 102415.0 uncultured marine thaumarchaeote AD1000_60_A11 \n", "974 5205251 102415.0 thaumarchaeote enrichment culture clone Ec.FBa... \n", "975 5571794 102415.0 uncultured marine thaumarchaeote KM3_201_H03 \n", "976 5571869 102415.0 uncultured marine thaumarchaeote KM3_82_D05 \n", "977 5571712 102415.0 uncultured marine thaumarchaeote AD1000_24_H07 \n", "978 5571961 102415.0 uncultured marine thaumarchaeote KM3_75_F06 \n", "979 5571926 102415.0 uncultured marine thaumarchaeote KM3_71_E12 \n", "980 5205222 102415.0 thaumarchaeote enrichment culture clone Ec.MTa... \n", "981 5571900 102415.0 uncultured marine thaumarchaeote KM3_06_B06 \n", "982 5205166 102415.0 thaumarchaeote enrichment culture clone Ec.FBb... \n", "983 5571740 102415.0 uncultured marine thaumarchaeote KM3_193_A03 \n", "984 5205235 102415.0 thaumarchaeote enrichment culture clone Ec.MTa... \n", "985 5571679 102415.0 uncultured marine thaumarchaeote KM3_23_E01 \n", "986 5571865 102415.0 uncultured marine thaumarchaeote SAT1000_48_A08 \n", "987 5571850 102415.0 uncultured marine thaumarchaeote SAT1000_10_G06 \n", "988 5571611 102415.0 uncultured marine thaumarchaeote AD1000_26_G12 \n", "989 5572016 102415.0 uncultured marine thaumarchaeote KM3_65_D04 \n", "990 5571969 102415.0 uncultured marine thaumarchaeote KM3_186_C08 \n", "991 5571667 102415.0 uncultured marine thaumarchaeote KM3_41_H02 \n", "992 5571890 102415.0 uncultured marine thaumarchaeote KM3_52_F05 \n", "993 5571807 102415.0 uncultured marine thaumarchaeote AD1000_54_F09 \n", "994 5571591 102415.0 uncultured marine thaumarchaeote KM3_175_A05 \n", "995 5571756 102415.0 uncultured marine thaumarchaeote KM3_46_E07 \n", "996 5571888 102415.0 uncultured marine thaumarchaeote KM3_02_A10 \n", "997 5205131 102415.0 thaumarchaeote enrichment culture clone Ec.FBa... \n", "998 5572032 102415.0 uncultured marine thaumarchaeote KM3_53_B02 \n", "\n", " rank sourceinfo \\\n", "0 no rank silva:0,ncbi:1,worms:1,gbif:0,irmng:0 \n", "1 no rank ncbi:131567 \n", "2 domain silva:D37982/#1,ncbi:2157,worms:8,gbif:2,irmng:12 \n", "3 no rank - terminal silva:AB302039/#2 \n", "4 phylum silva:D87348/#2,ncbi:651137,worms:559429,irmng... \n", "5 no rank - terminal silva:AB600373/#3 \n", "6 no rank silva:D87348/#3,ncbi:905826 \n", "7 species silva:AGBE01001967,ncbi:1089683 \n", "8 species silva:AF121992,ncbi:105567 \n", "9 species silva:JF715361,ncbi:360837 \n", "10 species silva:JN591993,ncbi:1118069 \n", "11 species silva:AF122001,ncbi:105576 \n", "12 order silva:AY192631/#4,ncbi:205948,worms:573555,irm... \n", "13 family silva:AY192631/#5,ncbi:205957,worms:573556,gbi... \n", "14 genus silva:AY192631/#6,ncbi:46769,worms:573557,gbif... \n", "15 species silva:JN881616,ncbi:261391 \n", "16 no rank - terminal silva:DQ397549,ncbi:414004 \n", "17 species silva:AF421159,ncbi:173517 \n", "18 species silva:AF420237,ncbi:171716 \n", "19 species silva:DQ299278,ncbi:375545 \n", "20 species silva:AF083072,ncbi:46770,worms:573558,gbif:59... \n", "21 no rank - terminal ncbi:414005 \n", "22 no rank - terminal ncbi:355925 \n", "23 no rank - terminal ncbi:375544 \n", "24 no rank - terminal ncbi:260466 \n", "25 species ncbi:260467 \n", "26 species silva:AF121098,ncbi:95930 \n", "27 species silva:AF121093,ncbi:95925 \n", "28 species silva:EU686625,ncbi:526685 \n", "29 species silva:EF069380,ncbi:171534 \n", ".. ... ... \n", "969 species ncbi:1238031 \n", "970 species ncbi:1237975 \n", "971 species ncbi:1456024 \n", "972 species ncbi:1456311 \n", "973 species ncbi:1455927 \n", "974 species ncbi:1237979 \n", "975 species ncbi:1456096 \n", "976 species ncbi:1456304 \n", "977 species ncbi:1455902 \n", "978 species ncbi:1456280 \n", "979 species ncbi:1456258 \n", "980 species ncbi:1238100 \n", "981 species ncbi:1455974 \n", "982 species ncbi:1238069 \n", "983 species ncbi:1456081 \n", "984 species ncbi:1238126 \n", "985 species ncbi:1456099 \n", "986 species ncbi:1456414 \n", "987 species ncbi:1456374 \n", "988 species ncbi:1455904 \n", "989 species ncbi:1456224 \n", "990 species ncbi:1456070 \n", "991 species ncbi:1456146 \n", "992 species ncbi:1456177 \n", "993 species ncbi:1455926 \n", "994 species ncbi:1456051 \n", "995 species ncbi:1456159 \n", "996 species ncbi:1455955 \n", "997 species ncbi:1238015 \n", "998 species ncbi:1456180 \n", "\n", " uniqname flags Unnamed: 7 \n", "0 NaN NaN NaN \n", "1 NaN NaN NaN \n", "2 Archaea (domain silva:D37982/#1) NaN NaN \n", "3 NaN NaN NaN \n", "4 NaN NaN NaN \n", "5 NaN NaN NaN \n", "6 NaN NaN NaN \n", "7 NaN sibling_higher NaN \n", "8 NaN sibling_higher NaN \n", "9 NaN sibling_higher NaN \n", "10 NaN sibling_higher NaN \n", "11 NaN sibling_higher NaN \n", "12 NaN NaN NaN \n", "13 NaN NaN NaN \n", "14 NaN NaN NaN \n", "15 NaN NaN NaN \n", "16 NaN NaN NaN \n", "17 NaN NaN NaN \n", "18 NaN NaN NaN \n", "19 NaN NaN NaN \n", "20 NaN NaN NaN \n", "21 NaN infraspecific NaN \n", "22 NaN was_container NaN \n", "23 NaN was_container NaN \n", "24 NaN was_container NaN \n", "25 NaN sibling_higher,not_otu NaN \n", "26 NaN sibling_higher NaN \n", "27 NaN sibling_higher NaN \n", "28 NaN sibling_higher NaN \n", "29 NaN sibling_higher NaN \n", ".. ... ... ... \n", "969 NaN environmental NaN \n", "970 NaN environmental NaN \n", "971 NaN environmental,not_otu NaN \n", "972 NaN environmental,not_otu NaN \n", "973 NaN environmental,not_otu NaN \n", "974 NaN environmental NaN \n", "975 NaN environmental,not_otu NaN \n", "976 NaN environmental,not_otu NaN \n", "977 NaN environmental,not_otu NaN \n", "978 NaN environmental,not_otu NaN \n", "979 NaN environmental,not_otu NaN \n", "980 NaN environmental NaN \n", "981 NaN environmental,not_otu NaN \n", "982 NaN environmental NaN \n", "983 NaN environmental,not_otu NaN \n", "984 NaN environmental NaN \n", "985 NaN environmental,not_otu NaN \n", "986 NaN environmental,not_otu NaN \n", "987 NaN environmental,not_otu NaN \n", "988 NaN environmental,not_otu NaN \n", "989 NaN environmental,not_otu NaN \n", "990 NaN environmental,not_otu NaN \n", "991 NaN environmental,not_otu NaN \n", "992 NaN environmental,not_otu NaN \n", "993 NaN environmental,not_otu NaN \n", "994 NaN environmental,not_otu NaN \n", "995 NaN environmental,not_otu NaN \n", "996 NaN environmental,not_otu NaN \n", "997 NaN environmental NaN \n", "998 NaN environmental,not_otu NaN \n", "\n", "[999 rows x 8 columns]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The description of the entries is given here:\n", "https://github.com/OpenTreeOfLife/reference-taxonomy/wiki/Interim-taxonomy-file-format" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Explore the table" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['uid', 'parent_uid', 'name', 'rank', 'sourceinfo', 'uniqname', 'flags',\n", " 'Unnamed: 7'],\n", " dtype='object')" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life.columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us drop some columns." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "tree_of_life = tree_of_life.drop(columns=['sourceinfo', 'uniqname', 'flags','Unnamed: 7'])" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uidparent_uidnamerank
0805080NaNlifeno rank
193302805080.0cellular organismsno rank
299642193302.0Archaeadomain
35246114996421.0Marine Hydrothermal Vent Group 1(MHVG-1)no rank - terminal
4102415996421.0Thaumarchaeotaphylum
\n", "
" ], "text/plain": [ " uid parent_uid name \\\n", "0 805080 NaN life \n", "1 93302 805080.0 cellular organisms \n", "2 996421 93302.0 Archaea \n", "3 5246114 996421.0 Marine Hydrothermal Vent Group 1(MHVG-1) \n", "4 102415 996421.0 Thaumarchaeota \n", "\n", " rank \n", "0 no rank \n", "1 no rank \n", "2 domain \n", "3 no rank - terminal \n", "4 phylum " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pandas infered the type of values inside each column (int, float, string and string). The parent_uid column has float values because there was a missing value, converted to `NaN`" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "int64 float64\n" ] } ], "source": [ "print(tree_of_life['uid'].dtype, tree_of_life.parent_uid.dtype)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How to access individual values." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'life'" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life.iloc[0, 2]" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'life'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life.loc[0, 'name']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exercise**: Guess the output of the below line." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# tree_of_life.uid[0] == tree_of_life.parent_uid[1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ordering the data." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uidparent_uidnamerank
2975246638102415.0AB64A-17no rank - terminal
2935246632102415.0AK31no rank - terminal
2985246637102415.0AK56no rank - terminal
2025246635102415.0AK59no rank - terminal
2045246636102415.0AK8no rank - terminal
\n", "
" ], "text/plain": [ " uid parent_uid name rank\n", "297 5246638 102415.0 AB64A-17 no rank - terminal\n", "293 5246632 102415.0 AK31 no rank - terminal\n", "298 5246637 102415.0 AK56 no rank - terminal\n", "202 5246635 102415.0 AK59 no rank - terminal\n", "204 5246636 102415.0 AK8 no rank - terminal" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life.sort_values(by='name').head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operation on the columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unique values, useful for categories:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['no rank', 'domain', 'no rank - terminal', 'phylum', 'species',\n", " 'order', 'family', 'genus', 'class'], dtype=object)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life['rank'].unique()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Selecting only one category." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uidparent_uidnamerank
752056494795965.0uncultured marine crenarchaeote 'Gulf of Maine'species
852080504795965.0uncultured marine archaeon DCM858species
952050924795965.0uncultured marine group I thaumarchaeotespecies
1052050724795965.0uncultured Nitrosopumilaceae archaeonspecies
1152087654795965.0uncultured marine archaeon DCM874species
\n", "
" ], "text/plain": [ " uid parent_uid name \\\n", "7 5205649 4795965.0 uncultured marine crenarchaeote 'Gulf of Maine' \n", "8 5208050 4795965.0 uncultured marine archaeon DCM858 \n", "9 5205092 4795965.0 uncultured marine group I thaumarchaeote \n", "10 5205072 4795965.0 uncultured Nitrosopumilaceae archaeon \n", "11 5208765 4795965.0 uncultured marine archaeon DCM874 \n", "\n", " rank \n", "7 species \n", "8 species \n", "9 species \n", "10 species \n", "11 species " ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life[tree_of_life['rank'] == 'species'].head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How many species do we have?" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "912" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(tree_of_life[tree_of_life['rank'] == 'species'])" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "species 912\n", "no rank - terminal 58\n", "no rank 12\n", "genus 8\n", "order 3\n", "family 3\n", "domain 1\n", "phylum 1\n", "class 1\n", "Name: rank, dtype: int64" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree_of_life['rank'].value_counts()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building the graph" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us build the adjacency matrix of the graph. For that we need to reorganize the data. First we separate the nodes and their properties from the edges." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "nodes = tree_of_life[['uid', 'name','rank']]\n", "edges = tree_of_life[['uid', 'parent_uid']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When using an adjacency matrix, nodes are indexed by their row or column number and not by a `uid`. Let us create a new index for the nodes." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
node_idxuidnamerank
00805080lifeno rank
1193302cellular organismsno rank
22996421Archaeadomain
335246114Marine Hydrothermal Vent Group 1(MHVG-1)no rank - terminal
44102415Thaumarchaeotaphylum
\n", "
" ], "text/plain": [ " node_idx uid name \\\n", "0 0 805080 life \n", "1 1 93302 cellular organisms \n", "2 2 996421 Archaea \n", "3 3 5246114 Marine Hydrothermal Vent Group 1(MHVG-1) \n", "4 4 102415 Thaumarchaeota \n", "\n", " rank \n", "0 no rank \n", "1 no rank \n", "2 domain \n", "3 no rank - terminal \n", "4 phylum " ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a column for node index.\n", "nodes.reset_index(level=0, inplace=True)\n", "nodes = nodes.rename(columns={'index':'node_idx'})\n", "nodes.head()" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
node_idx
uid
8050800
933021
9964212
52461143
1024154
\n", "
" ], "text/plain": [ " node_idx\n", "uid \n", "805080 0\n", "93302 1\n", "996421 2\n", "5246114 3\n", "102415 4" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a conversion table from uid to node index.\n", "uid2idx = nodes[['node_idx', 'uid']]\n", "uid2idx = uid2idx.set_index('uid')\n", "uid2idx.head()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uidparent_uid
0805080NaN
193302805080.0
299642193302.0
35246114996421.0
4102415996421.0
\n", "
" ], "text/plain": [ " uid parent_uid\n", "0 805080 NaN\n", "1 93302 805080.0\n", "2 996421 93302.0\n", "3 5246114 996421.0\n", "4 102415 996421.0" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "edges.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we are ready to use yet another powerful function of Pandas. Those familiar with SQL will recognize it: the `join` function." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "# Add a new column, matching the uid with the node_idx.\n", "edges = edges.join(uid2idx, on='uid')" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "# Do the same with the parent_uid.\n", "edges = edges.join(uid2idx, on='parent_uid', rsuffix='_parent')" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "# Drop the uids.\n", "edges = edges.drop(columns=['uid','parent_uid'])" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
node_idxnode_idx_parent
00NaN
110.0
221.0
332.0
442.0
\n", "
" ], "text/plain": [ " node_idx node_idx_parent\n", "0 0 NaN\n", "1 1 0.0\n", "2 2 1.0\n", "3 3 2.0\n", "4 4 2.0" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "edges.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The above table is a list of edges connecting nodes and their parents." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building the (weighted) adjacency matrix\n", "\n", "We will use numpy to build this matrix. Note that we don't have edge weights here, so our graph is going to be unweighted." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "n_nodes = len(nodes)\n", "adjacency = np.zeros((n_nodes, n_nodes), dtype=int)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "for idx, row in edges.iterrows():\n", " if np.isnan(row.node_idx_parent):\n", " continue\n", " i, j = int(row.node_idx), int(row.node_idx_parent)\n", " adjacency[i, j] = 1\n", " adjacency[j, i] = 1" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adjacency[:15, :15]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Congratulations, you have built the adjacency matrix!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graph visualization\n", "\n", "To conclude, let us visualize the graph. We will use the python module networkx." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "# A simple command to create the graph from the adjacency matrix.\n", "graph = nx.from_numpy_array(adjacency)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition, let us add some attributes to the nodes:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "node_props = nodes.to_dict()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "for key in node_props:\n", " # print(key, node_props[key])\n", " nx.set_node_attributes(graph, node_props[key], key)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us check if it is correctly recorded:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'node_idx': 1, 'uid': 93302, 'name': 'cellular organisms', 'rank': 'no rank'}" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "graph.node[1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Draw the graph with two different [layout algorithms](https://en.wikipedia.org/wiki/Graph_drawing#Layout_methods)." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/michael/.conda/envs/ntds_2018/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py:611: MatplotlibDeprecationWarning: isinstance(..., numbers.Number)\n", " if cb.is_numlike(alpha):\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nx.draw_spectral(graph)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/michael/.conda/envs/ntds_2018/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py:611: MatplotlibDeprecationWarning: isinstance(..., numbers.Number)\n", " if cb.is_numlike(alpha):\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAe4AAAE/CAYAAACAdSDcAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvqOYd8AAAIABJREFUeJzt3Xl4FFXaNvC7OmuHHZIgQmAcRzGsQQjgIBJFETCAAfEdBjLCzLhEZWYEWeKrg3y8GkRAcRiCMB8gI474qYAgm6AsAmrnFUVAxBUUhQ4KYQshSZ/vj0NDE5J0d9Wprq7u+3dddSlJd9VJ0t1Pne15NCGEABEREdmCw+oGEBERUeAYuImIiGyEgZuIiMhGGLiJiIhshIGbiIjIRhi4iYiIbISBm4iIyEYYuImIiGyEgZuIiMhGGLiJiIhshIGbiIjIRhi4iYiIbISBm4iIyEYYuImIiGwk1uoGEFEEcLuBRYuAXbvk/xcXA5oGpKTI49e/lo/75hugpARo0ADo0AEYNUp+n4gCprEeNxHp5nIBBQXAmjWAxwOcOxf4c51OQAigXz8gPx/IzDSvnUQRhIGbiPQpLATGjgVKS42fKzYWeOopYPx44+ciinAM3EQUvAkTgOnTZS9bpWbN5JB7nz5qz0sUQRi4iSg4EyYA06aZew0GcKIacVU5EQWusBCYMcP86/z0E3D77UBGhpxHJ6IL2OMmosC4XECvXmrmtIMRFwfMmgXk5YX2ukRhij1uIgpMQQFw9mzor1teDjz8sByiJyL2uIkoAG430KqVNYHb14QJwNSp1raByGLscRORf4sWWd0C6dln5Tw7URRj4CYi/3btsr63DcjtZ2PHAkVFVreEyDIM3ETkX0mJ1S24qLRUzrcTRSkGbiLyr0EDq1twqdWrZT50oijEwE1E/nXoACQmWt2KizQtfObdiUKMgZuI/Bs50uoWXKq0FPjsM6tbQWQJBm4i8i81VVbx0jSrW3LRsWNWt4DIEqzHTfbgW++Z9ZytkZ8PrFsHnDljdUukRo2sbgGRJZiAhcKbb71n4NItSaznHHqFhcCYMdZvDXM6gcmTgXHjrG0HkQUYuCl8FRYCjz4q5zNre5lqmvwgnz6d+axDobAQ+NvfgHPnrGtDYiJw8CBHWygqcY6bwpM3aJ85U3vQBuT3z5yRj2dWLfPl5QHbtgEtWlhzfU0D+vdn0KaoxcBN4cfluhi0g+EN3syqZT6XC/jlF2uu7XTKqRGiKMXATeGnoEB/6Uhm1TKf3hsrFZKS5JRIly6hvzZRmOAcN4UXFVWoOP9prsGDgeXL/U9hqMR1DEQXsMdN4UVFNixm1TKP2y1X+IcyaMfGAjk5wObNDNpE4D5uCjcqqlAxq5Z5VNwQxcYCV18tE6h484373gg4zvcnmjcH7rwTeOIJjp4Q+WDgpvCiqgoVs2qZQ8WNVUUF0LUrsHixDNyLFskbrWPHZFKV9u1lilUGa6JqMXBTeFFVhYpZtcyh+sYqJYVJVIiCxDluCi8qqlA5nbLXRurxxorIcgzcFF5UVKESIvyqWUUK3lgRWY6Bm8KL0SpUzKplLt5YEVmO+7gp/LhcQFaWvgQfSUly25A3QQeriqlnZB+3psmtXW+8ob5dRFGCgZvCk2+u8gCdi4tD/KxZcq8vq4qZR+WNFREFjUPlFJ7y8mSWrKQk/8PmmgbhdKKgSRP8n+JiGfSzsmSv8OzZy7cvlZbKry1fLh/HwiTBycwEpk+HSEoK7nlMV0qkBHvcpE+ohqCLimTPefVqGcB9c5h7e879+wP5+TiSlobCjh3x2C+/IL68PPBreAMKs3IFZeUdd+C2deuQ6PGw7CpRCDFwU3CsGoIOJFGHywVPr15w6ClQwiHcoOzbtw89e/bEnpdeQur//b8B3Vjxd0ukBgM3Bc4771xaGp49LC6aCgmPx4Obb74ZQ4cOxcMPPyy/yAxoRCHDwE2B0bFYLKRD0CqqisXHAz/8wEDjx4IFCzB37lzs2LEDMTExVjeHKOpwcRr5p7f+8pkz8nlFRea0y5eK4hfnzgH332/8PBHM7XZj4sSJmDdvHoM2kUUYuMm/goJL5y6DUVoqn282FcUvAOCtt7jKvBaPPvoo/vCHPyAjI8PqphBFLRYZodoZrb8shFy4VFxs7hC0quIXlZVylCAzk4upqtiwYQO2bNmCPXv2WN0UoqjGHjfVTsUQtKapOU9tVBW/AEI3SmAjpaWlyMvLw+zZs1GnTh2rm0MU1Ri4qXYqhqBLS+VqYzOpKH7h5TtKQACAp59+GhkZGcjOzra6KURRj4Gbaqe6/rJZVBetCMUogU3s3bsXc+fOxaxZs6xuChGBc9zkTyjqL6vIwuatKqZ3H3dVoRglsAGPx4P7778fkydPxpVXXml1c4gI7HGTP2bWX3a5ZNKUVq2ASZOAJUuAVavkf598EmjZUn7f5QrsOvn58lqqmD1KYAMLFixAeXk57uc2OaKwwQQsVDsFiU0q4+KAgwcRc8UVF79oVha2wkJg9Gi5Otyo3Fxg8WLj57GpI0eOoH379njnnXfQsWNHq5tDROexx0218w5B+6vQVQOPpmFLvXro0Ls33njjDXg8nkuzsPm7bxRCPm70aNlrHzECmDat5oVjeXnAgAG62nqJmkYJosjYsWMxcuRIBm2iMMMeN/lnsP6y2LQJa48exeOPP470U6ew6MABxJaV6W+Pv2ImbjeQliYzoemVmAgcPBi16U/feecd3Hfffdi9eze3fxGFGfa4yb/z9Zehs/6ylpmJfv36oaioCNMaNYJmJGgD/utpp6YCd9yhe5QAmiYrWkVp0C4tLcUDDzyAOXPmMGgThSH2uClwRuelVRQCqU51xUwMjBJUJiQg5v33ozZz2n//93/jq6++wtKlS61uChFVgz1uClxenqxZnZMjh5KrruB2OuXXc3Lk46ouJjNrX3R1xUx0jhKcdTjwl/JybDh+/PJvut1yfn3ECDmP7m++3Yb27NmDefPm4fnnn7e6KURUA/a4SR899ZdHjJBbvcxQUz3tIEcJPM8+i+xVq/DOO+9g3bp1uOWWW2TvvaBA5mwHLh0x8DffbiMejwc9e/ZEbm4uHnjgAaubQ0Q1YOCm0BkwQO7TNktNC8qKimTgXb1aBmjfSmfewNu/vwy8XbpACIGBAwdi7dq12P3ww2g9b576bWthaN68eVi4cCG2bdsGh4ODcUThioGbQsfMHjcgA+fkycC4cdV/P4hRAiEE5mZk4A+7diGo5VnVzbfbwOHDh9GhQwds3LgR7aN8GxxRuGPgptCZNk1mSFO9OM2XqqQpLhdEVhY0nVvgsHmzrRa3/f73v0fLli0xdepUq5tCRH4wcFPomLWq3Fd2NrBypfHzDB6sP+95TfPtgfDN2+52y1ECTZMjAvXqyYV4Dgfw9dfy9+h0Am3aAF27Bpfb3cfatWvx4IMPYvfu3UgKdssfEYUcAzeFlpGAGAgVPW4VNxj+Erh4A/RHHwF79sih+2PHjCWNAYCEBBnM69UD6tQB2ratNaifOXMG7dq1w5w5c9C3b19j1yaikGB1MAqt/Hxg3Tp9Wdj8CSZNaW0VyVRsW/OWBR037tIgXVQke9Fm/PwAUFYmD+92tn37ZM9/wgQZzNu0AX7zmws/65SZM9GtWzcGbSIbYY+bQs83V7lC5TExKPvyS9S96qqaHxTI1q6UFOD77403qF8/2fN++22gogLweIyfUxWHAx4AG2Ni0Omtt5DMwE1kGwzcZI1A91cHSADYrGkYVK8ennrqKTzwwAOIja0yoKT4mpFAANAA2RO/5x7d8+REFDoM3GSd2vZX63CySxdkJyXhgw8+QJMmTTB37lwMGDAAmqaZ1suPOA4HkJ4OzJwJ9OljdWuIqBoM3GS94mJg9mxgyhRjPeHzC8I+/OYb3H///di7dy+uvfZavDFxIlrffz+DdrA6dgTmz7d1NjiiSMT0SGS9776TC6iM3kOeXxDWrVs3fPLJJ1izZg1KS0uxNzcXHgbt4H36KdC9u9x/T0Rhgz1uspbqIewq28HEkSPwpKUhprxczfmjFXvfRGGDPW6yjhnzzseOXfJP7aWXEBMTo+780erTT4Fu3WRimQiqhkZkRwzcZA2Xy5zFYo0aXfrvXbvMzdQWTYSQyXOaNZOJdFwuq1tEFJUYuMkaBQWGV5FX5UlMvDwBS0mJ0msQgMpKYNkyoGdPOWpCRCHFwE2h53bLBCiKl1ecO3sWd69ejWXLlqGiokJ+sUEDpdcgH2VlwEMPyaxsRBQyDNwUeipSilalaYgbNAgD//QnzJw5E61atcKkSZNwvGVLuU2MzCGEXHU+caLVLSGKGlxVTqFnRl3uKqU0d+/ejRdffBHrX34Zn504gfhwSjcaiTQN+Oc/bVeHnMiOGLgp9AYMAFatUne+pCRg+vRqg8bp06dR3LMn0nbuBNeWm8zhAD780FZ1yInsiEPlFHqK5p0FUGvQBoA6dergVy++iBjWmTafxyO3ixGRqRi4KfQ6dDA87ywA7IuNxTP9+2NVWhpOnz5d84MzM4GBAw1djwL0ww/Af/2X1a0gimgM3BR6I0caP0dCAsSGDdAyMzFjxgxcccUV6NOnD5577jl88cUXuGQGyOUC3nrL+DUpMK+9xsVqRCbiHDdZY/BgmcxDz8tP0+SQ7BtvXPjSiRMnsGHDBqxZswZr1qxBfHw8+vXrh379+qHvvHmIXbWKpTxDiYvViEzDwE3WcLmArCx9mdOqrCCvSgiB3bt3Y/Xq1dixYgVe3bED3BBmAacT2LKFi9WIFONQOVkjM1MuKgt20Zh3MVotwUDTNLRv3x4TJkzA8jvvRAL3cVujtFRmyCMipWKtbgBFMe8w6qOPyg/52gZ/NE324GpZQV6tXbugMVe5dVaskEVJUlKsbom9ud0ycdGuXTKNb4MGcpHnqFH83UYhDpWT9YqKZM9s9WoZoH1zmDudMqD37w/k5wc/7Kp6zzgFb/Ro4IUXrG6FPblc8r2xZo38t+9NqPe90a+ffG+w5GrUYOCm8FFcLHsVn30my3M2aiSLhowcqb9XYUaWNgpO8+ZymxgFx1v21qzRKLItBm6KbNOmAZMmsbSn1dxuDukGQ0+tej/JiChycHEaRTYVe8bJODMKy0QqvbXqz5yRzysqMqddFDYYuCmypabKOUBNs7ol0c3lsroF9mGkVj1X8kcFDpVT5DOyZ5zUSE8H9u61uhXhz+0GWrUyNrWTmAgcPMipiQjGHjdFPr17xkmdY8esboF+brdcKzFihNylMGKE/HdxsfprqZhS0DROTUQ47uOm6OC7Z5w979D75RerWxA871as1auBigqgsvLi95YuBf7+94vbFFVtxdq1y/hCytJSuTODIhZ73BQ98vJkqtR69axuSfQ5d86cHqpZCguBnj2BZcuAsrJLgzYgA3lZmfx+z57y8SqUlKg5j51HOMgv9rgpunTpwoVqVlm0CBg3Tu05zcgoVlgI/PWvQHl5YI8vK5OPB4xvxVJUqx6NGqk5D4Ul9rgp+gT6gUxqqRy+dblkhblWreQ+/SVLZIa8JUuAJ58EWraU3w92NbvLFVzQ9iovB/7yF+NbsRTUqofTKRMXUcTiqnKKPvXqAadOWd2K6NOnD7BunfHzmJlR7OabgU2b9Lft2muBL77Q/3yuKqcAsMdN0adOHatbEJ2OHjV+Dt+MYv76HEJcTEoSyBy02y3XQBixf79cca6X0bwDmiYXzDFoRzQGboo+nP+zJ7MziuXn+78ZCMRjjxkbMs/PlyMFejid8vkU0Ri4KfpUXSFModGkibHnm51R7I039J27qspKY9nLTKxVT5GBq8op+nBxmiUOlJXh202bkJycjOTkZDRp0gRxcXGBPdntlqUt9faIhZD7savUBj958iQOHDiAnz79FLeWlEDZfoNqrhUUn7wDorQUGquDkQ8Gboo+RlftUtAqAWz65RcsmDQJR48eRXFxMX755RfUrVv3QiCv7khJSUFycjKuWb4cKYChwFpeUYFVgwZhXoMG+O6773Do0CGUlZUhOTkZz6hOyuPNXmZk+1teHpCZia//9Ce03LMH8fHxamvVk20xcFP0adsW2LfP6lZElRiHA/e8+y7u8emBejweHD9+HEePHq322L9//4X/n7B7NwYZzCgWV1GBkzt2YENsLOLi4hAfH4+GDRtC0zTccvKkut42oC57WZcuuK9JE4xfuBB9Dx9WW6s+3JmxRz9CMHBT9OnaVd18JgWmefPLPmwdDgcaN26Mxo0b49prr639+QMGyH3aBjUCEBMTg5iYGDgcDggh0Ki8HE3NWPegJ3tZlWB1NjERPbZvR69Fi+Te9GjgTTW7Zo38t+8N25tvyn37/fqpTTVrMwzcFH1GjgQmTLC6FdHlzjuNPV9RRrFTsbE4d+4cysvLIYSAw+HAvQ4HTElmEczuhRqCVSKAxx0OJLRuHR3Byt8efe9UwfLlMidAlM7rc1U5RZ/UVHWpJcm/mBjgiSf0P9/lAj75xHg7nE4Me/ppVFRU4MCBA9i4cSOeffZZ3JGWpr4HExMTePaywkJZdnb5chmwq0wJJHg88mvLl8vHqcqLHm7M3KMfYZg5jaLTn/4ELFhgdSuiw+DB+qcmfD/Mjaopo5iiYfhLOBzA4cP+52L1/HzebV+R1NN0ueRNiZ6/c1KSTJwTRYvz2OOm6FRQwGIjIVARE4Nv/uu/oKt/oDJo15ZRrKLC+PmrqmZO/zJmJ5SxE7P36EcYBm6KTqmpQK9eVrciogkASzIzcVt+PlJSUpCTk4PnnnsORUVFqPAXLPUGtZrUlFGssBDYsEHNNXwFMqfPYCWp3KMfJRi4KXpNmyaHNMkUWlYW7tmxA19//TU++eQT3H333fjyyy8xcuRINGnSBH379sVTTz2FrVu34mzVrV5GglpVNWUUKywEHnlEfY87Ntb/nD6D1UWLFhk/h3fffJTgqnKKXpmZMkBwhbk5Xnvtwv+2aNECw4YNw7BhwwAAR48exbZt27BlyxaMGTMGn3/+OTp37oyePXvi1g4d0Gv16tqzhQWitoxiest3BmLgQP/D5CqDleoa59Uxc0/1rl3GqqEB6vbN2wQXpxElJwM//2x1KyLLddcBn38e8MNPnjyJHTt2YMuWLWi+ZAlGfvcddJbZuKhdO2DhwuoXLWVkAJ9+avQKlwt0odSIEbJ2uFG5ucDixcbPU5Pa9lR7M7cZ3aamanFgdjawcqXx89gAxwmJVHyA0qVeeCGoh9erVw99+vTB//zP/yCvRw/jQRsAOnWqPoCuW2de0A60yEdJiZpr6knyEig/29RQWqpmm5qqrZlRVPWPQ+UU2QIZ4rv9dqBNG2DvXkubGjGSk4HbbtP/fEVB7ZuPP8bHr79+Se7zJk2aIG7UKCXnv0BPkY9wD1bBrOj33VMNBP478L439+yRa008Ht3NhdMZ+L75SCCIItFHHwmRkyNEYqI85MeLPJxO+bWcHPk47+M17dLH8dB3rF9v7G83fLiSdrwEiJiYGJGYmCjq1KkjnE6nuB0QHpU/a2ysEIMHC+FyBfczPvPM5a/LYA+nU4hp04z9rqvz0UdCJCXpa1NSkv/fRW3vTb1HYqIQbrf630WYgtUNIFJuzhz5AeIvEGuafNycOfJ548dbH/RsfHgAcTY93fjfT0FQOw2I8Q6HcDgcIi4uTsTHxwuHwyEOQXHgHjhQ38945IjxoGVWsMrJ0X8Tq2nyRqYmgb43VV4zAsHqBhAp5f1gCOaN7xO8Tw8apPaDPYqOcodD9G7QQAwfPlx89tln+v+GCoJaKSBaJSWJmJgYkZSUJGJjY8XdDRqo/9sauVExM0DqZeYNhZ73ZiBHIL38CMPFaRQ5DGSi8owdi5m//z1abNmCj667zpyiExGswuHAhMREtL3nHlx11VW47bbbMHDgQOzYsSP4k6WmypXKejPbaRoScnKwYOVKDBs2DJqm4YorrsDfT5zQd77aGNnGlJ8v52b1EELmb1+/Xv/1q2PWnmrVCXW8glkQGEmsvnMgUsZAD6YCEDuvvlocOnRInmvCBMt7sLY54uOFmDNHfP/99yIvL080btxYjB8/Xjz77LPiV7/6lejVq5dYu3at8Hg8gf8tFc6znjp1Svy/f/5TVJjxsxudGpgzx3gPt1kzIdatu/S8R47IKYfhw4XIzpb/feYZ/0PritYXiNzcS89rZHShuqPqNFeUgdUNIFLCjCE+znn7PzIyLhum/Pbbb8Uf//hH0aRJEzFp0iQxb9480bZtW3H99deL1157TVRUVAT2NzU47XGJZ54RwuFQ//MPHWrgRXv+Z1TVrmbNhHjhheAWZVaVna2mLdnZF8+p4r1Z9WfQsyAwgsDqBhApYdYqXfa8qz/q1/e7enz//v1ixIgRIiUlRTz99NNi6dKlonv37uLaa68V//rXv0RZWZn/v6vehYZVqepJ+h4Oh7FV3XPmCJGQEPq/XW2/KzN63Cremw6HENdfL3/fUbR6vCawugFESpg1xCcEe95VP/RHjw7qT7Nnzx4xdOhQ0bRpUzFjxgyxdu1a0adPH9GiRQsxc+ZMcerUqdpP4HLJHlZiory58m1PoD0wVT1J3yM+Xn8QMTIVoOqoJnhXTp0qKuLjjZ236g2wme/NKAWrG0CkhBlDfL4mTDBnqNVOR9u2hoYnP/nkEzFo0CDRvHlz8c9//lNs375d3HXXXSIlJUU8+eST4ueff679BG63EH//uxCdOgnRvLk8OnWSXwvV3K3vYWRVd06O9X9P4MJ6gIMHD4rJkyeLzmlp4qzRueiqU05mvzdV0LsmwCKwugFESoTirn7OnMt7fNFwOBzyQ0wRl8sl+vXrJ1q2bCnmz58vPvvsMzFq1CjRqFEjMWbMGPHDDz9c/qRgE+pUpWK4tuo19d7EqJzzNXhUaprYmpoqGjduLB588EHxv//7v+q3qYVzj9vo68oisLoBREqEKhOVd9g2JsbyD92QHNUsPlNl27Zt4pZbbhFXX321eOmll8S3334r/vrXv4pGjRqJe++9V3z55ZfygSrmuVUGS4fD2Gpm1TcRBo+KuDhx5sCBi+1TnTlNxc8bGytHVqr+TY30klWtn7AArG4AkQrH9+8X54wG02AyUbndcq63eXPLP3hNOZo1M566NEDvvfeeuPHGG8V1110nXn31VXHkyBHxxBNPiOTkZDG/c2dREeyHfk0fsqq2JE2YYOwHNmPY3shR3Q2ryhX9qm6aNE2ItDQh7r5biP79jfWSVf58FoDVDSAy4vjx42Ly5MmiSZMmoqhlS+GxIhOV2y1EVpb1H8AqjnbtQhawfXk8HrFu3TrRtWtX0b59e/Hmm2+Kk+++K87Fxen7Oarr+RldEOZwGA/aQpizUM7oUd0wtMoeqep93P6O2tpkdi72EIDVDSDSo6SkREyZMkUkJyeL3NxcsX//fuvfkC6XEHfcYb9FbE2bytGDMFiI4/F4xFtvvSUyMjLExgYNRKXqGzG9aTdjY9X1tsKtxw3UvPBLxYp+IaxbRV9d8A7HVLNBgtUNIArGiRMnxNNPPy1SUlLE8OHDxb59+y59QDgMgbndcuixd29r9ukGcjRsKMSf/xwWwbo6lT/9JCr09ra9R205s4P5u6ie5zcrGYyRw9/CL+9rOjdXBvnc3OD3VJuVqzyQ97f37xfOxV2CAEuvThSgkydPiqlTp4rU1FTxu9/9Tuzdu7fmB4fbopP16+UQtNVlQ6+8Mmx61n6ZudgwmDSj59O5KnXkSHgFbjPKg9a0cGzaNFEaE6N/JEXP4dtLDudyqkGApVcn8uP06dPi2WefFU2bNhVDhw4Vu3fvDuyJqob4VPLtidetG7oPrnvvtUew9mXWFqJnngl+R4DDIZPwqNS2rTVBurpDZQ/Sz/aqyvh48X5Cgqi46abQjkZ5f8Zw3poWhFiri5wQVae0tBRz587FtGnT0KNHD7zzzjto37594Cfo0gV44w2guFhWKvrsM+DYMaBRI6B9e2DkSCAlxazmVy8lBRg3Th7AhbZtfP55tElORrPY82/HevWAkyeB06eBb74Bysv1X3PwYGDePONtD7WSEjXnOXZM/tflAsaPBzZtCv4cHg8wbZqsejV1qv62uN3ytbhrF1Cnjv7zqKRpQP/+at4LhYWyAlhpqQxvVZWWwgHgBk2Do6gIuOUWYO3a6h+rWHlFBVYOGoRW332HzipO6H1dWcXS2waiKkpLS8WsWbNEs2bNxJ133ik++eQTq5tkqhMnToh69eqJkpKS6h/w0Uf6k76EyQpYXRT1jI72768ucU5MjL5h81p6oZbXflf1GtEzfx3iXAifZ2aKb3r0UHM+i3vcrMdNYeHs2bOYPXs2fvOb32Djxo14++23sWzZMnTs2NHqpplq7dq16NGjB+rXr1/9AzIzgRkzZN3hIJTHx9u7TnGHDkBioqFTnAHwyerVqHjwQdkLNKqyEhg7FigqCvw5hYVAVhawfLms3V2lfrfOiuNqqKplrbfWdmWlsesG6bqmTXHVwIGGX1dwOuWonZUsvW2gqHf27FkxZ84c0aJFC3HHHXcIl117iDr9/ve/F3PnzvX/wCAW3JXHx4u5GRnmN95MClb/njOrR5uWFliGLqtWUQdyaJq6RXeh3qNtpJfMVeUUtRQk5C8rKxNz584VLVu2FP369RMffvihiQ0OT+fOnRONGjUShw4dCuwJAS64c69eLRo3bhx43etwZSAgVMLkYWjvsHdNGbrCofpXbUfTpmr+RmGUd73Ww3clOPdxU1RRkJD/3LlzYv78+aJVq1aiT58+YseOHSH8AcLLO++8I7p16xb8E3321P5v8+biyxtuuGxP7XXXXSeKiooUttYCBoJfyOaOa9pSGO690JQUNX+jMMu7XuPh20u2OlGTApzjpsD4matDaan82vLl8nGFhZd8u6KiAgsXLkTr1q2xdOlSvPLKK1i3bh26d+8esh8h3Cxfvhx33nln8E/0rk6fPh2Hfv1rlJ09C2zZAjzyiFz9XFyMW2+9FRs3blTf6FDKzJRzsEHO7wuEcO5YCDm3++ijF1/zbjewZo38XrhyOtWcZ9euyz8Lwk3VlfM6X1frlV1tAAAgAElEQVTK1gQooAkRzq8uCgvebR7BLD45/yKvuPdeLFmyBFOmTEHLli0xefJk9OzZ07y22oQQAmlpadiwYQOuu+664J7scgEFBcCaNSivqEBcRcXF7zmdgBD4sWNHFAD4xwcfKG23JfxtM/IR0qBdVVISsHkz8O67wKRJ4R3Q0tOBvXsv/FMIgdOnT+P48eM4fvw4SkpKAvr/gt27cfPp0xb+IAGIiQE++ODygBvo60rT5Ptq+nQgL8/ctgaIgZtq53LJHnSwK0YBVMTH4+6mTfHzVVdh8uTJyMrKUt48uyoqKsLw4cPxxRdfBPfEAD9shKahVAjEvfAC4kaPNtjaMFBUJG9WVq+WH6S+q8TP36ygbl3g6FHr2qhpQE6ObM+SJda1IwDvpaRgbIsWFwJwSUkJEhMT0bBhQzRs2BANGjS45L81/X/600+jwcqVVv84tWvXTuZxqE4gr6v+/YH8/LDoaXsxAQvVrqBA91Ya7dw5zG3VCimbNkHTLN34EnZWrFgR/DB5ECMfmhBIAlA5bhwQGxs2PQXd/CXUueOOcNiiIwNAmI8oCQAtcnLwr/vvvxCA69evj7i4uOBPduONwDvvhPfoQqdONX8vHBM1BYA97mjgm7GppARo0EDukx01qvYXpdsNtGpl7E2ZmAgcPBiWL/6Qqeb3P2PDBty0YAEy+/cP7BwGRj4uDOGGUY9Bub//HZgyxepWwJOQgNMtW6Lel18aPpdpw/4OB3D4sJr3pIrPCLNNm3YxW2GksG5dHJnO6CrwCEnIb5lafv9nAOEJYBX+BRGwhcVUnTpZv3L5/LGvTh1x1mgRkcRE8wqRtGun9ndv4LUZktX/dsvTHwCuKo9Uga4CX7YM6NXrslXgANSsGC0trXl+KZL5+f07AWi1rMK/hNFVykLIIdziYn3PtwO32+oWXNC6Rw8kxMcbO0lFBdC3r5oGVTVzptrz5efrXqVu+gRa3boROdrHwB2JfOdCA/mwLy0FHn4YmDDh0q+rLvQQLYL5/Qtx+XaiqhYtMt4mTVNzHvKvfn3gyiuh8zZLEkIuqlK1bcsrIwO47Ta15zSyvcroDY4/3bqZe36LMHBHGr15g70VkCZOvPClynr11LSpUSM157EDvb9/b/CuLg82Rz78C5NeVSUA8frrEN98Y6w3WVkJzJ4N/OUv8qZLBYcDmD9fzbmqysu7GLz9tVfTLu6JbtLEnPZ4r3P77ead30IM3JHGwCpwABDTp+PDUaNw991348k338RZox8a4ZCQP5SM/P5LS+Xzq+LIh38DBljdAgDyA1WDoiHgM2eAL78EHnpIxdlkSVIzFyjm5clFkDk5clFq1dECp1N+PSdHPi4vD2jY0Lz2xMXJVeERiKvKI4miFZ5lDgeeuv12rN27F1sOHIChWjrRtKrcrFX4I0ao2RecmwssXmz8POHI7QaaNZMjR5EkPh744QegRw8ZxPXKyAB27lTXLn8C3V51111yO5Zq3j31Zpw7DLDHHUkUzWHGeTy4ads2fH3yJHY1bw6ht9ddNdVgpDNrLlpBicuKuLjIHvlITQVuusnqVqhXUSFfD0uWyB6kHgkJ5g2R18SblnfxYmDlSvnfceMu/yzo2lUO4avmdMpFcxGKgTuSKMob7ADQ89QpvLt0KbouWwZN7wKZCH/zXMasuWgFw30ejydihw0vmDZNf3ALVx6PXDeRmQnMmiWDcDCSkoDnngvfPfwjR8oEQSqFUU5xszBwRxJVc6EA4hMS0HHnzohIyB8yZs1Fp6YC/frpXqQkNA0b4uMhkpMVNC6MeYObkeB95ZXA+vXAnDnBv+bNsnu3/G9engzCgbTLdwFYOGfNS02VWe9ULcBLTAz/n1kBBm47c7tlL2PECLk4x/sGV0Dz7fnpXTEa4W+eyzRooOY81a3CN7BXFk4nZteti6+++spYu+wgLy/4nqmmya1X69cDhw7J7VJ5eTJ4x8SY19ZA+Y7ieBeADR4c+AKwcGfkte0rIwPYutUeP7NRVmeAIR1qy4im8sjOvvS6LpfMwJWYKDOi+T7Wm4lt8OCwqFdrCbMzzc2ZE3wd4fO1ov/whz+IOVVrRkcy72s1IUGI2NhLfyeaJo+0NCFGj645s1ZOjvlZvQI50tOrb59PXXaRnS3/W6Uuu23oeW17j9hY+d6LIlxVbjdBlDg0rKZVyDZLyB8yocjtrrMU4b///W+sWLECr7/+uv622ZHe16rbDaSlAefOhaqlNRs6FHjtNatbYb5gP9tiY4GBA8OucldIWH3nQEEwcleqsudHNQtFTnEdIx+HDh0SjRs3FhUVFSb+8BHkmWfMyxUezOFwRNf7sLbXdkyM/H34GymJAuxx24WR6lB6RNP+a5VcLnhuugkOPb1uhwPo0we4+Wb/lduAoHuT6enpePnll9G5c+fg2xZtzNpfHCzvPu5oex9yVK9WDNx2MXiwLEgRij9XhCcvMNNPP/2El9q2xbiSEsToTQbidMq/c79+chgwM1NJ20aPHo20tDSMHz9eyfkiWno6sG+f1a2Q73u+D6kKriq3A6PVoYIVbfuvFTmxcSP2tG6NR0+eRIyR7S3eym2BVA4LQu/evbFx40Yl54p44VBfOi6O70OqFgO3HYSyqlM07r9WoGzWLMT16YNbTp5EbEWFLBJhlBD+K4cFISsrC9u3b0dZWZnxtkU61VW59HjqKb4PqVoM3HagKCNaraJ5/7VBFbNnQ4wZA6fHY84bqrbKYUFo2LAh2rRpgx07dihqWOT61urkKxkZMkUoUTUYuO1AVUYuhyMyEjaEkcoPPkDl3/6GRLOLW9RUOSxIHC6vncfjwcSJE7H0228hzMihHQgrcouTrShOEkumUJWRa8gQudCJKzWVEEJg17Bh6KhiWNz/xYDVq+VqWwN/q969e+Pxxx/HlClTFDYuMpw+fRq5ubk4evQolr3/PrSMjNDv4+ZUFQWAgdsOOnSQK0uNDJc7nTJoc/hNmYJHHsHYAwdCN2zlrRxm4G/Yo0cP7N69GyUlJWig6oYwAvz4448YOHAg2rVrh//85z9ISEiQObRDtZMD4FQVBYxD5TZQPnw4KioqjJ1EiMivDhVCM2fORNwrryA+2GpNRlRXOSxIiYmJ6NatGzZv3qyoUfa3c+dOdO/eHUOGDMHChQtl0AbU5dD2JzZWbvviVBUFiIE7jFVWVuLf//430nv1wo6GDVkXO0wsXLgQs2bNwoM33ggt1NuGqlYO04Hz3BetWLECffr0wcyZM5Gfnw/N9z2mtzJeoBo2BEaPBn78UY6ocXicAsTAHYY8Hg+WLl2Kdu3aYd68efjXv/6FnqtXsy52GFi+fDkee+wxrF+/HnXKy0PfgOoqhwXp1ltvjfrALYTA9OnT8dBDD2H16tW46667qn+gb2U8FXwrkR07BrzwAm+oKWic41bJ7ZZzkLt2yZXgDRrI+elA0ldCfpisWLECkyZNQkJCAp5//nn06dPnYi9g+nS5LSiYtKdc7KLMu+++i/vuuw9r1qxB69at1S0aDJTTKRcTGnT99dfj0KFD+Omnn9CsWTMFDbOXc+fO4aGHHoLL5cKOHTuQlpZW+xPy8mTvu6AAWLUKqKgAgtlFoGlAixbAnXcCTzzBQE3GWZgnPXLUVmbTW/QhJ0c+rhoej0e8/fbbonPnziIjI0O89dZbwuPxVH8tb6ERf4UsNO1CSUcy7qOPPhIpKSnivffeu/hFFWU8gzkSE5UVVsjJyREvv/yyknPZyS+//CJuvvlmkZ2dLU6ePBn8CbylNIcOleU2r7pKiGuuEaJDB3lcc438Wnq6fIxdy2xSWGPgNspAIPV4PGLDhg3ihhtuEG3atBGvv/66qKys9H9N1sUOqb1794qmTZuKFStWXPqNI0dCF7gDrRwWoNmzZ4tRo0YpO58d7N+/X1x77bVizJgxrJJGtsbAbYSeMpvng/eWLVtEr169xDXXXCOWLFmi74PEe/efmytEdrb8L+/wlTpw4IBIS0sTL730UvUPMFLGM9jXjcIbsc8//1ykpaXVPLITYTZt2iSaNm0qXnzxRaubQmQYq4N5BTs/baDM5lmHA3c3bYrBTz+NESNGIDaWSw3CkdvtRs+ePZGXl4e//e1v1T8oFOVWTdjfK4RAWloa3nvvPVxzzTXKzhuOFi5ciIkTJ+KVV15B7969rW4OkWEM3C6XXHSyZo38t+/2ntrKKxoos+nRNIhBgxCzbJnBxpMuAdyknThxAjfffDP69+/vP8tYYWHwiwYDoWnyNWhSUo577rkHN9xwAx544AHl5w4HHo8Hjz32GF5//XWsWrUK1113ndVNIlLD0v6+1QKdn/YZ4hZCqJnbVLjQiAIU4CLC0vPTGA8++GDgQ8nBvJYCOWJjTV+n8NJLL4khQ4aYdn4rnTp1SuTk5IiePXuK4uJiq5tDpFT09rj19JISEoDnngNOngQmTTKegnTyZKYgDRXv37u0tNZREqFpKHM4sKRTJ4z68EM4gik0UVQkR29Wr5bXCKZ8pqbJo3nzkG0bOnToEDp06AC3242YmBhTrxVKvulLX3zxxYuZ0IgiRHQGbiPzknFxQO/ewNq1xtuRmwssXmz8PFQ7HTdpIikJmt4h6uJiORT/2WfA4cPAzz8D5eUykJeXyxSXiYnytZScDDRtalmxl/T0dLz88svo3LlzSK9rlp07d2LQoEHIy8vDxIkTL82ERhQhojNwG5ifBiAXC6mYz8zOBlauNH4eqpmRm7SkJJk/OoKT1zz88MNo2bIlxo8fb3VTDFuxYgX+/Oc/o7CwsOZMaEQRIPpSnrrdciGagfsVoWoRkoL0leRHQYEcHtdDUQ3scBYJ6U+FCDB9KVGEiL59SIsWGT6FBkCc/69uitJXUi2M3qQJoaQGdjjLyspCbm4uysrKbDkXHHT6UqIIEH097l27jC0qO8/wzJkQLLNpNgU3aRdqYEeohg0bIj09HTt27LC6KUE7duwY+vbti8OHD+P9999n0KaoEX2Bu6RE2al0D7azzGZoqLhJU1ADO9zZcbj8yy+/RPfu3dGpUycsX74cdevWtbpJRCETfYFbYUUn3b1ultlUw+0Gpk0DRowABgyQ/502TQ5tA+pu0hTUwA5nvXv3xoYNG6xuRsA2b96Mnj17YuzYsZgxY0ZEbWUjCkT0zXF36AD85z/BleVTiWU2jVu3Dhg7Fvj8c/lv37/lq6/Km6LmzeUNkgoRvoiwR48e2L17N06cOIH69etb3ZxaedOXLlmyBLfeeqvVzSGyRPT1uM2YV46JkcPftdE0U3JORxWXC8jIAPr2BfbskQG76g1YZaX82vffA/v3G79mFCwiTExMRLdu3bB582arm1Ijj8eDiRMn4qmnnsLmzZsZtCmqRV/gTk0F0tPVnvO3vwVycmRSjaq9PKdTfj0nR+4JZtDWp7AQ6NED+PTT0F43ShYRhvNw+enTpzF06FBs374dH3zwAXOOU9SLvqFyAJgxQ/baVPnVr2QGNN+MWceOySFWizJiRZTCQuCRR2TWsVCKokWEt956K0aNGmV1My7jTV/atm1bvPLKK7bcskakWnRmTgPkkKuK3htzjpsrFGUzaxIFmdO8KisrkZycjL1796JZs2ZWNwcA05cS1ST6hsq95s+XuaKNipKhVMsUFFgXtKNoEWFMTAyysrLw7rvvWt0UADJ9aZ8+fTBz5kzk5+czaBP5iN7AnZkJzJoFBFP9qaooGkq1hDfzWShF8SLCcNjP7U1f+uCDDzJ9KVENojdwA/KD+dFH9T+f+7HNFcqMZVxEeGGBmlWzZ+fOncN9992Hl19+GR988AEyMzMtaQdRuIvOxWm+nnlG9rKmT5dbiQIVZUOpllCUnrZWDgcwZIgcgYnyRYStW7dGZWUlvvrqK1xzzTUhvfaxY8cwZMgQ1KlTB1u3bkW9evVCen0iO4nuHrfX1KnAP/4he13cjx0+FKanrVFCggza48ZFddAGAE3TLBku96YvzcjIwPLlyxm0ifxg4PbKywO2bOF+7HCiMD1tjaIgF3kwQr2f25u+dMyYMZg5cybTlxIFIHq3g9WG+7HDw7RpwKRJ5g+XZ2cDK1eaew2bOHToEDp06IDi4mI4jCzcDMDChQsxYcIEvPLKK8yERhQEBm4KX2430KqV+YE7N1cm0CEAQHp6OpYsWYLrr7/elPN7PB489thjeP3117Fq1SpmQiMKEofKKXylpgL9+pl7jSjIRR4sM4fLvelLt23bxvSlRDoxcFN4y8+XiwHNwgQ6lzFrgdqPP/6IXr16oW7dutiwYQOSk5OVX4MoGjBwU3jLzJQr+M3IUc0EOtXKysrC9u3bUVZWpuycO3fuRPfu3TFkyBAsWrSIOceJDGDgpvCXlwc895yaFLW+mECnWg0bNkR6ejp27Nih5HxvvfUW05cSKcTATfaQlwds3y6Lw6jABDq1UjFc7k1fmpeXx/SlRAoxcJN9dOkC7NwJrF8PtGvnP1lOdZhAJyBGF6gxfSmRebgdjOyruBiYMgVYvhw4dEh+zeOp/rEJCRfntPPz2dP2crtlzoJdu2SmugYNgA4dUPq73yGlTRv8+OOPqF+/flCn9E1f+sorrzATGpFiDNwUGXyT5hw5Ahw9Kr/epAlwxRXRl0DHNyC73fL3IYQMzCUlslTq8ePy6w4HUFFx8blOJyAEttarBzFxIm4aMybgy37zwQd4fcAA3JKcjOuvvhqOhg2BDh2AUaOi53dPZDIGbqJI4nLJGuZr1sjRh3PndJ/KA8DjcCC2c2egadMLvfHLgrDbDUyZgrNLlyKuuBiapsHh+7HizcCWng7MnAn06aO7TUTEwE0UOaZNAx5/HCgvN+8a53vj6NcPGDQIWLECWLkSoqICAa84qF8f+O1vgZtvZk+cSAcGbiK7c7mAe+8FPv005JcWQOABuypNkwd74kRBYeAmsrPCQuCRRwCFyVIs07EjMH++TLpDRDXidjAiuyosBMaOjYygDcgRgx495M9FRDVij5vIjl56CfjjH2ve/mZnCQkyUx732RNVi4GbyG4KC4HRo4HKSqtbYp6kJGDzZu63J6oGh8qJ7MQ7PB7JQRuQ+8wLCqxuBVFYYo+byC5cLiArSwa1aJCYCBw8yO1iRFWwx01kFwUFQGmp1a0IHSFk9jciugQDN5EduN0yG1o0DZCVlckUtkR0CQZuIjtYtCgyV5D7s3+/1S0gCjsM3ER2sGuXobzjtvXFF1a3gCjsMHAT2YHbbXULrHH8uKz8RkQXMHAT2YG3TGm00TQuUCOqgoGbyA6iaVGaLyG4QI2oCgZuIjuI5r3Mx45Z3QKisMLATWQHqalWt8A6jRpZ3QKisMLATWQHHTrI+d5o43AA7dtb3QqisMKUp0R24HYDzZpF315uhwM4fDi6pwqIqoi1ugFEFIDUVKB5c+D7761uSWi1aRNY0Ha75erzXbuAkhKgQQM5SjFqFIM+RRz2uInsYvRoYPZsq1sRMgKAtn49cNttNT/I5ZI53Neskf8+e/bi95xOuSq9Xz8gPx/IzDS1vUShwjluIrt44omomecWAH7SNPx961a4a0o+U1goq6UtXy4Dtm/QBmRBlrNn5fezsuTjiSIAAzeRXaSmyqHjKKAB8CxYALfbjdatWyMvLw9fffXVxQcUFgKPPipLnPobNBRCPu7RRxm8KSJwqJzITtatA/r2tboV5mvWDPjxRwDAkSNHMHv2bMydOxe9evXC5OxstH3oIX11yZOSgM2bgS5dFDeYKHQYuInspl07YM8eq1thrmrmtk+dOoUFCxbg2okTcVtpKWL0nFfTgJwc4I03lDSTyAoM3ER243IBXbta3QrzZGQAO3dW/z23G6JVK2hV57ODkZgIHDzI1eZkW5zjJrKbzExg/HirW2GOuDhg/vyav79oEQwvz2PhErI57uMmsqNnnpG9xldftbol6jgcwKxZtc8/79p1+erxYJWWhlfhEu5BpyAxcBPZ1X/+A7RqBUybFhnVw8aNA/Lyan9MSYmaa4WqcEltQfm772reg/7mm8CkSdyDTtXiHDeR3RUVAQMHAj/9ZHVL9ImJkVu1pk71/9gRI4AlSwxfsig9HT88/TRuvPFGJCcnGz7fZfwlhikvlzdbHk/tN12aJh8/fbr/mxqKGpzjJrK7Ll3k1qm777a6JcFzOoF//COwoA3I3mpioqFLVsbH43TTpjg6fjw2NGuG9+rVw4fXXIOPhw3DoU8+MXRuAIElhqmoACoruQeddGGPmyiSTJwIPPts+BcjiY2VowT5+cHtqXa75fSA0XluTZOHz++pzOGA8HiwyenE9l690CInBzfddBNat24NLdCMdb6JYVTjHnQ6j4GbKNIUFgJjx8qeXbhp1EgOdz/xhP6FV4MHy96sSR9dQtNQEReHlzMyMPnIEZw5cwY33ngjevbsiZtuugkdO3ZEbGw1y4NcLtnTNiNoA9yDThcwcBNFoqIiOcf61ltyWNZCAkAFgH25uWi/eLHxE5odIL2SkoDp0/F9dja2bt2KLVu2YOvWrfjhhx/QvXv3C4G8a9euSExMNP2GAgD3oBMABm6iyFZcDEyZIgPKDz+EfvV5fDyQnY2dffsi+8knsXv3bjRq1Mj4Figzh6R9VTM8ffToUWzbtu1CMN+7dy+y2rTBso8/RlxlpbntcTqByZPlCnyKWgzcRNGiuFgGS5dLHm63OYGvXj2Z2e3224GRIy8E4oceegjNfvgBj8fEqCnD6Q3epaXm3ZAEMDx96tQp/PjII7hq0SLEhWJ0IzcXUDFyQbbFwE0UzbzB/LPP5N5mpxM4dEjuMT58WAYu316kpskgWb++7CXHxsrh23btZKD1CdRVlT73HMTYsUgE4FC1Bco7JbB6tXyeGfP6gQxPK9qmFpDsbGDlytBci8ISE7AQRbOUlJqHXasG9UaNgPbtaw3ONSoshPPxxwPrGftugQJqD95dusjesG9bDx8GNm5Ut7LemyK1tuFpVYlhAtGokf7nMktbRGCPm4jMZWQxmZ4tUNOmyaxjRreM+fI3PB2qHrfeOW5/CWGCmaLwxRsBSzABCxGZq6BA/xB2aal8fjBU5DOvyl+KVAWJYQIihBzxCEYgCWHOnpXfz8oKLNGLyyVX0bdqJW+SliwBVq2S/33ySaBlS/l9lyu4tlJAGLiJyDxut+zl6R3YE0LOXxcXB/4cM4at/Q1PBxtMdfAA+DY9HV+VlCDggVLf1feqsrSZcSNAQWHgJiLzqCifGWwZzgYNjF/Tl9Mp5/Zrk5oqh5oDzbCmQ2V8PBY0bYqsrCy0aNECw4cPx7x587B///7qA7nLpW/LnDd4FxVd/JrbLacgunYFHn5Y7Y0ABY2Bm4jMY0UZTtXD1oEOT+fnyyBvhqQkxD3/PKasWYPvv/8eW7ZswS233IL3338ft956K6688koMGzYMc+fOxb59+2QgVzFF4Tsk/sQT8t/BLvqr7kaADOHiNCIyz4ABcu7TqEC2QHkXSn30EbBsmZpV5cGmGVWdGCaArXFCCHz33XfYtGkTNm/ejE2bNqHumTP4+OefEW/kdxAbK4+yMuP75Kv+HrmozRhBRGSW4cOFkB/7xo7c3Jqv8dFHQuTkCJGYKA8V1/MeSUlCuFzB/cxz5sjnaZr/8zscQsTGCuF0Xvp1p1P+LIMHB399IcTPEyeK8rg4tb8Lo0diohDr1tX8t/L+zDk58m9KNeI+biIyT4cOspdlYLjck5AAR01zzGZmTzufqzzoalx5eXJLVU2JYbzbr/r3l8PrrVqp2y9/XuPvv5c1v8NJRYUcOamoqP5v5f0dLV8OrFvHGuS14FA5EZlHQRnOcgAP/Pa3uOvxx3H77bfD4Ti/NMfsEpoqAofKJDbBUDVFYSVVf4MIxMBNROYyWDVLaBo8mgZ3TAwOxcSgXvv2uOr66xG/eLH6FKd664SHm1CmYDUTa5BXi4GbiMxlQhnOCgAxAAxvvoqJkTcUzZsDd95prE54ODEje5wVWIO8WgzcRGS+UJXhDJTDAQwZAqSny39//XVkrW5WMEURNliD/DIM3EQUGsOGAa++anUrpIQE4De/kQEbUJe7O5wYnKIIG6xBfhkmYCEi8xUWyr3V4aKsDNizJ7JTdpqZECaUgk3AEwUYuInIXN7Um2VlVrckOHZP2ZmZKVdlJyVZ3RLj/BV5iTIM3ERkroKC8Jnb1sPOKTvz8i4GbxPzqJvOSA3yCMTATUTm8VYHszs95UXDRV6e3FKVkyMXeoVy+Dw2FoiLM3aOQIq8RBkGbiIyj4rqYOFAT3nRcNKli9xSdfCgXOiVmyu3wJmpXTvg7bflljsj9NQgj3AM3ERkHhXVwcJFsOVFw1FKilydvXgx0KmTeddJSADefRfo08dYuVNNk6lhuRXsEgzcRGSekhKrW6BOpK1uVl233EvTgDvuuBhsjaxudzrl8+kSDNxEZB6zgoNVIml1s+q65V5Vg63e1e16i7xEAQZuIjKPWcHBKpG0utmMeeOagm0wq9s1jQVG/GDgJiLzRNKiokhb3Zyaamz+uaqEhNqDrb/V7U6n/HpOjnwcg3aNmPKUiMwVKak3IzFntqoCMBkZwPz5gQ9rW1XuNEIwcBORuUyoDmaJwYMjs0qVkQIwcXHAU08xj3iIcaiciMwVCak3I3l1s57sarGx8kZm+3YGbQuwx01EoeHt2ZWWBjdsrmmyZ3funHltq43DAcyeHflzrkVFMjvc6tXyd15aevF7kVq33KYYuIkodGoLDl516wLdugG3335xcZt3PvTdd4FDh0LZYmDCBGDq1NBe00qcfw57DNxEFHp6g8OAAcCqVaFpY0yMHCGIpqBNthBrdQOIKAp5U28GKxQJXTRNriCfMSPyh8fJlrg4jYjsQ0VCF4dD9qZr20e8ZQuDNoUtDpUTkX243UCrVsYKlyQmAh9/LIfcOY9LNsTATUT2YpaLY9EAAAEzSURBVCShi6bJHnUk7semqMHATUT2YiShS1KSTKfJwhVkY5zjJiJ7YbUpinJcVU5E9uNdOBZIQhdNkwvPWG2KIgSHyonIvmpL6OJ0yoDev79MV8qeNkUIBm4isj9m+6IowsBNRERkI1ycRkREZCMM3ERERDbCwE1ERGQjDNxEREQ2wsBNRERkIwzcRERENsLATUREZCMM3ERERDbCwE1ERGQjDNxEREQ2wsBNRERkIwzcRERENsLATUREZCMM3ERERDbCwE1ERGQjDNxEREQ2wsBNRERkIwzcRERENsLATUREZCMM3ERERDbCwE1ERGQjDNxEREQ2wsBNRERkIwzcRERENsLATUREZCMM3ERERDbCwE1ERGQjDNxEREQ2wsBNRERkIwzcRERENsLATUREZCP/Hyo5hIQXfXOUAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nx.draw_spring(graph)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Save the graph to disk in the `gexf` format, readable by gephi and other tools that manipulate graphs. You may now explore the graph using gephi and compare the visualizations." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "nx.write_gexf(graph, 'tree_of_life.gexf')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 2 }