11.ggplot2——色阶与图例(一)

11 色阶与图例

除了位置之外,最常用的属性是基于颜色的图形属性,在ggplot2中有许多方法将值映射到颜色。在我们具体了解之前,学习一点色彩理论是很有用的。颜色理论很复杂,因为眼睛和大脑的基础生物学很复杂,此处只介绍一些更重要的问题。更详细的内容可以在线访问http://tinyurl.com/clrdtls了解。

11.1 简单的色彩原理

在物理层面上,颜色是由不同波长的光混合产生的。要完全描述一种颜色,我们需要知道波长的完全混合后的效果。然而,人眼只有三种不同的颜色感受器,因此我们可以用三个数字来概括对任何颜色的感知。你可能对颜色空间的RGB编码很熟悉,它通过产生颜色所需的红、绿、蓝光的强度来定义颜色。这个空间的一个问题是它在感知上不是统一的:相隔一个单位的两种颜色可能看起来相似或非常不同,这取决于它们在颜色空间中的位置。这使得创建一个从连续变量到一组颜色的映射变得困难。我们将使用一种叫做HCL色彩空间做尝试,它有色调、色度和亮度三个组成部分:

  • 色调范围从 0 到 360(角度),并给出具体的“颜色”(蓝色、红色、橙色等)。
  • 色度是颜色的“纯度”,范围从 0(灰色)到随亮度变化的最大值。
  • 亮度是颜色的亮度,范围从 0(黑色)到 1(白色)。

这三个维度具有不同的属性。色调围绕一个色轮排列,并认为是无序的:例如,绿色看起来并不比红色“大”,蓝色似乎不在绿色或红色“中间”。相比之下,色度和亮度都被认为是有序的:粉红色被认为介于红色和白色之间,而灰色被认为介于黑色和白色之间。

这三个组件的组合不会产生简单的几何形状。下图显示了HCL空间的 3d 形状。每个切片都是一个恒定的亮度(亮度),色调映射到角度,色度映射到半径。您可以看到每个切片的中心是灰色的,并且颜色越靠近边缘越浓。

图解:HCL色彩空间的形状。色调映射到角度,色度映射到半径,每个切片显示不同的亮度。HCL空间是一个非常奇怪的形状,但您可以看到每个切片中心附近的颜色是灰色的,当你向边缘移动,它们变得更加强烈。亮度 0 和 100 的切片被省略,因为它们将分别是单个黑点和单个白点。

需要注意的是,许多人(约10%的男性)没有正常的颜色受体,因此能够区分的颜色比平常少。简而言之,最好避免红绿对比,通过使用Visicheck(在线解决方案)模拟色盲的系统检查您的图。另一种替代方案是dichromat包,它提供模拟色盲的工具,以及一套已知对色盲很有效的配色方案。你也可以帮助色盲的人,就像你可以帮助黑白打印机的人一样:通过为其他图形属性(如尺寸、线条类型或形状)提供多于映射。

11.2 连续色阶

颜色渐变通常用于显示二维平面图形。本节中的图使用了faithful数据集的二维密度估计的表面,记录了黄石公园在喷发之间和每次喷发期间的等待时间。我隐藏图例并设置expand为 0,便于关注数据外观。请记住:虽然我使用erupt绘图来说明使用填充属性的概念,但同样的想法也适用于色阶。在本节中,无论我何时引用scale_fill_*(),都有一个相应的scale_colour_*()用于颜色图形属性(或者scale_color_*())。

erupt <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
  geom_raster() +
  scale_x_continuous(NULL, expand = c(0, 0)) + 
  scale_y_continuous(NULL, expand = c(0, 0)) + 
  theme(legend.position = "none")

11.2.1特殊调色板

有多种方法可以指定连续的色阶。稍后我将讨论可用于构建自己的调色板的通用工具,但这通常是不必要的,因为有许多“hand picked”的调色板可用。例如,ggplot2 提供了两个scale函数,它们预定义了调色板,scale_fill_viridis_c()scale_fill_distiller().。翠绿色(viridis scales)的设计是为了使其在颜色和黑白两种颜色上都具有感知上的统一,并使各种形式的色盲的人能够感知到。

erupt
erupt + scale_fill_viridis_c()
erupt + scale_fill_viridis_c(option = "magma")
image.png

ggplot2 内置的第二个连续色阶源自 ColorBrewer 色标:scale_fill_brewer()将这些颜色作为离散调色板提供,而scale_fill_distiller()scale_fill_fermenter()是连续和分箱相关。

erupt + scale_fill_distiller()
erupt + scale_fill_distiller(palette = "RdPu")
erupt + scale_fill_distiller(palette = "YlOrBr")
image.png

还有许多其他软件包提供有用的调色板。例如,scico包提供了更多在感知上统一的,并且适合科学可视化的调色板:

erupt + scico::scale_fill_scico(palette = "bilbao") # the default
erupt + scico::scale_fill_scico(palette = "vik")
erupt + scico::scale_fill_scico(palette = "lajolla")
image.png

然而,由于 R 中有很多调色板包,一个特别有用的是paletteer包,它提供了一个通用接口:

erupt + paletteer::scale_fill_paletteer_c("viridis::plasma")
erupt + paletteer::scale_fill_paletteer_c("scico::tokyo")
erupt + paletteer::scale_fill_paletteer_c("gameofthrones::targaryen")
image.png

11.2.2 稳定的方法

连续填充的默认方法是scale_fill_continuous(),反方向默认为scale_fill_gradient()。因此,这三个命令使用梯度比例生成相同的图形:

erupt
erupt + scale_fill_continuous()
erupt + scale_fill_gradient()
image.png

渐变为创建您喜欢的任何配色方案提供了一种强大的方法。您需要做的就是指定两个或多个参考颜色,ggplot2 将在它们之间进行线性插值。为此,您可以使用三个函数:

下面说明了梯度渐变的使用。第一个图使用线性插值的比例,从low灰色(十六进制代码:“#bebebe”)到high端棕色(“#a52a2a”)。第二个图形具有相同的端点,但使用scale_fill_gradient2()首先从灰色插值到白色(#ffffff),然后从白色插值到棕色。注意,mid参数指定了颜色在中间点,midpoint是该数据使用这个颜色(默认是midpoint = 0)的值,第三种方法是使用scale_fill_gradientn()将一个向量的参考颜色作为它的参数,并构建一个刻度,在指定的值之间线性内插。默认情况下,colours沿比例是相等间隔的,但如果您愿意,您可以指定一个values对应于每个参考颜色。

erupt + scale_fill_gradient(low = "grey", high = "brown")
erupt + scale_fill_gradient2(low = "grey", mid = "white", high = "brown", midpoint = .02)
erupt + scale_fill_gradientn(colours = terrain.colors(7))
image.png

创建好的调色板需要小心。通常,对于两点渐变比例,您希望传达值按顺序排列的感知印象,因此您希望保持色调不变,并改变色度和亮度。Munsell 颜色系统对此很有用,因为它提供了一种基于色调、色度和亮度指定颜色的简单方法。munsell 包提供了对 Munsell 颜色的轻松访问,然后可用于指定渐变比例:

munsell::hue_slice("5P") +  # generate a ggplot with hue_slice()
  annotate(                 # add arrows for annotation 
    geom = "segment", 
    x = c(7, 7), 
    y = c(1, 10), 
    xend = c(7, 7), 
    yend = c(2, 9), 
    arrow = arrow(length = unit(2, "mm"))
  ) 
#> Warning: Removed 31 rows containing missing values (geom_text).

# construct scale
erupt + scale_fill_gradient(
  low = munsell::mnsl("5P 2/12"), 
  high = munsell::mnsl("5P 7/12")
)
image.png

左图中的标签在这个比例下有点难以阅读,所以我习惯于annotate()添加箭头突出显示用于构建右侧比例的列。有关 munsell 软件包的更多信息,请参阅https://github.com/cwickham/munsell/

三点梯度量表的设计标准略有不同。通常,这种量表的目标是传达一种感知印象,即存在其他值与之不同的自然中点(通常为零值)。下面的左图显示了如何创建发散的“黄色/蓝色”比例。

最后,如果您有对您的数据有意义的颜色(例如,黑色车身颜色或标准地形颜色),或者您想使用由另一个包生成的调色板,您可能希望使用 n 点渐变。作为说明,下面的中间和右边的图使用了colorspace包。有关色彩空间包的更多信息,请参阅https://colorspace.r-forge.r-project.org/

# munsell example
erupt + scale_fill_gradient2(
  low = munsell::mnsl("5B 7/8"),
  high = munsell::mnsl("5Y 7/8"),
  mid = munsell::mnsl("N 7/0"),
  midpoint = .02
) 

# colorspace examples
erupt + scale_fill_gradientn(colours = colorspace::heat_hcl(7))
erupt + scale_fill_gradientn(colours = colorspace::diverge_hcl(7))
image.png

11.2.3 缺失值

所有连续色阶都有一个na.value参数,用于控制缺失值的颜色(包括标度限制范围之外的值)。默认情况下为灰色,当您使用彩色比例尺时,它会脱颖而出。如果您使用黑白比例,您可能希望将其设置为其他内容以使其更明显。您可以设置na.value = NA使缺失值不可见,或者选择一个特定颜色:

df <- data.frame(x = 1, y = 1:5, z = c(1, 3, 2, NA, 5))
base <- ggplot(df, aes(x, y)) + 
  geom_tile(aes(fill = z), size = 5) + 
  labs(x = NULL, y = NULL)

base
base + scale_fill_gradient(na.value = NA)
base + scale_fill_gradient(na.value = "yellow")
image.png

11.2.4 限制、中断和标签

您可以通过将它们设置为NULL来完全抑制中断。对于轴,这将删除刻度线、网格线和标签;对于图例,这将删除键和标签。

toy <- data.frame(
  const = 1, 
  up = 1:4,
  txt = letters[1:4], 
  big = (1:4)*1000,
  log = c(2, 5, 10, 2000)
)
leg <- ggplot(toy, aes(up, up, fill = big)) + 
  geom_tile() + 
  labs(x = NULL, y = NULL) 
leg + scale_fill_continuous(breaks = NULL)
image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容