Filled points in pointranges

Author

Andrew Heiss

Published

December 9, 2025

library(tidyverse)
library(parameters)
library(ggdist)

This doesn’t work—the color aesthetic controls both the point and the line:

# :(
lm(body_mass ~ 0 + species, data = penguins) |>
  model_parameters() |>
  ggplot(aes(x = Coefficient, y = Parameter, color = Parameter)) +
  geom_pointrange(
    aes(xmin = CI_low, xmax = CI_high, fill = Parameter),
    shape = 21,
    color = "white"
  ) +
  guides(color = "none", fill = "none")

This does work, and geom_linerange() uses xmin and xmax, which is more logical than geom_segment()s x and xend:

# :)
lm(body_mass ~ 0 + species, data = penguins) |>
  model_parameters() |>
  ggplot(aes(x = Coefficient, y = Parameter)) +
  geom_linerange(aes(xmin = CI_low, xmax = CI_high, color = Parameter)) +
  geom_point(aes(fill = Parameter), size = 3, shape = 21, color = "white") +
  guides(color = "none", fill = "none")

Or do it with one geom {ggdist}, which gives control over the aesthetics for the point and interval:

# :)
lm(body_mass ~ 0 + species, data = penguins) |>
  model_parameters() |>
  ggplot(aes(x = Coefficient, y = Parameter)) +
  geom_pointinterval(
    aes(
      xmin = CI_low,
      xmax = CI_high,
      interval_color = Parameter,
      point_fill = Parameter
    ),
    shape = 21,
    point_color = "white",
    point_size = 3
  ) +
  guides(interval_color = "none", point_fill = "none")