From 9558a7d06b5e3df10b67c4a97afd7dfc79a573ac Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 11:30:46 +0200
Subject: [PATCH 01/41] :art: format markdowns
---
docs/README.md | 16 +-
docs/vuegen_basic_case_study_configfile.md | 327 +++++++++++----------
2 files changed, 172 insertions(+), 171 deletions(-)
diff --git a/docs/README.md b/docs/README.md
index 8e11f08..2c090f5 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,10 +1,10 @@
# Docs creation
-In order to build the docs you need to
+In order to build the docs you need to
- 1. Install sphinx and additional support packages
- 2. Build the package reference files
- 3. Run sphinx to create a local html version
+1. Install sphinx and additional support packages
+2. Build the package reference files
+3. Run sphinx to create a local html version
The documentation is build using readthedocs automatically.
@@ -18,12 +18,13 @@ poetry install --with docs
## Build docs using Sphinx command line tools
-Command to be run from `path/to/docs`, i.e. from within the `docs` package folder:
+Command to be run from `path/to/docs`, i.e. from within the `docs` package folder:
Options:
- - `--separate` to build separate pages for each (sub-)module
-```bash
+- `--separate` to build separate pages for each (sub-)module
+
+```bash
# pwd: docs
# apidoc
sphinx-apidoc --force --implicit-namespaces --module-first -o reference ../src/vuegen
@@ -38,4 +39,3 @@ The README is included in the `Overview` section of the docs. We created a [Pyth
Relative links are used in the main README, which need to be resolved when building. It's
possible to include the a `relative-docs` option if one uses `index.md` ([see docs](https://myst-parser.readthedocs.io/en/latest/faq/index.html#include-a-file-from-outside-the-docs-folder-like-readme-md)). This does not work
with `href` links, only native markdown links.
-
diff --git a/docs/vuegen_basic_case_study_configfile.md b/docs/vuegen_basic_case_study_configfile.md
index 2336459..c4faabf 100644
--- a/docs/vuegen_basic_case_study_configfile.md
+++ b/docs/vuegen_basic_case_study_configfile.md
@@ -1,6 +1,6 @@
# Predefined Directory Case Study - Configuration File
-The [configuration file](https://github.com/Multiomics-Analytics-Group/vuegen/blob/main/docs/example_config_files/Basic_example_vuegen_demo_notebook_config.yaml) of the basic case study using a predefined directory is presented below:
+The [configuration file](https://github.com/Multiomics-Analytics-Group/vuegen/blob/main/docs/example_config_files/Basic_example_vuegen_demo_notebook_config.yaml) of the basic case study using a predefined directory is presented below:
```yaml
report:
@@ -9,168 +9,169 @@ report:
graphical_abstract: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.svg
logo: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.svg
sections:
-- title: Plots
- description: This section contains example plots.
- subsections:
- - title: Interactive Plots
- description: Optional description for section.
- components:
- - title: Top Species Plot By Biome Plotly
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/1_top_species_plot_by_biome_plotly.json
- description: ''
- caption: ''
- component_type: plot
- plot_type: plotly
- - title: Multiline Plot Altair
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/2_multiline_plot_altair.json
- description: ''
- caption: ''
- component_type: plot
- plot_type: altair
- - title: Pie Plot Countries Plotly
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/3_pie_plot_countries_plotly.json
- description: ''
- caption: ''
- component_type: plot
- plot_type: plotly
- - title: Pie Plots Biomes Plotly
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/4_pie_plots_biomes_plotly.json
- description: ''
- caption: ''
- component_type: plot
- plot_type: plotly
- - title: Saline Metagenomics Samples Map Altair
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/5_saline_metagenomics_samples_map_altair.json
- description: ''
- caption: ''
- component_type: plot
- plot_type: altair
- - title: Description
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/description.md
- description: ''
- caption: ''
- component_type: markdown
- - title: Static Plots
- description: ''
- components:
- - title: Number Samples Per Study
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/1_number_samples_per_study.png
- description: ''
- caption: ''
- component_type: plot
- plot_type: static
- - title: Animal Metagenomics Samples Map
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/2_animal_metagenomics_samples_map.png
- description: ''
- caption: ''
- component_type: plot
- plot_type: static
- - title: Alpha Diversity Host Associated Samples
- file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/3_alpha_diversity_host_associated_samples.png
- description: ''
- caption: ''
- component_type: plot
- plot_type: static
- - title: "Graphical overview of VueGen workflow and components"
- file_path: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_graph_abstract.png
- description: ''
- caption: The diagram illustrates the processing pipeline of VueGen, starting
- from either a directory or a YAML configuration file. Reports consist of hierarchical
- sections and subsections, each containing various components such as plots,
- dataframes, Markdown, HTML, and data retrieved via API calls.
- component_type: plot
- plot_type: static
-- title: Dataframes
- description: ''
- subsections:
- - title: All Formats
- description: This subsection contains example dataframes.
- components:
- - title: Phyla Correlation Network Csv
- file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/1_phyla_correlation_network_csv.csv
- description: ''
- caption: ''
- component_type: dataframe
- file_format: csv
- delimiter: ','
- - title: Abundance Table Example Xls
- file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/2_abundance_table_example_xls.xls
- description: ''
- caption: ''
- component_type: dataframe
- file_format: xls
- - title: Sample Info Example Txt
- file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/3_sample_info_example_txt.txt
- description: ''
- caption: ''
- component_type: dataframe
- file_format: txt
- delimiter: \t
- - title: Sample Info Example Parquet
- file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/4_sample_info_example_parquet.parquet
- description: ''
- caption: ''
- component_type: dataframe
- file_format: parquet
-- title: Networks
- description: ''
- subsections:
- - title: Interactive Networks
- description: Optional description for subsection
- components:
- - title: Man Example
- file_path: example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/1_man_example.graphml
- description: ''
- caption: ''
- component_type: plot
- plot_type: interactive_network
- - title: Description
- file_path: example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/description.md
- description: ''
- caption: ''
- component_type: markdown
- - title: Static Networks
- description: ''
- components:
- - title: Phyla Correlation Network
- file_path: example_data/Basic_example_vuegen_demo_notebook/3_Networks/2_Static_networks/1_phyla_correlation_network.png
- description: ''
- caption: ''
- component_type: plot
- plot_type: static
-- title: Html
- description: ''
- subsections:
- - title: All Html
- description: ''
- components:
- - title: Plot
- file_path: example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/1_plot.html
- description: ''
- caption: ''
- component_type: html
- - title: Ckg Network
- file_path: example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/2_ckg_network.html
- description: ''
- caption: ''
- component_type: plot
- plot_type: interactive_network
- - title: Multiqc Report
- file_path: example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/3_multiqc_report.html
- description: ''
- caption: ''
- component_type: html
-- title: Markdown
- description: ''
- subsections:
- - title: All Markdown
- description: ''
- components:
- - title: Readme
- file_path: example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md
- description: ''
- caption: ''
- component_type: markdown
+ - title: Plots
+ description: This section contains example plots.
+ subsections:
+ - title: Interactive Plots
+ description: Optional description for section.
+ components:
+ - title: Top Species Plot By Biome Plotly
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/1_top_species_plot_by_biome_plotly.json
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: plotly
+ - title: Multiline Plot Altair
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/2_multiline_plot_altair.json
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: altair
+ - title: Pie Plot Countries Plotly
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/3_pie_plot_countries_plotly.json
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: plotly
+ - title: Pie Plots Biomes Plotly
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/4_pie_plots_biomes_plotly.json
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: plotly
+ - title: Saline Metagenomics Samples Map Altair
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/5_saline_metagenomics_samples_map_altair.json
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: altair
+ - title: Description
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/description.md
+ description: ""
+ caption: ""
+ component_type: markdown
+ - title: Static Plots
+ description: ""
+ components:
+ - title: Number Samples Per Study
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/1_number_samples_per_study.png
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: static
+ - title: Animal Metagenomics Samples Map
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/2_animal_metagenomics_samples_map.png
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: static
+ - title: Alpha Diversity Host Associated Samples
+ file_path: example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/3_alpha_diversity_host_associated_samples.png
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: static
+ - title: "Graphical overview of VueGen workflow and components"
+ file_path: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_graph_abstract.png
+ description: ""
+ caption:
+ The diagram illustrates the processing pipeline of VueGen, starting
+ from either a directory or a YAML configuration file. Reports consist of hierarchical
+ sections and subsections, each containing various components such as plots,
+ dataframes, Markdown, HTML, and data retrieved via API calls.
+ component_type: plot
+ plot_type: static
+ - title: Dataframes
+ description: ""
+ subsections:
+ - title: All Formats
+ description: This subsection contains example dataframes.
+ components:
+ - title: Phyla Correlation Network Csv
+ file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/1_phyla_correlation_network_csv.csv
+ description: ""
+ caption: ""
+ component_type: dataframe
+ file_format: csv
+ delimiter: ","
+ - title: Abundance Table Example Xls
+ file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/2_abundance_table_example_xls.xls
+ description: ""
+ caption: ""
+ component_type: dataframe
+ file_format: xls
+ - title: Sample Info Example Txt
+ file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/3_sample_info_example_txt.txt
+ description: ""
+ caption: ""
+ component_type: dataframe
+ file_format: txt
+ delimiter: \t
+ - title: Sample Info Example Parquet
+ file_path: example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/4_sample_info_example_parquet.parquet
+ description: ""
+ caption: ""
+ component_type: dataframe
+ file_format: parquet
+ - title: Networks
+ description: ""
+ subsections:
+ - title: Interactive Networks
+ description: Optional description for subsection
+ components:
+ - title: Man Example
+ file_path: example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/1_man_example.graphml
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: interactive_network
+ - title: Description
+ file_path: example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/description.md
+ description: ""
+ caption: ""
+ component_type: markdown
+ - title: Static Networks
+ description: ""
+ components:
+ - title: Phyla Correlation Network
+ file_path: example_data/Basic_example_vuegen_demo_notebook/3_Networks/2_Static_networks/1_phyla_correlation_network.png
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: static
+ - title: Html
+ description: ""
+ subsections:
+ - title: All Html
+ description: ""
+ components:
+ - title: Plot
+ file_path: example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/1_plot.html
+ description: ""
+ caption: ""
+ component_type: html
+ - title: Ckg Network
+ file_path: example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/2_ckg_network.html
+ description: ""
+ caption: ""
+ component_type: plot
+ plot_type: interactive_network
+ - title: Multiqc Report
+ file_path: example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/3_multiqc_report.html
+ description: ""
+ caption: ""
+ component_type: html
+ - title: Markdown
+ description: ""
+ subsections:
+ - title: All Markdown
+ description: ""
+ components:
+ - title: Readme
+ file_path: example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md
+ description: ""
+ caption: ""
+ component_type: markdown
```
The directory with he example data is available in the [GitHub repository](https://github.com/Multiomics-Analytics-Group/vuegen/blob/main/docs/example_data/Basic_example_vuegen_demo_notebook).
From ca5a970cc0c8e30e194897c4235deee9ba326292 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:32:03 +0200
Subject: [PATCH 02/41] :art: docstrings to 90 characters and remove
whitespaces
---
src/vuegen/streamlit_reportview.py | 50 ++++++++++++++++++------------
1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index 8ed3a8e..640d292 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -260,7 +260,8 @@ def run_report(self, output_dir: str = SECTIONS_DIR) -> None:
self.report.logger.debug(
f"Running Streamlit report from directory: {output_dir}"
)
- # ! using pyinstaller: vuegen main script as executable, not the Python Interpreter
+ # ! using pyinstaller: vuegen main script as executable,
+ # ! not the Python Interpreter
msg = f"{sys.executable = }"
self.report.logger.debug(msg)
try:
@@ -326,7 +327,8 @@ def _format_text(
type : str
The type of the text (e.g., 'header', 'paragraph').
level : int, optional
- If the text is a header, the level of the header (e.g., 1 for h1, 2 for h2, etc.).
+ If the text is a header, the level of the header
+ (e.g., 1 for h1, 2 for h2, etc.).
color : str, optional
The color of the header text.
text_align : str, optional
@@ -521,8 +523,9 @@ def _combine_components(self, components: list[dict]) -> tuple[list, list, bool]
def _generate_subsection(self, subsection) -> tuple[List[str], List[str]]:
"""
- Generate code to render components (plots, dataframes, markdown) in the given subsection,
- creating imports and content for the subsection based on the component type.
+ Generate code to render components (plots, dataframes, markdown) in the given
+ subsection, creating imports and content for the subsection based on the
+ component type.
Parameters
----------
@@ -564,7 +567,8 @@ def _generate_subsection(self, subsection) -> tuple[List[str], List[str]]:
def _generate_plot_content(self, plot) -> List[str]:
"""
- Generate content for a plot component based on the plot type (static or interactive).
+ Generate content for a plot component based on the plot type
+ (static or interactive).
Parameters
----------
@@ -938,8 +942,8 @@ def _generate_html_content(self, html) -> List[str]:
def _generate_apicall_content(self, apicall) -> List[str]:
"""
- Generate content for an API component. This method handles the API call and formats
- the response for display in the Streamlit app.
+ Generate content for an API component. This method handles the API call and
+ formats the response for display in the Streamlit app.
Parameters
----------
@@ -983,23 +987,26 @@ def _generate_apicall_content(self, apicall) -> List[str]:
def _generate_chatbot_content(self, chatbot) -> List[str]:
"""
- Generate content to render a ChatBot component, supporting standard and Ollama-style streaming APIs.
+ Generate content to render a ChatBot component, supporting standard and
+ Ollama-style streaming APIs.
- This method builds and returns a list of strings, which are later executed to create the chatbot
- interface in a Streamlit app. It includes user input handling, API interaction logic, response parsing,
+ This method builds and returns a list of strings, which are later executed to
+ create the chatbot interface in a Streamlit app. It includes user input handling,
+ API interaction logic, response parsing,
and conditional rendering of text, source links, and HTML subgraphs.
The function distinguishes between two chatbot modes:
- - **Ollama-style streaming API**: Identified by the presence of `chatbot.model`. Uses streaming
- JSON chunks from the server to simulate a real-time response.
- - **Standard API**: Assumes a simple POST request with a prompt and a full JSON response with text,
+ - **Ollama-style streaming API**: Identified by the presence of `chatbot.model`.
+ Uses streaming JSON chunks from the server to simulate a real-time response.
+ - **Standard API**: Assumes a simple POST request with a prompt and a full JSON
+ response with text,
and other fields like links, HTML graphs, etc.
Parameters
----------
chatbot : ChatBot
- The ChatBot component to generate content for, containing configuration such as title, model,
- API endpoint, headers, and caption.
+ The ChatBot component to generate content for, containing configuration such
+ as title, model, API endpoint, headers, and caption.
Returns
-------
@@ -1074,7 +1081,8 @@ def parse_api_response(response):
return {{"role": "assistant", "content": output}}
output += body.get("message", {{}}).get("content", "")
except Exception as e:
- return {{"role": "assistant", "content": f"Error while processing API response: {{str(e)}}"}}
+ return {{"role": "assistant", "content":
+ f"Error while processing API response: {{str(e)}}"}}
# Simulated typing effect for responses
def response_generator(msg_content):
@@ -1088,12 +1096,13 @@ def response_generator(msg_content):
{handle_prompt_block}
# Retrieve question and generate answer
- combined = "\\n".join(msg["content"] for msg in st.session_state.messages if msg["role"] == "user")
+ combined = "\\n".join(msg["content"] for msg in st.session_state.messages
+ if msg["role"] == "user")
messages = [{{"role": "user", "content": combined}}]
- with st.spinner('Generating answer...'):
+ with st.spinner('Generating answer...'):
response = generate_query(messages)
parsed_response = parse_api_response(response)
-
+
# Add the assistant's response to the session state and display it
st.session_state.messages.append(parsed_response)
with st.chat_message("assistant"):
@@ -1168,7 +1177,8 @@ def _generate_component_imports(self, component: r.Component) -> List[str]:
Parameters
----------
component : r.Component
- The component for which to generate the required imports. The component can be of type:
+ The component for which to generate the required imports.
+ The component can be of type:
- PLOT
- DATAFRAME
From 04e4d5437568617ed8803aed4ec63a7fbba753ad Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:32:26 +0200
Subject: [PATCH 03/41] :wrench: set line length to 90 characters
---
setup.cfg | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 setup.cfg
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..12062ee
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[flake8]
+exclude = docs
+max-line-length = 90
+aggressive = 2
From e4c588163ebef06a2d878c5964259502a7423817 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:35:23 +0200
Subject: [PATCH 04/41] :art: split comments, add comments, remove more
whitespace, add more docstrings
---
src/vuegen/streamlit_reportview.py | 39 +++++++++++++++++++++---------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index 640d292..dc95db9 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -1,3 +1,7 @@
+"""
+StreamlitReportView class for generating Streamlit reports based on a configuration file.
+"""
+
import os
import subprocess
import sys
@@ -14,6 +18,7 @@
def write_python_file(fpath: str, imports: list[str], contents: list[str]) -> None:
+ """Write a Python file with the given imports and contents."""
with open(fpath, "w", encoding="utf8") as f:
# Write imports at the top of the file
f.write("\n".join(imports) + "\n\n")
@@ -75,12 +80,14 @@ def __init__(
def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
"""
- Generates the Streamlit report and creates Python files for each section and its subsections and plots.
+ Generates the Streamlit report and creates Python files for each section
+ and its subsections and plots.
Parameters
----------
output_dir : str, optional
- The folder where the generated report files will be saved (default is SECTIONS_DIR).
+ The folder where the generated report files will be saved
+ (default is SECTIONS_DIR).
"""
self.report.logger.debug(
f"Generating '{self.report_type}' report in directory: '{output_dir}'"
@@ -167,14 +174,17 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
self.report.logger.debug(
f"Section directory already existed: {section_dir_path}"
)
- # add an overview page to section of components exist
+ # add an overview page to section for it's section components
+ # they will be written when the components are parsed
+ # using `_generate_sections`
if section.components:
subsection_file_path = (
Path(section_name_var)
/ f"0_overview_{make_valid_identifier(section.title).lower()}.py"
).as_posix() # Make sure it's Posix Paths
section.file_path = subsection_file_path
- # Create a Page object for each subsection and add it to the home page content
+ # Create a Page object for each subsection and
+ # add it to the home page content
report_manag_content.append(
f"{section_name_var}_overview = st.Page('{subsection_file_path}', title='Overview {section.title}')"
)
@@ -194,7 +204,8 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
Path(section_name_var) / f"{subsection_name_var}.py"
).as_posix() # Make sure it's Posix Paths
subsection.file_path = subsection_file_path
- # Create a Page object for each subsection and add it to the home page content
+ # Create a Page object for each subsection and
+ # add it to the home page content
report_manag_content.append(
f"{subsection_name_var} = st.Page('{subsection_file_path}', title='{subsection.title}')"
)
@@ -411,7 +422,8 @@ def _generate_home_section(
# Add the home page to the report manager content
report_manag_content.append(
- "homepage = st.Page('Home/Homepage.py', title='Homepage')" # ! here Posix Path is hardcoded
+ # ! here Posix Path is hardcoded
+ "homepage = st.Page('Home/Homepage.py', title='Homepage')"
)
report_manag_content.append("sections_pages['Home'] = [homepage]\n")
self.report.logger.info("Home page added to the report manager content.")
@@ -421,7 +433,8 @@ def _generate_home_section(
def _generate_sections(self, output_dir: str) -> None:
"""
- Generates Python files for each section in the report, including subsections and its components (plots, dataframes, markdown).
+ Generates Python files for each section in the report, including subsections
+ and its components (plots, dataframes, markdown).
Parameters
----------
@@ -458,7 +471,9 @@ def _generate_sections(self, output_dir: str) -> None:
continue
# Iterate through subsections and integrate them into the section file
- # subsection should have the subsection_file_path as file_path?
+ # ! subsection should have the subsection_file_path as file_path,
+ # ! which is set when parsing the config in the main generate_sections
+ # ! method
for subsection in section.subsections:
self.report.logger.debug(
f"Processing subsection '{subsection.id}': '{subsection.title} -"
@@ -603,7 +618,8 @@ def _generate_plot_content(self, plot) -> List[str]:
# If network_data is a tuple, separate the network and html file path
networkx_graph, html_plot_file = networkx_graph
else:
- # Otherwise, create and save a new pyvis network from the netowrkx graph
+ # Otherwise,
+ # create and save a new pyvis network from the netowrkx graph
html_plot_file = (
Path(self.static_dir) / f"{plot.title.replace(' ', '_')}.html"
).resolve()
@@ -737,7 +753,8 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
f"Unsupported file extension: {file_extension}. Supported extensions are: {', '.join(fmt.value for fmt in r.DataFrameFormat)}."
)
# return [] # Skip execution if unsupported file extension
- # Should it not return here? Can we even call the method with an unsupported file extension?
+ # Should it not return here?
+ # Can we even call the method with an unsupported file extension?
# Build the file path (URL or local file)
if is_url(dataframe.file_path):
@@ -1067,7 +1084,7 @@ def generate_query(messages):
json={{"model": "{chatbot.model}", "messages": messages, "stream": True}},
)
response.raise_for_status()
- return response
+ return response
# Parse streaming response from Ollama
def parse_api_response(response):
From 5a909bbddd340f14f78b07d52457c5c56ae94114 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:37:19 +0200
Subject: [PATCH 05/41] :art: write strings on two line and let Python
concatenate theses
---
src/vuegen/streamlit_reportview.py | 61 ++++++++++++++++++++----------
1 file changed, 41 insertions(+), 20 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index dc95db9..0b122fa 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -106,7 +106,8 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
)
else:
self.report.logger.info(
- f"Output directory for static content already existed: '{self.static_dir}'"
+ "Output directory for static content already existed: "
+ f"{self.static_dir}"
)
try:
@@ -186,7 +187,8 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
# Create a Page object for each subsection and
# add it to the home page content
report_manag_content.append(
- f"{section_name_var}_overview = st.Page('{subsection_file_path}', title='Overview {section.title}')"
+ f"{section_name_var}_overview = st.Page('{subsection_file_path}'"
+ f", title='Overview {section.title}')"
)
subsection_page_vars.append(f"{section_name_var}_overview")
@@ -195,10 +197,12 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
subsection_name_var = make_valid_identifier(subsection.title)
if not subsection_name_var.isidentifier():
self.report.logger.warning(
- f"Subsection name '{subsection_name_var}' is not a valid identifier."
+ f"Subsection name '{subsection_name_var}' "
+ " is not a valid identifier."
)
raise ValueError(
- f"Subsection name is not a valid Python identifier: {subsection_name_var}"
+ "Subsection name is not a valid Python identifier: "
+ f"{subsection_name_var}"
)
subsection_file_path = (
Path(section_name_var) / f"{subsection_name_var}.py"
@@ -207,13 +211,15 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
# Create a Page object for each subsection and
# add it to the home page content
report_manag_content.append(
- f"{subsection_name_var} = st.Page('{subsection_file_path}', title='{subsection.title}')"
+ f"{subsection_name_var} = st.Page('{subsection_file_path}', "
+ f"title='{subsection.title}')"
)
subsection_page_vars.append(subsection_name_var)
# Add all subsection Page objects to the corresponding section
report_manag_content.append(
- f"sections_pages['{section.title}'] = [{', '.join(subsection_page_vars)}]\n"
+ f"sections_pages['{section.title}'] = "
+ f"[{', '.join(subsection_page_vars)}]\n"
)
# Add navigation object to the home page content
@@ -305,7 +311,8 @@ def run_report(self, output_dir: str = SECTIONS_DIR) -> None:
else:
# If autorun is False, print instructions for manual execution
self.report.logger.info(
- f"All the scripts to build the Streamlit app are available at {output_dir}"
+ "All the scripts to build the Streamlit app are available at "
+ f"{output_dir}"
)
self.report.logger.info(
"To run the Streamlit app, use the following command:"
@@ -314,8 +321,9 @@ def run_report(self, output_dir: str = SECTIONS_DIR) -> None:
f"streamlit run {Path(output_dir) / self.REPORT_MANAG_SCRIPT}"
)
msg = (
- f"\nAll the scripts to build the Streamlit app are available at: {output_dir}\n\n"
- f"To run the Streamlit app, use the following command:\n\n"
+ "\nAll the scripts to build the Streamlit app are available at: "
+ f"{output_dir}\n\n"
+ "To run the Streamlit app, use the following command:\n\n"
f"\tstreamlit run {Path(output_dir) / self.REPORT_MANAG_SCRIPT}"
)
print(msg)
@@ -403,7 +411,8 @@ def _generate_home_section(
)
if self.report.graphical_abstract:
home_content.append(
- f"\nst.image('{self.report.graphical_abstract}', use_column_width=True)"
+ f"\nst.image('{self.report.graphical_abstract}', "
+ "use_column_width=True)"
)
# add components content to page (if any)
@@ -446,7 +455,8 @@ def _generate_sections(self, output_dir: str) -> None:
try:
for section in self.report.sections[1:]:
self.report.logger.debug(
- f"Processing section '{section.id}': '{section.title}' - {len(section.subsections)} subsection(s)"
+ f"Processing section '{section.id}': '{section.title}' - "
+ f"{len(section.subsections)} subsection(s)"
)
if section.components:
@@ -500,8 +510,10 @@ def _generate_sections(self, output_dir: str) -> None:
)
except Exception as subsection_error:
self.report.logger.error(
- f"Error processing subsection '{subsection.id}' '{subsection.title}' "
- f"in section '{section.id}' '{section.title}': {str(subsection_error)}"
+ f"Error processing subsection '{subsection.id}'"
+ f" '{subsection.title}' "
+ f"in section '{section.id}' '{section.title}':"
+ f" {str(subsection_error)}"
)
raise
@@ -606,7 +618,8 @@ def _generate_plot_content(self, plot) -> List[str]:
if plot.plot_type == r.PlotType.STATIC:
plot_rel_path = get_relative_file_path(plot.file_path)
plot_content.append(
- f"\nst.image('{plot_rel_path.as_posix()}', caption='{plot.caption}', use_column_width=True)\n"
+ f"\nst.image('{plot_rel_path.as_posix()}', "
+ f" caption='{plot.caption}', use_column_width=True)\n"
)
elif plot.plot_type == r.PlotType.PLOTLY:
plot_content.append(self._generate_plot_code(plot))
@@ -659,7 +672,8 @@ def _generate_plot_content(self, plot) -> List[str]:
self.report.logger.warning(f"Unsupported plot type: {plot.plot_type}")
except Exception as e:
self.report.logger.error(
- f"Error generating content for '{plot.plot_type}' plot '{plot.id}' '{plot.title}': {str(e)}"
+ f"Error generating content for '{plot.plot_type}' plot '{plot.id}' "
+ f"'{plot.title}': {str(e)}"
)
raise
@@ -750,7 +764,10 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
file_extension == fmt.value_with_dot for fmt in r.DataFrameFormat
):
self.report.logger.error(
- f"Unsupported file extension: {file_extension}. Supported extensions are: {', '.join(fmt.value for fmt in r.DataFrameFormat)}."
+ f"Unsupported file extension: {file_extension}. "
+ "Supported extensions are: {}.".format(
+ ", ".join(fmt.value for fmt in r.DataFrameFormat)
+ )
)
# return [] # Skip execution if unsupported file extension
# Should it not return here?
@@ -787,7 +804,8 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
r.DataFrameFormat.XLSX.value_with_dot,
]:
dataframe_content.append(
- f"""df = pd.{read_function.__name__}('{dataframe.file_path}', sheet_name=selected_sheet)\n"""
+ f"df = pd.{read_function.__name__}('{dataframe.file_path}',"
+ " sheet_name=selected_sheet)\n"
)
else:
dataframe_content.append(
@@ -819,7 +837,8 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
)
except Exception as e:
self.report.logger.error(
- f"Error generating content for DataFrame: {dataframe.title}. Error: {str(e)}"
+ f"Error generating content for DataFrame: {dataframe.title}. "
+ f"Error: {str(e)}"
)
raise
@@ -880,7 +899,8 @@ def _generate_markdown_content(self, markdown) -> List[str]:
)
except Exception as e:
self.report.logger.error(
- f"Error generating content for Markdown: {markdown.title}. Error: {str(e)}"
+ f"Error generating content for Markdown: {markdown.title}. "
+ f"Error: {str(e)}"
)
raise
@@ -998,7 +1018,8 @@ def _generate_apicall_content(self, apicall) -> List[str]:
)
self.report.logger.info(
- f"Successfully generated content for APICall '{apicall.title}' using method '{apicall.method}'"
+ f"Successfully generated content for APICall '{apicall.title}' "
+ f"using method '{apicall.method}'"
)
return apicall_content
From c2a00169e8b43bcdfbb4a3c38018d67bb8e4292c Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:51:04 +0200
Subject: [PATCH 06/41] :art: snake_case
---
src/vuegen/streamlit_reportview.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index 0b122fa..4998f47 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -60,10 +60,10 @@ def __init__(
"""
super().__init__(report=report, report_type=report_type)
self.streamlit_autorun = streamlit_autorun
- self.BUNDLED_EXECUTION = False
+ self.bundled_execution = False
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
self.report.logger.info("running in a PyInstaller bundle")
- self.BUNDLED_EXECUTION = True
+ self.bundled_execution = True
else:
self.report.logger.info("running in a normal Python process")
@@ -287,7 +287,7 @@ def run_report(self, output_dir: str = SECTIONS_DIR) -> None:
self.report.logger.debug(
f"Running Streamlit report from file: {target_file}"
)
- if self.BUNDLED_EXECUTION:
+ if self.bundled_execution:
args = [
"streamlit",
"run",
From 4cc06c0a1cd73f9c75d68c165e78497e3d355d17 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:53:06 +0200
Subject: [PATCH 07/41] :art: raise ValueError if unknown type is provided
alternatively we could use a meaningful default
---
src/vuegen/streamlit_reportview.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index 4998f47..5a99c65 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -358,12 +358,16 @@ def _format_text(
str
A formatted markdown string for the specified text.
"""
+ tag = ""
if type == "header":
tag = f"h{level}"
elif type == "paragraph" or type == "caption":
tag = "p"
-
- return f"""st.markdown('''<{tag} style='text-align: {text_align}; color: {color};'>{text}{tag}>''', unsafe_allow_html=True)"""
+ else:
+ raise ValueError(
+ f"Unsupported text type: {type}. Supported types are 'header', "
+ "'paragraph', and 'caption'."
+ )
def _generate_home_section(
self,
From 57948ec95277fa5b83910fc81742eb893c2a85ec Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:53:26 +0200
Subject: [PATCH 08/41] :art: specify encoding explicitly
---
src/vuegen/streamlit_reportview.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index 5a99c65..f39f518 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -429,7 +429,7 @@ def _generate_home_section(
# Write the home page content to a Python file
home_page_path = Path(home_dir_path) / "Homepage.py"
- with open(home_page_path, "w") as home_page:
+ with open(home_page_path, "w", encoding="utf-8") as home_page:
home_page.write("\n".join(home_content))
self.report.logger.info(f"Home page content written to '{home_page_path}'.")
From 37cc80fcda00178d80493520ee819735d661aafb Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:54:13 +0200
Subject: [PATCH 09/41] :art: use textwrap to keep indentation
---
src/vuegen/streamlit_reportview.py | 158 +++++++++++++++++++----------
1 file changed, 103 insertions(+), 55 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index f39f518..9cb7263 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -119,8 +119,8 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
"""\
import os
import time
-
- import psutil
+
+ import psutil
import streamlit as st
"""
)
@@ -129,7 +129,10 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
report_manag_content.append(
textwrap.dedent(
f"""\
- st.set_page_config(layout="wide", page_title="{self.report.title}", page_icon="{self.report.logo}")
+ st.set_page_config(layout="wide",
+ page_title="{self.report.title}",
+ page_icon="{self.report.logo}"
+ )
st.logo("{self.report.logo}")
"""
)
@@ -138,7 +141,8 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
report_manag_content.append(
textwrap.dedent(
f"""\
- st.set_page_config(layout="wide", page_title="{self.report.title}")
+ st.set_page_config(layout="wide",
+ page_title="{self.report.title}")
"""
)
)
@@ -227,9 +231,12 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
textwrap.dedent(
"""\
report_nav = st.navigation(sections_pages)
-
- # Following https://discuss.streamlit.io/t/close-streamlit-app-with-button-click/35132/5
- exit_app = st.sidebar.button("Shut Down App", icon=":material/power_off:", use_container_width=True)
+
+ # Following https://discuss.streamlit.io/t/\
+close-streamlit-app-with-button-click/35132/5
+ exit_app = st.sidebar.button("Shut Down App",
+ icon=":material/power_off:",
+ use_container_width=True)
if exit_app:
st.toast("Shutting down the app...")
time.sleep(1)
@@ -238,7 +245,7 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
p = psutil.Process(pid)
p.terminate()
-
+
report_nav.run()
"""
)
@@ -367,7 +374,17 @@ def _format_text(
raise ValueError(
f"Unsupported text type: {type}. Supported types are 'header', "
"'paragraph', and 'caption'."
- )
+
+ return textwrap.dedent(
+ f"""
+ st.markdown(
+ (
+ "<{tag} style='text-align: {text_align}; "
+ "color: {color};'>{text}{tag}>"
+ ),
+ unsafe_allow_html=True)
+ """
+ )
def _generate_home_section(
self,
@@ -665,9 +682,16 @@ def _generate_plot_content(self, plot) -> List[str]:
# Append the code for additional information (nodes and edges count)
plot_content.append(
- f"""
-st.markdown(f" Number of nodes: {num_nodes}
", unsafe_allow_html=True)
-st.markdown(f" Number of relationships: {num_edges}
", unsafe_allow_html=True)\n"""
+ textwrap.dedent(
+ f"""
+ st.markdown((" "
+ f"Number of nodes: {num_nodes}
"),
+ unsafe_allow_html=True)
+ st.markdown((""
+ f" Number of relationships: {num_edges}
"),
+ unsafe_allow_html=True)
+ """
+ )
)
# Add the specific code for visualization
@@ -703,37 +727,51 @@ def _generate_plot_code(self, plot) -> str:
"""
# If the file path is a URL, generate code to fetch content via requests
if is_url(plot.file_path):
- plot_code = f"""
-response = requests.get('{plot.file_path}')
-response.raise_for_status()
-plot_json = json.loads(response.text)\n"""
+ plot_code = textwrap.dedent(
+ f"""
+ response = requests.get('{plot.file_path}')
+ response.raise_for_status()
+ plot_json = json.loads(response.text)\n"""
+ )
else: # If it's a local file
plot_rel_path = get_relative_file_path(plot.file_path)
- plot_code = f"""
-with open('{plot_rel_path.as_posix()}', 'r') as plot_file:
- plot_json = json.load(plot_file)\n"""
+ plot_code = textwrap.dedent(
+ f"""
+ with open('{plot_rel_path.as_posix()}', 'r') as plot_file:
+ plot_json = json.load(plot_file)\n"""
+ )
# Add specific code for each visualization tool
if plot.plot_type == r.PlotType.PLOTLY:
- plot_code += """
-# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
-# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-st.plotly_chart(plot_json, use_container_width=True)\n"""
+ plot_code += textwrap.dedent(
+ """
+ # Keep only 'data' and 'layout' sections
+ plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']}
+
+ # Remove 'frame' section in 'data'
+ plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])]
+ st.plotly_chart(plot_json, use_container_width=True)\n"""
+ )
elif plot.plot_type == r.PlotType.ALTAIR:
- plot_code += """
-altair_plot = alt.Chart.from_dict(plot_json)
-st.vega_lite_chart(json.loads(altair_plot.to_json()), use_container_width=True)\n"""
+ plot_code += textwrap.dedent(
+ """
+ altair_plot = alt.Chart.from_dict(plot_json)
+ st.vega_lite_chart(json.loads(altair_plot.to_json()),
+ use_container_width=True)\n"""
+ )
elif plot.plot_type == r.PlotType.INTERACTIVE_NETWORK:
- plot_code = """# Streamlit checkbox for controlling the layout
-control_layout = st.checkbox('Add panel to control layout', value=True)
-net_html_height = 1200 if control_layout else 630
-# Load HTML into HTML component for display on Streamlit
-st.components.v1.html(html_content, height=net_html_height)\n"""
+ plot_code = textwrap.dedent(
+ """\
+ # Streamlit checkbox for controlling the layout
+ control_layout = st.checkbox('Add panel to control layout', value=True)
+ net_html_height = 1200 if control_layout else 630
+ # Load HTML into HTML component for display on Streamlit
+ st.components.v1.html(html_content, height=net_html_height)\n"""
+ )
return plot_code
def _generate_dataframe_content(self, dataframe) -> List[str]:
@@ -796,7 +834,8 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
textwrap.dedent(
f"""\
sheet_names = table_utils.get_sheet_names("{dataframe.file_path}")
- selected_sheet = st.selectbox("Select a sheet to display", options=sheet_names)
+ selected_sheet = st.selectbox("Select a sheet to display",
+ options=sheet_names)
"""
)
)
@@ -818,26 +857,35 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
# ! Alternative to select box: iterate over sheets in DataFrame
# Displays a DataFrame using AgGrid with configurable options.
dataframe_content.append(
- """
-# Displays a DataFrame using AgGrid with configurable options.
-grid_builder = GridOptionsBuilder.from_dataframe(df)
-grid_builder.configure_default_column(editable=True, groupable=True, filter=True)
-grid_builder.configure_side_bar(filters_panel=True, columns_panel=True)
-grid_builder.configure_selection(selection_mode="multiple")
-grid_builder.configure_pagination(enabled=True, paginationAutoPageSize=False, paginationPageSize=20)
-grid_options = grid_builder.build()
-
-AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
-
-# Button to download the df
-df_csv = df.to_csv(sep=',', header=True, index=False).encode('utf-8')
-st.download_button(
- label="Download dataframe as CSV",
- data=df_csv,
- file_name=f"dataframe_{df_index}.csv",
- mime='text/csv',
- key=f"download_button_{df_index}")
-df_index += 1"""
+ textwrap.dedent(
+ """
+ # Displays a DataFrame using AgGrid with configurable options.
+ grid_builder = GridOptionsBuilder.from_dataframe(df)
+ grid_builder.configure_default_column(editable=True,
+ groupable=True,
+ filter=True,
+ )
+ grid_builder.configure_side_bar(filters_panel=True,
+ columns_panel=True)
+ grid_builder.configure_selection(selection_mode="multiple")
+ grid_builder.configure_pagination(enabled=True,
+ paginationAutoPageSize=False,
+ paginationPageSize=20,
+ )
+ grid_options = grid_builder.build()
+
+ AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
+
+ # Button to download the df
+ df_csv = df.to_csv(sep=',', header=True, index=False).encode('utf-8')
+ st.download_button(
+ label="Download dataframe as CSV",
+ data=df_csv,
+ file_name=f"dataframe_{df_index}.csv",
+ mime='text/csv',
+ key=f"download_button_{df_index}")
+ df_index += 1"""
+ )
)
except Exception as e:
self.report.logger.error(
From a0c4ca2cd71e5483c9b09ec0bd8f31eaa51069bc Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 19 Jun 2025 12:57:36 +0200
Subject: [PATCH 10/41] :bug: with textwrap the text cannot contain new line
statements
---
src/vuegen/streamlit_reportview.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index 9cb7263..46c3bb3 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -365,7 +365,6 @@ def _format_text(
str
A formatted markdown string for the specified text.
"""
- tag = ""
if type == "header":
tag = f"h{level}"
elif type == "paragraph" or type == "caption":
@@ -374,6 +373,9 @@ def _format_text(
raise ValueError(
f"Unsupported text type: {type}. Supported types are 'header', "
"'paragraph', and 'caption'."
+ )
+
+ text = text.strip() # get rid of new lines
return textwrap.dedent(
f"""
From 05b0d98a3e5fa32c8c50f85f035891e4594a3e4b Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Fri, 20 Jun 2025 09:56:27 +0200
Subject: [PATCH 11/41] :art: adjust comments and docstrings to line-length
---
src/vuegen/report.py | 55 +++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 19 deletions(-)
diff --git a/src/vuegen/report.py b/src/vuegen/report.py
index 55aab67..1d24162 100644
--- a/src/vuegen/report.py
+++ b/src/vuegen/report.py
@@ -87,15 +87,17 @@ def value_with_dot(self):
@dataclass
class Component:
"""
- Base class for different components in a report subsection. It encapsulates elements like
- plots, dataframes, markdown, or apicalls, providing a consistent structure for report generation.
+ Base class for different components in a report subsection. It encapsulates elements
+ like plots, dataframes, markdown, or apicalls,
+ providing a consistent structure for report generation.
Attributes
----------
_id_counter : ClassVar[int]
Class-level counter for unique IDs.
id : int
- Unique identifier for the component, assigned automatically when an object is created.
+ Unique identifier for the component, assigned automatically
+ when an object is created.
title : str
Title of the component.
component_type : ComponentType
@@ -103,7 +105,8 @@ class Component:
logger : logging.Logger
Logger object for tracking warnings, errors, and info messages.
file_path : Optional[str]
- Path to the file associated with the component (e.g., plot JSON file, image file, csv file, etc.).
+ Path to the file associated with the component
+ (e.g., plot JSON file, image file, csv file, etc.).
caption : Optional[str]
Caption providing additional context about the component (default: None).
"""
@@ -134,7 +137,8 @@ class Plot(Component):
plot_type : PlotType
The type of the plot (INTERACTIVE or STATIC).
csv_network_format : CSVNetworkFormat, optional
- The format of the CSV file for network plots (EDGELIST or ADJLIST) (default is None).
+ The format of the CSV file for network plots (EDGELIST or ADJLIST)
+ (default is None).
"""
def __init__(
@@ -265,7 +269,8 @@ def read_network(self) -> nx.Graph:
f"Unsupported format for CSV/TXT file: {self.csv_network_format}."
)
- # Handle other formats using the mapping and return the NetworkX graph object from the specified network file
+ # Handle other formats using the mapping and return the NetworkX graph object
+ # from the specified network file
G = file_extension_map[file_extension](file_stream)
G = self._add_size_attribute(G)
self.logger.info(f"Successfully read network from file: {self.file_path}.")
@@ -393,7 +398,8 @@ def create_and_save_pyvis_network(self, G: nx.Graph, output_file: str) -> Networ
def _add_size_attribute(self, G: nx.Graph) -> nx.Graph:
"""
- Adds a 'size' attribute to the nodes of a NetworkX graph based on their degree centrality.
+ Adds a 'size' attribute to the nodes of a NetworkX graph
+ based on their degree centrality.
Parameters
----------
@@ -445,9 +451,11 @@ class DataFrame(Component):
Attributes
----------
file_format : DataFrameFormat
- The format of the file from which the DataFrame is loaded (e.g., CSV, TXT, PARQUET).
+ The format of the file from which the DataFrame is loaded
+ (e.g., CSV, TXT, PARQUET).
delimiter : Optional[str]
- The delimiter to use if the file is a delimited text format (e.g., ';', '\t', etc).
+ The delimiter to use if the file is a delimited text format
+ (e.g., ';', '\t', etc).
"""
def __init__(
@@ -530,7 +538,8 @@ class APICall(Component):
api_url : str
The URL of the API to interact with.
method : str
- HTTP method to use for the request ("GET", "POST", or "PUT"). The deafult is "GET".
+ HTTP method to use for the request ("GET", "POST", or "PUT").
+ The deafult is "GET".
headers : Optional[dict]
Headers to include in the API request (default is None).
params : Optional[dict]
@@ -617,12 +626,14 @@ def make_api_request(
class ChatBot(Component):
"""
A component for creating a ChatBot that interacts with an API.
- This component uses an APICall instance to send requests to the chatbot API and receive responses.
+ This component uses an APICall instance to send requests
+ to the chatbot API and receive responses.
Attributes
----------
api_call : APICall
- An instance of the APICall class used to interact with the API for fetching chatbot responses.
+ An instance of the APICall class used to interact
+ with the API for fetching chatbot responses.
model : Optional[str]
The language model to use for the chatbot (default is None).
headers : Optional[dict]
@@ -670,7 +681,8 @@ class Subsection:
_id_counter : ClassVar[int]
Class-level counter for unique IDs.
id : int
- Unique identifier for the subsection, assigned automatically when an object is created.
+ Unique identifier for the subsection, assigned automatically
+ when an object is created.
title : str
Title of the subsection.
components : List[Component]
@@ -709,7 +721,8 @@ class Section:
_id_counter : ClassVar[int]
Class-level counter for unique IDs.
id : int
- Unique identifier for the section, assigned automatically when an object is created.
+ Unique identifier for the section, assigned automatically
+ when an object is created.
title : str
Title of the section.
subsections : List[Subsection]
@@ -798,7 +811,8 @@ def generate_report(self, output_dir: str = "sections") -> None:
Parameters
----------
output_dir : str, optional
- The folder where the generated report files will be saved (default is 'sections').
+ The folder where the generated report files will be saved
+ (default is 'sections').
"""
pass
@@ -822,7 +836,8 @@ def _generate_component_imports(self) -> str:
Parameters
----------
component : r.Component
- The component for which to generate the required imports. The component can be of type:
+ The component for which to generate the required imports.
+ The component can be of type:
- PLOT
- DATAFRAME
- MARKDOWN
@@ -852,7 +867,8 @@ def _format_text(self, text: str, type: str, level: int, color: str) -> str:
type : str
The type of the text (e.g., 'header', 'paragraph').
level : int, optional
- If the text is a header, the level of the header (e.g., 1 for h1, 2 for h2, etc.).
+ If the text is a header, the level of the header
+ (e.g., 1 for h1, 2 for h2, etc.).
color : str, optional
The color of the header text.
@@ -884,8 +900,9 @@ def _generate_subsection(
self, subsection: Subsection
) -> tuple[List[str], List[str]]:
"""
- Generate code to render components (plots, dataframes, markdown) in the given subsection,
- creating imports and content for the subsection based on the component type.
+ Generate code to render components (plots, dataframes, markdown) in the given
+ subsection, creating imports and content for the subsection based on
+ the component type.
Parameters
----------
From f7f26d350fff2a320824125ab04ce048563bdd6e Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Fri, 20 Jun 2025 09:57:12 +0200
Subject: [PATCH 12/41] :wrench: add jupytext configuration for notebooks to
project
---
pyproject.toml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pyproject.toml b/pyproject.toml
index 7a886d1..961cc90 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -74,3 +74,6 @@ vuegen = "vuegen.__main__:main"
[tool.isort]
profile = "black"
+
+[tool.jupytext]
+formats = "ipynb,py:percent"
From 1d9855ef913fccb1aa2a041bbdb5a48dade1747d Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Wed, 25 Jun 2025 14:42:02 +0200
Subject: [PATCH 13/41] =?UTF-8?q?=E2=9C=85=20update=20example=20report=20f?=
=?UTF-8?q?iles=20so=20test=20pass=20(reviewed=20changes=20are=20only=20st?=
=?UTF-8?q?yle=20of=20.py=20files)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/vuegen/streamlit_reportview.py | 4 +-
.../sections/Dataframes/All_Formats.py | 119 ++++++++++++++----
.../sections/Home/Homepage.py | 10 +-
.../sections/Html/All_Html.py | 44 ++++++-
.../sections/Markdown/All_Markdown.py | 18 ++-
.../sections/Networks/Interactive_Networks.py | 45 +++++--
.../sections/Networks/Static_Networks.py | 20 ++-
.../sections/Plots/Interactive_Plots.py | 112 ++++++++++++++---
.../sections/Plots/Static_Plots.py | 42 +++++--
.../sections/report_manager.py | 18 ++-
10 files changed, 358 insertions(+), 74 deletions(-)
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index ea63b09..f7a7fca 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -678,10 +678,10 @@ def _generate_plot_content(self, plot) -> List[str]:
textwrap.dedent(
f"""
st.markdown((" "
- f"Number of nodes: {num_nodes}
"),
+ "Number of nodes: {num_nodes}
"),
unsafe_allow_html=True)
st.markdown((""
- f" Number of relationships: {num_edges}
"),
+ " Number of relationships: {num_edges} "),
unsafe_allow_html=True)
"""
)
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Dataframes/All_Formats.py b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Dataframes/All_Formats.py
index 5d60849..1c70f5d 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Dataframes/All_Formats.py
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Dataframes/All_Formats.py
@@ -4,17 +4,38 @@
import streamlit as st
df_index = 1
-st.markdown('''All Formats
''', unsafe_allow_html=True)
-st.markdown('''Phyla Correlation Network Csv
''', unsafe_allow_html=True)
+
+st.markdown(
+ (
+ "All Formats
"
+ ),
+ unsafe_allow_html=True)
+
+
+st.markdown(
+ (
+ "Phyla Correlation Network Csv
"
+ ),
+ unsafe_allow_html=True)
+
df = pd.read_csv('docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/1_phyla_correlation_network_csv.csv')
# Displays a DataFrame using AgGrid with configurable options.
grid_builder = GridOptionsBuilder.from_dataframe(df)
-grid_builder.configure_default_column(editable=True, groupable=True, filter=True)
-grid_builder.configure_side_bar(filters_panel=True, columns_panel=True)
+grid_builder.configure_default_column(editable=True,
+ groupable=True,
+ filter=True,
+)
+grid_builder.configure_side_bar(filters_panel=True,
+ columns_panel=True)
grid_builder.configure_selection(selection_mode="multiple")
-grid_builder.configure_pagination(enabled=True, paginationAutoPageSize=False, paginationPageSize=20)
+grid_builder.configure_pagination(enabled=True,
+ paginationAutoPageSize=False,
+ paginationPageSize=20,
+)
grid_options = grid_builder.build()
AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
@@ -28,7 +49,14 @@
mime='text/csv',
key=f"download_button_{df_index}")
df_index += 1
-st.markdown('''Abundance Table Example Xls
''', unsafe_allow_html=True)
+
+st.markdown(
+ (
+ "Abundance Table Example Xls
"
+ ),
+ unsafe_allow_html=True)
+
selected_sheet = 0
sheet_names = table_utils.get_sheet_names("docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/2_abundance_table_example_xls.xls")
selected_sheet = st.selectbox("Select a sheet to display", options=sheet_names)
@@ -38,10 +66,17 @@
# Displays a DataFrame using AgGrid with configurable options.
grid_builder = GridOptionsBuilder.from_dataframe(df)
-grid_builder.configure_default_column(editable=True, groupable=True, filter=True)
-grid_builder.configure_side_bar(filters_panel=True, columns_panel=True)
+grid_builder.configure_default_column(editable=True,
+ groupable=True,
+ filter=True,
+)
+grid_builder.configure_side_bar(filters_panel=True,
+ columns_panel=True)
grid_builder.configure_selection(selection_mode="multiple")
-grid_builder.configure_pagination(enabled=True, paginationAutoPageSize=False, paginationPageSize=20)
+grid_builder.configure_pagination(enabled=True,
+ paginationAutoPageSize=False,
+ paginationPageSize=20,
+)
grid_options = grid_builder.build()
AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
@@ -55,16 +90,30 @@
mime='text/csv',
key=f"download_button_{df_index}")
df_index += 1
-st.markdown('''Sample Info Example Txt
''', unsafe_allow_html=True)
+
+st.markdown(
+ (
+ "Sample Info Example Txt
"
+ ),
+ unsafe_allow_html=True)
+
df = pd.read_table('docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/3_sample_info_example_txt.txt')
# Displays a DataFrame using AgGrid with configurable options.
grid_builder = GridOptionsBuilder.from_dataframe(df)
-grid_builder.configure_default_column(editable=True, groupable=True, filter=True)
-grid_builder.configure_side_bar(filters_panel=True, columns_panel=True)
+grid_builder.configure_default_column(editable=True,
+ groupable=True,
+ filter=True,
+)
+grid_builder.configure_side_bar(filters_panel=True,
+ columns_panel=True)
grid_builder.configure_selection(selection_mode="multiple")
-grid_builder.configure_pagination(enabled=True, paginationAutoPageSize=False, paginationPageSize=20)
+grid_builder.configure_pagination(enabled=True,
+ paginationAutoPageSize=False,
+ paginationPageSize=20,
+)
grid_options = grid_builder.build()
AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
@@ -78,16 +127,30 @@
mime='text/csv',
key=f"download_button_{df_index}")
df_index += 1
-st.markdown('''Sample Info Example Parquet
''', unsafe_allow_html=True)
+
+st.markdown(
+ (
+ "Sample Info Example Parquet
"
+ ),
+ unsafe_allow_html=True)
+
df = pd.read_parquet('docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/4_sample_info_example_parquet.parquet')
# Displays a DataFrame using AgGrid with configurable options.
grid_builder = GridOptionsBuilder.from_dataframe(df)
-grid_builder.configure_default_column(editable=True, groupable=True, filter=True)
-grid_builder.configure_side_bar(filters_panel=True, columns_panel=True)
+grid_builder.configure_default_column(editable=True,
+ groupable=True,
+ filter=True,
+)
+grid_builder.configure_side_bar(filters_panel=True,
+ columns_panel=True)
grid_builder.configure_selection(selection_mode="multiple")
-grid_builder.configure_pagination(enabled=True, paginationAutoPageSize=False, paginationPageSize=20)
+grid_builder.configure_pagination(enabled=True,
+ paginationAutoPageSize=False,
+ paginationPageSize=20,
+)
grid_options = grid_builder.build()
AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
@@ -101,17 +164,31 @@
mime='text/csv',
key=f"download_button_{df_index}")
df_index += 1
-st.markdown('''Example Xlsx
''', unsafe_allow_html=True)
+
+st.markdown(
+ (
+ "Example Xlsx
"
+ ),
+ unsafe_allow_html=True)
+
selected_sheet = 0
df = pd.read_excel('docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/5_example_xlsx.xlsx', sheet_name=selected_sheet)
# Displays a DataFrame using AgGrid with configurable options.
grid_builder = GridOptionsBuilder.from_dataframe(df)
-grid_builder.configure_default_column(editable=True, groupable=True, filter=True)
-grid_builder.configure_side_bar(filters_panel=True, columns_panel=True)
+grid_builder.configure_default_column(editable=True,
+ groupable=True,
+ filter=True,
+)
+grid_builder.configure_side_bar(filters_panel=True,
+ columns_panel=True)
grid_builder.configure_selection(selection_mode="multiple")
-grid_builder.configure_pagination(enabled=True, paginationAutoPageSize=False, paginationPageSize=20)
+grid_builder.configure_pagination(enabled=True,
+ paginationAutoPageSize=False,
+ paginationPageSize=20,
+)
grid_options = grid_builder.build()
AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True)
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Home/Homepage.py b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Home/Homepage.py
index e35e50f..54b18c0 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Home/Homepage.py
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Home/Homepage.py
@@ -1,6 +1,12 @@
import streamlit as st
-st.markdown('''A general description of the report.
-
''', unsafe_allow_html=True)
+
+st.markdown(
+ (
+ "A general description of the report.
"
+ ),
+ unsafe_allow_html=True)
+
footer = '''
-include-after-body:
- text: |
- """,
- r.ReportType.PDF: """
- pdf:
- toc: false
- fig-align: center
- margin:
- - bottom=40mm
- include-in-header:
- text: |
- \\usepackage{scrlayer-scrpage}
- \\usepackage{hyperref}
- \\clearpairofpagestyles
- \\lofoot{This report was generated with \\href{https://github.com/Multiomics-Analytics-Group/vuegen}{VueGen} | \\copyright{} 2025 \\href{https://github.com/Multiomics-Analytics-Group}{Multiomics Network Analytics Group}}
- \\rofoot{\\pagemark}""",
- r.ReportType.DOCX: """
- docx:
- toc: false""",
- r.ReportType.ODT: """
- odt:
- toc: false""",
- r.ReportType.REVEALJS: """
- revealjs:
- toc: false
- smaller: true
- controls: true
- navigation-mode: vertical
- controls-layout: bottom-right
- output-file: quarto_report_revealjs.html
-include-in-header:
- text: |
-
-include-after-body:
- text: |
- """,
- r.ReportType.PPTX: """
- pptx:
- toc: false
- output: true""",
- r.ReportType.JUPYTER: """
- html:
- toc: true
- toc-location: left
- toc-depth: 3
- page-layout: full
- self-contained: true
-include-in-header:
- text: |
-
-include-after-body:
- text: |
- """,
+ r.ReportType.HTML: textwrap.dedent(
+ """
+ html:
+ toc: true
+ toc-location: left
+ toc-depth: 3
+ page-layout: full
+ self-contained: true
+ include-in-header:
+ text: |
+
+ include-after-body:
+ text: |
+ """
+ ),
+ r.ReportType.PDF: textwrap.indent(
+ textwrap.dedent(
+ """
+ pdf:
+ toc: false
+ fig-align: center
+ margin:
+ - bottom=40mm
+ include-in-header:
+ text: |
+ \\usepackage{scrlayer-scrpage}
+ \\usepackage{hyperref}
+ \\clearpairofpagestyles
+ \\lofoot{This report was generated with \\href{https://github.com/Multiomics-Analytics-Group/vuegen}{VueGen} | \\copyright{} 2025 \\href{https://github.com/Multiomics-Analytics-Group}{Multiomics Network Analytics Group}}
+ \\rofoot{\\pagemark}"""
+ ),
+ " ",
+ ),
+ r.ReportType.DOCX: textwrap.indent(
+ textwrap.dedent(
+ """
+ docx:
+ toc: false"""
+ ),
+ " ",
+ ),
+ r.ReportType.ODT: textwrap.indent(
+ textwrap.dedent(
+ """
+ odt:
+ toc: false"""
+ ),
+ " ",
+ ),
+ r.ReportType.REVEALJS: textwrap.dedent(
+ """
+ revealjs:
+ toc: false
+ smaller: true
+ controls: true
+ navigation-mode: vertical
+ controls-layout: bottom-right
+ output-file: quarto_report_revealjs.html
+ include-in-header:
+ text: |
+
+ include-after-body:
+ text: |
+ """
+ ),
+ r.ReportType.PPTX: textwrap.indent(
+ textwrap.dedent(
+ """
+ pptx:
+ toc: false
+ output: true"""
+ ),
+ " ",
+ ),
+ r.ReportType.JUPYTER: textwrap.dedent(
+ """
+ html:
+ toc: true
+ toc-location: left
+ toc-depth: 3
+ page-layout: full
+ self-contained: true
+ include-in-header:
+ text: |
+
+ include-after-body:
+ text: |
+ """
+ ),
}
# Create a key based on the report type and format
key = self.report_type
@@ -632,41 +660,57 @@ def _generate_plot_code(self, plot, output_file="") -> str:
The generated plot code as a string.
"""
# Initialize plot code with common structure
- plot_code = f"""```{{python}}
-#| label: '{plot.title} {plot.id}'
-#| fig-cap: ""
-"""
+ plot_code = textwrap.dedent(
+ f"""
+ ```{{python}}
+ #| label: '{plot.title} {plot.id}'
+ #| fig-cap: ""
+ """
+ )
# If the file path is a URL, generate code to fetch content via requests
if is_url(plot.file_path):
- plot_code += f"""
-response = requests.get('{plot.file_path}')
-response.raise_for_status()
-plot_json = response.text\n"""
+ plot_code += textwrap.dedent(
+ f"""
+ response = requests.get('{plot.file_path}')
+ response.raise_for_status()
+ plot_json = response.text
+ """
+ )
else: # If it's a local file
plot_rel_path = get_relative_file_path(
plot.file_path, relative_to=self.output_dir
).as_posix()
- plot_code += f"""
+ plot_code += textwrap.dedent(
+ f"""
with open(report_dir /'{plot_rel_path}', 'r') as plot_file:
- plot_json = json.load(plot_file)\n"""
+ plot_json = json.load(plot_file)
+"""
+ )
# Add specific code for each visualization tool
if plot.plot_type == r.PlotType.PLOTLY:
- plot_code += """
-# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}\n
-# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]\n
-# Convert JSON to string
-plot_json_str = json.dumps(plot_json)\n
-# Create the plotly plot
-fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))\n"""
+ plot_code += textwrap.dedent(
+ """
+ # Keep only 'data' and 'layout' sections
+ plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}\n
+ # Remove 'frame' section in 'data'
+ plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]\n
+ # Convert JSON to string
+ plot_json_str = json.dumps(plot_json)\n
+ # Create the plotly plot
+ fig_plotly = pio.from_json(plot_json_str)
+ fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+ """
+ )
elif plot.plot_type == r.PlotType.ALTAIR:
- plot_code += """
-# Convert JSON to string
-plot_json_str = json.dumps(plot_json)\n
-# Create the plotly plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)\n"""
+ plot_code += textwrap.dedent(
+ """
+ # Convert JSON to string
+ plot_json_str = json.dumps(plot_json)
+
+ # Create the altair plot
+ fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+ """
+ )
elif plot.plot_type == r.PlotType.INTERACTIVE_NETWORK:
# Generate the HTML embedding for interactive networks
if is_url(plot.file_path) and plot.file_path.endswith(".html"):
@@ -677,10 +721,13 @@ def _generate_plot_code(self, plot, output_file="") -> str:
)
# Embed the HTML file in an iframe
- plot_code = f"""
-
-
-
\n"""
+ plot_code = textwrap.dedent(
+ f"""
+
+
+
+ """
+ )
return plot_code
def _generate_dataframe_content(self, dataframe) -> List[str]:
@@ -942,10 +989,14 @@ def _generate_html_content(self, html) -> List[str]:
html_file_path = get_relative_file_path(
html.file_path, relative_to=self.output_dir
)
- iframe_code = f"""
-
-
-
\n"""
+ iframe_code = textwrap.dedent(
+ f"""
+
+
+
+ """
+ )
html_content.append(iframe_code)
except Exception as e:
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd
index 8136c42..fe88ba3 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd
@@ -33,6 +33,7 @@ Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -59,6 +60,7 @@ fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
{fig-alt= width=90%}
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -69,7 +71,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
@@ -78,6 +80,7 @@ fig_altair.save("static/Multiline_Plot_Altair.png")
{fig-alt= width=90%}
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -104,6 +107,7 @@ fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
{fig-alt= width=90%}
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -130,6 +134,7 @@ fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
{fig-alt= width=90%}
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -140,7 +145,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
@@ -149,6 +154,7 @@ fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
{fig-alt= width=90%}
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
index 415e2fb..b3bcc23 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
@@ -58,6 +58,7 @@ Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -82,6 +83,7 @@ fig_plotly.show()
```
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -92,13 +94,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -123,6 +126,7 @@ fig_plotly.show()
```
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -147,6 +151,7 @@ fig_plotly.show()
```
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -157,13 +162,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
@@ -283,7 +289,8 @@ Optional description for subsection.
### Plot
-
+
### Ckg Network
@@ -299,7 +306,8 @@ Optional description for subsection.
### Multiqc Report
-
+
# Markdown
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
index 15a5be4..9ef1dce 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
@@ -58,6 +58,7 @@ Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -82,6 +83,7 @@ fig_plotly.show()
```
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -92,13 +94,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -123,6 +126,7 @@ fig_plotly.show()
```
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -147,6 +151,7 @@ fig_plotly.show()
```
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -157,13 +162,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
@@ -283,7 +289,8 @@ Optional description for subsection.
### Plot
-
+
### Ckg Network
@@ -299,7 +306,8 @@ Optional description for subsection.
### Multiqc Report
-
+
# Markdown
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd
index 8bcea9d..d8353b9 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd
@@ -33,6 +33,7 @@ Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -59,6 +60,7 @@ fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
{fig-alt= width=90%}
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -69,7 +71,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
@@ -78,6 +80,7 @@ fig_altair.save("static/Multiline_Plot_Altair.png")
{fig-alt= width=90%}
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -104,6 +107,7 @@ fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
{fig-alt= width=90%}
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -130,6 +134,7 @@ fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
{fig-alt= width=90%}
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -140,7 +145,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
@@ -149,6 +154,7 @@ fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
{fig-alt= width=90%}
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
index 17900ea..d4e5d09 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
@@ -43,6 +43,7 @@ Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -69,6 +70,7 @@ fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
{fig-alt= width=90%}
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -79,7 +81,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
@@ -88,6 +90,7 @@ fig_altair.save("static/Multiline_Plot_Altair.png")
{fig-alt= width=90%}
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -114,6 +117,7 @@ fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
{fig-alt= width=90%}
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -140,6 +144,7 @@ fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
{fig-alt= width=90%}
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -150,7 +155,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
@@ -159,6 +164,7 @@ fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
{fig-alt= width=90%}
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd
index a7db1d1..05d9afe 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd
@@ -34,6 +34,7 @@ Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -60,6 +61,7 @@ fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
{fig-alt= width=90%}
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -70,7 +72,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
@@ -79,6 +81,7 @@ fig_altair.save("static/Multiline_Plot_Altair.png")
{fig-alt= width=90%}
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -105,6 +108,7 @@ fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
{fig-alt= width=90%}
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -131,6 +135,7 @@ fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
{fig-alt= width=90%}
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -141,7 +146,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
@@ -150,6 +155,7 @@ fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
{fig-alt= width=90%}
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
index d3ba678..8ace56f 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
@@ -61,6 +61,7 @@ Optional description for section.
::: {.panel-tabset}
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -85,6 +86,7 @@ fig_plotly.show()
```
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -95,13 +97,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -126,6 +129,7 @@ fig_plotly.show()
```
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -150,6 +154,7 @@ fig_plotly.show()
```
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -160,13 +165,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Plotly Plot R
+
```{python}
#| label: 'Plotly Plot R 6'
#| fig-cap: ""
@@ -306,7 +312,8 @@ Optional description for subsection.
### Plot
-
+
### Ckg Network
@@ -322,7 +329,8 @@ Optional description for subsection.
### Multiqc Report
-
+
:::
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
index 54cb87e..e75c635 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
@@ -60,6 +60,7 @@ This section contains example plots.
Optional description for section.
### Top Species Plot By Biome Plotly
+
```{python}
#| label: 'Top Species Plot By Biome Plotly 1'
#| fig-cap: ""
@@ -84,6 +85,7 @@ fig_plotly.show()
```
### Multiline Plot Altair
+
```{python}
#| label: 'Multiline Plot Altair 2'
#| fig-cap: ""
@@ -94,13 +96,14 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
```
### Pie Plot Countries Plotly
+
```{python}
#| label: 'Pie Plot Countries Plotly 3'
#| fig-cap: ""
@@ -125,6 +128,7 @@ fig_plotly.show()
```
### Pie Plots Biomes Plotly
+
```{python}
#| label: 'Pie Plots Biomes Plotly 4'
#| fig-cap: ""
@@ -149,6 +153,7 @@ fig_plotly.show()
```
### Saline Metagenomics Samples Map Altair
+
```{python}
#| label: 'Saline Metagenomics Samples Map Altair 5'
#| fig-cap: ""
@@ -159,7 +164,7 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-# Create the plotly plot
+# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
fig_altair
@@ -257,7 +262,8 @@ Optional description for subsection
### Plot
-
+
### Ckg Network
@@ -273,7 +279,8 @@ Optional description for subsection
### Multiqc Report
-
+
# Markdown
From 206deab652bfaf0e26e0eef988c743360ea87dd1 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Wed, 25 Jun 2025 17:06:51 +0200
Subject: [PATCH 20/41] :art: keep urls at the top
- maybe 'Verschlimmbessern': footer can be hard to read (pdf)
- needed to use escaping of {} using unicode:
\u007b is { and \u007d is }
- :bug: jupyter used relative import -> changed to URL link of LOGO
- unify MONA mentioning (pdf)
---
src/vuegen/quarto_reportview.py | 64 ++++++++++++-------
.../html/quarto_report/quarto_report.qmd | 3 +-
.../jupyter/quarto_report/quarto_report.qmd | 7 +-
.../pdf/quarto_report/quarto_report.qmd | 4 +-
.../revealjs/quarto_report/quarto_report.qmd | 3 +-
.../html/quarto_report/quarto_report.qmd | 3 +-
6 files changed, 54 insertions(+), 30 deletions(-)
diff --git a/src/vuegen/quarto_reportview.py b/src/vuegen/quarto_reportview.py
index 21cda55..d2aeaa0 100644
--- a/src/vuegen/quarto_reportview.py
+++ b/src/vuegen/quarto_reportview.py
@@ -1,3 +1,5 @@
+"""QuartoReportView class for generating Quarto reports."""
+
import os
import subprocess
import sys
@@ -11,6 +13,15 @@
from . import table_utils
from .utils import create_folder, get_relative_file_path, is_url, sort_imports
+GITHUB_ORG_URL = "https://github.com/Multiomics-Analytics-Group"
+ORG = "Multiomics Network Analytics Group (MoNA)"
+GITHUB_ORG_URL_BRACKETS = "{https://github.com/Multiomics-Analytics-Group}"
+REPO_URL = "https://github.com/Multiomics-Analytics-Group/vuegen"
+LOGO_URL = (
+ "https://raw.githubusercontent.com/Multiomics-Analytics-Group/"
+ "vuegen/main/docs/images/vuegen_logo.svg"
+)
+
class QuartoReportView(r.ReportView):
"""
@@ -321,9 +332,10 @@ def _create_yaml_header(self) -> str:
format:"""
)
# Define format-specific YAML configurations
+ # \u007b is { and \u007d is }
format_configs = {
r.ReportType.HTML: textwrap.dedent(
- """
+ f"""
html:
toc: true
toc-location: left
@@ -333,27 +345,29 @@ def _create_yaml_header(self) -> str:
include-in-header:
text: |
include-after-body:
text: |
"""
),
+ # \u007b is { and \u007d is }
r.ReportType.PDF: textwrap.indent(
textwrap.dedent(
- """
+ f"""
pdf:
toc: false
fig-align: center
@@ -361,11 +375,13 @@ def _create_yaml_header(self) -> str:
- bottom=40mm
include-in-header:
text: |
- \\usepackage{scrlayer-scrpage}
- \\usepackage{hyperref}
+ \\usepackage{{scrlayer-scrpage}}
+ \\usepackage{{hyperref}}
\\clearpairofpagestyles
- \\lofoot{This report was generated with \\href{https://github.com/Multiomics-Analytics-Group/vuegen}{VueGen} | \\copyright{} 2025 \\href{https://github.com/Multiomics-Analytics-Group}{Multiomics Network Analytics Group}}
- \\rofoot{\\pagemark}"""
+ \\lofoot\u007bThis report was generated with
+ \\href{{{REPO_URL}}}{{VueGen}} | \\copyright{{}} 2025
+ \\href{GITHUB_ORG_URL_BRACKETS}\u007b{ORG}\u007d\u007d
+ \\rofoot{{\\pagemark}}"""
),
" ",
),
@@ -386,7 +402,7 @@ def _create_yaml_header(self) -> str:
" ",
),
r.ReportType.REVEALJS: textwrap.dedent(
- """
+ f"""
revealjs:
toc: false
smaller: true
@@ -397,22 +413,23 @@ def _create_yaml_header(self) -> str:
include-in-header:
text: |
include-after-body:
text: |
"""
),
r.ReportType.PPTX: textwrap.indent(
@@ -425,7 +442,7 @@ def _create_yaml_header(self) -> str:
" ",
),
r.ReportType.JUPYTER: textwrap.dedent(
- """
+ f"""
html:
toc: true
toc-location: left
@@ -435,22 +452,23 @@ def _create_yaml_header(self) -> str:
include-in-header:
text: |
include-after-body:
text: |
"""
),
}
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
index b3bcc23..3c962fe 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
@@ -30,7 +30,8 @@ include-after-body:
- | Copyright 2025 Multiomics Network Analytics Group (MoNA)
+ | Copyright 2025
+ Multiomics Network Analytics Group (MoNA)
---
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
index 9ef1dce..642d2d9 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
@@ -21,16 +21,17 @@ include-in-header:
width: 100%;
text-align: center;
margin-top: 20px;
- }
+ }
include-after-body:
text: |
---
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
index d4e5d09..5bc0532 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
@@ -16,7 +16,9 @@ format:
\usepackage{scrlayer-scrpage}
\usepackage{hyperref}
\clearpairofpagestyles
- \lofoot{This report was generated with \href{https://github.com/Multiomics-Analytics-Group/vuegen}{VueGen} | \copyright{} 2025 \href{https://github.com/Multiomics-Analytics-Group}{Multiomics Network Analytics Group}}
+ \lofoot{This report was generated with
+ \href{https://github.com/Multiomics-Analytics-Group/vuegen}{VueGen} | \copyright{} 2025
+ \href{https://github.com/Multiomics-Analytics-Group}{Multiomics Network Analytics Group (MoNA)}}
\rofoot{\pagemark}
---
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
index 8ace56f..6e6e974 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
@@ -31,7 +31,8 @@ include-after-body:
- | Copyright 2025 Multiomics Network Analytics Group (MoNA)
+ | Copyright 2025 Multiomics Network Analytics Group (MoNA)
---
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
index e75c635..06de8a5 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
@@ -30,7 +30,8 @@ include-after-body:
- | Copyright 2025 Multiomics Network Analytics Group (MoNA)
+ | Copyright 2025
+ Multiomics Network Analytics Group (MoNA)
---
From ed1132d11bb549555f27479ddb65e4f6cc88c585 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Wed, 25 Jun 2025 17:18:14 +0200
Subject: [PATCH 21/41] :art: limit remaining lines to 90 characters
---
src/vuegen/quarto_reportview.py | 21 ++++--
.../docx/quarto_report/quarto_report.qmd | 66 ++++++++++-------
.../html/quarto_report/quarto_report.qmd | 74 ++++++++++++-------
.../jupyter/quarto_report/quarto_report.qmd | 74 ++++++++++++-------
.../odt/quarto_report/quarto_report.qmd | 66 ++++++++++-------
.../pdf/quarto_report/quarto_report.qmd | 66 ++++++++++-------
.../pptx/quarto_report/quarto_report.qmd | 66 ++++++++++-------
.../revealjs/quarto_report/quarto_report.qmd | 74 ++++++++++++-------
.../html/quarto_report/quarto_report.qmd | 59 +++++++++------
9 files changed, 350 insertions(+), 216 deletions(-)
diff --git a/src/vuegen/quarto_reportview.py b/src/vuegen/quarto_reportview.py
index d2aeaa0..e9d7dea 100644
--- a/src/vuegen/quarto_reportview.py
+++ b/src/vuegen/quarto_reportview.py
@@ -709,14 +709,20 @@ def _generate_plot_code(self, plot, output_file="") -> str:
plot_code += textwrap.dedent(
"""
# Keep only 'data' and 'layout' sections
- plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}\n
+ plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
- plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]\n
+ plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
- plot_json_str = json.dumps(plot_json)\n
+ plot_json_str = json.dumps(plot_json)
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
- fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+ fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
"""
)
elif plot.plot_type == r.PlotType.ALTAIR:
@@ -726,7 +732,8 @@ def _generate_plot_code(self, plot, output_file="") -> str:
plot_json_str = json.dumps(plot_json)
# Create the altair plot
- fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+ fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
"""
)
elif plot.plot_type == r.PlotType.INTERACTIVE_NETWORK:
@@ -742,7 +749,9 @@ def _generate_plot_code(self, plot, output_file="") -> str:
plot_code = textwrap.dedent(
f"""
-
+
"""
)
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd
index fe88ba3..2201667 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/docx/quarto_report/quarto_report.qmd
@@ -42,17 +42,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
```
@@ -72,7 +75,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
```
@@ -89,17 +93,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
```
@@ -116,17 +123,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
```
@@ -146,7 +156,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
```
@@ -163,17 +174,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Plotly_Plot_R.png")
```
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
index 3c962fe..0a3a5e3 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/html/quarto_report/quarto_report.qmd
@@ -68,17 +68,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -96,7 +99,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -111,17 +115,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -136,17 +143,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -164,7 +174,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -179,17 +190,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -278,7 +292,9 @@ Optional description for subsection.
-
+
## Static Networks
@@ -301,7 +317,9 @@ Optional description for subsection.
-
+
### Multiqc Report
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
index 642d2d9..c9e6638 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/jupyter/quarto_report/quarto_report.qmd
@@ -68,17 +68,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -96,7 +99,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -111,17 +115,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -136,17 +143,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -164,7 +174,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -179,17 +190,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -278,7 +292,9 @@ Optional description for subsection.
-
+
## Static Networks
@@ -301,7 +317,9 @@ Optional description for subsection.
-
+
### Multiqc Report
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd
index d8353b9..bc4151c 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/odt/quarto_report/quarto_report.qmd
@@ -42,17 +42,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
```
@@ -72,7 +75,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
```
@@ -89,17 +93,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
```
@@ -116,17 +123,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
```
@@ -146,7 +156,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
```
@@ -163,17 +174,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Plotly_Plot_R.png")
```
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
index 5bc0532..edf136b 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/pdf/quarto_report/quarto_report.qmd
@@ -54,17 +54,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
```
@@ -84,7 +87,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
```
@@ -101,17 +105,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
```
@@ -128,17 +135,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
```
@@ -158,7 +168,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
```
@@ -175,17 +186,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Plotly_Plot_R.png")
```
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd
index 05d9afe..29d2c4f 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/pptx/quarto_report/quarto_report.qmd
@@ -43,17 +43,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Top_Species_Plot_By_Biome_Plotly.png")
```
@@ -73,7 +76,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Multiline_Plot_Altair.png")
```
@@ -90,17 +94,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plot_Countries_Plotly.png")
```
@@ -117,17 +124,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Pie_Plots_Biomes_Plotly.png")
```
@@ -147,7 +157,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair.save("static/Saline_Metagenomics_Samples_Map_Altair.png")
```
@@ -164,17 +175,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.write_image("static/Plotly_Plot_R.png")
```
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
index 6e6e974..23328cc 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/revealjs/quarto_report/quarto_report.qmd
@@ -71,17 +71,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -99,7 +102,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -114,17 +118,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -139,17 +146,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -167,7 +177,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -182,17 +193,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -293,7 +307,9 @@ Optional description for subsection.
-
+
:::
@@ -324,7 +340,9 @@ Optional description for subsection.
-
+
### Multiqc Report
diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
index 06de8a5..121e2d2 100644
--- a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
+++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/html/quarto_report/quarto_report.qmd
@@ -70,17 +70,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -98,7 +101,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -113,17 +117,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -138,17 +145,20 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json = json.load(plot_file)
# Keep only 'data' and 'layout' sections
-plot_json = {key: plot_json[key] for key in plot_json if key in ['data', 'layout']}
-
+plot_json = {key: plot_json[key] for key in plot_json
+ if key in ['data', 'layout']
+ }
# Remove 'frame' section in 'data'
-plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'} for entry in plot_json.get('data', [])]
-
+plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
+ for entry in plot_json.get('data', [])
+ ]
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
-
# Create the plotly plot
fig_plotly = pio.from_json(plot_json_str)
-fig_plotly.update_layout(autosize=False, width=950, height=400, margin=dict(b=50, t=50, l=50, r=50))
+fig_plotly.update_layout(autosize=False, width=950, height=400,
+ margin=dict(b=50, t=50, l=50, r=50)
+ )
fig_plotly.show()
```
@@ -166,7 +176,8 @@ with open(report_dir /'../../../../../docs/example_data/Basic_example_vuegen_dem
plot_json_str = json.dumps(plot_json)
# Create the altair plot
-fig_altair = alt.Chart.from_json(plot_json_str).properties(width=900, height=370)
+fig_altair = alt.Chart.from_json(plot_json_str
+ ).properties(width=900, height=370)
fig_altair
```
@@ -251,7 +262,9 @@ Optional description for subsection
-
+
## Static Networks
@@ -274,7 +287,9 @@ Optional description for subsection
-
+
### Multiqc Report
From 518ff91e05b02dd6b534d594fa185543a67f7d73 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 26 Jun 2025 11:29:42 +0200
Subject: [PATCH 22/41] :art: shorten docstrings and comments, implement lazy
logging
lazy logging is recommended (only a warning):
https://pylint.readthedocs.io/en/latest/user_guide/messages/warning/logging-fstring-interpolation.html
---
src/vuegen/config_manager.py | 47 ++++++++++++++++++++++++------------
1 file changed, 32 insertions(+), 15 deletions(-)
diff --git a/src/vuegen/config_manager.py b/src/vuegen/config_manager.py
index d3a613b..6df2dee 100644
--- a/src/vuegen/config_manager.py
+++ b/src/vuegen/config_manager.py
@@ -1,3 +1,7 @@
+"""ConfigManage creates configuration files from folders and can create components
+for reports from YAML config files.
+"""
+
import json
import logging
import os
@@ -10,7 +14,8 @@
class ConfigManager:
"""
- Class for handling metadata of reports from YAML config file and creating report objects.
+ Class for handling metadata of reports from YAML config file and creating report
+ objects.
"""
def __init__(self, logger: Optional[logging.Logger] = None, max_depth: int = 2):
@@ -20,10 +25,11 @@ def __init__(self, logger: Optional[logging.Logger] = None, max_depth: int = 2):
Parameters
----------
logger : logging.Logger, optional
- A logger instance for the class. If not provided, a default logger will be created.
+ A logger instance for the class.
+ If not provided, a default logger will be created.
max_depth : int, optional
- The maximum depth of the directory structure to consider when generating the report
- config from a directory.
+ The maximum depth of the directory structure to consider when generating
+ the report config from a directory.
The default is 2, which means it will include sections and subsections.
"""
if logger is None:
@@ -53,7 +59,8 @@ def _create_title_fromdir(self, file_dirname: str) -> str:
def _create_component_config_fromfile(self, file_path: Path) -> Dict[str, str]:
"""
- Infers a component config from a file, including component type, plot type, and additional fields.
+ Infers a component config from a file, including component type, plot type,
+ and additional fields.
Parameters
----------
@@ -144,13 +151,16 @@ def _create_component_config_fromfile(self, file_path: Path) -> Dict[str, str]:
else:
component_config["plot_type"] = r.PlotType.PLOTLY.value
except Exception as e:
- self.logger.warning(f"Could not parse JSON file {file_path}: {e}")
+ self.logger.warning("Could not parse JSON file %s: %s", file_path, e)
component_config["plot_type"] = "unknown"
elif file_ext == ".md":
component_config["component_type"] = r.ComponentType.MARKDOWN.value
else:
+ if not file_ext:
+ # hidden files starting with a dot
+ file_ext = file_path.name
self.logger.error(
- f"Unsupported file extension: {file_ext}. Skipping file: {file_path}"
+ "Unsupported file extension: %s. Skipping file: %s", file_ext, file_path
)
return None
@@ -158,7 +168,8 @@ def _create_component_config_fromfile(self, file_path: Path) -> Dict[str, str]:
def _sort_paths_by_numprefix(self, paths: List[Path]) -> List[Path]:
"""
- Sorts a list of Paths by numeric prefixes in their names, placing non-numeric items at the end.
+ Sorts a list of Paths by numeric prefixes in their names, placing non-numeric
+ items at the end.
Parameters
----------
@@ -298,7 +309,8 @@ def create_yamlconfig_fromdir(
self, base_dir: str
) -> Tuple[Dict[str, Union[str, List[Dict]]], Path]:
"""
- Generates a YAML-compatible config file from a directory. It also returns the resolved folder path.
+ Generates a YAML-compatible config file from a directory. It also returns the
+ resolved folder path.
Parameters
----------
@@ -361,7 +373,8 @@ def create_yamlconfig_fromdir(
def initialize_report(self, config: dict) -> tuple[r.Report, dict]:
"""
- Extracts report metadata from a YAML config file and returns a Report object and the raw metadata.
+ Extracts report metadata from a YAML config file and returns a Report object and
+ the raw metadata.
Parameters
----------
@@ -371,7 +384,8 @@ def initialize_report(self, config: dict) -> tuple[r.Report, dict]:
Returns
-------
report, config : tuple[Report, dict]
- A tuple containing the Report object created from the YAML config file and the raw metadata dictionary.
+ A tuple containing the Report object created from the YAML config file and
+ the raw metadata dictionary.
Raises
------
@@ -396,7 +410,9 @@ def initialize_report(self, config: dict) -> tuple[r.Report, dict]:
report.sections.append(section)
self.logger.info(
- f"Report '{report.title}' initialized with {len(report.sections)} sections."
+ "Report '%s' initialized with %d sections.",
+ report.title,
+ len(report.sections),
)
return report, config
@@ -472,7 +488,8 @@ def _create_component(self, component_data: dict) -> r.Component:
Returns
-------
Component
- A Component object (Plot, DataFrame, or Markdown) populated with the provided metadata.
+ A Component object (Plot, DataFrame, or Markdown) populated with the provided
+ metadata.
"""
# Determine the component type
component_type = assert_enum_value(
@@ -620,8 +637,8 @@ def _create_apicall_component(self, component_data: dict) -> r.APICall:
try:
parsed_body = json.loads(request_body)
except json.JSONDecodeError as e:
- self.logger.error(f"Failed to parse request_body JSON: {e}")
- raise ValueError(f"Invalid JSON in request_body: {e}")
+ self.logger.error("Failed to parse request_body JSON: %s", e)
+ raise ValueError("Invalid JSON in request_body.") from e
return r.APICall(
title=component_data["title"],
From e2a9da1cc8978ff249f4dc5338a1aef6dbe9bee1 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Thu, 26 Jun 2025 12:52:01 +0200
Subject: [PATCH 23/41] :art: remove trailing white-space from streamlit footer
---
src/vuegen/utils/__init__.py | 2 +-
.../streamlit_report/sections/Dataframes/All_Formats.py | 2 +-
.../streamlit_report/sections/Home/Homepage.py | 2 +-
.../streamlit_report/sections/Html/All_Html.py | 2 +-
.../streamlit_report/sections/Markdown/All_Markdown.py | 2 +-
.../streamlit_report/sections/Networks/Interactive_Networks.py | 2 +-
.../streamlit_report/sections/Networks/Static_Networks.py | 2 +-
.../streamlit_report/sections/Plots/Interactive_Plots.py | 2 +-
.../streamlit_report/sections/Plots/Static_Plots.py | 2 +-
9 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/vuegen/utils/__init__.py b/src/vuegen/utils/__init__.py
index 12f5092..79eca3f 100644
--- a/src/vuegen/utils/__init__.py
+++ b/src/vuegen/utils/__init__.py
@@ -870,7 +870,7 @@ def generate_footer() -> str:
}