上节学习了ggplot2的基础作图,并掌握了基本的作图模板。但是每次作图只有两个变量映射到了图形中,如下图:
从图中可以看出汽车发动机排量越大,在高速路上的燃料效率越低的趋势,但是其中的几个红色点却偏离了这个趋势,如果想直接从图中知道这几个点更多的信息,比如汽车的类型,就需要将汽车的类型class映射到图中,因为x和y轴已经被前面两种变量占用了,这时可以用不同的形状或者颜色来表示class,使用以下代码:
代码语言:javascript复制library(ggplot2)
ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = class))
可以看到不同类型的汽车以颜色群分,而那6个离群点有5辆是两座汽车,1辆是中型汽车,这张图的信息量又提升了一个维度。
Aesthetic mappings
什么是美学映射?上图中把汽车的类型映射成每个点的颜色就是一种美学映射,这些美学形象是如何映射到每个点的?
学习基本作图时,两个变量displ和hwy的值分别映射到了x和y轴上,再添加geom_poin()函数后x和y轴会生成标尺,这样我们就知道每个点对应的x和y的值了。对于美学映射来说,可以用颜色的种类,不同的形状或者图形的大小等来对应所要映射的变量中的每个唯一值。
上图只是在aes()中添加了一个参数color = class,ggplot2就会给class中的每个唯一值赋予一种颜色,并添加相应的图例。变量中的值并不一定要是一系列数值(连续变量),如这里就是汽车的各种类型(离散变量)。
size参数
美学映射包含多个种类,如果想将变量中的值映射为点的大小,可以用以下代码:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, size = class))
#> Warning: Using size for a discrete variable is not advised.
可以看到这种图是很难区分各种汽车类型的,而且运行这个代码时,也有消息提醒不推荐使用点的大小来表示离散变量。其实这种美学映射在生信中用的很多,例如单细胞分析包Seurat的DotPlot()函数,是用点的大小来表示某一群细胞中表达某个基因的细胞所占该群细胞的比例。
alpha参数
alpha参数可以调节图形的透明度:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, alpha = class))
可以看到和size一样,不易区分,透明度也不适合表示汽车类型。
shape参数
同样地,要想用形状表示变量中的不同值,可以使用如下代码:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, shape = class))
#> messages:
#> 1: The shape palette can deal with a maximum of 6 discrete values because
#> more than 6 becomes difficult to discriminate; you have 7. Consider
#> specifying shapes manually if you must have them.
#> 2: Removed 62 rows containing missing values (geom_point).
可以看到suv这个类型没有出现在图中,看console中提示可以知道,geom_point()函数默认只使用6种形状来展示数据,因为它认为过多的形状不易于区分。确实这样,6种就已经不好区分了,需要把图放大,看的很费劲。
如果实在需要形状来表示的话,就得手动添加,可以考虑以下代码:
代码语言:javascript复制ggplot(mpg)
geom_point(mapping = aes(x = displ, y = hwy, shape = class))
scale_shape_manual(values = c(0:4, 24, 23))
但是这里subcompact和midsize这两种车型形状相同,因为这张图的每个形状都是手动选择的,用到的是scale_shape_manual(values = c(0:4, 24, 23))这个函数,其中的参数values指定了7种形状,0:4代表0,1,2,3,4五种,再加上24,23两种共七种,这些形状是R中内建的:
为什么图中的24和23没有颜色?看以下代码:
代码语言:javascript复制ggplot(mpg)
geom_point(mapping = aes(x = displ, y = hwy, shape = class, fill = class), fill = 'red')
scale_shape_manual(values = c(0:4, 24, 23))
这下就有了,其实观察R内建的那些形状,只有15-24是有填充颜色的,如果自己敲代码试一下就知道15-20的黑色是固定的,改不了,而21-24的颜色是可以更改的。
这里有一点需要注意,如果仔细看了代码,可以发现上面的代码中fill参数出现了两个,一个在aes()中,一个在外面。这是因为aes()本身也是一个函数,它在geom_point()函数中可以将各个变量映射到图形中,而外面那个fill参数是控制整个图中的点的颜色的。
这种情况同样适用于color参数:
代码语言:javascript复制ggplot(mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = class))
ggplot(mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = class), color = 'blue')
习题练习
1. What’s gone wrong with this code? Why are the points not blue?
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = "blue"))
代码中的错误是因为color参数的位置不对,应该放在aes()外面,才能改变所有点的颜色;这个点为什么不是蓝色,可以用其他颜色试试:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = "black"))
ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = 2))
这里我试了黑色和数字2,都没报错,只有参数为数字时颜色变了,推测可能是aes()这个函数的原因,细节放在后面学习*。
2. Which variables in mpg
are categorical? Which variables are continuous? (Hint: type ?mpg
to read the documentation for the dataset). How can you see this information when you run mpg
?
mpg中的哪些变量是分类变量和连续变量,提示?mgp查看文档,一个是可以通过查看文档,根据各个变量的含义来推断是何种变量,如manufacturer这种,肯定是分类变量了。另一种方法可以直接运行mpg:
代码语言:javascript复制> mpg
# A tibble: 234 × 11
manufacturer model displ year cyl trans drv cty hwy fl class
<chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
1 audi a4 1.8 1999 4 auto… f 18 29 p comp…
2 audi a4 1.8 1999 4 manu… f 21 29 p comp…
3 audi a4 2 2008 4 manu… f 20 31 p comp…
4 audi a4 2 2008 4 auto… f 21 30 p comp…
5 audi a4 2.8 1999 6 auto… f 16 26 p comp…
6 audi a4 2.8 1999 6 manu… f 18 26 p comp…
7 audi a4 3.1 2008 6 auto… f 18 27 p comp…
8 audi a4 quattro 1.8 1999 4 manu… 4 18 26 p comp…
9 audi a4 quattro 1.8 1999 4 auto… 4 16 25 p comp…
10 audi a4 quattro 2 2008 4 manu… 4 20 28 p comp…
# … with 224 more rows
在每个变量名下方的<>,是每个变量的数据类型,chr是character,变量类型是字符的就是分类变量,而dbl是double代表复数,int是integer代表实数,这两种是连续变量。
3. Map a continuous variable to color
, size
, and shape
. How do these aesthetics behave differently for categorical vs. continuous variables?
其实是要掌握连续变量和离散变量分别适合用哪些美学映射。这里选择的连续变量是cyl,代表的是汽缸数量,作图看最直观:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = cyl))
ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, size = cyl))
可以看到颜色和尺寸都可以较好的反映出连续变量的信息,但是用shape时,会出现报错:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, shape = cyl))
#> Error: A continuous variable can not be mapped to shape
因为连续变量中的不同值太多,没有足够的形状来表示各个数值,所以不能使用shape参数映射连续变量。
4. What happens if you map the same variable to multiple aesthetics?
试一下:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = displ, size = displ))
这里将displ映射到了x轴,color和size,可以看到点的大小和颜色都与displ的值呈正相关,都能合理的显示出displ的值,但是表现的信息是冗余的。
5. What does the stroke
aesthetic do? What shapes does it work with? (Hint: use ?geom_point
)
按照提示运行?geom_point查看帮助文档,stroke是用来调节一个形状的边线粗细,如:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = cyl, stroke = 1, fill = manufacturer), shape = 24, size = 5)
ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = cyl, stroke = 3, fill = manufacturer), shape = 24, size = 5)
可以看到,对于这种可以填充颜色的形状,stroke决定边线粗细,color决定边线颜色,fill决定填充颜色
6. What happens if you map an aesthetic to something other than a variable name, like aes(colour = displ < 5)
? Note, you’ll also need to specify x and y.
先运行代码看一下:
代码语言:javascript复制ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy, color = displ < 5))
如上,图形中的点按照displ的值是否小于5自动分成了两组,这种参数输入方式很有用,能够快速看到符合筛选条件的点的分布。
参考资料:
https://r4ds.had.co.nz/index.html