AreaMark
Chart content that represents data using the area of one or more regions.
Declaration
@MainActor @preconcurrency struct AreaMarkOverview
Use AreaMark to represent data as filled regions on a chart. To create a simple area mark chart, plot a date or an ordered string property on the x-axis, and a number on the y-axis. For example, suppose you have data that represents the cost of a cheeseburger over time, stored in an array of Food structures:
let cheeseburgerCost: [Food] = [
.init(name: "Cheeseburger", price: 0.15, year: 1960),
.init(name: "Cheeseburger", price: 0.20, year: 1970),
// ...
.init(name: "Cheeseburger", price: 1.10, year: 2020)
]
struct Food: Identifiable {
let name: String
let price: Double
let date: Date
let id = UUID()
init(name: String, price: Double, year: Int) {
self.name = name
self.price = price
let calendar = Calendar.autoupdatingCurrent
self.date = calendar.date(from: DateComponents(year: year))!
}
}You can create labeled data in the form of PlottableValue instances for each of the x and y inputs to an area mark:
Chart(cheeseburgerCost) { cost in
AreaMark(
x: .value("Date", cost.date),
y: .value("Price", cost.price)
)
}The resulting chart automatically scales and labels the axes based on the data, and fills the area under the data points with a default color:
[Image]
If you want only the line without filling in the area below the line, use LineMark instead.
Add detail with a stacked area chart
To represent an additional dimension of information, you can create a stacked area chart. For example, suppose you have another data set that represents the same cost data from the previous example, but which is broken into the component costs for the burger, bun, and cheese:
let cheeseburgerCostByItem: [Food] = [
.init(name: "Burger", price: 0.07, year: 1960),
.init(name: "Cheese", price: 0.03, year: 1960),
.init(name: "Bun", price: 0.05, year: 1960),
.init(name: "Burger", price: 0.10, year: 1970),
.init(name: "Cheese", price: 0.04, year: 1970),
.init(name: "Bun", price: 0.06, year: 1970),
// ...
.init(name: "Burger", price: 0.60, year: 2020),
.init(name: "Cheese", price: 0.26, year: 2020),
.init(name: "Bun", price: 0.24, year: 2020)
]You can again create an area mark with the data, but in this case add the foregroundStyle(by:) modifier to create a stacked area chart that divides the information into distinct regions based on the data’s name property:
Chart(cheeseburgerCostByItem) { cost in
AreaMark(
x: .value("Date", cost.date),
y: .value("Price", cost.price)
)
.foregroundStyle(by: .value("Food Item", cost.name))
}The chart automatically assigns a different color to each region, and adds a legend that indicates what each color represents based on the names that you provide to the modifier:
[Image]
Stack the data in different ways
You can highlight different aspects of the data by stacking it in different ways. For example, the previous chart shows the absolute contributions of each ingredient to the cheeseburger’s total cost. To see the relative contributions instead, you can create a normalized chart by setting the area mark’s stacking parameter to normalized:
Chart(cheeseburgerCostByItem) { cost in
AreaMark(
x: .value("Date", cost.date),
y: .value("Price", cost.price),
stacking: .normalized
)
.foregroundStyle(by: .value("Food Item", cost.name))
}[Image]
Alternatively, you can use center stacking to create a streamgraph, which shifts the area chart’s baseline to the center of the chart’s plotting area:
Chart(cheeseburgerCostByItem) { cost in
AreaMark(
x: .value("Date", cost.date),
y: .value("Price", cost.price),
stacking: .center
)
.foregroundStyle(by: .value("Food Item", cost.name))
}[Image]
Create a range area chart
You can also use area marks to create a range area chart, where you provide an interval to fill in for each data point. To do this, you provide either a date or ordered string category for the x-axis and a range of values for the y-axis, or vice versa. For example, suppose you record the minimum and maximum temperatures every day in a Weather structure:
struct Weather: Identifiable {
let date: Date
let maximumTemperature: Double
let minimumTemperature: Double
let id: Int
}If you load a collection of these structures into a data array, you can use the date on the x-axis, and each day’s minimum and maximum temperature as the start and end points for the y-axis:
Chart(data) { day in
AreaMark(
x: .value("Date", day.date),
yStart: .value("Minimum Temperature", day.minimumTemperature),
yEnd: .value("Maximum Temperature", day.maximumTemperature)
)
}This creates a filled region that’s shaped by the start and end points on each date:
[Image]