Skip to content

Commit 79df207

Browse files
committed
Add method to generate imports in the StreamlitReportView class instead of doing that with a Plot method
1 parent aeb6fbf commit 79df207

File tree

4 files changed

+141
-86
lines changed

4 files changed

+141
-86
lines changed

report/main.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010
report, report_metadata = yaml_manager.load_report_metadata('./report_metadata_micw2graph.yaml')
1111

1212
# Create report view
13-
doc_report = doc_reportview.QuartoReportView(report_metadata['report']['identifier'], report_metadata['report']['name'],
14-
report=report,
15-
report_type = ReportType[report_metadata['report']['report_type'].upper()],
16-
report_format = doc_reportview.ReportFormat[report_metadata['report']['report_format'].upper()],
17-
columns=None)
18-
doc_report.generate_report(output_dir="quarto_report/")
19-
doc_report.run_report(output_dir="quarto_report/")
13+
# doc_report = doc_reportview.QuartoReportView(report_metadata['report']['identifier'], report_metadata['report']['name'],
14+
# report=report,
15+
# report_type = ReportType[report_metadata['report']['report_type'].upper()],
16+
# report_format = doc_reportview.ReportFormat[report_metadata['report']['report_format'].upper()],
17+
# columns=None)
18+
# doc_report.generate_report(output_dir="quarto_report/")
19+
# doc_report.run_report(output_dir="quarto_report/")
2020

21-
#st_report = st_reportview.StreamlitReportView(report_metadata['report']['identifier'], report_metadata['report']['name'],
22-
# report=report, report_type = ReportType[report_metadata['report']['report_type'].upper()], columns=None)
23-
#st_report.generate_report(output_dir="streamlit_report/sections")
24-
#st_report.run_report(output_dir="streamlit_report/sections")
21+
st_report = st_reportview.StreamlitReportView(report_metadata['report']['identifier'], report_metadata['report']['name'],
22+
report=report, report_type = ReportType[report_metadata['report']['report_type'].upper()], columns=None)
23+
st_report.generate_report(output_dir="streamlit_report/sections")
24+
st_report.run_report(output_dir="streamlit_report/sections")
2525

report/quarto_reportview.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ def _generate_subsection(self, subsection, is_report_static, is_report_revealjs)
198198
subsection_content.append(f'::: {{.panel-tabset}}\n')
199199

200200
for component in subsection.components:
201-
imports_component = self._generate_component_imports(component)
202-
subsection_imports.append(imports_component)
201+
component_imports = self._generate_component_imports(component)
202+
subsection_imports.append(component_imports)
203203

204204
if component.component_type == r.ComponentType.PLOT:
205205
subsection_content.extend(self._generate_plot_content(component, is_report_static))

report/streamlit_reportview.py

Lines changed: 126 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,11 @@ def _generate_home_section(self, output_dir: str, report_manag_content: list) ->
146146
home_content.append(f"\nst.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"""\nwith 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"""\nwith 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"\nst.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}')
281242
st.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}')
284245
st.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}')
288249
st.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')
292253
st.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}')
296257
st.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()
305266
st.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"\nst.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\nimport 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 ''

report_metadata_micw2graph.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ report:
1313
and potential ecological functions.
1414
graphical_abstract: "example_data/MicW2Graph/Methods_MicW2Graph.png"
1515
logo: "example_data/mona_logo.png"
16-
report_type: "document"
17-
report_format: "pdf"
16+
report_type: "streamlit"
17+
report_format: ""
1818
sections:
1919
- identifier: 21324
2020
name: "Exploratory Data analysis"

0 commit comments

Comments
 (0)