Skip to content
Back to skills

Swift Charts

ASecurity

Building data visualizations in SwiftUI using Apple's Swift Charts framework

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 2, 2026
datagoswiftreactperformance

Security analysis

A100/100

Scanned June 2, 2026

npx -y skills add aRustyDev/agents --skill swift-charts --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Swift Charts?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Swift Charts
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/arustydev-swift-charts/badge)](https://www.skillsdirectory.com/skills/arustydev-swift-charts)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: swift-charts
description: Building data visualizations in SwiftUI using Apple's Swift Charts framework
tags: [swift, swiftui, charts, data-visualization, ios]
---

# Swift Charts

## Purpose

Building data visualizations in SwiftUI using Apple's Swift Charts framework.

## Basic Charts

### Line Chart

```swift
import Charts
import SwiftUI

struct TimeSeriesView: View {
    let data: [DataPoint]

    var body: some View {
        Chart(data) { point in
            LineMark(
                x: .value("Date", point.date),
                y: .value("Value", point.value)
            )
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .month)) { value in
                AxisValueLabel(format: .dateTime.month(.abbreviated))
            }
        }
    }
}
```

### Bar Chart

```swift
struct CategoryChart: View {
    let sales: [CategorySales]

    var body: some View {
        Chart(sales) { item in
            BarMark(
                x: .value("Category", item.category),
                y: .value("Sales", item.amount)
            )
            .foregroundStyle(by: .value("Category", item.category))
        }
        .chartLegend(.hidden)
    }
}
```

### Scatter Plot

```swift
struct ScatterView: View {
    let points: [Observation]

    var body: some View {
        Chart(points) { point in
            PointMark(
                x: .value("X", point.x),
                y: .value("Y", point.y)
            )
            .foregroundStyle(by: .value("Cluster", point.cluster))
            .symbolSize(point.weight * 10)
        }
    }
}
```

### Area Chart

```swift
struct StackedAreaChart: View {
    let data: [CategoryTimeSeries]

    var body: some View {
        Chart(data) { series in
            ForEach(series.values) { point in
                AreaMark(
                    x: .value("Date", point.date),
                    y: .value("Value", point.value)
                )
            }
            .foregroundStyle(by: .value("Category", series.category))
        }
        .chartForegroundStyleScale([
            "Sales": .blue,
            "Expenses": .red,
            "Profit": .green
        ])
    }
}
```

## Advanced Marks

### Combined Marks

```swift
struct CombinedChart: View {
    let data: [DataPoint]

    var body: some View {
        Chart(data) { point in
            // Line for trend
            LineMark(
                x: .value("Date", point.date),
                y: .value("Value", point.value)
            )
            .foregroundStyle(.blue)

            // Points for individual values
            PointMark(
                x: .value("Date", point.date),
                y: .value("Value", point.value)
            )
            .foregroundStyle(.blue)

            // Rule for average
            RuleMark(y: .value("Average", average))
                .foregroundStyle(.red.opacity(0.5))
                .lineStyle(StrokeStyle(dash: [5, 5]))
        }
    }

    var average: Double {
        data.map(\.value).reduce(0, +) / Double(data.count)
    }
}
```

### Range Marks

```swift
struct RangeChart: View {
    let data: [RangeData]

    var body: some View {
        Chart(data) { item in
            // Show range
            RectangleMark(
                x: .value("Category", item.category),
                yStart: .value("Min", item.min),
                yEnd: .value("Max", item.max)
            )
            .opacity(0.3)

            // Show median
            PointMark(
                x: .value("Category", item.category),
                y: .value("Median", item.median)
            )
        }
    }
}
```

## Interactivity

### Selection

```swift
struct InteractiveChart: View {
    let data: [DataPoint]
    @State private var selectedDate: Date?

    var body: some View {
        Chart(data) { point in
            LineMark(
                x: .value("Date", point.date),
                y: .value("Value", point.value)
            )

            if let selected = selectedDate,
               let point = data.first(where: { Calendar.current.isDate($0.date, inSameDayAs: selected) }) {
                RuleMark(x: .value("Selected", point.date))
                    .foregroundStyle(.gray.opacity(0.3))

                PointMark(
                    x: .value("Date", point.date),
                    y: .value("Value", point.value)
                )
                .foregroundStyle(.red)
                .symbolSize(100)
            }
        }
        .chartXSelection(value: $selectedDate)
        .chartOverlay { proxy in
            GeometryReader { geometry in
                if let selected = selectedDate,
                   let point = data.first(where: { Calendar.current.isDate($0.date, inSameDayAs: selected) }),
                   let position = proxy.position(forX: point.date) {
                    VStack {
                        Text(point.date, format: .dateTime.month().day())
                        Text(point.value, format: .number)
                            .bold()
                    }
                    .padding(8)
                    .background(.ultraThinMaterial)
                    .cornerRadius(8)
                    .position(x: position, y: 20)
                }
            }
        }
    }
}
```

### Scrolling Charts

```swift
struct ScrollableChart: View {
    let data: [DataPoint]
    @State private var scrollPosition: Date = .now

    var body: some View {
        Chart(data) { point in
            LineMark(
                x: .value("Date", point.date),
                y: .value("Value", point.value)
            )
        }
        .chartScrollableAxes(.horizontal)
        .chartXVisibleDomain(length: 3600 * 24 * 30) // 30 days
        .chartScrollPosition(x: $scrollPosition)
    }
}
```

## Styling

### Custom Colors

```swift
Chart(data) { point in
    BarMark(
        x: .value("Category", point.category),
        y: .value("Value", point.value)
    )
    .foregroundStyle(by: .value("Category", point.category))
}
.chartForegroundStyleScale([
    "Category A": Color.blue,
    "Category B": Color.green,
    "Category C": Color.orange
])
```

### Axis Customization

```swift
Chart(data) { point in
    LineMark(
        x: .value("Date", point.date),
        y: .value("Value", point.value)
    )
}
.chartXAxis {
    AxisMarks(preset: .aligned) { value in
        AxisGridLine()
        AxisTick()
        AxisValueLabel(format: .dateTime.month())
    }
}
.chartYAxis {
    AxisMarks(position: .leading) { value in
        AxisGridLine()
        AxisValueLabel {
            if let intValue = value.as(Int.self) {
                Text("$\(intValue)")
            }
        }
    }
}
```

### Plot Area Styling

```swift
Chart(data) { point in
    LineMark(
        x: .value("X", point.x),
        y: .value("Y", point.y)
    )
}
.chartPlotStyle { plotArea in
    plotArea
        .background(.gray.opacity(0.1))
        .border(.gray, width: 1)
}
```

## Performance (Large Datasets)

### Vectorized Plots (WWDC24)

```swift
// For datasets > 1000 points
struct LargeDatasetChart: View {
    let points: [Point]  // Thousands of points

    var body: some View {
        Chart {
            PointPlot(points, x: \.x, y: \.y)
                .foregroundStyle(.blue)
        }
    }
}
```

### Data Aggregation

```swift
struct AggregatedChart: View {
    let rawData: [DataPoint]

    var aggregatedData: [DataPoint] {
        // Aggregate to reasonable number of points
        Dictionary(grouping: rawData) { point in
            Calendar.current.startOfDay(for: point.date)
        }
        .map { date, points in
            DataPoint(
                date: date,
                value: points.map(\.value).reduce(0, +) / Double(points.count)
            )
        }
        .sorted(by: { $0.date < $1.date })
    }

    var body: some View {
        Chart(aggregatedData) { point in
            LineMark(
                x: .value("Date", point.date),
                y: .value("Value", point.value)
            )
        }
    }
}
```

## Chart3D (macOS 26+ / iOS 20+)

```swift
import Charts

struct Scatter3DView: View {
    let points: [Point3D]

    var body: some View {
        Chart3D(points) { point in
            PointMark3D(
                x: .value("X", point.x),
                y: .value("Y", point.y),
                z: .value("Z", point.z)
            )
            .foregroundStyle(by: .value("Cluster", point.cluster))
        }
        .chart3DStyle(.interactive) // Allows rotation
    }
}
```

## Common Patterns

### Empty State

```swift
struct ChartWithEmptyState: View {
    let data: [DataPoint]

    var body: some View {
        if data.isEmpty {
            ContentUnavailableView(
                "No Data",
                systemImage: "chart.bar.xaxis",
                description: Text("Add some data to see the chart")
            )
        } else {
            Chart(data) { point in
                LineMark(
                    x: .value("Date", point.date),
                    y: .value("Value", point.value)
                )
            }
        }
    }
}
```

### Loading State

```swift
struct ChartWithLoading: View {
    let data: [DataPoint]?
    let isLoading: Bool

    var body: some View {
        ZStack {
            if let data {
                Chart(data) { point in
                    LineMark(
                        x: .value("Date", point.date),
                        y: .value("Value", point.value)
                    )
                }
            }

            if isLoading {
                ProgressView()
            }
        }
    }
}
```

## Related Skills

- duckdb-swift: Data source for charts
- swiftui-data-flow: Reactive chart updates
- grape-graphs: Force-directed graph visualization

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…