Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Table below x axis in ggplot

Tags:

r

ggplot2

Hello everyone I was trying to add some text below the x axis in ggplot2 and I was able to do so using geom_textand with help of coord_cartesian but I couldn't make it reproducible as this need to run in a loop. I thought that adding the values I want with the row names (First, Second) in a table would fix it, does anybody have experience in that. below is the workaround I did. Thank you very much in advance.


## Data

Grade <- 1 : 20 

Case <-  rep(paste('case' , 1:5,sep = ''),4)

Number <- paste('n', 1:20 ,  sep = '')

Class <- c(rep('Class1',5) , rep('Class2',5) , rep('Class3',5) , rep('Class4',5))

se <- 0.2

df <- data.frame(Grade,Case ,Number, Class  , se)


## plot 

ggplot(df, aes(x= factor(Case , levels = c('case1','case2' , 'case3' , 'case4','case5')) , y=Grade ,
                        fill= Grade)) + 


  geom_bar(position="dodge", stat="identity",
           colour="black",
           size=.4) +    

  geom_errorbar(aes(ymin=Grade +se, ymax=Grade +se),
                size=.3,    
                width=.2,
                position=position_dodge(.9))+


  geom_linerange(aes(ymin = Grade , ymax = Grade +se),position=position_dodge(.9))+

  geom_text(aes(label=Number , y = Grade  + se + 1),data=df, position=position_dodge(0.9), size= 4) +


  ggtitle('Place a table below x axis')+

  facet_grid(~Class) + 

  xlab('') + 

  ylab('Case Num') + 

  theme_gray()+


  theme(plot.margin = unit(c(1,1,1,6), "lines"),
        axis.text.x = element_text(size = 15))  +

  scale_x_discrete(labels = paste(1:5 , '\n' ,  10:15,  sep = '')) + 

  geom_text(data = df[df$Class == 'Class1',],x = -1 , y = -3, 

            label= 'First\nSecond' , size = 4)+


  coord_cartesian(clip = "off" , xlim = c(1, 5) )

enter image description here

EDIT:

Sorry for the confusion,although the solution suggested by @stefan is pretty much convenient but the main purpose is to have something like this: enter image description here

considering that the proposed table will contain external characters, not taken from the data frame at all (if possible!).

like image 885
Sam_9090 Avatar asked Sep 06 '26 02:09

Sam_9090


1 Answers

As an alternative approach to tackle this problem I simply set up the table as a second ggplot which I glue together with the major ggplot using patchwork.

## Data

Grade <- 1 : 20 
Case <-  rep(paste('case' , 1:5,sep = ''),4)
Number <- paste('n', 1:20 ,  sep = '')
Class <- c(rep('Class1',5) , rep('Class2',5) , rep('Class3',5) , rep('Class4',5))

se <- 0.2

df <- data.frame(Grade,Case ,Number, Class  , se)

library(patchwork)    
library(ggplot2)
library(tidyr)
library(dplyr)

## plot 

p1 <- ggplot(df, aes(x= factor(Case , levels = c('case1','case2' , 'case3' , 'case4','case5')) , y=Grade ,
               fill= Grade)) + 
  geom_bar(position="dodge", stat="identity",
           colour="black",
           size=.4) +    
  geom_errorbar(aes(ymin=Grade +se, ymax=Grade +se),
                size=.3,    
                width=.2,
                position=position_dodge(.9))+
  geom_linerange(aes(ymin = Grade , ymax = Grade +se),position=position_dodge(.9))+
  geom_text(aes(label=Number , y = Grade  + se + 1),data=df, position=position_dodge(0.9), size= 4) +
  ggtitle('Place a table below x axis')+
  facet_grid(~Class) + 
  xlab(NULL) + 
  ylab('Case Num') + 
  theme_gray()+
  theme(axis.text.x = element_blank())

p2 <- df %>% 
  mutate(First = as.integer(stringr::str_extract(Case, "\\d")),
         Second = First + 9,
         Third = Second + 9) %>% 
  pivot_longer(c(First, Second, Third), names_to = "layer", values_to = "label") %>% 
  ggplot(aes(x = Case)) +
  geom_text(aes(y = factor(layer, c("Third", "Second", "First")), label = label)) +
  labs(y = "", x = NULL) +
  theme_minimal() +
  theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.x = element_blank(),
        panel.grid = element_blank(), strip.text = element_blank()) +
  facet_grid(~Class)

p1 / p2 +  plot_layout(heights = c(8, 1))

Created on 2020-05-23 by the reprex package (v0.3.0)

EDIT: Tweak to get a more table like output by adding a geom_tile and removing the spacing between facets as well as setting expansion of x-axis to zero:

p2 <- df %>%
  select(Case, Class) %>% 
  mutate(First = letters[1:nrow(.)],
         Second = LETTERS[1:nrow(.)],
         Third = as.character(1:nrow(.))) %>% 
  pivot_longer(c(First, Second, Third), names_to = "layer", values_to = "label") %>% 
  ggplot(aes(x = Case, y = factor(layer, c("Third", "Second", "First")))) +
  # Add Table Style
  geom_tile(fill = "blue", alpha = .4, color = "black") +
  geom_text(aes(label = label)) +
  # Remove expansion of axsis
  scale_x_discrete(expand = expansion(mult = c(0, 0))) +
  labs(y = "", x = NULL) +
  theme_minimal() +
  theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.x = element_blank(),
        panel.grid = element_blank(), strip.text = element_blank(), panel.spacing.x = unit(0, "mm")) +
  facet_grid(~Class)

p1 / p2 +  plot_layout(heights = c(8, 1))

Created on 2020-05-24 by the reprex package (v0.3.0)

like image 200
stefan Avatar answered Sep 07 '26 16:09

stefan