Varför Swift Charts Är Det Bästa Valet för Datavisualisering på Apple-plattformar
Datavisualisering är en avgörande del av moderna appar — det spelar ingen roll om du bygger en fitness-tracker, en finansapp eller en väderapplikation. Innan iOS 16 var vi tvungna att antingen dra in tredjepartsbibliotek eller hacka ihop egna diagramlösningar från grunden med Path och Shape. Det funkade, visst, men det var arbetsintensivt och ganska plågsamt att underhålla.
Sen kom Swift Charts och förändrade spelplanen helt.
Apple introducerade ett deklarativt ramverk som integreras sömlöst med SwiftUI, stödjer alla Apple-plattformar och levererar tillgänglighet, Dark Mode och Dynamic Type direkt ur lådan. Sedan lanseringen har ramverket utvecklats i rask takt — rullningsbara diagram och cirkeldiagram i iOS 17, funktionsplottar och vektoriserade API:er i iOS 18, och nu 3D-diagram med Chart3D i iOS 26.
I den här guiden tar vi dig genom hela resan: från grundläggande stapeldiagram till interaktiva, rullningsbara diagram och de helt nya 3D-visualiseringarna. Varje avsnitt innehåller fungerande kodexempel som du kan köra direkt i dina egna projekt.
Komma Igång med Swift Charts
Importera ramverket
Swift Charts ingår i SDK:n från och med iOS 16, macOS 13, watchOS 9 och tvOS 16. Inga externa beroenden behövs — bara importera:
import SwiftUI
import Charts
Din första Chart-vy
Kärnan i Swift Charts är Chart-vyn. Inuti den placerar du marks — grafiska element som representerar data. Varje mark-typ skapar en specifik typ av visualisering.
Här är det enklaste möjliga exemplet:
struct FörsäljningsData: Identifiable {
let id = UUID()
let månad: String
let belopp: Double
}
let försäljning = [
FörsäljningsData(månad: "Jan", belopp: 5200),
FörsäljningsData(månad: "Feb", belopp: 7800),
FörsäljningsData(månad: "Mar", belopp: 6100),
FörsäljningsData(månad: "Apr", belopp: 9400),
FörsäljningsData(månad: "Maj", belopp: 8300),
FörsäljningsData(månad: "Jun", belopp: 11200)
]
struct FörsäljningsDiagram: View {
var body: some View {
Chart(försäljning) { post in
BarMark(
x: .value("Månad", post.månad),
y: .value("Belopp", post.belopp)
)
}
.frame(height: 300)
.padding()
}
}
Det är bokstavligen allt som krävs. Chart tar en samling data och för varje element skapar du en BarMark med x- och y-värden. SwiftUI sköter axlar, skalor och layout automatiskt. Ganska elegant, faktiskt.
Mark-typer: Byggstenarna i Dina Diagram
Swift Charts bygger på komposition snarare än färdiga diagramtyper. Du kombinerar marks för att skapa precis det diagram du behöver. Låt oss gå igenom dem.
BarMark — Stapeldiagram
BarMark är den mest använda marken och perfekt för att jämföra diskreta kategorier. Vill du ha horisontella staplar istället? Bara byt x och y:
Chart(försäljning) { post in
BarMark(
x: .value("Belopp", post.belopp),
y: .value("Månad", post.månad)
)
.foregroundStyle(.blue.gradient)
}
LineMark — Linjediagram
LineMark kopplar ihop datapunkter med linjesegment och är idealisk för att visa trender över tid:
Chart(temperaturData) { punkt in
LineMark(
x: .value("Dag", punkt.datum),
y: .value("Temperatur", punkt.grader)
)
.interpolationMethod(.catmullRom)
}
.chartYAxisLabel("°C")
Modifieraren .interpolationMethod(.catmullRom) ger dig mjuka kurvor istället för raka linjer mellan datapunkterna. Det ser betydligt mer professionellt ut.
PointMark — Punktdiagram
PointMark visar enskilda datapunkter och är utmärkt för scatterplots:
Chart(mätningar) { m in
PointMark(
x: .value("Vikt", m.vikt),
y: .value("Längd", m.längd)
)
.symbolSize(60)
.foregroundStyle(by: .value("Kategori", m.kategori))
}
AreaMark — Ytdiagram
AreaMark fyller ytan under en linje — effektivt för att visa volymer och ackumulerade värden:
Chart(trafik) { dag in
AreaMark(
x: .value("Datum", dag.datum),
y: .value("Besökare", dag.besökare)
)
.foregroundStyle(.green.opacity(0.3))
LineMark(
x: .value("Datum", dag.datum),
y: .value("Besökare", dag.besökare)
)
.foregroundStyle(.green)
}
Att kombinera AreaMark med LineMark i samma diagram ger en tydlig linje ovanpå den fyllda ytan. Det här mönstret dyker upp i princip överallt i produktionsappar, och av goda skäl — det ser riktigt snyggt ut.
RuleMark — Referenslinjer
RuleMark ritar horisontella eller vertikala linjer. Jag använder den oftast för att visa medelvärden eller mål:
Chart {
ForEach(försäljning) { post in
BarMark(
x: .value("Månad", post.månad),
y: .value("Belopp", post.belopp)
)
}
RuleMark(y: .value("Mål", 8000))
.foregroundStyle(.red)
.lineStyle(StrokeStyle(lineWidth: 2, dash: [5, 3]))
.annotation(position: .top, alignment: .leading) {
Text("Mål: 8 000 kr")
.font(.caption)
.foregroundStyle(.red)
}
}
RectangleMark — Värmekarta
RectangleMark skapar rektangulära ytor och lämpar sig perfekt för heatmaps:
Chart(aktivitet) { cell in
RectangleMark(
x: .value("Veckodag", cell.dag),
y: .value("Timme", cell.timme)
)
.foregroundStyle(by: .value("Intensitet", cell.värde))
}
Anpassa Diagrammens Utseende
Färger och stilar
Du styr färgerna med .foregroundStyle. Den kan ta en fast färg, en gradient eller automatiskt tilldela färger baserat på datavärden:
Chart(försäljning) { post in
BarMark(
x: .value("Månad", post.månad),
y: .value("Belopp", post.belopp)
)
.foregroundStyle(by: .value("Produkt", post.produkt))
}
.chartForegroundStyleScale([
"App": .blue,
"Prenumeration": .green,
"Engångsköp": .orange
])
Axelanpassning
Med chartXAxis och chartYAxis kan du detaljstyra axlarnas utseende. Det ger dig full kontroll:
Chart(data) { punkt in
LineMark(
x: .value("Datum", punkt.datum),
y: .value("Värde", punkt.värde)
)
}
.chartXAxis {
AxisMarks(values: .stride(by: .month)) { value in
AxisGridLine()
AxisValueLabel(format: .dateTime.month(.abbreviated))
}
}
.chartYAxis {
AxisMarks(position: .leading) { value in
AxisGridLine()
AxisValueLabel()
}
}
.chartYScale(domain: 0...100)
Dölja axlar och legend
Ibland vill du ha ett renare utseende — särskilt i widgets eller kompakta vyer. Så här gör du:
Chart(data) { ... }
.chartXAxis(.hidden)
.chartYAxis(.hidden)
.chartLegend(.hidden)
SectorMark: Cirkeldiagram och Munkdiagram (iOS 17+)
En av de mest efterfrågade funktionerna landade i iOS 17 — SectorMark för cirkeldiagram och munkdiagram. Ärligt talat var det på tiden. Före iOS 17 var vi tvungna att bygga dessa manuellt med Path och Arc, vilket var... ja, inte kul.
Nu räcker det med några rader kod.
Grundläggande cirkeldiagram
struct KategoriData: Identifiable {
let id = UUID()
let namn: String
let andel: Double
}
let kategorier = [
KategoriData(namn: "Mat", andel: 35),
KategoriData(namn: "Boende", andel: 40),
KategoriData(namn: "Transport", andel: 15),
KategoriData(namn: "Nöje", andel: 10)
]
struct CirkelDiagram: View {
var body: some View {
Chart(kategorier) { kat in
SectorMark(
angle: .value("Andel", kat.andel),
angularInset: 2
)
.foregroundStyle(by: .value("Kategori", kat.namn))
.cornerRadius(4)
}
.frame(height: 300)
}
}
Konvertera till munkdiagram
Att omvandla cirkeldiagrammet till ett munkdiagram kräver bara en enda parameter — innerRadius:
SectorMark(
angle: .value("Andel", kat.andel),
innerRadius: .ratio(0.6),
angularInset: 2
)
Du kan dessutom lägga till text i mitten av munkdiagrammet med chartBackground. Det här är ett litet knep som verkligen lyfter designen:
Chart(kategorier) { kat in
SectorMark(
angle: .value("Andel", kat.andel),
innerRadius: .ratio(0.6),
angularInset: 2
)
.foregroundStyle(by: .value("Kategori", kat.namn))
}
.chartBackground { proxy in
GeometryReader { geo in
if let frame = proxy.plotFrame {
let rect = geo[frame]
VStack {
Text("Budget")
.font(.headline)
Text("2026")
.font(.caption)
.foregroundStyle(.secondary)
}
.position(x: rect.midX, y: rect.midY)
}
}
}
Interaktiva Diagram med Selektion (iOS 17+)
iOS 17 introducerade inbyggda selektionsmodifierare som gör det enkelt att skapa interaktiva diagram. Ingen manuell gesthantering behövs längre — äntligen.
Punkt-selektion med chartXSelection
Den nya chartXSelection-modifieraren hanterar all gestigenkänning åt dig. Du binder den till en state-variabel och Swift Charts uppdaterar värdet automatiskt när användaren trycker eller drar:
struct InteraktivtDiagram: View {
@State private var valdDatum: Date?
var body: some View {
Chart(dagligFörsäljning) { dag in
LineMark(
x: .value("Datum", dag.datum),
y: .value("Intäkt", dag.intäkt)
)
if let valdDatum,
let punkt = dagligFörsäljning.first(where: {
Calendar.current.isDate($0.datum, inSameDayAs: valdDatum)
}) {
RuleMark(x: .value("Vald", punkt.datum))
.foregroundStyle(.gray.opacity(0.3))
.annotation(position: .top) {
VStack(alignment: .leading) {
Text(punkt.datum, format: .dateTime.day().month())
.font(.caption)
Text("\(punkt.intäkt, format: .number) kr")
.font(.headline)
}
.padding(8)
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8))
}
}
}
.chartXSelection(value: $valdDatum)
}
}
Det fina med det här är hur lite kod som faktiskt behövs. Några rader och du har en fullt interaktiv upplevelse.
Range-selektion
Du kan även välja ett intervall istället för en enskild punkt. På iOS aktiveras det med tvåfingersgester, och på macOS med dragning:
@State private var intervall: (Date, Date)?
Chart(data) { ... }
.chartXSelection(value: $intervall)
Vinkelselektion för cirkeldiagram
För SectorMark finns den specialiserade chartAngleSelection-modifieraren:
@State private var valdSektor: Double?
Chart(kategorier) { kat in
SectorMark(
angle: .value("Andel", kat.andel),
innerRadius: .ratio(0.6),
outerRadius: kat.namn == valdKategori ? .ratio(1.0) : .ratio(0.9),
angularInset: 2
)
.foregroundStyle(by: .value("Kategori", kat.namn))
}
.chartAngleSelection(value: $valdSektor)
Rullningsbara Diagram (iOS 17+)
Har du stora datamängder som inte ryms på skärmen? Ingen fara. Med iOS 17 kan du göra diagram rullningsbara med bara ett par modifierare.
Grundläggande rullning
struct RullbartDiagram: View {
@State private var scrollPosition: Date = .now
var body: some View {
Chart(årsdata) { dag in
BarMark(
x: .value("Datum", dag.datum, unit: .day),
y: .value("Steg", dag.steg)
)
}
.chartScrollableAxes(.horizontal)
.chartXVisibleDomain(length: 3600 * 24 * 30) // 30 dagar synligt
.chartScrollPosition(x: $scrollPosition)
}
}
chartScrollableAxes(.horizontal) aktiverar horisontell rullning. Med chartXVisibleDomain anger du hur mycket data som syns åt gången — i det här fallet 30 dagars tidsintervall. Och chartScrollPosition ger dig den aktuella scrollpositionen i en binding, vilket är otroligt användbart om du vill synka diagrammet med annan UI.
Snapping-beteende
Vill du att diagrammet alltid ska snäppa till specifika positioner? Till exempel den första dagen i varje månad? Det går att lösa med chartScrollTargetBehavior:
Chart(årsdata) { dag in
BarMark(
x: .value("Datum", dag.datum, unit: .day),
y: .value("Steg", dag.steg)
)
}
.chartScrollableAxes(.horizontal)
.chartXVisibleDomain(length: 3600 * 24 * 30)
.chartScrollTargetBehavior(
.valueAligned(
matching: DateComponents(day: 1),
majorAlignment: .matching(DateComponents(month: 1, day: 1))
)
)
Funktionsplottar och Vektoriserade API:er (iOS 18+)
Med iOS 18 fick Swift Charts möjligheten att rita matematiska funktioner och hantera stora datamängder mer effektivt. Det här är ärligt talat ganska coolt — det öppnar dörren för helt nya användningsområden bortom ren datavisualisering.
LinePlot — Rita matematiska funktioner
LinePlot tar en closure som accepterar en Double och returnerar en Double. Det gör det trivialt att plotta valfri matematisk funktion:
Chart {
LinePlot(x: "x", y: "sin(x)") { x in
sin(x)
}
.foregroundStyle(.blue)
LinePlot(x: "x", y: "cos(x)") { x in
cos(x)
}
.foregroundStyle(.red)
}
.chartXScale(domain: -.pi * 2 ... .pi * 2)
.chartYScale(domain: -1.5...1.5)
AreaPlot — Ytan mellan funktioner
AreaPlot kan visualisera ytan mellan två funktioner genom att returnera en tupel med start- och slutvärden:
Chart {
AreaPlot(x: "x", yStart: "nedre", yEnd: "övre") { x in
(sin(x) - 0.3, sin(x) + 0.3)
}
.foregroundStyle(.blue.opacity(0.2))
LinePlot(x: "x", y: "sin(x)") { x in
sin(x)
}
.foregroundStyle(.blue)
}
.chartXScale(domain: 0 ... .pi * 4)
Vektoriserade plottar för prestanda
De nya vektoriserade API:erna — PointPlot, LinePlot, BarPlot, RulePlot, RectanglePlot, AreaPlot och SectorPlot — är optimerade för att hantera tusentals datapunkter effektivt. Några tips för bästa prestanda:
- Gruppera data efter stil för att minimera stilbyten under rendering
- Konvertera beräknade egenskaper till lagrade egenskaper när det är möjligt
- Ange kända stilar och domänbegränsningar i förväg istället för att låta ramverket beräkna dem
- För extremt stora datamängder (10 000+ punkter) bör du implementera nedsampling (t.ex. med LTTB-algoritmen) utanför huvudtråden
3D-diagram med Chart3D (iOS 26+)
Okej, nu kommer vi till den riktigt spännande delen. På WWDC 2025 presenterade Apple fullständigt stöd för 3D-diagram med det nya Chart3D-API:et. Det bygger på RealityKit och fungerar på iOS 26, macOS 26 och visionOS 26.
Från 2D till 3D — En enkel migration
Att gå från ett 2D-diagram till 3D är förvånansvärt enkelt. Du byter Chart mot Chart3D och lägger till en z-axel. Det är i princip det:
// 2D-version
Chart(mätningar) { m in
PointMark(
x: .value("Vikt", m.vikt),
y: .value("Längd", m.längd)
)
.foregroundStyle(by: .value("Typ", m.typ))
}
// 3D-version
Chart3D(mätningar) { m in
PointMark(
x: .value("Vikt", m.vikt),
y: .value("Längd", m.längd),
z: .value("Ålder", m.ålder)
)
.foregroundStyle(by: .value("Typ", m.typ))
}
SurfacePlot — Matematiska ytor i 3D
SurfacePlot är den tredimensionella motsvarigheten till LinePlot. Den plottar en matematisk yta genom att ta två variabler och returnera ett y-värde:
Chart3D {
SurfacePlot(x: "x", y: "y", z: "z") { x, z in
sin(x) * cos(z)
}
.foregroundStyle(
Gradient(colors: [.blue, .cyan, .green, .yellow, .orange])
)
}
.chartXScale(domain: -3...3)
.chartZScale(domain: -3...3)
Du kan dessutom applicera specialiserade stilar som .heightBased och .normalBased på SurfacePlot för att framhäva höjdskillnader respektive ytans lutning. Riktigt snyggt för vetenskapliga visualiseringar.
Kameraposition och perspektiv
Med Chart3DPose kan du styra betraktningsvinkeln. Binder du posen till en state-variabel kan användaren interagera med diagrammet genom rotationsgesler:
struct Interaktivt3DDiagram: View {
@State private var pose = Chart3DPose(
azimuth: .degrees(30),
inclination: .degrees(20)
)
var body: some View {
Chart3D(dataset) { punkt in
PointMark(
x: .value("X", punkt.x),
y: .value("Y", punkt.y),
z: .value("Z", punkt.z)
)
}
.chart3DPose($pose)
}
}
Som standard använder Chart3D ortografisk projektion — alla element har samma storlek oavsett avstånd. Vill du ha djupeffekt kan du aktivera perspektivprojektion, där närmare objekt visas större. Det ger en mer realistisk 3D-upplevelse, särskilt på visionOS.
3D-diagram på visionOS
Chart3D fungerar naturligt på Vision Pro där tredimensionella datamängder verkligen får extra mening. Användare kan rotera, zooma och utforska data i rummet — en upplevelse som saknar motstycke i traditionella 2D-diagram. Om du har tillgång till en Vision Pro och jobbar med datatunga appar är det här värt att experimentera med.
Tillgänglighet — Inbyggt från Start
En av Swift Charts starkaste sidor (och något Apple verkligen gjort rätt) är att tillgänglighet är automatiskt. Du får stöd för VoiceOver, Audio Graphs som låter användare lyssna på datatrender, Dynamic Type, Dark Mode och High Contrast-läge utan extra arbete.
Audio Graphs fungerar dessutom med LinePlot och andra funktionsplottar, inte bara datadrivna diagram.
Vill du ge ytterligare kontext kan du anpassa tillgänglighetsetiketter:
BarMark(
x: .value("Månad", post.månad),
y: .value("Belopp", post.belopp)
)
.accessibilityLabel("\(post.månad)")
.accessibilityValue("\(post.belopp) kronor")
Bästa Praxis för Produktionsappar
- Välj rätt mark-typ — Använd
BarMarkför jämförelser,LineMarkför trender,SectorMarkför proportioner ochPointMarkför korrelationer - Kombinera marks — Overlaya
LineMarkmedAreaMarkeller lägg tillRuleMarkför referensvärden - Tänk på prestanda — För stora datamängder, använd de vektoriserade API:erna och undvik tunga beräkningar i rendering-closures
- Animera förändringar — Swift Charts animerar automatiskt förändringar i data med
withAnimation - Anpassa för plattformen — Testa dina diagram på olika skärmstorlekar, i Dark Mode och med Dynamic Type
- Använd chartBackground och annotation — Ge kontext med förklarande text och visuella markeringar direkt i diagrammet
Vanliga Frågor
Vilka iOS-versioner stödjer Swift Charts?
Grundläggande Swift Charts med BarMark, LineMark, PointMark, AreaMark, RuleMark och RectangleMark kräver iOS 16 eller senare. SectorMark (cirkeldiagram), rullningsbara diagram och selektions-API:er kräver iOS 17. Funktionsplottar och vektoriserade API:er kräver iOS 18. Chart3D och SurfacePlot kräver iOS 26.
Kan jag använda Swift Charts i en widget?
Absolut. Swift Charts fungerar utmärkt i widgets. Tänk bara på att dölja axlar och legend med .chartXAxis(.hidden) och .chartLegend(.hidden) för att maximera utrymmet. Interaktiva funktioner som selektion fungerar dock inte i widgets.
Hur hanterar jag stora datamängder utan prestandaproblem?
Använd de vektoriserade plot-API:erna som kom i iOS 18. Gruppera data efter stil för att minimera renderingsbyten. Har du extremt stora datamängder (över 10 000 punkter) bör du implementera nedsampling med algoritmer som LTTB (Largest Triangle Three Buckets) utanför huvudtråden innan du plottar.
Kan jag blanda olika mark-typer i samma diagram?
Ja, det är just det som gör Swift Charts så kraftfullt. Du kan till exempel kombinera BarMark med RuleMark för att visa staplar med ett målvärde, eller lägga PointMark ovanpå LineMark för att markera specifika datapunkter. Alla marks delar samma koordinatsystem inom en Chart-vy.
Vad är skillnaden mellan Chart och Chart3D?
Chart är den tvådimensionella containern som funnits sedan iOS 16 och stödjer x- och y-axlar. Chart3D, introducerad i iOS 26, lägger till en z-axel och bygger på RealityKit för 3D-rendering. Migrering är enkel — byt Chart mot Chart3D och lägg till z-värden i dina marks. Chart3D stödjer PointMark, RuleMark, RectangleMark och det unika SurfacePlot.