You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何访问并编辑Plotly回调创建的图形(Python)

问题描述

点击图片上的瑕疵位置时会添加圆形标记(效果如下):
点击添加圆形标记示例

我通过Plotly回调实现了这个功能,但所有添加的图形trace_name和trace_index都是0,只有坐标不同。现在我可以用鼠标选择并编辑任意图形,但无法删除它们,也没法获取这些图形的信息。Plotly肯定存储了这些数据,请问怎么访问这些图形及其属性,实现编辑或删除操作?


实现代码
# 使用的库:

# 用于绘图和捕获用户交互的包
import plotly.graph_objects as go

# 创建交互控件的包
import ipywidgets as widgets

# 处理数组的库
import numpy as np

# OpenCV库
import cv2


# 通过ipywidgets和opencv加载图片
# 存储上传文件的对象
uploader = widgets.FileUpload(accept = '',  # 允许的文件扩展名,例如 '.txt', '.pdf', 'image/*'
                              multiple = False  # 是否允许多文件上传
                             )

# 显示上传按钮
# 本代码原本在笔记本环境运行,所以后续代码会暂停
# 如果直接"全部运行"或在Jupyter环境外执行会报错
display(uploader)


# 获取文件内容并存储
uploaded_file = list(uploader.value.values())[0]

# 用OpenCV加载图片
image = cv2.imdecode(np.asarray(bytearray(uploaded_file['content'])), cv2.IMREAD_UNCHANGED)

# 如果图片加载失败,输出错误
if image is None:
    print('加载图片失败: {}'.format(uploaded_file['metadata']['name']))
else:
    print('成功加载图片: {}'.format(uploaded_file['metadata']['name']))


# 将BGR格式转为RGB
image = image[:, :, :: -1]


# 创建用于处理图片的FigureWidget对象
fig = go.FigureWidget()


# 向图中添加图片
fig.add_image(z = image);


# 更新布局
fig.update_layout(height = 800,
                  width = 1200,
                  title = f"图片文件名: {uploaded_file['metadata']['name']}",
                 );

# 获取图片对应的trace对象
image_fig = fig.data[0]

# 创建输出对象
out = widgets.Output()

# 回调函数
@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"鼠标点击坐标: x = {x}, y = {y}.\nTrace名称: {trace_name}. \nTrace索引: {trace_index}."
    
    print(points)
    print()
    print(selector)
    print()
    print(message)
    
    # 左键点击时
    if selector.button == 0:
        # 绘制圆形
        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",
                     )

# 注册点击回调
image_fig.on_click(get_mouse_clicks)

# 显示输出
widgets.VBox([fig, out])

解决方案

Plotly的FigureWidget中添加的形状(shape)都存储在fig.layout.shapes列表里,你可以通过这个列表直接访问、修改或删除所有标记的圆形:

1. 访问所有形状

直接遍历fig.layout.shapes就能获取每个形状的属性,比如坐标、颜色等:

# 遍历所有形状并打印属性
for idx, shape in enumerate(fig.layout.shapes):
    print(f"形状索引 {idx}:")
    print(f"  类型: {shape.type}")
    print(f"  坐标范围: x0={shape.x0}, y0={shape.y0}, x1={shape.x1}, y1={shape.y1}")
    print(f"  填充色: {shape.fillcolor}")

2. 删除指定形状

你可以通过索引删除单个形状,或者清空所有形状:

# 删除索引为0的形状
if fig.layout.shapes:
    fig.layout.shapes.pop(0)

# 清空所有形状
fig.layout.shapes = []

3. 添加右键删除功能

可以扩展原有的回调函数,添加右键点击删除选中形状的逻辑。Plotly的selector对象能获取当前选中的形状,结合右键点击事件实现删除:

# 修改后的回调函数
@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]
    
    # 左键添加圆形
    if selector.button == 0:
        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",
                     )
    # 右键删除选中的形状
    elif selector.button == 2:
        # 获取当前选中的形状索引
        selected_shape_idx = selector.selected_shape_idx
        if selected_shape_idx is not None and 0 <= selected_shape_idx < len(fig.layout.shapes):
            fig.layout.shapes.pop(selected_shape_idx)
            print(f"已删除索引为 {selected_shape_idx} 的形状")

4. 编辑形状属性

直接修改fig.layout.shapes中对应形状的属性即可,比如修改颜色或大小:

# 修改第一个形状的填充色为红色
if fig.layout.shapes:
    fig.layout.shapes[0].fillcolor = "red"
    # 修改圆形大小
    center_x = (fig.layout.shapes[0].x0 + fig.layout.shapes[0].x1)/2
    center_y = (fig.layout.shapes[0].y0 + fig.layout.shapes[0].y1)/2
    new_size = 15
    fig.layout.shapes[0].x0 = center_x - new_size/2
    fig.layout.shapes[0].x1 = center_x + new_size/2
    fig.layout.shapes[0].y0 = center_y - new_size/2
    fig.layout.shapes[0].y1 = center_y + new_size/2

内容的提问来源于stack exchange,提问作者iacisme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:05:26