Skip to content

Commit

Permalink
Change plotly figure widget to allow image annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
itepifanio authored and maartenbreddels committed Sep 29, 2023
1 parent 115d423 commit 7aed04d
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 24 deletions.
50 changes: 26 additions & 24 deletions solara/components/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,39 +272,41 @@ def FigurePlotly(
on_click: Callable[[Any], None] = None,
on_hover: Callable[[Any], None] = None,
on_unhover: Callable[[Any], None] = None,
on_relayout: Callable[[Any], None] = None,
dependencies=None,
):
from plotly.graph_objs._figurewidget import FigureWidget

def on_points_callback(data):
if data:
event_type = data["event_type"]
if event_type == "plotly_click":
if on_click:
on_click(data)
elif event_type == "plotly_hover":
if on_hover:
on_hover(data)
elif event_type == "plotly_unhover":
if on_unhover:
on_unhover(data)
elif event_type == "plotly_selected":
if on_selection:
on_selection(data)
elif event_type == "plotly_deselect":
if on_deselect:
on_deselect(data)

fig_element = FigureWidget.element(on__js2py_pointsCallback=on_points_callback)
if not data:
return

event_type = data["event_type"]
event_mapping = {
"plotly_click": on_click,
"plotly_hover": on_hover,
"plotly_unhover": on_unhover,
"plotly_selected": on_selection,
"plotly_deselect": on_deselect
}

callback = event_mapping.get(event_type)
if callback:
callback(data)

fig_element = FigureWidget.element(
on__js2py_pointsCallback=on_points_callback,
on__js2py_relayout=on_relayout
)

def update_data():
fig_widget: FigureWidget = solara.get_widget(fig_element)
fig_widget = solara.get_widget(fig_element)
fig_widget.layout = fig.layout

length = len(fig_widget.data)
fig_widget.add_traces(fig.data)
data = list(fig_widget.data)
fig_widget.data = data[length:]
if hasattr(fig_widget, 'data'):
length = len(fig_widget.data)
data = list(fig_widget.data)
fig_widget.data = data[length:]

solara.use_effect(update_data, dependencies or fig)
return fig_element
Expand Down
57 changes: 57 additions & 0 deletions solara/website/pages/examples/visualization/annotator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""# Image annotation with Solara
This example displays how to annotate images with different drawing tools in plotly figures. Use the canvas
below to draw shapes and visualize the canvas callback.
Check [plotly docs](https://dash.plotly.com/annotations) for more information about image annotation.
"""
import json
import plotly.graph_objects as go

import solara

title = "Plotly Image Annotator"
text = solara.reactive('Draw on canvas')

class CustomEncoder(json.JSONEncoder):
def default(self, o):
# Convert object instances to their string representation
if isinstance(o, object):
return str(o)
return super().default(o)

@solara.component
def Page():
def on_relayout(data):
if data is None:
return

relayout_data = data['relayout_data']

if "shapes" in relayout_data:
text.value = str(json.dumps(relayout_data["shapes"], indent=2, cls=CustomEncoder))

with solara.Div() as main:

fig = go.FigureWidget(
layout=go.Layout(
showlegend=False,
autosize=False,
width=600,
height=600,
modebar={
"add": [
"drawclosedpath",
"drawcircle",
"drawrect",
"eraseshape",
]
}
)
)

solara.FigurePlotly(fig, on_relayout=on_relayout)
solara.Preformatted(text.value)

return main

0 comments on commit 7aed04d

Please sign in to comment.