Interactive

class Endpoint(fn: Optional[Callable] = None, prefix: Optional[Union[str, fastapi.routing.APIRouter]] = None, route: Optional[str] = None)

Create an endpoint from a function in Meerkat.

Typically, you will not need to call this class directly, but instead use the endpoint decorator.

fn

The function to create an endpoint from.

Type

Callable

prefix

The prefix for this endpoint.

Type

str

route

The route for this endpoint.

Type

str

Note: All endpoints can be hit with a POST request at /{endpoint_id}/dispatch/ The request needs a JSON body with the following keys:

  • kwargs: a dictionary of keyword arguments to be

    passed to the endpoint function fn

  • payload: additional payload, if any

Optionally, the user can customize how endpoints are organized by specifying a prefix and a route. The prefix is a string that is used to identify a router. For example, the prefix for the router that handles endpoints is “/endpoint”. The route is a string that is used to identify an endpoint within a router. For example, the route for the endpoint that handles the get function could be “/get”.

If only a prefix is specified, then the route will be the name of the function e.g. “my_endpoint”. If both a prefix and a route are specified, then the route will be the specified route e.g. “/specific/route/”.

Refer to the FastAPI documentation for more information on how to create routers and endpoints.

property frontend

Returns a Pydantic model that can be should be sent to the frontend.

These models are typically named <something>Frontend (e.g. ComponentFrontend, StoreFrontend).

run(*args, **kwargs) Any

Actually run the endpoint function fn.

Parameters
  • *args – Positional arguments to pass to fn.

  • **kwargs – Keyword arguments to pass to fn.

Returns

The return value of fn.

compose(fn: Union[meerkat.interactive.endpoint.Endpoint, callable]) meerkat.interactive.endpoint.Endpoint

Create a new Endpoint that applies fn to the return value of this Endpoint. Effectively equivalent to fn(self.fn(*args, **kwargs)).

Parameters

fn (Endpoint, callable) – An Endpoint or a callable function that accepts a single argument of the same type as the return of this Endpoint (i.e. self).

Returns

The new composed Endpoint.

Return type

Endpoint

add_route(method: str = 'POST') None

Add a FastAPI route for this endpoint to the router. This function will not do anything if the router is None (i.e. no prefix was specified).

This function is called automatically when the endpoint is created using the endpoint decorator.

class State(prefix=None, *args, **kwargs)
endpoint(fn: Optional[Callable] = None, prefix: Optional[Union[str, fastapi.routing.APIRouter]] = None, route: Optional[str] = None, method: str = 'POST')

Decorator to mark a function as an endpoint.

An endpoint is a function that can be called to
  • update the value of a Store (e.g. incrementing a counter)

  • update a DataFrame (e.g. adding a new row)

  • run a computation and return its result to the frontend

  • run a function in response to a frontend event (e.g. button

    click)

Endpoints differ from reactive functions in that they are not automatically triggered by changes in their inputs. Instead, they are triggered by explicit calls to the endpoint function.

The Store and DataFrame objects that are modified inside the endpoint function will automatically trigger reactive functions that depend on them.

Warning: Due to this, we do not recommend running endpoints manually in your Python code. This can lead to unexpected behavior e.g. running an endpoint inside an operation may change a Store that causes the operation to be triggered repeatedly, leading to an infinite loop.

Almost all use cases can be handled by using the frontend to trigger endpoints.

@endpoint
def increment(count: Store, step: int = 1):
    count._ += step
    # ^ update the count Store, which will trigger operations
    #   that depend on it

    # return the updated value to the frontend
    return count._

# Now you can create a button that calls the increment endpoint
counter = Store(0)
button = Button(on_click=increment(counter))
# ^ read this as: call the increment endpoint with the counter
# Store when the button is clicked
Parameters
  • fn – The function to decorate.

  • prefix – The prefix to add to the route. If a string, it will be prepended to the route. If an APIRouter, the route will be added to the router.

  • route – The route to add to the endpoint. If not specified, the route will be the name of the function.

  • method – The HTTP method to use for the endpoint. Defaults to “POST”.

Returns

The decorated function, as an Endpoint object.

endpoints(cls=None, prefix=None)

Decorator to mark a class as containing a collection of endpoints. All instance methods in the marked class will be converted to endpoints.

This decorator is useful when you want to create a class that contains some logical state variables (e.g. a Counter class), along with methods to manipulate the values of those variables (e.g. increment or decrement the counter).

class react(reactive: bool = True, *, nested_return: Optional[bool] = None)

Context-manager that is used control if code is an interface operation.

Code-blocks in this context manager will create nodes in the operation graph, which are executed whenever their inputs are modified.

A basic example that adds two numbers:

a = Store(1)
b = Store(2)
with react():
    c = a + b

When either a or b is modified, the code block will re-execute with the new values of a and b.

Also functions as a decorator. (Make sure to instantiate with parenthesis.):

@react()
def add(a: int, b: int) -> int:
    return a + b

a = Store(1)
b = Store(2)
c = add(a, b)

A more complex example that concatenates two mk.DataFrame objects:

@react()
def concat(df1: mk.DataFrame, df2: mk.DataFrame) -> mk.DataFrame:
    return mk.concat([df1, df2])

df1 = mk.DataFrame(...)
df2 = mk.DataFrame(...)
df3 = concat(df1, df2)
Parameters
  • reactive – The function to decorate.

  • nested_return – Whether the function returns an object (e.g. List, Dict) with a nested structure. If True, a Store or Reference will be created for every element in the nested structure. If False, a single Store or Reference wrapping the entire object will be created. For example, if the function returns two DataFrames in a tuple, then nested_return should be True. However, if the functions returns a variable length list of ints, then nested_return should likely be False.

Returns

A decorated function that creates an operation node in the operation graph.

class no_react(nested_return: Optional[bool] = None)
is_reactive() bool

Whether the code is in reactive context.

Returns

True if the code is in a reactive context.

Return type

bool

make_endpoint(endpoint_or_fn: Optional[Union[Callable, meerkat.interactive.endpoint.Endpoint]]) meerkat.interactive.endpoint.Endpoint

Make an Endpoint.

class Modification(*, id: str)

Base class for modifications.

Modifications are used to track changes to Reference and Store nodes in the graph.

id

The id of the Reference or Store.

Type

str

property node

The Reference or Store node that this modification is for.

add_to_queue()

Add this modification to the queue.

class DataFrameModification(*, id: str, scope: List[str], type: str = 'ref')
property node: Node

The Reference or Store node that this modification is for.

class Document(id: str = None, *args, df: meerkat.dataframe.DataFrame, text_column: meerkat.interactive.graph.store.Store[str], paragraph_column: meerkat.interactive.graph.store.Store[str] = None, label_column: meerkat.interactive.graph.store.Store[str] = None, id_column: meerkat.interactive.graph.store.Store[str] = None, on_sentence_label: meerkat.interactive.endpoint.Endpoint = None, **kwargs)
class Store(wrapped: meerkat.interactive.types.T, backend_only: bool = False)
property frontend

Returns a Pydantic model that can be should be sent to the frontend.

These models are typically named <something>Frontend (e.g. ComponentFrontend, StoreFrontend).

set(new_value: meerkat.interactive.types.T)

Set the value of the store.

make_store(value: Union[str, None, pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool, List[Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool]], Dict[Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool], Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool]], Dict[Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool], List[Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool]]], List[Dict[Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool], Union[pydantic.types.StrictInt, pydantic.types.StrictStr, pydantic.types.StrictFloat, pydantic.types.StrictBool]]]]) meerkat.interactive.graph.store.Store

Make a Store.

If value is a Store, return it. Otherwise, return a new Store that wraps value.

Parameters

value (Union[str, Storeable]) – The value to wrap.

Returns

The Store wrapping value.

Return type

Store

trigger() List[meerkat.interactive.modification.Modification]

Trigger the computation graph of an interface based on a list of modifications.

To force trigger, add the modifications to the modification queue.

Returns

The list of modifications that resulted from running the

computation graph.

Return type

List[Modification]

class Component(id: str = None, *args, **kwargs)
property frontend

Returns a Pydantic model that can be should be sent to the frontend.

These models are typically named <something>Frontend (e.g. ComponentFrontend, StoreFrontend).

class Discover(*, df: meerkat.dataframe.DataFrame, by: meerkat.interactive.graph.store.Store[str], target: str = None, pred: str = None, on_discover: meerkat.interactive.endpoint.Endpoint = None, **kwargs)
class Gallery(id: str = None, *args, df: meerkat.dataframe.DataFrame, main_column: meerkat.interactive.graph.store.Store[str], tag_columns: meerkat.interactive.graph.store.Store[List[str]] = None, selected: meerkat.interactive.graph.store.Store[List[int]] = None, **kwargs)
class Markdown(id: str = None, *args, data: str, **kwargs)
class Match(*, df: meerkat.dataframe.DataFrame, against: meerkat.interactive.graph.store.Store[str], text: meerkat.interactive.graph.store.Store[str] = None, encoder: str = 'clip', on_match: meerkat.interactive.endpoint.Endpoint = None, title: meerkat.interactive.graph.store.Store[str] = None, **kwargs)
class Row(id: str = None, *args, df: meerkat.dataframe.DataFrame, primary_key_column: meerkat.interactive.graph.store.Store[str], cell_specs: meerkat.interactive.graph.store.Store[Dict[str, Dict[str, Any]]], selected_key: meerkat.interactive.graph.store.Store[str] = None, title: str = '', on_change: meerkat.interactive.endpoint.Endpoint = None, **kwargs)
class Plot(*, df: meerkat.dataframe.DataFrame, x: meerkat.interactive.graph.store.Store[str], y: meerkat.interactive.graph.store.Store[str], primary_key: meerkat.interactive.graph.store.Store[str] = None, x_label: meerkat.interactive.graph.store.Store[str] = None, y_label: meerkat.interactive.graph.store.Store[str] = None, type: meerkat.interactive.graph.store.Store[str] = Store('scatter'), slot: str = None, keys_to_remove: meerkat.interactive.graph.store.Store[list] = None, metadata_columns: list = None, on_select: meerkat.interactive.endpoint.Endpoint = None, **kwargs)
class SliceByCards(sliceby: meerkat.ops.sliceby.sliceby.SliceBy, main_column: str, tag_columns: List[str] = None, aggregations: Dict[str, Callable[[DataFrame], Union[int, float, str]]] = None, df: meerkat.dataframe.DataFrame = None)
class Stats(data: meerkat.interactive.graph.store.Store[Dict[str, Union[meerkat.interactive.graph.store.Store[Union[int, float, str]], int, float, str]]], specs: Mapping[str, Mapping[str, any]] = None)
class EditTarget(target: meerkat.dataframe.DataFrame, target_id_column: str, source_id_column: str)
class Table(id: str = None, *args, df: meerkat.dataframe.DataFrame, per_page: int = 100, **kwargs)
class Tabs(*, tabs: Union[Mapping[str, meerkat.interactive.app.src.lib.component.abstract.Component], Sequence[meerkat.interactive.app.src.lib.component.tabs.Tab]], **kwargs)
class Filter(id: str = None, *args, df: meerkat.dataframe.DataFrame, criteria: meerkat.interactive.graph.store.Store[List[meerkat.interactive.app.src.lib.component.filter.FilterCriterion]] = None, operations: meerkat.interactive.graph.store.Store[List[str]] = None, title: meerkat.interactive.graph.store.Store[str] = Store('Filter'), **kwargs)

This component handles filtering of a dataframe.

Filtering criteria are maintained in a Store. On change of values in the store, the dataframe is filtered.

This component will return a Reference object, which can be used downstream.

class Interface(component: meerkat.interactive.app.src.lib.component.abstract.Component, name: str = 'Interface', id: Optional[str] = None, height: str = '1000px', width: str = '100%')
reactive(fn: Optional[Callable] = None, nested_return: Optional[bool] = None) Callable

Decorator that is used to mark a function as an interface operation.

Functions decorated with this will create nodes in the operation graph, which are executed whenever their inputs are modified.

TODO: Remove nested_return argument. With the addition of __iter__ and __next__ to mk.gui.Store, we no longer need to support nested return values. This will require looking through current use of reactive and patching them.

A basic example that adds two numbers:

@reactive
def add(a: int, b: int) -> int:
    return a + b

a = Store(1)
b = Store(2)
c = add(a, b)

When either a or b is modified, the add function will be called again with the new values of a and b.

A more complex example that concatenates two mk.DataFrame objects:

@reactive
def concat(df1: mk.DataFrame, df2: mk.DataFrame) -> mk.DataFrame:
    return mk.concat([df1, df2])

df1 = mk.DataFrame(...)
df2 = mk.DataFrame(...)
df3 = concat(df1, df2)
Parameters
  • fn – The function to decorate.

  • nested_return – Whether the function returns an object (e.g. List, Dict) with a nested structure. If True, a Store or Reference will be created for every element in the nested structure. If False, a single Store or Reference wrapping the entire object will be created. For example, if the function returns two DataFrames in a tuple, then nested_return should be True. However, if the functions returns a variable length list of ints, then nested_return should likely be False.

Returns

A decorated function that creates an operation node in the operation graph.

start(shareable: bool = False, subdomain: Optional[str] = None, api_server_name: Optional[str] = None, api_port: Optional[int] = None, npm_port: Optional[int] = None, dev: bool = True)

Start a Meerkat interactive server.

Parameters
  • shareable (bool) – whether to share the interface at a publicly accesible link. This feature works by establishing a reverse SSH tunnel to a Meerkat server. Do not use this feature with private data. In order to use this feature, you will need an SSH key for the server. If you already have one, add it to the file at f”{config.system.ssh_identity_file}, or set the option mk.config.system.ssh_identity_file to the file where they are stored. If you don’t yet have a key, you can request access by emailing eyuboglu@stanford.edu. Remember to ensure after downloading it that the identity file is read/write only by the user (e.g. with chmod 600 path/to/id_file). See subdomain arg for controlling the domain name of the shared link. Defaults to False.

  • subdomain (str) – the subdomain to use for the shared link. For example, if subdomain=”myinterface”, then the shareable link will have the domain myinterface.meerkat.wiki. Defaults to None, in which case a random subdomain will be generated.

  • api_port (int) – the port to use for the Meerkat API server. Defaults to None, in which case a random port will be used.

  • npm_port (int) – the port to use for the Meerkat Vite server. Defaults to None, in which case a random port will be used.

class Editor(df: meerkat.dataframe.DataFrame, col: Union[meerkat.interactive.graph.store.Store, str], target: meerkat.interactive.edit.EditTarget = None, selected: meerkat.interactive.graph.store.Store[List[int]] = None, primary_key: str = None, title: str = None)
class Sort(id: str = None, *args, df: meerkat.dataframe.DataFrame, criteria: meerkat.interactive.graph.store.Store[Union[List[meerkat.interactive.app.src.lib.component.sort.SortCriterion], meerkat.interactive.app.src.lib.component.sort.SortCriterion]] = None, title: meerkat.interactive.graph.store.Store[str] = Store('Sort'), **kwargs)

This component handles a sort_by list and a sort_order list.

Sorting criteria are maintained in a Store. On change of these values, the dataframe is sorted.

This component will return a Reference object, which is a sorted view of the dataframe. The sort operation is out-of-place, so a new dataframe will be returned as a result of the op.

class StatsLabeler(df: meerkat.dataframe.DataFrame, label_target: meerkat.interactive.edit.EditTarget = None, phase_target: meerkat.interactive.edit.EditTarget = None, phase: Union[meerkat.interactive.graph.store.Store[str], str] = 'train', active_key: Union[meerkat.interactive.graph.store.Store[str], str] = None, selected: meerkat.interactive.graph.store.Store[List[int]] = None, primary_key: str = None, precision_estimate: List[meerkat.interactive.graph.store.Store[float]] = None, recall_estimate: List[meerkat.interactive.graph.store.Store[float]] = None)
class Choice(id: str = None, *args, choices: meerkat.interactive.graph.store.Store[list], value: meerkat.interactive.graph.store.Store[str], gui_type: str = 'dropdown', title: str = None, **kwargs)

A choice ref.

class Textbox(id: str = None, *args, text: meerkat.interactive.graph.store.Store[str] = None, title: str = '', **kwargs)
class Button(id: str = None, *args, title: meerkat.interactive.graph.store.Store[str], on_click: meerkat.interactive.endpoint.Endpoint = None, **kwargs)
class ColumnLayout(id: str = None, *args, components: Sequence[meerkat.interactive.app.src.lib.component.abstract.Component], classes: str = 'flex-row', **kwargs)
class RowLayout(id: str = None, *args, components: Sequence[meerkat.interactive.app.src.lib.component.abstract.Component], classes: str = 'grid-cols-1', **kwargs)
class Div(id: str = None, *args, component: meerkat.interactive.app.src.lib.component.abstract.Component, classes: str = '', **kwargs)
class Flex(id: str = None, *args, components: Sequence[meerkat.interactive.app.src.lib.component.abstract.Component], classes: str = 'flex-col', **kwargs)
class Grid(id: str = None, *args, components: Sequence[meerkat.interactive.app.src.lib.component.abstract.Component], classes: str = 'grid-cols-2', **kwargs)
class MultiSelect(id: str = None, *args, choices: meerkat.interactive.graph.store.Store[list], selected: meerkat.interactive.graph.store.Store[list] = None, gui_type: str = 'multiselect', title: str = None, **kwargs)
class Image(id: str = None, *args, data: str, height: str = '100%', width: str = '100%', layout: str = 'object-cover', **kwargs)
class Text(id: str = None, *args, data: Any = None, dtype: str = None, precision: int = 3, percentage: bool = False, **kwargs)
class Code(id: str = None, *args, data: str, language: str = 'python', theme: str = 'okaidia', **kwargs)
class CodeDisplay(id: str = None, *args, data: meerkat.interactive.graph.store.Store[str], language: str = 'python', **kwargs)