Data Visualization and HTML Rendering
flyte-sdk provides a flexible rendering system to visualize data directly in the Flyte console. You can either use automatic rendering by annotating your task signatures or manually build multi-tab reports using the flyte.report module.
Automatic Rendering with Annotated Types
You can attach a renderer to a task input or output using typing.Annotated. When Flyte executes the task, it uses the specified renderer to generate an HTML representation for the Flyte Deck.
from typing import Annotated
import pandas as pd
from flyte.types import TopFrameRenderer
import flyte
@flyte.task
def process_data(
# Render the first 5 rows and 5 columns of the input dataframe
df: Annotated[pd.DataFrame, TopFrameRenderer(max_rows=5, max_cols=5)]
) -> pd.DataFrame:
return df
Built-in Renderers
flyte-sdk includes several built-in renderers in flyte.types:
TopFrameRenderer(max_rows=10, max_cols=100): Renders a Pandas DataFrame as an HTML table.MarkdownRenderer(): Converts a markdown string into HTML usingmarkdown-it.SourceCodeRenderer(title="Source Code"): Renders Python source code with syntax highlighting using Pygments.PythonDependencyRenderer(title="Dependencies"): Generates a report of installed pip packages and provides a "Copy as requirements.txt" button.
Example using MarkdownRenderer:
from typing import Annotated
from flyte.types import MarkdownRenderer
import flyte
@flyte.task
def get_summary() -> Annotated[str, MarkdownRenderer()]:
return "# Task Summary\n\n* Success: True\n* Items processed: 100"
Creating Custom Renderers
To create a custom renderer, implement the Renderable protocol defined in src/flyte/types/_renderer.py. Your class must provide a to_html method that returns a valid HTML string.
from typing import Annotated, Any
from flyte.types import Renderable
import flyte
class ColorRenderer(Renderable):
def __init__(self, color: str = "blue"):
self._color = color
def to_html(self, python_value: Any) -> str:
# Return an HTML fragment (usually inserted into a <div>)
return f"<div style='color: {self._color}'>Value: {python_value}</div>"
@flyte.task
def custom_render_task(x: int) -> Annotated[int, ColorRenderer(color="red")]:
return x
Manual Reporting with flyte.report
For complex visualizations or multi-tab reports, use the flyte.report module. You must enable reporting in the @task decorator by setting report=True.
import flyte
import flyte.report
import pandas as pd
@flyte.task(report=True)
async def generate_complex_report():
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
# Log to the default 'main' tab
flyte.report.log("<h2>Execution Started</h2>")
# Create and log to a specific tab
data_tab = flyte.report.get_tab("Data View")
data_tab.log(df.to_html(classes="table table-striped"))
# Replace content in a tab
status_tab = flyte.report.get_tab("Status")
status_tab.replace("<p>Processing complete!</p>")
# You must flush the report to persist it to storage
await flyte.report.flush.aio()
Key Reporting Functions
flyte.report.log(content: str, do_flush: bool = False): Appends HTML content to the "main" tab.flyte.report.replace(content: str, do_flush: bool = False): Overwrites the content of the "main" tab.flyte.report.get_tab(name: str): Returns aTabobject for a specific tab name.Tabobjects have their ownlog(content)andreplace(content)methods.flyte.report.flush(): Persists the current report state to Flyte storage. This is available as a synchronous function or an asynchronous one viaflush.aio().
Customizing Global Dataframe Rendering
By default, flyte-sdk uses TopFrameRenderer for Pandas DataFrames and ArrowRenderer for PyArrow Tables. You can override these globally using DataFrameTransformerEngine.register_renderer.
from flyte.io._dataframe.dataframe import DataFrameTransformerEngine
from flyte.types import Renderable
import pandas as pd
class MyCustomDFRenderer(Renderable):
def to_html(self, df: pd.DataFrame) -> str:
return f"DataFrame with {len(df)} rows"
# Register the renderer globally for all pd.DataFrame types
DataFrameTransformerEngine.register_renderer(pd.DataFrame, MyCustomDFRenderer())
Troubleshooting and Gotchas
- HTML Fragments: The
to_htmlmethod andflyte.report.logshould return/accept HTML fragments (e.g.,<div>...</div>), not full HTML documents with<html>or<body>tags, as they are typically inserted into existing containers in the Flyte Console. - Flushing Reports: If you use
flyte.report, the report will not appear in the Flyte Deck unless you callflush()orawait flush.aio()before the task completes. - Performance: Large dataframes are truncated by default (
DEFAULT_MAX_ROWS = 10,DEFAULT_MAX_COLS = 100) to prevent UI performance issues in the browser. UseTopFrameRenderer(max_rows=N)to adjust these limits.