En esta página

Gráfico de dispersión simple

Utilizando Scatter3D en una aplicación QML.

Simple Scatter Graph muestra cómo realizar una visualización sencilla de un gráfico de dispersión utilizando Scatter3D y QML.

Para obtener instrucciones sobre cómo interactuar con el gráfico, consulte esta página.

Para obtener instrucciones sobre cómo crear una nueva aplicación Qt Quick propia, consulte la ayuda de Qt Creator.

Ejecutar el ejemplo

Para ejecutar el ejemplo desde Qt Creator, abra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.

Configuración del diseño

Antes de sumergirse en el código QML, main.cpp configura la aplicación. El archivo main.qml se lee del recurso (qrc:)

viewer.setSource(QUrl("qrc:/qml/scatter/main.qml"));

Este archivo main.qml es el punto de partida para el código QML de la aplicación. En primer lugar, importa todos los módulos QML necesarios:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtGraphs

A continuación, cree un elemento Data que será el elemento que contenga los datos para el gráfico.

Data {
    id: seriesData
}

A continuación, crea dos elementos GraphsTheme que definan dos temas diferentes para el gráfico, un tema Qt Green y un tema Qt Neon Green.

GraphsTheme {
    id: themeQt
    theme: GraphsTheme.Theme.QtGreen
    labelFont.pointSize: 40
}

GraphsTheme {
    id: themeQtNeonGreen
    theme: GraphsTheme.Theme.QtGreenNeon
    colorScheme: GraphsTheme.ColorScheme.Dark
}

El diseño de esta aplicación va a consistir en cinco botones diferentes para activar y desactivar diferentes opciones visuales para el gráfico, y por supuesto el propio gráfico. Hay muchas formas de organizarlos, una forma es tener un GridLayout que contenga cuatro botones, el Graph, y el quinto botón, todos apareciendo en un ColumnLayout.

ColumnLayout {
    id: mainLayout
    anchors.fill: parent
    anchors.margins: margin
    spacing: spacing

El GridLayout es responsivo. Esto significa que el número de columnas utilizadas depende de la anchura de la ventana de la aplicación. Esto se hace asignando a la propiedad columns un operador ternario, que se resuelve en 1, 2 ó 4, dependiendo de la anchura de la ventana.

GridLayout {
    Layout.fillWidth: true
    rowSpacing: spacing
    columnSpacing: spacing

    columns: mainView.width < mainView.buttonMinWidth * 2 + mainView.spacing + mainView.margin * 2 // width of 2 buttons
             ? 1
             : (mainView.width < mainView.buttonMinWidth * 4 + mainView.spacing * 3 + mainView.margin * 2 // width of 4 buttons
                ? 2
                : 4)

En este GridLayout, se instancian cuatro RoundButtons. Uno para activar las sombras, otro para suavizar la malla, otro para la posición de la cámara y, por último, otro para cambiar el fondo del gráfico. Todos los botones siguen la misma estructura. En lugar de redefinir esta estructura para todos los botones, se puede hacer un componente personalizado.

component CustomButton : RoundButton {
    id: buttonRoot

CustomButtom extiende el tipo RoundButton, pero añade algunos complementos. Se establecen propiedades como Layout.minimumWidth, Layout.FillWidth, radius y background. Éstas definen el estilo y el diseño del botón.

property alias source: iconImage.source

Layout.minimumWidth: buttonMinWidth
Layout.fillWidth: true

radius: mainView.radius

background: Rectangle {
    radius: mainView.radius
    color: "white"
    border.color: "black"
}

Mientras que contentItem define el contenido del botón, en este caso un tipo Row que contiene un icono y algo de texto. El icono se importa utilizando un tipo Image y estableciendo la propiedad source. El texto se crea utilizando un tipo Label y se establece utilizando su propiedad text. Se crean dos alianzas para estas dos propiedades en la parte superior del componente personalizado, lo que permitirá establecerlas cuando se cree una instancia de CustomButton.

contentItem: Row {
    id: content
    Image {
        id: iconImage
    }
    Label {
        text: buttonRoot.text
        horizontalAlignment: Text.AlignLeft
        anchors.verticalCenter: parent.verticalCenter
    }
}

En GridLayout se crean cuatro CustomButton. Es necesario establecer tres propiedades, las dos aliadas para la imagen del icono y el texto, y la señal onClicked.

CustomButton {
    id: shadowButton
    text: graph.shadowQuality === Graphs3D.ShadowQuality.None ?
              qsTr("Show Shadows") : qsTr("Hide Shadows")
    source: graph.shadowQuality === Graphs3D.ShadowQuality.None ?
                "qrc:/images/shadow.svg" : "qrc:/images/shadow_hide.svg"
    onClicked: {
        graph.shadowQuality = graph.shadowQuality === Graphs3D.ShadowQuality.None ?
                    Graphs3D.ShadowQuality.High :
                    Graphs3D.ShadowQuality.None
    }
}

Por ejemplo, el botón de sombra establece la señal onClicked para activar y desactivar la sombra.

Configuración del gráfico

Lo siguiente en el diseño es Graph, que se define en su propio archivo QML Graph.qml, y se instanciará como sigue:

Graph {
    id: graph
    Layout.fillWidth: true
    Layout.fillHeight: true
}

Mirando su implementación en Graph.qml, el gráfico es de tipo Scatter3D, anidado dentro de un tipo Item.

Scatter3D {
    id: scatterGraph

Antes de definir los conjuntos de datos, se configuran algunas de las propiedades de los ejes.

axisX.segmentCount: 3
axisX.subSegmentCount: 2
axisX.labelFormat: "%.2f"
axisZ.segmentCount: 2
axisZ.subSegmentCount: 2
axisZ.labelFormat: "%.2f"
axisY.segmentCount: 2
axisY.subSegmentCount: 2
axisY.labelFormat: "%.2f"

Configuración de los datos

El gráfico muestra tres conjuntos de datos, que representan los datos dados en Data.qml. Los conjuntos de datos se almacenan en tipos ListModel

ListModel {
    id: dataModel
    ListElement{ xPos: -10.0; yPos: 5.0; zPos: -5.0 }
    ...
    ListElement{ xPos: -7.54 ; yPos: 2.8 ; zPos: -3.68 }
}

ListModel {
    id: dataModelTwo
    ListElement{ xPos: 2.25 ; yPos: 1.36 ; zPos: -1.3 }
    ...
    ListElement{ xPos: -3.4 ; yPos: 0.6 ; zPos: 0.9 }
}

ListModel {
    id: dataModelThree
    ListElement{ xPos: 8.0; yPos: -2.0; zPos: 4.0 }
    ...
    ListElement{ xPos: 5.66 ; yPos: -4.98 ; zPos: 3.72 }
}

y expuestos a los otros archivos usando property aliases

property alias model: dataModel
property alias modelTwo: dataModelTwo
property alias modelThree: dataModelThree

Antes de utilizar estos alias, cree un tipo Scatter3DSeries, que contenga un elemento ItemModelScatterDataProxy.

Scatter3DSeries {
    id: scatterSeries
    itemLabelFormat: "Series 1: X:@xLabel Y:@yLabel Z:@zLabel"

    ItemModelScatterDataProxy {
        itemModel: seriesData.model
        xPosRole: "xPos"
        yPosRole: "yPos"
        zPosRole: "zPos"
    }
}

Este proxy de datos hace referencia a los conjuntos de datos en Data.qml utilizando su propiedad itemModel. Se accede a los alias mencionados anteriormente a través de id del tipo Data instanciado en main.qml, seriesData.

itemModel: seriesData.model

Repita este procedimiento para los dos conjuntos de datos restantes.

Scatter3DSeries {
    id: scatterSeriesTwo
    ...
ItemModelScatterDataProxy {
    itemModel: seriesData.modelTwo
    ...
    }
}
Scatter3DSeries {
    id: scatterSeriesThree
    ...
ItemModelScatterDataProxy {
    itemModel: seriesData.modelThree
    ...
    }
}

Genial, el gráfico de dispersión apunta ahora a los tres conjuntos de datos.

Lo único que queda por hacer es añadir el botón restante, el theme button, a nuestro ColumnLayout. La única diferencia con este botón es que está situado en el lado izquierdo del diseño. Esto se consigue definiendo la propiedad Layout.alignment como Qt.AlignLeft y Layout.fillWidth como false.

CustomButton {
    id: themeButton
    Layout.alignment: Qt.AlignLeft
    Layout.fillWidth: false

Contenidos de ejemplo

Proyecto de ejemplo @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.