Source code for energytrackr.plot.builtin_page_sections.plot_embed
"""PlotEmbed - embeds registered Bokeh plots into HTML report using Tabs."""from__future__importannotationsfrombokeh.core.validation.checkimportValidationIssues,check_integrityfrombokeh.embedimportcomponentsfrombokeh.modelsimportTabPanel,Tabsfrombokeh.resourcesimportCDNfromjinja2importEnvironmentfromenergytrackr.plot.builtin_plots.registryimportget_registered_plotsfromenergytrackr.plot.core.contextimportContextfromenergytrackr.plot.core.interfacesimportPageObjfromenergytrackr.utils.exceptionsimportBokehValidationIssuesErrorfromenergytrackr.utils.loggerimportlogger
[docs]classPlotEmbed(PageObj):"""Page section that injects the interactive Bokeh charts into HTML."""def__init__(self,div_class:str="bokeh-chart")->None:"""Initialize the PlotEmbed section."""self.div_class=div_class
[docs]defrender(self,env:Environment,ctx:Context)->str:# noqa: ARG002"""Return HTML snippet containing Bokeh resources, script, and div. Args: env (Environment): Jinja2 environment for rendering. ctx (Context): Context object containing the plots to embed. Returns: str: HTML snippet with Bokeh resources and embedded plots. """tabs=self._build_tabs(ctx)self._validate_tabs(tabs)returnself._render_html(tabs)
@staticmethoddef_build_tabs(ctx:Context)->list[TabPanel]:"""Build TabPanels in registry order, then add any extras. Args: ctx (Context): Context object containing the plots to embed. Returns: list[TabPanel]: List of TabPanels for each plot. """tabs:list[TabPanel]=[TabPanel(child=plot_layout,title=name)fornameinget_registered_plots()if(plot_layout:=ctx.plots.get(name))]fortitle,layoutinctx.plots.items():iftitlenotinget_registered_plots():tabs.append(TabPanel(child=layout,title=title))returntabs@staticmethoddef_validate_tabs(tabs:list[TabPanel])->None:"""Validate each tab's Bokeh layout, raise if issues found. Args: tabs (list[TabPanel]): List of TabPanels to validate. Raises: BokehValidationIssuesError: If any validation issues are found. """forpanelintabs:root=panel.childrefs=root.references()issues:ValidationIssues=check_integrity(refs)ifissues.errororissues.warning:logger.error("๐ Bokeh validation issues in tab '%s':",panel.title)forissueinissues.error:logger.error(" E-%d%s: %s",issue.code,issue.name,issue.text)forissueinissues.warning:logger.warning(" W-%d%s: %s",issue.code,issue.name,issue.text)raiseBokehValidationIssuesError(panel.title,issues)def_render_html(self,tabs:list[TabPanel])->str:"""Render the final HTML snippet with CDN resources and Bokeh components. Args: tabs (list[TabPanel]): List of TabPanels to render. Returns: str: HTML snippet with CDN resources and embedded plots. """tabs_widget=Tabs(tabs=tabs,sizing_mode="stretch_width")script,div=components(tabs_widget)cdn_js=CDN.js_filescdn_css=CDN.css_filescdn_tags=[f'<link rel="stylesheet" href="{url}">'forurlincdn_css]cdn_tags+=[f'<script src="{url}"></script>'forurlincdn_js]cdn_html="\n".join(cdn_tags)returnf'{cdn_html}\n{script}\n<div class="{self.div_class}">{div}</div>'