View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Videos

Abrir menú Cerrar menú
  • Colecciones
  • Temas
  • Todos los videos
  • Información

Más videos

  • Información
  • Resumen
  • Transcripción
  • Código
  • Lleva los gráficos Swift a la tercera dimensión

    Aprende cómo llevar tus gráficos Swift 2D a la tercera dimensión con Chart3D y visualiza tus conjuntos de datos desde perspectivas completamente nuevas. Grafica tus datos en 3D, visualiza superficies matemáticas y personaliza todo, desde la cámara hasta los materiales, para que tus gráficos 3D sean más intuitivos y agradables. Para aprovechar al máximo esta sesión, recomendamos familiarizarse con la creación de gráficos Swift 2D.

    Capítulos

    • 0:00 - Introducción
    • 1:54 - Trazado en 3D
    • 5:05 - Gráfico de superficie
    • 7:03 - Personalización

    Recursos

    • Swift Charts
    • Swift Charts updates
      • Video HD
      • Video SD

    Videos relacionados

    WWDC24

    • Swift Charts: Vectorized and function plots

    WWDC22

    • Design an effective chart
    • Design app experiences with charts
  • Buscar este video…

    Hola. Soy Mike, ingeniero del equipo de System Experience. Hoy veremos una nueva y emocionante funcionalidad de Swift Charts. Swift Charts es una estructura para crear gráficas accesibles y sorprendentes.

    Las gráficas se usan en las plataformas de Apple para verificar la temperatura en Clima, mostrar el uso de la batería en Configuración y graficar funciones con Notas Matemáticas.

    Con los elementos disponibles en Swift Charts, puedes crear gráficas 2D con componentes como marcas de eje, etiquetas y gráficas de líneas.

    Pero la gráfica se expande. Ahora en iOS, macOS y visionOS 26, Swift Charts admite gráficas 3D. Ofrece la posibilidad de explorar y comprender conjuntos de datos desde perspectivas completamente nuevas.

    En esta sesión, veremos cómo llevar un conjunto de gráficas 2D a la tercera dimensión mediante la representación en 3D, cómo usar las gráficas de superficie para graficar funciones matemáticas tridimensionales y formas de personalizar tus gráficas para que sean más intuitivas y agradables. Pero antes, tengo un anuncio importante:

    ¡amo los pingüinos!

    Uno de mis conjuntos de datos favoritos contiene mediciones de cientos de pingüinos del archipiélago Palmer en la Antártida.

    Entre estos datos se incluyen la longitud del pico y de las aletas, así como el peso. Y se agrupan por especie: pingüinos barbijo, papúa y Adelia.

    Extraeré información de los datos con Swift Charts para visualizar las diferencias entre estas especies con la representación gráfica en 3D.

    En esta gráfica 2D se muestra la relación entre las longitudes de las aletas y los pesos de los pingüinos. PointMark grafica la longitud de la aleta y el peso de cada pingüino, y foregroundStyle colorea los puntos por especie y crea la leyenda en la esquina.

    Es fantástico, y Swift Charts facilita la creación de la gráfica. La gráfica muestra que los pingüinos barbijo y Adelia tienen longitudes de aleta y pesos similares, y los papúa tienen aletas más largas y pesan más.

    El conjunto de datos incluye la longitud del pico, así que hice una gráfica que representa la longitud y el peso.

    Esta muestra que los pingüinos barbijo y papúa tienen longitudes de pico similares mientras que los Adelia tienen picos más cortos.

    Por último, aquí vemos las longitudes de los picos y las aletas, y al parecer los pingüinos con picos más largos tienden a tener aletas más largas.

    Estas gráficas 2D son excelentes y ofrecen una buena perspectiva de las relaciones entre dos propiedades a la vez.

    Sin embargo, ahora Swift Charts puede llevarlas al siguiente nivel y crear una sola gráfica con todos estos datos.

    Y se llama Chart3D. Chart3D toma conceptos de gráficas 2D, como las gráficas de dispersión, y los trae al formato 3D.

    Para crear una gráfica 3D, cambiaré Chart a Chart3D.

    PointMark funciona muy bien en Chart3D y toma un valor Z. Aquí uso Beak Length.

    También estableceré el eje Z en Beak Length. Eso es todo.

    Con unas pocas líneas de código y Chart3D, puedo ver las diferencias entre especies de pingüinos de una manera divertida e interactiva.

    Puedo usar gestos simples para rotar la gráfica en ángulos precisos y ver tres grupos de puntos de datos.

    También puedo ver la gráfica desde los lados para comparar dos propiedades a la vez, como si estuviera viendo la gráfica en 2D.

    Las gráficas 3D funcionan muy bien cuando la forma de los datos es más importante que los valores exactos. Esto sucede naturalmente cuando los datos en sí son tridimensionales, en especial si representan una posición física en el espacio 3D.

    La interactividad es clave para entender conjuntos de datos tridimensionales. Considera las gráficas 3D solo si la interacción mejora la experiencia en tu app. Cuando se trata de la mejor representación para tu conjunto de datos, la elección entre 2D y 3D no es blanco o negro.

    PointMarks, RuleMarks y RectangleMarks se actualizaron para gráficas 3D. Ahora, SurfacePlot es exclusivo de Chart3D. Analicemos en profundidad cómo funciona SurfacePlot.

    SurfacePlot es la extensión tridimensional de LinePlot. Grafica una superficie matemática que contiene hasta dos variables en tres dimensiones.

    La nueva API SurfacePlot es similar a la API LinePlot.

    Acepta un cierre que toma dos dobles y devuelve un doble.

    Después de ingresar una expresión matemática en el cierre, SurfacePlot evalúa la expresión de diferentes valores de X y Z, y crea una superficie continua de los valores Y calculados. Estas superficies pueden ser tan complejas o simples como desees.

    Para más información sobre las gráficas de funciones de la API LinePlot, consulta Swift Charts: Vectorized and function plots de la WWDC24.

    ¿Sabes qué? Al mirar el conjunto de datos de los pingüinos, veo que hay una relación lineal entre la longitud del pico y la longitud de la aleta de un pingüino y su peso. Parece razonable, pero en lugar de adivinar, puedo usar SurfacePlot para mostrar una regresión lineal de los datos.

    Definí una clase LinearRegression que estima un valor y basado en las variables independientes x y z. Específicamente, configuré la regresión lineal para estimar el peso de un pingüino en función de la longitud de la aleta y el pico.

    Esta regresión lineal se usa luego en SurfacePlot para graficar los pesos estimados como una superficie continua.

    ¡Excelente! Parece que sí hay una relación lineal en estos datos. SurfacePlot muestra una correlación positiva entre la longitud de la aleta y el peso, y también hay una ligera correlación positiva entre la longitud del pico y el peso.

    Ahora, veamos algunas formas de personalizar el estilo y el comportamiento de Chart3D.

    Mientras interactuaba con el conjunto de datos de los pingüinos, noté que cambiar el ángulo de la gráfica cambia la apariencia de los datos.

    Este ángulo es ideal para mostrar los grupos de datos. Y este otro funciona bien para mostrar una relación lineal.

    A estos ángulos se los denomina poses.

    Es importante elegir una pose inicial que proporcione una buena representación de los datos.

    Para los datos dinámicos cuyos valores no conoces de antemano, intenta elegir una pose inicial que funcione para estos conjuntos de datos.

    La pose de la gráfica se ajusta con el modificador Chart3DPose y toma un Chart3DPose.

    Puedo establecer una pose específica, como .front, o definir una personalizada. Este inicializador toma dos parámetros: azimuth, que gira la gráfica a la izquierda y la derecha, e inclination, que la inclina arriba y abajo.

    Mira cómo los puntos de la parte posterior de la gráfica tienen el mismo tamaño que los de la parte delantera.

    Esto facilita la comparación de tamaños y distancias, independientemente de la profundidad.

    También es ideal para ver gráficas desde un lateral, ya que convierte con eficacia gráficas 3D en 2D.

    Esto se conoce como proyección de cámara ortográfica.

    Chart3D ofrece dos proyecciones: la ortográfica, el comportamiento predeterminado, y en perspectiva. Con la proyección en perspectiva, los puntos más alejados son más pequeños y las líneas paralelas convergen. Esto permite una experiencia inmersiva y ayuda con la percepción de profundidad.

    La proyección de cámara se establece con el modificador chart3DCameraProjection.

    SurfacePlot tiene opciones de personalización para los estilos de superficie.

    ForegroundStyle acepta degradados como LinearGradient o EllipticalGradient y admite dos nuevos valores: heightBased, que colorea los puntos de la superficie según la altura de la superficie en ese punto, y normalBased, que colorea los puntos según el ángulo de la superficie en ese punto.

    Hay muchos otros modificadores para Chart3D, algunos te pueden resultar familiares de gráficas 2D. Úsalos para personalizar estilos de superficie, símbolos PointMark, el dominio de la gráfica y las marcas de eje, o el comportamiento de selección.

    Al combinar estos modificadores de vista junto con PointMark, RuleMark, RectangleMark y SurfacePlot, puedes lograr todo tipo de gráficas interesantes. Esto es solo la punta del iceberg.

    Las gráficas 3D se ven muy bien en el Vision Pro, que es un entorno ideal para los datos tridimensionales.

    Estas son algunas de las nuevas funcionalidades 3D de Swift Charts.

    Si la representación 3D es adecuada para tus datos, prueba graficar con Chart3D para dar un nuevo nivel de profundidad a tus gráficas y usa las API de personalización de Swift Charts para diseñar gráficas accesibles y sorprendentes.

    Para conocer las mejores prácticas de Swift Charts para tus apps, consulta Design app experiences with charts de la WWDC22.

    Gracias. Ya quiero ver los tipos de gráficas que llevarás a la tercera dimensión.

    • 2:03 - A scatterplot of a penguin's flipper length and weight

      // A scatterplot of a penguin's flipper length and weight
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        var body: some View {
          Chart(penguins) { penguin in
            PointMark(
              x: .value("Flipper Length", penguin.flipperLength),
              y: .value("Weight", penguin.weight)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartXScale(domain: 160...240)
          .chartYScale(domain: 2...7)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 2:39 - A scatterplot of a penguin's beak length and weight

      // A scatterplot of a penguin's beak length and weight
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        var body: some View {
          Chart(penguins) { penguin in
            PointMark(
              x: .value("Beak Length", penguin.beakLength),
              y: .value("Weight", penguin.weight)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chartXAxisLabel("Beak Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartXScale(domain: 30...60)
          .chartYScale(domain: 2...7)
          .chartXAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 2:51 - A scatterplot of a penguin's beak length and flipper length

      // A scatterplot of a penguin's beak length and flipper length
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        var body: some View {
          Chart(penguins) { penguin in
            PointMark(
              x: .value("Beak Length", penguin.beakLength),
              y: .value("Flipper Length", penguin.flipperLength)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chartXAxisLabel("Beak Length (mm)")
          .chartYAxisLabel("Flipper Length (mm)")
          .chartXScale(domain: 30...60)
          .chartYScale(domain: 160...240)
          .chartXAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 3:28 - A scatterplot of a penguin's flipper length, beak length, and weight

      // A scatterplot of a penguin's flipper length, beak length, and weight
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        var body: some View {
          Chart3D(penguins) { penguin in
            PointMark(
              x: .value("Flipper Length", penguin.flipperLength),
              y: .value("Weight", penguin.weight),
              z: .value("Beak Length", penguin.beakLength)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartZAxisLabel("Beak Length (mm)")
          .chartXScale(domain: 160...240, range: -0.5...0.5)
          .chartYScale(domain: 2...7, range: -0.5...0.5)
          .chartZScale(domain: 30...60, range: -0.5...0.5)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartZAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 5:19 - A surface plot showing mathematical functions (x * z)

      // A surface plot showing mathematical functions
      
      import SwiftUI
      import Charts
      
      var SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              // (Double, Double) -> Double
              x * z
            }
          }
        }
      }
    • 5:43 - A surface plot showing mathematical functions

      // A surface plot showing mathematical functions
      
      import SwiftUI
      import Charts
      
      var SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              // (Double, Double) -> Double
              (sin(5 * x) + sin(5 * z)) / 2
            }
          }
        }
      }
    • 5:46 - A surface plot showing mathematical functions (-z)

      // A surface plot showing mathematical functions
      
      import SwiftUI
      import Charts
      
      var SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              // (Double, Double) -> Double
              -z
            }
          }
        }
      }
    • 6:19 - Present a linear regression of the penguin data

      // Present a linear regression of the penguin data
      
      import SwiftUI
      import Charts
      import CreateML
      import TabularData
      
      final class LinearRegression: Sendable {
        let regressor: MLLinearRegressor
      
        init(
          _ data: Data,
          x xPath: KeyPath,
          y yPath: KeyPath,
          z zPath: KeyPath
        ) {
          let x = Column(name: "X", contents: data.map { $0[keyPath: xPath] })
          let y = Column(name: "Y", contents: data.map { $0[keyPath: yPath] })
          let z = Column(name: "Z", contents: data.map { $0[keyPath: zPath] })
          let data = DataFrame(columns: [x, y, z].map { $0.eraseToAnyColumn() })
          regressor = try! MLLinearRegressor(trainingData: data, targetColumn: "Y")
        }
      
        func callAsFunction(_ x: Double, _ z: Double) -> Double {
          let x = Column(name: "X", contents: [x])
          let z = Column(name: "Z", contents: [z])
          let data = DataFrame(columns: [x, z].map { $0.eraseToAnyColumn() })
          return (try? regressor.predictions(from: data))?.first as? Double ?? .nan
        }
      }
      
      let linearRegression = LinearRegression(
        penguins,
        x: \.flipperLength,
        y: \.weight,
        z: \.beakLength
      )
      
      struct PenguinChart: some View {
        var body: some View {
          Chart3D {
            ForEach(penguins) { penguin in
              PointMark(
                x: .value("Flipper Length", penguin.flipperLength),
                y: .value("Weight", penguin.weight),
                z: .value("Beak Length", penguin.beakLength),
              )
              .foregroundStyle(by: .value("Species", penguin.species))
            }
      
            SurfacePlot(x: "Flipper Length", y: "Weight", z: "Beak Length") { flipperLength, beakLength in
              linearRegression(flipperLength, beakLength)
            }
            .foregroundStyle(.gray)
          }
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartZAxisLabel("Beak Length (mm)")
          .chartXScale(domain: 160...240, range: -0.5...0.5)
          .chartYScale(domain: 2...7, range: -0.5...0.5)
          .chartZScale(domain: 30...60, range: -0.5...0.5)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartZAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 7:50 - Adjust the initial chart pose (Default)

      // Adjust the initial chart pose
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        @State var pose: Chart3DPose = .default
      
        var body: some View {
          Chart3D(penguins) { penguin in
            PointMark(
              x: .value("Flipper Length", penguin.flipperLength),
              y: .value("Weight", penguin.weight),
              z: .value("Beak Length", penguin.beakLength)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chart3DPose($pose)
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartZAxisLabel("Beak Length (mm)")
          .chartXScale(domain: 160...240, range: -0.5...0.5)
          .chartYScale(domain: 2...7, range: -0.5...0.5)
          .chartZScale(domain: 30...60, range: -0.5...0.5)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartZAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 8:02 - Adjust the initial chart pose (Front)

      // Adjust the initial chart pose
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        @State var pose: Chart3DPose = .front
      
        var body: some View {
          Chart3D(penguins) { penguin in
            PointMark(
              x: .value("Flipper Length", penguin.flipperLength),
              y: .value("Weight", penguin.weight),
              z: .value("Beak Length", penguin.beakLength)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chart3DPose($pose)
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartZAxisLabel("Beak Length (mm)")
          .chartXScale(domain: 160...240, range: -0.5...0.5)
          .chartYScale(domain: 2...7, range: -0.5...0.5)
          .chartZScale(domain: 30...60, range: -0.5...0.5)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartZAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 8:09 - Adjust the initial chart pose (Custom)

      // Adjust the initial chart pose
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        @State var pose = Chart3DPose(
          azimuth: .degrees(20),
          inclination: .degrees(7)
        )
      
        var body: some View {
          Chart3D(penguins) { penguin in
            PointMark(
              x: .value("Flipper Length", penguin.flipperLength),
              y: .value("Weight", penguin.weight),
              z: .value("Beak Length", penguin.beakLength)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chart3DPose($pose)
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartZAxisLabel("Beak Length (mm)")
          .chartXScale(domain: 160...240, range: -0.5...0.5)
          .chartYScale(domain: 2...7, range: -0.5...0.5)
          .chartZScale(domain: 30...60, range: -0.5...0.5)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartZAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 9:15 - Adjust the initial chart pose and camera projection

      // Adjust the initial chart pose and camera projection
      
      import SwiftUI
      import Charts
      
      struct PenguinChart: View {
        @State var pose = Chart3DPose(
          azimuth: .degrees(20),
          inclination: .degrees(7)
        )
      
        var body: some View {
          Chart3D(penguins) { penguin in
            PointMark(
              x: .value("Flipper Length", penguin.flipperLength),
              y: .value("Weight", penguin.weight),
              z: .value("Beak Length", penguin.beakLength)
            )
            .foregroundStyle(by: .value("Species", penguin.species))
          }
          .chart3DPose($pose)
          .chart3DCameraProjection(.perspective)
          .chartXAxisLabel("Flipper Length (mm)")
          .chartYAxisLabel("Weight (kg)")
          .chartZAxisLabel("Beak Length (mm)")
          .chartXScale(domain: 160...240, range: -0.5...0.5)
          .chartYScale(domain: 2...7, range: -0.5...0.5)
          .chartZScale(domain: 30...60, range: -0.5...0.5)
          .chartXAxis {
            AxisMarks(values: [160, 180, 200, 220, 240]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartYAxis {
            AxisMarks(values: [2, 3, 4, 5, 6, 7]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
          .chartZAxis {
            AxisMarks(values: [30, 40, 50, 60]) {
              AxisTick()
              AxisGridLine()
              AxisValueLabel()
            }
          }
        }
      }
    • 9:24 - Customize the surface styles for a sinc function

      // Customize the surface styles for a sinc function
      
      import SwiftUI
      import Charts
      
      struct SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              let h = hypot(x, z)
              return sin(h) / h
            }
          }
          .chartXScale(domain: -10...10, range: -0.5...0.5)
          .chartZScale(domain: -10...10, range: -0.5...0.5)
          .chartYScale(domain: -0.23...1, range: -0.5...0.5)
        }
      }
    • 9:29 - Customize the surface styles for a sinc function (EllipticalGradient)

      // Customize the surface styles for a sinc function
      
      import SwiftUI
      import Charts
      
      struct SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              let h = hypot(x, z)
              return sin(h) / h
            }
            .foregroundStyle(EllipticalGradient(colors: [.red, .orange, .yellow, .green, .blue, .indigo, .purple]))
          }
          .chartXScale(domain: -10...10, range: -0.5...0.5)
          .chartZScale(domain: -10...10, range: -0.5...0.5)
          .chartYScale(domain: -0.23...1, range: -0.5...0.5)
        }
      }
    • 9:38 - Customize the surface styles for a sinc function (heightBased)

      // Customize the surface styles for a sinc function
      
      import SwiftUI
      import Charts
      
      struct SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              let h = hypot(x, z)
              return sin(h) / h
            }
            .foregroundStyle(.heightBased)
          }
          .chartXScale(domain: -10...10, range: -0.5...0.5)
          .chartZScale(domain: -10...10, range: -0.5...0.5)
          .chartYScale(domain: -0.23...1, range: -0.5...0.5)
        }
      }
    • 9:47 - Customize the surface styles for a sinc function (normalBased)

      // Customize the surface styles for a sinc function
      
      import SwiftUI
      import Charts
      
      struct SurfacePlotChart: View {
        var body: some View {
          Chart3D {
            SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
              let h = hypot(x, z)
              return sin(h) / h
            }
            .foregroundStyle(.normalBased)
          }
          .chartXScale(domain: -10...10, range: -0.5...0.5)
          .chartZScale(domain: -10...10, range: -0.5...0.5)
          .chartYScale(domain: -0.23...1, range: -0.5...0.5)
        }
      }
    • 0:00 - Introducción
    • Swift Charts admite gráficos 3D en iOS, macOS y visionOS 26. Crea visualizaciones 3D que permitan a las personas explorar datos desde nuevas perspectivas.

    • 1:54 - Trazado en 3D
    • Hacer un gráfico 3D es similar al enfoque para hacer gráficos 2D. Explora cómo un solo gráfico 3D puede representar múltiples perspectivas de gráficos 2D. Construye un gráfico de dispersión 3D con PointMark y Chart3D. Los gráficos 3D son interactivos y se pueden rotar para revelar información diferente, como grupos de datos. Muchas marcas para gráficos 2D se reinventaron para 3D.

    • 5:05 - Gráfico de superficie
    • SurfacePlot traza funciones de 2 variables en 3D, creando una superficie continua. Proporciona una expresión que produzca un valor Y en términos de X y Z. Estas superficies pueden ser simples, como un plano, o más complejas con formas interesantes.

    • 7:03 - Personalización
    • Swift Charts tiene modificadores para personalizar la apariencia de los gráficos 3D. Establece el ángulo de visión del gráfico con el modificador chart3DPose. Especifica el comportamiento 3D del gráfico con el modificador chart3DCameraProjection. También hay nuevos estilos de primer plano para los gráficos de superficie. Cambia el color en los puntos pegados en el ángulo de la superficie en un punto particular o altura relativa. Estas técnicas, así como muchos modificadores de los gráficos 2D, personalizan los gráficos 3D para que sean hermosos.

Developer Footer

  • Videos
  • WWDC25
  • Lleva los gráficos Swift a la tercera dimensión
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Store
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Sample Code
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines