在 R 中创建带有两个 Y 轴的分组条形图

Creating a grouped barplot with two Y axes in R

我有以下数据框,其中包含 8 周时间跨度的视觉/每小时目击次数 (SPH) 和声学/每小时点击次数 (CPH) 数据集。我想要一个分组条形图,将一周内的两个值分组在一起。所以例如第 1 周为 2.676 sightings/h,第 1 周为 75.35 clicks/h。由于两个变量的单位不同,我还需要两个 y 轴,一个用于左侧的 sightings/h,另一个用于clicks/h右边。

data.frame(Week = c(1, 2, 3, 4, 5, 6, 7, 8), SPH = c(2.676, 2.660, 4.175, 2.134, 
    3.742, 1.395, 4.739, 2.756), CPH = c(75.35, 29.58, 20.51, 80.43, 97.94, 85.39, 168.61, 142.19))

我试图创建一个矩阵来绘制数据,但我不知道如何正确地告诉 R 前两个变量属于第 1 周,后两个变量属于第 2 周等。

希望大家能帮帮我。

提前致以最诚挚的问候和感谢。 :)

这个怎么样:

dat <- data.frame(Week = c(1, 2, 3, 4, 5, 6, 7, 8), 
                  SPH = c(2.676, 2.660, 4.175, 2.134, 3.742, 1.395, 4.739, 2.756), 
                  CPH = c(75.35, 29.58, 20.51, 80.43, 97.94, 85.39, 168.61, 142.19))

library(tidyr) 
library(dplyr)

## Find minimum and maximum values for each variable
tmp <- dat %>% 
  summarise(across(c("SPH", "CPH"), ~list(min = min(.x), max=max(.x)))) %>% 
  unnest(everything())

## make mapping from CPH to SPH 
m <- lm(SPH ~ CPH, data=tmp)
## make mapping from SPH to CPH
m_inv <- lm(CPH ~ SPH, data=tmp)


## transform CPH so it's on the same scale as SPH. 
## to do this, you need to use the coefficients from model m above
dat <- dat %>% 
  mutate(CPH = coef(m)[1] + coef(m)[2]*CPH) %>%
  ## pivot the data so all plotting values are in a single column
  pivot_longer(c("SPH", "CPH"), 
               names_to="var", values_to="vals") %>% 
  mutate(var = factor(var, levels=c("SPH", "CPH"), 
                      labels=c("Sightings", "Clicks")))


ggplot(dat, aes(x=as.factor(Week), y=vals, fill=var)) + 
  geom_bar(position="dodge", stat="identity") + 
  ## use model m_inv from above to identify the transformation from the tick values of SPH 
  ## to the appropriate tick values of CPH
  scale_y_continuous(sec.axis=sec_axis(trans = ~coef(m_inv)[1] + coef(m_inv)[2]*.x, name="Clicks/hour")) + 
  labs(y="Sightings/hour", x="Week", fill="") + 
  theme_bw() + 
  theme(legend.position="top")


更新 - 两个轴都从零开始

要使两个轴都从零开始,您需要更改线性图中使用的值都从零开始。这是一个更新的完整示例:

dat <- data.frame(Week = c(1, 2, 3, 4, 5, 6, 7, 8), 
                  SPH = c(2.676, 2.660, 4.175, 2.134, 3.742, 1.395, 4.739, 2.756), 
                  CPH = c(75.35, 29.58, 20.51, 80.43, 97.94, 85.39, 168.61, 142.19))

library(tidyr) 
library(dplyr)

## Find minimum and maximum values for each variable
tmp <- dat %>% 
  summarise(across(c("SPH", "CPH"), ~list(min = min(.x), max=max(.x)))) %>% 
  unnest(everything())


## set lower bound of each to zero
tmp$SPH[1] <- 0
tmp$CPH[1] <- 0

## make mapping from CPH to SPH 
m <- lm(SPH ~ CPH, data=tmp)
## make mapping from SPH to CPH
m_inv <- lm(CPH ~ SPH, data=tmp)


## transform CPH so it's on the same scale as SPH. 
## to do this, you need to use the coefficients from model m above
dat <- dat %>% 
  mutate(CPH = coef(m)[1] + coef(m)[2]*CPH) %>%
  ## pivot the data so all plotting values are in a single column
  pivot_longer(c("SPH", "CPH"), 
               names_to="var", values_to="vals") %>% 
  mutate(var = factor(var, levels=c("SPH", "CPH"), 
                      labels=c("Sightings", "Clicks")))


ggplot(dat, aes(x=as.factor(Week), y=vals, fill=var)) + 
  geom_bar(position="dodge", stat="identity") + 
  ## use model m_inv from above to identify the transformation from the tick values of SPH 
  ## to the appropriate tick values of CPH
  scale_y_continuous(sec.axis=sec_axis(trans = ~coef(m_inv)[1] + coef(m_inv)[2]*.x, name="Clicks/hour")) + 
  labs(y="Sightings/hour", x="Week", fill="") + 
  theme_bw() + 
  theme(legend.position="top")