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.