33import report as r
44from typing import List
55import networkx as nx
6- from utils import create_folder
6+ import pandas as pd
7+ from utils import create_folder , is_url
78
89class QuartoReportView (r .ReportView ):
910 """
@@ -329,23 +330,39 @@ def _generate_plot_code(self, plot, output_file = "") -> str:
329330 str
330331 The generated plot code as a string.
331332 """
332- # Start with the common data loading code
333+ # Initialize plot code with common structure
333334 plot_code = f"""```{{python}}
334335#| label: '{ plot .title } '
335336#| fig-cap: ""
337+ """
338+ # If the file path is a URL, generate code to fetch content via requests
339+ if is_url (plot .file_path ):
340+ plot_code += f"""
341+ response = requests.get('{ plot .file_path } ')
342+ response.raise_for_status()
343+ plot_json = response.text\n """
344+ else : # If it's a local file
345+ plot_code += f"""
336346with open('{ os .path .join (".." , plot .file_path )} ', 'r') as plot_file:
337- plot_data = plot_file.read()
338- """
347+ plot_json = plot_file.read()\n """
339348 # Add specific code for each visualization tool
340349 if plot .plot_type == r .PlotType .PLOTLY :
341- plot_code += """fig_plotly = pio.from_json(plot_data)
342- fig_plotly.update_layout(width=950, height=500 )
343- """
350+ plot_code += """
351+ fig_plotly = pio.from_json(plot_json )
352+ fig_plotly.update_layout(width=950, height=500) \n """
344353 elif plot .plot_type == r .PlotType .ALTAIR :
345- plot_code += """fig_altair = alt.Chart.from_json(plot_data ).properties(width=900, height=400)"""
354+ plot_code += """fig_altair = alt.Chart.from_json(plot_json ).properties(width=900, height=400)"""
346355 elif plot .plot_type == r .PlotType .INTERACTIVE_NETWORK :
347- plot_code = f"""<div style="text-align: center;">
348- <iframe src="{ os .path .join (".." , output_file )} " alt="{ plot .title } plot" width="800px" height="630px"></iframe>
356+ # Generate the HTML embedding for interactive networks
357+ if is_url (plot .file_path ) and plot .file_path .endswith ('.html' ):
358+ iframe_src = output_file
359+ else :
360+ iframe_src = os .path .join (".." , output_file )
361+
362+ # Embed the HTML file in an iframe
363+ plot_code = f"""
364+ <div style="text-align: center;">
365+ <iframe src="{ iframe_src } " alt="{ plot .title } plot" width="800px" height="630px"></iframe>
349366</div>\n """
350367 return plot_code
351368
@@ -365,46 +382,47 @@ def _generate_dataframe_content(self, dataframe, is_report_static) -> List[str]:
365382 list : List[str]
366383 The list of content lines for the DataFrame.
367384 """
368- datframe_content = []
385+ dataframe_content = []
369386 # Add title
370- datframe_content .append (f'### { dataframe .title } ' )
387+ dataframe_content .append (f'### { dataframe .title } ' )
371388
372389 # Append header for DataFrame loading
373- datframe_content .append (f"""```{{python}}
390+ dataframe_content .append (f"""```{{python}}
374391#| label: '{ dataframe .title } '
375392#| fig-cap: ""
376393""" )
394+ # Mapping of file extensions to read functions
395+ read_function_mapping = {
396+ r .DataFrameFormat .CSV .value_with_dot : pd .read_csv ,
397+ r .DataFrameFormat .PARQUET .value_with_dot : pd .read_parquet ,
398+ r .DataFrameFormat .TXT .value_with_dot : pd .read_table ,
399+ r .DataFrameFormat .XLS .value_with_dot : pd .read_excel
400+ }
377401 try :
378- if dataframe .file_format == r .DataFrameFormat .CSV :
379- if dataframe .delimiter :
380- datframe_content .append (f"""df = pd.read_csv('{ os .path .join (".." , dataframe .file_path )} ', delimiter='{ dataframe .delimiter } ')""" )
381- datframe_content .extend (self ._show_dataframe (dataframe , is_report_static ))
382- else :
383- datframe_content .append (f"""df = pd.read_csv('{ os .path .join (".." , dataframe .file_path )} ')""" )
384- datframe_content .extend (self ._show_dataframe (dataframe , is_report_static ))
385- elif dataframe .file_format == r .DataFrameFormat .PARQUET :
386- datframe_content .append (f"""df = pd.read_parquet('{ os .path .join (".." , dataframe .file_path )} ')""" )
387- datframe_content .extend (self ._show_dataframe (dataframe , is_report_static ))
388- elif dataframe .file_format == r .DataFrameFormat .TXT :
389- datframe_content .append (f"""df = pd.read_csv('{ os .path .join (".." , dataframe .file_path )} ', sep='\\ t')""" )
390- datframe_content .extend (self ._show_dataframe (dataframe , is_report_static ))
391- elif dataframe .file_format == r .DataFrameFormat .EXCEL :
392- datframe_content .append (f"""df = pd.read_excel('{ os .path .join (".." , dataframe .file_path )} ')""" )
393- datframe_content .extend (self ._show_dataframe (dataframe , is_report_static ))
394- else :
395- self .report .logger .error (f"Unsupported DataFrame file format: { dataframe .file_format } " )
396- raise ValueError (f"Unsupported DataFrame file format: { dataframe .file_format } " )
402+ # Check if the file extension matches any DataFrameFormat value
403+ file_extension = os .path .splitext (dataframe .file_path )[1 ].lower ()
404+ if not any (file_extension == fmt .value_with_dot for fmt in r .DataFrameFormat ):
405+ self .report .logger .error (f"Unsupported file extension: { file_extension } . Supported extensions are: { ', ' .join (fmt .value for fmt in r .DataFrameFormat )} ." )
406+
407+ # Build the file path (URL or local file)
408+ file_path = dataframe .file_path if is_url (dataframe .file_path ) else os .path .join (".." , dataframe .file_path )
409+
410+ # Load the DataFrame using the correct function
411+ read_function = read_function_mapping [file_extension ]
412+ dataframe_content .append (f"""df = pd.{ read_function .__name__ } ('{ file_path } ')""" )
413+
414+ # Display the dataframe
415+ dataframe_content .extend (self ._show_dataframe (dataframe , is_report_static ))
397416
398417 except Exception as e :
399418 self .report .logger .error (f"Error generating content for DataFrame: { dataframe .title } . Error: { str (e )} " )
400419 raise
401-
402420 # Add caption if available
403421 if dataframe .caption :
404- datframe_content .append (f'>{ dataframe .caption } \n ' )
422+ dataframe_content .append (f'>{ dataframe .caption } \n ' )
405423
406424 self .report .logger .info (f"Successfully generated content for DataFrame: '{ dataframe .title } '" )
407- return datframe_content
425+ return dataframe_content
408426
409427 def _generate_markdown_content (self , markdown ) -> List [str ]:
410428 """
@@ -425,13 +443,25 @@ def _generate_markdown_content(self, markdown) -> List[str]:
425443 markdown_content .append (f'### { markdown .title } ' )
426444
427445 try :
428- markdown_content .append (f"""```{{python}}
446+ # Initialize md code with common structure
447+ markdown_content .append (f"""
448+ ```{{python}}
429449#| label: '{ markdown .title } '
430- #| fig-cap: ""
450+ #| fig-cap: ""\n """ )
451+ # If the file path is a URL, generate code to fetch content via requests
452+ if is_url (markdown .file_path ):
453+ markdown_content .append (f"""
454+ response = requests.get('{ markdown .file_path } ')
455+ response.raise_for_status()
456+ markdown_content = response.text\n """ )
457+ else : #If it's a local file
458+ markdown_content .append (f"""
431459with open('{ os .path .join (".." , markdown .file_path )} ', 'r') as markdown_file:
432- markdown_content = markdown_file.read()
433- display.Markdown(markdown_content)
434- ```\n """ )
460+ markdown_content = markdown_file.read()\n """ )
461+
462+ # Code to display md content
463+ markdown_content .append (f"""display.Markdown(markdown_content)\n ```\n """ )
464+
435465 except Exception as e :
436466 self .report .logger .error (f"Error generating content for Markdown: { markdown .title } . Error: { str (e )} " )
437467 raise
@@ -450,7 +480,7 @@ def _generate_image_content(self, image_path: str, alt_text: str = "", width: in
450480 Parameters
451481 ----------
452482 image_path : str
453- Path to the image file.
483+ Path to the image file or a URL to the image .
454484 width : int, optional
455485 Width of the image in pixels (default is 650).
456486 height : int, optional
@@ -463,8 +493,11 @@ def _generate_image_content(self, image_path: str, alt_text: str = "", width: in
463493 str
464494 The formatted image content.
465495 """
466- return f"""
467- } ){{ width={ width } px height={ height } px fig-align="center"}}\n """
496+ # Check if the image path is a URL or a local file path
497+ if is_url (image_path ):
498+ return f"""{{ width={ width } px height={ height } px fig-align="center"}}\n """
499+ else :
500+ return f"""} ){{ width={ width } px height={ height } px fig-align="center"}}\n """
468501
469502 def _show_dataframe (self , dataframe , is_report_static , static_dir : str = STATIC_FILES_DIR ) -> List [str ]:
470503 """
@@ -517,11 +550,11 @@ def _generate_component_imports(self, component: r.Component) -> List[str]:
517550 # Dictionary to hold the imports for each component type
518551 components_imports = {
519552 'plot' : {
520- r .PlotType .ALTAIR : ['import altair as alt' ],
521- r .PlotType .PLOTLY : ['import plotly.io as pio' ]
553+ r .PlotType .ALTAIR : ['import altair as alt' , 'import requests' ],
554+ r .PlotType .PLOTLY : ['import plotly.io as pio' , 'import requests' ]
522555 },
523556 'dataframe' : ['import pandas as pd' , 'from itables import show' , 'import dataframe_image as dfi' ],
524- 'markdown' : ['import IPython.display as display' ]
557+ 'markdown' : ['import IPython.display as display' , 'import requests' ]
525558 }
526559
527560 # Iterate over sections and subsections to determine needed imports
0 commit comments