Search code examples
rggplot2plot

Resize the panel and y axis text size equally in R using ggplot2


I have the following toy data frame and ggplot2 graph. I want the size of the panel and the size of the text in y axis to be equal, like splitting the view in half. In the end, the result will be rendered in pdf what is the reason that I want this kind of resizing and splitting if I can say freely.

library(dplyr, warn = FALSE)
library(ggplot2)
library(ggstats)
library(purrr)

likert_levels <- c(
  "Strongly disagree",
  "Disagree",
  "Neither agree nor disagree",
  "Agree",
  "Strongly agree"
)

df <-
  tibble(
    "there is an argument sort_prop_include_center that could be set up to TRUE in order to include half of the centered level when sorting data" = sample(likert_levels, 150, replace = TRUE),
    "Similarly, the argument totals_include_center allows you to include half of the centered level into the left and the right totals" = sample(likert_levels, 150, replace = TRUE, prob = 5:1),
    "Here is one possible option which uses reorder and an ifelse to reorder the variable mapped on y using the counts (aka the sum) of Strictly disagree " = sample(likert_levels, 150, replace = TRUE, prob = 1:5),
    "and disagree answers. Under the hood ggstats::gglikert reshape the data to long where the question id's are stored in a column named .question and the answers in a column named .answer:" = sample(likert_levels, 150, replace = TRUE, prob = 1:5),
    "They used sampling data and create a data frame called df. I am using the same as given in the link. (the df not the df_dk). Ok, if i run in R the following code :" = sample(c(likert_levels, NA), 150, replace = TRUE),
    "proportion of answers higher than the centered level. I want the plot to be sorted according to very left proportions that are the combination (sum) of the two lower levels. (i.e. Respectively the percentages on the very right in the sum of the two lower categories. )" = sample(likert_levels, 150, replace = TRUE, prob = c(1, 0, 1, 1, 0))
  ) %>%
  mutate(across(everything(), ~ factor(.x, levels = likert_levels)))

# function to save retyping common arguments
anno <- partial(annotate, "text", x = -1, angle = 90, size = 5, fontface = "bold")

gglikert(df) +
  aes(y = reorder(.question,
                  ifelse(
                    .answer %in% c("Strongly disagree", "Disagree"),
                    1, 0
                  ),
                  FUN = sum, decreasing = TRUE
  )) +
  theme(axis.text.y = element_text(size = 8)) + 
  geom_hline(yintercept = c(1.5, 5.5), linetype = "dashed", colour = "grey20") +
  anno(y = 1, label = "warning\nzone", color = "#A6611A") +
  anno(y = 3.5, label = "so-so", color = "black") +
  anno(y = 6, label = "no warning\nzone", color = "#018571") +
  labs(y = NULL)

enter image description here How can I succeed it in R using ggplot2?

Edit: if it is possible to remove the lines in the background theme .To be totally blank


Solution

  • This will require a bit of manual tweaking depending on your output size/device, but it gives you fine grain control over the final figure with the figure taking up the entire plot space.

    The gist is to manipulate the space taken up by the y-axis labels through the use of the y_label_wrap argument in gglikert()

    y_label_wrap number of characters per line for y axis labels, see scales::label_wrap()

    We then should tweak the legend because it was already getting clipped prior to our edits.

    As per your question edit, we can use panel(panel.grid = element_blank()) to remove all gridlines.

    As per your comment question, it sounds like you may be interested in the totals_hjust argument which I have now set at 0.5.

    totals_hjust horizontal adjustment of totals labels on the x axis

    library(dplyr, warn = FALSE)
    library(ggplot2)
    library(ggstats)
    library(purrr)
    
    likert_levels <- c(
      "Strongly disagree",
      "Disagree",
      "Neither agree nor disagree",
      "Agree",
      "Strongly agree"
    )
    
    df <-
      tibble(
        "there is an argument sort_prop_include_center that could be set up to TRUE in order to include half of the centered level when sorting data" = sample(likert_levels, 150, replace = TRUE),
        "Similarly, the argument totals_include_center allows you to include half of the centered level into the left and the right totals" = sample(likert_levels, 150, replace = TRUE, prob = 5:1),
        "Here is one possible option which uses reorder and an ifelse to reorder the variable mapped on y using the counts (aka the sum) of Strictly disagree " = sample(likert_levels, 150, replace = TRUE, prob = 1:5),
        "and disagree answers. Under the hood ggstats::gglikert reshape the data to long where the question id's are stored in a column named .question and the answers in a column named .answer:" = sample(likert_levels, 150, replace = TRUE, prob = 1:5),
        "They used sampling data and create a data frame called df. I am using the same as given in the link. (the df not the df_dk). Ok, if i run in R the following code :" = sample(c(likert_levels, NA), 150, replace = TRUE),
        "proportion of answers higher than the centered level. I want the plot to be sorted according to very left proportions that are the combination (sum) of the two lower levels. (i.e. Respectively the percentages on the very right in the sum of the two lower categories. )" = sample(
          likert_levels,
          150,
          replace = TRUE,
          prob = c(1, 0, 1, 1, 0)
        )
      ) %>%
      mutate(across(everything(), ~ factor(.x, levels = likert_levels)))
    
    # function to save retyping common arguments
    anno <-
      partial(
        annotate,
        "text",
        x = -1,
        angle = 90,
        size = 3,
        fontface = "bold"
      )
    
    gg <- gglikert(
      df, 
      labels_size = 2, 
      y_label_wrap = 68,
      totals_hjust = 0.5
    ) +
      aes(y = reorder(
        .question,
        ifelse(.answer %in% c("Strongly disagree", "Disagree"),
               1, 0),
        FUN = sum,
        decreasing = TRUE
      )) +
      theme(axis.text.y = element_text(size = 8)) +
      geom_hline(
        yintercept = c(1.5, 5.5),
        linetype = "dashed",
        colour = "grey20"
      ) +
      anno(y = 1,
           label = "warning\nzone",
           color = "#A6611A") +
      anno(y = 3.5,
           label = "so-so",
           color = "black") +
      anno(y = 6,
           label = "no warning\nzone",
           color = "#018571") +
      labs(y = NULL)
    
    gg +
      theme(
        # set to "inside" to enable use of `legend.position.inside`
        legend.position = "inside",
        # move legend to the left and down a smidge
        legend.position.inside = c(0, -0.1), 
        # maintain horizontal direction
        legend.direction = "horizontal",
        # remove gridlines
        panel.grid = element_blank(),
        # add some margin to prevent clipping
        plot.margin = margin(
          t = 1,
          r = 1,
          b = 25,
          l = 1
        )
      )
    

    Created on 2024-04-24 with reprex v2.1.0