Skip to content

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: y

Normalized 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: normalize

Streamgraph (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: wiggle

Centered 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: silhouette

Stacked 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: sum

Stacked 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: y

Normalized 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: normalize

Expanded 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: expand

Reversed 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: true

Key Features

Stack Transform Options

stack:

  • 'y' - Stack vertically (default for most charts)
  • 'x' - Stack horizontally
  • true - 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 order
  • false - Normal order (default)

Use Cases

  1. Standard Stacked Areas - Show cumulative trends over time
  2. Normalized Stacks - Compare proportions across categories
  3. Streamgraphs - Beautiful flowing visualizations for presentations
  4. Centered Stacks - Symmetric comparisons
  5. 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: true for interactive exploration
  • Use fillOpacity to 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: 2

Performance 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

Released under the MIT License. Built by Boundary Lab.