Skip to content

Commit 2646491

Browse files
authored
Merge pull request #147 from mlexchange/overlayShapes
re drawing shapes after relayout event
2 parents db5b0fb + f2e3e57 commit 2646491

File tree

3 files changed

+28
-23
lines changed

3 files changed

+28
-23
lines changed

callbacks/control_bar.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -457,10 +457,11 @@ def open_delete_class_modal(
457457
Input({"type": "edit-class-store", "index": ALL}, "data"),
458458
State({"type": "annotation-class-store", "index": ALL}, "data"),
459459
State("image-selection-slider", "value"),
460+
State("image-viewer", "relayoutData"),
460461
prevent_initial_call=True,
461462
)
462463
def re_draw_annotations_after_editing_class_color(
463-
hide_show_click, all_annotation_class_store, image_idx
464+
edit_store, all_annotation_class_store, image_idx, relayout
464465
):
465466
"""
466467
After editing a class color, the color is changed in the class-store, but the color change is not reflected
@@ -486,17 +487,13 @@ def re_draw_annotations_after_editing_class_color(
486487
State({"type": "edit-annotation-class-text-input", "index": MATCH}, "value"),
487488
State({"type": "edit-annotation-class-colorpicker", "index": MATCH}, "value"),
488489
State({"type": "annotation-class-store", "index": MATCH}, "data"),
489-
State("image-selection-slider", "value"),
490490
prevent_initial_call=True,
491491
)
492-
def edit_annotation_class(
493-
edit_clicked, new_label, new_color, annotation_class_store, img_idx
494-
):
492+
def edit_annotation_class(edit_clicked, new_label, new_color, annotation_class_store):
495493
"""
496494
This callback edits the name and color of an annotation class by updating class-store metadata. We also trigger
497495
edit-class-store so we can then redraw the annotations in re_draw_annotations_after_editing_class_color().
498496
"""
499-
img_idx = str(img_idx - 1)
500497
# update store meta data
501498
annotation_class_store["label"] = new_label
502499
annotation_class_store["color"] = new_color
@@ -509,12 +506,12 @@ def edit_annotation_class(
509506
"border": f"2px solid {new_color}",
510507
}
511508
# update color in previous annotation data
512-
if img_idx in annotation_class_store["annotations"]:
513-
for a in annotation_class_store["annotations"][img_idx]:
514-
a["line"]["color"] = new_color
515-
if "fillcolor" in a:
516-
a["fillcolor"] = new_color
517-
509+
for img_idx, annots in annotation_class_store["annotations"].items():
510+
for annots in annotation_class_store["annotations"][img_idx]:
511+
annots["line"]["color"] = new_color
512+
if "fillcolor" in annots:
513+
annots["fillcolor"] = new_color
514+
print(ctx.triggered_id)
518515
return new_label, class_color_identifier, annotation_class_store, 1, True
519516

520517

callbacks/image_viewer.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ def update_viewfinder(relayout_data, annotation_store):
324324
{"type": "annotation-class-store", "index": ALL}, "data", allow_duplicate=True
325325
),
326326
Output("annotation-store", "data", allow_duplicate=True),
327+
Output("image-viewer", "figure", allow_duplicate=True),
327328
Input("image-viewer", "relayoutData"),
328329
State("image-selection-slider", "value"),
329330
State("annotation-store", "data"),
@@ -347,24 +348,23 @@ def locally_store_annotations(
347348
annotation_store["view"]["xaxis_range_1"] = relayout_data["xaxis.range[1]"]
348349
annotation_store["view"]["yaxis_range_0"] = relayout_data["yaxis.range[0]"]
349350
annotation_store["view"]["yaxis_range_1"] = relayout_data["yaxis.range[1]"]
350-
return all_annotation_class_store, annotation_store
351-
# Case 2: a shape is modified, the relayoutData will have the format "shape[_].path", with the new path (not very useful)
352-
# we can instead take all the shapes from the fig layout directly and reset them in the store
351+
return all_annotation_class_store, annotation_store, dash.no_update
352+
# Case 2: A shape is modified, drawn or deleted. Save all the current shapes on the fig layout, which includes new
353+
# modified, and deleted shapes.
353354
if (
354355
any(["shapes" in key for key in relayout_data])
355356
and "shapes" in fig["layout"].keys()
356357
):
357358
shapes = fig["layout"]["shapes"]
358-
# Case 3: a new shape is drawn, we have access to all this data directly from the relayoutData under the 'shapes' key
359-
elif "shapes" in relayout_data:
360-
shapes = relayout_data["shapes"]
361-
# Clear all annotation from the stores at the current slice, except for the hidden shapes
359+
360+
# Clear all annotation from the stores at the current slice,
361+
# except for the hidden shapes (hidden shapes cannot be modified or deleted)
362362
for a_class in all_annotation_class_store:
363363
if not a_class["is_visible"]:
364364
continue
365365
if img_idx in a_class["annotations"]:
366366
del a_class["annotations"][img_idx]
367-
# Add back each annotation on the current slice in each respective store
367+
# Add back each annotation on the current slice in each respective store.
368368
for shape in shapes:
369369
for a_class in all_annotation_class_store:
370370
if a_class["color"] == shape["line"]["color"]:
@@ -373,8 +373,16 @@ def locally_store_annotations(
373373
else:
374374
a_class["annotations"][img_idx] = [shape]
375375
break
376-
377-
return all_annotation_class_store, annotation_store
376+
# redraw all annotations on the fig so the store is aligned with whats on the app
377+
# ie: drawing with a hidden class hides the shape immediately
378+
# ie: drawing with the first class pushes the shape to the back of the image imdediately
379+
fig = Patch()
380+
all_annotations = []
381+
for a in all_annotation_class_store:
382+
if a["is_visible"] and "annotations" in a and img_idx in a["annotations"]:
383+
all_annotations += a["annotations"][img_idx]
384+
fig["layout"]["shapes"] = all_annotations
385+
return all_annotation_class_store, annotation_store, fig
378386

379387

380388
@callback(

components/annotation_class.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def annotation_class_item(class_color, class_label, existing_ids, data=None):
6161
),
6262
dcc.Store(
6363
id={"type": "edit-class-store", "index": class_id},
64-
data={"is_visible": True},
64+
data=False,
6565
),
6666
html.Div(
6767
[

0 commit comments

Comments
 (0)