Stacked Area Charts and Transforms
This example demonstrates stacking transforms for area and bar charts, including normalized stacks and streamgraphs.
Basic Stacked Area
Standard stacked area chart showing cumulative values over time.
View Source
data:
source: [
{"year": "2020", "category": "Product A", "revenue": 100},
{"year": "2020", "category": "Product B", "revenue": 150},
{"year": "2020", "category": "Product C", "revenue": 80},
{"year": "2021", "category": "Product A", "revenue": 120},
{"year": "2021", "category": "Product B", "revenue": 180},
{"year": "2021", "category": "Product C", "revenue": 90},
{"year": "2022", "category": "Product A", "revenue": 140},
{"year": "2022", "category": "Product B", "revenue": 200},
{"year": "2022", "category": "Product C", "revenue": 100}
]
engine: plot
title: Revenue by Product (Stacked)
width: 600
height: 400
marks:
- type: area
configuration:
x: year
y: revenue
fill: category
stack: yNormalized Stacked Area (100%)
Shows proportions that sum to 100% at each point.
View Source
data:
source: [
{"year": "2020", "category": "Mobile", "users": 120},
{"year": "2020", "category": "Desktop", "users": 80},
{"year": "2020", "category": "Tablet", "users": 30},
{"year": "2021", "category": "Mobile", "users": 180},
{"year": "2021", "category": "Desktop", "users": 70},
{"year": "2021", "category": "Tablet", "users": 25},
{"year": "2022", "category": "Mobile", "users": 240},
{"year": "2022", "category": "Desktop", "users": 60},
{"year": "2022", "category": "Tablet", "users": 20}
]
engine: plot
title: User Distribution by Device Type (Normalized)
width: 600
height: 400
marks:
- type: area
configuration:
x: year
y: users
fill: category
stack: y
offset: normalizeStreamgraph (Wiggle Offset)
Flowing organic shape with centered baseline.
View Source
data:
source: [
{"month": "Jan", "genre": "Rock", "streams": 450},
{"month": "Jan", "genre": "Pop", "streams": 380},
{"month": "Jan", "genre": "Jazz", "streams": 120},
{"month": "Jan", "genre": "Classical", "streams": 90},
{"month": "Feb", "genre": "Rock", "streams": 420},
{"month": "Feb", "genre": "Pop", "streams": 410},
{"month": "Feb", "genre": "Jazz", "streams": 110},
{"month": "Feb", "genre": "Classical", "streams": 85},
{"month": "Mar", "genre": "Rock", "streams": 480},
{"month": "Mar", "genre": "Pop", "streams": 450},
{"month": "Mar", "genre": "Jazz", "streams": 130},
{"month": "Mar", "genre": "Classical", "streams": 95},
{"month": "Apr", "genre": "Rock", "streams": 510},
{"month": "Apr", "genre": "Pop", "streams": 490},
{"month": "Apr", "genre": "Jazz", "streams": 140},
{"month": "Apr", "genre": "Classical", "streams": 100}
]
engine: plot
title: Music Streaming by Genre (Streamgraph)
width: 600
height: 400
marks:
- type: area
configuration:
x: month
y: streams
fill: genre
stack: y
offset: wiggleCentered Stacked Area (Silhouette)
Symmetric stacking centered around zero.
View Source
data:
source: [
{"quarter": "Q1", "region": "North", "sales": 250},
{"quarter": "Q1", "region": "South", "sales": 180},
{"quarter": "Q1", "region": "East", "sales": 220},
{"quarter": "Q1", "region": "West", "sales": 200},
{"quarter": "Q2", "region": "North", "sales": 280},
{"quarter": "Q2", "region": "South", "sales": 200},
{"quarter": "Q2", "region": "East", "sales": 240},
{"quarter": "Q2", "region": "West", "sales": 220},
{"quarter": "Q3", "region": "North", "sales": 300},
{"quarter": "Q3", "region": "South", "sales": 210},
{"quarter": "Q3", "region": "East", "sales": 260},
{"quarter": "Q3", "region": "West", "sales": 230}
]
engine: plot
title: Regional Sales (Centered)
width: 600
height: 400
marks:
- type: area
configuration:
x: quarter
y: sales
fill: region
stack: y
offset: silhouetteStacked Area with Custom Ordering
Stack order by sum (largest on bottom).
View Source
data:
source: [
{"day": "Mon", "task": "Email", "hours": 2},
{"day": "Mon", "task": "Meetings", "hours": 3},
{"day": "Mon", "task": "Coding", "hours": 4},
{"day": "Tue", "task": "Email", "hours": 1.5},
{"day": "Tue", "task": "Meetings", "hours": 4},
{"day": "Tue", "task": "Coding", "hours": 3.5},
{"day": "Wed", "task": "Email", "hours": 2.5},
{"day": "Wed", "task": "Meetings", "hours": 2},
{"day": "Wed", "task": "Coding", "hours": 5},
{"day": "Thu", "task": "Email", "hours": 2},
{"day": "Thu", "task": "Meetings", "hours": 3.5},
{"day": "Thu", "task": "Coding", "hours": 4},
{"day": "Fri", "task": "Email", "hours": 1},
{"day": "Fri", "task": "Meetings", "hours": 2.5},
{"day": "Fri", "task": "Coding", "hours": 3.5}
]
engine: plot
title: Time Allocation by Task (Ordered by Sum)
width: 600
height: 400
marks:
- type: area
configuration:
x: day
y: hours
fill: task
stack: y
order: sumStacked Bars
Vertical stacked bar chart.
View Source
data:
source: [
{"country": "USA", "energy": "Coal", "production": 450},
{"country": "USA", "energy": "Gas", "production": 380},
{"country": "USA", "energy": "Renewables", "production": 320},
{"country": "China", "energy": "Coal", "production": 820},
{"country": "China", "energy": "Gas", "production": 180},
{"country": "China", "energy": "Renewables", "production": 410},
{"country": "India", "energy": "Coal", "production": 580},
{"country": "India", "energy": "Gas", "production": 120},
{"country": "India", "energy": "Renewables", "production": 180}
]
engine: plot
title: Energy Production by Type and Country
width: 600
height: 400
marks:
- type: bar
configuration:
x: country
y: production
fill: energy
stack: yNormalized Stacked Bars (100%)
Shows proportions in bar format.
View Source
data:
source: [
{"browser": "Chrome", "platform": "Windows", "users": 520},
{"browser": "Chrome", "platform": "macOS", "users": 280},
{"browser": "Chrome", "platform": "Linux", "users": 45},
{"browser": "Firefox", "platform": "Windows", "users": 180},
{"browser": "Firefox", "platform": "macOS", "users": 120},
{"browser": "Firefox", "platform": "Linux", "users": 35},
{"browser": "Safari", "platform": "Windows", "users": 10},
{"browser": "Safari", "platform": "macOS", "users": 350},
{"browser": "Safari", "platform": "Linux", "users": 2}
]
engine: plot
title: Browser Users by Platform (Normalized)
width: 600
height: 400
marks:
- type: bar
configuration:
x: browser
y: users
fill: platform
stack: y
offset: normalizeExpanded Stacked Area
Stacked area with expand offset.
View Source
data:
source: [
{"week": "W1", "status": "Completed", "count": 45},
{"week": "W1", "status": "In Progress", "count": 23},
{"week": "W1", "status": "Pending", "count": 12},
{"week": "W2", "status": "Completed", "count": 52},
{"week": "W2", "status": "In Progress", "count": 28},
{"week": "W2", "status": "Pending", "count": 15},
{"week": "W3", "status": "Completed", "count": 58},
{"week": "W3", "status": "In Progress", "count": 25},
{"week": "W3", "status": "Pending", "count": 10},
{"week": "W4", "status": "Completed", "count": 65},
{"week": "W4", "status": "In Progress", "count": 22},
{"week": "W4", "status": "Pending", "count": 8}
]
engine: plot
title: Task Status Over Time (Expanded)
width: 600
height: 400
marks:
- type: area
configuration:
x: week
y: count
fill: status
stack: y
offset: expandReversed Stack Order
Stack with reversed order.
View Source
data:
source: [
{"period": "Morning", "activity": "Sleep", "minutes": 0},
{"period": "Morning", "activity": "Work", "minutes": 180},
{"period": "Morning", "activity": "Exercise", "minutes": 30},
{"period": "Afternoon", "activity": "Sleep", "minutes": 0},
{"period": "Afternoon", "activity": "Work", "minutes": 240},
{"period": "Afternoon", "activity": "Exercise", "minutes": 0},
{"period": "Evening", "activity": "Sleep", "minutes": 0},
{"period": "Evening", "activity": "Work", "minutes": 60},
{"period": "Evening", "activity": "Exercise", "minutes": 45},
{"period": "Night", "activity": "Sleep", "minutes": 420},
{"period": "Night", "activity": "Work", "minutes": 0},
{"period": "Night", "activity": "Exercise", "minutes": 0}
]
engine: plot
title: Daily Activities (Reversed Stack)
width: 600
height: 400
marks:
- type: area
configuration:
x: period
y: minutes
fill: activity
stack: y
reverse: trueKey Features
Stack Transform Options
stack:
'y'- Stack vertically (default for most charts)'x'- Stack horizontallytrue- Auto-detect stack direction
offset:
'normalize'- Normalize to 100% at each point'expand'- Expand to fill available space'center'- Center around baseline'wiggle'- Minimize wiggle (streamgraphs)'silhouette'- Symmetric around center
order:
'value'- Order by value'sum'- Order by sum (largest totals on bottom)'appearance'- Order by first appearance'inside-out'- Inside-out ordering
reverse:
true- Reverse the stack orderfalse- Normal order (default)
Use Cases
- Standard Stacked Areas - Show cumulative trends over time
- Normalized Stacks - Compare proportions across categories
- Streamgraphs - Beautiful flowing visualizations for presentations
- Centered Stacks - Symmetric comparisons
- Stacked Bars - Categorical comparisons with parts-to-whole
Tips
- Use
offset: 'normalize'when proportions matter more than absolute values - Use
offset: 'wiggle'for aesthetic streamgraphs in presentations - Use
order: 'sum'to put largest categories on bottom for stability - Combine with
tip: truefor interactive exploration - Use
fillOpacityto distinguish overlapping series - Choose colors carefully - use color scales for better distinction
Combining with Other Marks
You can overlay lines on stacked areas to show totals:
yaml
marks:
- type: area
configuration:
x: date
y: value
fill: category
stack: y
- type: line
configuration:
x: date
y: total
stroke: black
strokeWidth: 2Performance Notes
- Stacking is handled efficiently by Observable Plot
- Works well with datasets up to 10,000 points
- Multiple series (5-10 categories) perform well
- Consider aggregating data for very large datasets