rggplot2visualization

Different x-ticks per facet in ggplot2


I'm trying to visualize self-paced reading data across different experimental conditions and participant groups. Each condition and group involves reading distinct sentences, so I want the x-axis labels in each facet to show the corresponding words from the sentences they read, rather than a generic variable like Position. Note, I don't want to just use some subset of the data from the dataframe for the x-ticks because I'd like the labels to illustrate some things not present in the actual data, so I want to manually specify these labels independent of the dataset.

Here’s a minimal working example (MWE) of my data and current plot setup. In this example:

library(ggplot2) library(dplyr)

# Simulated dataset
reading_data_clean <- tibble::tibble(
  Position = rep(-5:3, times = 6),
  Read_time = rnorm(54, mean = 500, sd = 50),
  Subcondition = rep(c("ANE", "AR", "ENE", "ER", "agreement", "non-agreement"), each = 9),
  Language = rep(c("Danish", "German"), each = 27),
  Condition = rep(c("a-verb", "definite", "num.agreement"), each = 9, times = 2),
  Facet = rep(c("Danish-a-verb", "Danish-definite", "Danish-num.agreement", 
                "German-a-verb", "German-definite", "German-num.agreement"), each = 9)
)

# Custom x-tick labels for each facet
custom_labels <- list(
  "Danish-a-verb" = c("hunden", "bjeffer", "hele", "natten", "fordi", "katten", "løb", "på", "..."),
  "Danish-definite" = c("stenen", "lå", "ved", "floden", "og", "var", "markant", "stor", "..."),
  "Danish-num.agreement" = c("de", "fleste", "bøger", "er", "ikke", "tilgængelige", "for", "alle", "..."),
  "German-a-verb" = c("der", "Hund", "bellt", "die", "ganze", "Nacht", "weil", "die", "Katze"),
  "German-definite" = c("der", "Stein", "lag", "am", "Fluss", "und", "war", "sehr", "groß"),
  "German-num.agreement" = c("die", "meisten", "Bücher", "sind", "nicht", "für", "alle", "verfügbar", "...")
)

# Simplified plot
plot <- ggplot(reading_data_clean, 
               aes(x = Position, y = Read_time, color = Subcondition, group = Subcondition)) +
  geom_line(size = 1) +
  geom_point(size = 2) +
  # Use the dynamic Word column for x-axis labels
  
  facet_wrap(~ Facet, scales = "free_x") +  # Allow free x-axis labels for each facet
  labs(
    title = "Facet-Specific X-Ticks with Custom Labels",
    x = "Sentence Position",
    y = "Read Time (msec)",
    color = "Subcondition"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 10, angle = 45, hjust = 1),
    strip.text = element_text(size = 14, face = "bold"),
    legend.position = "bottom"
  )

# Print the plot
print(plot)

Solution

  • One option would be to use the ggh4x package which via ggh4x::facetted_pos_scales allows to individually specify the positional scales per facet:

    # Seed used
    set.seed(123)
    
    library(ggplot2)
    library(ggh4x)
    
    scale_x <- reading_data_clean |>
      split(~Facet) |>
      lapply(
        \(x) {
          scale_x_continuous(
            breaks = sort(x$Position),
            labels = custom_labels[[unique(x$Facet)]]
          )
        }
      )
    
    ggplot(
      reading_data_clean,
      aes(
        x = Position, y = Read_time, color = Subcondition,
        group = Subcondition
      )
    ) +
      geom_line(size = 1) +
      geom_point(size = 2) +
      # Use the dynamic Word column for x-axis labels
      facet_wrap(~Facet, scales = "free_x") + # Allow free x-axis labels for each facet
      ggh4x::facetted_pos_scales(
        x = scale_x
      ) +
      labs(
        title = "Facet-Specific X-Ticks with Custom Labels",
        x = "Sentence Position",
        y = "Read Time (msec)",
        color = "Subcondition"
      ) +
      theme_minimal() +
      theme(
        axis.text.x = element_text(size = 10, angle = 45, hjust = 1),
        # strip.text = element_text(size = 14, face = "bold"),
        legend.position = "bottom"
      )
    

    enter image description here