如何在一个折线图中绘制多个组的成对均值?

How to plot paired means for multiple groups in one line graph?

我还在学习 R 代码,所以也许这个问题很简单,但我就是想不出来。

我想绘制在三个不同时间点进行的调查问卷的平均分数和置信区间:基线时、4 个治疗周期后和 8 个治疗周期后。本问卷包含 3 个量表;感觉、运动和自主神经。所以我想绘制每个时间点三个不同尺度的平均分数。所以我想要一个线图,X 轴上有时间点(基线;4 个周期后;8 个周期后),Y 轴上我想要分数,图表必须包含三个不同的颜色线,表示感觉、运动和自主尺度。我想使用 ggplot。

我有一个包含以下列的数据框:

这就是我想要的:

希望有人能帮助我!非常感谢!

这是我用虚构的数据想出来的。感谢您分享您的数据结构,但将来最好分享数据本身,这可以通过控制台中的 dput(your.data.frame) 完成,然后 copying/pasting 输出到问题中作为代码...或者只是使用代码创建一个虚拟集,这就是我在这里所做的。

虚拟数据

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

raw_df <- data.frame(
  id=1:60,
  c0sen=rnorm(60, 7, 0.2),
  c4sen=rnorm(60, 8.5, 0.5),
  c8sen=rnorm(60, 11, 1.2),
  c0mot=rnorm(60, 6, 0.3),
  c4mot=rnorm(60, 7.5, 0.5),
  c8mot=rnorm(60, 9.6, 0.8),
  c0aut=rnorm(60, 3, 0.1),
  c4aut=rnorm(60, 2.9, 0.1),
  c8aut=rnorm(60, 3.5, 0.8)
)

处理数据

在继续绘图之前,您需要准备数据集以使用 ggplot2 进行绘图。与 Tidyverse, you should prepare your data to be following Tidy Data Principles 中的其他软件包一样,这就是我将在此处使用 tidyrdplyr 软件包所做的。

按原样排列的数据有很多相同的信息分布在我们需要 gather() 在一起的多个列中,但在每一列中也有我们需要 separate() 的多条信息]分开(时间和测量类型)。

第一步是将数据收集成“长”格式,其中有一列用于 measure(c0aut、c8mot 等),一列用于 score,同时维护 id 列。然后我们需要将measure列分成两列:一列描述time,另一列描述测量的type

df <- raw_df %>%
  gather(key='measure', value='score', -id) %>%
  separate(col=measure, into=c('c_time','type'), sep=2)

最后,我想修复 c_time 只给我号码,我们可以这样做:

df <- df %>% separate(c_time, into=c('c', 'time'), sep=1) %>%
  select(-c)

现在,应该注意 df$time 实际上是一个字符向量(不是数值)...但这实际上没关系,因为我们希望 ggplot2 将其视为序数因子,而不是数值,因为在 x 轴上我们希望 0、4 和 8 均匀分布。

绘制数据

既然你提到这对你来说是新的,我将把情节代码分解成几个部分,这样就可以很容易地按照创建情节所采取的步骤进行操作。首先,我们从基础开始,我们在其中设置数据框以及整个过程中使用的通用美学。请注意,color= 映射到类型,但 group= 也是如此。这是必要的,以便 ggplot2 知道数据也应该根据类型分组(而不是将数据集作为一个整体)。这对我们要绘制的几何体来说非常重要。

p <- ggplot(df, aes(x=time, y=score, color=type, group=type))

统计和几何学。 然后,我们通过 3 次调用 stat_summary 在绘图区域绘制数据,绘制线、误差线和点(按此顺序)。误差条是使用均值 +/- 标准误差 ("mean_se") 绘制的,尽管当然可以使用其他函数。我们还必须用错误栏覆盖 color= 美学,因为我们希望它们都是黑色的(而不是根据类型着色),并且我们必须向点添加 shape= 美学,以便我们可以将其映射到类型以匹配您的情节。

p <- p + stat_summary(
    geom='line', fun=mean) +
  stat_summary(
    geom='errorbar', fun.data=mean_se,
    color='black', width=0.1) +
  stat_summary(
    geom='point', fun=mean, aes(shape=type))

体重秤。 对于比例,我通过重命名我们的 "0", "4", "8" 轴来设置 x 轴属性,并且我还将扩展设置为不像默认扩展那么多,因为它看起来更好一些。 scale_colorscale_shape 调用对于同时更改它们很重要,否则您将失去两个比例之间的连接,并且 ggplot2 实际上会显示两个单独的比例。

type_labels <- c('Autonomic', 'Motor', 'Sensory')

p <- p + scale_x_discrete(
    name=NULL, labels=c('Baseline', '4 weeks', '8 weeks'),
    expand=expansion(mult=0.05)) +
  scale_color_manual(name=NULL, labels=type_labels, values=rainbow(3)) +
  scale_shape_discrete(name=NULL, labels=type_labels)

主题元素。 最后,我设置了主题元素,其中包括命名内容、保持 theme_bw() 的整体整洁外观以及在图例周围添加方框,我将其放置在底部。

p <- p + labs(
    title='EORTC QLQ-CIPN20',
    y='Symptom Score'
  ) +
  theme_bw() +
  theme(
    legend.position='bottom',
    legend.title=element_blank(),
    legend.background = element_rect(color='black')
  )
p

这一切都为您提供了以下内容:

在这样的问题中包含您的实际数据总是一个好主意,但以下内容应该与您所拥有的非常接近:

set.seed(123)

df  <- data.frame(ID    = factor(1:60),
                  c0sen = rbinom(60, 15, 8.8/15),
                  c4sen = rbinom(60, 15, 9.2/15),
                  c8sen = rbinom(60, 15, 10/15),
                  c0mot = rbinom(60, 15, 8.1/15),
                  c4mot = rbinom(60, 15, 8.4/15),
                  c8mot = rbinom(60, 15, 8.6/15),
                  c0aut = rbinom(60, 15, 3/15),
                  c4aut = rbinom(60, 15, 3/15),
                  c8aut = rbinom(60, 15, 3.5/15))
head(df)
#>   ID c0sen c4sen c8sen c0mot c4mot c8mot c0aut c4aut c8aut
#> 1  1    10     8     9     6     8     7     1     3     2
#> 2  2     7    12    11     9     8    13     2     3     5
#> 3  3     9    10    11     7    10     7     5     3     3
#> 4  4     7    10    11     9     8     7     2     2     4
#> 5  5     6     8    11     8     9     8     2     5     6
#> 6  6    12     9     6     8     7     9     4     3     2

现在,这只是使用 ggplot 绘图的错误格式。您首先需要将数据转换为长格式,然后对其进行汇总。在这里,我们使用 reshape2::melt 将数据整形为适当的列,然后使用来自 dplyr 的 summarize 进行汇总:

library(reshape2)
library(dplyr)

summary_df <- melt(df) %>% 
  mutate(time = as.numeric(substr(variable, 2, 2))) %>%
  transmute(ID, time, modality = as.factor(substr(variable, 3, 5)), 
            score = value) %>%
  group_by(modality, time) %>%
  summarize(mean = mean(score), 
            upper = mean + 1.96 * sd(score)/sqrt(length(score)),
            lower = mean - 1.96 * sd(score)/sqrt(length(score)))

这给了我们一些可以使用的东西:

summary_df
#> # A tibble: 9 x 5
#> # Groups:   modality [3]
#>   modality  time  mean upper lower
#>   <fct>    <dbl> <dbl> <dbl> <dbl>
#> 1 aut          0  2.93  3.35  2.52
#> 2 aut          4  2.87  3.25  2.48
#> 3 aut          8  3.45  3.89  3.01
#> 4 mot          0  7.95  8.38  7.52
#> 5 mot          4  8.48  8.99  7.98
#> 6 mot          8  8.62  9.15  8.09
#> 7 sen          0  8.7   9.18  8.22
#> 8 sen          4  9.17  9.63  8.71
#> 9 sen          8 10.1  10.5   9.70

现在我们使用 geom_linegeom_pointgeom_errorbar 的组合进行绘图:

library(ggplot2)

ggplot(summary_df, aes(x = time, y = mean, colour = modality)) + 
  geom_line(size = 1) + 
  geom_point(aes(shape = modality), size = 3) +
  geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2, size = 1) +
  theme_classic() +
  scale_color_discrete(labels = c("Autonomic", "Motor", "Sensory")) +
  scale_shape_discrete(labels = c("Autonomic", "Motor", "Sensory")) +
  theme(legend.position = "bottom", text = element_text(size = 12)) +
  labs(x = "Cycles", y = "Symptom score")

给我们想要的结果:

reprex package (v0.3.0)

于 2020 年 7 月 2 日创建