Skip to content

Instantly share code, notes, and snippets.

@arunavo4
Last active September 21, 2025 13:40
Show Gist options
  • Select an option

  • Save arunavo4/731c00ef19c5da0910c81f8da031571d to your computer and use it in GitHub Desktop.

Select an option

Save arunavo4/731c00ef19c5da0910c81f8da031571d to your computer and use it in GitHub Desktop.
Guide to Swift Charts
***
# The Complete Guide to Swift Charts
Swift Charts is a powerful and declarative framework for creating a wide variety of charts to visualize data and mathematical functions in your apps. This guide combines foundational knowledge from its introduction with advanced features like pie charts, interactivity, function plots, and high-performance vectorized plots.
## Table of Contents
1. [Introduction to Swift Charts](#1-introduction-to-swift-charts)
2. [Core Concepts: Marks and Composition](#2-core-concepts-marks-and-composition)
3. [Data Types in Swift Charts](#3-data-types-in-swift-charts)
4. [Plotting Data with Mark Properties](#4-plotting-data-with-mark-properties)
5. [Building Common Charts](#5-building-common-charts)
* [Bar Charts](#bar-charts)
* [Line Charts](#line-charts)
* [Area Charts](#area-charts)
* [Combining Marks](#combining-marks)
6. [New in iOS 18: Function and Vectorized Plots](#6-new-in-ios-18-function-and-vectorized-plots)
* [Function Plots](#function-plots)
* [Vectorized Plots for Performance](#vectorized-plots-for-performance)
* [When to Use Mark-based vs. Vectorized Plots](#when-to-use-mark-based-vs-vectorized-plots)
7. [Pie and Donut Charts](#7-pie-and-donut-charts)
* [Creating a Pie Chart with `SectorMark`](#creating-a-pie-chart-with-sectormark)
* [Customizing Pie Charts](#customizing-pie-charts)
* [Creating a Donut Chart](#creating-a-donut-chart)
8. [Chart Interactivity](#8-chart-interactivity)
* [Selection](#selection)
* [Scrolling](#scrolling)
9. [Customizing Chart Components](#9-customizing-chart-components)
* [Customizing Axes](#customizing-axes)
* [Customizing Legends](#customizing-legends)
* [Customizing the Plot Area](#customizing-the-plot-area)
10. [Designing Effective Charts](#10-designing-effective-charts)
---
## 1. Introduction to Swift Charts
Data visualization makes your app more informative and engaging. Swift Charts achieves this by offering:
* **Declarative Syntax**: You specify *what* you want in your chart with a small amount of code, and Swift Charts handles the rendering. It feels just like SwiftUI.
* **Rich Customization**: While the framework provides excellent defaults, it also offers a rich set of options to style your chart to match your app's unique design.
* **Accessibility First**: Charts are automatically accessible to VoiceOver users and support Audio Graphs, with options for further customization to ensure they are usable by everyone.
A simple chart can be created with just a few lines of code:
```swift
import SwiftUI
import Charts
// 1. Define your data structure
struct PancakeSales: Identifiable {
let name: String
let sales: Int
var id: String { name }
}
// 2. Create your data array
let salesData: [PancakeSales] = [
.init(name: "Cachapa", sales: 916),
.init(name: "Injera", sales: 850),
// ... more data
]
// 3. Create the Chart View
struct SimpleBarChart: View {
var body: some View {
Chart(salesData) { pancake in
BarMark(
x: .value("Pancake Style", pancake.name),
y: .value("Sales", pancake.sales)
)
}
}
}
```
---
## 2. Core Concepts: Marks and Composition
The fundamental building block of any chart is a **Mark**. A mark is a graphical element that represents a single piece of data (e.g., a bar, a point, a line segment). You create charts by composing one or more marks inside a `Chart` view.
```swift
Chart {
// One or more marks go here
BarMark(...)
LineMark(...)
}
```
Swift Charts provides several mark types: `BarMark`, `LineMark`, `PointMark`, `AreaMark`, `RuleMark`, `RectangleMark`, and `SectorMark`.
---
## 3. Data Types in Swift Charts
Swift Charts understands three main types of data:
1. **Quantitative**: Numerical values like `Int` or `Double`.
2. **Nominal**: Categorical data, often a `String` or an `enum`.
3. **Temporal**: Time-based values represented by `Date`.
---
## 4. Plotting Data with Mark Properties
You map your data to the visual properties of a mark using `.value(label, value)`. Common properties include:
* **`x` and `y`**: The position of the mark.
* **`foregroundStyle`**: The color or style of the mark.
* **`symbol`**: The shape of a point mark.
By mapping different data fields to these properties, you can encode multiple dimensions of information into your chart.
```swift
.foregroundStyle(by: .value("City", series.city)) // Colors each line by city and adds a legend
```
---
## 5. Building Common Charts
### Bar Charts
Bar charts are great for comparing quantities across different categories.
```swift
Chart(salesData) {
BarMark(
x: .value("Pancake", $0.name),
y: .value("Sales", $0.sales)
)
}
```
### Line Charts
Line charts are excellent for showing trends over a continuous domain, like time.
```swift
Chart(dailySales) {
LineMark(
x: .value("Day", $0.day, unit: .day),
y: .value("Sales", $0.sales)
)
}
```
### Area Charts
Area charts emphasize the volume or magnitude of change over time by filling the area below the line.
```swift
Chart(monthlySales) {
AreaMark(
x: .value("Month", $0.month, unit: .month),
yStart: .value("Min Sales", $0.minSales),
yEnd: .value("Max Sales", $0.maxSales)
)
}
```
### Combining Marks
Layer marks to create richer visualizations, such as adding points on top of a line.
```swift
Chart(dailySales) { sale in
LineMark(...)
PointMark(...)
}
```
---
## 6. New in iOS 18: Function and Vectorized Plots
Swift Charts now extends beyond plotting discrete data points to visualizing mathematical functions and rendering large datasets with high performance.
### Function Plots
You can now plot functions directly without pre-calculating data points. This is ideal for scientific, educational, and analytical apps.
**`LinePlot` and `AreaPlot`**
These new views take a closure that defines the function to be plotted.
**Example: Plotting a Normal Distribution Over a Histogram**
```swift
// A standard math function for a normal distribution curve
func normalDistribution(x: Double, mean: Double, standardDeviation: Double) -> Double { ... }
Chart {
// 1. The histogram of the actual data
ForEach(bins) { bin in
BarMark(
x: .value("Capacity", bin.range),
y: .value("Probability", bin.probability)
)
}
// 2. The function plot layered on top
LinePlot(x: "Capacity density", y: "Probability") { x in
// The closure calculates the y-value for any given x-value
normalDistribution(x: x, mean: mean, standardDeviation: sd)
}
.foregroundStyle(.gray)
}
```
**Handling Discontinuous or Undefined Functions**
If a function is undefined in parts of its domain (e.g., `y = 1/x` at `x=0`), return `Double.nan` from the closure. Swift Charts will automatically create a gap in the plot.
```swift
LinePlot { x in
guard x != 0 else { return .nan }
return 1 / x
}
```
**Parametric Functions**
For functions where `x` and `y` are both dependent on a third parameter (e.g., `t`), the `LinePlot` closure can return a tuple `(x, y)`.
```swift
// Plot a heart shape using a parametric function
LinePlot(t: "t", domain: -Double.pi...Double.pi) { t in
let x = sqrt(2) * pow(sin(t), 3)
let y = cos(t) * (2 - cos(t) - pow(cos(t), 2))
return (x, y)
}
```
### Vectorized Plots for Performance
For very large datasets (thousands or millions of points), iterating with `ForEach` can be inefficient. **Vectorized plots** process entire collections of data at once for significantly better performance.
This is achieved by passing the data collection directly to the plot initializer and using **key paths** to map properties.
**Example: Plotting a Scatter Plot of Thousands of Solar Panels**
```swift
// Data structure with stored properties for performance
struct DataPoint: Identifiable {
let id: Int
let capacity: Double
let panelAxisType: String
var x: Double // Projected longitude
var y: Double // Projected latitude
}
struct SolarMap: View {
@ObservedObject var model: Model
var body: some View {
Chart {
// No ForEach loop! The plot handles the entire collection.
PointPlot(
model.data,
x: .value("Longitude", \.x), // Key path for x
y: .value("Latitude", \.y) // Key path for y
)
.symbolSize(by: .value("Capacity", \.capacity))
.foregroundStyle(by: .value("Axis Type", \.panelAxisType))
}
}
}
```
**Performance Tips for Vectorized Plots:**
1. **Group Data by Style**: If your data is sorted by the property used for styling (e.g., `panelAxisType`), Swift Charts can render it more efficiently.
2. **Avoid Computed Properties**: Use stored properties for plotted values (`x`, `y`, `capacity`) instead of computed properties to prevent repeated calculations during rendering.
3. **Specify Scale Domains**: If you know the range of your data, specify it with `.chartXScale(domain:)` and `.chartYScale(domain:)`. This prevents Swift Charts from iterating over the entire dataset just to determine the bounds.
### When to Use Mark-based vs. Vectorized Plots
| Plot Type | Best For | Key Advantage |
| ---------------- | ---------------------------------------------------------------------- | ------------------ |
| **Vectorized Plot** | Large datasets (> hundreds of points) where all points are styled homogeneously. | **High Performance** |
| **Mark-based Plot** | Smaller datasets or when individual points require unique styling, conditional logic, or complex layering. | **High Flexibility** |
---
## 7. Pie and Donut Charts
Pie charts are excellent for visualizing part-to-whole relationships.
### Creating a Pie Chart with `SectorMark`
Use `SectorMark` and map your quantitative value to the **`angle`** property.
```swift
struct PieChartExample: View {
var body: some View {
Chart(salesData) { element in
SectorMark(
angle: .value("Sales", element.sales)
)
.foregroundStyle(by: .value("Name", element.name))
}
}
}
```
### Customizing Pie Charts
Use modifiers like `.cornerRadius(_:)` and `.angularInset(_:)` to add visual flair.
### Creating a Donut Chart
Create a donut chart by setting the **`innerRadius`**.
```swift
SectorMark(
angle: .value("Sales", element.sales),
innerRadius: .ratio(0.618)
)
```
---
## 8. Chart Interactivity
Swift Charts includes powerful APIs for selection and scrolling.
### Selection
Use modifiers like `.chartXSelection(value:)` or `.chartAngleSelection(value:)` to bind user interactions to a `@State` variable. Use the `chartOverlay` or `chartBackground` modifiers with a `ChartProxy` to display contextual information based on the selection.
```swift
@State private var selectedSales: PancakeSales?
Chart(...)
.chartAngleSelection(value: $selectedSales)
.chartBackground { proxy in
if let selectedSales {
Text("\(selectedSales.sales) sold")
.position(x: proxy.plotAreaCenter.x, y: proxy.plotAreaCenter.y)
}
}
```
### Scrolling
For large datasets, enable scrolling with these modifiers:
1. `.chartScrollableAxes(_:)`: Enable scrolling on an axis.
2. `.chartXVisibleDomain(length:)`: Set the initial visible data range.
3. `.chartScrollPosition(x:)`: Bind the scroll position to a `@State` variable.
4. `.chartScrollTargetBehavior(_:)`: Customize snapping and pagination behavior.
---
## 9. Customizing Chart Components
### Customizing Axes
Use the `.chartXAxis` and `.chartYAxis` modifiers to gain full control over grid lines, ticks, and labels.
```swift
.chartXAxis {
AxisMarks(values: .stride(by: .month)) { value in
AxisGridLine()
AxisTick()
AxisValueLabel(format: .dateTime.month(.narrow))
}
}
```
### Customizing Legends
Control the legend's visibility and position with `.chartLegend()`.
### Customizing the Plot Area
The **plot area** is the region inside the axes. Style it using `.chartPlotStyle`.
```swift
.chartPlotStyle { plotArea in
plotArea.background(.blue.opacity(0.1))
}
```
---
## 10. Designing Effective Charts
* **Describe Your Charts**: Always provide a title and summary.
* **Progressively Reveal Complexity**: Start simple and allow users to drill down into more interactive and detailed views.
* **Use a Consistent Design System**: Use visual differences (color, shape) to signal differences in data, and maintain consistency across your app.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment