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: Union[str, Task]

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

id: str, optional, default None

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

type: str, optional, default None

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]

#FIXME document

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

[source]

from metaflow.cards import VegaChart

VegaChart.from_altair_chart

[source]

VegaChart.update(self, spec)

[source]

Update the chart.

Parameters 

spec: dict or altair.Chart

The updated chart spec or an altair Chart Object.

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]

#FIXME document

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.

ShowDoc(MetaflowCard.render)
    ---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

File ~/mambaforge/envs/docs/lib/python3.11/site-packages/IPython/core/formatters.py:344, in BaseFormatter.__call__(self, obj)
342 method = get_real_method(obj, self.print_method)
343 if method is not None:
--> 344 return method()
345 return None
346 else:


File ~/mambaforge/envs/docs/lib/python3.11/site-packages/nbdoc/showdoc.py:218, in ShowDoc._repr_html_(self)
216 def _repr_html_(self):
217 "This method controls what is displayed in Jupyter Notebooks."
--> 218 return f'<HTMLRemove>\n{self.nbhtml}\n</HTMLRemove>\n{self.jsx}'


File ~/mambaforge/envs/docs/lib/python3.11/site-packages/nbdoc/showdoc.py:253, in ShowDoc.jsx(self)
251 nm = f'<DocSection type="{self.typ}" name="{self.objnm}" module="{self.modnm}" show_import="{self.show_import}" heading_level="{self.hd_lvl}"{self._src_link_attr}>'
252 spoof = '...' if self.decorator else self.spoofstr
--> 253 sp = get_sig_section(self.obj, spoofstr=spoof)
254 return f'{nm}\n{sp}\n' + self.npdocs + '\n</DocSection>'


File ~/mambaforge/envs/docs/lib/python3.11/site-packages/nbdoc/showdoc.py:115, in get_sig_section(obj, spoofstr)
113 return ''
114 params = sig.parameters.items()
--> 115 jsx_params = [fmt_sig_param(p) for _, p in params]
116 else:
117 jsx_params = [f'<SigArg name="{spoofstr}" />']


File ~/mambaforge/envs/docs/lib/python3.11/site-packages/nbdoc/showdoc.py:115, in <listcomp>(.0)
113 return ''
114 params = sig.parameters.items()
--> 115 jsx_params = [fmt_sig_param(p) for _, p in params]
116 else:
117 jsx_params = [f'<SigArg name="{spoofstr}" />']


File ~/mambaforge/envs/docs/lib/python3.11/site-packages/nbdoc/showdoc.py:99, in fmt_sig_param(p)
96 prefix = f'<SigArg name="{name}" '
98 if p.annotation != inspect._empty:
---> 99 prefix += f'type="{p.annotation.__name__}" '
100 if p.default != inspect._empty:
101 prefix += f'default="{p.default}" '


AttributeError: 'str' object has no attribute '__name__'





<nbdoc.showdoc.ShowDoc at 0x1149f0790>

MetaflowCard.render_runtime

[source]

MetaflowCard.refresh

[source]