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

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Tópicos
  • Todos os vídeos
  • Sobre

Voltar para WWDC25

  • Sobre
  • Resumo
  • Transcrição
  • Código
  • Leve o Swift Charts para a terceira dimensão

    Saiba como transformar seus gráficos 2D do Swift Charts em gráficos 3D com o Chart3D e visualizar seus conjuntos de dados de perspectivas completamente novas. Exiba seus dados em 3D, visualize superfícies matemáticas e personalize tudo, da câmera aos materiais, para deixar seus gráficos 3D mais intuitivos e agradáveis. Para aproveitar ao máximo esta sessão, recomendamos que você esteja com a criação de gráficos 2D usando o Swift Charts.

    Capítulos

    • 0:00 - Introdução
    • 1:54 - Criar em 3D
    • 5:05 - Gráficos de superfície
    • 7:03 - Personalização

    Recursos

    • Swift Charts
    • Swift Charts updates
      • Vídeo HD
      • Vídeo SD

    Vídeos relacionados

    WWDC24

    • Swift Charts: Vectorized and function plots

    WWDC22

    • Design an effective chart
    • Design app experiences with charts
  • Buscar neste vídeo...

    Olá! Meu nome é Mike. Sou engineer na equipe de System Experience. Hoje, quero falar sobre um novo recurso incrível do Swift Charts. Swift Charts é um framework para criar gráficos acessíveis e impressionantes.

    Usamos gráficos nas plataformas da Apple para verificar a temperatura no app Tempo, mostrar o uso da bateria nos Ajustes e representar funções matemáticas nas Notas de Cálculo.

    Ao usar os blocos de construção disponíveis no Swift Charts, você cria gráficos 2D usando componentes como marcas de eixo, rótulos e gráficos de linha.

    E tem mais! Novidade no iOS, no macOS e no visionOS 26, o Swift Charts agora aceita gráficos 3D. Isso mesmo, agora as pessoas podem explorar e entender conjuntos de dados de perspectivas completamente novas.

    Nesta sessão, vou mostrar como transformar gráficos 2D em 3D com a plotagem em 3D e também falar sobre como os gráficos de superfície podem ser usados para criar gráficos de funções matemáticas tridimensionais e maneiras de personalizar seus gráficos para deixá-los mais intuitivos e agradáveis. Mas antes, tenho um anúncio importante para fazer:

    eu amo pinguins!

    Um dos meus conjuntos de dados favoritos contém medições de centenas de pinguins em todo o Arquipélago Palmer, na Antártida.

    Os dados incluem comprimento do bico e da nadadeira e peso de cada pinguim e estão agrupados por espécie: pinguim-de-barbicha, pinguim-gentoo e pinguim-de-adélia.

    Vou usar o Swift Charts para obter insights desses dados e mostrar como a plotagem em 3D ajuda a visualizar as diferenças entre as espécies de pinguins.

    Criei um gráfico 2D para mostrar a relação entre os comprimentos das nadadeiras e os pesos dos pinguins. PointMark plota o comprimento da nadadeira e o peso de cada pinguim, e foregroundStyle colore os pontos por espécie e cria a legenda no canto.

    Isso é ótimo, e o Swift Charts facilitou a criação do gráfico. Este gráfico mostra que os pinguins-de-barbicha e os pinguins-de-adélia têm comprimentos de nadadeira e pesos semelhantes, enquanto os pinguins-gentoo têm nadadeiras mais longas e pesam mais.

    O conjunto de dados também inclui o comprimento do bico, então fiz um gráfico que plota o comprimento do bico e o peso.

    Este mostra que os pinguins-de-barbicha e os pinguins-gentoo têm comprimentos de bico semelhantes, enquanto os pinguins-de-adélia têm bicos mais curtos.

    Por fim, fiz um gráfico para os comprimentos do bico e das nadadeiras, que mostra que pinguins com bicos mais longos tendem a ter nadadeiras mais longas também.

    Esses gráficos 2D são ótimos e fornecem bons insights sobre as relações entre duas propriedades ao mesmo tempo.

    No entanto, o Swift Charts agora pode criar um único gráfico que contém todos esses dados.

    É o Chart3D. O Chart3D usa conceitos conhecidos de gráficos 2D, como gráficos de dispersão, e os transforma em 3D.

    Para usar um gráfico 3D, vou mudar Chart para Chart3D.

    PointMark funciona bem no Chart3D e agora aceita um valor z. Aqui, vou usar o comprimento do bico.

    Vou definir o rótulo do eixo Z como "Comprimento do bico" também. Pronto!

    Com poucas linhas de código e o Chart3D, consigo ver as diferenças entre as espécies de pinguins de uma forma divertida e interativa.

    Posso usar gestos simples para girar o gráfico em ângulos precisos e ver três clusters de pontos de dados.

    Também posso visualizar o gráfico pelas laterais para comparar duas propriedades, semelhante a um gráfico 2D.

    Gráficos 3D funcionam bem quando a forma dos dados é mais importante do que os valores exatos. Isso pode acontecer quando os dados em si são tridimensionais, especialmente se representarem uma posição física no espaço 3D.

    Além disso interatividade é fundamental para entender conjuntos de dados tridimensionais. Por isso, só use gráficos 3D se a interação aprimorar a experiência no app. Quando se trata da melhor representação para seu conjunto de dados, escolher entre 2D e 3D não é algo simples.

    PointMarks, RuleMarks e RectangleMarks foram atualizados para gráficos 3D. E agora, exclusivamente no Chart3D, temos o SurfacePlot. Vou mostrar como ele funciona.

    SurfacePlot é a extensão tridimensional do LinePlot. Ele plota uma superfície matemática que contém até duas variáveis em três dimensões.

    A nova API SurfacePlot é semelhante à API LinePlot.

    Ele aceita um fechamento que usa dois duplos e retorna um duplo.

    Depois de inserir uma expressão matemática no fechamento, o SurfacePlot avalia a expressão para obter diferentes valores de x e z e cria uma superfície contínua dos valores y computados. Essas superfícies podem ser complexas ou simples, como você quiser.

    Para saber mais sobre gráficos de função por meio da API LinePlot, confira a sessão "Swift Charts: Gráficos vetorizados e de funções", da WWDC24.

    Sabe de uma coisa? Agora que estou olhando o conjunto de dados de novo, parece haver uma relação linear entre o comprimento do bico e da nadadeira com o peso de um pinguim. Esse raciocínio parece razoável, mas, em vez ficar adivinhando, posso usar o SurfacePlot para mostrar uma regressão linear dos dados.

    Defini uma classe LinearRegression que estima um valor y com base nas variáveis independentes x e z. Mais especificamente, defini a regressão linear para estimar o peso de um pinguim com base no comprimento da nadadeira e do bico.

    Essa regressão linear é usada no SurfacePlot para plotar os pesos estimados como uma superfície contínua.

    Ótimo! Parece mesmo que há uma relação linear nesses dados. O SurfacePlot mostra uma correlação positiva entre o comprimento da nadadeira e o peso, e há uma ligeira correlação positiva entre o comprimento do bico e o peso também.

    Agora, vou mostrar algumas maneiras de personalizar o estilo e o comportamento do Chart3D.

    Enquanto eu estava interagindo com o conjunto de dados de pinguins, notei que alterar o ângulo do gráfico também altera a aparência dos dados.

    Este ângulo é ótimo para mostrar os clusters de pontos de dados. Já este ângulo funciona bem para mostrar uma relação linear.

    Esses ângulos são conhecidos como a posição do gráfico.

    É importante escolher uma posição inicial que forneça uma boa representação dos dados.

    Para dados dinâmicos em que você não sabe os valores de antemão, escolha uma posição inicial que funcione bem para conjuntos de dados desse tipo.

    A posição do gráfico é ajustada usando o modificador Chart3DPose e usa um Chart3DPose.

    Posso definir a posição com valores específicos, como front, ou definir uma posição personalizada. Este inicializador usa dois parâmetros: azimute, que gira o gráfico para esquerda e para direita,

    e inclination, que inclina o gráfico para cima e para baixo.

    Agora, observe como os pontos próximos à parte de trás do gráfico têm o mesmo tamanho que os próximos à parte da frente.

    Isso facilita a comparação de tamanhos e distâncias no gráfico, independentemente da profundidade. Também é ótimo para visualizar gráficos de lado, pois transforma um gráfico 3D em 2D.

    Isso é conhecido como projeção de câmera ortográfica.

    O Chart3D oferece duas projeções de câmera: ortográfica, que é o comportamento padrão, e perspectiva. Na projeção perspectiva, os pontos de dados mais distantes parecem menores, e as linhas paralelas convergem. Isso permite uma experiência imersiva e ajuda na percepção de profundidade.

    A projeção de câmera é definida usando o modificador chart3DCameraProjection.

    SurfacePlots também têm algumas opções de personalização para os estilos de superfície.

    ForegroundStyle aceita gradientes como LinearGradient ou EllipticalGradient e aceita dois novos valores: heightBased, que colore pontos com base na altura da superfície naquele ponto, e normalBased, que colore pontos com base no ângulo da superfície naquele ponto.

    Existem outros modificadores disponíveis para o Chart3D, alguns dos quais são comuns em gráficos 2D. Use-os para personalizar estilos de superfície, símbolos PointMark, domínio do gráfico, marcas de eixo ou o comportamento da seleção.

    Combinando esses modificadores de visualização com PointMark, RuleMark, RectangleMark e SurfacePlot, você tem uma infinidade de gráficos interessantes. Essa é só a ponta do iceberg.

    Os gráficos 3D funcionam e ficam ótimos no Vision Pro, uma opção natural para conjuntos de dados tridimensionais!

    Esses são alguns dos novos recursos em 3D que estão chegando ao Swift Charts.

    Depois de decidir representar seus dados em 3D, tente plotar com o Chart3D para dar um novo nível de profundidade aos seus gráficos e use as APIs de personalização do Swift Charts para criar gráficos acessíveis e impressionantes.

    Para saber mais sobre as práticas recomendadas para incorporar o Swift Charts aos seus apps, confira a sessão "Criar experiências de apps com gráficos", da WWDC22.

    Obrigado. Estou ansioso para ver os tipos de gráfico que você vai trazer para a terceira dimensão.

    • 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 - Introdução
    • O Swift Charts é compatível com gráficos 3D no iOS, macOS e visionOS 26. Crie visualizações em 3D que permitam que as pessoas explorem dados sob novas perspectivas.

    • 1:54 - Criar em 3D
    • A abordagem de criação de um gráfico 3D é semelhante à de gráficos 2D. Explore como um único gráfico 3D pode representar várias perspectivas de gráficos 2D. Crie um gráfico de dispersão 3D com o PointMark e Chart3D. Gráficos 3D são interativos e podem ser girados para revelar diferentes informações, como clusters de dados. Muitas elementos gráficos usados em gráficos 2D foram reformulados para uso em 3D.

    • 5:05 - Gráficos de superfície
    • SurfacePlot plota funções de 2 variáveis em 3D, criando uma superfície contínua. Forneça uma expressão que produza um valor y em termos de x e z. Essas superfícies podem ser simples, como um plano, ou mais complexas com formas interessantes.

    • 7:03 - Personalização
    • O Swift Charts tem modificadores para personalizar a aparência de gráficos 3D. Defina o ângulo de visualização do gráfico com o modificador chart3DPose. Especifique o comportamento 3D do gráfico com o modificador chart3DCameraProjection. Há também novos estilos de primeiro plano para gráficos de superfície. Altere a cor em pontos posicionados no ângulo da superfície em um ponto específico, ou de acordo com a altura relativa. Essas técnicas, bem como muitos modificadores de gráficos 2D, personalizam gráficos 3D para torná-los visualmente atraentes.

Developer Footer

  • Vídeos
  • WWDC25
  • Leve o Swift Charts para a terceira dimensão
  • 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