在ggplot系统中,用于调整坐标轴和坐标系的函数有三类,第一类是scale_x/y_*函数,第二类是coord_*函数,第三类是x/ylim、labs等方便函数。
一、scale_x/y_*函数
如函数名称所示,scale_x/y_*中的"x"和"y"用于指明是对X轴还是Y轴进行调整,而"*"则指明坐标轴的类型及调整方法。我们下面将进行详细说明。
1. scale_x/y_continuous
当与坐标轴对应的数据是连续变量时,我们用scale_x/y_continous对坐标轴进行调整。本例使用的数据集为cpi1718.csv,它记录了2017和2018年中国各月的CPI数值。
library(ggplot2)
dat=read.csv("cpi1718.csv", row.names=1) # 课件中的文件
p=ggplot(dat)+geom_line(aes(1: 24, CPI), size=1) # 因为数据包含24个数据点,所以我们暂且把X值定为1至24的整数
p+scale_x_continuous(name="DATE", breaks=c(1, 5, 11), labels=c ("1", "60", "Here is 800"), minor_breaks=c(20.5, 21.5))
p+scale_y_continuous(position="right")+scale_x_continuous (limits=c(-3, 28), breaks=c(-10, 0, 30))
p+scale_y_continuous(expand=expansion(mult=c(0.02, 0.05), add=c(3, 4)))
我们来解释一下各参数的含义:
●name:坐标轴的标题。
●position:坐标轴的位置。X轴默认为"bottom",可改为"top",Y轴默认为"left",可改为"right"。
●limits:坐标轴值域。本例中,与X轴相对应的数据的最小值是1,最大值是24,但我们仍可以将值域改为-3至8。ggplot会完全删去超出坐标轴值域的图形,并弹出警告。
●breaks:添加主要网格线(与坐标轴上的标签相对应的白色线条)和坐标轴刻度线的位置。如果不进行修改,ggplot会自动寻找合适的位置。当设为NULL时,所有位置都将被取消。
●labels:在由breaks指定的位置添加标签的内容,其长度要与breaks的长度相等。如不需要标签,可将其设为NULL。注意:标签的位置与内容无需相符,比如,在本例中,用breaks指定的位置是1、5、11,但用labels指定的标签则并非是这几个数值。另外,超出了由limits指定的值域的标签也不会显示出来,比如,在本例中,limits的值为-3至28,因此在-10和30这两个位置的标签就不会显示出来。使用labels参数的另一种方法是让它指向一个可对默认标签进行加工的函数。
●minor_breaks:添加次要网格线(即下方没有坐标轴标签的白色线条)的位置。如不需要次要网格线,可将其设为NULL。在默认情况下,ggplot首先确定主要网格线的位置,然后在主要网格线之间添加次要网格线,但我们同样可以对此进行修改。
●expand:坐标轴向左右或上下扩展的程度。这个参数的值必须是一个由expansion指定的值,其默认值为expansion(mult=0.05)(对连续变量)或expansion(add=0.6)(对离散变量),其中mult参数的前后两个值决定向左边和右边(或下边和上边)扩展的倍数,add参数决定在扩展之后直接添加的值。若参数只有一个值,会自动变为两个值。在本例中,Y轴值域若按Y值的最小值和最大值来算的话,理应是103至106.8,Y轴最下方和最上方的距离是106.8-103=3.8。但我们设定了expand=expansion(mult=c(0.02, 0.05), add=c(3, 4)),因此Y轴下方会扩展至103-3.8*0.02-3=99.924,上方会扩展至106.8+3.8*0.05+4=110.99。显然,如果不希望坐标轴扩展的话,只要认定expand=expansion(0)即可。
●trans:调整数值的方法。默认值为"identity",即不作调整。常用选项有"log"(自然对数)、"log2"(以2为底的对数)、"log10"(以10为底的对数)、"sqrt"(开方)等。见以下例子。
●guide:参数值需由guide_axis函数生成。见以下例子。
## 用trans="log10"来呈现差异很大的数值
big=data.frame(x=1: 6, y=c(1, 2, 3, 200, 1022, 50000))
ggplot(big)+geom_point(aes(x, y))+
scale_y_continuous(trans="log10", breaks=big$y)
# 在本例中,与Y轴对应的数值之间的差异被放大,这是因为图表使用的不是原始数值,而是以10为底的对数
p+scale_x_continuous(guide=guide_axis(n.dodge=2, angle=30)) # n.dodge用于设置标签行数(默认值为1),有助于摆放多个较长的标签。angle为标签旋转角度,类似于本章第三节将提及的axis.text=element_text(angle=...),但差异在于,前者会自动选择美观的对齐方式
2. scale_x/y_discrete
当数据为离散变量(例如,条形图中用于划分类别的变量)时,修改坐标轴需使用scale_x/y_discrete函数。让我们以世界各地专利授权数据为例进行讲解。
dat=read.csv("patents6.csv", row.names=1) # 课件中的文件
v=dat$Count
lab=dat$Area
p=ggplot()+geom_bar(aes(x=lab, y=v), stat="identity", fill="firebrick")
# 有时标签上的数字会以科学计数法的形式出现,但这并不是我们想要的。解决方法是把options(scipen=...)调整为一个较大的数
options(scipen=10) # 此时再作图,标签就是正常的200000、400000……了
p+scale_x_discrete(name="离散坐标", breaks=c("非州", "亚洲"), labels=c("Africa", "Asia")) # 在选定的位置标注经修改的标签
p+scale_x_discrete(limits=c("非州", "亚洲", "大洋洲")) # 仅显示选中的数据点,此时会弹出警告
p+scale_x_discrete(expand=expansion(mult=0.5)) # 本例包含6个数据点,我们可视其为占据了X轴上1至6的位置,最大值与最小值的距离是6-1=5,因此,如果设置expansion(mult=0.5)的话,那么左边将延伸到1-5*0.5=-1.5,右边延伸至6+5*0.5=8.5
ggplot()+geom_point(aes(x=lab, y=v), size=5) # 当然,除了条形图外,散点图也可使用离散变量
3. scale_x/y_date/datetime
如果变量为日期/时间对象(例如,折线图中与X轴对应的变量),我们有两种绘制方法:第一种方法是用1至n(n为数据点的个数)的整数来代替数值,第二种方法是将日期/时间对象映射到图表中。
我们以上文中使用过的CPI数据为例。
dat=read.csv("cpi1718.csv", row.names=1)
dat$Date=as.Date(dat$Date)
## 对标签进行一些调整(我们在第一章介绍了调整日期显示方式的代码)
lab=dat$Date
lab=seq(lab[1], lab[length(lab)], by="3 month")
lab_text=format(lab, format="%y年\n%b")
ggplot(dat)+geom_line(aes(Date, CPI), size=1)+
scale_x_date(name="Month", breaks=lab, labels=lab_text, expand=expansion(add=30)) # 用expand增加显示的天数
## scale_x/y_dateime的使用方法与scale_x/y_date相仿;只不过,为了防止标签挤在一起,我们得对文字进行更多调整
x=as.POSIXct("2019-08-08 12:00:00")+3600*(0: 23)
n=length(x)
mybreak=x[seq(1, n, 4)]
mylab=format(mybreak, format="%e日\n%H时%M分")
ggplot()+geom_point(aes(x, 1: n), size=3)+
scale_x_datetime(name="Time", breaks=mybreak, labels=mylab)
4. 获取美观的标签
坐标轴上每个标签与其两边的标签之间的间隔都是相等的。但我们会发现,这个间隔并不是随意计算出来的,而通常是1、2、5、10、100等数值的倍数。以此方式添加的标签会使坐标轴较为美观,我们通常亦无需对其进行修改。但有时,我们要么需要获取坐标轴标签以及相应的位置,要么自己生成一系列标签和位置。
library(plothelper)
dat=read.csv("cpi1718.csv", row.names=1)
## 用plothelper包中的get_gg_label函数可以获取gg对象的坐标轴信息
p=ggplot(dat)+geom_line(aes(1: nrow(dat), CPI), size=1) # 此图X轴标签均是5的倍数,Y轴标签均是1的倍数
mylab=get_gg_label(a=p)
# get_gg_label的结果是一个包含五项的列表:$min和$max为坐标轴的范围;$label为标签;$position为加标签的位置,也就是画主网格线的位置;$all是画所有网格线的位置
mylab=get_gg_label(a=p, axis="x") # 设axis="x",则查看X轴的情况
# 以下两种写法会得到相同的结果,一是给出一个向量,二是给出最小值和最大值,同时还可用mult和add参数模仿expansion的效果
get_gg_label(v=dat$CPI, mult=0.05)
get_gg_label(a=min(dat$CPI), b=max(dat$CPI), mult=0.05)(www.xing528.com)
我们也可以直接用pretty生成标签位置
mylab=pretty(x=dat$CPI, n=5, min.n=2)
# [1] 103 104 105 106 107
# x参数是与坐标轴对应的向量,n为预期标签数量,min.n为当无法生成n个标签时至少生成多少个标签,默认值为n %/% 3的结果
二、coord_*函数
如果我们要对整个坐标系进行调整,就要用到coord_*系列函数。不过,在画一个图表的过程中,我们只能使用一次coord_*函数进行设置,否则,后边的设置会取代前边的设置。
coord_*函数的参数大多是相同的,包括:
●xlim、ylim:坐标轴值域。但它们实际效果与scale_x/y_*中limits的效果并不相同。请看以下示例。
●expand:是否扩展坐标轴值域。这个参数的可选项为TRUE(默认)和FALSE,而不像scale_x/y_*中的expand那样必须被赋予一个由expansion设定的值。
●clip:是否允许将图形画在超出面板的地方。默认值为"on",可改为"off"。请看以下示例。
1. coord_cartesian:对坐标系进行设置
dat=read.csv("patents6.csv", row.names=1) # 使用上文提到过的专利授权数据
v=dat$Count
lab=dat$Area
p=ggplot()+geom_bar(aes(x=lab, y=v), stat="identity", fill="firebrick")
## 对条形图的Y轴进行调整:首先,ggplot并不会把条形图Y轴上的最小值设为0,所以如有必要,我们可以在此手动设置,其次,我们希望Y轴最高点略高于数据的最大值,故在此让最大值乘以1.1;另外,既然我们已经设置好了坐标轴,当然不希望它再自动扩展,所以把 expand设为FALSE
p+coord_cartesian(ylim=c(0, max(v)*1.1), expand=FALSE)
# 将clip设为"off"的作用之一是为图片加水印(后边的章节会介绍本例中theme和geom_text的用法)
p+geom_text(aes(x=3.5, y=c(200000, 600000), label="这是水印"), angle=45, color="grey75", size=25)+
theme(plot.margin=unit(rep(10, 4), "mm"))+
coord_cartesian(clip="off")
# 务必注意以下两种设置坐标轴值域方法的差异
p+coord_cartesian(ylim=c(0, 200000)) # 此时,有两个柱子超过了200000,但它们未超值域的部分仍会显示
p+scale_y_continuous(limits=c(0, 200000)) # 此时,那些有一部分超出了值域的图形根本不会出现在图表中
2. coord_flip:翻转X轴和Y轴
p+coord_flip() # 垂直条形图变为水平条形图
p+coord_flip(ylim=c(0, max(v)*1.1), expand=FALSE) # coord_flip中的xlim和ylim所调整的是翻转前的X轴和Y轴
## orientation参数
# 以下例子没有使用coord_flip,但却同样达到了翻转坐标轴的目的。注意:此处有两处修改。第一,我们设置orientation="y",第二,我们用aes(x=v, y=lab)代替了aes(x=lab, y=v)
ggplot()+geom_bar(aes(x=v, y=lab), stat="identity", fill="firebrick", orientation="y")
# orientation的取值为"x"(默认)或"y"。实际上,除geom_bar之外,geom_line以及后文要介绍的geom_ribbon、geom_area、geom_smooth函数都使用这个参数
3. coord_polar:使用极坐标系
极坐标系可以被视为有着环状坐标轴的坐标系。与以上coord_*函数不同, coord_polar没有xlim、ylim和expand参数。theta用以决定将哪个坐标轴变为环形,默认值为"x",可改为"y";start用以设定起始点,默认值为0,即钟表表盘12点钟位置,3.14为6点钟位置;direction为旋转方向,1为顺时针(默认),-1为逆时针。
p+coord_polar() # 玫瑰图
p+coord_polar(start=1.57) # 将起始点改为3点钟方向
4. coord_fixed:固定代表单位长度的线段长度比
dat=read.csv("cpi1718.csv", row.names=1) # 以上文提到的CPI数据为例
p=ggplot(dat)+geom_line(aes(1: 24, CPI))
R会根据窗口的比例,自动调整代表单位长度的线段长度比,进而确定图表的高宽比。在本例中,假如要求坐标轴不进行扩展,X轴使用的是1至24的数值,跨度为23,Y轴使用103至106.8的数值,跨度为3.8;但即便如此,读者看到的X轴和Y轴在长度上并不会差太多,这是因为R进行了自动调整。如果不进行这一调整,X轴的长度将是Y轴的6倍多,我们将会得到一个扁平的图表,而这并不是我们想要的。可见,自动调整高宽比的功能,有助于我们得到理想的图表。但有时,我们却不希望R进行自动调整,比如,在我们画圆形时,如果R作了调整,那么显示出来的就可能是个椭圆。
我们可以用coord_fixed函数来取消自动调整功能并确定高宽比。参数ratio的默认值为1,其含义是:设窗口中用于显示X轴上一个单位长度的线段长度是a,用于显示Y轴上一个单位长度的线段长度是b,则ratio=b/a。不过要强调的是,这里的所谓高宽比,只是面板部分(即ggplot图表中的灰色矩形)的高宽比;而完整的图表还包含坐标轴、图例等附属元素,不受此高宽比限制。
p+coord_fixed() # 此时显示的将是一个虽然宽和高会随窗口变化,但是高宽比却不相应改变的扁平图表
## 以画正方形为例(本例用到的geom_polygon在后边的章节会讲到)
q=ggplot()+geom_polygon(aes(x=c(0, 1, 1, 0), y=c(0, 0, 1, 1))) # 此时我们看到的,可能是也可能不是正方形,图表高宽比会随窗口大小的改变而改变
q+coord_fixed() # 采用默认值,即ratio=1,此时无论我们怎样改变窗口,正方形都可以正常显示
q+coord_fixed(0.5) # 此时无论怎样改变窗口,正方形左右两边的长度都只会显示为上下两边长度的二分之一
## 既需固定高宽比,又要用coord_flip翻转坐标轴的情况:此时不能同时使用两个coord_fixed和coord_flip,而只能使用theme(aspect.ratio=...)的设置方法。不过,coord_fixed与theme(aspect.ratio=...)的调整机制是不同的,后者并不调整代表单位长度的线段长度比,而是直接确定面板区域的高宽比
xy=data.frame(x=letters[1: 10], y=1: 10) # 假设我们现在需要画一个X轴长度是Y轴长度2倍的条形图
r=ggplot(xy)+geom_bar(aes(x=x, y=y), stat="identity", fill="firebrick")
r+coord_flip(expand=FALSE) # 翻转坐标轴,但未固定高宽比
r+coord_fixed(2, expand=FALSE) # 固定高宽比,但未翻转坐标轴
r+coord_flip(expand=FALSE)+theme(aspect.ratio=2) # 同时产生两种效果
三、方便函数
dat=read.csv("cpi1718.csv", row.names=1)
p=ggplot(dat)+geom_line(aes(1: 24, CPI), size=1)
## 用labs添加各种标题性文字(图3-1-1)
p+labs(title="标题", subtitle="副标题", caption="注释(通常用来标出数据来源)", tag="标记\n例如\n Figure 1", x="X轴标题", y="Y轴标题")+theme(title=element_text(size=20))
图3-1-1 标题性文字
## 用x/ylim调整坐标轴范围
p+xlim(-2, 30)+ylim(100, 110)
p+xlim(-2, 30)+ylim(100, NA) # 只设置坐标轴的一端,另一端设为NA,以便让函数自行设定
## 注意:x/ylim、scale_x/y_*和coord_*这三类函数都可以调整坐标系范围,作图时不要重复使用。x/ylim和scale_x/y_*在调整坐标轴值域时效果是一样的,超出值域的图形将被完全删除
四、颠倒坐标轴、双坐标轴
在实际作图任务中,绘制双坐标轴通常没有实际意义,故在此仅作简单说明。
p=ggplot()+geom_point(aes(1: 5, 1: 5))
p+scale_x_continuous(sec.axis=dup_axis()) # 默认状态下,两条坐标轴完全相同
p+scale_x_continuous(name="first", sec.axis=dup_axis(name="second", breaks=c(2, 4))) # 可单独对每个坐标轴进行设置,dup_axis函数的参数跟scale_x/y_*相同
颠倒坐标轴的用途包括,在散点图中让较大值显示在左边,并让较小值显示在右边;在条形图中让矩形从上往下伸展等等。本章第三节提供了一个颠倒Y轴的图表示例。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。