metanno.ui
AnnotatedImage [source]
An interactive image viewer that supports drawing, selecting, and styling geometric shapes (polygons, rectangles, points...) as annotations.
Under the hood, we use Konva to render the image and its annotations.
Examples
from pret import component, create_store, use_store_snapshot, use_event_callback
from metanno import AnnotatedImage
import time
# Reactive store holding the annotation list
img_state = create_store([
{
"id": "1",
"type": "polygon",
"points": [10, 10, 50, 20],
"label": "OBJ",
"style": "primary",
}
])
# Style preset referenced from the annotation above
img_annotation_styles = {
"primary": {
"strokeColor": "red",
"strokeWidth": 2,
"fillColor": "rgba(255,0,0,0.5)",
"labelPosition": "center",
"align": "center",
"verticalAlign": "top",
},
"secondary": {
"strokeColor": "blue",
"strokeWidth": 2,
"fillColor": "#0000ff80",
"textColor": "white",
}
}
@component
def MyImage():
tracked_state = use_store_snapshot(img_state)
@use_event_callback
def on_mouse_select(modkeys, shapes):
# Toggle 'mouseSelected' flag
for shp in shapes:
img_state.append({
"id": str(time.time()),
"points": shp["points"],
"label": "OBJ",
"style": "primary",
})
@use_event_callback
def on_click(shape_idx, modkeys):
if shape_idx is None:
img_state.clear()
else:
old_style = img_state[shape_idx].get("style", "primary")
new_style = "secondary" if old_style == "primary" else "primary"
img_state[shape_idx]["style"] = new_style
return AnnotatedImage(
image="https://picsum.photos/400/300",
annotations=tracked_state,
annotation_styles=img_annotation_styles,
on_mouse_select=on_mouse_select,
on_click=on_click,
)
MyImage()
Parameters
| PARAMETER | DESCRIPTION |
|---|---|
annotations | List of annotation objects drawn on top of the image. Each annotation must contain the geometric
TYPE: |
annotation_styles | Named style presets referenced by the
TYPE: |
image | Source URL or base-64 data URI of the image to annotate. TYPE: |
mouse_selection | Temporary shapes being drawn by the user while the mouse button is held down. Supplied back to TYPE: |
style | Inline CSS-compatible style overrides for the root element of the component. TYPE: |
handle | Optional imperative handle that the parent may call (empty for now). TYPE: |
key | React key for stable reconciliation. TYPE: |
on_click | Invoked when the user clicks on an existing shape.
TYPE: |
on_key_press | Invoked when the component has focus and the user presses a key.
TYPE: |
on_mouse_enter_shape | Hover callbacks fired when the mouse pointer enters or leaves a shape. TYPE: |
on_mouse_select | Fired after the user completes a drag selection.
TYPE: |
Table [source]
A component for displaying a table with various features such as filtering, highlighting rows, and handling cell changes.
Examples
from pret import component, create_store, use_store_snapshot, use_event_callback
from metanno import Table
table_state = create_store([
{"id": "1", "date": "2023-01-01", "text": "Sample text 1", "type": "ENT", "labels": ["ready"]},
{"id": "2", "date": "2023-01-03", "text": "Sample text 2", "type": "OTHER", "labels": ["ready", "danger"]},
{"id": "3", "date": "2023-01-05", "text": "Sample text 3", "type": "ENT", "labels": ["blue"]},
{"id": "4", "date": "2023-01-07", "text": "Sample text 4", "type": "OTHER", "labels": ["bad"]},
{"id": "5", "date": "2023-01-09", "text": "Sample text 5", "type": "ENT", "labels": []},
{"id": "6", "date": "2023-01-11", "text": "Sample text 6", "type": "OTHER", "labels": ["custom"]},
{"id": "7", "date": "2023-01-13", "text": "Sample text 7", "type": "FOO", "labels": ["ready"]},
{"id": "8", "date": "2023-01-15", "text": "Sample text 8", "type": "FOO2", "labels": ["danger"]},
{"id": "9", "date": "2023-01-17", "text": "Sample text 9", "type": "FOO3", "labels": ["blue"]},
{"id": "10", "date": "2023-01-19", "text": "Sample text 10", "type": "ENT", "labels": ["bad"]},
{"id": "11", "date": "2023-01-21", "text": "Sample text 11", "type": "OTHER", "labels": ["custom"]},
{"id": "12", "date": "2023-01-23", "text": "Sample text 12", "type": "ENT", "labels": ["ready"]},
{"id": "13", "date": "2023-01-25", "text": "Sample text 13", "type": "OTHER", "labels": ["danger"]},
{"id": "14", "date": "2023-01-27", "text": "Sample text 14", "type": "FOO2", "labels": ["blue"]},
{"id": "15", "date": "2023-01-29", "text": "Sample text 15", "type": "FOO3", "labels": ["bad"]},
])
columns = [
{"key": "id", "kind": "text", "name": "id", "filterable": True},
{"key": "date", "kind": "text", "name": "end", "filterable": True},
{"key": "text", "kind": "text", "name": "text", "filterable": True, "editable": True},
{"key": "type", "kind": "text", "name": "label", "filterable": True, "editable": True, "choices": ["ENT", "OTHER", "STUFF", "FOO", "FOO2", "FOO3"]},
{"key": "labels", "kind": "multi-text", "name": "labels", "filterable": True, "editable": True, "choices": ["ready", "danger", "blue", "bad", "custom"]},
]
@component
def MyTable():
@use_event_callback
def on_cell_change(row_id, row_idx, col, new_value):
table_state[row_idx][col] = new_value
view_state = use_store_snapshot(table_state)
return Table(
primary_key="id",
rows=view_state,
columns=columns,
auto_filter=True,
on_cell_change=on_cell_change,
)
MyTable()
Parameters
| PARAMETER | DESCRIPTION |
|---|---|
rows | The data for each row in the table, where each row is a dictionary mapping column keys to their values. TYPE: |
columns | The columns to display in the table:
TYPE: |
primary_key | The key used to uniquely identify each row in the table. TYPE: |
filters | The current filters applied to the table, mapping column keys to filter values. TYPE: |
highlighted_rows | List of row indices that should be highlighted. TYPE: |
handle | Imperative handle for actions that can be performed on the table, such as scrolling:
TYPE: |
auto_filter | Whether to automatically apply filters as the user types. TYPE: |
input_value | The current input value to show in the input field when the user is editing a cell. If undefined, this is automatically handled by the component. TYPE: |
suggestions | List of suggestions to show when the user is typing in the input field. TYPE: |
position | The current position of the cursor in the table, including:
TYPE: |
style | Custom styles for the table component. TYPE: |
key | A unique key for the component instance, used for React's reconciliation. TYPE: |
on_input_change | Callback triggered when the input value changes in a cell:
TYPE: |
on_scroll_bottom | Callback triggered when the user scrolls to the bottom of the table:
TYPE: |
on_cell_change | Callback triggered when a cell's value changes:
TYPE: |
on_click_cell_content | Callback triggered when the content of a cell is clicked (like a hyperlink):
TYPE: |
on_filters_change | Callback triggered when filters are updated:
TYPE: |
on_mouse_enter_row | Callback triggered when the mouse enters a row:
TYPE: |
on_mouse_leave_row | Callback triggered when the mouse leaves a row:
TYPE: |
on_mouse_hover_row | Callback triggered when the mouse hovers over a row:
TYPE: |
on_position_change | Callback triggered when the cursor position changes:
TYPE: |
on_subset_change | Callback triggered when the subset of visible rows changes:
TYPE: |
AnnotatedText [source]
The AnnotatedText is a rich text viewer that supports span-level annotations, nested token highlights, and various user event callbacks.
Examples
from pret import (
component,
create_store,
use_store_snapshot,
use_event_callback,
use_state,
)
from metanno import AnnotatedText
from pret_joy import Button, Box
txt = (
"Metanno brings annotation components to Pret\n"
"to build tailored annotation tools."
)
# One span covering the word “Metanno”
spans = create_store(
[
{
"id": f"span-0-7",
"start": 0,
"end": 7,
"label": "OBJ",
"highlighted": False,
}
]
)
txt_annotation_styles = create_store(
{
"OBJ": {
"color": "red",
"shape": "underline",
}
}
)
@component
def MyText():
tracked_spans = use_store_snapshot(spans)
tracked_styles = use_store_snapshot(txt_annotation_styles)
@use_event_callback
def handle_select(ranges, modkeys):
for sp in ranges:
spans.extend(
[
{
"id": f"span-{sp['begin']}-{sp['end']}",
"start": sp["begin"],
"end": sp["end"],
"label": "OBJ",
}
]
)
def on_mouse_enter_span(span_id, modkeys):
for i, sp in enumerate(spans):
if sp["id"] == span_id:
spans[i]["highlighted"] = True
def on_mouse_leave_span(span_id, modkeys):
for i, sp in enumerate(spans):
if sp["id"] == span_id:
spans[i]["highlighted"] = False
def on_span_style_change():
old_style = txt_annotation_styles["OBJ"]["shape"]
new_style = "box" if old_style == "underline" else "underline"
txt_annotation_styles["OBJ"]["shape"] = new_style
return Box(
Button("Change style", on_click=on_span_style_change),
Button("Remove annotations", on_click=lambda: spans.clear()),
AnnotatedText(
text=txt,
spans=tracked_spans,
annotation_styles=tracked_styles,
on_mouse_select=handle_select,
on_mouse_enter_span=on_mouse_enter_span,
on_mouse_leave_span=on_mouse_leave_span,
style={"gridColumn": "1 / -1"},
begin_key="start", # Custom field names
),
sx={
"p": 1,
"display": "grid",
"gridTemplateColumns": "repeat(2, auto)",
"gap": 1,
},
)
MyText()
Parameters
| PARAMETER | DESCRIPTION |
|---|---|
text | Raw text content shown in the viewer. TYPE: |
spans | Span-level annotations over
and may optionally include:
TYPE: |
annotation_styles | Named style presets that control span background color, border, label placement, etc. Each style may define properties such as:
TYPE: |
mouse_selection | Current mouse drag selection expressed as character‐offset ranges. Passed to TYPE: |
style | CSS style overrides for the outer element. TYPE: |
handle | Imperative handle for actions that can be performed on the component:
TYPE: |
begin_key | Name of the field in TYPE: |
end_key | Name of the field in TYPE: |
primary_key | Name of the field in TYPE: |
label_key | Name of the field in TYPE: |
style_key | Name of the field in TYPE: |
highlighted_key | Name of the field in TYPE: |
on_click_span | Called when the user clicks on a span.
TYPE: |
on_key_press | Called when a key is pressed with focus inside the component.
TYPE: |
on_mouse_enter_span | Called when the mouse pointer enters a span.
TYPE: |
on_mouse_leave_span | Called when the mouse pointer leaves a span.
TYPE: |
on_mouse_hover_spans | Triggered every time the set of hovered spans changes.
TYPE: |
on_mouse_select | Triggered when the user finishes selecting text with the mouse.
TYPE: |
key | React reconciliation key (not the same as the previous TYPE: |