Earth Microbiome Project Case Study - Notebook

Contents

Earth Microbiome Project Case Study - Notebook#

Open In Colab

This notebook is an end-to-end demo of the Vuegen Python package, starting from content generation. This sofwtare automates the creation of reports based on a directory with plots, dataframes, and other files in different formats. A YAML configuration file is generated from the directory to define the structure of the report. Users can customize the report by modifying the configuration file, or they can create their own configuration file instead of passing a directory as input.

The configuration file specifies the structure of the report, including sections, subsections, and various components such as plots, dataframes, markdown, html, and API calls. Reports can be generated in various formats, including documents (PDF, HTML, DOCX, ODT), presentations (PPTX, Reveal.js), notebooks (Jupyter) or Streamlit web applications.

An overview of the VueGen workflow is shown in the figure below:

Vuegen graphical abstarct

About the data#

The Earth Microbiome Project (EMP) is a systematic attempt to characterize global microbial taxonomic and functional diversity for the benefit of the planet and humankind. It aimed to sample the Earth’s microbial communities at an unprecedented scale in order to advance our understanding of the organizing biogeographic principles that govern microbial community structure. The EMP dataset is generated from samples that individual researchers have compiled and contributed to the EMP. The result is both a reference database giving global context to DNA sequence data and a framework for incorporating data from future studies, fostering increasingly complete characterization of Earth’s microbial diversity.

The data and scripts for this project are available on the EMP GitHub repository, and addtional details can be found in the original article by Thompson et al. (2017).

Notebook structure#

First, we will set up the work environment by installing the necessary packages and importing the required libraries. Then, we will create various plots and tables on the exploratory data analysis, metagenomics, and network analysis sections. Next, we will create a report using Vuegen, including the plots and tables generated in the previous sections. Finally, we will extend the report by modifying the configuration file to include additional components.

  1. Work environment setup

  2. Exploratory data analysis

  3. Metagenomics

  4. Network analysis

  5. Report generation

  6. Extending the report

Credits and Contributors#

0. Work environment setup and helper functions#

0.1. Installing libraries and creating global variables for platform and working directory#

To run this notebook locally, you should create a virtual environment with the required libraries. If you are running this notebook on Google Colab, everything should be set.

# Vuegen library
%pip install vuegen

Hide code cell output

Requirement already satisfied: vuegen in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (0.6.0.post1.dev0+1a42fa3)
Requirement already satisfied: altair[save] in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (6.0.0)
Requirement already satisfied: dataframe-image<0.3.0,>=0.2.6 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (0.2.7)
Requirement already satisfied: itables<3.0.0,>=2.2.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (2.7.0)
Requirement already satisfied: kaleido<0.3.0,>=0.2.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (0.2.1)
Requirement already satisfied: matplotlib<4.0.0,>=3.9.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (3.10.8)
Requirement already satisfied: nbclient<0.11.0,>=0.10.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (0.10.4)
Requirement already satisfied: nbformat<6.0.0,>=5.10.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (5.10.4)
Requirement already satisfied: openpyxl<4.0.0,>=3.1.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (3.1.5)
Requirement already satisfied: pandas<3.0.0,>=2.2.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pandas[parquet]<3.0.0,>=2.2.2->vuegen) (2.3.3)
Requirement already satisfied: plotly<6.0.0,>=5.15.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (5.24.1)
Requirement already satisfied: pyvis<0.4.0,>=0.3.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (0.3.2)
Requirement already satisfied: pyyaml<7.0.0,>=6.0.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (6.0.3)
Requirement already satisfied: quarto-cli in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (1.8.27)
Requirement already satisfied: streamlit<2.0.0,>=1.39.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (1.54.0)
Requirement already satisfied: streamlit-aggrid in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (1.2.1.post2)
Requirement already satisfied: vl-convert-python<2.0.0,>=1.7.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (1.9.0.post1)
Requirement already satisfied: xlrd<3.0.0,>=2.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from vuegen) (2.0.2)
Requirement already satisfied: nbconvert>=5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (7.17.0)
Requirement already satisfied: aiohttp>=3.10.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (3.13.3)
Requirement already satisfied: requests in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (2.32.5)
Requirement already satisfied: pillow in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (12.1.0)
Requirement already satisfied: packaging in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (26.0)
Requirement already satisfied: mistune in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (3.2.0)
Requirement already satisfied: lxml in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (6.0.2)
Requirement already satisfied: beautifulsoup4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (4.14.3)
Requirement already satisfied: cssutils in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (2.11.1)
Requirement already satisfied: playwright in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (1.58.0)
Requirement already satisfied: cssselect in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from dataframe-image<0.3.0,>=0.2.6->vuegen) (1.4.0)
Requirement already satisfied: contourpy>=1.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (4.61.1)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (1.4.9)
Requirement already satisfied: numpy>=1.23 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (2.4.2)
Requirement already satisfied: pyparsing>=3 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (3.3.2)
Requirement already satisfied: python-dateutil>=2.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib<4.0.0,>=3.9.2->vuegen) (2.9.0.post0)
Requirement already satisfied: jupyter-client>=6.1.12 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbclient<0.11.0,>=0.10.0->vuegen) (8.8.0)
Requirement already satisfied: jupyter-core!=5.0.*,>=4.12 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbclient<0.11.0,>=0.10.0->vuegen) (5.9.1)
Requirement already satisfied: traitlets>=5.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbclient<0.11.0,>=0.10.0->vuegen) (5.14.3)
Requirement already satisfied: fastjsonschema>=2.15 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbformat<6.0.0,>=5.10.4->vuegen) (2.21.2)
Requirement already satisfied: jsonschema>=2.6 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbformat<6.0.0,>=5.10.4->vuegen) (4.26.0)
Requirement already satisfied: et-xmlfile in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from openpyxl<4.0.0,>=3.1.5->vuegen) (2.0.0)
Requirement already satisfied: pytz>=2020.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pandas<3.0.0,>=2.2.2->pandas[parquet]<3.0.0,>=2.2.2->vuegen) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pandas<3.0.0,>=2.2.2->pandas[parquet]<3.0.0,>=2.2.2->vuegen) (2025.3)
Requirement already satisfied: pyarrow>=10.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pandas[parquet]<3.0.0,>=2.2.2->vuegen) (23.0.0)
Requirement already satisfied: tenacity>=6.2.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from plotly<6.0.0,>=5.15.0->vuegen) (9.1.4)
Requirement already satisfied: ipython>=5.3.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pyvis<0.4.0,>=0.3.2->vuegen) (9.10.0)
Requirement already satisfied: jinja2>=2.9.6 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pyvis<0.4.0,>=0.3.2->vuegen) (3.1.6)
Requirement already satisfied: jsonpickle>=1.4.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pyvis<0.4.0,>=0.3.2->vuegen) (4.1.1)
Requirement already satisfied: networkx>=1.11 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pyvis<0.4.0,>=0.3.2->vuegen) (3.6.1)
Requirement already satisfied: blinker<2,>=1.5.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (1.9.0)
Requirement already satisfied: cachetools<7,>=5.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (6.2.6)
Requirement already satisfied: click<9,>=7.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (8.3.1)
Requirement already satisfied: gitpython!=3.1.19,<4,>=3.0.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (3.1.46)
Requirement already satisfied: pydeck<1,>=0.8.0b4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (0.9.1)
Requirement already satisfied: protobuf<7,>=3.20 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (6.33.5)
Requirement already satisfied: toml<2,>=0.10.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (0.10.2)
Requirement already satisfied: tornado!=6.5.0,<7,>=6.0.3 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (6.5.4)
Requirement already satisfied: typing-extensions<5,>=4.10.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (4.15.0)
Requirement already satisfied: watchdog<7,>=2.1.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit<2.0.0,>=1.39.0->vuegen) (6.0.0)
Requirement already satisfied: narwhals>=1.27.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from altair[save]->vuegen) (2.16.0)
Requirement already satisfied: gitdb<5,>=4.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from gitpython!=3.1.19,<4,>=3.0.7->streamlit<2.0.0,>=1.39.0->vuegen) (4.0.12)
Requirement already satisfied: smmap<6,>=3.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from gitdb<5,>=4.0.1->gitpython!=3.1.19,<4,>=3.0.7->streamlit<2.0.0,>=1.39.0->vuegen) (5.0.2)
Requirement already satisfied: charset_normalizer<4,>=2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from requests->dataframe-image<0.3.0,>=0.2.6->vuegen) (3.4.4)
Requirement already satisfied: idna<4,>=2.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from requests->dataframe-image<0.3.0,>=0.2.6->vuegen) (3.11)
Requirement already satisfied: urllib3<3,>=1.21.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from requests->dataframe-image<0.3.0,>=0.2.6->vuegen) (2.6.3)
Requirement already satisfied: certifi>=2017.4.17 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from requests->dataframe-image<0.3.0,>=0.2.6->vuegen) (2026.1.4)
Requirement already satisfied: aiohappyeyeballs>=2.5.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (2.6.1)
Requirement already satisfied: aiosignal>=1.4.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (1.4.0)
Requirement already satisfied: attrs>=17.3.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (25.4.0)
Requirement already satisfied: frozenlist>=1.1.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (1.8.0)
Requirement already satisfied: multidict<7.0,>=4.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (6.7.1)
Requirement already satisfied: propcache>=0.2.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (0.4.1)
Requirement already satisfied: yarl<2.0,>=1.17.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from aiohttp>=3.10.2->dataframe-image<0.3.0,>=0.2.6->vuegen) (1.22.0)
Requirement already satisfied: decorator>=4.3.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (5.2.1)
Requirement already satisfied: ipython-pygments-lexers>=1.0.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (1.1.1)
Requirement already satisfied: jedi>=0.18.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.19.2)
Requirement already satisfied: matplotlib-inline>=0.1.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.2.1)
Requirement already satisfied: pexpect>4.3 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (4.9.0)
Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (3.0.52)
Requirement already satisfied: pygments>=2.11.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (2.19.2)
Requirement already satisfied: stack_data>=0.6.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.6.3)
Requirement already satisfied: wcwidth in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.6.0)
Requirement already satisfied: parso<0.9.0,>=0.8.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jedi>=0.18.1->ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.8.6)
Requirement already satisfied: MarkupSafe>=2.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jinja2>=2.9.6->pyvis<0.4.0,>=0.3.2->vuegen) (3.0.3)
Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema>=2.6->nbformat<6.0.0,>=5.10.4->vuegen) (2025.9.1)
Requirement already satisfied: referencing>=0.28.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema>=2.6->nbformat<6.0.0,>=5.10.4->vuegen) (0.37.0)
Requirement already satisfied: rpds-py>=0.25.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema>=2.6->nbformat<6.0.0,>=5.10.4->vuegen) (0.30.0)
Requirement already satisfied: pyzmq>=25.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-client>=6.1.12->nbclient<0.11.0,>=0.10.0->vuegen) (27.1.0)
Requirement already satisfied: platformdirs>=2.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-core!=5.0.*,>=4.12->nbclient<0.11.0,>=0.10.0->vuegen) (4.5.1)
Requirement already satisfied: bleach!=5.0.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from bleach[css]!=5.0.0->nbconvert>=5->dataframe-image<0.3.0,>=0.2.6->vuegen) (6.3.0)
Requirement already satisfied: defusedxml in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbconvert>=5->dataframe-image<0.3.0,>=0.2.6->vuegen) (0.7.1)
Requirement already satisfied: jupyterlab-pygments in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbconvert>=5->dataframe-image<0.3.0,>=0.2.6->vuegen) (0.3.0)

Requirement already satisfied: pandocfilters>=1.4.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from nbconvert>=5->dataframe-image<0.3.0,>=0.2.6->vuegen) (1.5.1)
Requirement already satisfied: webencodings in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from bleach!=5.0.0->bleach[css]!=5.0.0->nbconvert>=5->dataframe-image<0.3.0,>=0.2.6->vuegen) (0.5.1)
Requirement already satisfied: tinycss2<1.5,>=1.1.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from bleach[css]!=5.0.0->nbconvert>=5->dataframe-image<0.3.0,>=0.2.6->vuegen) (1.4.0)
Requirement already satisfied: ptyprocess>=0.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pexpect>4.3->ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.7.0)
Requirement already satisfied: six>=1.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib<4.0.0,>=3.9.2->vuegen) (1.17.0)
Requirement already satisfied: executing>=1.2.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from stack_data>=0.6.0->ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (2.2.1)
Requirement already satisfied: asttokens>=2.1.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from stack_data>=0.6.0->ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (3.0.1)
Requirement already satisfied: pure-eval in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from stack_data>=0.6.0->ipython>=5.3.0->pyvis<0.4.0,>=0.3.2->vuegen) (0.2.3)
Requirement already satisfied: soupsieve>=1.6.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from beautifulsoup4->dataframe-image<0.3.0,>=0.2.6->vuegen) (2.8.3)
Requirement already satisfied: more-itertools in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from cssutils->dataframe-image<0.3.0,>=0.2.6->vuegen) (10.8.0)
Requirement already satisfied: pyee<14,>=13 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from playwright->dataframe-image<0.3.0,>=0.2.6->vuegen) (13.0.0)
Requirement already satisfied: greenlet<4.0.0,>=3.1.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from playwright->dataframe-image<0.3.0,>=0.2.6->vuegen) (3.3.1)
Requirement already satisfied: jupyter in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from quarto-cli->vuegen) (1.1.1)
Requirement already satisfied: wheel in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from quarto-cli->vuegen) (0.40.0)
Requirement already satisfied: notebook in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter->quarto-cli->vuegen) (7.5.3)
Requirement already satisfied: jupyter-console in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter->quarto-cli->vuegen) (6.6.3)
Requirement already satisfied: ipykernel in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter->quarto-cli->vuegen) (7.2.0)
Requirement already satisfied: ipywidgets in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter->quarto-cli->vuegen) (8.1.8)
Requirement already satisfied: jupyterlab in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter->quarto-cli->vuegen) (4.5.3)
Requirement already satisfied: comm>=0.1.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipykernel->jupyter->quarto-cli->vuegen) (0.2.3)
Requirement already satisfied: debugpy>=1.6.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipykernel->jupyter->quarto-cli->vuegen) (1.8.20)
Requirement already satisfied: nest-asyncio>=1.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipykernel->jupyter->quarto-cli->vuegen) (1.6.0)
Requirement already satisfied: psutil>=5.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipykernel->jupyter->quarto-cli->vuegen) (7.2.2)
Requirement already satisfied: widgetsnbextension~=4.0.14 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipywidgets->jupyter->quarto-cli->vuegen) (4.0.15)
Requirement already satisfied: jupyterlab_widgets~=3.0.15 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from ipywidgets->jupyter->quarto-cli->vuegen) (3.0.16)
Requirement already satisfied: async-lru>=1.0.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (2.1.0)
Requirement already satisfied: httpx<1,>=0.25.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (0.28.1)
Requirement already satisfied: jupyter-lsp>=2.0.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (2.3.0)
Requirement already satisfied: jupyter-server<3,>=2.4.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (2.17.0)
Requirement already satisfied: jupyterlab-server<3,>=2.28.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (2.28.0)
Requirement already satisfied: notebook-shim>=0.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (0.2.4)
Requirement already satisfied: setuptools>=41.1.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab->jupyter->quarto-cli->vuegen) (82.0.0)
Requirement already satisfied: anyio in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from httpx<1,>=0.25.0->jupyterlab->jupyter->quarto-cli->vuegen) (4.12.1)
Requirement already satisfied: httpcore==1.* in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from httpx<1,>=0.25.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.0.9)
Requirement already satisfied: h11>=0.16 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from httpcore==1.*->httpx<1,>=0.25.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.16.0)
Requirement already satisfied: argon2-cffi>=21.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (25.1.0)
Requirement already satisfied: jupyter-events>=0.11.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.12.0)
Requirement already satisfied: jupyter-server-terminals>=0.4.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.5.4)
Requirement already satisfied: overrides>=5.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (7.7.0)
Requirement already satisfied: prometheus-client>=0.9 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.24.1)
Requirement already satisfied: send2trash>=1.8.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (2.1.0)
Requirement already satisfied: terminado>=0.8.3 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.18.1)
Requirement already satisfied: websocket-client>=1.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.9.0)
Requirement already satisfied: babel>=2.10 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab-server<3,>=2.28.0->jupyterlab->jupyter->quarto-cli->vuegen) (2.18.0)
Requirement already satisfied: json5>=0.9.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyterlab-server<3,>=2.28.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.13.0)
Requirement already satisfied: argon2-cffi-bindings in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from argon2-cffi>=21.1->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (25.1.0)
Requirement already satisfied: python-json-logger>=2.0.4 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (4.0.0)
Requirement already satisfied: rfc3339-validator in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.1.4)
Requirement already satisfied: rfc3986-validator>=0.1.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (0.1.1)
Requirement already satisfied: fqdn in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.5.1)
Requirement already satisfied: isoduration in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (20.11.0)
Requirement already satisfied: jsonpointer>1.13 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (3.0.0)
Requirement already satisfied: rfc3987-syntax>=1.1.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.1.0)
Requirement already satisfied: uri-template in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.3.0)
Requirement already satisfied: webcolors>=24.6.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (25.10.0)
Requirement already satisfied: lark>=1.2.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from rfc3987-syntax>=1.1.0->jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.3.1)
Requirement already satisfied: cffi>=1.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from argon2-cffi-bindings->argon2-cffi>=21.1->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (2.0.0)
Requirement already satisfied: pycparser in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi>=21.1->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (3.0)
Requirement already satisfied: arrow>=0.15.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from isoduration->jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.4.0->jupyterlab->jupyter->quarto-cli->vuegen) (1.4.0)
Requirement already satisfied: python-decouple in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from streamlit-aggrid->vuegen) (3.8)
Note: you may need to restart the kernel to use updated packages.
# Libraries for the notebook
%pip install cartopy seaborn biom-format

Hide code cell output

Collecting cartopy
  Downloading cartopy-0.25.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.metadata (6.1 kB)
Collecting seaborn
  Downloading seaborn-0.13.2-py3-none-any.whl.metadata (5.4 kB)
Collecting biom-format
  Downloading biom_format-2.1.17-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)
Requirement already satisfied: numpy>=1.23 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from cartopy) (2.4.2)
Requirement already satisfied: matplotlib>=3.6 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from cartopy) (3.10.8)
Collecting shapely>=2.0 (from cartopy)
  Downloading shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (6.8 kB)
Requirement already satisfied: packaging>=21 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from cartopy) (26.0)
Collecting pyshp>=2.3 (from cartopy)
  Downloading pyshp-3.0.3-py3-none-any.whl.metadata (65 kB)
Collecting pyproj>=3.3.1 (from cartopy)
  Downloading pyproj-3.7.2-cp311-cp311-manylinux_2_28_x86_64.whl.metadata (31 kB)
Requirement already satisfied: pandas>=1.2 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from seaborn) (2.3.3)
Requirement already satisfied: click in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from biom-format) (8.3.1)
Collecting scipy>=1.3.1 (from biom-format)
  Downloading scipy-1.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (62 kB)
Collecting h5py (from biom-format)
  Downloading h5py-3.15.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (3.0 kB)
Requirement already satisfied: contourpy>=1.0.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (4.61.1)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (1.4.9)
Requirement already satisfied: pillow>=8 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (12.1.0)
Requirement already satisfied: pyparsing>=3 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (3.3.2)
Requirement already satisfied: python-dateutil>=2.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from matplotlib>=3.6->cartopy) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pandas>=1.2->seaborn) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pandas>=1.2->seaborn) (2025.3)
Requirement already satisfied: certifi in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from pyproj>=3.3.1->cartopy) (2026.1.4)
Requirement already satisfied: six>=1.5 in /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib>=3.6->cartopy) (1.17.0)
Downloading cartopy-0.25.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (11.8 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/11.8 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.8/11.8 MB 146.6 MB/s  0:00:00
?25hDownloading seaborn-0.13.2-py3-none-any.whl (294 kB)
Downloading biom_format-2.1.17-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.3 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/12.3 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.3/12.3 MB 127.0 MB/s  0:00:00
?25hDownloading pyproj-3.7.2-cp311-cp311-manylinux_2_28_x86_64.whl (9.5 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/9.5 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9.5/9.5 MB 171.8 MB/s  0:00:00
?25h
Downloading pyshp-3.0.3-py3-none-any.whl (58 kB)
Downloading scipy-1.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (35.1 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/35.1 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 35.1/35.1 MB 209.8 MB/s  0:00:00
?25h
Downloading shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (3.1 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.1/3.1 MB 176.4 MB/s  0:00:00
?25hDownloading h5py-3.15.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (4.7 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/4.7 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.7/4.7 MB 173.9 MB/s  0:00:00
?25h
Installing collected packages: shapely, scipy, pyshp, pyproj, h5py, seaborn, cartopy, biom-format
?25l
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0/8 [shapely]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/8 [scipy]
   ━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━ 3/8 [pyproj]
   ━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━ 4/8 [h5py]
   ━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━ 4/8 [h5py]
   ━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━ 5/8 [seaborn]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━ 6/8 [cartopy]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━ 6/8 [cartopy]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━ 6/8 [cartopy]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━ 7/8 [biom-format]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━ 7/8 [biom-format]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8/8 [biom-format]
Successfully installed biom-format-2.1.17 cartopy-0.25.0 h5py-3.15.1 pyproj-3.7.2 pyshp-3.0.3 scipy-1.17.0 seaborn-0.13.2 shapely-2.1.2
Note: you may need to restart the kernel to use updated packages.

Hide code cell content

import os

IN_COLAB = "COLAB_GPU" in os.environ

Hide code cell content

# Optional library to launch a streamlit app from colab
if IN_COLAB:
    !npm install localtunnel

Hide code cell content

# Output directory
base_output_dir = "./example_data/Earth_microbiome_vuegen_demo_notebook/"

0.2. Importing libraries#

Hide code cell content

# Imports
import os
import yaml
import requests

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import plotly.graph_objects as go
import plotly.express as px
import altair as alt
import seaborn as sns

import biom
import networkx as nx

from vuegen import report_generator
from vuegen.utils import get_logger, load_yaml_config

if IN_COLAB:
    import urllib

0.3. Creating working directory#

Hide code cell content

os.makedirs(base_output_dir, exist_ok=True)

0.4. Markdown project description#

Create a markdown file with the project description to be displayed in the main page of the report. It is also possible to do this for the sections and subsections of the report by creating a description.md file in the corresponding directory.

Hide code cell content

# Create project description
project_description = """
The Earth Microbiome Project (EMP) is a systematic attempt to characterize global microbial taxonomic and functional diversity for the benefit of the planet and humankind. 
It aimed to sample the Earth’s microbial communities at an unprecedented scale in order to advance our understanding of the organizing biogeographic principles that govern microbial community structure. 
The EMP dataset is generated from samples that individual researchers have compiled and contributed to the EMP. 
The result is both a reference database giving global context to DNA sequence data and a framework for incorporating data from future studies, fostering increasingly complete characterization of Earth’s microbial diversity.

You can find more information about the Earth Microbiome Project at https://earthmicrobiome.org/ and in the [original article](https://www.nature.com/articles/nature24621).
"""

# Write the description to a file
with open(os.path.join(base_output_dir, "description.md"), "w") as file:
    file.write(project_description)

0.5. Helper functions#

Hide code cell content

def get_empo_cat_color(empocat=None, returndict=False):
    """returns standard empo colors for EMP figures
    input:
    empocat- empo category name (string)
    returndict-  the user needs the dictionary mapping category to color (boolean)

    output: either a color for passed empocat or the dictionay if returndict=True"""

    # hex codes for matplotlib colors are described here:
    # https://github.com/matplotlib/matplotlib/blob/cf83cd5642506ef808853648b9eb409f8dbd6ff3/lib/matplotlib/_color_data.py

    empo_cat_color = {
        "EMP sample": "#929591",  # 'grey'
        "Host-associated": "#fb9a99",
        "Free-living": "#e31a1c",
        "Animal": "#b2df8a",
        "Plant": "#33a02c",
        "Non-saline": "#a6cee3",
        "Saline": "#1f78b4",
        "Aerosol (non-saline)": "#d3d3d3",  # 'lightgrey'
        "Animal corpus": "#ffff00",  # 'yellow'
        "Animal distal gut": "#8b4513",  # 'saddlebrown'
        "Animal proximal gut": "#d2b48c",  # 'tan'
        "Animal secretion": "#f4a460",  # 'sandybrown'
        "Animal surface": "#b8860b",  # 'darkgoldenrod'
        "Hypersaline (saline)": "#87cefa",  # 'lightskyblue'
        "Intertidal (saline)": "#afeeee",  # 'paleturquoise'
        "Mock community": "#ff00ff",  # 'fuchsia'
        "Plant corpus": "#7cfc00",  # 'lawngreen'
        "Plant rhizosphere": "#006400",  # 'darkgreen'
        "Plant surface": "#00fa9a",  # 'mediumspringgreen'
        "Sediment (non-saline)": "#ffa07a",  # 'lightsalmon'
        "Sediment (saline)": "#ff6347",  # 'tomato'
        "Soil (non-saline)": "#ff0000",  # 'red'
        "Sterile water blank": "#ee82ee",  # 'violet'
        "Surface (non-saline)": "#000000",  # 'black'
        "Surface (saline)": "#696969",  # 'dimgrey'
        "Water (non-saline)": "#000080",  # 'navy'
        "Water (saline)": "#4169e1",  # 'royalblue'
    }

    if returndict == True:
        return empo_cat_color
    else:
        return empo_cat_color[empocat]

1. Exploratory data analysis#

1.1. Global scope of sample provenance#

Samples come from 7 continents, 43 countries, 21 biomes (ENVO), 92 environmental features (ENVO), and 17 environments (EMPO).

1.1.1. Load data and create section and subsection directories#

Hide code cell content

# Create the output directory for the EDA section and sample provenance subsection
sample_prov_output_dir = os.path.join(
    base_output_dir, "1_Exploratory_data_analysis/1_sample_exploration/"
)
os.makedirs(sample_prov_output_dir, exist_ok=True)

# Load data and filter out control samples
metadata_mapping = "https://raw.githubusercontent.com//biocore/emp/master/data/mapping-files/emp_qiime_mapping_release1.tsv"
metadata_mapping_df = pd.read_table(metadata_mapping, index_col=0)
metadata_mapping_df = metadata_mapping_df[metadata_mapping_df["empo_1"] != "Control"]

1.1.2. Random subset of the metadata dataframe#

Hide code cell content

# Obtain a random sample of the metadata df with a random seed
sample_metadata_mapping_df = metadata_mapping_df.sample(100, random_state=42)

# Export the sample df as a CSV file
sample_metadata_mapping_df.to_csv(
    f"{sample_prov_output_dir}/1_metadata_random_subset.csv"
)

1.1.3. Static map with matplotlib#

Hide code cell source

# Extract Animal dataset
animal_df = metadata_mapping_df[metadata_mapping_df["empo_2"] == "Animal"]

# Unique subcategories in empo_3
animal_empo3 = animal_df["empo_3"].unique()

# Create a figure with Cartopy map projection
fig, ax = plt.subplots(
    figsize=(12, 8), dpi=300, subplot_kw={"projection": ccrs.PlateCarree()}
)

# Add features to the map
ax.add_feature(cfeature.BORDERS, edgecolor="white", linewidth=0.5)
ax.add_feature(cfeature.LAND, edgecolor="white", facecolor="lightgray", linewidth=0.5)
ax.add_feature(cfeature.COASTLINE, edgecolor="white", linewidth=0.5)

# Set extent (global map)
ax.set_extent([-180, 180, -90, 90])

# Plot each subcategory with a unique color (unfilled circles with borders)
for empo3 in animal_empo3:
    subset = animal_df[animal_df["empo_3"] == empo3]
    color = get_empo_cat_color(empo3)  # Get color for category
    ax.scatter(
        subset["longitude_deg"],
        subset["latitude_deg"],
        color="none",
        edgecolors=color,
        linewidth=1.5,
        label=empo3,
        s=40,
        transform=ccrs.PlateCarree(),
        zorder=2,
    )

# Add legend with updated labels
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels, loc="lower center", ncol=2, fontsize=10)

# Save the figure
animal_map_out_path = os.path.join(sample_prov_output_dir, "2_animal_samples_map.png")
plt.savefig(animal_map_out_path, dpi=300, bbox_inches="tight")
/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages/cartopy/io/__init__.py:242: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/110m_physical/ne_110m_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages/cartopy/io/__init__.py:242: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_admin_0_boundary_lines_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages/cartopy/io/__init__.py:242: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/110m_physical/ne_110m_coastline.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)

1.1.4. Interactive map with plotly#

Hide code cell source

# Extract Plant dataset
plant_df = metadata_mapping_df[metadata_mapping_df["empo_2"] == "Plant"]

# Unique subcategories in empo_3
plant_empo3 = plant_df["empo_3"].unique()

# Create a base map figure
fig = go.Figure()

# Plot each subcategory with unique color (unfilled circles with borders)
for empo3 in plant_empo3:
    subset = plant_df[plant_df["empo_3"] == empo3]
    color = get_empo_cat_color(empo3)  # Get color for category

    fig.add_trace(
        go.Scattergeo(
            lon=subset["longitude_deg"],
            lat=subset["latitude_deg"],
            mode="markers",
            marker=dict(
                symbol="circle-open",  # Unfilled circle
                color=color,
                size=6,  # Marker size
                line=dict(
                    width=1.5, color=color
                ),  # Border color matches category color
            ),
            name=empo3,
        )
    )

# Update map layout (fixes horizontal blank space)
fig.update_layout(
    geo=dict(
        landcolor="rgb(217, 217, 217)",  # Light gray land color
        showcountries=True,  # Enable country borders
        countrycolor="white",  # Set country borders to white
        countrywidth=0.5,  # Border thickness
        coastlinecolor="white",
        fitbounds="locations",  # Focuses only on data points
        lataxis=dict(range=[-60, 85], showgrid=False),  # Custom latitude range
        lonaxis=dict(range=[-180, 180], showgrid=False),  # Custom longitude range
    ),
    autosize=False,
    width=800,  # Adjust width to remove blank space
    height=600,  # Keep a balanced height
    margin=dict(l=10, r=10, t=10, b=10),  # Reduce margins to keep map centered
    legend=dict(
        title="",
        font=dict(size=16),  # Legend font size
        x=0.5,  # Center legend horizontally
        xanchor="center",
        yanchor="top",
        orientation="h",  # Horizontal legend layout
    ),
)

# Save the figure as SVG and JSON
# plant_map_out_path = os.path.join(sample_prov_output_dir, "2_plant_samples_map.svg")
# fig.write_image(plant_map_out_path, scale=2)

plant_map_json_path = os.path.join(sample_prov_output_dir, "3_plant_samples_map.json")
fig.write_json(plant_map_json_path)

# Show the figure
fig.show(renderer="svg")
_images/ec9a68bf4995961b7eefae1ae43edc4f422d9769e0879b675166f0335165c524.svg

1.1.5. Interactive map with Altair#

Hide code cell source

# Extract Saline dataset
saline_df = metadata_mapping_df[metadata_mapping_df["empo_2"] == "Saline"].copy()

# Create a dictionary for simplified category names for the legend
simplified_category_names = {
    "Water (saline)": "Water",
    "Sediment (saline)": "Sediment",
    "Surface (saline)": "Surface",
    "Hypersaline (saline)": "Hypersaline",
}

# Simplify the empo_3 names in the DataFrame for legend
saline_df["simplified_empo_3"] = saline_df["empo_3"].apply(
    lambda x: simplified_category_names.get(x, x)
)

# Apply the get_empo_cat_color function to generate the color column
saline_df["color"] = saline_df["empo_3"].apply(get_empo_cat_color)

# Create the base world map (use the CDN URL or a different base map if you prefer)
countries = alt.topo_feature(
    "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json", "countries"
)

# Create a background map of countries
background_map = (
    alt.Chart(countries)
    .mark_geoshape(fill="lightgray", stroke="white")
    .project("equirectangular")
    .properties(width=800, height=400)
)

# Create the points for saline samples with custom colors
saline_points = (
    alt.Chart(saline_df)
    .mark_point(
        size=50,
        shape="circle",
        filled=False,
    )
    .encode(
        longitude="longitude_deg:Q",
        latitude="latitude_deg:Q",
        color=alt.Color(
            "simplified_empo_3:N",
            scale=alt.Scale(
                domain=list(saline_df["simplified_empo_3"].unique()),
                range=[get_empo_cat_color(cat) for cat in saline_df["empo_3"].unique()],
            ),
            legend=alt.Legend(
                title="", orient="bottom", symbolSize=120, labelFontSize=16
            ),
        ),
        tooltip=["latitude_deg", "longitude_deg", "empo_3"],
    )
)

# Overlay the points on the world map
map_with_points = background_map + saline_points

# Save as JSON and
saline_json_path = os.path.join(sample_prov_output_dir, "4_saline_samples_map.json")
with open(saline_json_path, "w") as f:
    f.write(map_with_points.to_json())

# saline_png_path = os.path.join(sample_prov_output_dir, "5_saline_samples_map.png")
# map_with_points.save(saline_png_path)

# Display the map
map_with_points

2. Metagenomics#

2.1. Alpha diversity#

The alpha diversity was measured as number of observed 90bp tag sequences (richness), in n = 23,828 biologically independent samples as a function of environment. Tag sequence counts were subsampled to 5,000 observations.

2.1.1. Load data and create section and subsection directories#

Hide code cell content

# Create the output directory for the metagenomics section and alpha diversity subsection
alpha_div_output_dir = os.path.join(base_output_dir, "2_Metagenomics/1_alpha_diversity")
os.makedirs(alpha_div_output_dir, exist_ok=True)

# Load data
mapping_qc_filt = "https://raw.githubusercontent.com//biocore/emp/master/data/mapping-files/emp_qiime_mapping_qc_filtered.tsv"
mapping_qc_filt_df = pd.read_csv(
    mapping_qc_filt, sep="\t", index_col=0, header=0
).sort_index()

Hide code cell content

# Define colors of host associated and free living categories
colorsHA = {
    "Animal corpus": get_empo_cat_color("Animal corpus"),
    "Plant corpus": get_empo_cat_color("Plant corpus"),
    "Animal secretion": get_empo_cat_color("Animal secretion"),
    "Plant surface": get_empo_cat_color("Plant surface"),
    "Animal proximal gut": get_empo_cat_color("Animal proximal gut"),
    "Animal surface": get_empo_cat_color("Animal surface"),
    "Animal distal gut": get_empo_cat_color("Animal distal gut"),
    "Plant rhizosphere": get_empo_cat_color("Plant rhizosphere"),
}

colorsFL = {
    "Water (saline)": get_empo_cat_color("Water (saline)"),
    "Aerosol (non-saline)": get_empo_cat_color("Aerosol (non-saline)"),
    "Hypersaline (saline)": get_empo_cat_color("Hypersaline (saline)"),
    "Surface (non-saline)": get_empo_cat_color("Surface (non-saline)"),
    "Surface (saline)": get_empo_cat_color("Surface (saline)"),
    "Water (non-saline)": get_empo_cat_color("Water (non-saline)"),
    "Sediment (saline)": get_empo_cat_color("Sediment (saline)"),
    "Soil (non-saline)": get_empo_cat_color("Soil (non-saline)"),
    "Sediment (non-saline)": get_empo_cat_color("Sediment (non-saline)"),
}

2.1.2. Static box plot with matplotlib#

Hide code cell source

# Ensure y variable is numeric to avoid aggregation errors
mapping_qc_filt_df["adiv_observed_otus"] = pd.to_numeric(
    mapping_qc_filt_df["adiv_observed_otus"], errors="coerce"
)

# Get valid categories (only ones in colorsHA)
valid_categories_HA = set(colorsHA.keys())

# Filter dataset to include only valid categories
filtered_data_HA = mapping_qc_filt_df[
    (mapping_qc_filt_df["empo_0"] == "EMP sample")
    & (mapping_qc_filt_df["empo_3"].isin(valid_categories_HA))
]

# Compute sorted order (only for valid categories)
sorted_order = (
    filtered_data_HA.groupby(["empo_3"])["adiv_observed_otus"]
    .mean()
    .dropna()
    .sort_values()
    .index.tolist()
)

# Create palette dictionary using only valid categories
palette_dict = {cat: colorsHA[cat] for cat in sorted_order}

# Create figure for Matplotlib
fig = plt.figure(figsize=(16, 8))

# Plot the boxplot and jitter plot
sns.boxplot(
    fliersize=0,
    x="empo_3",
    y="adiv_observed_otus",
    hue="empo_3",
    linewidth=1,
    data=filtered_data_HA,
    order=sorted_order,
    palette=palette_dict,
)
sns.stripplot(
    jitter=True,
    x="empo_3",
    y="adiv_observed_otus",
    data=filtered_data_HA,
    order=sorted_order,
    color="black",
    size=1,
)

# Customize the plot
plt.xticks(rotation=45, ha="right", fontsize=16)
plt.yticks(fontsize=16)
plt.xlabel("")
plt.ylim(0, 3000)
plt.ylabel("Observed tag sequences", fontsize=16)

# Add median line
median = filtered_data_HA["adiv_observed_otus"].median()
plt.axhline(y=median, xmin=0, xmax=1, color="y")

# Adjust layout and save the figure
plt.tight_layout()
fig.patch.set_alpha(0.0)

# Ensure directory exists before saving
os.makedirs(alpha_div_output_dir, exist_ok=True)

# Save figure
alpha_div_box_plot_host_ass = os.path.join(
    alpha_div_output_dir, "1_alpha_diversity_host_associated_samples.png"
)
plt.savefig(alpha_div_box_plot_host_ass, dpi=300, bbox_inches="tight")

2.1.3. Interactive box plot with plotly#

Hide code cell source

# Ensure y variable is numeric to avoid aggregation errors
mapping_qc_filt_df["adiv_observed_otus"] = pd.to_numeric(
    mapping_qc_filt_df["adiv_observed_otus"], errors="coerce"
)

# Get valid free-living categories (only ones in colorsFL)
valid_categories_FL = list(colorsFL.keys())

# Filter dataset to include only valid free-living categories
filtered_data_FL = mapping_qc_filt_df[
    (mapping_qc_filt_df["empo_0"] == "EMP sample")
    & (mapping_qc_filt_df["empo_3"].isin(valid_categories_FL))
]

# Compute sorted order (only for valid categories)
sorted_order_FL = (
    filtered_data_FL.groupby(["empo_3"])["adiv_observed_otus"]
    .mean()
    .dropna()
    .sort_values()
    .index.tolist()
)

# Create the Plotly figure using boxplot and stripplot (jittered points)
fig = px.box(
    filtered_data_FL,
    x="empo_3",
    y="adiv_observed_otus",
    color="empo_3",
    category_orders={"empo_3": sorted_order_FL},
    color_discrete_map=colorsFL,
    labels={"adiv_observed_otus": "Observed tag sequences"},
    points=False,
)

# Add jittered points (strip plot)
fig.add_trace(
    px.strip(
        filtered_data_FL, x="empo_3", y="adiv_observed_otus", stripmode="overlay"
    ).data[0]
)

# Modify the dot color and size directly inside the add_trace()
fig.data[-1].update(marker=dict(color="black", size=1, opacity=0.7))

# Add median line
median = filtered_data_FL["adiv_observed_otus"].median()
fig.add_hline(y=median, line=dict(color="yellow"))

# Customize the plot
fig.update_layout(
    xaxis_title="",
    yaxis_title="Observed tag sequences",
    xaxis_tickangle=-45,
    plot_bgcolor="rgba(0,0,0,0)",
    showlegend=False,
    height=600,
    font=dict(size=14),
)

# Save figure as JSON
alpha_div_box_plot_free_living_json = os.path.join(
    alpha_div_output_dir, "2_alpha_diversity_free_living_samples.json"
)
fig.write_json(alpha_div_box_plot_free_living_json)

# Save figure as PNG
# alpha_div_box_plot_free_living_png = os.path.join(alpha_div_output_dir, "3_alpha_div_box_plot_free_living.png")
# fig.write_image(alpha_div_box_plot_free_living_png, width=800, height=600, scale=2)

# Show the plot
fig.show(renderer="png")
_images/d12a74d691af219a096580b34a28c19bebf7004db04d7c878441049f452be995.png

2.2. Gene average copy number 16S rRNA#

The average copy number of the 16S rRNA gene was measured in n = 23,828 biologically independent samples as a function of environment.

2.2.1. Load data and create section and subsection directories#

Hide code cell content

# Create the output directory for the metagenomics section and average copy number subsection
avg_copy_numb_dir = os.path.join(
    base_output_dir, "2_Metagenomics/2_average_copy_number"
)
os.makedirs(avg_copy_numb_dir, exist_ok=True)

# Load data
emp_gg_otus_sampsum = "https://raw.githubusercontent.com//biocore/emp/master/data/predicted-rrna-copy-number/emp_cr_gg_13_8.qc_filtered_filt_summary_samplesum.txt"
emp_gg_otus_sampsum_df = pd.read_csv(
    emp_gg_otus_sampsum, sep="\t", index_col=0, header=None
).sort_index()
emp_gg_otus_norm_sampsum = "https://raw.githubusercontent.com//biocore/emp/master/data/predicted-rrna-copy-number/emp_cr_gg_13_8.normalized_qcfilt_summary_samplesum.txt"
emp_gg_otus_norm_sampsum_df = pd.read_csv(
    emp_gg_otus_norm_sampsum, sep="\t", index_col=0, header=None
).sort_index()

Hide code cell content

# Create a new df by copying mapping_qc_filt_df
mapping_qc_filt_merged_df = mapping_qc_filt_df.copy()

# Merge new mapping df with emp_gg_otus_sampsum and emp_gg_otus_norm_sampsum
mapping_qc_filt_merged_df["sampsum"] = emp_gg_otus_sampsum_df[1]
mapping_qc_filt_merged_df["normsampsum"] = emp_gg_otus_norm_sampsum_df[1]
mapping_qc_filt_merged_df["copynumberdepletion"] = np.divide(
    emp_gg_otus_norm_sampsum_df[1], emp_gg_otus_sampsum_df[1]
)
mapping_qc_filt_merged_df["averagecopy"] = np.divide(
    1, np.divide(emp_gg_otus_norm_sampsum_df[1], emp_gg_otus_sampsum_df[1])
)

2.2.2. Static plot with matplotlib#

Hide code cell source

plt.figure(figsize=(10, 6))

for i in ["Animal", "Non-saline", "Plant", "Saline"]:
    plt.hist(
        mapping_qc_filt_merged_df[mapping_qc_filt_merged_df.empo_2 == i][
            "averagecopy"
        ].dropna(),
        label=i,
        bins=200,
        linewidth=0,
        color=get_empo_cat_color(i),
        alpha=0.8,
    )

# Customize axes: remove top and right borders
plt.gca().spines["top"].set_visible(False)
plt.gca().spines["right"].set_visible(False)

# Titles and labels
plt.legend(loc=1, prop={"size": 9}, frameon=False)
plt.xlabel("Predicted average community 16S copy number", fontsize=12)
plt.ylabel("Number of samples", fontsize=12)
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.xlim([0, 8])
plt.tight_layout()

# Save the figure
avg_copy_numb_empo2 = os.path.join(
    avg_copy_numb_dir, "1_average_copy_number_emp_ontology_level2.png"
)
plt.savefig(avg_copy_numb_empo2, dpi=300, bbox_inches="tight")

2.2.3. Interactive plot with plotly#

Hide code cell source

# Create a list to store histogram traces
hist_traces = []

# Loop through unique categories in 'empo_3'
for i in mapping_qc_filt_merged_df.empo_3.dropna().unique():
    hist_traces.append(
        go.Histogram(
            x=mapping_qc_filt_merged_df[mapping_qc_filt_merged_df.empo_3 == i][
                "averagecopy"
            ].dropna(),
            name=i,  # Legend name
            marker=dict(color=get_empo_cat_color(i)),  # Assign color
            opacity=0.5,
            nbinsx=200,  # Number of bins
        )
    )

# Create the figure
fig = go.Figure(hist_traces)

# Update layout to remove top and right borders
fig.update_layout(
    xaxis_title="Predicted average community 16S copy number",
    yaxis_title="Number of samples",
    xaxis=dict(
        range=[0, 8],
        tickfont=dict(size=10),
        showline=True,
        linewidth=1,
        linecolor="black",
        mirror=False,
        showgrid=False,
        zeroline=False,
    ),
    yaxis=dict(
        tickfont=dict(size=10),
        showline=True,
        linewidth=1,
        linecolor="black",
        mirror=False,
        showgrid=False,
        zeroline=False,
    ),
    barmode="overlay",
    showlegend=True,
    legend=dict(font=dict(size=11), borderwidth=0),
    plot_bgcolor="white",
)
# Save the figure as JSON
avg_copy_numb_empo3_json = os.path.join(
    avg_copy_numb_dir, "2_average_copy_number_emp_ontology_level3.json"
)
fig.write_json(avg_copy_numb_empo3_json)

# Save the figure as PNG
# avg_copy_numb_empo3_png = os.path.join(avg_copy_numb_dir, "3_avg_copy_numb_empo3.png")
# fig.write_image(avg_copy_numb_empo3_png, scale=2)

# Show the figure
fig.show(renderer="png")
_images/46df19ae039fd953d682749ff6f7e37a8b826d3dd20ab504886e8d06f8450e0b.png

2.3. Nestedness#

2.3.1. Load the data and create section and subsection directories#

Hide code cell content

# Create the output directory for the metagenomics section and nestedness subsection
nestedness_dir = os.path.join(base_output_dir, "2_Metagenomics/3_nestedness")
os.makedirs(nestedness_dir, exist_ok=True)

# Load data
nest_phylum_allsamples = "https://raw.githubusercontent.com//biocore/emp/master/data/nestedness/nest_phylum_allsamples.csv"
nest_phylum_allsamples_df = pd.read_csv(nest_phylum_allsamples)
nest_phylum_animalsamples = "https://raw.githubusercontent.com//biocore/emp/master/data/nestedness/nest_phylum_Animal.csv"
nest_phylum_animalsamples_df = pd.read_csv(nest_phylum_animalsamples)
nest_phylum_plantsamples = "https://raw.githubusercontent.com//biocore/emp/master/data/nestedness/nest_phylum_Plant.csv"
nest_phylum_plantsamples_df = pd.read_csv(nest_phylum_plantsamples)
nest_phylum_nonsalinesamples = "https://raw.githubusercontent.com//biocore/emp/master/data/nestedness/nest_phylum_Non-saline.csv"
nest_phylum_nonsalinesamples_df = pd.read_csv(nest_phylum_nonsalinesamples)

2.3.2. Random subset of the nestedness dataframe#

Hide code cell content

# Obtain a randome sample of the nestedness df for all samples
sample_nest_phylum_allsamples_df = nest_phylum_allsamples_df.sample(
    100, random_state=42
)

# Export the sample df as a CSV file
sample_nest_phylum_allsamples_df.to_csv(
    f"{nestedness_dir}/1_nestedness_random_subset.csv"
)

2.3.3. Interactive plots with plotly#

Hide code cell source

# Determine axis limits
xmax = nest_phylum_allsamples_df.SAMPLE_RANK.max()
ymax = nest_phylum_allsamples_df.OBSERVATION_RANK.max()

# Get colors for each empo_3 category
nest_phylum_allsamples_df["color"] = nest_phylum_allsamples_df["empo_3"].apply(
    get_empo_cat_color
)

# Create the scatter plot
fig = px.scatter(
    nest_phylum_allsamples_df,
    x="SAMPLE_RANK",
    y="OBSERVATION_RANK",
    color="empo_3",
    color_discrete_map={
        empo: get_empo_cat_color(empo)
        for empo in nest_phylum_allsamples_df["empo_3"].unique()
    },
    labels={
        "SAMPLE_RANK": "All samples (sorted by richness)",
        "OBSERVATION_RANK": "Phyla (sorted by prevalence)",
    },
    template="plotly_white",
)

# Customize layout
fig.update_traces(marker=dict(symbol="line-ns-open", size=10))  # "|" marker equivalent
fig.update_layout(
    width=1200,  # Increase width for a wider plot
    height=600,  # Adjust height if needed
    xaxis=dict(range=[0, xmax + 1], title_font=dict(size=20), tickfont=dict(size=18)),
    yaxis=dict(range=[0, ymax + 0.8], title_font=dict(size=20), tickfont=dict(size=18)),
    showlegend=False,
)

# Save the figure as an interactive HTML file
os.makedirs(nestedness_dir, exist_ok=True)
nest_phylum_allsamples_path = os.path.join(nestedness_dir, "2_all_samples.json")
fig.write_json(nest_phylum_allsamples_path)

# Show the figure
fig.show(renderer="png")
_images/4ae8ba5b10aa8ab8831bfcdad1097e24027a3689faef61384ee9d3202d2e5cc5.png

Hide code cell content

# Determine axis limits
xmax = nest_phylum_plantsamples_df.SAMPLE_RANK.max()
ymax = nest_phylum_plantsamples_df.OBSERVATION_RANK.max()

# Get colors for each empo_3 category
nest_phylum_plantsamples_df["color"] = nest_phylum_plantsamples_df["empo_3"].apply(
    get_empo_cat_color
)

# Create the scatter plot
fig = px.scatter(
    nest_phylum_plantsamples_df,
    x="SAMPLE_RANK",
    y="OBSERVATION_RANK",
    color="empo_3",
    color_discrete_map={
        empo: get_empo_cat_color(empo)
        for empo in nest_phylum_plantsamples_df["empo_3"].unique()
    },
    labels={
        "SAMPLE_RANK": "Plant samples (sorted by richness)",
        "OBSERVATION_RANK": "Phyla (sorted by prevalence)",
    },
    template="plotly_white",
)

# Customize layout
fig.update_traces(marker=dict(symbol="line-ns-open", size=10))  # "|" marker equivalent
fig.update_layout(
    width=1200,  # Increase width for a wider plot
    height=600,  # Adjust height if needed
    xaxis=dict(range=[0, xmax + 1], title_font=dict(size=20), tickfont=dict(size=18)),
    yaxis=dict(range=[0, ymax + 0.8], title_font=dict(size=20), tickfont=dict(size=18)),
    legend=dict(
        orientation="h",  # Horizontal legend
        yanchor="top",
        y=-0.2,  # Moves the legend below the x-axis
        xanchor="center",
        x=0.5,  # Centers the legend
        font=dict(size=16),
    ),
    legend_title_text="",
)

# Save the figure as an interactive HTML file
os.makedirs(nestedness_dir, exist_ok=True)
nest_phylum_plantsamples_path = os.path.join(nestedness_dir, "3_plant_samples.json")
fig.write_json(nest_phylum_plantsamples_path)

# Show the figure
fig.show(renderer="png")
_images/0a679d299fe879a14d8a1b4c5a63826592fcd4c903f80049b46eb21a0451a40d.png

2.3.4. Static plots with matplotlib#

Hide code cell source

# Determine axis limits
xmax = nest_phylum_animalsamples_df.SAMPLE_RANK.max()
ymax = nest_phylum_animalsamples_df.OBSERVATION_RANK.max()

# Create the figure and axis
fig, ax = plt.subplots(figsize=(500 / 30, 80 / 12.7))  # Adjust size as needed

# Store legend handles and labels
legend_handles = []
legend_labels = []

# Plot data
for empo3 in np.sort(nest_phylum_animalsamples_df.empo_3.unique()):
    color = get_empo_cat_color(empo3)
    scatter = ax.scatter(
        nest_phylum_animalsamples_df[
            nest_phylum_animalsamples_df.empo_3 == empo3
        ].SAMPLE_RANK,
        nest_phylum_animalsamples_df[
            nest_phylum_animalsamples_df.empo_3 == empo3
        ].OBSERVATION_RANK,
        marker="|",
        linewidths=2,
        label=empo3,
        color=color,
    )
    legend_handles.append(scatter)
    legend_labels.append(empo3)

# Customize labels and appearance
ax.set_xlabel("Animal samples (sorted by richness)", fontsize=20)
ax.set_ylabel("Phyla (sorted by prevalence)", fontsize=20)
ax.tick_params(axis="both", which="major", labelsize=18)

# Add legend
ax.legend(
    handles=legend_handles,
    labels=legend_labels,
    loc="upper center",
    bbox_to_anchor=(0.5, -0.2),  # Moves legend below x-axis
    ncol=3,
    fontsize=16,
    frameon=False,
    scatterpoints=1,
    handletextpad=0.5,
)

# Increase space at the bottom so the legend is not cut off
plt.subplots_adjust(bottom=0.25)

ax.set_xlim([0, xmax + 1])
ax.set_ylim([0, ymax + 0.8])

plt.tight_layout()
fig.patch.set_alpha(0.0)

# Save the figure
os.makedirs(nestedness_dir, exist_ok=True)
nest_phylum_animalsamples_path = os.path.join(nestedness_dir, "4_animal_samples.png")
plt.savefig(nest_phylum_animalsamples_path, dpi=300, bbox_inches="tight")

Hide code cell source

# Determine axis limits
xmax = nest_phylum_nonsalinesamples_df.SAMPLE_RANK.max()
ymax = nest_phylum_nonsalinesamples_df.OBSERVATION_RANK.max()

# Create the figure and axis
fig, ax = plt.subplots(figsize=(500 / 30, 80 / 12.7))  # Adjust size as needed

# Store legend handles and labels
legend_handles = []
legend_labels = []

# Plot data
for empo3 in np.sort(nest_phylum_nonsalinesamples_df.empo_3.unique()):
    color = get_empo_cat_color(empo3)
    scatter = ax.scatter(
        nest_phylum_nonsalinesamples_df[
            nest_phylum_nonsalinesamples_df.empo_3 == empo3
        ].SAMPLE_RANK,
        nest_phylum_nonsalinesamples_df[
            nest_phylum_nonsalinesamples_df.empo_3 == empo3
        ].OBSERVATION_RANK,
        marker="|",
        linewidths=2,
        label=empo3,
        color=color,
    )
    legend_handles.append(scatter)
    legend_labels.append(empo3)

# Customize labels and appearance
ax.set_xlabel("Non saline samples (sorted by richness)", fontsize=20)
ax.set_ylabel("Phyla (sorted by prevalence)", fontsize=20)
ax.tick_params(axis="both", which="major", labelsize=18)

# Add legend
ax.legend(
    handles=legend_handles,
    labels=legend_labels,
    loc="upper center",
    bbox_to_anchor=(0.5, -0.2),  # Moves legend below x-axis
    ncol=3,
    fontsize=16,
    frameon=False,
    scatterpoints=1,
    handletextpad=0.5,
)

# Increase space at the bottom so the legend is not cut off
plt.subplots_adjust(bottom=0.25)

ax.set_xlim([0, xmax + 1])
ax.set_ylim([0, ymax + 0.8])

plt.tight_layout()
fig.patch.set_alpha(0.0)

# Save the figure
os.makedirs(nestedness_dir, exist_ok=True)
nest_phylum_nonsalinesamples_path = os.path.join(
    nestedness_dir, "5_non_saline_samples.png"
)
plt.savefig(nest_phylum_nonsalinesamples_path, dpi=300, bbox_inches="tight")

3. Network analysis#

3.1. Phyla association networks#

3.1.1 Load data and create section and subsection directories#

Hide code cell content

# Create the output directory for the network analysis section and microbial networks subsection
network_dir = os.path.join(
    base_output_dir, "3_Network_analysis/1_phyla_association_networks"
)
os.makedirs(network_dir, exist_ok=True)

# Load OTU counts table
otu_counts = "https://raw.githubusercontent.com//biocore/emp/master/data/biom-tables/emp_deblur_100bp.subset_2k.rare_5000.biom"

# Download the file and save it as a binary file
response = requests.get(otu_counts)
with open(
    "example_data/Earth_microbiome_vuegen_demo_notebook/emp_deblur_100bp.subset_2k.rare_5000.biom",
    "wb",
) as f:
    f.write(response.content)

# Load the BIOM file and convert it to a DataFrame
otu_counts_table = biom.load_table(
    "example_data/Earth_microbiome_vuegen_demo_notebook/emp_deblur_100bp.subset_2k.rare_5000.biom"
)

Hide code cell content

# Collapse the table to the phylum level
phylum_idx = 1
collapse_f = lambda id_, md: "; ".join(md["taxonomy"][: phylum_idx + 1])
phyla_table = otu_counts_table.collapse(collapse_f, axis="observation")

# Convert the collapsed table to a DataFrame
phyla_counts_df = phyla_table.to_dataframe()

3.1.2. Clean data and export a subset of the counts table#

Hide code cell content

# Clean the index (which contains Phylum names) by removing unnecessary parts
phyla_counts_df.index = (
    phyla_counts_df.index.str.split(";").str[-1].str.replace("p__", "", regex=False)
)

# Remove special characters like [] and unnecessary spaces
phyla_counts_df.index = (
    phyla_counts_df.index.str.replace("[", "", regex=False)
    .str.replace("]", "", regex=False)
    .str.strip()
)

# Remove rows where the index only has 'k__' and 'Unclassified'
phyla_counts_df = phyla_counts_df[~(phyla_counts_df.index == "Unclassified")]
phyla_counts_df = phyla_counts_df[~phyla_counts_df.index.str.contains("k__")]

# Remove duplicaye rows
phyla_counts_df = phyla_counts_df[~phyla_counts_df.index.duplicated(keep="first")]

Hide code cell content

# Obtain a randome sample of the columns of the phyla counts df
sample_phyla_counts_df = phyla_counts_df.sample(50, axis=1)

# Export the sample df as a CSV file
sample_phyla_counts_df.to_csv(f"{network_dir}/1_phyla_counts_subset.csv")

3.1.3. Phyla association network edge list#

Hide code cell content

# Compute correlation matrix with absolute values
phyla_corr_matrix = phyla_counts_df.T.corr().abs()

# Create a binary adjacency matrix using a threshold
threshold = 0.5
phyla_corr_matrix_binary = phyla_corr_matrix > threshold

# Set diagonal values to 0
np.fill_diagonal(phyla_corr_matrix_binary.values, 0)

Hide code cell content

# Create a graph from the binary matrix
G = nx.Graph()

# Add nodes (Phyla)
phyla = phyla_corr_matrix_binary.index.tolist()
G.add_nodes_from(phyla)

# Add edges where binary_matrix == 1
for i in range(len(phyla)):
    for j in range(i + 1, len(phyla)):  # Avoid duplicate edges
        if phyla_corr_matrix_binary.iloc[i, j] == 1:
            G.add_edge(phyla[i], phyla[j])

# Remove singleton nodes (nodes with no edges)
G.remove_nodes_from(list(nx.isolates(G)))

# Export network as an edge list in CSV format, the "edge_list" word should be in the file name to be
# recognized as an edge list file
edge_list = nx.to_pandas_edgelist(G)
edge_list.to_csv(
    os.path.join(
        network_dir, "2_phyla_correlation_network_with_0.5_threshold_edgelist.csv"
    ),
    index=False,
)

3.1.4. Phyla association network static plot#

Hide code cell source

# Draw the network
plt.figure(figsize=(8, 6))
pos = nx.kamada_kawai_layout(G)  # Layout for better visualization
nx.draw(
    G,
    pos,
    with_labels=True,
    node_size=500,
    node_color="lightblue",
    edgecolors="black",
    linewidths=0.3,
    font_size=10,
)

# Export the figure as a PNG file
network_path = os.path.join(
    network_dir, "3_phyla_correlation_network_with_0.5_threshold.png"
)
plt.savefig(network_path, dpi=300, bbox_inches="tight")

4. Report generation#

To generate different report types, just modify the report_type variable. The available types are:

  • streamlit

  • html

  • pdf

  • docx

  • odt

  • revealjs

  • pptx

  • jupyter

4.1. Streamlit report#

To launch the Streamlit web application from Colab, open the generated URL and copy the localtunnel entry point IP into the corresponding field on the opened page. Once submited, you will be redirected to your Streamlit web application.

# Generate the report
report_type = "streamlit"
_ = report_generator.get_report(
    dir_path=base_output_dir, report_type=report_type, logger=None
)

Hide code cell output

[2026-02-10 13:06:49,162] vuegen: INFO - Path to log file: logs/2026-02-10_13-06-49_report.log
[2026-02-10 13:06:49,234] vuegen: ERROR - Unsupported file extension: .yaml. Skipping file: example_data/Earth_microbiome_vuegen_demo_notebook/Earth_microbiome_vuegen_demo_notebook_config.yaml
[2026-02-10 13:06:49,236] vuegen: ERROR - Unsupported file extension: .biom. Skipping file: example_data/Earth_microbiome_vuegen_demo_notebook/emp_deblur_100bp.subset_2k.rare_5000.biom
[2026-02-10 13:06:49,249] vuegen: INFO - Configuration file generated at earth_microbiome_vuegen_demo_notebook_config.yaml
[2026-02-10 13:06:49,267] vuegen: INFO - Report 'Earth Microbiome Vuegen Demo Notebook' initialized with 3 sections.
[2026-02-10 13:06:49,269] vuegen: INFO - running in a normal Python process
[2026-02-10 13:06:49,271] vuegen: DEBUG - Generating 'streamlit' report in directory: 'streamlit_report/sections'
[2026-02-10 13:06:49,272] vuegen: INFO - Output directory already existed: 'streamlit_report/sections'
[2026-02-10 13:06:49,273] vuegen: INFO - Output directory for static content already existed: 'streamlit_report/static'
[2026-02-10 13:06:49,274] vuegen: DEBUG - Processing app navigation code.
[2026-02-10 13:06:49,275] vuegen: DEBUG - Processing home section.
[2026-02-10 13:06:49,277] vuegen: DEBUG - Home directory already existed: streamlit_report/sections/Home
[2026-02-10 13:06:49,278] vuegen: INFO - Home page content written to 'streamlit_report/sections/Home/Homepage.py'.
[2026-02-10 13:06:49,280] vuegen: INFO - Home page added to the report manager content.
[2026-02-10 13:06:49,281] vuegen: DEBUG - Created section directory: streamlit_report/sections/Exploratory_Data_Analysis
[2026-02-10 13:06:49,282] vuegen: DEBUG - Created section directory: streamlit_report/sections/Metagenomics
[2026-02-10 13:06:49,285] vuegen: DEBUG - Created section directory: streamlit_report/sections/Network_Analysis
[2026-02-10 13:06:49,285] vuegen: INFO - Created app navigation script: report_manager.py
[2026-02-10 13:06:49,287] vuegen: INFO - Starting to generate sections for the report.
[2026-02-10 13:06:49,289] vuegen: DEBUG - Processing section '1': 'Exploratory Data Analysis' - 1 subsection(s)
[2026-02-10 13:06:49,289] vuegen: DEBUG - Processing subsection '1': 'Sample Exploration' - 4 component(s)
[2026-02-10 13:06:49,291] vuegen: INFO - Successfully generated content for DataFrame: 'Metadata Random Subset'
[2026-02-10 13:06:49,294] vuegen: INFO - Successfully generated content for plot '1': 'Animal Samples Map'
[2026-02-10 13:06:49,295] vuegen: INFO - Successfully generated content for plot '2': 'Plant Samples Map'
[2026-02-10 13:06:49,297] vuegen: INFO - Successfully generated content for plot '3': 'Saline Samples Map'
[2026-02-10 13:06:49,298] vuegen: INFO - Generated content and imports for subsection: 'Sample Exploration'
[2026-02-10 13:06:49,300] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Exploratory_Data_Analysis/Sample_Exploration.py'
[2026-02-10 13:06:49,300] vuegen: DEBUG - Processing section '2': 'Metagenomics' - 3 subsection(s)
[2026-02-10 13:06:49,301] vuegen: DEBUG - Processing subsection '2': 'Alpha Diversity' - 2 component(s)
[2026-02-10 13:06:49,303] vuegen: INFO - Successfully generated content for plot '4': 'Alpha Diversity Host Associated Samples'
[2026-02-10 13:06:49,306] vuegen: INFO - Successfully generated content for plot '5': 'Alpha Diversity Free Living Samples'
[2026-02-10 13:06:49,306] vuegen: INFO - Generated content and imports for subsection: 'Alpha Diversity'
[2026-02-10 13:06:49,308] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Alpha_Diversity.py'
[2026-02-10 13:06:49,309] vuegen: DEBUG - Processing subsection '3': 'Average Copy Number' - 2 component(s)
[2026-02-10 13:06:49,310] vuegen: INFO - Successfully generated content for plot '6': 'Average Copy Number Emp Ontology Level2'
[2026-02-10 13:06:49,313] vuegen: INFO - Successfully generated content for plot '7': 'Average Copy Number Emp Ontology Level3'
[2026-02-10 13:06:49,313] vuegen: INFO - Generated content and imports for subsection: 'Average Copy Number'
[2026-02-10 13:06:49,315] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Average_Copy_Number.py'
[2026-02-10 13:06:49,316] vuegen: DEBUG - Processing subsection '4': 'Nestedness' - 5 component(s)
[2026-02-10 13:06:49,317] vuegen: INFO - Successfully generated content for DataFrame: 'Nestedness Random Subset'
[2026-02-10 13:06:49,320] vuegen: INFO - Successfully generated content for plot '8': 'All Samples'
[2026-02-10 13:06:49,320] vuegen: INFO - Successfully generated content for plot '9': 'Plant Samples'
[2026-02-10 13:06:49,323] vuegen: INFO - Successfully generated content for plot '10': 'Animal Samples'
[2026-02-10 13:06:49,323] vuegen: INFO - Successfully generated content for plot '11': 'Non Saline Samples'
[2026-02-10 13:06:49,326] vuegen: INFO - Generated content and imports for subsection: 'Nestedness'
[2026-02-10 13:06:49,326] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Nestedness.py'
[2026-02-10 13:06:49,328] vuegen: DEBUG - Processing section '3': 'Network Analysis' - 1 subsection(s)
[2026-02-10 13:06:49,329] vuegen: DEBUG - Processing subsection '5': 'Phyla Association Networks' - 3 component(s)
[2026-02-10 13:06:49,330] vuegen: INFO - Successfully generated content for DataFrame: 'Phyla Counts Subset'
[2026-02-10 13:06:49,335] vuegen: INFO - Successfully read network from file: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/example_data/Earth_microbiome_vuegen_demo_notebook/3_Network_analysis/1_phyla_association_networks/2_phyla_correlation_network_with_0.5_threshold_edgelist.csv.
[2026-02-10 13:06:49,336] vuegen: DEBUG - Try to save network as PyVis network: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/streamlit_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:06:49,356] vuegen: INFO - PyVis network created and saved as: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/streamlit_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:06:49,358] vuegen: INFO - Successfully generated content for plot '12': 'Phyla Correlation Network With 0.5 Threshold Edgelist'
[2026-02-10 13:06:49,359] vuegen: INFO - Successfully generated content for plot '13': 'Phyla Correlation Network With 0.5 Threshold'
[2026-02-10 13:06:49,361] vuegen: INFO - Generated content and imports for subsection: 'Phyla Association Networks'
[2026-02-10 13:06:49,362] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Network_Analysis/Phyla_Association_Networks.py'
[2026-02-10 13:06:49,364] vuegen: INFO - All the scripts to build the Streamlit app are available at streamlit_report/sections
[2026-02-10 13:06:49,365] vuegen: INFO - To run the Streamlit app, use the following command:
[2026-02-10 13:06:49,366] vuegen: INFO - streamlit run streamlit_report/sections/report_manager.py

All the scripts to build the Streamlit app are available at: streamlit_report/sections

To run the Streamlit app, use the following command:

	streamlit run streamlit_report/sections/report_manager.py
run_streamlit = False
# run_streamlit = True # uncomment line to run the streamlit report
# Launch the Streamlit report depneding on the platform
if not IN_COLAB and run_streamlit:
    !streamlit run streamlit_report/sections/report_manager.py
elif run_streamlit:
    # see: https://discuss.streamlit.io/t/how-to-launch-streamlit-app-from-google-colab-notebook/42399
    print(
        "Password/Enpoint IP for localtunnel is:",
        urllib.request.urlopen("https://ipv4.icanhazip.com")
        .read()
        .decode("utf8")
        .strip("\n"),
    )
    # Run the Streamlit app in the background
    !streamlit run streamlit_report/sections/report_manager.py --server.address=localhost &>/content/logs.txt &
    # Expose the Streamlit app on port 8501
    !npx localtunnel --port 8501 --subdomain vuegen-demo
else:
    print("Streamlit report not executed, set run_streamlit to True to run the report")

Hide code cell output

Streamlit report not executed, set run_streamlit to True to run the report

4.2. HTML and other report types#

# Generate the report
report_type = "html"
report_dir, config_path = report_generator.get_report(
    dir_path=base_output_dir, report_type=report_type, logger=None
)

Hide code cell output

[2026-02-10 13:06:49,387] vuegen: INFO - Path to log file: logs/2026-02-10_13-06-49_report.log
[2026-02-10 13:06:49,459] vuegen: ERROR - Unsupported file extension: .yaml. Skipping file: example_data/Earth_microbiome_vuegen_demo_notebook/Earth_microbiome_vuegen_demo_notebook_config.yaml
[2026-02-10 13:06:49,460] vuegen: ERROR - Unsupported file extension: .biom. Skipping file: example_data/Earth_microbiome_vuegen_demo_notebook/emp_deblur_100bp.subset_2k.rare_5000.biom
[2026-02-10 13:06:49,474] vuegen: INFO - Configuration file generated at earth_microbiome_vuegen_demo_notebook_config.yaml
[2026-02-10 13:06:49,492] vuegen: INFO - Report 'Earth Microbiome Vuegen Demo Notebook' initialized with 3 sections.
[2026-02-10 13:06:49,494] vuegen: INFO - running in a normal Python process
[2026-02-10 13:06:49,495] vuegen: DEBUG - env_vars (QuartoReport): environ({'READTHEDOCS_VIRTUALENV_PATH': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest', 'READTHEDOCS_CANONICAL_URL': 'https://vuegen.readthedocs.io/en/latest/', 'HOSTNAME': 'build-31350061-project-1135329-vuegen', 'READTHEDOCS_GIT_CLONE_URL': 'https://github.com/Multiomics-Analytics-Group/vuegen.git', 'HOME': '/home/docs', 'NO_COLOR': '1', 'READTHEDOCS': 'True', 'READTHEDOCS_PRODUCTION_DOMAIN': 'app.readthedocs.org', 'READTHEDOCS_REPOSITORY_PATH': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest', 'READTHEDOCS_PROJECT': 'vuegen', 'READTHEDOCS_OUTPUT': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/_readthedocs/', 'PATH': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/bin:/home/docs/.asdf/shims:/home/docs/.asdf/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', 'READTHEDOCS_VERSION_TYPE': 'branch', 'LANG': 'C.UTF-8', 'READTHEDOCS_LANGUAGE': 'en', 'DEBIAN_FRONTEND': 'noninteractive', 'READTHEDOCS_GIT_COMMIT_HASH': '1a42fa37f8f843f0111db72fc2c035c6f3ebb2de', 'READTHEDOCS_VERSION_NAME': 'latest', 'READTHEDOCS_VERSION': 'latest', 'PWD': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs', 'READTHEDOCS_GIT_IDENTIFIER': 'main', 'DOCUTILSCONFIG': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/docutils.conf', 'MPLBACKEND': 'Agg', 'JPY_PARENT_PID': '704', 'PYDEVD_USE_FRAME_EVAL': 'NO', 'TERM': 'xterm-color', 'CLICOLOR': '1', 'FORCE_COLOR': '1', 'CLICOLOR_FORCE': '1', 'PAGER': 'cat', 'GIT_PAGER': 'cat'})
[2026-02-10 13:06:49,496] vuegen: DEBUG - PATH: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/bin:/home/docs/.asdf/shims:/home/docs/.asdf/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[2026-02-10 13:06:49,497] vuegen: DEBUG - sys.path: ['/home/docs/.asdf/installs/python/3.11.12/lib/python311.zip', '/home/docs/.asdf/installs/python/3.11.12/lib/python3.11', '/home/docs/.asdf/installs/python/3.11.12/lib/python3.11/lib-dynload', '', '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages']
[2026-02-10 13:06:49,499] vuegen: DEBUG - Generating 'html' report in directory: '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report'
[2026-02-10 13:06:49,500] vuegen: DEBUG - Output directory already existed: '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report'
[2026-02-10 13:06:49,502] vuegen: INFO - Output directory for static content already existed: 'quarto_report/static'
[2026-02-10 13:06:49,503] vuegen: INFO - Starting to generate sections for the report.
[2026-02-10 13:06:49,505] vuegen: DEBUG - Processing section: 'Exploratory Data Analysis' - 1 subsection(s)
[2026-02-10 13:06:49,506] vuegen: DEBUG - Processing subsection: 'Sample Exploration' - 4 component(s)
[2026-02-10 13:06:49,507] vuegen: DEBUG - component_imports: ['import pandas as pd', 'from itables import show, init_notebook_mode', 'init_notebook_mode(all_interactive=True)']
[2026-02-10 13:06:49,508] vuegen: INFO - Successfully generated content for DataFrame: 'Metadata Random Subset'
[2026-02-10 13:06:49,510] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,511] vuegen: INFO - Successfully generated content for plot: 'Animal Samples Map'
[2026-02-10 13:06:49,513] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:06:49,514] vuegen: INFO - Successfully generated content for plot: 'Plant Samples Map'
[2026-02-10 13:06:49,516] vuegen: DEBUG - component_imports: ['import altair as alt', 'import requests', 'import json']
[2026-02-10 13:06:49,517] vuegen: INFO - Successfully generated content for plot: 'Saline Samples Map'
[2026-02-10 13:06:49,519] vuegen: INFO - Generated content and imports for subsection: 'Sample Exploration'
[2026-02-10 13:06:49,519] vuegen: DEBUG - Processing section: 'Metagenomics' - 3 subsection(s)
[2026-02-10 13:06:49,521] vuegen: DEBUG - Processing subsection: 'Alpha Diversity' - 2 component(s)
[2026-02-10 13:06:49,523] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,523] vuegen: INFO - Successfully generated content for plot: 'Alpha Diversity Host Associated Samples'
[2026-02-10 13:06:49,525] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:06:49,527] vuegen: INFO - Successfully generated content for plot: 'Alpha Diversity Free Living Samples'
[2026-02-10 13:06:49,527] vuegen: INFO - Generated content and imports for subsection: 'Alpha Diversity'
[2026-02-10 13:06:49,528] vuegen: DEBUG - Processing subsection: 'Average Copy Number' - 2 component(s)
[2026-02-10 13:06:49,530] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,532] vuegen: INFO - Successfully generated content for plot: 'Average Copy Number Emp Ontology Level2'
[2026-02-10 13:06:49,532] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:06:49,534] vuegen: INFO - Successfully generated content for plot: 'Average Copy Number Emp Ontology Level3'
[2026-02-10 13:06:49,536] vuegen: INFO - Generated content and imports for subsection: 'Average Copy Number'
[2026-02-10 13:06:49,536] vuegen: DEBUG - Processing subsection: 'Nestedness' - 5 component(s)
[2026-02-10 13:06:49,537] vuegen: DEBUG - component_imports: ['import pandas as pd', 'from itables import show, init_notebook_mode', 'init_notebook_mode(all_interactive=True)']
[2026-02-10 13:06:49,540] vuegen: INFO - Successfully generated content for DataFrame: 'Nestedness Random Subset'
[2026-02-10 13:06:49,541] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:06:49,542] vuegen: INFO - Successfully generated content for plot: 'All Samples'
[2026-02-10 13:06:49,544] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:06:49,545] vuegen: INFO - Successfully generated content for plot: 'Plant Samples'
[2026-02-10 13:06:49,547] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,547] vuegen: INFO - Successfully generated content for plot: 'Animal Samples'
[2026-02-10 13:06:49,549] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,551] vuegen: INFO - Successfully generated content for plot: 'Non Saline Samples'
[2026-02-10 13:06:49,552] vuegen: INFO - Generated content and imports for subsection: 'Nestedness'
[2026-02-10 13:06:49,553] vuegen: DEBUG - Processing section: 'Network Analysis' - 1 subsection(s)
[2026-02-10 13:06:49,554] vuegen: DEBUG - Processing subsection: 'Phyla Association Networks' - 3 component(s)
[2026-02-10 13:06:49,555] vuegen: DEBUG - component_imports: ['import pandas as pd', 'from itables import show, init_notebook_mode', 'init_notebook_mode(all_interactive=True)']
[2026-02-10 13:06:49,558] vuegen: INFO - Successfully generated content for DataFrame: 'Phyla Counts Subset'
[2026-02-10 13:06:49,558] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,561] vuegen: INFO - Successfully read network from file: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/example_data/Earth_microbiome_vuegen_demo_notebook/3_Network_analysis/1_phyla_association_networks/2_phyla_correlation_network_with_0.5_threshold_edgelist.csv.
[2026-02-10 13:06:49,564] vuegen: DEBUG - Try to save network as PyVis network: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:06:49,582] vuegen: INFO - PyVis network created and saved as: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:06:49,584] vuegen: INFO - Successfully generated content for plot: 'Phyla Correlation Network With 0.5 Threshold Edgelist'
[2026-02-10 13:06:49,584] vuegen: DEBUG - component_imports: []
[2026-02-10 13:06:49,587] vuegen: INFO - Successfully generated content for plot: 'Phyla Correlation Network With 0.5 Threshold'
[2026-02-10 13:06:49,587] vuegen: INFO - Generated content and imports for subsection: 'Phyla Association Networks'
[2026-02-10 13:06:49,589] vuegen: INFO - Created qmd script to render the app: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/quarto_report.qmd
[2026-02-10 13:06:49,591] vuegen: INFO - Running 'Earth Microbiome Vuegen Demo Notebook' 'html' report with ['quarto', 'render', '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/quarto_report.qmd']
[2026-02-10 13:07:21,018] vuegen: INFO - 'Earth Microbiome Vuegen Demo Notebook' 'html' report rendered
Starting python3 kernel...
Done

Executing 'quarto_report.quarto_ipynb'
  Cell 1/10: 'Imports'......................................
Done
  Cell 2/10: 'Metadata Random Subset 4'.....................Done
  Cell 3/10: 'Plant Samples Map 15'.........................
Done
  Cell 4/10: 'Saline Samples Map 16'........................
Done
  Cell 5/10: 'Alpha Diversity Free Living Samples 18'.......Done
  Cell 6/10: 'Average Copy Number Emp Ontology Level3 20'...
Done
  Cell 7/10: 'Nestedness Random Subset 5'...................Done
  Cell 8/10: 'All Samples 21'...............................
Done
  Cell 9/10: 'Plant Samples 22'.............................Done
  Cell 10/10: 'Phyla Counts Subset 6'........................Done
pandoc 
  to: html
  output-file: quarto_report.html
  standalone: true
  self-contained: true
  section-divs: true
  html-math-method: mathjax
  wrap: none
  default-image-extension: png
  toc: true
  toc-depth: 3
  variables: {}
  
metadata
  document-css: false
  link-citations: true
  date-format: long
  lang: en
  title: Earth Microbiome Vuegen Demo Notebook
  jupyter: python3
  toc-location: left
  page-layout: full
Output created: quarto_report.html

5. Extending the report#

Now, we will extend the report by modifying the configuration file to include a logo and graphica abstract in the main page, a descritption for a section and a subsection, and a new plot from a url. We are modifying this file from the notebook, but it is also possible to do it directly in the configuration file with a text editor.

5.1. Adding a logo and graphical abstract#

Hide code cell content

empo_logo_path = (
    "https://raw.githubusercontent.com/ElDeveloper/cogs220/master/emp-logo.svg"
)

# Load the YAML file
config = load_yaml_config(config_path)

# Update the logo and graphical abstract with the URL
config["report"].update({"logo": empo_logo_path, "graphical_abstract": empo_logo_path})

5.2. Including a description for a section and a subsection#

Hide code cell content

# Update the description for the EDA section
for section in config["sections"]:
    if section["title"] == "Exploratory Data Analysis":
        section["description"] = (
            "This section contains the exploratory data analysis of the Earth Microbiome Project (EMP) dataset."
        )

# Update the description for the alpha diversity subsection from the Metagenomics section
for section in config["sections"]:
    if section["title"] == "Metagenomics":
        for subsection in section["subsections"]:
            if subsection["title"] == "Alpha Diversity":
                subsection["description"] = (
                    "This subsection contains the alpha diversity analysis of the EMP dataset."
                )

5.3. Adding a new plot from a url#

Hide code cell content

# Define new plot with a URL as the file path
chem_prop_plot = {
    "title": "Physicochemical properties of the EMP samples",
    "file_path": "https://raw.githubusercontent.com/biocore/emp/master/methods/images/figureED1_physicochemical.png",
    "description": "",
    "caption": "Pairwise scatter plots of available physicochemical metadat are shown for temperature, salinity, oxygen, and pH, and for phosphate, nitrate, and ammonium",
    "component_type": "plot",
    "plot_type": "static",
}

# Add the plot to the Sample Provenance subsection in the EDA section
for section in config["sections"]:
    if section["title"] == "Exploratory Data Analysis":
        for subsection in section["subsections"]:
            if subsection["title"] == "Sample Exploration":
                subsection["components"].append(chem_prop_plot)

5.4. Creating a new subsection with a plot from a url#

Hide code cell content

# Define new plot with a URL as the file path
specif_seq_plot = {
    "title": "Specificity of sequences and higher taxonomic groups for environment",
    "file_path": "https://raw.githubusercontent.com/biocore/emp/master/methods/images/figure4_entropy.png",
    "description": "",
    "caption": "a) Environment distribution in all genera and 400 randomly chosen tag sequence. b) and c) Shannon entropy within each taxonomic group.",
    "component_type": "plot",
    "plot_type": "static",
}

# Define the new subsection for the Shannon entropy analysis
entropy_subsection = {
    "title": "Shanon entropy analysis",
    "description": "This subsection contains the Shannon entropy analysis of the EMP dataset.",
    "components": [specif_seq_plot],
}

# Add the new subsection to the Metagenomics section
for section in config["sections"]:
    if section["title"] == "Metagenomics":
        section["subsections"].append(entropy_subsection)

# Save the modified YAML file
with open(config_path, "w") as file:
    yaml.dump(config, file, default_flow_style=False)

5.5. Stremlit report with the extended configuration file#

To launch the Streamlit web application from Colab, open the generated URL and copy the localtunnel entry point IP into the corresponding field on the opened page. Once submited, you will be redirected to your Streamlit web application.

# Test the changes by generarating the report from the modified YAML file
report_type = "streamlit"
_ = report_generator.get_report(
    config_path=config_path, report_type=report_type, logger=None
)

Hide code cell output

[2026-02-10 13:07:21,086] vuegen: INFO - Path to log file: logs/2026-02-10_13-07-21_report.log
[2026-02-10 13:07:21,106] vuegen: INFO - Report 'Earth Microbiome Vuegen Demo Notebook' initialized with 3 sections.
[2026-02-10 13:07:21,108] vuegen: INFO - running in a normal Python process
[2026-02-10 13:07:21,108] vuegen: DEBUG - Generating 'streamlit' report in directory: 'streamlit_report/sections'
[2026-02-10 13:07:21,109] vuegen: INFO - Output directory already existed: 'streamlit_report/sections'
[2026-02-10 13:07:21,112] vuegen: INFO - Output directory for static content already existed: 'streamlit_report/static'
[2026-02-10 13:07:21,114] vuegen: DEBUG - Processing app navigation code.
[2026-02-10 13:07:21,114] vuegen: DEBUG - Processing home section.
[2026-02-10 13:07:21,116] vuegen: DEBUG - Home directory already existed: streamlit_report/sections/Home
[2026-02-10 13:07:21,117] vuegen: INFO - Home page content written to 'streamlit_report/sections/Home/Homepage.py'.
[2026-02-10 13:07:21,119] vuegen: INFO - Home page added to the report manager content.
[2026-02-10 13:07:21,119] vuegen: DEBUG - Section directory already existed: streamlit_report/sections/Exploratory_Data_Analysis
[2026-02-10 13:07:21,121] vuegen: DEBUG - Section directory already existed: streamlit_report/sections/Metagenomics
[2026-02-10 13:07:21,123] vuegen: DEBUG - Section directory already existed: streamlit_report/sections/Network_Analysis
[2026-02-10 13:07:21,124] vuegen: INFO - Created app navigation script: report_manager.py
[2026-02-10 13:07:21,125] vuegen: INFO - Starting to generate sections for the report.
[2026-02-10 13:07:21,127] vuegen: DEBUG - Processing section '7': 'Exploratory Data Analysis' - 1 subsection(s)
[2026-02-10 13:07:21,127] vuegen: DEBUG - Processing subsection '11': 'Sample Exploration' - 5 component(s)
[2026-02-10 13:07:21,129] vuegen: INFO - Successfully generated content for DataFrame: 'Metadata Random Subset'
[2026-02-10 13:07:21,132] vuegen: INFO - Successfully generated content for plot '27': 'Animal Samples Map'
[2026-02-10 13:07:21,132] vuegen: INFO - Successfully generated content for plot '28': 'Plant Samples Map'
[2026-02-10 13:07:21,135] vuegen: INFO - Successfully generated content for plot '29': 'Saline Samples Map'
[2026-02-10 13:07:21,135] vuegen: INFO - Successfully generated content for plot '30': 'Physicochemical properties of the EMP samples'
[2026-02-10 13:07:21,137] vuegen: INFO - Generated content and imports for subsection: 'Sample Exploration'
[2026-02-10 13:07:21,139] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Exploratory_Data_Analysis/Sample_Exploration.py'
[2026-02-10 13:07:21,139] vuegen: DEBUG - Processing section '8': 'Metagenomics' - 4 subsection(s)
[2026-02-10 13:07:21,140] vuegen: DEBUG - Processing subsection '12': 'Alpha Diversity' - 2 component(s)
[2026-02-10 13:07:21,142] vuegen: INFO - Successfully generated content for plot '31': 'Alpha Diversity Host Associated Samples'
[2026-02-10 13:07:21,144] vuegen: INFO - Successfully generated content for plot '32': 'Alpha Diversity Free Living Samples'
[2026-02-10 13:07:21,145] vuegen: INFO - Generated content and imports for subsection: 'Alpha Diversity'
[2026-02-10 13:07:21,146] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Alpha_Diversity.py'
[2026-02-10 13:07:21,148] vuegen: DEBUG - Processing subsection '13': 'Average Copy Number' - 2 component(s)
[2026-02-10 13:07:21,149] vuegen: INFO - Successfully generated content for plot '33': 'Average Copy Number Emp Ontology Level2'
[2026-02-10 13:07:21,151] vuegen: INFO - Successfully generated content for plot '34': 'Average Copy Number Emp Ontology Level3'
[2026-02-10 13:07:21,153] vuegen: INFO - Generated content and imports for subsection: 'Average Copy Number'
[2026-02-10 13:07:21,153] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Average_Copy_Number.py'
[2026-02-10 13:07:21,156] vuegen: DEBUG - Processing subsection '14': 'Nestedness' - 5 component(s)
[2026-02-10 13:07:21,157] vuegen: INFO - Successfully generated content for DataFrame: 'Nestedness Random Subset'
[2026-02-10 13:07:21,159] vuegen: INFO - Successfully generated content for plot '35': 'All Samples'
[2026-02-10 13:07:21,160] vuegen: INFO - Successfully generated content for plot '36': 'Plant Samples'
[2026-02-10 13:07:21,162] vuegen: INFO - Successfully generated content for plot '37': 'Animal Samples'
[2026-02-10 13:07:21,163] vuegen: INFO - Successfully generated content for plot '38': 'Non Saline Samples'
[2026-02-10 13:07:21,164] vuegen: INFO - Generated content and imports for subsection: 'Nestedness'
[2026-02-10 13:07:21,166] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Nestedness.py'
[2026-02-10 13:07:21,167] vuegen: DEBUG - Processing subsection '15': 'Shanon entropy analysis' - 1 component(s)
[2026-02-10 13:07:21,168] vuegen: INFO - Successfully generated content for plot '39': 'Specificity of sequences and higher taxonomic groups for environment'
[2026-02-10 13:07:21,170] vuegen: INFO - Generated content and imports for subsection: 'Shanon entropy analysis'
[2026-02-10 13:07:21,171] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Metagenomics/Shanon_entropy_analysis.py'
[2026-02-10 13:07:21,172] vuegen: DEBUG - Processing section '9': 'Network Analysis' - 1 subsection(s)
[2026-02-10 13:07:21,173] vuegen: DEBUG - Processing subsection '16': 'Phyla Association Networks' - 3 component(s)
[2026-02-10 13:07:21,175] vuegen: INFO - Successfully generated content for DataFrame: 'Phyla Counts Subset'
[2026-02-10 13:07:21,179] vuegen: INFO - Successfully read network from file: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/example_data/Earth_microbiome_vuegen_demo_notebook/3_Network_analysis/1_phyla_association_networks/2_phyla_correlation_network_with_0.5_threshold_edgelist.csv.
[2026-02-10 13:07:21,179] vuegen: DEBUG - Try to save network as PyVis network: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/streamlit_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:07:21,199] vuegen: INFO - PyVis network created and saved as: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/streamlit_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:07:21,201] vuegen: INFO - Successfully generated content for plot '40': 'Phyla Correlation Network With 0.5 Threshold Edgelist'
[2026-02-10 13:07:21,203] vuegen: INFO - Successfully generated content for plot '41': 'Phyla Correlation Network With 0.5 Threshold'
[2026-02-10 13:07:21,204] vuegen: INFO - Generated content and imports for subsection: 'Phyla Association Networks'
[2026-02-10 13:07:21,206] vuegen: INFO - Subsection file created: 'streamlit_report/sections/Network_Analysis/Phyla_Association_Networks.py'
[2026-02-10 13:07:21,208] vuegen: INFO - All the scripts to build the Streamlit app are available at streamlit_report/sections
[2026-02-10 13:07:21,208] vuegen: INFO - To run the Streamlit app, use the following command:
[2026-02-10 13:07:21,210] vuegen: INFO - streamlit run streamlit_report/sections/report_manager.py

All the scripts to build the Streamlit app are available at: streamlit_report/sections

To run the Streamlit app, use the following command:

	streamlit run streamlit_report/sections/report_manager.py
run_streamlit = False
# run_streamlit = True # uncomment line to run the streamlit report
# Launch the Streamlit report depneding on the platform
if not IN_COLAB and run_streamlit:
    !streamlit run streamlit_report/sections/report_manager.py
elif run_streamlit:
    # see: https://discuss.streamlit.io/t/how-to-launch-streamlit-app-from-google-colab-notebook/42399
    print(
        "Password/Enpoint IP for localtunnel is:",
        urllib.request.urlopen("https://ipv4.icanhazip.com")
        .read()
        .decode("utf8")
        .strip("\n"),
    )
    # Run the Streamlit app in the background
    !streamlit run streamlit_report/sections/report_manager.py --server.address=localhost &>/content/logs.txt &
    # Expose the Streamlit app on port 8501
    !npx localtunnel --port 8501 --subdomain vuegen-demo
else:
    print("Streamlit report not executed, set run_streamlit to True to run the report")

Hide code cell output

Streamlit report not executed, set run_streamlit to True to run the report

5.6. HTML and other report types with the extended configuration file#

# Test the changes by generarating the report from the modified YAML file
report_type = "html"
_ = report_generator.get_report(
    config_path=config_path, report_type=report_type, logger=None
)

Hide code cell output

[2026-02-10 13:07:21,249] vuegen: INFO - Path to log file: logs/2026-02-10_13-07-21_report.log
[2026-02-10 13:07:21,306] vuegen: INFO - Report 'Earth Microbiome Vuegen Demo Notebook' initialized with 3 sections.
[2026-02-10 13:07:21,307] vuegen: INFO - running in a normal Python process
[2026-02-10 13:07:21,313] vuegen: DEBUG - env_vars (QuartoReport): environ({'READTHEDOCS_VIRTUALENV_PATH': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest', 'READTHEDOCS_CANONICAL_URL': 'https://vuegen.readthedocs.io/en/latest/', 'HOSTNAME': 'build-31350061-project-1135329-vuegen', 'READTHEDOCS_GIT_CLONE_URL': 'https://github.com/Multiomics-Analytics-Group/vuegen.git', 'HOME': '/home/docs', 'NO_COLOR': '1', 'READTHEDOCS': 'True', 'READTHEDOCS_PRODUCTION_DOMAIN': 'app.readthedocs.org', 'READTHEDOCS_REPOSITORY_PATH': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest', 'READTHEDOCS_PROJECT': 'vuegen', 'READTHEDOCS_OUTPUT': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/_readthedocs/', 'PATH': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/bin:/home/docs/.asdf/shims:/home/docs/.asdf/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', 'READTHEDOCS_VERSION_TYPE': 'branch', 'LANG': 'C.UTF-8', 'READTHEDOCS_LANGUAGE': 'en', 'DEBIAN_FRONTEND': 'noninteractive', 'READTHEDOCS_GIT_COMMIT_HASH': '1a42fa37f8f843f0111db72fc2c035c6f3ebb2de', 'READTHEDOCS_VERSION_NAME': 'latest', 'READTHEDOCS_VERSION': 'latest', 'PWD': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs', 'READTHEDOCS_GIT_IDENTIFIER': 'main', 'DOCUTILSCONFIG': '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/docutils.conf', 'MPLBACKEND': 'Agg', 'JPY_PARENT_PID': '704', 'PYDEVD_USE_FRAME_EVAL': 'NO', 'TERM': 'xterm-color', 'CLICOLOR': '1', 'FORCE_COLOR': '1', 'CLICOLOR_FORCE': '1', 'PAGER': 'cat', 'GIT_PAGER': 'cat'})
[2026-02-10 13:07:21,317] vuegen: DEBUG - PATH: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/bin:/home/docs/.asdf/shims:/home/docs/.asdf/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[2026-02-10 13:07:21,321] vuegen: DEBUG - sys.path: ['/home/docs/.asdf/installs/python/3.11.12/lib/python311.zip', '/home/docs/.asdf/installs/python/3.11.12/lib/python3.11', '/home/docs/.asdf/installs/python/3.11.12/lib/python3.11/lib-dynload', '', '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/envs/latest/lib/python3.11/site-packages']
[2026-02-10 13:07:21,324] vuegen: DEBUG - Generating 'html' report in directory: '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report'
[2026-02-10 13:07:21,327] vuegen: DEBUG - Output directory already existed: '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report'
[2026-02-10 13:07:21,330] vuegen: INFO - Output directory for static content already existed: 'quarto_report/static'
[2026-02-10 13:07:21,336] vuegen: INFO - Starting to generate sections for the report.
[2026-02-10 13:07:21,336] vuegen: DEBUG - Processing section: 'Exploratory Data Analysis' - 1 subsection(s)
[2026-02-10 13:07:21,338] vuegen: DEBUG - Processing subsection: 'Sample Exploration' - 5 component(s)
[2026-02-10 13:07:21,343] vuegen: DEBUG - component_imports: ['import pandas as pd', 'from itables import show, init_notebook_mode', 'init_notebook_mode(all_interactive=True)']
[2026-02-10 13:07:21,347] vuegen: INFO - Successfully generated content for DataFrame: 'Metadata Random Subset'
[2026-02-10 13:07:21,355] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,359] vuegen: INFO - Successfully generated content for plot: 'Animal Samples Map'
[2026-02-10 13:07:21,360] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:07:21,364] vuegen: INFO - Successfully generated content for plot: 'Plant Samples Map'
[2026-02-10 13:07:21,367] vuegen: DEBUG - component_imports: ['import altair as alt', 'import requests', 'import json']
[2026-02-10 13:07:21,372] vuegen: INFO - Successfully generated content for plot: 'Saline Samples Map'
[2026-02-10 13:07:21,376] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,377] vuegen: INFO - Successfully generated content for plot: 'Physicochemical properties of the EMP samples'
[2026-02-10 13:07:21,381] vuegen: INFO - Generated content and imports for subsection: 'Sample Exploration'
[2026-02-10 13:07:21,382] vuegen: DEBUG - Processing section: 'Metagenomics' - 4 subsection(s)
[2026-02-10 13:07:21,389] vuegen: DEBUG - Processing subsection: 'Alpha Diversity' - 2 component(s)
[2026-02-10 13:07:21,390] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,396] vuegen: INFO - Successfully generated content for plot: 'Alpha Diversity Host Associated Samples'
[2026-02-10 13:07:21,399] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:07:21,401] vuegen: INFO - Successfully generated content for plot: 'Alpha Diversity Free Living Samples'
[2026-02-10 13:07:21,405] vuegen: INFO - Generated content and imports for subsection: 'Alpha Diversity'
[2026-02-10 13:07:21,408] vuegen: DEBUG - Processing subsection: 'Average Copy Number' - 2 component(s)
[2026-02-10 13:07:21,412] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,416] vuegen: INFO - Successfully generated content for plot: 'Average Copy Number Emp Ontology Level2'
[2026-02-10 13:07:21,419] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:07:21,422] vuegen: INFO - Successfully generated content for plot: 'Average Copy Number Emp Ontology Level3'
[2026-02-10 13:07:21,424] vuegen: INFO - Generated content and imports for subsection: 'Average Copy Number'
[2026-02-10 13:07:21,430] vuegen: DEBUG - Processing subsection: 'Nestedness' - 5 component(s)
[2026-02-10 13:07:21,431] vuegen: DEBUG - component_imports: ['import pandas as pd', 'from itables import show, init_notebook_mode', 'init_notebook_mode(all_interactive=True)']
[2026-02-10 13:07:21,434] vuegen: INFO - Successfully generated content for DataFrame: 'Nestedness Random Subset'
[2026-02-10 13:07:21,438] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:07:21,441] vuegen: INFO - Successfully generated content for plot: 'All Samples'
[2026-02-10 13:07:21,447] vuegen: DEBUG - component_imports: ['import plotly.io as pio', 'import requests', 'import json']
[2026-02-10 13:07:21,451] vuegen: INFO - Successfully generated content for plot: 'Plant Samples'
[2026-02-10 13:07:21,453] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,461] vuegen: INFO - Successfully generated content for plot: 'Animal Samples'
[2026-02-10 13:07:21,465] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,468] vuegen: INFO - Successfully generated content for plot: 'Non Saline Samples'
[2026-02-10 13:07:21,469] vuegen: INFO - Generated content and imports for subsection: 'Nestedness'
[2026-02-10 13:07:21,470] vuegen: DEBUG - Processing subsection: 'Shanon entropy analysis' - 1 component(s)
[2026-02-10 13:07:21,474] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,479] vuegen: INFO - Successfully generated content for plot: 'Specificity of sequences and higher taxonomic groups for environment'
[2026-02-10 13:07:21,479] vuegen: INFO - Generated content and imports for subsection: 'Shanon entropy analysis'
[2026-02-10 13:07:21,487] vuegen: DEBUG - Processing section: 'Network Analysis' - 1 subsection(s)
[2026-02-10 13:07:21,488] vuegen: DEBUG - Processing subsection: 'Phyla Association Networks' - 3 component(s)
[2026-02-10 13:07:21,491] vuegen: DEBUG - component_imports: ['import pandas as pd', 'from itables import show, init_notebook_mode', 'init_notebook_mode(all_interactive=True)']
[2026-02-10 13:07:21,496] vuegen: INFO - Successfully generated content for DataFrame: 'Phyla Counts Subset'
[2026-02-10 13:07:21,500] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,503] vuegen: INFO - Successfully read network from file: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/example_data/Earth_microbiome_vuegen_demo_notebook/3_Network_analysis/1_phyla_association_networks/2_phyla_correlation_network_with_0.5_threshold_edgelist.csv.
[2026-02-10 13:07:21,508] vuegen: DEBUG - Try to save network as PyVis network: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:07:21,558] vuegen: INFO - PyVis network created and saved as: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/static/Phyla_Correlation_Network_With_0.5_Threshold_Edgelist.html.
[2026-02-10 13:07:21,561] vuegen: INFO - Successfully generated content for plot: 'Phyla Correlation Network With 0.5 Threshold Edgelist'
[2026-02-10 13:07:21,569] vuegen: DEBUG - component_imports: []
[2026-02-10 13:07:21,573] vuegen: INFO - Successfully generated content for plot: 'Phyla Correlation Network With 0.5 Threshold'
[2026-02-10 13:07:21,576] vuegen: INFO - Generated content and imports for subsection: 'Phyla Association Networks'
[2026-02-10 13:07:21,577] vuegen: INFO - Created qmd script to render the app: /home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/quarto_report.qmd
[2026-02-10 13:07:21,577] vuegen: INFO - Running 'Earth Microbiome Vuegen Demo Notebook' 'html' report with ['quarto', 'render', '/home/docs/checkouts/readthedocs.org/user_builds/vuegen/checkouts/latest/docs/quarto_report/quarto_report.qmd']
[2026-02-10 13:07:53,385] vuegen: INFO - 'Earth Microbiome Vuegen Demo Notebook' 'html' report rendered
Starting python3 kernel...
Done

Executing 'quarto_report.quarto_ipynb'
  Cell 1/10: 'Imports'......................................
Done
  Cell 2/10: 'Metadata Random Subset 10'....................Done
  Cell 3/10: 'Plant Samples Map 43'.........................
Done
  Cell 4/10: 'Saline Samples Map 44'........................
Done
  Cell 5/10: 'Alpha Diversity Free Living Samples 47'.......Done
  Cell 6/10: 'Average Copy Number Emp Ontology Level3 49'...
Done
  Cell 7/10: 'Nestedness Random Subset 11'..................Done
  Cell 8/10: 'All Samples 50'...............................
Done
  Cell 9/10: 'Plant Samples 51'.............................Done
  Cell 10/10: 'Phyla Counts Subset 12'.......................Done
pandoc 
  to: html
  output-file: quarto_report.html
  standalone: true
  self-contained: true
  section-divs: true
  html-math-method: mathjax
  wrap: none
  default-image-extension: png
  toc: true
  toc-depth: 3
  variables: {}
  
metadata
  document-css: false
  link-citations: true
  date-format: long
  lang: en
  title: Earth Microbiome Vuegen Demo Notebook
  jupyter: python3
  toc-location: left
  page-layout: full
Output created: quarto_report.html