@@ -146,11 +146,11 @@ def _generate_home_section(self, output_dir: str, report_manag_content: list) ->
146146 home_content .append (f"\n st.image('{ self .report .graphical_abstract } ', use_column_width=True)" )
147147
148148 # Write the home page content to a Python file
149- with open (os .path .join (output_dir , "Home" , "homepage .py" ), 'w' ) as home_page :
149+ with open (os .path .join (output_dir , "Home" , "Homepage .py" ), 'w' ) as home_page :
150150 home_page .write ("\n " .join (home_content ))
151151
152152 # Add the home page to the report manager content
153- report_manag_content .append (f"homepage = st.Page('home/homepage .py', title='Homepage')" )
153+ report_manag_content .append (f"homepage = st.Page('Home/Homepage .py', title='Homepage')" )
154154 report_manag_content .append (f"sections_pages['Home'] = [homepage]\n " )
155155
156156 def _generate_sections (self , output_dir : str ) -> None :
@@ -168,24 +168,16 @@ def _generate_sections(self, output_dir: str) -> None:
168168 if section .subsections :
169169 # Iterate through subsections and integrate them into the section file
170170 for subsection in section .subsections :
171- # Track imports to avoid duplication
171+ # Create subsection content and imports for the report
172172 imports = []
173173 imports .append ('import streamlit as st' )
174174
175175 # Create subsection file
176176 subsection_file_path = os .path .join (output_dir , section_name_var , section_name_var + "_" + subsection .name .replace (" " , "_" ) + ".py" )
177177
178- # Add subsection header and description
179- subsection_header = self ._format_text (text = subsection .name , type = 'header' , level = 3 , color = '#023558' )
180- subsection_desc = self ._format_text (text = subsection .description , type = 'paragraph' )
181-
182- # Collect subsection content
183- subsection_content = [subsection_header , subsection_desc ]
184-
185- # Generate plots for the subsection
186- imports_subsection = self ._generate_subsection (subsection , subsection_content )
187-
188- imports .extend (imports_subsection )
178+ # Generate content for the subsection
179+ subsection_content , subsection_imports = self ._generate_subsection (subsection )
180+ imports .extend (subsection_imports )
189181
190182 # Remove duplicated imports
191183 unique_imports = set ()
@@ -202,7 +194,7 @@ def _generate_sections(self, output_dir: str) -> None:
202194 # Write the subsection content (descriptions, plots)
203195 subsection_file .write ("\n " .join (subsection_content ))
204196
205- def _generate_subsection (self , subsection , content ) -> List [str ]:
197+ def _generate_subsection (self , subsection ) -> List [str ]:
206198 """
207199 Generate code to render components (plots, dataframes, markdown) in the given subsection,
208200 creating imports and content for the subsection based on the component type.
@@ -218,89 +210,152 @@ def _generate_subsection(self, subsection, content) -> List[str]:
218210
219211 Returns
220212 -------
221- list
222- A list of imports for the subsection.
213+ tuple : (List[str], List[str])
214+ - list of subsection content lines (List[str])
215+ - list of imports for the subsection (List[str])
223216 """
224- imports_written_subsection = []
217+ subsection_content = []
218+ subsection_imports = []
219+
220+ # Add subsection header and description
221+ subsection_content .append (self ._format_text (text = subsection .name , type = 'header' , level = 3 , color = '#023558' ))
222+ subsection_content .append (self ._format_text (text = subsection .description , type = 'paragraph' ))
223+
225224 for component in subsection .components :
226225 # Write imports if not already done
227- imports_component = component . generate_imports ( )
228- imports_written_subsection .append (imports_component )
226+ component_imports = self . _generate_component_imports ( component )
227+ subsection_imports .append (component_imports )
229228
230229 # Handle different types of components
231230 if component .component_type == r .ComponentType .PLOT :
232231 # Cast component to Plot
233232 plot = component
234- if plot .plot_type == r .PlotType .INTERACTIVE :
235- if plot .visualization_tool == r .VisualizationTool .PLOTLY :
236- content .append (self ._format_text (text = plot .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
237- content .append (f"""\n with open('{ plot .file_path } ', 'r') as plot_file:
238- plot_json = json.load(plot_file)
239- st.plotly_chart(plot_json, use_container_width=True)\n """ )
240- elif plot .visualization_tool == r .VisualizationTool .ALTAIR :
241- content .append (self ._format_text (text = plot .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
242- content .append (f"""\n with open('{ plot .file_path } ', 'r') as plot_file:
243- plot_json = json.load(plot_file)
244- altair_plot = alt.Chart.from_dict(plot_json)
245- st.vega_lite_chart(json.loads(altair_plot.to_json()), use_container_width=True)\n """ )
246- elif plot .visualization_tool == r .VisualizationTool .PYVIS :
247- G = plot .read_network ()
248- # Define the output file name
249- output_file = f"example_data/{ plot .name .replace (' ' , '_' )} .html"
250- # Get the Network object
251- net = plot .create_and_save_pyvis_network (G , output_file )
252- num_nodes = len (net .nodes )
253- num_edges = len (net .edges )
254- content .append (self ._format_text (text = plot .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
255-
256- content .append (f"""
257- with open('{ output_file } ', 'r') as f:
258- html_data = f.read()
259-
260- st.markdown(f"<p style='text-align: center; color: black;'> <b>Number of nodes:</b> { num_nodes } </p>", unsafe_allow_html=True)
261- st.markdown(f"<p style='text-align: center; color: black;'> <b>Number of relationships:</b> { num_edges } </p>", unsafe_allow_html=True)
262-
263- # Streamlit checkbox for controlling the layout
264- control_layout = st.checkbox('Add panel to control layout', value=True)
265- net_html_height = 1200 if control_layout else 630
266-
267- # Load HTML into HTML component for display on Streamlit
268- st.components.v1.html(html_data, height=net_html_height)""" )
269-
270- elif plot .plot_type == r .PlotType .STATIC :
271- content .append (self ._format_text (text = plot .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
272- content .append (f"\n st.image('{ plot .file_path } ', caption='{ plot .caption } ', use_column_width=True)\n " )
233+ subsection_content .extend (self ._generate_plot_content (plot ))
273234
274235 elif component .component_type == r .ComponentType .DATAFRAME :
275236 # Cast component to DataFrame
276237 dataframe = component
277238 if dataframe .file_format == r .DataFrameFormat .CSV :
278- content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
239+ subsection_content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
279240 if dataframe .delimiter :
280- content .append (f"""df = pd.read_csv('{ dataframe .file_path } ', delimiter='{ dataframe .delimiter } ')
241+ subsection_content .append (f"""df = pd.read_csv('{ dataframe .file_path } ', delimiter='{ dataframe .delimiter } ')
281242st.dataframe(df, use_container_width=True)\n """ )
282243 else :
283- content .append (f"""df = pd.read_csv('{ dataframe .file_path } ')
244+ subsection_content .append (f"""df = pd.read_csv('{ dataframe .file_path } ')
284245st.dataframe(df, use_container_width=True)\n """ )
285246 elif dataframe .file_format == r .DataFrameFormat .PARQUET :
286- content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
287- content .append (f"""df = pd.read_parquet('{ dataframe .file_path } ')
247+ subsection_content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
248+ subsection_content .append (f"""df = pd.read_parquet('{ dataframe .file_path } ')
288249st.dataframe(df, use_container_width=True)\n """ )
289250 elif dataframe .file_format == r .DataFrameFormat .TXT :
290- content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
291- content .append (f"""df = pd.read_csv('{ dataframe .file_path } ', sep='\\ t')
251+ subsection_content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
252+ subsection_content .append (f"""df = pd.read_csv('{ dataframe .file_path } ', sep='\\ t')
292253st.dataframe(df, use_container_width=True)\n """ )
293254 elif dataframe .file_format == r .DataFrameFormat .EXCEL :
294- content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
295- content .append (f"""df = pd.read_excel('{ dataframe .file_path } ')
255+ subsection_content .append (self ._format_text (text = dataframe .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
256+ subsection_content .append (f"""df = pd.read_excel('{ dataframe .file_path } ')
296257st.dataframe(df, use_container_width=True)\n """ )
297258 else :
298259 raise ValueError (f"Unsupported DataFrame file format: { dataframe .file_format } " )
299260 elif component .component_type == r .ComponentType .MARKDOWN :
300261 # Cast component to Markdown
301262 markdown = component
302- content .append (self ._format_text (text = markdown .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
303- content .append (f"""with open('{ markdown .file_path } ', 'r') as markdown_file:
263+ subsection_content .append (self ._format_text (text = markdown .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
264+ subsection_content .append (f"""with open('{ markdown .file_path } ', 'r') as markdown_file:
304265 markdown_content = markdown_file.read()
305266st.markdown(markdown_content, unsafe_allow_html=True)\n """ )
306- return imports_written_subsection
267+ return subsection_content , subsection_imports
268+
269+ def _generate_plot_content (self , plot ) -> List [str ]:
270+ """
271+ Generate content for a plot component based on the plot type (static or interactive).
272+
273+ Parameters
274+ ----------
275+ plot : Plot
276+ The plot component to generate content for.
277+
278+ Returns
279+ -------
280+ list : List[str]
281+ The list of content lines for the plot.
282+ """
283+ plot_content = []
284+ plot_content .append (self ._format_text (text = plot .title , type = 'header' , level = 4 , color = '#2b8cbe' ))
285+
286+ if plot .plot_type == r .PlotType .INTERACTIVE :
287+ # Handle interactive plot
288+ if plot .visualization_tool == r .VisualizationTool .PLOTLY :
289+ plot_content .append (f"""with open('{ plot .file_path } ', 'r') as plot_file:
290+ plot_json = json.load(plot_file)
291+ st.plotly_chart(plot_json, use_container_width=True)\n """ )
292+ elif plot .visualization_tool == r .VisualizationTool .ALTAIR :
293+ plot_content .append (f"""with open('{ plot .file_path } ', 'r') as plot_file:
294+ plot_json = json.load(plot_file)
295+ altair_plot = alt.Chart.from_dict(plot_json)
296+ st.vega_lite_chart(json.loads(altair_plot.to_json()), use_container_width=True)\n """ )
297+ elif plot .visualization_tool == r .VisualizationTool .PYVIS :
298+ # For PyVis, handle the network visualization
299+ G = plot .read_network ()
300+ html_plot_file = f"streamlit_report/{ plot .name .replace (' ' , '_' )} .html"
301+ net = plot .create_and_save_pyvis_network (G , html_plot_file )
302+ num_nodes = len (net .nodes )
303+ num_edges = len (net .edges )
304+ plot_content .append (f"""with open('{ html_plot_file } ', 'r') as f:
305+ html_data = f.read()
306+
307+ st.markdown(f"<p style='text-align: center; color: black;'> <b>Number of nodes:</b> { num_nodes } </p>", unsafe_allow_html=True)
308+ st.markdown(f"<p style='text-align: center; color: black;'> <b>Number of relationships:</b> { num_edges } </p>", unsafe_allow_html=True)
309+
310+ # Streamlit checkbox for controlling the layout
311+ control_layout = st.checkbox('Add panel to control layout', value=True)
312+ net_html_height = 1200 if control_layout else 630
313+
314+ # Load HTML into HTML component for display on Streamlit
315+ st.components.v1.html(html_data, height=net_html_height)\n """ )
316+ elif plot .plot_type == r .PlotType .STATIC :
317+ # Handle static plot
318+ plot_content .append (f"\n st.image('{ plot .file_path } ', caption='{ plot .caption } ', use_column_width=True)\n " )
319+
320+ return plot_content
321+
322+
323+ def _generate_component_imports (self , component : r .Component ) -> str :
324+ """
325+ Generate necessary imports for a component of the report.
326+
327+ Parameters
328+ ----------
329+ component : r.Component
330+ The component for which to generate the required imports. The component can be of type:
331+ - PLOT
332+ - DATAFRAME
333+
334+ Returns
335+ -------
336+ str
337+ A str of import statements for the component.
338+ """
339+ # Dictionary to hold the imports for each component type
340+ components_imports = {
341+ 'plot' : {
342+ r .VisualizationTool .ALTAIR : 'import json\n import altair as alt' ,
343+ r .VisualizationTool .PLOTLY : 'import json'
344+ },
345+ 'dataframe' : 'import pandas as pd'
346+ }
347+
348+ # Iterate over sections and subsections to determine needed imports
349+ component_type = component .component_type
350+
351+ # Add relevant imports based on component type and visualization tool
352+ if component_type == r .ComponentType .PLOT :
353+ visualization_tool = getattr (component , 'visualization_tool' , None )
354+ if visualization_tool in components_imports ['plot' ]:
355+ return components_imports ['plot' ][visualization_tool ]
356+
357+ elif component_type == r .ComponentType .DATAFRAME :
358+ return components_imports ['dataframe' ]
359+
360+ # If no relevant import is found, return an empty string
361+ return ''
0 commit comments