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


25

我想展示某些变量(〜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"))

2
您可以发布数据吗?找到大致相似的示例很容易,但是为了使线程保持联系,使用相同沙箱的人会有所帮助。另外,绿色区域的意义是什么?
尼克·考克斯


@NickCox当然,应该早点想到这一点!我省略了绿色区域,因为它不是必不可少的(它仅显示了被认为“足够”的值的范围)

Answers:


42

幸运的是,您的示例首先具有最佳大小(15组中的每个组最多7个值),以图形方式表明存在问题;第二,允许使用其他相当简单的解决方案。该图是不同领域的人们通常称为“ 意大利面条 ”的一种,尽管并不总是清楚该术语是富感情还是侮辱性的。该图的确显示了所有群体的集体或家庭行为,但在显示要探索的细节方面却毫无希望。

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

那么,为什么不将两种想法结合起来:每个小组一个单独的面板,又将其他小组作为背景显示呢?这关键在于突出显示焦点所在的组,而忽略其他组,这在此示例中很容易,因为使用了一些线条颜色,粗细等。在其他示例中,标记或点符号的选择可能很自然。

在此处输入图片说明

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

  1. A和M只有一个值。

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

  3. 一些组绘制较高,一些较低,依此类推。

在这里,我将不做任何解释:数据是匿名的,但是无论如何,这都是研究人员所关心的。

根据您软件中容易实现或可能实现的功能,这里可以更改一些小细节,例如是否重复轴标签和标题(有赞成和反对的简单参数)。

更大的问题是该策略将在更广泛的范围内发挥作用。组的数量是主要驱动力,远大于每个组的分数。粗略地讲,该方法最多可以使用25个组(例如5 x 5显示屏):如果组更多,不仅图变得更小且更难以阅读,甚至研究人员也失去了扫描所有图的倾向。面板。如果有数百个(数千个……)组,通常必须选择少量的组来显示。需要混合一些标准,例如选择一些“典型”面板和一些“极端”面板;应该由项目目标和对每个数据集有意义的一些想法来驱动。另一种有效的方法是在每个面板中强调少量的系列。所以,如果有25个广泛的组,则可以将每个广泛的组与其他所有组一起显示为背景。或者,可能会有一些平均或其他汇总。使用(例如)主要或独立组件也可能是一个好主意。

尽管该示例要求绘制线图,但原理自然很普遍。示例可以相乘,散布图,模型诊断图等。

此方法的一些参考资料[非常欢迎其他参考]:

Cox,NJ2010。制图子集。Stata Journal 10:670-681。

Knaflic,CN2015。使用数据讲故事:业务专业人员的数据可视化指南。新泽西州霍博肯:威利。

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

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

Unwin,A.,2015年。与R. Boca Raton,FL进行图形数据分析:CRC出版社。

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

注意:该图是在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))

编辑额外参考资料2016年5月,9月;2017年4月,2018年12月,2019年4月:

开罗,答: 2016年。 《真实的艺术:数据,图表和通讯地图》。 加利福尼亚州旧金山:新骑手。第211章

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

Carr,DB和Pickle,LW2010。使用微地图可视化数据模式。佛罗里达州Boca Raton:CRC出版社。第85页

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

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

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

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

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

Wickham,H.,2016年。ggplot2:用于数据分析的优雅图形。湛:施普林格。参见第157页。


+1,太好了,是否有R或SAS功能可以执行此类图表?真的很棒
预报员

我真的喜欢这个主意!只是想知道使用ggplot2在R中绘制此图形的最佳方法。我会稍等一下,然后再接受答案,希望很好。

2
抱歉,我不知道如何在SAS中执行任何操作。当然任何事情的Stata能做到的,R可以做的一样好或更好,还是那么其用户一直告诉我....
尼克·考克斯

@NickCox我想通了,这根本不是问题,看起来非常好,非常适合我的目的。

@NickCox,还有另外两个参考文献:1 . WS Cleveland撰写的数据图形元素。新书,2 . Cole Nussbaumer Knaflic撰写的“用数据讲故事:业务专业人员的数据可视化指南”。这本书(#2)进行了案例研究一章称为“避免意大利面条图的策略”。
预报员

22

作为对尼克回答的补充,以下是一些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)

样例


6

对于那些想ggplot2在R中使用方法的人,请考虑facetshade软件包中的函数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("")

另一种方法是绘制两个单独的层,一个用于背景,一个用于突出显示的情况。诀窍是使用不包含面变量的数据集绘制背景层。对于橄榄油数据集,代码为:

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")

1
这似乎是一种不错的通用方法(+1),但特定示例与另一个问题更多相关。一堆具有不同突出显示区域的重复散点图将无法解决有关时间序列的问题。
Sextus Empiricus

@martin实际上,这也是Adrian的解决方案。请注意,他使用两个相同的标记变量,以便可以将一个变量放入背景层。使用下面的tidyverse标记可以更清楚地看到编码思想,并且通常,优雅的图形格式可以掩盖代码的重要部分。 ggplot(df %>% select(-label), aes(x=time, y=y, group=label2)) + geom_line(alpha=0.8, color="grey") + labs(y=NULL) + geom_line(data=df, color="red") + facet_wrap(~ label)
安东尼·温温

5

这是受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")

在此处输入图片说明


1
这里的主要想法似乎是可以添加某种汇总曲线以帮助您的身心。同意,但是在您的答案中,您可以说明权衡转移到平均值(或参考水平)0而不是保留原始单位和值的情况。主题专家和/或客户很可能会考虑24或28或任何值。当然,这里的数据只是讨论的工具,但要点很笼统。
尼克·考克斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.