R语言数据可视化教程(ggplot2)_坐标轴设置

时间:2021-11-24 05:57:29
# 8.坐标轴
# 8.1交换x轴和y轴
# 使用coord_flip()来翻转坐标轴
library(ggplot2)
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+coord_flip()
# 如果x变量是一个因子型变量,则排列顺序可以通过使用scale_x_discrete()和参数limits=rev(levels(...))进行反转
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+coord_flip()+scale_x_discrete(limits=rev(levels(PlantGrowth$group)))


# 8.2设置连续型坐标轴的值域
# 可以使用xlim()和ylim()来设置一条连续型坐标轴的最小值和最大值
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
# 显示图形
p
p +ylim(0,max(PlantGrowth$weight))
# 使用ylim()来设定范围是通过scale_y_continuous()来设定范围的简便写法(对于xlim()和scale_x_continuous()同理)
# 以下两种表达方式等价:
ylim(0,10)
scale_y_continuous(limits = c(0,10))
# 有时需要设定scale_y_continuous()的其他属性,在这些情况下同时使用ylim()和scale_y_continuous()可能会让程序产生一些不可预知的行为,这是因为只有命令中的后一条会生效
# 示例如下,仅有第二条命令生效
p+ylim(0,10)+scale_y_continuous(breaks = c(0,5,10)) # 将刻度线放在0,5,10的位置
p+scale_y_continuous(breaks = c(0,5,10))+ylim(0,10)
# 要让两项修改均生效,舍弃ylim()并直接在scale_y_continuous()中同时设定limits和breaks即可
p+scale_y_continuous(limits = c(0,10),breaks = c(0,5,10))


# ggplot2中有两种设置坐标轴值域的方式,第一种方式是修改标度,第二种方式是应用一个坐标变换。
# 当你修改x标度和y标度的范围时,任何在范围以外的数据都会被移除


# 通过使用坐标变换,数据则不会被修剪;从本质上说,它只是将数据放大或缩小到指定的范围
p+scale_y_continuous(limits = c(5,6.5)) # 与使用ylim()相同
p+coord_cartesian(ylim = c(5,6.5))
# 最后,通过使用expand_limits()来单向扩展值域也是可以的,但是不能使用它来缩减值域
p+expand_limits(y=0)


# 8.3 反转一条连续型坐标轴
# 使用scale_y_reverse或scale_x_reverse(),坐标轴的方向也可以通过指定反序的范围来反转,先写最大值,再写最小值
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_y_reverse()
#通过指定反序的范围产生类似的效果
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+ylim(6.5,3.5)


# 与scale_y_continuous()类似,scale_y_reverse()也无法与ylim配合工作
# 如果希望反转某条坐标轴并为它设定值域,则必须通过反序设定范围的方式,在scale_y_reverse()语句内完成
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_y_reverse(limits=c(8,0))


# 8.4修改类别型坐标轴上项目的顺序
# 对于类别型(或者说离散型)坐标轴来说,会有一个因子型变量映射到它上面,坐标轴上项目的顺序可以通过设定scale_x_discrete()或scale_y_discrete()中的参数limits来修改
# 要手动设定坐标轴上项目的顺序,将一个依理想顺序排列的水平向量指定给limits即可。也可以使用这个向量来忽略某些项目
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
p+scale_x_discrete(limits=c("trt1","ctrl","trt2"))


# 也可以使用以上方法展示项目的子集:
p+scale_x_discrete(limits=c("ctrl","trt1"))
# 要反转项目顺序,设定limits=rev(levels(...)),将因子型变量放在括号中即可。
p + scale_x_discrete(limits=rev(levels(PlantGrowth$group)))


# 8.5设置x轴和y轴的缩放比例
# 使用coord_fixed()
# 以下代码将得到x轴和y轴之间1:1的缩放效果
library(gcookbook)
sp <- ggplot(marathon,aes(x=Half,y=Full))+geom_point()
sp + coord_fixed()


# 通过在scale_y_continuous()和scale_x_continuous()中调整参数breaks,从而将刻度间距设为相同
sp + coord_fixed()+ scale_y_continuous(breaks = seq(0,420,30))+scale_x_continuous(breaks = seq(0,420,30))


# 如果希望为两个坐标轴之间指定其他的固定比例而非相同的比例,可以设置参数ratio。
sp + coord_fixed(ratio = 1/2) + scale_y_continuous(breaks = seq(0,420,30))+scale_x_continuous(breaks = seq(0,420,15))


# 8.6 设置刻度线的位置
# 通常来说ggplot()会自动将刻度线摆放在合适的位置,但如果希望改变他们的位置,设置标度中的参数breaks即可
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_y_continuous(breaks = c(4,4.25,4.5,5,6,8))


# 刻度线的位置决定了绘制主网格线的位置。如果该坐标轴表示一个连续型变量,那么颜色更暗且没有标签的次网格线将被默认绘制在每两个主网格线的正中间位置。
# 使用seq()函数或运算符:来生成刻度线的位置向量
seq(4,7,by=.5)
5:10
# 如果坐标轴是离散的而不是连续型的,则默认会为每个项目生成一条刻度线。
# 对于离散型坐标轴,可以通过指定limits来修改项目的顺序或移除项目。
# 设定breaks将会决定为哪些水平加上标签,但不会移除它们或是改变他们的顺序
# 为离散型坐标轴同时设定breaks和limits
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_x_discrete(limits=c("trt2","ctrl"),breaks="ctrl")


# 8.7 移除刻度线和标签
# 使用theme(axis.text.y=element_blank()),也可对axis.text.x做相同处理,对于连续型和离散型坐标轴均有效
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
p + theme(axis.text.y = element_blank())


# 要移除刻度线,可使用theme(axis.ticks=element_blank()).这样将会同时移除两轴的刻度线
 p + theme(axis.ticks = element_blank(),axis.text.y = element_blank())
 
# 要移除刻度线、刻度标签和网格线,将breaks设置为NULL即可
p +scale_y_continuous(breaks = NULL) 
# 这种方法仅对连续型坐标轴有效
# 事实上,共有三种项目可以控制:刻度标签,刻度线和网格线,对于连续型坐标轴,ggplot()通常会在每个breaks值得位置放置刻度线、刻度标签和主网格线。
# 对于类别型坐标轴,这些元素则出现在每个limits值的位置。
# 我们可以独立控制每条坐标轴上的刻度标签。但是,刻度线和网格线必须同时控制。
# 8.8 修改刻度标签的文本
library(gcookbook)
hwp <- ggplot(heightweight,aes(x=ageYear,y=heightIn))+geom_point()
hwp
# 任意设定标签,在标度中为breaks和labels赋值即可。
hwp + scale_y_continuous(breaks=c(50,56,60,66,72),labels = c("Tiny","Really\nshort","Short","Medium","Tallish"))


# 定义一个格式刷(formatter)函数,这样的函数可以读入数值并返回相应的字符串
# 以下函数将英寸数值转换为英尺加英寸的格式:
footinch_formatter <- function(x){
  foot <- floor(x/12)
  inch <- x%%12
  return(paste(foot,"'",inch,"\"",sep=""))
}
footinch_formatter(56:64)
# 使用参数labels将我们的函数传递给标度
hwp+scale_y_continuous(labels = footinch_formatter)
# 通过指定参数breaks让ggplot()每隔四英寸设置一条刻度线取而代之
hwp + scale_y_continuous(breaks = seq(48,72,4),labels = footinch_formatter)


# 将时间测度转换为HH:MM:SS(时:分:秒)或者其他类似的格式。
timeHMS_formatter <- function(x){
  h <- floor(x/60)
  m <- floor(x%%60)
  s <- round(60*(x%%1)) # 舍入到最接近的秒数
  lab <- sprintf("%02d:%02d:%02d",h,m,s) # 格式化字符串为HH:MM:SS的格式
  lab <- gsub("^00:","",lab)  # 如果开头存在00: 则移除
  lab <- gsub("^0","",lab)  # 如果开头存在0 则移除
  return(lab)
}
timeHMS_formatter(c(.33,50,51.25,59.32,60,60.1,130.23))
# 随ggplot2()安装的scales包自带了一些内建的格式化函数
# comma()在千、百万、十亿等位置向数字添加逗号
# dollar()添加一个美元符号并舍入到最接近的美分
# percent()乘以100,舍入到最接近的整数值,并添加一个百分号
# scientific()对大数字和小数字给出科学计数法表示。
# 要使用这些函数,必须首先使用library(scales)加载scales包


# 8.9 修改刻度标签的外观
bp <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_x_discrete(breaks=c("ctrl","trt1","trt2"),labels=c("Control","Treatment 1","Treatment 2"))
bp
# 将文本逆时针旋转90°
bp+theme(axis.text.x = element_text(angle = 90,hjust = 1,vjust = .5))
# 将文本旋转30°
bp+theme(axis.text.x = element_text(angle = 30,hjust = 1,vjust = 1))
# 参数hjust和vjust设置了横向对齐(左对齐、居中、右对齐)和纵向对齐(顶部对齐/居中/底部对齐)


# 除了旋转以外,其他的文本属性,如大小、样式(粗体/斜体/常规)和字体族(如Times和Helvetica)可以使用element_text()进行设置
bp +theme(axis.text.x = element_text(family = "Times",face = "italic",colour = "darkred",size = rel(0.9)))
# size(文字大小)被设为rel(0.9),意为当前主体基础字体大小的0.9倍
# 这些命令仅仅控制了单个坐标轴刻度标签的外观,并不影响其他坐标轴、坐标轴标签、整体的标题或图例
# 要控制所有这些元素的外观,可以使用主题系统


# 8.10修改坐标轴标签的文本
# 使用xlab()或ylab()来修改坐标轴标签的文本
library(gcookbook)
hwp <- ggplot(heightweight,aes(x=ageYear,y=heightIn,colour=sex))+geom_point()
# 使用默认的坐标轴标签
hwp
# 设置坐标轴标签
hwp+xlab("Age in years")+ylab("Height in inches")
# 默认情况下,图形将直接使用数据框中的列名作为坐标轴标签。
# 也可以使用labs()
hwp + labs(x="Age in years",y="Height in inches")
# 设置坐标轴标签的另一种方法是在标度中指定
hwp+scale_x_continuous(name = "Age in years")
# 这种方法同样适用于其他的坐标轴标度,如scale_y_continuous()、scale_x_discrete()等
# 还可以使用\n来添加换行
hwp +scale_x_continuous(name = "Age\n(Years)")


# 8.11移除坐标轴标签
# 对于x轴标签,使用theme(axis.title.x=element_blank())。对于y轴标签,针对axis.title.y处理
# 隐藏x轴标签
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
p + theme(axis.title.x = element_blank())
# 移除坐标轴标签的另一种方法是将其设定为一个空字符串。但如果以这种方式去做,那么图中将仍为文本留出空间
p + xlab("")
# 当使用theme()来设置axis.title.x=element_blank()时,x或y标度的名称是不会改变的,只是这样不会显示文本而且不会为其留出空间。
# 当你设置标签为“"时,标度的名称就改变了,并且实际上显示了(空白的)文本


# 8.12 修改坐标轴标签的外观
# 要修改x轴标签的外观,使用axis.title.x即可
library(gcookbook)
library(ggplot2)
hwp <- ggplot(heightweight,aes(x=ageYear,y=heightIn))+geom_point()
hwp + theme(axis.title.x = element_text(face = "italic",colour="darkred",size=14))


# 对于y轴标签来说,有时不对文本进行旋转会比较有用
# 标签中的\n表示另起一行
hwp + ylab("Height\n(inches)")+theme(axis.title.y = element_text(angle = 0,face = "italic",size = 14))
# 调用element_text()时,默认的角度是0,如果设置了axis.title.y但没有指定这个角度,它将以文本的顶部指向上方的朝向显示。
# 如果修改了axis.title.y中的其他任何属性并且希望它以正常朝向,即旋转90°显示,则必须手动指定这个角度
hwp + ylab("Height\n(inches)")+theme(axis.title.y = element_text(angle = 90,face="italic",colour = "darkred",size=14))
# 8.13沿坐标轴显示直线
# 使用主题设置中的axis.line
library(gcookbook)
p <- ggplot(heightweight,aes(x=ageYear,y=heightIn))+geom_point()
p + theme(axis.line = element_line(colour = "black"))


# 如果最初使用的主题在绘图区域的周围就有一条边,则需要同时重置参数panel.border
p + theme_bw()+theme(panel.border = element_blank(),axis.line = element_line(colour = "black"))
# 如果边界线比较粗,则它们的末端将仅会部分地重叠,要让它们完全重叠,设置lineend="square"即可
# 对于较粗的线条,只有一半重叠
p + theme_bw()+theme(panel.border = element_blank(),axis.line = element_line(colour = "black",size = 4))
# 完全重叠
p + theme_bw()+ theme(panel.border = element_blank(),axis.line = element_line(colour = "black",size = 4,lineend = "square"))


# 8.14 使用对数坐标轴
# 使用scale_x_log10()和/或scale_y_log10()
library(MASS)
# 基本图形
p <- ggplot(Animals,aes(x=body,y=brain,label=rownames(Animals)))+geom_text(size=3)
p
# 使用对数x标度和对数y标度
p + scale_x_log10()+scale_y_log10()
# 使用对数坐标轴时,视觉上某段给定的距离表示着常数倍的比例改变
# 使用线性坐标轴时,视觉上某段给定的距离表示着常数单位数量的改变


# 某些数据集在x轴上是呈指数分布的,而另一些则是在y轴上呈指数分布(或者两轴皆是)
Animals
10^(0:3)
10^(-1:3)
p + scale_x_log10(breaks=10^(-1:5))+scale_y_log10(breaks=10^(0:3))


# 要让刻度线标签转而使用指数计数法,只要使用scales包中的函数trans_format()即可
library(scales)
p + scale_x_log10(breaks=10^(-1:5),labels=trans_format("log10",math_format(10^.x)))+scale_y_log10(breaks=10^(0:3),labels=trans_format("log10",math_format(10^.x)))
# 使用对数坐标轴的另一种方法是,在将数据映射到x和y卓彪之前,先对其进行变换
# 坐标轴仍然是线性的——它表示对数变换后的数值
ggplot(Animals,aes(x=log10(body),y=log10(brain),label=rownames(Animals)))+geom_text()


library(scales)
# 对x使用自然对数变换,对y使用log2变换
p + scale_x_continuous(trans = log_trans(),breaks = trans_breaks("log",function(x) exp(x)),labels = trans_format("log",math_format(e^.x)))+scale_y_continuous(trans = log2_trans(),breaks = trans_breaks("log2",function(x) 2^x),labels = trans_format("log2",math_format(2^.x)))


# 默认的刻度线间距可能不够好,可以在标度中使用参数breaks来设置它们
library(gcookbook)
ggplot(aapl,aes(x=date,y=adj_price))+geom_line()
ggplot(aapl,aes(x=date,y=adj_price))+geom_line()+scale_y_log10(breaks=c(2,10,50,250))
# 8.15 为对数坐标轴添加刻度
# 使用annotation_logticks()
library(MASS)
library(scales)
library(ggplot2)
ggplot(Animals,aes(x=body,y=brain,label=rownames(Animals)))+geom_text(size=3)+annotation_logticks()+scale_x_log10(breaks = trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)))+scale_y_log10(breaks=trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)))
# 使用annotation_logticks()创建的刻度线事实上是绘图区域中的几何对象
# 使用theme_bw()让刻度线和网格线的颜色更协调一些
# 默认情况下,次网格线在视觉上出现在两条主网格线的正中间,但这与对数标度下表示“5”的刻度线位置并不相同。
# 要让两者位置相同,可以手动设置标度的minor_breaks参数
ggplot(Animals,aes(x=body,y=brain,label=rownames(Animals)))+geom_text(size=3)+annotation_logticks()+scale_x_log10(breaks = trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)),minor_breaks=log10(5)+ -2:5)+scale_y_log10(breaks=trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)),minor_breaks=log10(5)+ -1:3)+coord_fixed()+theme_bw()
# 所谓5的位置,是指前一个长刻度线对应数值5倍的位置
# 8.16 绘制环状图形
# 使用coord_polar()
library(gcookbook)
wind
ggplot(wind,aes(x=DirCat,fill=SpeedCat))+geom_histogram(binwidth = 15,origin=-7.5)+coord_polar()+scale_x_continuous(limits = c(0,360))
# 使用极坐标图时要小心,因为这种图形会扭曲对数据的感知
# 通过反转图例、使用不同的调色板、添加外框线以及将分割点设置为某些更熟悉的值得方式,让图形稍微美观一些
ggplot(wind,aes(x=DirCat,fill=SpeedCat))+geom_histogram(binwidth = 15,origin=-7.5,colour="black",size=.25)+guides(fill=guide_legend(reverse = TRUE))+coord_polar()+scale_x_continuous(limits = c(0,360),breaks = seq(0,360,by=45),minor_breaks = seq(0,360,by=15))+scale_fill_brewer()
# 使用参数start设置图形起始的角度可能也是有用的,特别是当我们使用一个离散型变量映射为角度(theta)时。
# 起始角度的值以弧度计,如果知道要调整的角度,则必须将它转换为弧度:
coord_polar(start = -45*pi/180)
# 默认情况下,对于映射到y(或者说r)的变量,最小值将被映射到中心;换句话说,数据中的最小值将被映射到视觉上半径为0的位置。
# 如果希望一个为0的数据值被映射到半径为0的位置,为了确保图形能这样绘制,需要设置对应的界限(limit)
# 在使用一个连续型的x(或者说theta)时,数据中的最小值和最大值是重合的。有时这样是可取的,有时却不是。要修改这种默认行为,需要设置对应的界限
# 极坐标的theta值不能环绕一周
# 将mdeaths的时间序列数据放入一个数据框
md <- data.frame(deaths = as.numeric(mdeaths),month = as.numeric(cycle(mdeaths)))
# 计算每个月的平均死亡数量
library(plyr)
md <- ddply(md,"month",summarise,deaths=mean(deaths))
md
# 绘制基本图形
p <- ggplot(md,aes(x=month,y=deaths))+geom_line()+scale_x_continuous(breaks = 1:12)
# 使用coord_polar
p + coord_polar()
# 通过设置y(或者说r)的界限为从0到数据中的最大值来解决这个问题
# 使用coord_polar并将y(r)的下届设置为0
p+coord_polar()+ylim(0,max(md$deaths))
# 设置x的界限为0~12
p + coord_polar()+ylim(0,max(md$deaths))+xlim(0,12)
# 首尾不相接的问题。需要修改数据框,添加一个月份为0,对应值与12月相同的行
# 通过添加一个值与12的值相同的0来连接曲线
mdx <- md[md$month==12,]
mdx$month <- 0
mdnew <- rbind(mdx,md)


# 通过使用%+%,绘制与之前相同的图形,只是使用的数据不同
p %+%mdnew+coord_polar()+ylim(0,max(md$deaths))
# 注意运算符%+%的使用,当你使用%+%向一个ggplot对象添加一个数据框时,它会替换ggplot对象中的默认数据框
# 8.17 在坐标轴上使用日期
# 将一列类为Date的变量映射为x轴或y轴即可。
# 观察数据结构
str(economics)
ggplot(economics,aes(x=date,y=psavert))+geom_line()
# ggplot2可以处理两类时间相关的对象,日期对象(类为Date的对象)和日期时间对象(类为POSIXt的对象)。
# 两类对象的区别是,Date对象表示的是日期,分辨率为一天,而POSIXt对象则表示时刻,拥有精确到秒的小数部分的分辨率
# 设置分割点与数值坐标轴的方式类似——主要的不同在于设置所要使用的日期序列
# 如果未设置分割点,则将自动选择
# 取economics的一个子集
econ <- subset(economics,date >= as.Date("1992-05-01") & date < as.Date("1993-06-01"))
# 基本图形——不指定分割点
p <- ggplot(econ,aes(x=date,y=psavert))+geom_line()
p
# 分割点可使用函数seq()来创建,给定起始和终止日期和一个步长区间
# 指定一个日期向量为分割点
datebreaks <- seq(as.Date("1992-06-01"),as.Date("1993-06-01"),by="2 month")
# 使用分割点并旋转文本标签
p + scale_x_date(breaks = datebreaks)+theme(axis.text.x = element_text(angle = 10,hjust = 1))
# 可以通过使用scales包中的date_format()函数来指定分割点(标签)的格式
library(scales)
p + scale_x_date(breaks = datebreaks,labels=date_format("%Y %b"))+theme(axis.text.x = element_text(angle = 30,hjust = 1))
# %Y:含世纪的年份(2012)
# %y:不含世纪的年份(12)
# %m:十进制数表示月份(08)
# %b:当前区域设置(locale)的月份名缩写(Aug)
# %B:当前区域设置的月份名全称(August)
# %d:十进制数表示的月份中的日期(04)
# %U:十进制数表示的一年中的第几周,星期日作为每周的第一天(00-53)
# %W:十进制数表示的一年中的第几周,星期一作为每周的第一天(00-53)
# %w:星期几(0-6,星期日为0)
# %a:星期几的缩写名(Thu)
# %A:星期几的全称(Thursday)
# 以上选型中的一部分依赖于计算机的区域设置(locale)。月份和日期在不同的语言中会有不同的名称
# 可以使用Sys.setlocale()来修改区域设置
# Windows
# Sys.setlocale("LC_TIME","italian")
# 8.18在坐标轴上使用相对时间
# 时间值通常以数字的形式存储。时间也能从某个起始时间经过的分钟数或秒数来存储。这些情况下,可以将一个值映射到x轴或y轴上,并使用一个格式刷来生成合适的坐标轴标签
# 转换时间序列对象WWWusage为数据框
www <- data.frame(minute = as.numeric(time(WWWusage)),users=as.numeric(WWWusage))
# 定义一个格式刷函数——可将以分钟表示的时间转换为字符串
timeHM_formatter <- function(X){
  h <- floor(x/60)
  m <- floor(x %% 60)
  lab <- sprintf("%d:%02d",h,m) #将字符串格式化为HH:MM(时:分)的格式
  return(lab)
}
# 默认的x轴
ggplot(www,aes(x=minute,y=users))+geom_line()
# 使用格式化后的时间
ggplot(www,aes(x=minute,y=users))+geom_line()+scale_x_continuous(name="time",breaks = seq(0,100,by=10),labels = timeHM_formatter())
# 手动设置分割点和标签
scale_x_continuous(breaks = c(0,20,40,60,80,100),labels = c("0:00","0:20","0:40","1:00","1:20","1:40"))
# 使用函数timeHM_formatter()来讲数值时间(以分钟表示)转换为一个类似于“1:10”的字符串
timeHM_formatter(c(0,50,51,59,60,130,604))
timeHMS_formatter(c(20,3000,3075,3559.2,3600,3606,7813.8))