Open Yairama opened 3 months ago
Hello @Yairama and thank you for your question! The answer is that there's no built-in way of doing this but it is on the roadmap as a future feature. But, depending on exactly what you want to save, you may already be able to achieve what you need.
Please could you explain exactly what you'd like to save? e.g. just the graphs? one page or multiple pages? the filters/parameters controls? It's already possible to save plots to png from your browser by clicking the little "Download to png" icon in the top right corner of each graph.
Hello @antonymilne ,
Thank you for your response! I'm content with saving an HTML page containing multiple graphs divided into various sections, or several pages (each section as a page) with their respective graphs. There is no need for filters; I'm only interested in ensuring the plots remain interactive.
P.S.: Nice cat.
Hi @Yairama, sorry for the very delayed reply - I completely lost track of this and was then reminded about it again today.
Here's what I've come up with as a possible solution that I think should work pretty well for now🤞The biggest (only?) catch is that you cannot easily download the entire dashboard into a single HTML file; instead you need to download each page individually.
This page from the plotly docs is a good reference. Note:
plotly.js
but that can be changed using the include_js
argumentformat
like I did here with REPORT_TEMPLATE
Link to py.cafe example with the following code.
from dash import dcc, callback, State, Input, Output
import dash_bootstrap_components as dbc
from dash.exceptions import PreventUpdate
import vizro.plotly.express as px
from vizro import Vizro
import vizro.models as vm
from vizro.managers import model_manager
from vizro.models import Page
from vizro.models.types import capture
import plotly.graph_objs as go
import plotly.io as pio
df = px.data.iris()
# Template that graph HTML is injected into
REPORT_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
{graphs}
</body>
</html>
"""
class PageWithDownloadReport(vm.Page):
def pre_build(self):
super().pre_build()
# Fetch all graphs on the page. There will be a nicer way to do this in future
graph_ids = [
model_id
for model_id in model_manager._get_model_children(self.id)
if isinstance(model_manager[model_id], vm.Graph)
]
# Build a callback to take in all graph on the page and output an HTML report
@callback(
output=Output("download", "data", allow_duplicate=True),
inputs=[
Input(f"download_button_{self.id}", "n_clicks"),
tuple(State(graph_id, "figure") for graph_id in graph_ids),
],
prevent_initial_call=True,
)
def download_report(n_clicks, graphs):
if not n_clicks:
raise PreventUpdate
# Convert each graph to HTML, concatenate all the resulting divs together and then inject into
# REPORT_TEMPLATE.
graphs_html = "".join(pio.to_html(graph, full_html=False) for graph in graphs)
report_html = REPORT_TEMPLATE.format(graphs=graphs_html)
return dcc.send_string(report_html, filename=f"report_{self.id}.html")
# Add download button to controls.
self.controls.append(
vm.Button(id=f"download_button_{self.id}", text="Download report"),
)
page_1 = PageWithDownloadReport(
title="Page 1",
components=[
vm.Graph(figure=px.histogram(df, x="sepal_width", color="species")),
vm.Graph(figure=px.scatter(df, x="sepal_width", y="sepal_length", color="species")),
],
controls=[vm.Filter(column="species")],
)
page_2 = PageWithDownloadReport(
title="Page 2",
components=[
vm.Graph(figure=px.scatter(df, x="sepal_width", y="sepal_length", color="species")),
],
controls=[vm.Filter(column="species")],
)
dashboard = vm.Dashboard(pages=[page_1, page_2])
app = Vizro().build(dashboard)
# Download component to handle downloaded reports:
app.dash.layout.children.append(dcc.Download(id="download"))
app.run()
FYI @petar-qb
Thanks a lot @antonymilne for the backup solution !! Won't it be possible to keep the filters, buttons,...inside the html report ?
Basically, an integrated solution of this feature would be a real plus for vizro. For medium-sized applications, sharing an html file is oftent a faster solution with no security constraints, compared with more traditional deployment solutions. Some libraries (such as Datapane) offered this practical feature.
@antonymilne Thanks for the answer, testing it!
Additionally, it would be a future feature?
Thanks for the comment @Bebio95! To be honest this feature has gone down in priority now that we have py.cafe which enables you to easily share not just static HTML but a fully functioning dashboard. This definitely does not work for all use cases (e.g. with a free account your dashboard will be public for a start) but we really like it as an alternative to traditional deployments.
However, static export is still something that's on our roadmap and I am always thinking about it and have repeatedly gone back to it and played around with some options. And this time I think I may have actually found something that works great without us doing anything! 🙌
Check out https://github.com/gildas-lormeau/SingleFile. It's a browser extension that works great on Vizro (and Dash too I guess).
Some alternative that's also worth knowing about:
Let me know what you think! I've really spent a lot of time thinking about this problem over the last year and I'm super excited to have found SingleFile so I hope it works for you!
Hello @antonymilne, First of all, I want to really thank you for your work and all the time you have dedicated to this topic. I will have a look at the different solutions proposed and I'll give you a feedback shortly. Thks
Question
Hi, I am using Vizro to generate visualizations and would like to know if there is a way to save the report in HTML format. My goal is to save these reports as artifacts in MLflow. Could you provide an example or guidance on how to achieve this?
Code/Examples
No response
Which package?
vizro
Code of Conduct