<@ULVA73B9P> how can I have plot outputs in a pref...
# marvin-ai
j
@Marvin how can I have plot outputs in a prefect flow visible in the ui
m
thought for 209.4 seconds
Great question! In Prefect 3.x, the best way to make plots visible in the UI is to create artifacts during your flow/task run. You have two common options: 1) Easiest (no hosting): embed the plot in a Markdown artifact as a base64 image - Shows directly in the run’s Artifacts tab and on the global Artifacts page (if you set a
key
) - Works with matplotlib and most libraries that can save to PNG
Copy code
from prefect import flow, task
from prefect.artifacts import create_markdown_artifact
import io, base64
import matplotlib.pyplot as plt

@task
def plot_as_markdown():
    fig, ax = plt.subplots()
    ax.plot([1, 2, 3], [1, 4, 9])
    ax.set_title("Demo plot")

    buf = io.BytesIO()
    fig.savefig(buf, format="png", dpi=120, bbox_inches="tight")
    plt.close(fig)
    buf.seek(0)
    b64 = base64.b64encode(buf.read()).decode()

    md = f"!<data:image/png;base64,{b64}|plot>"
    create_markdown_artifact(
        markdown=md,
        key="demo-plot",  # lowercase, numbers, dashes only
        description="Matplotlib figure embedded as Markdown"
    )

@flow
def demo_flow():
    plot_as_markdown()

if __name__ == "__main__":
    demo_flow()
2) Image artifact (requires a public URL) - Use
create_image_artifact(image_url=...)
- You’ll need to host the image (e.g., S3 with public-read, static web server) - Then pass the public URL to the artifact
Copy code
from prefect import flow, task
from prefect.artifacts import create_image_artifact
import io
import matplotlib.pyplot as plt
import boto3

@task
def plot_and_publish():
    fig, ax = plt.subplots()
    ax.plot([1, 2, 3], [1, 4, 9])
    buf = io.BytesIO()
    fig.savefig(buf, format="png")
    plt.close(fig)
    buf.seek(0)

    # Upload to a publicly accessible location (example: S3)
    s3 = boto3.client("s3")
    bucket, key = "my-public-bucket", "plots/demo.png"
    s3.upload_fileobj(
        buf, bucket, key,
        ExtraArgs={"ContentType": "image/png", "ACL": "public-read"}
    )
    url = f"https://{bucket}.<http://s3.amazonaws.com/{key}|s3.amazonaws.com/{key}>"

    create_image_artifact(
        image_url=url,
        key="demo-plot",
        description="Matplotlib figure hosted on S3"
    )

@flow
def demo_flow():
    plot_and_publish()
Notes - The
key
is important if you want the artifact to show up on the global Artifacts page; it must be lowercase letters, numbers, and dashes. - Without a
key
, you’ll still see the artifact under that run’s Artifacts tab. - If you have an interactive Plotly chart, host the HTML and use a link artifact:
Copy code
from prefect.artifacts import create_link_artifact
  create_link_artifact(link=html_url, link_text="Interactive chart", key="plotly-demo")
Where to view in the UI - Flow/Task run details → Artifacts tab - Global Artifacts page (requires
key
) to see the latest version and history of that artifact Docs - Concepts: Artifacts concepts - How-to: Create artifacts - API: prefect.artifacts API Would you prefer the Markdown-embedded route (no hosting) or hosting images (e.g., S3)? Also, which plotting library are you using?