Skip to content

Smooth Curves and Curve Interpolation

Observable Plot supports various curve interpolation methods for line and area marks. This guide demonstrates all available curve types and when to use each one.

Linear Curves (Default)

Straight Line Segments

The default curve connects points with straight lines:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 35},
      {"x": 2, "y": 25},
      {"x": 3, "y": 45},
      {"x": 4, "y": 30},
      {"x": 5, "y": 50}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: linear
      stroke: steelblue
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 4
      fill: steelblue

When to Use:

  • Default behavior (no curve specified)
  • Sharp transitions are meaningful
  • Minimal smoothing desired
  • Performance-critical applications

Step Curves

Step After

Creates horizontal then vertical segments (step-after):

data-glass
data:
  source: |
    [
      {"time": 0, "value": 10},
      {"time": 1, "value": 25},
      {"time": 2, "value": 20},
      {"time": 3, "value": 40},
      {"time": 4, "value": 35}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: time
      y: value
      curve: step-after
      stroke: darkorange
      strokeWidth: 2
  - type: dot
    configuration:
      x: time
      y: value
      r: 3
      fill: darkorange

Use Cases:

  • Digital signals
  • State changes
  • Inventory levels
  • Constant value between observations

Step Before

Creates vertical then horizontal segments (step-before):

data-glass
data:
  source: |
    [
      {"time": 0, "value": 10},
      {"time": 1, "value": 25},
      {"time": 2, "value": 20},
      {"time": 3, "value": 40},
      {"time": 4, "value": 35}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: time
      y: value
      curve: step-before
      stroke: purple
      strokeWidth: 2
  - type: dot
    configuration:
      x: time
      y: value
      r: 3
      fill: purple

Use Cases:

  • Leading indicators
  • Future projections
  • Forward-looking data

Step (Middle)

Creates steps centered on data points:

data-glass
data:
  source: |
    [
      {"time": 0, "value": 10},
      {"time": 1, "value": 25},
      {"time": 2, "value": 20},
      {"time": 3, "value": 40},
      {"time": 4, "value": 35}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: time
      y: value
      curve: step
      stroke: green
      strokeWidth: 2
  - type: dot
    configuration:
      x: time
      y: value
      r: 3
      fill: green

Use Cases:

  • Centered step functions
  • Histogram-like line charts
  • Categorical transitions

Smooth Curves

Basis Spline

Creates smooth B-spline curves:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 35},
      {"x": 2, "y": 25},
      {"x": 3, "y": 45},
      {"x": 4, "y": 30},
      {"x": 5, "y": 50}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: basis
      stroke: "#e74c3c"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 3
      fill: "#e74c3c"

Characteristics:

  • Very smooth curves
  • May not pass through control points
  • Good for general smoothing
  • Creates aesthetically pleasing curves

Cardinal Spline

Creates interpolated curves with adjustable tension:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 35},
      {"x": 2, "y": 25},
      {"x": 3, "y": 45},
      {"x": 4, "y": 30},
      {"x": 5, "y": 50}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: cardinal
      stroke: "#9b59b6"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 3
      fill: "#9b59b6"

Characteristics:

  • Passes through all data points
  • Smooth interpolation
  • Adjustable tension parameter
  • Good balance of smoothness and accuracy

Catmull-Rom Spline

Creates smooth curves passing through all points:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 35},
      {"x": 2, "y": 25},
      {"x": 3, "y": 45},
      {"x": 4, "y": 30},
      {"x": 5, "y": 50}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: catmull-rom
      stroke: "#3498db"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 3
      fill: "#3498db"

Characteristics:

  • Passes through all control points
  • Very smooth appearance
  • Popular for general smoothing
  • Good for presentation graphics

Natural Spline

Creates smooth curves with natural boundary conditions:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 35},
      {"x": 2, "y": 25},
      {"x": 3, "y": 45},
      {"x": 4, "y": 30},
      {"x": 5, "y": 50}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: natural
      stroke: "#16a085"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 3
      fill: "#16a085"

Characteristics:

  • Minimal curvature at endpoints
  • Natural-looking curves
  • Good for scientific data
  • Reduces overshoot at boundaries

Monotone Curves

Monotone X

Preserves monotonicity in x-direction:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 10},
      {"x": 1, "y": 15},
      {"x": 2, "y": 25},
      {"x": 3, "y": 28},
      {"x": 4, "y": 40},
      {"x": 5, "y": 45}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: monotone-x
      stroke: "#d35400"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 3
      fill: "#d35400"

Use Cases:

  • Monotonically increasing/decreasing data
  • Financial charts (prices always go up or down)
  • Prevents artificial peaks and valleys
  • Maintains data trends

Monotone Y

Preserves monotonicity in y-direction:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 10},
      {"x": 1, "y": 20},
      {"x": 2, "y": 15},
      {"x": 3, "y": 30},
      {"x": 4, "y": 25},
      {"x": 5, "y": 40}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: monotone-y
      stroke: "#c0392b"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 3
      fill: "#c0392b"

Use Cases:

  • Horizontal trends
  • Time series with guaranteed monotonicity
  • Growth/decay patterns

Bump Curves

Bump X

Creates smooth horizontal transitions:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 40},
      {"x": 2, "y": 30},
      {"x": 3, "y": 50},
      {"x": 4, "y": 35}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: bump-x
      stroke: "#8e44ad"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 4
      fill: "#8e44ad"

Use Cases:

  • Sankey-style diagrams
  • Flow charts
  • Ranking changes over time
  • Horizontal emphasis

Bump Y

Creates smooth vertical transitions:

data-glass
data:
  source: |
    [
      {"x": 0, "y": 20},
      {"x": 1, "y": 40},
      {"x": 2, "y": 30},
      {"x": 3, "y": 50},
      {"x": 4, "y": 35}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: bump-y
      stroke: "#2980b9"
      strokeWidth: 2
  - type: dot
    configuration:
      x: x
      y: y
      r: 4
      fill: "#2980b9"

Use Cases:

  • Vertical flow diagrams
  • Stream graphs
  • Vertical ranking changes

Area Curves

Smooth Area Chart

Apply curves to area marks for smooth fills:

data-glass
data:
  source: |
    [
      {"date": "2024-01", "value": 100},
      {"date": "2024-02", "value": 130},
      {"date": "2024-03", "value": 115},
      {"date": "2024-04", "value": 145},
      {"date": "2024-05", "value": 160},
      {"date": "2024-06", "value": 150}
    ]
width: 600
height: 350
marks:
  - type: area
    configuration:
      x: date
      y: value
      curve: catmull-rom
      fill: steelblue
      fillOpacity: 0.4
  - type: line
    configuration:
      x: date
      y: value
      curve: catmull-rom
      stroke: steelblue
      strokeWidth: 2

Area Curve Tips:

  • Match curve type between area and line marks
  • Smooth curves create more organic appearance
  • Good for highlighting trends

Curve Comparison

Side-by-Side Comparison

Compare multiple curve types:

data-glass
data:
  source: |
    [
      {"x": 0, "linear": 20, "basis": 20, "monotone": 20},
      {"x": 1, "linear": 35, "basis": 35, "monotone": 35},
      {"x": 2, "linear": 25, "basis": 25, "monotone": 25},
      {"x": 3, "linear": 45, "basis": 45, "monotone": 45},
      {"x": 4, "linear": 30, "basis": 30, "monotone": 30}
    ]
width: 600
height: 350
scales:
  color:
    legend: true
marks:
  - type: line
    configuration:
      x: x
      y: linear
      curve: linear
      stroke: red
      strokeWidth: 2
  - type: line
    configuration:
      x: x
      y: basis
      curve: basis
      stroke: blue
      strokeWidth: 2
  - type: line
    configuration:
      x: x
      y: monotone
      curve: monotone-x
      stroke: green
      strokeWidth: 2

Best Practices

Curve Selection Guide

Choose Linear When:

  • Data has sharp transitions
  • Precision is critical
  • Interpolation would be misleading
  • Performance is a concern

Choose Step When:

  • Data represents discrete states
  • Values are constant between observations
  • Digital signals or categorical changes

Choose Smooth (Basis/Catmull-Rom) When:

  • Aesthetic appearance matters
  • Underlying process is continuous
  • Minor overshooting is acceptable
  • Presentation over precision

Choose Monotone When:

  • Data must preserve increasing/decreasing trends
  • Financial or scientific accuracy needed
  • Artificial peaks/valleys would be misleading

Choose Bump When:

  • Creating flow diagrams
  • Sankey-style visualizations
  • Emphasizing smooth transitions
  • Ranking or hierarchy changes

Performance Considerations

Rendering Speed

Fastest to Slowest:

  1. Linear - Simple line segments
  2. Step - Horizontal/vertical segments only
  3. Monotone - Constrained cubic interpolation
  4. Basis - Cubic B-splines
  5. Cardinal/Catmull-Rom - Complex spline calculations
  6. Natural - Matrix operations for boundary conditions

Optimization Tips:

  • Use linear for >1000 points
  • Consider data sampling for smooth curves
  • Test performance with your data size

Common Patterns

1. Smooth Time Series

yaml
marks:
  - type: line
    configuration:
      x: date
      y: value
      curve: catmull-rom  # Smooth, passes through points

2. Step Function

yaml
marks:
  - type: line
    configuration:
      x: time
      y: state
      curve: step-after  # Constant until next value

3. Monotonic Growth

yaml
marks:
  - type: line
    configuration:
      x: date
      y: cumulative
      curve: monotone-x  # Always increasing

4. Natural Scientific Data

yaml
marks:
  - type: line
    configuration:
      x: measurement
      y: result
      curve: natural  # Minimal endpoint curvature

Curve Type Reference

Curve TypePasses Through PointsSmoothnessBest For
linear✅ YesNoneDefault, precise data
step✅ YesNoneDiscrete states
step-after✅ YesNoneState changes
step-before✅ YesNoneLeading indicators
basis❌ NoVery HighAesthetic smoothing
cardinal✅ YesHighSmooth interpolation
catmull-rom✅ YesHighGeneral smoothing
natural✅ YesHighScientific data
monotone-x✅ YesMediumMonotonic trends
monotone-y✅ YesMediumHorizontal trends
bump-x✅ YesMediumFlow diagrams
bump-y✅ YesMediumVertical flows

Troubleshooting

Problem: Curve overshoots data points

  • Solution: Use monotone-x or monotone-y instead
  • Alternative: Use natural for minimal endpoint overshoot

Problem: Curve doesn't pass through points

  • Solution: Avoid basis - use catmull-rom or cardinal
  • Check: Verify curve spelling is correct

Problem: Jagged appearance with smooth curve

  • Solution: Increase data density or simplify curve type
  • Check: Ensure sufficient data points (minimum 3-4)

Problem: Performance issues

  • Solution: Use linear or reduce data points
  • Consider: Sampling data before visualization

Advanced Techniques

Custom Tension

Some curves support tension parameters (via Observable Plot options):

yaml
# Catmull-Rom with custom tension
marks:
  - type: line
    configuration:
      x: x
      y: y
      curve: catmull-rom
      tension: 0.5  # 0 = cardinal, 1 = tight

Mixed Curves

Use different curves for different series:

yaml
marks:
  - type: line  # Smooth primary trend
    configuration:
      x: date
      y: actual
      curve: catmull-rom
  - type: line  # Sharp forecast
    configuration:
      x: date
      y: forecast
      curve: linear

  • Text Annotations - Label curve peaks and valleys
  • Stacked Areas - Apply curves to stacked area charts
  • Error Bars - Combine curves with confidence intervals

Last Updated: 2025-01-12Part of Phase 3: Advanced Mark Types

Released under the MIT License. Built by Boundary Lab.