@@ -50,6 +50,7 @@ def __init__(
5050 report_type : r .ReportType ,
5151 streamlit_autorun : bool = False ,
5252 static_dir : str = STATIC_FILES_DIR ,
53+ sections_dir : str = SECTIONS_DIR ,
5354 ):
5455 """Initialize ReportView with the report and report type.
5556
@@ -86,8 +87,9 @@ def __init__(
8687 }
8788
8889 self .static_dir = static_dir
90+ self .section_dir = sections_dir
8991
90- def generate_report (self , output_dir : str = SECTIONS_DIR ) -> None :
92+ def generate_report (self , output_dir : str = None ) -> None :
9193 """
9294 Generates the Streamlit report and creates Python files for each section
9395 and its subsections and plots.
@@ -98,6 +100,10 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
98100 The folder where the generated report files will be saved
99101 (default is SECTIONS_DIR).
100102 """
103+ if output_dir is not None :
104+ # ? does this imply changes to the static dir
105+ self .section_dir = Path (output_dir ).resolve ()
106+ output_dir = Path (self .section_dir )
101107 self .report .logger .debug (
102108 "Generating '%s' report in directory: '%s'" , self .report_type , output_dir
103109 )
@@ -274,6 +280,29 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
274280
275281 # Create Python files for each section and its subsections and plots
276282 self ._generate_sections (output_dir = output_dir )
283+
284+ # Save README.md to the output directory
285+ fpath = self .section_dir .parent / "README.md"
286+ with open (fpath , "w" , encoding = "utf-8" ) as f :
287+
288+ f .write (
289+ textwrap .dedent (
290+ f"""\
291+ # Streamlit Report
292+
293+ This report was generated using the Vuegen library:
294+ https://github.com/Multiomics-Analytics-Group/vuegen
295+
296+ Executed from: `{ Path .cwd ()} `
297+
298+ Written to: `{ self .section_dir .resolve ()} `
299+
300+ Folder cannot be moved from above path, but can be executed
301+ from anywhere on the system.
302+ """
303+ )
304+ )
305+
277306 except Exception as e :
278307 self .report .logger .error (
279308 "An error occurred while generating the report: %s" ,
@@ -282,7 +311,7 @@ def generate_report(self, output_dir: str = SECTIONS_DIR) -> None:
282311 )
283312 raise
284313
285- def run_report (self , output_dir : str = SECTIONS_DIR ) -> None :
314+ def run_report (self , output_dir : str = None ) -> None :
286315 """
287316 Runs the generated Streamlit report.
288317
@@ -291,6 +320,9 @@ def run_report(self, output_dir: str = SECTIONS_DIR) -> None:
291320 output_dir : str, optional
292321 The folder where the report was generated (default is SECTIONS_DIR).
293322 """
323+ if output_dir is not None :
324+ self .report .logger .warning ("The output_dir parameter is deprecated." )
325+ output_dir = Path (self .section_dir )
294326 if self .streamlit_autorun :
295327 self .report .logger .info (
296328 "Running '%s' %s report." , self .report .title , self .report_type
@@ -659,10 +691,17 @@ def _generate_plot_content(self, plot) -> List[str]:
659691 # If the file path is a URL, keep the file path as is
660692 if is_url (plot .file_path ):
661693 plot_file_path = plot .file_path
694+ plot_content .append (f"plot_file_path = '{ plot_file_path } '" )
662695 else : # If it's a local file
663- plot_file_path = get_relative_file_path (plot .file_path ).as_posix ()
696+ plot_file_path = get_relative_file_path (
697+ plot .file_path , relative_to = self .section_dir
698+ ).as_posix ()
699+ plot_content .append (
700+ f"plot_file_path = (section_dir / '{ plot_file_path } ')"
701+ ".resolve().as_posix()"
702+ )
664703 plot_content .append (
665- f" \n st .image(' { plot_file_path } ', "
704+ "st .image(plot_file_path, "
666705 f" caption='{ plot .caption } ', use_column_width=True)\n "
667706 )
668707 elif plot .plot_type == r .PlotType .PLOTLY :
@@ -701,11 +740,14 @@ def _generate_plot_content(self, plot) -> List[str]:
701740 )
702741 )
703742 else :
704- fpath = Path (html_plot_file ).resolve ().relative_to (Path .cwd ())
743+ fpath = get_relative_file_path (
744+ html_plot_file , relative_to = self .section_dir
745+ ).as_posix ()
705746 plot_content .append (
706747 textwrap .dedent (
707748 f"""
708- with open('{ fpath } ', 'r') as html_file:
749+ file_path = (section_dir / '{ fpath } ').resolve().as_posix()
750+ with open(file_path, 'r') as html_file:
709751 html_content = html_file.read()
710752 """
711753 )
@@ -772,10 +814,13 @@ def _generate_plot_code(self, plot) -> str:
772814 plot_json = json.loads(response.text)\n """
773815 )
774816 else : # If it's a local file
775- plot_rel_path = get_relative_file_path (plot .file_path )
817+ plot_rel_path = get_relative_file_path (
818+ plot .file_path , relative_to = self .section_dir
819+ ).as_posix ()
776820 plot_code = textwrap .dedent (
777821 f"""
778- with open('{ plot_rel_path .as_posix ()} ', 'r') as plot_file:
822+ file_path = (section_dir / '{ plot_rel_path } ').resolve().as_posix()
823+ with open(file_path, 'r') as plot_file:
779824 plot_json = json.load(plot_file)\n """
780825 )
781826
@@ -866,11 +911,14 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
866911 sheet_names = table_utils .get_sheet_names (df_file_path .as_posix ())
867912 if len (sheet_names ) > 1 :
868913 # If there are multiple sheets, ask the user to select one
869- fpath = df_file_path .as_posix ()
914+ fpath = get_relative_file_path (
915+ dataframe .file_path , relative_to = self .section_dir
916+ ).as_posix ()
870917 dataframe_content .append (
871918 textwrap .dedent (
872919 f"""\
873- sheet_names = table_utils.get_sheet_names("{ fpath } ")
920+ file_path = (section_dir / '{ fpath } ').resolve().as_posix()
921+ sheet_names = table_utils.get_sheet_names(file_path)
874922 selected_sheet = st.selectbox("Select a sheet to display",
875923 options=sheet_names,
876924 )
@@ -879,18 +927,27 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
879927 )
880928
881929 # Load the DataFrame using the correct function
882- read_function = read_function_mapping [file_extension ]
930+ df_file_path = get_relative_file_path (
931+ dataframe .file_path , relative_to = self .section_dir
932+ ).as_posix ()
933+ read_function = read_function_mapping [file_extension ].__name__
883934 if file_extension in [
884935 r .DataFrameFormat .XLS .value_with_dot ,
885936 r .DataFrameFormat .XLSX .value_with_dot ,
886937 ]:
887938 dataframe_content .append (
888- f"df = pd.{ read_function .__name__ } ('{ df_file_path .as_posix ()} ',"
889- " sheet_name=selected_sheet)\n "
939+ textwrap .dedent (
940+ f"""\
941+ file_path = (section_dir / '{ df_file_path } ').resolve()
942+ df = pd.{ read_function } (file_path, sheet_name=selected_sheet)
943+ """
944+ )
890945 )
891946 else :
892947 dataframe_content .append (
893- f"df = pd.{ read_function .__name__ } ('{ df_file_path .as_posix ()} ')\n "
948+ f"file_path = (section_dir / '{ df_file_path } '"
949+ ").resolve().as_posix()\n "
950+ f"df = pd.{ read_function } (file_path)\n "
894951 )
895952 # ! Alternative to select box: iterate over sheets in DataFrame
896953 # Displays a DataFrame using AgGrid with configurable options.
@@ -984,11 +1041,15 @@ def _generate_markdown_content(self, markdown) -> List[str]:
9841041 )
9851042 )
9861043 else : # If it's a local file
987- md_rel_path = get_relative_file_path (markdown .file_path )
1044+ md_rel_path = get_relative_file_path (
1045+ markdown .file_path , relative_to = self .section_dir
1046+ ).as_posix ()
1047+
9881048 markdown_content .append (
9891049 textwrap .dedent (
9901050 f"""
991- with open('{ md_rel_path .as_posix ()} ', 'r') as markdown_file:
1051+ file_path = (section_dir / '{ md_rel_path } ').resolve().as_posix()
1052+ with open(file_path, 'r') as markdown_file:
9921053 markdown_content = markdown_file.read()
9931054 """
9941055 )
@@ -1054,13 +1115,16 @@ def _generate_html_content(self, html) -> List[str]:
10541115 )
10551116 )
10561117 else : # If it's a local file
1057- html_rel_path = get_relative_file_path (html .file_path ).as_posix ()
1118+ html_rel_path = get_relative_file_path (
1119+ html .file_path , relative_to = self .section_dir
1120+ ).as_posix ()
10581121 html_content .append (
10591122 textwrap .dedent (
1060- f"""
1061- with open('{ html_rel_path } ', 'r', encoding='utf-8') as f:
1062- html_content = f.read()
1063- """
1123+ f"""\
1124+ file_path = (section_dir / '{ html_rel_path } ').resolve().as_posix()
1125+ with open(file_path, 'r', encoding='utf-8') as f:
1126+ html_content = f.read()
1127+ """
10641128 )
10651129 )
10661130
@@ -1378,7 +1442,11 @@ def _generate_component_imports(self, component: r.Component) -> List[str]:
13781442 }
13791443
13801444 component_type = component .component_type
1381- component_imports = ["import streamlit as st" ]
1445+ component_imports = [
1446+ "import streamlit as st" ,
1447+ "from pathlib import Path" ,
1448+ "section_dir = Path(__file__).resolve().parent.parent" ,
1449+ ]
13821450
13831451 # Add relevant imports based on component type and visualization tool
13841452 if component_type == r .ComponentType .PLOT :
0 commit comments