Skip to content

Text Annotations and Labels

Text marks enable you to add labels, annotations, and callouts to your charts. This guide demonstrates various text positioning and styling techniques.

Basic Text Labels

Simple Point Labels

Label each data point with text at its position:

data-glass
data:
  source: |
    [
      {"x": 10, "y": 20, "label": "Start"},
      {"x": 30, "y": 50, "label": "Peak"},
      {"x": 50, "y": 35, "label": "Valley"},
      {"x": 70, "y": 60, "label": "End"}
    ]
width: 600
height: 400
marks:
  - type: dot
    configuration:
      x: x
      y: y
      r: 6
      fill: steelblue
  - type: text
    configuration:
      x: x
      y: y
      text: label
      dy: -10

Key Features:

  • text: label - Field containing the text to display
  • dy: -10 - Offset text 10 pixels above the point
  • Combines with dot marks for labeled scatter plots

Text Positioning

Using dx and dy Offsets

Fine-tune text position with pixel offsets:

data-glass
data:
  source: |
    [
      {"x": 1, "y": 10, "label": "Q1", "offset": 0},
      {"x": 2, "y": 25, "label": "Q2", "offset": 5},
      {"x": 3, "y": 18, "label": "Q3", "offset": -5},
      {"x": 4, "y": 32, "label": "Q4", "offset": 0}
    ]
width: 600
height: 300
marks:
  - type: line
    configuration:
      x: x
      y: y
      stroke: steelblue
      strokeWidth: 2
  - type: text
    configuration:
      x: x
      y: y
      text: label
      dx: 0
      dy: -12
      fontSize: 14
      fontWeight: bold

Use Cases:

  • Avoiding label overlap
  • Aligning labels with specific visual elements
  • Creating callouts that point to data

Text Anchor Points

Control horizontal alignment with textAnchor:

data-glass
data:
  source: |
    [
      {"x": 10, "value": 100, "label": "Start ←", "anchor": "end"},
      {"x": 50, "value": 150, "label": "Middle", "anchor": "middle"},
      {"x": 90, "value": 120, "label": "→ End", "anchor": "start"}
    ]
width: 600
height: 300
marks:
  - type: rule
    configuration:
      x: x
      y1: 0
      y2: value
      stroke: lightgray
  - type: text
    configuration:
      x: x
      y: value
      text: label
      textAnchor: anchor
      dy: -8
      fontSize: 12

Text Anchor Options:

  • start - Text starts at the anchor point (left-aligned)
  • middle - Text centered at anchor point (default)
  • end - Text ends at anchor point (right-aligned)

Rotated Text

Angled Labels

Rotate text to fit in tight spaces or follow trends:

data-glass
data:
  source: |
    [
      {"category": "Product A", "value": 45},
      {"category": "Product B", "value": 78},
      {"category": "Product C", "value": 32},
      {"category": "Product D", "value": 91},
      {"category": "Product E", "value": 56}
    ]
width: 600
height: 400
marks:
  - type: bar
    configuration:
      x: category
      y: value
      fill: steelblue
  - type: text
    configuration:
      x: category
      y: value
      text: value
      dy: -5
      rotate: -45
      fontSize: 11
      textAnchor: end

Rotation Tips:

  • Negative angles rotate counter-clockwise
  • Useful for long categorical labels
  • Combine with textAnchor for proper alignment

Font Styling

Custom Typography

Apply font styling for emphasis and hierarchy:

data-glass
data:
  source: |
    [
      {"x": 20, "y": 80, "text": "Title", "size": 18, "weight": "bold"},
      {"x": 20, "y": 60, "text": "Subtitle", "size": 14, "weight": "normal"},
      {"x": 20, "y": 40, "text": "Caption", "size": 10, "weight": "300"}
    ]
width: 600
height: 300
marks:
  - type: text
    configuration:
      x: x
      y: y
      text: text
      fontSize: size
      fontWeight: weight
      textAnchor: start

Font Properties:

  • fontSize - Number or string (e.g., 12, "14px")
  • fontWeight - "normal", "bold", "300", "600", etc.
  • fontFamily - Font name (e.g., "Arial", "monospace")

Colored Text

Color-Coded Labels

Use fill encoding for categorical colors:

data-glass
data:
  source: |
    [
      {"x": 10, "y": 50, "label": "Group A", "category": "A"},
      {"x": 30, "y": 70, "label": "Group B", "category": "B"},
      {"x": 50, "y": 40, "label": "Group C", "category": "C"},
      {"x": 70, "y": 85, "label": "Group D", "category": "D"}
    ]
width: 600
height: 400
scales:
  color:
    legend: true
marks:
  - type: dot
    configuration:
      x: x
      y: y
      fill: category
      r: 8
  - type: text
    configuration:
      x: x
      y: y
      text: label
      fill: category
      dy: 15
      fontSize: 12
      fontWeight: bold

Color Encoding:

  • fill: category - Map text color to categorical variable
  • Matches dot colors automatically
  • Creates consistent visual grouping

Data Annotations

Highlight Specific Values

Add contextual information to charts:

data-glass
data:
  source: |
    [
      {"month": "Jan", "sales": 120},
      {"month": "Feb", "sales": 145},
      {"month": "Mar", "sales": 189},
      {"month": "Apr", "sales": 156},
      {"month": "May", "sales": 198},
      {"month": "Jun", "sales": 221}
    ]
width: 600
height: 350
marks:
  - type: line
    configuration:
      x: month
      y: sales
      stroke: steelblue
      strokeWidth: 2
  - type: dot
    configuration:
      x: month
      y: sales
      r: 4
      fill: steelblue
  - type: text
    configuration:
      x: month
      y: sales
      text: sales
      dy: -12
      fontSize: 11

Annotation Patterns:

  • Show exact values above data points
  • Add context with descriptive text
  • Highlight outliers or important events

Callouts and Pointers

Annotated Events

Mark important events with styled callouts:

data-glass
data:
  source: |
    [
      {"date": "2024-01", "value": 100},
      {"date": "2024-02", "value": 120},
      {"date": "2024-03", "value": 150},
      {"date": "2024-04", "value": 145},
      {"date": "2024-05", "value": 180},
      {"date": "2024-06", "value": 165}
    ]
width: 600
height: 350
marks:
  - type: area
    configuration:
      x: date
      y: value
      fill: steelblue
      fillOpacity: 0.3
  - type: line
    configuration:
      x: date
      y: value
      stroke: steelblue
      strokeWidth: 2
  - type: text
    configuration:
      x: date
      y: value
      text: value
      dy: -8
      fontSize: 10
      fill: "#333"

Multi-Line Text

Stacked Labels

Create hierarchical labels with multiple text marks:

data-glass
data:
  source: |
    [
      {"x": 25, "y": 50, "title": "Product A", "subtitle": "45 units"},
      {"x": 50, "y": 75, "title": "Product B", "subtitle": "78 units"},
      {"x": 75, "y": 40, "title": "Product C", "subtitle": "32 units"}
    ]
width: 800
height: 400
marks:
  - type: dot
    configuration:
      x: x
      y: y
      r: 10
      fill: steelblue
  - type: text
    configuration:
      x: x
      y: y
      text: title
      dy: 20
      fontSize: 13
      fontWeight: bold
  - type: text
    configuration:
      x: x
      y: y
      text: subtitle
      dy: 35
      fontSize: 10
      fill: gray

Multi-Line Technique:

  • Create separate text marks for each line
  • Use different dy offsets to stack vertically
  • Vary font size and weight for hierarchy

Best Practices

Positioning Guidelines

  1. Avoid Overlap

    • Use dx and dy to offset labels from data points
    • Common offset: dy: -10 or dy: -12
  2. Choose Appropriate Anchors

    • Left-aligned text: textAnchor: "start"
    • Centered text: textAnchor: "middle" (default)
    • Right-aligned text: textAnchor: "end"
  3. Font Sizing

    • Data labels: 10-12px
    • Titles: 14-18px
    • Annotations: 11-13px
  4. Rotation

    • Use sparingly - only when necessary
    • Common angles: -45°, -90°, 45°
    • Combine with appropriate textAnchor

Performance Tips

  • Limit Label Count

    • Show labels only for important points
    • Filter data before creating text marks
    • Consider showing labels only on hover (using tip instead)
  • Readable Fonts

    • System fonts are fastest: fontFamily: "system-ui"
    • Sans-serif fonts for clarity
    • Avoid very small sizes (<9px)

Common Patterns

1. Label First and Last Points Only

yaml
# Filter to show only first and last values
marks:
  - type: text
    configuration:
      x: date
      y: value
      text: value
      # Filter logic in data preprocessing

2. Percentage Labels

yaml
marks:
  - type: text
    configuration:
      x: category
      y: percentage
      text: percentage  # Format as "45%" in data
      dy: -8

3. Dynamic Positioning

yaml
# Adjust dy based on positive/negative values
marks:
  - type: text
    configuration:
      x: date
      y: value
      text: label
      dy: -12  # Above for positive, below for negative

Troubleshooting

Problem: Text overlaps with data points

  • Solution: Increase dy offset (e.g., dy: -15)

Problem: Long labels get cut off

  • Solution: Adjust chart margins or rotate text

Problem: Text hard to read

  • Solution: Increase fontSize or add contrasting fill color

Problem: Labels overlap each other

  • Solution: Reduce number of labels or use variable dx/dy offsets

  • Vector Arrows - Directional indicators with arrows
  • Link Marks - Connect points with lines and labels
  • Smooth Curves - Combine text with curved lines

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

Released under the MIT License. Built by Boundary Lab.