diff --git a/.github/workflows/cdci.yml b/.github/workflows/cdci.yml index 13652a9..5bf89f2 100644 --- a/.github/workflows/cdci.yml +++ b/.github/workflows/cdci.yml @@ -118,6 +118,15 @@ jobs: echo "Error: One or more protected files have been modified." exit 1 fi + - name: streamlit report based on predefined config file + run: | + cd docs + vuegen -c example_config_files/Basic_example_vuegen_demo_notebook_config.yaml -output_dir ../tests/report_examples/Basic_example_vuegen_demo_notebook_cfg + # Check for changes + if git diff ../tests/report_examples | grep .; then + echo "Error: One or more protected files have been modified." + exit 1 + fi - name: check streamlit report files for chatbot API run: | vuegen -c docs/example_config_files/Chatbot_example_config.yaml -output_dir tests/report_examples/chat_bot @@ -208,7 +217,7 @@ jobs: - name: Build executable run: | cd gui - pyinstaller -n vuegen_gui --onefile --windowed --collect-all pyvis --collect-all streamlit --collect-all st_aggrid --collect-all customtkinter --collect-all quarto_cli --collect-all plotly --collect-all _plotly_utils --collect-all traitlets --collect-all referencing --collect-all rpds --collect-all tenacity --collect-all pandas --collect-all numpy --collect-all matplotlib --collect-all openpyxl --collect-all xlrd --collect-all nbformat --collect-all nbclient --collect-all altair --collect-all itables --collect-all kaleido --collect-all pyarrow --collect-all dataframe_image --collect-all narwhals --collect-all PIL --collect-all vl_convert --collect-all typing-extensions --add-data ../docs/example_data/Basic_example_vuegen_demo_notebook:example_data/Basic_example_vuegen_demo_notebook --add-data ../docs/images/vuegen_logo.png:. app.py + pyinstaller -n vuegen_gui --onefile --windowed --collect-all pyvis --collect-all streamlit --collect-all st_aggrid --collect-all customtkinter --collect-all quarto_cli --collect-all plotly --collect-all _plotly_utils --collect-all traitlets --collect-all referencing --collect-all rpds --collect-all tenacity --collect-all pandas --collect-all numpy --collect-all matplotlib --collect-all openpyxl --collect-all xlrd --collect-all nbformat --collect-all nbclient --collect-all altair --collect-all itables --collect-all kaleido --collect-all pyarrow --collect-all dataframe_image --collect-all narwhals --collect-all PIL --collect-all vl_convert --collect-all typing-extensions --add-data ../docs/example_data/Basic_example_vuegen_demo_notebook:example_data/Basic_example_vuegen_demo_notebook --add-data ../docs/images/logo/vuegen_logo.png:. app.py # --windowed only for mac, see: # https://pyinstaller.org/en/stable/usage.html#building-macos-app-bundles # 'Under macOS, PyInstaller always builds a UNIX executable in dist.' diff --git a/docs/example_config_files/Basic_example_vuegen_demo_notebook_config.yaml b/docs/example_config_files/Basic_example_vuegen_demo_notebook_config.yaml index a54a1a2..cac4260 100644 --- a/docs/example_config_files/Basic_example_vuegen_demo_notebook_config.yaml +++ b/docs/example_config_files/Basic_example_vuegen_demo_notebook_config.yaml @@ -1,8 +1,8 @@ report: title: Basic Example Vuegen Demo Notebook description: A general description of the report. - graphical_abstract: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.png - logo: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.png + graphical_abstract: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png + logo: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png sections: - title: Plots description: This section contains example plots. diff --git a/docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md b/docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md index be93449..70ea330 100644 --- a/docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md +++ b/docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md @@ -1,8 +1,8 @@ -![VueGen Logo](https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.png) +![VueGen Logo](https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png)

VueGen is a Python library that automates the creation of scientific reports. diff --git a/docs/split_readme.py b/docs/split_readme.py index 22a7870..1792af8 100644 --- a/docs/split_readme.py +++ b/docs/split_readme.py @@ -3,7 +3,7 @@ # Mapping section titles to their corresponding filenames SECTION_MAPPING = { - "![VueGen Logo](https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.svg)": "home_page.md", + "![VueGen Logo](https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/HEAD/docs/images/logo/vuegen_logo.svg)": "home_page.md", "About the project": "about.md", "Installation": "installation.md", "Execution": "execution.md", diff --git a/docs/vuegen_basic_case_study.ipynb b/docs/vuegen_basic_case_study.ipynb index 431511e..cc15fb8 100644 --- a/docs/vuegen_basic_case_study.ipynb +++ b/docs/vuegen_basic_case_study.ipynb @@ -273,7 +273,7 @@ }, "outputs": [], "source": [ - "vuegen_logo_path = \"https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.svg\"\n", + "vuegen_logo_path = \"https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png\"\n", "\n", "# Load the YAML file\n", "print(\n", @@ -457,7 +457,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.6" + "version": "3.12.9" } }, "nbformat": 4, diff --git a/docs/vuegen_basic_case_study_configfile.md b/docs/vuegen_basic_case_study_configfile.md index 6cb1d71..65d4b9b 100644 --- a/docs/vuegen_basic_case_study_configfile.md +++ b/docs/vuegen_basic_case_study_configfile.md @@ -6,8 +6,8 @@ The [configuration file](https://github.com/Multiomics-Analytics-Group/vuegen/bl report: title: Basic Example Vuegen Demo Notebook description: A general description of the report. - graphical_abstract: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.png - logo: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_logo.png + graphical_abstract: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png + logo: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png sections: - title: Plots description: This section contains example plots. diff --git a/gui/Makefile b/gui/Makefile index 4688457..7cc703f 100644 --- a/gui/Makefile +++ b/gui/Makefile @@ -39,7 +39,7 @@ bundle: --collect-all vl_convert \ --collect-all typing-extensions \ --add-data ../docs/example_data/Basic_example_vuegen_demo_notebook:example_data/Basic_example_vuegen_demo_notebook \ - --add-data ../docs/images/vuegen_logo.png:. \ + --add-data ../docs/images/logo/vuegen_logo.png:. \ app.py diff --git a/src/vuegen/report_generator.py b/src/vuegen/report_generator.py index a3f5db7..a14fa5d 100644 --- a/src/vuegen/report_generator.py +++ b/src/vuegen/report_generator.py @@ -108,9 +108,10 @@ def get_report( report_type=report_type, streamlit_autorun=streamlit_autorun, static_dir=static_files_dir, + sections_dir=sections_dir, ) - st_report.generate_report(output_dir=sections_dir) - st_report.run_report(output_dir=sections_dir) + st_report.generate_report() + st_report.run_report() else: # Check if Quarto is installed if shutil.which("quarto") is None and not hasattr( diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py index 67023eb..36a38a7 100644 --- a/src/vuegen/streamlit_reportview.py +++ b/src/vuegen/streamlit_reportview.py @@ -50,6 +50,7 @@ def __init__( report_type: r.ReportType, streamlit_autorun: bool = False, static_dir: str = STATIC_FILES_DIR, + sections_dir: str = SECTIONS_DIR, ): """Initialize ReportView with the report and report type. @@ -86,8 +87,9 @@ def __init__( } self.static_dir = static_dir + self.section_dir = sections_dir - def generate_report(self, output_dir: str = SECTIONS_DIR) -> None: + def generate_report(self, output_dir: str = None) -> None: """ Generates the Streamlit report and creates Python files for each section and its subsections and plots. @@ -98,6 +100,10 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None: The folder where the generated report files will be saved (default is SECTIONS_DIR). """ + if output_dir is not None: + # ? does this imply changes to the static dir + self.section_dir = Path(output_dir).resolve() + output_dir = Path(self.section_dir) self.report.logger.debug( "Generating '%s' report in directory: '%s'", self.report_type, output_dir ) @@ -274,6 +280,29 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None: # Create Python files for each section and its subsections and plots self._generate_sections(output_dir=output_dir) + + # Save README.md to the output directory + fpath = self.section_dir.parent / "README.md" + with open(fpath, "w", encoding="utf-8") as f: + + f.write( + textwrap.dedent( + f"""\ + # Streamlit Report + + This report was generated using the Vuegen library: + https://github.com/Multiomics-Analytics-Group/vuegen + + Executed from: `{Path.cwd()}` + + Written to: `{self.section_dir.resolve()}` + + Folder cannot be moved from above path, but can be executed + from anywhere on the system. + """ + ) + ) + except Exception as e: self.report.logger.error( "An error occurred while generating the report: %s", @@ -282,7 +311,7 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None: ) raise - def run_report(self, output_dir: str = SECTIONS_DIR) -> None: + def run_report(self, output_dir: str = None) -> None: """ Runs the generated Streamlit report. @@ -291,6 +320,9 @@ def run_report(self, output_dir: str = SECTIONS_DIR) -> None: output_dir : str, optional The folder where the report was generated (default is SECTIONS_DIR). """ + if output_dir is not None: + self.report.logger.warning("The output_dir parameter is deprecated.") + output_dir = Path(self.section_dir) if self.streamlit_autorun: self.report.logger.info( "Running '%s' %s report.", self.report.title, self.report_type @@ -657,10 +689,17 @@ def _generate_plot_content(self, plot) -> List[str]: # If the file path is a URL, keep the file path as is if is_url(plot.file_path): plot_file_path = plot.file_path + plot_content.append(f"plot_file_path = '{plot_file_path}'") else: # If it's a local file - plot_file_path = get_relative_file_path(plot.file_path).as_posix() + plot_file_path = get_relative_file_path( + plot.file_path, relative_to=self.section_dir + ).as_posix() + plot_content.append( + f"plot_file_path = (section_dir / '{plot_file_path}')" + ".resolve().as_posix()" + ) plot_content.append( - f"\nst.image('{plot_file_path}', " + "st.image(plot_file_path," f" caption='{plot.caption}', use_column_width=True)\n" ) elif plot.plot_type == r.PlotType.PLOTLY: @@ -699,11 +738,14 @@ def _generate_plot_content(self, plot) -> List[str]: ) ) else: - fpath = Path(html_plot_file).resolve().relative_to(Path.cwd()) + fpath = get_relative_file_path( + html_plot_file, relative_to=self.section_dir + ).as_posix() plot_content.append( textwrap.dedent( f""" - with open('{fpath}', 'r') as html_file: + file_path = (section_dir / '{fpath}').resolve().as_posix() + with open(file_path, 'r') as html_file: html_content = html_file.read() """ ) @@ -770,10 +812,13 @@ def _generate_plot_code(self, plot) -> str: 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_rel_path = get_relative_file_path( + plot.file_path, relative_to=self.section_dir + ).as_posix() plot_code = textwrap.dedent( f""" - with open('{plot_rel_path.as_posix()}', 'r') as plot_file: + file_path = (section_dir / '{plot_rel_path}').resolve().as_posix() + with open(file_path, 'r') as plot_file: plot_json = json.load(plot_file)\n""" ) @@ -864,11 +909,14 @@ def _generate_dataframe_content(self, dataframe) -> List[str]: sheet_names = table_utils.get_sheet_names(df_file_path.as_posix()) if len(sheet_names) > 1: # If there are multiple sheets, ask the user to select one - fpath = df_file_path.as_posix() + fpath = get_relative_file_path( + dataframe.file_path, relative_to=self.section_dir + ).as_posix() dataframe_content.append( textwrap.dedent( f"""\ - sheet_names = table_utils.get_sheet_names("{fpath}") + file_path = (section_dir / '{fpath}').resolve().as_posix() + sheet_names = table_utils.get_sheet_names(file_path) selected_sheet = st.selectbox("Select a sheet to display", options=sheet_names, ) @@ -877,18 +925,27 @@ def _generate_dataframe_content(self, dataframe) -> List[str]: ) # Load the DataFrame using the correct function - read_function = read_function_mapping[file_extension] + df_file_path = get_relative_file_path( + dataframe.file_path, relative_to=self.section_dir + ).as_posix() + read_function = read_function_mapping[file_extension].__name__ if file_extension in [ r.DataFrameFormat.XLS.value_with_dot, r.DataFrameFormat.XLSX.value_with_dot, ]: dataframe_content.append( - f"df = pd.{read_function.__name__}('{df_file_path.as_posix()}'," - " sheet_name=selected_sheet)\n" + textwrap.dedent( + f"""\ + file_path = (section_dir / '{df_file_path}').resolve() + df = pd.{read_function}(file_path, sheet_name=selected_sheet) + """ + ) ) else: dataframe_content.append( - f"df = pd.{read_function.__name__}('{df_file_path.as_posix()}')\n" + f"file_path = (section_dir / '{df_file_path}'" + ").resolve().as_posix()\n" + f"df = pd.{read_function}(file_path)\n" ) # ! Alternative to select box: iterate over sheets in DataFrame # Displays a DataFrame using AgGrid with configurable options. @@ -982,11 +1039,15 @@ def _generate_markdown_content(self, markdown) -> List[str]: ) ) else: # If it's a local file - md_rel_path = get_relative_file_path(markdown.file_path) + md_rel_path = get_relative_file_path( + markdown.file_path, relative_to=self.section_dir + ).as_posix() + markdown_content.append( textwrap.dedent( f""" - with open('{md_rel_path.as_posix()}', 'r') as markdown_file: + file_path = (section_dir / '{md_rel_path}').resolve().as_posix() + with open(file_path, 'r') as markdown_file: markdown_content = markdown_file.read() """ ) @@ -1052,13 +1113,16 @@ def _generate_html_content(self, html) -> List[str]: ) ) else: # If it's a local file - html_rel_path = get_relative_file_path(html.file_path).as_posix() + html_rel_path = get_relative_file_path( + html.file_path, relative_to=self.section_dir + ).as_posix() html_content.append( textwrap.dedent( - f""" - with open('{html_rel_path}', 'r', encoding='utf-8') as f: - html_content = f.read() - """ + f"""\ + file_path = (section_dir / '{html_rel_path}').resolve().as_posix() + with open(file_path, 'r', encoding='utf-8') as f: + html_content = f.read() + """ ) ) @@ -1376,7 +1440,11 @@ def _generate_component_imports(self, component: r.Component) -> List[str]: } component_type = component.component_type - component_imports = ["import streamlit as st"] + component_imports = [ + "import streamlit as st", + "from pathlib import Path", + "section_dir = Path(__file__).resolve().parent.parent", + ] # Add relevant imports based on component type and visualization tool if component_type == r.ComponentType.PLOT: 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 d7cd522..2babf56 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 @@ -1,8 +1,10 @@ +from pathlib import Path from st_aggrid import AgGrid, GridOptionsBuilder from vuegen import table_utils import pandas as pd import streamlit as st df_index = 1 +section_dir = Path(__file__).resolve().parent.parent st.markdown( @@ -20,7 +22,8 @@ ), 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') +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/1_phyla_correlation_network_csv.csv').resolve().as_posix() +df = pd.read_csv(file_path) # Displays a DataFrame using AgGrid with configurable options. @@ -59,12 +62,14 @@ 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") +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/2_abundance_table_example_xls.xls').resolve().as_posix() +sheet_names = table_utils.get_sheet_names(file_path) selected_sheet = st.selectbox("Select a sheet to display", options=sheet_names, ) -df = pd.read_excel('docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/2_abundance_table_example_xls.xls', sheet_name=selected_sheet) +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/2_abundance_table_example_xls.xls').resolve() +df = pd.read_excel(file_path, sheet_name=selected_sheet) # Displays a DataFrame using AgGrid with configurable options. @@ -102,7 +107,8 @@ ), 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') +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/3_sample_info_example_txt.txt').resolve().as_posix() +df = pd.read_table(file_path) # Displays a DataFrame using AgGrid with configurable options. @@ -140,7 +146,8 @@ ), 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') +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/4_sample_info_example_parquet.parquet').resolve().as_posix() +df = pd.read_parquet(file_path) # Displays a DataFrame using AgGrid with configurable options. @@ -179,7 +186,8 @@ 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) +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/2_Dataframes/1_All_formats/5_example_xlsx.xlsx').resolve() +df = pd.read_excel(file_path, sheet_name=selected_sheet) # Displays a DataFrame using AgGrid with configurable options. diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Html/All_Html.py b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Html/All_Html.py index 4cc5108..e44d890 100644 --- a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Html/All_Html.py +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Html/All_Html.py @@ -1,5 +1,7 @@ +from pathlib import Path import requests import streamlit as st +section_dir = Path(__file__).resolve().parent.parent st.markdown( @@ -17,8 +19,8 @@ ), unsafe_allow_html=True) - -with open('docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/1_plot.html', 'r', encoding='utf-8') as f: +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/1_plot.html').resolve().as_posix() +with open(file_path, 'r', encoding='utf-8') as f: html_content = f.read() st.components.v1.html(html_content, height=600, scrolling=True) @@ -32,7 +34,8 @@ unsafe_allow_html=True) -with open('docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/2_ckg_network.html', 'r') as html_file: +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/2_ckg_network.html').resolve().as_posix() +with open(file_path, 'r') as html_file: html_content = html_file.read() @@ -58,8 +61,8 @@ ), unsafe_allow_html=True) - -with open('docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/3_multiqc_report.html', 'r', encoding='utf-8') as f: +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/3_multiqc_report.html').resolve().as_posix() +with open(file_path, 'r', encoding='utf-8') as f: html_content = f.read() st.components.v1.html(html_content, height=600, scrolling=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Markdown/All_Markdown.py b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Markdown/All_Markdown.py index 547e015..40b331d 100644 --- a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Markdown/All_Markdown.py +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Markdown/All_Markdown.py @@ -1,5 +1,7 @@ +from pathlib import Path import requests import streamlit as st +section_dir = Path(__file__).resolve().parent.parent st.markdown( @@ -18,7 +20,8 @@ unsafe_allow_html=True) -with open('docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md', 'r') as markdown_file: +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md').resolve().as_posix() +with open(file_path, 'r') as markdown_file: markdown_content = markdown_file.read() st.markdown(markdown_content, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Interactive_Networks.py b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Interactive_Networks.py index 232be22..7eaa895 100644 --- a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Interactive_Networks.py +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Interactive_Networks.py @@ -1,5 +1,7 @@ +from pathlib import Path import requests import streamlit as st +section_dir = Path(__file__).resolve().parent.parent st.markdown( @@ -26,7 +28,8 @@ unsafe_allow_html=True) -with open('tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/static/Man_Example.html', 'r') as html_file: +file_path = (section_dir / '../static/Man_Example.html').resolve().as_posix() +with open(file_path, 'r') as html_file: html_content = html_file.read() @@ -53,7 +56,8 @@ unsafe_allow_html=True) -with open('docs/example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/description.md', 'r') as markdown_file: +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/description.md').resolve().as_posix() +with open(file_path, 'r') as markdown_file: markdown_content = markdown_file.read() st.markdown(markdown_content, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Static_Networks.py b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Static_Networks.py index 0392a30..fce1380 100644 --- a/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Static_Networks.py +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook/streamlit_report/sections/Networks/Static_Networks.py @@ -1,4 +1,6 @@ +from pathlib import Path import streamlit as st +section_dir = Path(__file__).resolve().parent.parent st.markdown( @@ -16,8 +18,8 @@ ), unsafe_allow_html=True) - -st.image('docs/example_data/Basic_example_vuegen_demo_notebook/3_Networks/2_Static_networks/1_phyla_correlation_network.png', caption='', use_column_width=True) +plot_file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/3_Networks/2_Static_networks/1_phyla_correlation_network.png').resolve().as_posix() +st.image(plot_file_path, caption='', use_column_width=True) footer = ''' +

+''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Home/Homepage.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Home/Homepage.py new file mode 100644 index 0000000..0131be5 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Home/Homepage.py @@ -0,0 +1,32 @@ +import streamlit as st + +st.markdown( + ( + "

A general description of the report.

" + ), + unsafe_allow_html=True) + + +st.image('https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png', use_column_width=True) +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Html/All_Html.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Html/All_Html.py new file mode 100644 index 0000000..e44d890 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Html/All_Html.py @@ -0,0 +1,90 @@ +from pathlib import Path +import requests +import streamlit as st +section_dir = Path(__file__).resolve().parent.parent + + +st.markdown( + ( + "

All Html

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Plot

" + ), + unsafe_allow_html=True) + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/1_plot.html').resolve().as_posix() +with open(file_path, 'r', encoding='utf-8') as f: + html_content = f.read() + +st.components.v1.html(html_content, height=600, scrolling=True) + + +st.markdown( + ( + "

Ckg Network

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/2_ckg_network.html').resolve().as_posix() +with open(file_path, 'r') as html_file: + html_content = html_file.read() + + +st.markdown(("

" + "Number of nodes: 33

"), + unsafe_allow_html=True) +st.markdown(("

" + " Number of relationships: 35" + "

"), + unsafe_allow_html=True) + +# 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) + + +st.markdown( + ( + "

Multiqc Report

" + ), + unsafe_allow_html=True) + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/4_Html/1_All_html/3_multiqc_report.html').resolve().as_posix() +with open(file_path, 'r', encoding='utf-8') as f: + html_content = f.read() + +st.components.v1.html(html_content, height=600, scrolling=True) + +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Markdown/All_Markdown.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Markdown/All_Markdown.py new file mode 100644 index 0000000..40b331d --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Markdown/All_Markdown.py @@ -0,0 +1,49 @@ +from pathlib import Path +import requests +import streamlit as st +section_dir = Path(__file__).resolve().parent.parent + + +st.markdown( + ( + "

All Markdown

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Readme

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/5_Markdown/1_All_markdown/README.md').resolve().as_posix() +with open(file_path, 'r') as markdown_file: + markdown_content = markdown_file.read() + +st.markdown(markdown_content, unsafe_allow_html=True) + +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Networks/Interactive_Networks.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Networks/Interactive_Networks.py new file mode 100644 index 0000000..0b29029 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Networks/Interactive_Networks.py @@ -0,0 +1,85 @@ +from pathlib import Path +import requests +import streamlit as st +section_dir = Path(__file__).resolve().parent.parent + + +st.markdown( + ( + "

Interactive Networks

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Optional description for subsection

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Man Example

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../static/Man_Example.html').resolve().as_posix() +with open(file_path, 'r') as html_file: + html_content = html_file.read() + + +st.markdown(("

" + "Number of nodes: 9

"), + unsafe_allow_html=True) +st.markdown(("

" + " Number of relationships: 14" + "

"), + unsafe_allow_html=True) + +# 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) + + +st.markdown( + ( + "

Description

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/3_Networks/1_Interactive_networks/description.md').resolve().as_posix() +with open(file_path, 'r') as markdown_file: + markdown_content = markdown_file.read() + +st.markdown(markdown_content, unsafe_allow_html=True) + +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Networks/Static_Networks.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Networks/Static_Networks.py new file mode 100644 index 0000000..fce1380 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Networks/Static_Networks.py @@ -0,0 +1,44 @@ +from pathlib import Path +import streamlit as st +section_dir = Path(__file__).resolve().parent.parent + + +st.markdown( + ( + "

Static Networks

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Phyla Correlation Network

" + ), + unsafe_allow_html=True) + +plot_file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/3_Networks/2_Static_networks/1_phyla_correlation_network.png').resolve().as_posix() +st.image(plot_file_path, caption='', use_column_width=True) + +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Plots/Interactive_Plots.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Plots/Interactive_Plots.py new file mode 100644 index 0000000..94f5177 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Plots/Interactive_Plots.py @@ -0,0 +1,159 @@ +from pathlib import Path +import altair as alt +import json +import requests +import streamlit as st +section_dir = Path(__file__).resolve().parent.parent + + +st.markdown( + ( + "

Interactive Plots

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Optional description for section.

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Top Species Plot By Biome Plotly

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/1_top_species_plot_by_biome_plotly.json').resolve().as_posix() +with open(file_path, 'r') as plot_file: + 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']} + +# 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) + + +st.markdown( + ( + "

Multiline Plot Altair

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/2_multiline_plot_altair.json').resolve().as_posix() +with open(file_path, 'r') as plot_file: + plot_json = json.load(plot_file) + +altair_plot = alt.Chart.from_dict(plot_json) +st.vega_lite_chart(json.loads(altair_plot.to_json()), + use_container_width=True) + + +st.markdown( + ( + "

Pie Plot Countries Plotly

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/3_pie_plot_countries_plotly.json').resolve().as_posix() +with open(file_path, 'r') as plot_file: + 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']} + +# 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) + + +st.markdown( + ( + "

Pie Plots Biomes Plotly

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/4_pie_plots_biomes_plotly.json').resolve().as_posix() +with open(file_path, 'r') as plot_file: + 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']} + +# 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) + + +st.markdown( + ( + "

Saline Metagenomics Samples Map Altair

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/5_saline_metagenomics_samples_map_altair.json').resolve().as_posix() +with open(file_path, 'r') as plot_file: + plot_json = json.load(plot_file) + +altair_plot = alt.Chart.from_dict(plot_json) +st.vega_lite_chart(json.loads(altair_plot.to_json()), + use_container_width=True) + + +st.markdown( + ( + "

Description

" + ), + unsafe_allow_html=True) + + +file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/1_Interactive_plots/description.md').resolve().as_posix() +with open(file_path, 'r') as markdown_file: + markdown_content = markdown_file.read() + +st.markdown(markdown_content, unsafe_allow_html=True) + +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Plots/Static_Plots.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Plots/Static_Plots.py new file mode 100644 index 0000000..9eeb920 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/Plots/Static_Plots.py @@ -0,0 +1,77 @@ +from pathlib import Path +import streamlit as st +section_dir = Path(__file__).resolve().parent.parent + + +st.markdown( + ( + "

Static Plots

" + ), + unsafe_allow_html=True) + + +st.markdown( + ( + "

Number Samples Per Study

" + ), + unsafe_allow_html=True) + +plot_file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/1_number_samples_per_study.png').resolve().as_posix() +st.image(plot_file_path, caption='', use_column_width=True) + + +st.markdown( + ( + "

Animal Metagenomics Samples Map

" + ), + unsafe_allow_html=True) + +plot_file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/2_animal_metagenomics_samples_map.png').resolve().as_posix() +st.image(plot_file_path, caption='', use_column_width=True) + + +st.markdown( + ( + "

Alpha Diversity Host Associated Samples

" + ), + unsafe_allow_html=True) + +plot_file_path = (section_dir / '../../../../../docs/example_data/Basic_example_vuegen_demo_notebook/1_Plots/2_Static_plots/3_alpha_diversity_host_associated_samples.png').resolve().as_posix() +st.image(plot_file_path, caption='', use_column_width=True) + + +st.markdown( + ( + "

Graphical overview of VueGen workflow and components

" + ), + unsafe_allow_html=True) + +plot_file_path = 'https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/vuegen_graph_abstract.png' +st.image(plot_file_path, 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.', use_column_width=True) + +footer = ''' + + +''' + +st.markdown(footer, unsafe_allow_html=True) diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/report_manager.py b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/report_manager.py new file mode 100644 index 0000000..afb89c3 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/sections/report_manager.py @@ -0,0 +1,58 @@ +import os +import time + +import psutil +import streamlit as st + +st.set_page_config(layout="wide", + page_title="Basic Example Vuegen Demo Notebook", + page_icon="https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png" +) +st.logo("https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuegen/main/docs/images/logo/vuegen_logo.png") + + +st.markdown( + ( + "

Basic Example Vuegen Demo Notebook

" + ), + unsafe_allow_html=True) + + +sections_pages = {} +homepage = st.Page('Home/Homepage.py', title='Homepage') +sections_pages['Home'] = [homepage] + +Interactive_Plots = st.Page('Plots/Interactive_Plots.py', title='Interactive Plots') +Static_Plots = st.Page('Plots/Static_Plots.py', title='Static Plots') +sections_pages['Plots'] = [Interactive_Plots, Static_Plots] + +All_Formats = st.Page('Dataframes/All_Formats.py', title='All Formats') +sections_pages['Dataframes'] = [All_Formats] + +Interactive_Networks = st.Page('Networks/Interactive_Networks.py', title='Interactive Networks') +Static_Networks = st.Page('Networks/Static_Networks.py', title='Static Networks') +sections_pages['Networks'] = [Interactive_Networks, Static_Networks] + +All_Html = st.Page('Html/All_Html.py', title='All Html') +sections_pages['Html'] = [All_Html] + +All_Markdown = st.Page('Markdown/All_Markdown.py', title='All Markdown') +sections_pages['Markdown'] = [All_Markdown] + +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) +if exit_app: + st.toast("Shutting down the app...") + time.sleep(1) + # Terminate streamlit python process + pid = os.getpid() + p = psutil.Process(pid) + p.terminate() + + +report_nav.run() diff --git a/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/static/Man_Example.html b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/static/Man_Example.html new file mode 100644 index 0000000..5aa9c86 --- /dev/null +++ b/tests/report_examples/Basic_example_vuegen_demo_notebook_cfg/streamlit_report/static/Man_Example.html @@ -0,0 +1,179 @@ + + + + + + + + + +
+

+
+ + + + + + +
+

+
+ + + + + +
+ + +
+
+ + + +
+ + + + + \ No newline at end of file