在一张图中可视化多个变量

机器算法验证 r 数据可视化
2022-01-20 01:24:50

我想展示某些变量(~15)的值是如何随时间变化的,但我也想展示每年这些变量之间的差异。所以我创造了这个情节:

在此处输入图像描述

但即使更改配色方案或添加不同的线条/形状类型,这看起来也很混乱。有没有更好的方法来可视化这种数据?

使用 R 代码测试数据:

structure(list(Var = structure(c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 
6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 
8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 11L, 11L, 11L, 11L, 11L, 
11L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 
14L, 14L, 14L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 
17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), .Label = c("A", 
"B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), class = "factor"), 
    Year = c(2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
    1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 
    2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
    1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 
    2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 
    1991L, 1993L, 1996L, 2000L, 2011L, 2015L, 1991L, 1993L, 1996L, 
    2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 
    2011L, 2015L), Val = c(25.6, 22.93, 20.82, 24.1, 24.5, 29, 
    25.55, 24.5, 24.52, 20.73, 25.8, 25.5, 29.5, 27.7, 25.1, 
    25, 24.55, 26.75, 25, 30.5, 27.25, 25.1, 22.4, 27.07, 26, 
    29, 27.2, 24.2, 23, 24.27, 27.68, 27, 30.5, 28.1, 24.9, 23.75, 
    22.75, 27.25, 25, 29, 28.45, 24, 20.25, 17.07, 24.45, 25, 
    28.5, 26.75, 24.9, 21.25, 20.65, 25.1, 24.5, 26.5, 25.35, 
    23.5, 21.93, 26.5, 24.5, 29, 29.1, 26.4, 28.1, 23.75, 26.5, 
    28.05, 27, 30.5, 25.65, 23.3, 23.25, 24.57, 26.07, 27.5, 
    28.85, 27.7, 22, 23.43, 26.88, 27, 30.5, 29.25, 28.1, 23, 
    23.8, 28.32, 27, 29.5, 29.15, 27.6)), row.names = c(1L, 4L, 
5L, 6L, 7L, 8L, 9L, 10L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 
21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 35L, 
36L, 37L, 38L, 39L, 40L, 41L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 
53L, 54L, 55L, 56L, 57L, 58L, 59L, 62L, 63L, 64L, 65L, 66L, 67L, 
68L, 69L, 70L, 71L, 72L, 73L, 74L, 75L, 78L, 79L, 80L, 81L, 82L, 
83L, 84L, 87L, 88L, 89L, 90L, 91L, 92L, 95L, 96L, 97L, 98L, 99L, 
100L, 101L, 104L, 105L, 106L, 107L, 108L, 109L, 110L), na.action = structure(c(2L, 
3L, 11L, 12L, 33L, 34L, 42L, 43L, 51L, 52L, 60L, 61L, 76L, 77L, 
85L, 86L, 93L, 94L, 102L, 103L), .Names = c("2", "3", "11", "12", 
"33", "34", "42", "43", "51", "52", "60", "61", "76", "77", "85", 
"86", "93", "94", "102", "103"), class = "omit"), class = "data.frame", .Names = c("Var", 
"Year", "Val"))
4个回答

幸运的是,您的示例首先具有最佳大小(15 组中的每组最多 7 个值),以图形方式显示存在问题;其次,允许其他相当简单的解决方案。该图表是一种通常被不同领域的人们称为意大利面条的图表,尽管并不总是清楚该术语是否意味着深情或辱骂。(“意大利面条”一词在 1985 年由 Gene Zelazny 使用,但可能更早。)该图确实显示了所有群体的集体或家庭行为,但在显示要探索的细节方面相当无望。

一种标准的替代方法是在单独的面板中显示单独的组,但这反过来又会使精确的组间比较变得困难;每个组都与其他组的上下文分开。

那么,为什么不将这两个想法结合起来:为每个组设置一个单独的面板,同时将其他组显示为背景呢?这关键取决于突出焦点组和淡化其他组,这在此示例中很容易,因为使用了一些线条颜色、粗细等。在其他示例中,标记或点符号的选择可能是自然的。

在此处输入图像描述

在这种情况下,强调了可能的实际或科学重要性或兴趣的细节:

  1. A 和 M 只有一个值。

  2. 在所有其他情况下,我们没有所有给定年份的所有值。

  3. 一些组情节高,一些低,等等。

我不会在这里尝试解释:数据是匿名的,但无论如何这是研究人员关心的问题。

根据您的软件中的简单或可能,这里有更改小细节的空间,例如轴标签和标题是否重复(支持和反对都有简单的论据)。

更大的问题是这种策略将在多大程度上更普遍地起作用。组数是主要驱动因素,比每组中的点数更重要。粗略地说,这种方法最多可以处理大约 25 个组(例如 5 x 5 显示器):组越多,不仅图形变得更小,更难阅读,甚至研究人员也失去了扫描所有面板。如果有数百(千,...)个组,通常必须选择少数组进行显示。需要一些标准组合,例如选择一些“典型”和一些“极端”面板;这应该由项目目标和对每个数据集有意义的一些想法驱动。另一种可能有效的方法是在每个面板中强调少量系列。所以,如果有 25 个大组,则可以将每个大组与所有其他组一起显示为背景。或者,可能有一些平均或其他总结。使用(例如)主要或独立组件也可能是一个好主意。

虽然这个例子需要线图,但原理自然是很笼统的。示例可以是相乘图、散点图、模型诊断图等。

相似但不相同的想法

Cleveland (1985, pp.74, 203, 205, 268) 显示了图表,其中重复了组的汇总曲线,每个组的数据分别显示。(注意:这些图表没有出现在 1994 年的克利夫兰。)

沃尔格伦等人。(1996, pp.47, 69) 使用相同的想法。

克利夫兰,WS 1985。图形数据的元素。加利福尼亚州蒙特雷:沃兹沃思。

克利夫兰,WS 1994。图形数据的元素。新泽西州萨米特:霍巴特出版社。

Wallgren, A.、B. Wallgren、R. Persson、U. Jorner 和 J.-A。哈兰德。1996.绘制统计数据和数据:创建更好的图表。加利福尼亚州纽伯里公园:SAGE。

Zelazny(1985 年及以后的版本)有不同的转折:

Zelazny, G. 1985。用图表说出来:成功演示的高管指南。 伊利诺伊州霍姆伍德:道琼斯-欧文。参见第 39 页,查看包含四个面板的图表:A 系列依次与 B、C、D、E 系列进行比较。另请参见第 111 页。

第 4 版中的同一页:Zelazny, G. 2001。用图表说:视觉传达执行指南。纽约:麦格劳-希尔。参见第 39 页,查看包含四个面板的图表:A 系列依次与 B、C、D、E 系列进行比较。另请参见第 111 页。

直接例子[欢迎其他人]

Koenker, R. 2005。分位数回归。剑桥:剑桥大学出版社。见第 12-13 页。

Carr, DB 和 Pickle, LW 2010。使用微图可视化数据模式。佛罗里达州博卡拉顿:CRC 出版社。见第 85 页。

Cox, NJ 2010。绘制子集。统计杂志10:670-681。

Yau, N. 2013。数据点:有意义的可视化。 印第安纳波利斯,印第安纳州:约翰威利。见第 224 页。

Rougier, NP, Droettboom, M. 和 Bourne, PE 2014。获得更好数据的十个简单规则。 PLOS 计算生物学10(9):e1003833。doi:10.1371/journal.pcbi.1003833 链接在这里

Schwabish, JA 2014。数据可视化的经济学家指南。经济展望杂志28:209-234。

Knaflic,CN 2015。用数据讲故事:商业专业人士的数据可视化指南。新泽西州霍博肯:威利。见第 233 页。

Unwin, A. 2015。与佛罗里达州博卡拉顿 ( R. Boca Raton) 合作的图形数据分析:CRC 出版社。见第 121、217 页。

Berinato, S. 2016。 好图表:HBR 指南,使数据可视化更智能、更有说服力。 马萨诸塞州波士顿:哈佛商业评论出版社。见第 74 页。

Cairo, A. 2016。 真实的艺术:用于交流的数据、图表和地图。 加利福尼亚州旧金山:新车手。见第 211 页

Camões, J. 2016。工作中的数据:在 Microsoft Excel 中创建有效图表和信息图形的最佳实践加利福尼亚州旧金山:新车手。见第 354 页。

Standage, T. 2016。走图:经济学家解释:你不知道的事情你不知道。伦敦:简介书籍。见第 177 页。

Wickham, H. 2016。ggplot2:用于数据分析的优雅图形。查姆:斯普林格。见第 157 页。

Schwabish, J. 2017。 更好的演示文稿:学者、研究人员和 Wonks 指南。 纽约:哥伦比亚大学出版社。见第 98 页。

Kriebel, A. 和 Murray, E. 2018。#MakeoverMonday:改进我们如何可视化和分析数据,一次一张图表。新泽西州霍博肯:约翰威利。见第 303 页。

Grant, R. 2019。数据可视化:图表、地图和交互式图形。 佛罗里达州博卡拉顿:CRC 出版社。见第 52 页。

Koponen, J. 和 Hildén, J. 2019。 数据可视化手册。 埃斯波:阿尔托艺术书籍。请参见第 101 页。

Tufte, ER 2020。用新鲜的眼光看待:意义、空间、数据、真理。 康涅狄格州柴郡:图形出版社。参见第 26 页 [John Burn-Murdoch 的原创作品,但在对数刻度 (!) 上显示 0,并按国家/地区的字母顺序显示,可以调整]

注意:图表是在 Stata 中创建的。subsetplot必须先安装ssc inst subsetplot. 数据是从 R 复制和粘贴的,值标签被定义为显示年份90 95 00 05 10 15主要命令是

subsetplot connected Val Year, by(Var) c(L) lcolor(gs12) backdrop(line) xtitle("") combine(imargin(small)) subset(lcolor(blue) mcolor(blue))

作为对尼克的回答的补充,这里有一些使用模拟数据制作类似图的 R 代码:

library(ggplot2)

get_df <- function(label="group A", n_obs=10, drift=runif(1)) {
    df <- data.frame(time=seq(1, n_obs), label=label)
    df$y <- df$time * drift + cumsum(rnorm(n_obs))
    return(df)
}
df_list <- lapply(sprintf("group %s", toupper(letters[1:9])),
                  function(label) { get_df(label) })
df <- do.call(rbind, df_list)
df$label2 <- df$label

p <- (ggplot(df, aes(x=time, y=y, group=label2)) +
      geom_line(size=0.9, alpha=0.8,
                data=df[, c("time", "y", "label2")], color="grey") +
      geom_line(size=1.1, color="black") +
      ylab("") +
      theme_bw() +
      theme(panel.border=element_blank()) +
      theme(strip.background=element_blank()) +
      facet_wrap(~ label))
p
ggsave("example_facet.png", p, width=10, height=8)

示例图

对于那些想要ggplot2在 R 中使用方法的人,请考虑facetshadepackage 中的函数extracat这提供了一种通用方法,而不仅仅是线图。这是一个带有散点图的示例(来自本页的底部):

data(olives, package="extracat")
library(scales)
fs1 <- facetshade(data = olives,
                  aes(x = palmitic, y = palmitoleic), f = 
                      . ~ Area)
fs1 + geom_point(colour = alpha("black", 0.05)) +
      geom_point(data = olives, colour = "red") +
      facet_wrap(f=~Area, nrow=3) + 
          theme(legend.position="none")

在此处输入图像描述


编辑:使用他之前回答中的 Adrian 模拟数据集:

library(extracat)
facetshade(df, aes(x=time, y=y), f = .~label, bg.all = FALSE, 
            keep.orig = TRUE) +
           geom_line(aes(x=time, y=y, 
             group=orig.label),colour = alpha(1,0.3)) +
           geom_line(data=df, aes(colour=label), size = 1.2) 
           + xlab("") + ylab("")

另一种方法是绘制两个单独的图层,一个用于背景,一个用于突出显示的案例。诀窍是使用没有 faceting 变量的数据集绘制背景层。对于橄榄油数据集,代码是:

data(olives, package="extracat")
ggplot(olives, aes(palmitic, palmitoleic)) + 
  facet_wrap(~Area, nrow=3) + 
  geom_point(data=olives %>% select(-Area), 
        colour=alpha("black", 0.05)) + 
  geom_point(data=olives, colour="red") + 
  theme(legend.position="none")

这是一个受 Ch 启发的解决方案。11.3,“德克萨斯住房数据”部分,在Hadley Wickham 的 ggplot2 书中在这里,我为每个时间序列拟合一个线性模型,获取残差(以均值 0 为中心),并以不同的颜色绘制一条摘要线。

library(ggplot2)
library(dplyr)
#works with dplyr version 0.4.3.9000 from Github (hadley/dplyr@4f2d7f8), or higher

df1 <- as.data.frame(list(Var = structure(c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 
                                 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 
                                 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 
                                 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 11L, 11L, 11L, 11L, 11L, 
                                 11L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 
                                 14L, 14L, 14L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 
                                 17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), .Label = c("A", 
                                                                                               "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
                                                                                               "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), class = "factor"), 
               Year = c(2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
                        1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 
                        2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
                        1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 
                        2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 
                        1991L, 1993L, 1996L, 2000L, 2011L, 2015L, 1991L, 1993L, 1996L, 
                        2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 
                        2011L, 2015L), 
               Val = c(25.6, 22.93, 20.82, 24.1, 24.5, 29, 
                       25.55, 24.5, 24.52, 20.73, 25.8, 25.5, 29.5, 27.7, 25.1, 
                       25, 24.55, 26.75, 25, 30.5, 27.25, 25.1, 22.4, 27.07, 26, 
                       29, 27.2, 24.2, 23, 24.27, 27.68, 27, 30.5, 28.1, 24.9, 23.75, 
                       22.75, 27.25, 25, 29, 28.45, 24, 20.25, 17.07, 24.45, 25, 
                       28.5, 26.75, 24.9, 21.25, 20.65, 25.1, 24.5, 26.5, 25.35, 
                       23.5, 21.93, 26.5, 24.5, 29, 29.1, 26.4, 28.1, 23.75, 26.5, 
                       28.05, 27, 30.5, 25.65, 23.3, 23.25, 24.57, 26.07, 27.5, 
                       28.85, 27.7, 22, 23.43, 26.88, 27, 30.5, 29.25, 28.1, 23, 
                       23.8, 28.32, 27, 29.5, 29.15, 27.6)), 
               row.names = c(1L, 4L, 
                           5L, 6L, 7L, 8L, 9L, 10L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 
                           21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 35L, 
                           36L, 37L, 38L, 39L, 40L, 41L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 
                           53L, 54L, 55L, 56L, 57L, 58L, 59L, 62L, 63L, 64L, 65L, 66L, 67L, 
                           68L, 69L, 70L, 71L, 72L, 73L, 74L, 75L, 78L, 79L, 80L, 81L, 82L, 
                           83L, 84L, 87L, 88L, 89L, 90L, 91L, 92L, 95L, 96L, 97L, 98L, 99L, 
                           100L, 101L, 104L, 105L, 106L, 107L, 108L, 109L, 110L), 
               na.action = structure(c(2L, 
                          3L, 11L, 12L, 33L, 34L, 42L, 43L, 51L, 52L, 60L, 61L, 76L, 77L, 
                          85L, 86L, 93L, 94L, 102L, 103L), 
                .Names = c("2", "3", "11", "12","33", "34", "42", "43", "51", "52", "60", 
                           "61", "76", "77", "85", "86", "93", "94", "102", "103"), class = "omit"), 
                class = "data.frame", .Names = c("Var","Year", "Val"))


df1 %>%
        group_by(Var) %>%
        do(mutate(.,resid = resid(lm(Val ~ Year, data=., na.action = na.exclude)))) %>%
        ggplot(aes(Year, resid)) +
        labs(y=paste0("Val "), x="Year") +
        geom_line(aes(group = Var), alpha = 1/5) +
        geom_line(stat = "summary", fun.y = "mean", colour = "red")

在此处输入图像描述