Skip to main content

Example of changing the annotator state

Example of changing the annotator state
Example of changing the annotator state

Check the following link to review the demo of changing the states.

states.py

This demo provides the following features:

  1. A basic DashPictureAnnotation allowing
    1. Creating, modify, or removing annotation boxes by dragging and dropping.
    2. Modify the annotation label by an input box.
  2. Every time the annotation data is changed, the changed results will be reflected by the text below the annotator window.
  3. Three controlling buttons:
    • Toggle disabled: Toggle the disabled property. When this property is enabled, the annotator is not usable.
    • Toggle image: Toggle the currently displayed image.
    • Reset data: Reset the annotation data to the initial state.

Define the layout

Compared to the minimal demo, there are three additional buttons.

(
dpa.DashPictureAnnotation(...),
html.Div(
html.Button(
children="Toggle disabled", id="btn-disabled", style=styles["mr1"]
),
html.Button(
children="Toggle image", id="btn-image", style=styles["mr1"]
),
html.Button(children="Reset data", id="btn-data"),
),
)

By clicking different buttons, the different callbacks will be triggered for changing the annotator states.

Define the callbacks

The first button toggles the state of the disabled property. It just read and flip the current disabled property.

@app.callback(
Output("annotator", "disabled"),
Input("btn-disabled", "n_clicks"),
State("annotator", "disabled"),
prevent_initial_call=True,
)
def toggle_disabled(n_clicks: Optional[int], is_disabled: Optional[bool]):
if n_clicks:
return not bool(is_disabled)
return dash.no_update

The second callback read and roll the current image. It read the current image address, get the name of the image from the address, and use the image name to query the next image address that should be displayed.

@app.callback(
Output("annotator", "image"),
Input("btn-image", "n_clicks"),
State("annotator", "image"),
prevent_initial_call=False,
)
def toggle_image(n_clicks: Optional[int], prev_image: Optional[str]) -> str:
if n_clicks:
if isinstance(prev_image, str):
try:
idx = image_list.index(os.path.split(prev_image)[-1])
except ValueError:
return "/assets/test_image.svg"
next_idx = (idx + 1) % len(image_list)
return "/assets/{0}".format(image_list[next_idx])
return "/assets/test_image.svg"

The third callback reset the current annotation data to the initial value.

@app.callback(
Output("annotator", "data"),
Input("btn-data", "n_clicks"),
prevent_initial_call=False,
)
def reset_data(n_clicks: Optional[int]):
if n_clicks:
return default_data
return dash.no_update