Hello. The jpeg below shows the circles that are added to an image when I click on a location in the image (say a blemish I want to remove):
Below is the code I used to do this. I need help knowing how to access these shapes so I can edit or delete them? I found a way of using plotly callbacks to create these shapes, but if you look at the image - all shapes have trace 0 and 0 as a trace_name and trace_index. The only thing that changes are the x and y cordinates.
I can select and edit any shape I want using the mouse, but I can’t delete the shape, nor can I access any information on these shapes.
I’m sure plotly must be storing this somewhere. Can someone please help me understand how to access these shapes, and shape properties so I can edit or delete them?
Thank you!
# LIbraries used to run this code:
# Package that will be used to make graphs and capture user interactions 
import plotly.graph_objects as go
# Package to create interactive controls
import ipywidgets as widgets
# Library used to handle array and array-like objects
import numpy as np
# OpenCV Library
import cv2
# Load an image using ipywidgets and opencv to create an image
# Object to store loaded files
uploader = widgets.FileUpload(accept = '',  # Accepted file extension e.g. '.txt', '.pdf', 'image/*', 'image/*,.pdf'
                              multiple = False  # True to accept multiple files upload else False
                             )
# Display the button to load an image
# This code is orginally run in a notebook, so there is a pause in the remaining code below
# This code will cause an error if attempting to "run-all" or outside a jupyter environment
display(uploader)
# Grab the file content and store it in a new object
uploaded_file = list(uploader.value.values())[0]
# Load image into OpenCV
image = cv2.imdecode(np.asarray(bytearray(uploaded_file['content'])), cv2.IMREAD_UNCHANGED)
# If image is not read properly, return error
if image is None:
    print('Failed to load image file: {}'.format(uploaded_file['metadata']['name']))
else:
    print('Succesfully loaded image file: {}'.format(uploaded_file['metadata']['name']))
# Convert from bgr to rgb
image = image[:, :, :: -1]
# Create a figurewidget object that will be used to 
# handle the image
fig = go.FigureWidget()
# Add the image to the figure object
fig.add_image(z = image);
# Update the layout 
fig.update_layout(height = 800,
                  width = 1200,
                  title = f"Image filename: {uploaded_file['metadata']['name']}",
                 );
# Image figure object
image_fig = fig.data[0]
# Create an output object
out = widgets.Output()
# Callback function
@out.capture(clear_output = True)
def get_mouse_clicks(trace, points, selector):
    
    size = 10
    
    ind = points.point_inds[0]
    
    x = ind[1]
    y = ind[0]
    
    trace_name = points.trace_name
    trace_index = points.trace_index
    
    message = f"The mouse points are:x = {x}, y = {y}.\nThe trace name is: {trace_name}. \nThe trace index is: {trace_index}."
    
    print(points)
    print()
    print(selector)
    print()
    print(message)
    
    # When the left button is clicked
    if selector.button == 0:
        # Draw a circle
        fig.add_shape(editable = True,
                      type = "circle",
                      x0 = x - size / 2, 
                      y0 = y - size / 2, 
                      x1 = x + size / 2, 
                      y1 = y + size / 2, 
                      xref = 'x', 
                      yref = 'y',
                      fillcolor = "grey",
                      line_color = "black",
                     )
# Register the callback
image_fig.on_click(get_mouse_clicks)
# Display output
widgets.VBox([fig, out])
I’m not interested in finding a solution using Dash. At this point I’m trying to put something conceptual together first, which is why I’m interested in using ipywidgets and plotly to do this.
Thank you!
–Igor
