
-
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
Vidéos connexes
WWDC24
WWDC22
-
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: RandomAccessCollection>( _ data: Data, x xPath: KeyPath<Data.Element, Double>, y yPath: KeyPath<Data.Element, Double>, z zPath: KeyPath<Data.Element, Double> ) { 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.