添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
闯红灯的墨镜  ·  Google PageSpeed ...·  1 月前    · 
腹黑的领带  ·  Download Microsoft ...·  4 月前    · 
飞翔的荒野  ·  Testing an activity ...·  6 月前    · 
在数据分析过程中使用基础作图函数可以快速对数据进行概览,因此记住一些常用的基础作图函数是很有用的,比如 plot hist boxplot pie 等函数。R的基础作图函数分为高阶作图函数和低阶作图函数,高阶作图函数能直接作出完整图形,而低阶作图函数只能在已有图形上添加内容。作图函数可以通过一些参数来进行作图效果的修饰:
main sub xlab ylab 参数依次分别设置主标题、副标题、x轴标题、y轴标题;
xlim ylim 分别限定横轴、纵轴的范围;
add 参数确定是否作在前一个作图函数的结果上(默认 add=FALSE ); axes 设定对否画出坐标轴和边框(默认 axes=TRUE ); asp 参数设置y/x的比例。
另外还有一些参数可以通过par(……)来进行全局设置,有的可以直接放到作图函数中。如adj、bg、bty、cex(字体大小)、col(颜色)、font(字体风格)、las、lty(线的类型)、lwd(线的粗细)、mar、mfcol、mfrow、pch(点的类型)、ps、pty、tck、tcl、xaxt、yaxt、等等的,详情查看R的说明文档。
这些参数一般来说了解一下即可 ,通常只用基础作图快速概览,不需要对图进行精细调节。要做出精美的图,还是使用 ggplot2 更顺手和可控一些。 这里以一个身高数据作为示例。
SG <- read.delim("ftp://ftp.biolab.wang/data/height_inheritance.tsv", skip=1, fileEncoding="UTF-8")
head(SG, n=2)
##    序号 性别 年龄 身高 父亲身高 母亲身高
##  1    1   女   18  157      173      160
##  2    2   女   20  155      165      154

高阶作图函数

plot(x, y) 将x映射到横轴,y映射到y轴。可以通过type参数设置图的类型, type=“p” 做散点图( p oint), type=“l” 做折线图( l ine), type=“b” 做折线图加点两者( b oth), type=“o” 也是线加点,但线在点上, type=“c” 也是线加点,但不显示点(也就是线线段之端点不衔接,而折线图线段端点是连接的), type=“h” 做直方图( h istogram), type=“s” 做阶梯图( s teps),数据映射到竖线的顶端, type=“S” 也是阶梯图,但数据映射到竖线的下端, type=“n” 表示不将图plot出来而只是把坐标系绘制出来;
plot(SG$父亲身高, SG$母亲身高, xlab="父亲身高", ylab="母亲身高", main="学生父亲身高与母亲身高对照图")
plot(1:10, 1:10, type="s", xlab="横轴标题", ylab="纵轴标题", main="type=\"s\"")
plot(1:10, 1:10, type="S", xlab="横轴标题", ylab="纵轴标题", main="type=\"S\"")
boxplot 作箱线图(盒形图),在数据分析的时候快速看数据分布情况很方便。 boxplot(y~x) ,命令y映射到纵坐标,按照x来进行分组,x的值作为横坐标; boxplot(x) ,如果x为向量,则x映射到纵坐标,仅展示为一组,如果x是数据框或者矩阵,则每列一个个分组,列标题为横坐标。
boxplot(SG$身高~SG$性别, xlab=NULL, ylab="身高(cm)", col=c("blue", "pink"), main="学生身高调查")
sunflowerplot(x, y) 也是作散点图,但是具有相似坐标的点将会被做成一个带短线(像花一样)的点,由花瓣数代表数据点的个数。
set.seed(2020); X <- sample(1:10, 100, replace=TRUE)
set.seed(2022); Y <- sample(1:10, 100, replace=TRUE)
sunflowerplot(X, Y)
points(x, y) 添加点; lines(x, y) 添加线; text(x, y, labels, …) 添加文字; legend(x, y, legend) 添加图例; axis(side, vect) 添加坐标轴;
plot((SG$父亲身高+SG$母亲身高)/2, SG$身高, type="n", axes=FALSE, xlab="父母平均身高(cm)", ylab="学生身高(cm)")
text((SG$父亲身高+SG$母亲身高)/2, SG$身高, labels=SG$性别, cex=0.5, col=c(="cyan", 女= "purple")[SG$性别])
axis(side=3)
axis(side=4)
ggplot2 是对作图语法的一种极好的实现,加上其强大的 拓展 , 是一个深受喜爱的数据可视化工具。具备一定英文阅读能力的可以阅读ggplot2的作者Hadley Wickham的书 ggplot2: Elegant Graphics for Data Analysis 。我这尝试简要地介绍,以飨初学。
对于数据可视化需要考虑这些要素:用于作图的数据、数据的统计变换、图的类型、变量的视觉映射、映射的标尺、构图元素的位置调整、坐标系统、分面、图的主题风格等等各个方面。ggplot2的作图代码模版如下:
library(ggplot2)
ggplot(data = <数据框>) + 
  <几何函数>(
     mapping = aes(<视觉映射>),
     stat = <统计转换>, 
     position = <位置调整>
  <标尺函数> +
  <坐标系统函数> +
  <分面函数> + 
  <主题风格函数>
data、mapping、stat、position、等等参数放在 ggplot() 函数里则控制为全局,设置到 几何函数 里则控制本几何函数。 几何对象(Geometric object),即图的类型,由geom_开头的 几何函数 定义。几何对象包括:散点图(geom_point)、折线图(geom_line)、柱状图(geom_bar)、直方图(geom_histogram)、盒形图(geom_boxplot)、密度曲线(geom_density)、……
几何对象分为个体几何对象(Individual geoms)和群体几何对象(Collective Geoms),个体几何对象为数据框中的每一行绘制一个图形对象,比如散点图(point geom)将,而群体几何对象将多个观测值展示到一个几何对象。
具体使用的时候,需要知道每个几个对象的适用场景,比如geom_bar默认情况下x和y只需要给的一个参数,默认对其进行计数统计(即 stat=“count” )。比如这里使用柱状图展示两个班级的人数:
默认情况下如果同时给了x和y参数,就会报错:
ggplot(data=data.frame(班级=c("1班", "2班"), 人数=c(32, 23))) + 
    geom_bar(aes(x = 班级, y=人数))
这时候设置 stat=“identity” 则直接使用y作为纵坐标
ggplot(data=data.frame(班级=c("1班", "2班"), 人数=c(32, 23))) + 
    geom_bar(aes(x = 班级, y=人数), stat="identity")

视觉映射 (aes)

视觉映射(Aesthetic mappings) ,一个变量的值可以映射到不同的视觉属性,由几何函数中mapping参数定义。包括:横坐标(x)、纵坐标(y)、颜色(colour)、填充(fill)、透明度(alpha)、形状(shape)、大小(size)、 边框宽度(stroke)、线条类型(linetype)、分组(group)、…… 。不同几何对象能够映射的视觉属性有差异,而不同属性间的叠加也因属性值不同而会有不同。
初学者需要留意的是,这些视觉的元素放在aes函数里的效果是不同的。设定在 aes 里给mapping是以此作为一个变量进行映射,而放在 aes 函数外则是使用其值作为参数。比如自己运行如下两个作图代码试试看点的颜色有何不同,图片还有些什么差异:
ggplot() +  geom_point(mapping=aes(x=1:5, y=1:5, colour="blue"))
ggplot() +  geom_point(mapping=aes(x=1:5, y=1:5), colour="blue")
把“blue”放到aes里,是把它作为一个变量进行了映射,系统默认给映射到了红色,同时还会自动生成了图例。而把“blue”给了aes外边的colour,是设置了点的颜色为“bule”。
(dat <- data.frame(S1=1:5, S2=1:5, C1=letters[1:5], 
  C2=c("blue", "cyan", "green", "pink", "red")))
##    S1 S2 C1    C2
##  1  1  1  a  blue
##  2  2  2  b  cyan
##  3  3  3  c green
##  4  4  4  d  pink
##  5  5  5  e   red
ggplot(dat) + 
  geom_point(aes(x=S1, y=S2, color=C1)) +
  ggtitle("图1")
ggplot(dat) + 
  geom_point(aes(x=S1, y=S2, color=C2)) +
  ggtitle("图2")
ggplot(dat) + 
  geom_point(aes(x=S1, y=S2), color=dat$C2) +
  ggtitle("图3")
统计变换(Statistical transformations),对数据进行的转换,包括本身(stat_identity)、计数(stat_count)、……。统计变换和几何对象有一定的对应关系或者配合关系。
以stat_identity为例,设置可以可以是 stat=“identity” 或者 stat=stat_identity() 的方式,后者可以添加调整的参数,包括mapping指定变量映射以及geom指定几何对象。比如:
ggplot() + 
    stat_identity(
        mapping = aes(x=1:5, y=1:5), 
        geom    = "point")
效果等同于如下代码,都得到右图:
ggplot() + 
    geom_point(
        mapping=aes(x=1:5, y=1:5), 
        stat="identity")

位置调整 (position)

位置调整(Position adjustments),调整图形对象的位置。包括:原位(position_identity)、堆叠(position_stack)、比例堆叠(position_fill,堆叠且柱高归一)、分列(position_dodge)、加噪(position_jitter, 随机微量加减以避免点间重叠)、加噪分列(position_jitterdodge)、偏距(position_nudge,调整指定的距离,常用于是的文字偏离坐标一些)。
设置方式同样有: position=“stack” position=position_stack() 的方式,后者可以指定更多的参数。比如:
ggplot(data=data.frame(班级=c("1班", "1班", "2班", "2班"), 成绩=c("合格", "挂科", "合格", "挂科"), 人数=c(45, 5, 40, 6))) +
    geom_bar(mapping=aes(x=班级, y=人数, fill=成绩), 
             stat="identity",
             position=position_dodge(width=1)) +
    geom_text(mapping=aes(x=班级, y=人数, label=人数, group=成绩), 
             position=position_dodge(width=1), vjust=0)
这里通过设置同样的position参数,是的文字的标记正好出现在柱子的上方。试试看,把这两个width改得不一样会怎么样。这里对text不映射颜色,所以使用了group来进行分组,以便进行dodge排列,如果设置了colour映射则可省group。试试看,如果去掉了group参数会怎么样?
ggplot(data=data.frame(班级=c("1班", "1班", "2班", "2班"), 成绩=c("合格", "挂科", "合格", "挂科"), 人数=c(45, 5, 40, 6))) +
    geom_bar(mapping=aes(x=班级, y=人数, fill=成绩), 
             stat="identity",
             position="stack") +
    geom_text(mapping=aes(x=班级, y=人数, label=人数, group=成绩), 
             position=position_stack(vjust=0.5))
这里使用position_stack,在使用堆叠排列的时候,使得文字和柱子对应,使用vjust使之居中。vjust是纵向上的位置调整,默认值为1。还有一个reverse参数,可使用 ?position_stack 查看了解详情。
ggplot() + 
    geom_line(aes(x=1:10,y=sin(1:10))) +
    scale_x_continuous(limits = c(2.5, 7.5))
而使用coord来设置,则相当于只是截取了图片的这部分,而不影响数据。
ggplot() + 
    geom_line(aes(x=1:10,y=sin(1:10))) +
    coord_cartesian(xlim = c(2.5, 7.5))

分面(facet)

分面(Facet) 根据某些变量将数据分成子集,在针对各个子集分别作图并排列在一个页面,包括:网格型(facet_grid)和封面型(facet_wrap)。 另外也可以使用一些完整的预设主题,比如theme_grey()、theme_bw()、theme_classic()、theme_void()、……。尝试看看个个主题的风格是什么样子的。比如试试:
ggplot() + geom_point(mapping=aes(x=1:5, y=1:5), stat="identity") + theme_classic()
图片另存为pdf时,如果不指定字体,那么汉字无法显示。
pdf("test01.pdf")
plot(x=1, y=1, main="好", sub="I think that's OK")
##  Warning messages:
##  1: In title(...) : 'mbcsToSbcs'里转换'好'出错:<e5>代替了dot
##  2: In title(...) : 'mbcsToSbcs'里转换'好'出错:<a5>代替了dot
##  3: In title(...) : 'mbcsToSbcs'里转换'好'出错:<bd>代替了dot
##  4: In title(...) : 'mbcsToSbcs'里转换'好'出错:<e5>代替了dot
##  5: In title(...) : 'mbcsToSbcs'里转换'好'出错:<a5>代替了dot
##  6: In title(...) : 'mbcsToSbcs'里转换'好'出错:<bd>代替了dot
dev.off()
##  null device 
##            1 

使用GB1字体

这时候可以在pdf设备设置family参数
pdf("test02.pdf", family="GB1")
plot(x=1, y=1, main="好", sub="I think that's OK")
dev.off()
##  null device 
##            1 
也可以在绘图命令中指定family参数
pdf("test03.pdf")
plot(x=1, y=1, main="好", sub="I think that's OK", family= "GB1")
dev.off()
##  null device 
##            1 
可以看到,中文正常显示了,但是英文的显示效果似乎有些不太好。 最简单的是加载showtext包之后执行 showtext_auto() 命令,这样就能自动使用showtext来显示字体,如果不想用showtext了,可以用 showtext_auto(FALSE) 命令关闭。
library(showtext)
showtext_auto(TRUE)
pdf("test04.pdf")
plot(x=1, y=1, main="好", sub="I think that's OK")
dev.off()
##  null device 
##            1 
可以看到,这时候汉字和英文的显示效果都不错,但是这些字无法向文字一样被选择和复制。这里使用了showtext包内置的文泉驿微米黑(WenQuanYi Micro Hei family)字体。
showtext包使用sysfonts包的font_add函数添加的字体,加载showtext的时候,sysfonts包也会被加载。比如,我们这里添加宋体、黑体、楷体、隶书,叫做SHKL。
library(showtext)
showtext_auto(TRUE)
font_add(
  family     = "SHKL",
  regular    = "C:/Windows/Fonts/simsun.ttc",
  bold       = "C:/Windows/Fonts/simhei.ttf",
  italic     = "C:/Windows/Fonts/simkai.ttf",
  bolditalic =  "C:/Windows/Fonts/SIMLI.TTF"
pdf('test05.pdf', height=3, width=7)
plot(c(0,1), c(0.1,0.9), type='n', axes=FALSE, xlab='', ylab='')
text(0.5, 0.8, 'regular(正体) 对应 宋体', family="SHKL", font=1)
text(0.5, 0.6, 'bold(粗体) 对应 黑体', family="SHKL", font=2)
text(0.5, 0.4, 'italic(斜体) 对应 楷体', family="SHKL", font=3)
text(0.5, 0.2, 'bolditalic(粗斜体) 对应 隶书', family="SHKL", font=4)
dev.off()
showtext_auto ( TRUE ) font_add ( family = "宋体" , regular = "C:/Windows/Fonts/simsun.ttc" ) font_add ( family = "黑体" , regular = "C:/Windows/Fonts/simhei.ttf" ) font_add ( family = "楷体" , regular = "C:/Windows/Fonts/simkai.ttf" ) font_add ( family = "隶书" , regular = "C:/Windows/Fonts/SIMLI.TTF" ) pdf ( 'test06.pdf' , height = 3 , width = 2 ) plot ( c ( 0 , 1 ) , c ( 0.1 , 0.9 ) , type = 'n' , axes = FALSE, xlab = '' , ylab = '' ) text ( 0.5 , 0.8 , '这是宋体' , family = "宋体" ) text ( 0.5 , 0.6 , '这是黑体' , family = "黑体" ) text ( 0.5 , 0.4 , '这是楷体' , family = "楷体" ) text ( 0.5 , 0.2 , '这是隶书' , family = "隶书" ) dev. off ( ) 使用grid包的Viewports可以精确地控制图片在页面上的位置。
比如,我们现在有一组数据,记录一些学生的身高以及他们父母的身高。我们用这个数据做三个图,然后将三个图排布在一个页面。
URL <- "ftp://ftp.biolab.wang/data/height_inheritance.tsv";
dat <- read.delim(URL, skip=1, encoding="UTF-8")
library(grid)
library(ggplot2)
library(plyr)
library(ggpubr)
library(reshape)
图一,男女生身高均值比较:
ggplot ( dat01 ) + geom_bar ( aes ( x = 性别, y = Mean, fill = 性别 ) , stat = "identity" ) + geom_errorbar ( aes ( x = 性别, y = Mean, ymin = Mean - SD, ymax = Mean + SD, colour = 性别 ) , width = 0.25 , linewidth = 2 xlab ( NULL ) + ylab ( "Height" ) + scale_x_discrete ( labels = c ( "Male" , "Female" ) ) + scale_y_continuous ( limits = c ( 0 , 200 ) , expand = c ( 0 , 0 ) ) + theme_classic ( ) + theme ( legend. position = "none" ) 图二,男生身高对父母平均身高的回归直线:
aes ( x = 父母平均身高, y = 身高 ) ) + geom_point ( ) + geom_smooth ( method = 'lm' , formula = y~x, se = FALSE ) + ggpubr :: stat_regline_equation ( aes ( label = paste ( "~" , after_stat ( eq. label ) , after_stat ( rr. label ) , sep = "~~~~" ) ) , formula = y~x, size = 3 , label. x . npc = 0.1 , label. y . npc = 0.1 scale_x_continuous ( limits = c ( 150 , 175 ) , expand = c ( 0 , 0 ) , breaks = seq ( 150 , 175 , 5 ) ) + scale_y_continuous ( limits = c ( 150 , 190 ) , expand = c ( 0 , 0 ) , breaks = seq ( 150 , 190 , 5 ) ) + xlab ( "Midparental Height" ) + ylab ( "Height" ) + theme_classic ( ) + theme ( ) 图三,亲代和子代身高分布图,区分性别:
dat03 <- dat[ , c("序号", "性别", "身高")]
dat03$代次 <- "子代"
dat04 <- dat[ , c("序号", "父亲身高", "母亲身高")]
names(dat04)[2:3] <- c("男", "女")
dat04 <- reshape::melt(dat04, id=1)
names(dat04)[2:3] <- c("性别", "身高")
dat04$代次 <- "亲代"
dat05 <- rbind(dat03, dat04)
ggplot(dat05) +
  geom_boxplot(aes(x=性别, y=身高, colour=代次)) +
  scale_y_continuous(limits=c(140, 190),
    expand=c(0, 0), breaks=seq(140, 190, 5)) +
  scale_x_discrete(labels=c("Male", "Female")) +
  xlab(NULL) +
  ylab("Height") +
  theme_classic() +
  theme(legend.position=c(1, 1),
    legend.justification=c(1, 1),
    legend.box.background = element_blank(),
    legend.key = element_blank()
图片排版,将图二排在左边的2/3的页面,右边的1/3的页面上半部分排图一,下半部分排图三。
grid.newpage()   # 打开一个新的页面,当前视窗为整个页面
vp <- viewport(x=1/3, y=1/2, width=2/3, height=1)
pushViewport(vp) # 进入子视窗,然后当前视窗为vp指定的区域
grid.draw(ggplotGrob(g2))   
grid.text("A", x=0, y=1, hjust=0, vjust=1, 
  gp=gpar(fontsize=15, col="blue"))
upViewport()    # 做完图之后,回到父视窗,又回到了整个页面
vp <- viewport(x=5/6, y=3/4, width=1/3, height=1/2)
pushViewport(vp)
grid.draw(ggplotGrob(g1))
grid.text("B", x=0, y=1, hjust=0, vjust=1, 
  gp=gpar(fontsize=15, col="blue"))
upViewport()
vp <- viewport(x=5/6, y=1/4, width=1/3, height=1/2)
pushViewport(vp)
grid.draw(ggplotGrob(g3))
grid.text("C", x=0, y=1, hjust=0, vjust=1, 
  gp=gpar(fontsize=15, col="blue"))
upViewport()
vp ← viewport(x=5/6, y=1/4, width=1/3, height=1/2)中的x和y是子视窗(Viewport)中心在父视窗中的位置,1/2就是中心处;而width和height是子视窗相对于父视窗的宽度和高度。pushViewport进入到当前视窗的子视窗,而upViewport则回到当前视窗的父视窗。 先告诉R Ghostscript的安装路径,这个根据自己实际来决定,比如我这里安装在D盘,使用的是64位的:
Sys.setenv(R_GSCMD="D:/Program/gs/gs9.18/bin/gswin64.exe")
然后直接使用embedFonts函数即可。
embedFonts(file="file_name.pdf", outfile = "new_file_name.pdf")