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

PyQt中Scattermapbox框选/套索选数据,解决selectedpoints未更新及获取选中数据

解决PyQt中Scattermapbox框选数据点后无法获取选中数据的问题

问题原因

你当前的代码里,fig对象是在Python端生成后转成静态HTML加载到QWebEngineView的,前端Plotly的框选/套索交互只会在浏览器端更新图表状态,不会自动同步回Python端的fig对象,因此selectedpoints始终是空数组。要获取选中数据,必须建立前端JS与Python代码的通信,把选中点的索引传递回Python。

修改后的完整代码

import sys
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QDialog
import plotly.graph_objects as go
import pandas as pd
from PyQt5.QtCore import QObject, pyqtSlot


class JavaScriptBridge(QObject):
    """JS与Python的通信桥接类"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent_widget = parent

    @pyqtSlot(list)
    def receive_selected_indices(self, indices):
        """接收JS传递的选中点索引"""
        self.parent_widget.handle_selected_indices(indices)


class DashboardScreen(QDialog):
    def __init__(self):
        super(DashboardScreen, self).__init__()       
        # 保存原始数据,方便后续筛选选中项
        self.data = {'Fid': ['A', 'B', 'C'],
                'Project': [1,2,3],
                'Date': [23, 24, 25],
                'Latitude': [10, 20, 30],
                'Longitude': [70, 75, 80]}
        self.df = pd.DataFrame(self.data)
        
        # 创建Scattermapbox图表
        fig = go.Figure(go.Scattermapbox(
            lat=self.df['Latitude'],
            lon=self.df['Longitude'],
            hovertext=self.df['Project'],
            mode='markers',    
            marker={'size': 10, 'color': 'blue'},
            selected=dict(marker={'color': 'red'}),
            selectedpoints=[],
            uid='scatter_trace'  # 给trace设置唯一标识,方便JS定位
        ))
        
        fig.update_layout(
            mapbox_style="white-bg"  
        )
            
        fig.update_layout(mapbox_layers=[
                {
                    "below": 'traces',
                    "sourcetype": "raster",
                    "sourceattribution": "United States Geological Survey",
                    "source":  [
                "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}"
                               ]
                }
              ],
            margin={"r":0,"t":0,"l":0,"b":0}
        )
        
        self.setLayout(QVBoxLayout())

        # 初始化WebView并加载带交互监听的图表
        self.webView = QWebEngineView()
        # 注册JS桥接对象,实现双向通信
        self.js_bridge = JavaScriptBridge(self)
        self.webView.page().setWebChannel(self.js_bridge)
        
        # 生成基础HTML并添加选中事件监听的JS代码
        base_html = fig.to_html(include_plotlyjs='cdn')
        selected_event_js = """
        <script>
        // 获取页面中的Plotly图表对象
        const chart = document.querySelector('.plotly-graph-div');
        // 监听Plotly的选中事件
        chart.addEventListener('plotly_selected', (event) => {
            const selectedIndices = [];
            if (event.points) {
                // 提取每个选中点的索引
                event.points.forEach(point => selectedIndices.push(point.pointIndex));
            }
            // 将索引传递给Python端
            window.receive_selected_indices(selectedIndices);
        });
        </script>
        """
        # 合并HTML与JS代码
        full_html = base_html.replace('</body>', selected_event_js + '</body>')
        self.webView.setHtml(full_html)
        self.layout().addWidget(self.webView)

        # 添加查看选中数据的按钮
        self.button = QPushButton("查看选中数据")
        self.button.clicked.connect(self.show_selected_data)
        self.layout().addWidget(self.button)
        
        # 存储当前选中的点索引
        self.current_selected_indices = []

    def handle_selected_indices(self, indices):
        """更新Python端的选中索引"""
        self.current_selected_indices = indices

    def show_selected_data(self):
        """展示选中的数据(支持转为DataFrame、列表、数组)"""
        if not self.current_selected_indices:
            print("未选中任何数据点")
            return
        
        # 转为DataFrame
        selected_df = self.df.iloc[self.current_selected_indices]
        print("选中数据(DataFrame):")
        print(selected_df)
        
        # 转为列表
        selected_lat_list = selected_df['Latitude'].tolist()
        selected_lon_list = selected_df['Longitude'].tolist()
        print("\n选中纬度列表:", selected_lat_list)
        print("选中经度列表:", selected_lon_list)
        
        # 转为numpy数组
        selected_lat_array = selected_df['Latitude'].to_numpy()
        selected_lon_array = selected_df['Longitude'].to_numpy()
        print("\n选中纬度数组:", selected_lat_array)
        print("选中经度数组:", selected_lon_array)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    welcome = DashboardScreen()
    welcome.show()
    try:
        sys.exit(app.exec_())
    except Exception:
        print("Exiting!!")

关键修改说明

  • JS-Python通信桥接:通过JavaScriptBridge类和pyqtSlot装饰器,实现前端JS与Python代码的数据传递通道。
  • Plotly事件监听:在HTML中插入JS代码,监听plotly_selected事件,提取选中点的索引并传递给Python。
  • 原始数据缓存:将原始DataFrame保存为类属性,避免从静态fig对象中提取数据,确保数据获取的准确性和效率。
  • 实时索引更新:维护current_selected_indices变量实时同步前端选中状态,点击按钮即可快速筛选出对应数据。

内容的提问来源于stack exchange,提问作者PARVATHY RAMAKRISHNAN P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 17:34:53