首页 理论教育 ggplot实战:政经数据可视化

ggplot实战:政经数据可视化

时间:2023-11-19 理论教育 版权反馈
【摘要】:在ggplot系统中,用于调整坐标轴和坐标系的函数有三类,第一类是scale_x/y_*函数,第二类是coord_*函数,第三类是x/ylim、labs等方便函数。ggplot会完全删去超出坐标轴值域的图形,并弹出警告。

ggplot实战:政经数据可视化

在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) # 此时再作图标签就是正常的200000400000……

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_ribbongeom_areageom_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/ylimscale_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轴的图表示例。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈