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

Python与QML中Scatter3DSeries无显示问题(基于AbstractTableModel)

问题排查与解决方案

核心错误点

  • 重复定义data方法:MyTableModel中两次实现了data方法,后定义的覆盖前一个,导致角色映射逻辑混乱。
  • Role映射逻辑错误:ItemModelScatterDataProxy通过角色名而非列索引获取数据,但原data方法未针对x/y/z对应的UserRole做单独处理,仍按列返回数据,无法匹配Proxy的角色请求。
  • 类初始化错误:ListTab的初始化方法写成了init(),正确Python类构造方法应为__init__,且存在缩进错误,导致模型和QuickView的初始化逻辑无法正确执行。
  • QQuickView未完成加载与显示:仅创建QQuickView并设置上下文属性,但未加载QML文件、设置窗口尺寸或显示窗口。
  • QML组件尺寸未设置:Scatter3D未指定宽度和高度,可能导致控件不可见。

修正后的Python代码

from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtQuickWidgets import QQuickWidget
import sys

class MyTableModel(QAbstractTableModel):
    XRole = Qt.UserRole + 1
    YRole = Qt.UserRole + 2
    ZRole = Qt.UserRole + 3

    def __init__(self, x, y, z, parent=None):
        super().__init__(parent)
        self._data = list(zip(x, y, z))

    def rowCount(self, parent=QModelIndex()):
        return len(self._data) if not parent.isValid() else 0

    def columnCount(self, parent=QModelIndex()):
        return 3 if not parent.isValid() else 0

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid() or index.row() >= len(self._data):
            return None
        
        x_val, y_val, z_val = self._data[index.row()]
        
        if role == Qt.DisplayRole:
            if index.column() == 0:
                return x_val
            elif index.column() == 1:
                return y_val
            elif index.column() == 2:
                return z_val
        elif role == self.XRole:
            return x_val
        elif role == self.YRole:
            return y_val
        elif role == self.ZRole:
            return z_val
        
        return None

    def roleNames(self):
        roles = super().roleNames()
        roles[self.XRole] = b'x'
        roles[self.YRole] = b'y'
        roles[self.ZRole] = b'z'
        return roles

class ListTab(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        listx = [1,2,3]
        listy = [4,5,6]
        listz = [7,8,9]
        
        model = MyTableModel(listx, listy, listz)
        
        self.quickwidget = QQuickWidget()
        self.quickwidget.rootContext().setContextProperty("myModel", model)
        # 替换为你的QML文件实际路径
        self.quickwidget.setSource("scatter.qml")
        self.quickwidget.setMinimumSize(800, 600)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    tab = ListTab()
    tab.quickwidget.show()
    sys.exit(app.exec_())

修正后的QML代码

import QtQuick 2.15
import QtDataVisualization 1.15

Scatter3D {
    id: scatter3Dplot
    width: 800
    height: 600

    axisX: ValueAxis3D { labelFormat: "%.1f" }
    axisY: ValueAxis3D { labelFormat: "%.1f" }
    axisZ: ValueAxis3D { labelFormat: "%.1f" }

    Scatter3DSeries {
        id: scatterSeriesPlot
        ItemModelScatterDataProxy {
            itemModel: myModel
            xPosRole: "x"
            yPosRole: "y"
            zPosRole: "z"
        }
        mesh: Scatter3DSeries.Sphere
        meshSize: 0.3
    }
}

额外说明

  • 确保已安装QtDataVisualization模块,可通过pip install PyQt5[datavisualization]安装。
  • QML文件路径需指向实际文件,也可将QML内容以字符串形式加载(适合简单场景)。
  • 添加坐标轴是为了直观观察散点位置,若不需要可移除,建议保留用于调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:37:03