首页 理论教育 使用ggplot绘制多边形

使用ggplot绘制多边形

时间:2023-11-19 理论教育 版权反馈
【摘要】:无论是什么形状的多边形,只要我们依次给出它的各个顶点,就可以利用geom_polygon把它绘制出来。可见,geom_polygon比那些只能绘制有规律的多边形的函数更加灵活。在本例中,我们通过计算得知第三个顶点的Y坐标为1.732ggplot()+coord_fixed()+geom_polygon+geom_polygon## 通过分组来一次性绘制多个图形dat=rbinddat=data.frameggplot+coord_fixed()+geom_polygon+scale_fill_manual## 另一种分配颜色的方式是aes函数外使用fill参数:矩形有4个顶点,所以要重复4次"purple";三角形有3个顶点,所以要重复3次"orange"ggplot+coord_fixed()+geom_polygonplothelper包中的rotatexy函数可使多边形旋转。

使用ggplot绘制多边形

无论是什么形状的多边形,只要我们依次给出它的各个顶点,就可以利用geom_polygon把它绘制出来。可见,geom_polygon比那些只能绘制有规律的多边形的函数更加灵活。

# install.packages("unikn")

library(unikn) # 使用配色

library(plothelper)

library(ggfittext) # 用于添加文字

library(ggforce) # 使用geom_shape

##绘制矩形和等边三角形

square=data.frame(x=c(0, 4, 4, 0), y=c(0, 0, 2, 2)) # 矩形的四个顶点无需计算即可给出分别是[0, 0][4, 0][4, 2][0, 2]

triangle=data.frame(x=c(0, 2, 1), y=c(0, 0, 1.732)) # 我们有时要通过计算得到顶点的位置在本例中我们通过计算得知第三个顶点的Y坐标为1.732

ggplot()+coord_fixed()+

geom_polygon(data=square, aes(x=x, y=y), fill="purple", color="yellow", linetype=2, size=2)+

geom_polygon(data=triangle, aes(x=x, y=y), fill="orange")

## 通过分组来一次性绘制多个图形

dat=rbind(square, triangle)

dat=data.frame(dat, shape=c(1, 1, 1, 1, 2, 2, 2))

ggplot(dat)+coord_fixed()+

geom_polygon(aes(x, y, fill=factor(shape)))+

scale_fill_manual(values=c("1"="purple", "2"="orange"))

## 另一种分配颜色的方式是aes函数外使用fill参数矩形有4个顶点所以要重复4次"purple"三角形有3个顶点所以要重复3次"orange"

ggplot(dat)+coord_fixed()+

geom_polygon(aes(x, y, group=factor(shape)), fill=c(rep("purple", 4), rep("orange", 3)))

plothelper包中的rotatexy函数可使多边形旋转。

## rotatexy的x参数需使用一个仅有两列的数据框或矩阵第一列为X坐标第二列为Y坐标),如果有多个多边形需要处理就应如本例一样把它们放到列表里,或者把它们合并为一个矩阵并用f参数指定一列数值用来把它们分割开在本例中即为rotatexy(dat[, -3], f=dat$shape, ...)xmiddle和ymiddle用于指定围绕哪个点旋转可以指定一个点或者指定跟多边形一样多的点在本例中矩阵和三角形分别围绕[2, 1]和[0, 0]点旋转angle用于指定角度可以指定一个角度也可以指定跟多边形同样多的角度函数会自动进行分组并生成名为"g"的一列因此在用geom_polygon画图时我们可以把aes函数中的fill等参数指向这一列不过如果在rotatexy中设置group=FALSE则g列不会产生todf参数会使旋转后的多边形合并成单一的数据框如果要保持列表形式可设定

todf=FALSE

dat2=list(square, triangle)

dat2=rotatexy(x=dat2, xmiddle=c(2, 0), ymiddle=c(1, 0), angle=c(pi/4, pi/3)) # 结果包含xyg三列

ggplot(dat2)+coord_fixed()+

geom_polygon(aes(x, y, fill=factor(g)))

plothelper包中的rectxy函数能够一次性生成多个矩形的顶点坐标(图6-31a)。rectxy与geom_tile/rect的区别在于,后者并不会给出顶点坐标,而是会直接把图形画出来。

## rectxy用x和y来指定矩形的位置x和y可以指矩形中心点xytype="middle"默认值)、矩形左边中心点xytype="left"或矩形左下角的顶点xytype="bottomleft")。a和b用于设定矩形的宽和高本例绘制了边长为1和0.7的两个正方形angle用于指定旋转角度此外rectxy还跟rotatexy一样拥有group和todf参数

dat=rectxy(x=c(0, 0.5), y=c(0, -1.1), xytype="middle", a=c(1, 0.7), b=c(1, 0.7), angle=c(0, pi/9))

ggplot(dat)+coord_fixed()+theme_void()+

theme(plot.background=element_rect(colcor=NA, fill="beige"))+

geom_polygon(show.legend=FALSE, aes(x, y, fill=factor(g)),color=NA)+

scale_fill_manual(values=c("1"="black", "2"="red"))

ellipsexy能够一次性生成多个圆形的坐标(图6-3-1b)。

图6-3-1 左=图a 使用rectxy,右=图b 使用ellipsexy

## ellipsexy的xyxytypeangle的使用方法与rectxy相同a和b用来指定椭圆的长半径和短半径如需绘制圆形可设置两个相等的值),n用来指定绘制单个图形时使用的点数

an=seq(0, 7*pi/4, by=pi/4)

a=c(2, 1, 2, 1, 2, 1, 2, 1)

b=c(1, 0.5, 1, 0.5, 1, 0.5, 1, 0.5)

dat=ellipsexy(x=0, y=0, xytype="left", a=a, b=b, angle=an, n=50)

fill=rep(c("red", "blue", "yellow", "gray80"), 2)

names(fill)=1: 8

ggplot(dat)+coord_fixed()+theme_void()+

geom_polygon(show.legend=FALSE, aes(x, y, fill=factor(g)), color="black", size=2)+

scale_fill_manual(values=fill)

使用包括ellipsexy在内的函数可以绘制出一些有趣的抽象图案(图6-3-2)

图6-3-2 用geom_polygon绘制抽象图案

# 生成70个圆环或扇形

nx=7; ny=10; seed=123 # 可修改的三个参数

N=nx*ny

dat=expand.grid(1: nx, 1: ny); colnames(dat)=c("x", "y") # 批量生成中心点

# 生成圆环随机生成起始角度并传递给start和end参数

set.seed(seed); cir_start=runif(N, 0, 2*pi); seed=seed+1

set.seed(seed); cir_end=cir_start+runif(N, pi, 1.5*pi); seed=seed+1

cir=ellipsexy(dat$x, dat$y, a=0.38, b=0.38, start=cir_start, end=cir_end, fan=FALSE)

# 生成扇形

set.seed(seed); fan_start=runif(N, 0, 2*pi); seed=seed+1

set.seed(seed); fan_end=fan_start+runif(N, pi, 1.8*pi); seed=seed+1

fan=ellipsexy(dat$x, dat$y, a=0.25, b=0.25, start=fan_start, end=fan_end, fan=TRUE) # 当fan=TRUE时输出结果用于画扇形而当an=FALSE默认则用于绘制弓形

# 生成颜色

set.seed(seed); cir_color=sample(c("red", "green", "blue", "gray30","yellow"), N, TRUE); seed=seed+1

set.seed(seed); fan_color=sample(c("red", "green", "blue", "gray30","yellow"), N, TRUE)

# 绘制圆环和扇形添加半透明矩形和文字

p1=ggplot()+coord_fixed()+theme_void()+

geom_path(show.legend=FALSE, data=cir, aes(x, y, color= factor(g)), size=1.2)+ # 这里生成有缺口的圆环时不能用geom_polygon而要用geom_path

geom_polygon(show.legend=FALSE, data=fan, aes(x, y, fill= factor(g)))+

scale_color_manual(values=cir_color)+

scale_fill_manual(values=fan_color)

p2=geom_rect(aes(xmin=1-0.2, xmax=7+0.2, ymin=2, ymax=9), fill="white", alpha=0.85)

p3=geom_fit_text(aes(xmin=1, xmax=7, ymin=2, ymax=9, label="The\n32nd\n Olympic\n Games"), grow=TRUE, reflow=FALSE, family="mono", fontface=2)

p1+p2+p3+theme(plot.background=element_rect(fill="cornsilk",color="cornsilk"))

接下来我们用geom_polygon绘制条形图,不过,用来表示数量的图形不再是矩形,而是其他图形。比如,我们希望用看起来像三角形,但又不带顶角的图形代替矩形。这样的图形有很多,我们现在就用简单的正态曲线来绘制(图6-33)。示例中的数据为世界银行发布的营商环境评估的总分数。

图6-3-3 用特殊图形绘制条形图

# 本例将使用unikn包中的一组配色加载后用seecol("all")查看所有配色及其名称

dat=read.csv("business small.csv", row.names=1) # 课件中的文件

v=dat$DB2019 # 分值

lab=dat$Name # 标签

width=1 # 为图形指定宽度

# 首先生成一个基础图形我们最好让这个图形关于Y轴对称因为这样会使对它(www.xing528.com)

进行位移变得方便

x=seq(-3, 3, 0.05)

y=dnorm(x, sd=1) # 读者可尝试用sd参数来调整最终画出的图形

xy=cbind(x, y) # 生成基础图形

# 接下来根据基础图形生成多个条形

n=length(v)

dat=rep(list(xy), times=n)

for (i in 1: n){

# 用rescale调整水平位置水平位置的中心点就是1, 2, 3, ...

dat[[i]][, 1]=scales::rescale(dat[[i]][, 1], to=c(i-width/2, i+width/2))

# 用rescale将图形的Y坐标调整到从0至相应高度的值域中

dat[[i]][, 2]=scales::rescale(dat[[i]][, 2], to=c(0, v[i]))

}

dat=do.call(rbind, dat)

dat=data.frame(dat, g=rep(1: n, each=nrow(dat)/n)) # 添加分组标记

mycolor=seecol(pal=pal_unikn_pref, n=8) # pal=颜色名称名称不要加引号 names(mycolor)=NULL # 务必去掉用seecol函数生成的各个颜色的名称 ggplot(dat)+

geom_polygon(show.legend=FALSE, aes(x, y, fill=factor(g)))+

scale_fill_manual(values=mycolor)+

scale_x_continuous(breaks=1: n, labels=lab)+

labs(title="Business Environment Evaluation")+

theme_minimal()+

theme(

axis.title=element_blank(),

axis.text.y=element_text(size=16),

axis.text.x=element_text(angle=30, size=16, family="mono", face=2, hjust=0.8),

panel.grid.minor.x=element_blank(),

plot.title=element_text(size=22, family="mono", face=2)

)

下面我们来绘制雷达图。雷达图中,用于表示数值大小的部分可看成是一个多边形,相邻的两条连线之间的夹角相等。我们将使用营商便利程度评估数据来展示作图过程(图6-3-4)。

图6-3-4 绘制雷达图

dat=read.csv("db 5dim.csv", row.names=1) # 课件中的文件

nd=ncol(dat) # 项目数

n=nrow(dat) # 国家数

# 我们先写出生成单个雷达图位置的函数在这个函数中r参数是被评估对象在各个维度上的取值x和y是雷达图的中心点输出的多边形的坐标将会按照从pi/2的位置开始顺时针排列

radar_pos=function(r, x=0, y=0){

theta=seq(pi/2, -3*pi/2, length.out=length(r)+1)[1: length (r)]

data.frame(x=r*cos(theta)+x, y=r*sin(theta)+y)

}

# 为查看这个函数的效果我们可以先试着画一个多边形toy=radar_pos(c(2, 1, 2)); ggplot(toy)+geom_polygon(aes(x, y))+coord_fixed()

# 雷达图的四个中心点的坐标

x0=0; y0=0

# 代表1008060分的同心圆

cir=ellipsexy(x=x0, y=y0, a=c(60, 80, 100), b=c(60, 80, 100))

# 将数据框中每行的向量填充到列表中以便让ANYxy函数使用

L=as.list(data.frame(t(dat)))

# 用ANYxy函数生成多边形ANYxy的第一个参数是需用到的函数此处即radar_pos),后边的参数均为这个被用到的函数的参数输出结果中的g列用于分组

ra=ANYxy(myfun=radar_pos, r=L, x=x0, y=y0)

names(ra)[3]="G" # 用于表示数值的多边形所带有的分组编号跟同心圆的分组编号的作用不一样因此这里把第三列的"g"改为"G"

# 设置文字

lab=colnames(dat) # 各维度标签

lab=gsub("\\.", " ", lab) # 将句点变成空格

lab=scales::wrap_format(9)(lab) # 设置每行宽度为9

# 仍然使用ANYxy生成长为100满分为100分的轴线并添加标签

ax=ANYxy(myfun=radar_pos, r=list(rep(100, nd)), x=x0, y=y0, group=FALSE)

ax=data.frame(ax, xend=0, yend=0, lab=lab)

# 用于绘制多边形的ra数据框包含G列我们可以借助这一列及facet_wrap函数把雷达图画到四个分面图中去我们将在第七章介绍这一操作和该操作涉及的theme函数所以现在大家只要知道facet_wrap可用来完成分面操作即可

country=rownames(dat)

names(country)=as.character(1: n) # 为向量中的各项赋予名字是为了使用facet_wrap函数

ggplot()+coord_fixed(xlim=c(-200, 200), ylim=c(-160, 160), expand=FALSE)+

facet_wrap(~G, labeller=labeller(G=country))+

geom_polygon(data=cir, aes(x, y, group=g), fill=NA, color="blue", linetype=3)+

geom_segment(data=ax, aes(x=x, y=y, xend=xend, yend=yend), color="blue", linetype=3.5)+

geom_polygon(show.legend=FALSE, data=ra, aes(x, y, fill=factor(G), color=factor(G)), size=1, alpha=0.6)+

scale_color_manual(values=c("#9b1b30", "#F96714", "#2A4B7C","#797B3A"))+

scale_fill_manual(values=c("#9b1b30", "#F96714", "#2A4B7C","#797B3A"))+

geom_text(data=ax, aes(x=x, y=y, label=lab), lineheight=0.7, vjust="outward", hjust="outward", size=3.5, color="gray10")+

labs(title="Business Environment Evaluation")+

theme_void()+

theme(strip.text=element_text(face=4, hjust=0, size=13, family="mono", margin=margin(2, 2, 2, 2, unit="mm")),

plot.background=element_rect(color=NA, fill="#F3E0BE"),

plot.title=element_text(size=17, hjust=0.5, color="grey10")

)

#==========

# 练习绘制四个角呈弧形的条形图

#==========

# 除geom_polygon外ggforce包中的geom_shape亦可用于绘制多边形我们可用它绘制四个角为弧形而非直角的条形图

library(ggforce)

v=c(1, 2, 3, 5, 4)

dat=rectxy(x=0, y=1: 5, xytype="left", a=v, b=0.8)

ggplot(dat)+geom_shape(aes(x=x, y=y, group=factor(g)), fill="red", radius=unit(5, "mm"))

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

我要反馈