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.