Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

back-to-back barplot with independent axes R

Tags:

r

ggplot2

I am wanting to plot back-to-back barplot, however each side is on an independent axes. I can plot them back to back by taking the negative of one set, but that leaves them on the same access and because pvalues are smaller their bars are barely represented.

library(ggplot2)
df <-structure(list(Description = c("a", "b", "c", "d", "e", "f", 
    "g", "h", "a", "b", "c", "d", "e", "f", "g", "h"), test = c("size", 
    "size", "size", "size", "size", "size", "size", "size", "p", 
    "p", "p", "p", "p", "p", "p", "p"), value = c(0.1, 0.1, 0.125, 
    0.1, 0.075, 0.1, 0.075, 0.125, 0.000230705311441713, 0.000314488619269942, 
    0.00106639822095382, 0.00108290238851994, 0.00114723539549198, 
    0.00160204850890075, 0.0019276388745184, 0.00320371567547557)), .Names = c("Description", 
    "test", "value"), row.names = c(NA, -16L), class = "data.frame")

df$value[df$test == 'p'] <- -(df$value[df$test == 'p'])

ggplot(df, aes(x=Description, y= value, group=test, fill=test)) + geom_col() +coord_flip()

Ideally I would like each group on independent axes so that the bars meet at zero (in the middle of the plot region) but be on different scales for this example ylim would be something like ylim(0,0.13) and for pvalue c(0, 0.0035)

like image 741
George Avatar asked Oct 14 '25 07:10

George


2 Answers

You can do this by using facets, and tweaking to remove the spacing between facets:

ggplot(df, aes(x=Description, y= value, fill=test)) + 
    facet_wrap(~ test, scales = "free_x") + 
    geom_col() + 
    coord_flip() +
    scale_y_continuous(expand = c(0, 0)) +
    theme(panel.spacing.x = unit(0, "mm"))

It might create some issues with axis labels, and these would be a bit tricky to solve. In that case, it might be easier to keep some space between the facets, at the expense of not having the bars meet in the middle.

Output:

enter image description here

PS: you can also remove the negative axis labels with something like:

scale_y_continuous(
    expand = c(0, 0), 
    labels = function(x) signif(abs(x), 3)
)
like image 170
Marius Avatar answered Oct 19 '25 16:10

Marius


I have adapted this elegant solution to my needs. Kudos to Lingyun Zhang.

library(dplyr)
library(ggplot2)

set.seed(123)
ten_positive_rand_numbers <- abs(rnorm(10)) + 0.1
the_prob <- ten_positive_rand_numbers / sum(ten_positive_rand_numbers)

fk_data <- data.frame(job_type = sample(LETTERS[1:10], 1000, 
                                        replace = TRUE, prob = the_prob),
                      gender = sample(c("Male", "Female"), 1000, 
                                      replace = TRUE))

# prepare data for plotting
plotting_df <-
  fk_data %>% 
  group_by(job_type, gender) %>% 
  summarise(Freq = n()) %>% 
  # a trick!
  mutate(Freq = if_else(gender == "Male", -Freq, Freq))
## find the order
temp_df <-
  plotting_df %>% 
  filter(gender == "Female") %>% 
  arrange(Freq)
the_order <- temp_df$job_type

# plot
p <- 
  plotting_df %>% 
  ggplot(aes(x = job_type, y = Freq, group = gender, fill = gender)) +
  geom_bar(stat = "identity", width = 0.75) +
  coord_flip() +
  scale_x_discrete(limits = the_order) +
  # another trick!
  scale_y_continuous(breaks = seq(-150, 150, 50), 
                     labels = abs(seq(-150, 150, 50))) +
  labs(x = "Job type", y = "Count", title = "Back-to-back bar chart") +
  theme(legend.position = "bottom",
        legend.title = element_blank(),
        plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill =  "grey90")) +
  # reverse the order of items in legend
  # guides(fill = guide_legend(reverse = TRUE)) +
  # change the default colors of bars
  scale_fill_manual(values = c("red", "blue"),
                    name = "",
                    breaks = c("Male", "Female"),
                    labels = c("Male", "Female")) 
print(p)

It can be improved with other minor details, including geom_hline(yintercept = 0, colour = "black").

like image 39
MonkeyCousin Avatar answered Oct 19 '25 16:10

MonkeyCousin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!