Interactive
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)).
- 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
- 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)¶