Search code examples
rggplot2ggmosaic

Add text labels to a ggplot2 mosaic plot


Using the following data:

Category <- c("Bankpass", "Bankpass", "Bankpass", "Moving", "Moving")
Subcategory <- c("Stolen", "Lost", "Login", "Address", "New contract")
Weight <- c(10,20,13,40,20)
Duration <- as.character(c(0.2,0.4,0.5,0.44,0.66))
Silence <- as.character(c(0.1,0.3,0.25,0.74,0.26))
df <- data.frame(Category, Subcategory, Weight, Duration, Silence)

Which I use to create the following mosaic plot:

library (ggplot2)
library (ggmosaic)

g <- ggplot(data = df) +
  geom_mosaic(aes(weight = Weight, x = product(Category), fill = Duration), 
              offset = 0, na.rm = TRUE) +  
  theme(axis.text.x = element_text(angle = -25, hjust = .1)) +
  theme(axis.title.x = element_blank()) +
  scale_fill_manual(values = c("#e8f5e9", "#c8e6c9", "#a5d6a7", "#81c784", "#66bb6a"))

enter image description here

This works, however I would like to include text labels on the elements on the graph ("Showing fe stolen, lost" etc.)

However, when I do:

g + geom_text(x = Category, y = Subcategory, label = Weight)

I get the following error:

Error in UseMethod("rescale") : no applicable method for 'rescale' applied to an object of class "character"

Any thoughts on what goes wrong here?


Solution

  • Here is my attempt. The x-axis is in a discrete variable (i.e., Category). So you cannot use it in geom_text(). You somehow need to create a numeric variable for the axis. Similarly, you need to find position in the y-axis for labels. In order to get numeric values for the two dimensions, I decided to access to the data frame staying behind your graphic. When you use the ggmosaic package, there is one data frame behind a graphic in this case. You can get it using ggplot_build(). You can calculate x and y values using the information in the data frame (e.g., xmin, and xmax). This is good news. But, we have bad news too. When you reach the data, you realize that there is no information about Subcategory that you need for labels.

    We can overcome this challenge joining the data frame above with the original data. When I joined the data, I calculated proportion for both the original data and the other data. The values are purposely converted to character. temp is the data set you need in order to add labels.

    library(dplyr)
    library(ggplot2)
    library(ggmosaic)
    
    # Add proportion for each and convert to character for join
    
    df <- group_by(df, Category) %>%
          mutate(prop = as.character(round(Weight / sum(Weight),3)))
    
    # Add proportion for each and convert to character.
    # Get x and y values for positions
    # Use prop for join
    
    temp <- ggplot_build(g)$data %>%
            as.data.frame %>%
            transmute(prop = as.character(round(ymax - ymin, 3)),
                      x.position = (xmax + xmin) / 2,
                      y.position = (ymax + ymin) / 2) %>%
            right_join(df)
    
    g + geom_text(x = temp$x.position, y = temp$y.position, label = temp$Subcategory) 
    

    enter image description here