UnsoughtNine
UnsoughtNine

Reputation: 63

geom_text() alignment challenges with grouped bar plot

I am currently using position = position_dodge2(preserve = "single") within a geom_bar() function to produce two grouped bar plots, with consistent bar widths regardless of the number of levels within each group. This is working fine. The right and left plots are structured the same way, are prepared as two independent plots, with two different datasets, and than assembled through ggarrange() as a final formatting step. One fix would solve the issue in both plots.

The issue I am having trouble with is when I introduce a geom_text() object. Default settings align all geom_text() objects over the central group axis. I have been able to use position_dodge2(width = x) to move individual labels off that axis, but I am forced to specify a width I am having trouble identifying.

This entire process is run through a for() loop dozens of times, so the width is not something I can simply manually play with until I am satisfied.

EDIT: Sample data and code now provided below.

Data:

# Sample1
Species,Class,count,Per
Acer negundo,Invasive,45,7.142857143
Acer platanoides,Invasive,10,1.587301587
Acer rubrum,Native,5,0.793650794
Fraxinus americana,Native,75,11.9047619
Juglans nigra,Native,5,0.793650794
Picea glauca,Native,5,0.793650794
Prunus avium,Exotic,25,3.968253968
Prunus serotina,Native,25,3.968253968
Quercus macrocarpa,Native,5,0.793650794
Rhamnus cathartica,Invasive,355,56.34920635
Rhus typhina,Native,5,0.793650794
Robinia pseudoacacia,Invasive,5,0.793650794
Salix fragilis,Exotic,10,1.587301587
Tilia americana,Native,40,6.349206349
Ulmus americana,Native,15,2.380952381

# Sample2
Species,Class,count,Per
Acer negundo,Invasive,3,7.5
Acer platanoides,Invasive,10,25
Fraxinus americana,Native,1,2.5
Fraxinus pennsylvanica,Native,1,2.5
Juglans nigra,Native,15,37.5
Prunus avium,Exotic,1,2.5
Prunus serotina,Native,2,5
Robinia pseudoacacia,Invasive,3,7.5
Tilia americana,Native,3,7.5
Ulmus americana,Native,1,2.5

Code:

plot1 <- ggplot(sample1, 
                aes(fill=Species, x = Class, y = Per)) +   
  geom_bar(position = position_dodge2(preserve = "single", width = 1.1), stat = "identity") +
  scale_x_discrete(position = "top")  +
  ylab("Proportion of Overstory Trees (%)") +
  xlab("") +
  scale_y_reverse(limits = c(max(mat_data_curr$Per), 0)) +
  coord_flip() +
  ggtitle("Overstory Stocking") +
  geom_text(aes(label = Species, hjust = 1.05), 
            position = position_dodge2(width = mat_dodge),
            fontface = "italic",
            size = 1) +
  scale_fill_manual(values = spp_cols) +
  theme(panel.background = element_rect(fill = 'white', color = 'white'),
        panel.grid.major = element_line(colour = "grey", 
                                        linetype = "dashed", 
                                        linewidth = 0.2),
        legend.position="none",
        axis.text=element_text(size = 6),
        axis.title = element_text(size = 8, face = "bold", margin(t = 10)),
        plot.title = element_text(size = 10, face = "bold"))

plot2 <- ggplot(sample2, aes(fill = Species, x = Class, y = Per)) +   
  geom_bar(position = position_dodge2(preserve = "single", width = 1.1), stat = "identity") +
  geom_text(aes(label = Species, hjust = -0.05), 
            position = position_dodge2(width = 0.9), 
            fontface = "italic", 
            size = 1) +
  scale_y_continuous(limits = c(0, max(mat_data_curr$Per))) +
  coord_flip() +
  ggtitle("Regeneration Stocking") +
  ylab("Proportion of Regeneration (%)") +
  xlab("") +
  scale_fill_manual(values = spp_cols) +
  theme(panel.background = element_rect(fill = 'white', color = 'white'),
        panel.grid.major = element_line(colour = "grey", 
                                        linetype = "dashed", 
                                        linewidth = 0.2),
        legend.position="none",
        axis.text=element_text(size = 6),
        axis.title = element_text(size = 8, face = "bold", margin = margin(t = 10)),
        plot.title = element_text(size = 10, face = "bold", hjust = 1))

plot_comb <- ggarrange(plot1,NA,plot2,nrow=1,ncol=3,widths=c(1,0.05,1)) + 
  annotate('text', x = 0.5, y = 0.5, label = 'Class and Species', size = 4, angle='90', fontface = "bold")

sample of the issue I'm running into.

Upvotes: 0

Views: 47

Answers (1)

I_O
I_O

Reputation: 6911

If you're not bound to the specific layout provided (e. g. vertical "Class and species" bar), you could prepare two separate plots (one with reversed scale, the other with inverted axis position), combine them with e. g. {patchwork} and take formatting from there.

Example:

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

d <- 
  data.frame(species = c('U. americana', 'T. americana',
                         'A. platanoides', 'A. negundo',
                         'S. fragilis', 'S. alba',
                         'U. americana', 'P. serotina',
                         'R. cathartica', 'A. negundo',
                         'S. fragilis', 'S. alba'),
           class = gl(3, 4, labels = c('native', 'invasive', 'exotic')),
           stocking = gl(2, 1, labels = c('overstory', 'regeneration')),
           prop = runif(12, 10, 100)
           )

## arrange and plot with {patchwork} `+` operator:
p_overstory + p_regeneration 

side-by-side plot with patchwork

Upvotes: 0

Related Questions