HAHS.
Back to Catalog

Lollipop Chart

chart

Also known as: lollipop plot, dot-and-stem chart, pin chart

CompareShow ranking CategoricalNumerical Point/Dot

Description

A lollipop chart replaces the filled rectangles of a bar chart with a thin line (the stem) capped by a dot (the head), creating a lighter, more elegant visual representation. The positional encoding is identical to a bar chart: the dot’s position along the value axis conveys the magnitude, and the stem connects it to the baseline, making the zero-reference explicit. The result is a chart that conveys the same information as a bar chart but with substantially less ink.

The lollipop chart occupies a design space between the bar chart and the Cleveland dot plot. It retains the bar chart’s explicit connection to the baseline (important when zero is a meaningful reference) while borrowing the dot plot’s minimalism. This makes it particularly effective when there are many categories: where bars would create a visually heavy block of color, lollipops produce a lighter, more scannable display that emphasizes the data points themselves.

Because the dot is the primary visual element, lollipop charts draw attention to the position of each value rather than the magnitude of the filled area. This can make value comparison marginally more difficult than with bars (where the eye compares lengths of filled regions) but significantly reduces visual clutter and improves the figure-ground separation, especially in charts with 15 or more categories.

Lollipop Chart — interactive example

When to Use

  • Comparing values across many categories (10-50+) where bars would feel visually heavy
  • Creating cleaner, more modern-looking alternatives to bar charts in dashboards and reports
  • When the zero baseline is a meaningful reference and you want the stem to make that connection explicit
  • Showing rankings where the dot position is more important than the magnitude of filled area
  • Reducing chart-junk and improving data-ink ratio in visualizations with many data points

When NOT to Use

  • When the audience strongly expects a bar chart and the lollipop form might cause confusion
  • For showing parts of a whole or stacked composition — use a stacked bar chart
  • When the data has very similar values and the dots cluster together, making comparison difficult
  • When bars provide a useful secondary encoding (e.g., colored fills showing sub-categories within each bar)

Anatomy

  • Dot (head): A circular mark at the data value, serving as the primary visual cue for comparison.
  • Stem (line): A thin line connecting the dot to the baseline, providing a visual anchor and emphasizing distance from zero.
  • Baseline: The zero line from which stems originate; typically shown as a rule line.
  • Category axis: The axis listing discrete categories (vertical for horizontal lollipops, horizontal for vertical).
  • Value axis: The quantitative axis with a numeric scale.
  • Color encoding: Dots and stems can be colored by category, group, or a conditional threshold (e.g., red for below target, green for above).

Variations

  • Horizontal lollipop: Stems extend left to right; preferred for many categories with long labels.
  • Vertical lollipop: Stems extend upward from a horizontal baseline; useful for time-ordered categories.
  • Grouped lollipop: Multiple dots per category at different positions, replacing grouped bar charts.
  • Dumbbell (connected dot) chart: Two dots per category connected by a line showing the range or change, without a baseline stem.
  • Colored threshold lollipop: Dots and stems change color based on a threshold value (e.g., above/below average), adding a conditional encoding.
  • Diverging lollipop: Stems extend in both directions from a center baseline to show positive and negative deviations.

Code Reference

// Observable Plot - horizontal lollipop chart
Plot.plot({
  marks: [
    Plot.ruleX(data, {
      x: "value",
      y: "category",
      stroke: "#6366f1",
      strokeWidth: 2
    }),
    Plot.dot(data, {
      x: "value",
      y: "category",
      fill: "#6366f1",
      r: 6,
      tip: true
    }),
    Plot.ruleX([0])
  ],
  y: { label: null },
  x: { label: "Value" },
  marginLeft: 120
})