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

Vidéos

Ouvrir le menu Fermer le menu
  • Collections
  • Sujets
  • Toutes les vidéos
  • À propos

Plus de vidéos

  • À propos
  • Résumé
  • Transcription
  • Code
  • Donnez une nouvelle dimension à Swift Charts avec la 3D

    Découvrez comment donner une troisième dimension à vos graphiques Swift 2D avec Chart3D et visualiser vos ensembles de données sous des perspectives entièrement nouvelles. Représentez vos données en 3D, visualisez des surfaces mathématiques et personnalisez chaque élément, de la caméra aux matériaux, afin de rendre vos graphiques 3D encore plus intuitifs et attrayants. Pour tirer le meilleur parti de cette séance, nous vous recommandons de vous familiariser avec la création de graphiques Swift 2D.

    Chapitres

    • 0:00 - Introduction
    • 1:54 - Tracé en 3D
    • 5:05 - Tracé de surface
    • 7:03 - Personnalisation

    Ressources

    • Swift Charts
    • Swift Charts updates
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC24

    • Swift Charts: Vectorized and function plots

    WWDC22

    • Design an effective chart
    • Design app experiences with charts
  • Rechercher dans cette vidéo…

    Bonjour, je suis Mike, ingénieur dans l’équipe System Experience. Je vais vous parler d’une nouvelle fonctionnalité intéressante de Swift Charts. Swift Charts est un framework qui permet de créer des graphiques clairs et attrayants.

    Les graphiques sont utilisés sur toutes les plates-formes Apple, par exemple pour consulter la météo, afficher l’utilisation de la batterie ou représenter graphiquement des fonctions mathématiques.

    Avec les éléments de base de Swift Charts, vous pouvez créer des graphiques 2D avec des axes, des étiquettes et des courbes.

    Mais l’intrigue se corse ! Dans iOS, macOS et visionOS 26 : Swift Charts prend désormais en charge les graphiques 3D. Vous pouvez désormais aider les utilisateurs à explorer et comprendre les données sous un tout nouvel angle.

    Dans cette séance, je vais vous montrer comment passer de graphiques 2D à la 3D, expliquer comment utiliser les surfaces pour représenter des fonctions mathématiques en 3 dimensions, et présenter des options de personnalisation pour rendre vos graphiques plus intuitifs et attrayants. Mais d’abord, j’ai une annonce importante :

    j’adore les manchots !

    L’un de mes jeux de données préférés contient des mesures portant sur des centaines de manchots dans l’archipel Palmer, en Antarctique.

    Ces données incluent la longueur du bec, la longueur des nageoires et le poids de chaque manchot, regroupés par espèce : à jugulaire, papou et Adélie.

    Je vais utiliser Swift Charts pour explorer ces données et visualiser en 3D les différences entre les espèces de manchots.

    J’ai donc créé un graphique 2D pour illustrer la relation entre la longueur des nageoires et le poids des manchots. PointMark permet de tracer la longueur des nageoires et le poids de chacun tandis que foregroundStyle colore les points selon l’espèce et crée la légende dans le coin.

    C’est super et Swift Charts a permis de créer ce graphique très facilement. Ce graphique montre que les manchots à jugulaire et Adélie ont des nageoires et un poids similaires, tandis que les manchots papous ont des nageoires plus longues et un poids plus élevé.

    Le jeu de données contient aussi la longueur du bec, j’ai donc aussi créé un graphique qui trace la longueur du bec en fonction du poids.

    Celui-ci montre que les manchots à jugulaire et les manchots papous ont des longueurs de bec similaires et que celui des manchots Adélie est plus court.

    Enfin, j’ai créé un graphique montrant que les manchots au bec long ont aussi tendance à avoir de longues nageoires.

    Chacun de ces graphiques 2D est utile et donne de bonnes indications sur la relation entre deux caractéristiques à la fois.

    Swift Charts permet désormais de passer à la vitesse supérieure en regroupant toutes ces données dans un seul graphique.

    Et ça s’appelle Chart3D. Chart3D reprend des concepts familiers des graphiques 2D, tels que les nuages de points, et les transpose en 3D.

    Pour utiliser un graphique 3D, je vais remplacer Chart par Chart3D.

    PointMark fonctionne très bien dans Chart3D et accepte désormais une valeur Z. Ici, j’utilise Longueur du bec.

    Je vais aussi définir le libellé de l’axe Z sur « Longueur du bec ». Voilà !

    Avec quelques lignes de code et Chart3D, je vois tout de suite les différences entre les espèces de manchots, de manière ludique et interactive.

    Avec des gestes simples, je peux faire pivoter le graphique à des angles précis et voir 3 groupes de points de données.

    Je peux aussi afficher le graphique sur les côtés pour comparer deux propriétés comme si je visualisais le graphique en 2D.

    Les graphiques 3D sont très efficaces lorsque la forme des données prévaut sur leurs valeurs exactes. Cela peut se produire naturellement lorsque les données sont tridimensionnelles, surtout si elles représentent une position physique dans un espace 3D.

    L’interactivité étant clé pour explorer des données 3D, n’utilisez ces graphiques que si elle améliore vraiment l’expérience de votre app. Lorsqu’il s’agit de la meilleure représentation pour vos données, le choix entre la 2D et la 3D n’est pas si évident.

    PointMark, RuleMark et RectangleMark ont tous été mis à jour pour les graphiques 3D. Et maintenant, exclusivement pour Chart3D : SurfacePlot. Voyons comment ça fonctionne.

    SurfacePlot est l’extension tridimensionnelle de LinePlot. Il trace une surface mathématique contenant jusqu’à 2 variables en 3 dimensions.

    La nouvelle API SurfacePlot est similaire à l’API LinePlot.

    Elle accepte une fonction qui prend deux réels et renvoie un réel.

    Une fois l’expression mathématique saisie dans la closure, SurfacePlot l’évalue pour différentes valeurs de X et Z, et génère une surface continue à partir des valeurs Y calculées. Ces surfaces peuvent être aussi complexes ou simples que vous le voulez.

    Pour en savoir plus sur la représentation de fonctions avec l’API LinePlot, regardez « Swift Charts: Vectorized and function plots » de la WWDC24.

    Vous savez quoi ? En regardant à nouveau l’ensemble de données sur les manchots, il semble qu’il existe une relation linéaire entre la longueur du bec, celle des nageoires et le poids d’un manchot. Ça semble être une hypothèse raisonnable, mais au lieu d’improviser, j’utilise SurfacePlot pour afficher une régression linéaire des données.

    J’ai défini une classe LinearRegression qui estime une valeur Y à partir des variables indépendantes X et Z. J’ai configuré la régression linéaire pour estimer le poids d’un manchot en fonction de la longueur de ses nageoires et de son bec.

    Cette régression linéaire est utilisée dans SurfacePlot pour tracer les poids estimés sous forme de surface continue.

    Parfait ! Il semble qu’il y ait une relation linéaire dans ces données. Le SurfacePlot montre une corrélation positive entre la longueur des nageoires et le poids, ainsi qu’une légère corrélation positive entre la longueur du bec et le poids.

    Voyons maintenant comment personnaliser le style et le comportement de Chart3D.

    En explorant l’ensemble de données sur les manchots, j’ai remarqué que modifier l’angle du graphique change aussi la perception des données.

    Cet angle est idéal pour afficher les regroupements de points de données. Tandis que cet angle fonctionne mieux pour illustrer une relation linéaire.

    Ces angles sont appelés la pose du graphique.

    Il est important de choisir une pose initiale qui offre une bonne représentation de vos données.

    Pour des données dynamiques dont les valeurs sont inconnues à l’avance, choisissez une pose initiale adaptée aux jeux de données typiques de ce type.

    La pose du graphique se règle avec le modificateur Chart3DPose, qui prend une valeur de type Chart3DPose.

    Je peux définir une pose précise, comme une vue de face, ou créer une pose personnalisée. Cet initialiseur prend 2 paramètres : l’azimut, qui fait pivoter le graphique vers la gauche et la droite, et l’inclinaison, qui incline le graphique de haut en bas.

    Notez que les points situés à l’arrière du graphique ont la même taille que ceux à l’avant.

    Cela facilite la comparaison des tailles et des distances sur le graphique, quelle que soit la profondeur.

    C’est aussi très pratique pour une vue latérale, car cela revient à transformer un graphique 3D en vue 2D.

    Cela s’appelle une projection en caméra orthographique.

    Chart3D propose deux types de projection de caméra : orthographique, qui est le comportement par défaut, et perspective. Avec la projection en perspective, les points éloignés paraissent plus petits et les lignes parallèles convergent. Cela offre une expérience plus immersive et améliore la perception de la profondeur.

    La projection de la caméra se définit avec le modificateur chart3DCameraProjection.

    SurfacePlot offre également quelques options pour personnaliser le style de la surface.

    ForegroundStyle accepte les dégradés tels que LinearGradient ou EllipticalGradient, et prend en charge 2 nouvelles valeurs : heightBased, qui colore chaque point en fonction de sa hauteur sur la surface, et normalBased, qui le colore selon l’angle de la surface à cet endroit.

    Chart3D propose de nombreux modificateurs, certains déjà connus en 2D. Utilisez-les pour personnaliser le style des surfaces, les symboles PointMark, le domaine et les axes du graphique, ou le comportement de la sélection.

    En combinant ces modificateurs d’affichage avec PointMark, RuleMark, RectangleMark et SurfacePlot, il est possible d’obtenir toutes sortes de graphiques intéressants. Et vous n’avez encore rien vu.

    Les graphiques 3D sont parfaits sur Vision Pro, où ils mettent naturellement en valeur les données tridimensionnelles !

    Voici un aperçu des nouveautés 3D à venir dans Swift Charts.

    Une fois que vous avez choisi la 3D pour vos données, essayez Chart3D pour donner plus de profondeur à vos graphiques, et utilisez les API de Swift Charts pour créer des visuels attrayants et personnalisés.

    Pour découvrir les bonnes pratiques d’intégration de Swift Charts dans vos apps, regardez « Design app experiences with charts » de la WWDC22.

    Merci. J’ai hâte de découvrir les graphiques que vous allez créer en 3D.

    • 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 - Introduction
    • Swift Charts prend en charge les graphiques 3D sous iOS, macOS et visionOS 26. Créez des visualisations 3D qui permettent aux utilisateurs d’explorer les données sous de nouveaux angles.

    • 1:54 - Tracé en 3D
    • La création d’un graphique 3D est similaire à celle d’un graphique 2D. Découvrez comment un seul graphique 3D peut représenter plusieurs perspectives de graphiques 2D. Créez un nuage de points 3D avec PointMark et Chart3D. Les graphiques 3D sont interactifs et vous pouvez les faire pivoter pour révéler différentes informations, telles que des groupes de données. De nombreuses marques pour les graphiques 2D ont été repensées pour la 3D.

    • 5:05 - Tracé de surface
    • SurfacePlot trace des fonctions de 2 variables en 3D et crée ainsi une surface continue. Que ce soit pour dessiner un simple plan ou pour créer des formes plus élaborées aux reliefs captivants, il suffit d’entrer une expression qui définit la hauteur y selon les coordonnées x et z du plan horizontal.

    • 7:03 - Personnalisation
    • Swift Charts offre plusieurs options pour personnaliser l’aspect des graphiques en 3D. Vous pouvez ajuster l’angle de visualisation grâce à la fonction chart3DPose, et définir le rendu 3D avec chart3DCameraProjection. Les graphiques de surface bénéficient aussi de nouvelles options de style. Vous pouvez notamment modifier la couleur des points selon leur position ou leur hauteur relative sur la surface. En combinant ces fonctionnalités avec les nombreux paramètres déjà disponibles pour les graphiques 2D, vous pouvez créer des visualisations 3D élégantes et sur mesure.

Developer Footer

  • Vidéos
  • WWDC25
  • Donnez une nouvelle dimension à Swift Charts avec la 3D
  • 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