@@ -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
@@ -657,10 +689,17 @@ def _generate_plot_content(self, plot) -> List[str]:
657689 # If the file path is a URL, keep the file path as is
658690 if is_url (plot .file_path ):
659691 plot_file_path = plot .file_path
692+ plot_content .append (f"plot_file_path = '{ plot_file_path } '" )
660693 else : # If it's a local file
661- plot_file_path = get_relative_file_path (plot .file_path ).as_posix ()
694+ plot_file_path = get_relative_file_path (
695+ plot .file_path , relative_to = self .section_dir
696+ ).as_posix ()
697+ plot_content .append (
698+ f"plot_file_path = (section_dir / '{ plot_file_path } ')"
699+ ".resolve().as_posix()"
700+ )
662701 plot_content .append (
663- f" \n st .image(' { plot_file_path } ', "
702+ "st .image(plot_file_path, "
664703 f" caption='{ plot .caption } ', use_column_width=True)\n "
665704 )
666705 elif plot .plot_type == r .PlotType .PLOTLY :
@@ -699,11 +738,14 @@ def _generate_plot_content(self, plot) -> List[str]:
699738 )
700739 )
701740 else :
702- fpath = Path (html_plot_file ).resolve ().relative_to (Path .cwd ())
741+ fpath = get_relative_file_path (
742+ html_plot_file , relative_to = self .section_dir
743+ ).as_posix ()
703744 plot_content .append (
704745 textwrap .dedent (
705746 f"""
706- with open('{ fpath } ', 'r') as html_file:
747+ file_path = (section_dir / '{ fpath } ').resolve().as_posix()
748+ with open(file_path, 'r') as html_file:
707749 html_content = html_file.read()
708750 """
709751 )
@@ -770,10 +812,13 @@ def _generate_plot_code(self, plot) -> str:
770812 plot_json = json.loads(response.text)\n """
771813 )
772814 else : # If it's a local file
773- plot_rel_path = get_relative_file_path (plot .file_path )
815+ plot_rel_path = get_relative_file_path (
816+ plot .file_path , relative_to = self .section_dir
817+ ).as_posix ()
774818 plot_code = textwrap .dedent (
775819 f"""
776- with open('{ plot_rel_path .as_posix ()} ', 'r') as plot_file:
820+ file_path = (section_dir / '{ plot_rel_path } ').resolve().as_posix()
821+ with open(file_path, 'r') as plot_file:
777822 plot_json = json.load(plot_file)\n """
778823 )
779824
@@ -864,11 +909,14 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
864909 sheet_names = table_utils .get_sheet_names (df_file_path .as_posix ())
865910 if len (sheet_names ) > 1 :
866911 # If there are multiple sheets, ask the user to select one
867- fpath = df_file_path .as_posix ()
912+ fpath = get_relative_file_path (
913+ dataframe .file_path , relative_to = self .section_dir
914+ ).as_posix ()
868915 dataframe_content .append (
869916 textwrap .dedent (
870917 f"""\
871- sheet_names = table_utils.get_sheet_names("{ fpath } ")
918+ file_path = (section_dir / '{ fpath } ').resolve().as_posix()
919+ sheet_names = table_utils.get_sheet_names(file_path)
872920 selected_sheet = st.selectbox("Select a sheet to display",
873921 options=sheet_names,
874922 )
@@ -877,18 +925,27 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
877925 )
878926
879927 # Load the DataFrame using the correct function
880- read_function = read_function_mapping [file_extension ]
928+ df_file_path = get_relative_file_path (
929+ dataframe .file_path , relative_to = self .section_dir
930+ ).as_posix ()
931+ read_function = read_function_mapping [file_extension ].__name__
881932 if file_extension in [
882933 r .DataFrameFormat .XLS .value_with_dot ,
883934 r .DataFrameFormat .XLSX .value_with_dot ,
884935 ]:
885936 dataframe_content .append (
886- f"df = pd.{ read_function .__name__ } ('{ df_file_path .as_posix ()} ',"
887- " sheet_name=selected_sheet)\n "
937+ textwrap .dedent (
938+ f"""\
939+ file_path = (section_dir / '{ df_file_path } ').resolve()
940+ df = pd.{ read_function } (file_path, sheet_name=selected_sheet)
941+ """
942+ )
888943 )
889944 else :
890945 dataframe_content .append (
891- f"df = pd.{ read_function .__name__ } ('{ df_file_path .as_posix ()} ')\n "
946+ f"file_path = (section_dir / '{ df_file_path } '"
947+ ").resolve().as_posix()\n "
948+ f"df = pd.{ read_function } (file_path)\n "
892949 )
893950 # ! Alternative to select box: iterate over sheets in DataFrame
894951 # Displays a DataFrame using AgGrid with configurable options.
@@ -982,11 +1039,15 @@ def _generate_markdown_content(self, markdown) -> List[str]:
9821039 )
9831040 )
9841041 else : # If it's a local file
985- md_rel_path = get_relative_file_path (markdown .file_path )
1042+ md_rel_path = get_relative_file_path (
1043+ markdown .file_path , relative_to = self .section_dir
1044+ ).as_posix ()
1045+
9861046 markdown_content .append (
9871047 textwrap .dedent (
9881048 f"""
989- with open('{ md_rel_path .as_posix ()} ', 'r') as markdown_file:
1049+ file_path = (section_dir / '{ md_rel_path } ').resolve().as_posix()
1050+ with open(file_path, 'r') as markdown_file:
9901051 markdown_content = markdown_file.read()
9911052 """
9921053 )
@@ -1052,13 +1113,16 @@ def _generate_html_content(self, html) -> List[str]:
10521113 )
10531114 )
10541115 else : # If it's a local file
1055- html_rel_path = get_relative_file_path (html .file_path ).as_posix ()
1116+ html_rel_path = get_relative_file_path (
1117+ html .file_path , relative_to = self .section_dir
1118+ ).as_posix ()
10561119 html_content .append (
10571120 textwrap .dedent (
1058- f"""
1059- with open('{ html_rel_path } ', 'r', encoding='utf-8') as f:
1060- html_content = f.read()
1061- """
1121+ f"""\
1122+ file_path = (section_dir / '{ html_rel_path } ').resolve().as_posix()
1123+ with open(file_path, 'r', encoding='utf-8') as f:
1124+ html_content = f.read()
1125+ """
10621126 )
10631127 )
10641128
@@ -1376,7 +1440,11 @@ def _generate_component_imports(self, component: r.Component) -> List[str]:
13761440 }
13771441
13781442 component_type = component .component_type
1379- component_imports = ["import streamlit as st" ]
1443+ component_imports = [
1444+ "import streamlit as st" ,
1445+ "from pathlib import Path" ,
1446+ "section_dir = Path(__file__).resolve().parent.parent" ,
1447+ ]
13801448
13811449 # Add relevant imports based on component type and visualization tool
13821450 if component_type == r .ComponentType .PLOT :
0 commit comments