Skip to main content

Cards - Visualizing results

Metaflow Cards allows you to produce human readable reports in workflows and observe their behavior live. Use the following APIs to enable, customize, and access cards:

Retrieving cards

To retrieve a card after a run has finished, use the get_cards function e.g. in a notebook or the card get command on the CLI.

Since a task can contain multiple cards get_cards returns a container object, CardContainer, which holds Card objects corresponding to individual cards. Notably both CardContainer and Card objects contain a function that allow them to visualize cards in the notebook output cell automatically, so a single get_cards call can be used to show all cards of a step in a notebook.

get_cards(task, id, type, follow_resumed)

[source]

from metaflow.cards import get_cards

Get cards related to a Task.

Note that get_cards resolves the cards contained by the task, but it doesn't actually retrieve them from the datastore. Actual card contents are retrieved lazily either when the card is rendered in a notebook to when you call Card.get. This means that get_cards is a fast call even when individual cards contain a lot of data.

Parameters 

task: str or Task

A Task object or pathspec {flow_name}/{run_id}/{step_name}/{task_id} that uniquely identifies a task.

id: str, optional

The ID of card to retrieve if multiple cards are present.

type: str, optional

The type of card to retrieve if multiple cards are present.

follow_resumed: bool, default: True

If the task has been resumed, then setting this flag will resolve the card for the origin task.

Returns 

CardContainer

A list-like object that holds Card objects.

CardContainer()

[source]

CardContainer is an immutable list-like object, returned by get_cards, which contains individual Cards.

Notably, CardContainer contains a special _repr_html_ function which renders cards automatically in an output cell of a notebook.

The following operations are supported:

cards = get_cards(MyTask)

# retrieve by index
first_card = cards[0]

# check length
if len(cards) > 1:
    print('many cards present!')

# iteration
list_of_cards = list(cards)

Card represents an individual Metaflow Card, a single HTML file, produced by the card @card decorator. Cards are contained by CardContainer, returned by get_cards.

Note that the contents of the card, an HTML file, is retrieved lazily when you call Card.get for the first time or when the card is rendered in a notebook.

Card.get(self)

[source]

Retrieves the HTML contents of the card from the Metaflow datastore.

Returns 

str

HTML contents of the card.

Card.view(self)

[source]

Opens the card in a local web browser.

This call uses Python's built-in webbrowser module to open the card.

Card components

You can customize the contents of a card easily using card components, a set of visual elements included in Metaflow which are documented below. See Easy Custom Reports with Card Components for instructions.

The components are added to cards in @step methods (or functions called from steps), using the current.card object.

Markdown

Markdown(text)

[source]

from metaflow.cards import Markdown

A block of text formatted in Markdown.

Example:

current.card.append(
    Markdown("# This is a header appended from `@step` code")
)
Parameters 

text: str

Text formatted in Markdown.

Markdown.update(self, text)

[source]

Update the markdown content of this component. Use this to refresh content of a dynamic card.

Parameters 

text: str

Text formatted in Markdown.

Image

Image(src, label, disable_updates)

[source]

from metaflow.cards import Image

An image.

Images can be created directly from PNG/JPG/GIF bytes, PIL.Image`s, or Matplotlib figures. Note that the image data is embedded in the card, so no external files are required to show the image.

Example: Create an Image from bytes:

current.card.append(
    Image(
        requests.get("https://www.gif-vif.com/hacker-cat.gif").content,
        "Image From Bytes"
    )
)

Example: Create an Image from a Matplotlib figure

import pandas as pd
import numpy as np
current.card.append(
    Image.from_matplotlib(
        pandas.DataFrame(
            np.random.randint(0, 100, size=(15, 4)),
            columns=list("ABCD"),
        ).plot()
    )
)

Example: Create an Image from a PIL Image

from PIL import Image as PILImage
current.card.append(
    Image.from_pil_image(
        PILImage.fromarray(np.random.randn(1024, 768), "RGB"),
        "From PIL Image"
    )
)
Parameters 

src: bytes

The image data in bytes.

label: str

Optional label for the image.

Attributes 

component_id

Image.from_matplotlib(plot, label, disable_updates)

[source]

Create an Image from a Matplotlib plot.

Parameters 

plot: matplotlib.figure.Figure or matplotlib.axes.Axes or matplotlib.axes._subplots.AxesSubplot

a PIL axes (plot) object.

label: str, optional

Optional label for the image.

Image.from_pil_image(pilimage, label, disable_updates)

[source]

Create an Image from a PIL image.

Parameters 

pilimage: PIL.Image

a PIL image object.

label: str, optional

Optional label for the image.

Artifact

Artifact(artifact, name, compressed)

[source]

from metaflow.cards import Artifact

A pretty-printed version of any Python object.

Large objects are truncated using Python's built-in reprlib.

Example:

from datetime import datetime
current.card.append(Artifact({'now': datetime.utcnow()}))
Parameters 

artifact: object

Any Python object.

name: str, optional

Optional label for the object.

compressed: bool, default: True

Use a truncated representation.

Table

Table(data, headers, disable_updates)

[source]

from metaflow.cards import Table

A table.

The contents of the table can be text or numerical data, a Pandas dataframe, or other card components: Artifact, Image, Markdown objects.

Example: Text and artifacts

from metaflow.cards import Table, Artifact
current.card.append(
    Table([
        ['first row', Artifact({'a': 2})],
        ['second row', Artifact(3)]
    ])
)

Example: Table from a Pandas dataframe

from metaflow.cards import Table
import pandas as pd
import numpy as np
current.card.append(
    Table.from_dataframe(
        pd.DataFrame(
            np.random.randint(0, 100, size=(15, 4)),
            columns=list("ABCD")
        )
    )
)
Parameters 

data: List[List[str or MetaflowCardComponent]], optional

List (rows) of lists (columns). Each item can be a string or a MetaflowCardComponent.

headers: List[str], optional

Optional header row for the table.

Attributes 

component_id

Table.from_dataframe(dataframe, truncate)

[source]

Create a Table based on a Pandas dataframe.

Parameters 

dataframe: Optional[pandas.DataFrame]

Pandas dataframe.

truncate: bool, default: True

Truncate large dataframe instead of showing all rows (default: True).

VegaChart

VegaChart(spec, show_controls)

[source]

from metaflow.cards import VegaChart

Create a chart based on a Vega Lite specification.

Parameters 

spec: dict

Vega Lite chart specification as a dictionary.

show_controls: bool, optional

Show Vega controls for downloading the chart image etc.

VegaChart.from_altair_chart(altair_chart)

[source]

Create a chart based on an Altair Chart object.

Parameters 

chart: altair.Chart

An Altair Chart object.

VegaChart.update(self, spec)

[source]

Update the chart specification and data. Use this to refresh content of a dynamic card.

Parameters 

spec: dict

The updated chart Vega Lite specifcation

ProgressBar

ProgressBar(max, label, value, unit, metadata)

[source]

from metaflow.cards import ProgressBar

A Progress bar for tracking progress of any task.

Example:

progress_bar = ProgressBar(
    max=100,
    label="Progress Bar",
    value=0,
    unit="%",
    metadata="0.1 items/s"
)
current.card.append(
    progress_bar
)
for i in range(100):
    progress_bar.update(i, metadata="%s items/s" % i)

Parameters 

max: int

The maximum value of the progress bar.

label: str, optional

Optional label for the progress bar.

value: int, optional

Optional initial value of the progress bar.

unit: str, optional

Optional unit for the progress bar.

metadata: str, optional

Optional additional information to show on the progress bar.

Attributes 

component_id

ProgressBar.update(self, new_value, metadata)

[source]

Update the progress bar status. Use this to refresh content of a dynamic card.

Parameters 

new_value: int

Updated value of the progress bar

metadata: str

Updated additional information

Defining a custom card

You can define custom cards types (T in @card(type=T)) by creating a Python package that includes a class that derives from MetaflowCard, documented below. Read more in Advanced, Shareable Cards with Card Templates.

Find detailed instructions, a starter template, and an example of a simple static custom card and an example of a dynamic card.

MetaflowCard(options)

[source]

from metaflow.cards import MetaflowCard

Metaflow cards derive from this base class.

Subclasses of this class are called card types. The desired card type T is defined in the @card decorator as @card(type=T).

After a task with @card(type=T, options=S) finishes executing, Metaflow instantiates a subclass C of MetaflowCard that has its type attribute set to T, i.e. C.type=T. The constructor is given the options dictionary S that contains arbitrary JSON-encodable data that is passed to the instance, parametrizing the card. The subclass may override the constructor to capture and process the options.

The subclass needs to implement a render(task) method that produces the card contents in HTML, given the finished task that is represented by a Task object.

Parameters 

options: Dict

JSON-encodable dictionary containing user-definable options for the class.

Attributes 

type: str

Card type string. Note that this should be a globally unique name, similar to a Python package name, to avoid name clashes between different custom cards.

MetaflowCard.render(self, task)

[source]

Produce custom card contents in HTML. The HTML returned by this method represents the final card contents.

Subclasses override this method to customize the card contents.

Note that dynamic cards can also access an attribute self.runtime_data inside this method to retrieve the latest user-defined runtime data, i.e. the latest data object passed in to render_runtime or refresh.

Parameters 

task: Task

A Task object that allows you to access data from the finished task and tasks preceding it.

Returns 

str

Card contents as an HTML string.

MetaflowCard.render_runtime(self, task, data)

[source]

Produce intermediate custom card contents in HTML. The HTML returned by this method represents a runtime snapshot of a dynamic card.

Subclasses may override this method to customize the card contents while a task is executing, making the card dynamic.

Note that in contrast to render, the task object passed to this method does not allow you to access artifacts from the currently running task, since they are not yet available. Instead, you can use the data dictionary to retrieve runtime data passed in the user-facing refresh method.

Parameters 

task: Task

A Task object that allows you to access data from tasks preceding it the currently running task.

data: dict

A dictionary containing user-defined runtime data.

Returns 

str

Card contents as an HTML string.

MetaflowCard.refresh(self, task, data)

[source]

Produce a runtime data JSON that is passed to the card Javascript on the client-side.

Subclasses may override this method to customize the card contents while a task is executing, making the card dynamic.

A JSON-encoded dictionary returned by this method is passed to the metaflow_card_update Javascript method on the client-side card to update its contents live. You can perform arbitrary preprocessing and refinement of the data passed to Javascript in this method. Or, you may simply return the user-defined data as-is.

Note that in contrast to render, the task object passed to this method does not allow you to access artifacts from the currently running task, since they are not yet available. Instead, you can use the data dictionary to retrieve runtime data passed in the user-facing refresh method.

Parameters 

task: Task

A Task object that allows you to access data from tasks preceding it the currently running task.

data: dict

A dictionary containing user-defined runtime data.

Returns 

dict

Dictionary passed to the card on the client-side