如果我们只希望在面板上添加背景,那么使用annotation_raster即可。
library(cowplot) # 需使用ggdraw、draw_plot函数
library(plothelper)
library(scales)
library(magick)
library(readxl) # 读取 Excel文件
library(RColor Brewer) # 使用配色
# 处理图片
img=image_read("two soldiers.jpg") # 课件中的图片
img=image_resize(img, "60%x60%") # 适当缩小图片尺寸
img=image_convert(img, colorspace="gray") # 如有需要,可将图片转化为黑白图片
# 先在最底层添加图片,再添加其他图层
ggplot()+annotation_raster(img, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)+
geom_point(aes(1: 10, 1: 10), color="red", size=5)
不过,更常见的情况是,我们希望让图片充当整个图表的背景,我们以美国各年度军费数据为例进行说明(图7-2-1)。
dat=read_excel("us military.xlsx") # 课件中的文件
dat=as.data.frame(dat)
# 第一步:通过annotation_raster添加图片并生成背景图层
# 为防止图片颜色与其他图层的颜色混在一起,我们在图片上添加一个半透明矩形(此操作亦可通过magick::image_colorize完成)
white=matrix(alpha("white", 0.5))
bg=ggplot()+theme_void()+
annotation_raster(raster=img, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)+
annotation_raster(raster=white, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)
# 第二步:生成呈现数据的图层。注意:要确保面板背景色和整个图表的背景色被去除,否则背景图片不会显露出来
yearlab=seq(1960, 2018, 5)
valuepos=pretty(dat$Value)
valuelab=valuepos/(10^9)
p=ggplot(dat)+
geom_line(aes(Year, Value), color="orangered", size=1.2, alpha=0.7)+
geom_point(aes(Year, Value), color="orangered", size=1.5)+
scale_x_continuous(breaks=yearlab)+
scale_y_continuous(breaks=valuepos, labels=valuelab)+
labs(title="US Military Expenditure\n(unit: billion current$)")+
theme_minimal()+
theme(
plot.title=element_text(size=25, color="darkgreen", family="serif", face=3),
axis.title=element_blank(),
axis.text=element_text(color="darkgreen", face=3, size=14, family="serif"),
axis.text.x=element_text(angle=20),
panel.grid=element_line(color="darksalmon"),
panel.grid.minor.x=element_blank(),
panel.grid.minor.y=element_blank()
)
# 第三步:用ggdraw()+draw_plot(...)的方式合并
ggdraw()+draw_plot(bg)+draw_plot(p, width=0.8, height=0.8, x=0.1, y=0.1)+theme(aspect.ratio=0.7)
# draw_plot用四个参数控制被添加图层的位置:x和y是被添加图层的左下角的坐标,width和height是宽和高
图7-2-1 将图片设置为背景
我们还可以将渐变色设为背景,以绘制条形图为例进行示范(图7-2-2)。
dat=read.csv("buy.csv", row.names=1) # 前面的章节使用过的文件
# 整理数据
tab=table(dat$Item, dat$Age)
dat=as.data.frame(tab)
colnames(dat)=c("Item", "Age", "Number")
图7-2-2 将渐变色设为背景
# 第一步:生成渐变色
m=c("#EF4868", "#F56B50", "#F48C48", "#F1A955", "#EEC274")
m=color Ramp Palette(m, space="Lab")(30)
m=matrix(m, nrow=1)
bg=ggplot()+annotation_raster(m, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf, interpolate=TRUE)+theme_void()
# 第二步:生成呈现数据的图层
p=ggplot(dat)+
geom_bar(aes(x=Item, y=Number, alpha=Age), stat="identity", fill="white", position=position_dodge(width=0.6), width=0.5)+
scale_alpha_manual(values=c(0.3, 0.6, 0.9))+
labs(title="Wine Preferences of Different Ages\n\n")+
theme_void()+
theme(
panel.grid.major.y=element_line(color="grey92"),
axis.text=element_text(color="white", face=2, size=20,family="mono"),
legend.position="bottom",
legend.box.spacing=unit(1, "cm"),
legend.title=element_text(color="white", family="mono", size=25),
legend.text=element_text(color="white", family="mono", size=18),
plot.title=element_text(color="white", size=22, family="mono", face=2, hjust=0.5)
)
# 第三步:合并
ggdraw()+draw_plot(bg)+draw_plot(p, width=0.8, height=0.8, x=0.1, y=0.1)+theme(aspect.ratio=0.6)
#==========
# 练习:添加半透明渐变色
#==========
# 我们继续使用上例中的图层进行示范
wine=image_read("red wine.jpg") # 课件中的图片
# 同时以图片和渐变色为背景(图7-2-3)
n_each_col=50
grey=matrix("grey15", nrow=6, ncol=n_each_col)
grey[2, ]=rainbow(n_each_col, end=5/6)
grey=apply(grey, 2, FUN=function(x) alpha(color Ramp Palette(x)(30), 0.7))
bg2=ggplot()+theme_void()+
annotation_raster(raster=wine, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)+
annotation_raster(raster=grey, xmin=-Inf, xmax=Inf, ymin=-Inf,ymax=Inf, interpolate=TRUE)
ggdraw()+draw_plot(bg2)+draw_plot(p, width=0.8, height=0.8, x=0.1, y=0.1)+theme(aspect.ratio=0.6)
图7-2-3 同时以图片和渐变色为背景
# 在最上层添加半透明渐变色(图7-2-4)
wine_black=image_colorize(wine, opacity=60, color="black") # 用半透明矩形覆盖
bg3=ggplot()+theme_void()+
annotation_raster(raster=wine_black, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)
n_each_row=90
seq_alpha=seq(0.6, 0.05, length.out=n_each_row)
upper=color Ramp Palette(c("blue", "white", "red"))(30)
upper=rep(list(upper), n_each_row)
upper=do.call(cbind, upper)
upper=t(apply(upper, 1, alpha, alpha=seq_alpha))
upper=ggplot()+annotation_raster(raster=upper, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf, interpolate=TRUE)+theme_void()
ggdraw()+draw_plot(bg3)+draw_plot(p, width=0.8, height=0.8, x=0.1, y=0.1)+theme(aspect.ratio=0.6)+draw_plot(upper)
图7-2-4 在图表最上层添加半透明渐变色
#==========
# 练习:利用有特定功能的函数生成背景
#==========
# 本例继续使用上例中的图层进行示范,介绍如何将维诺图(Voronoi diagram)和网络图设置为背景。感兴趣的读者可自行学习这两种图表的绘制方法
# 在维诺图中,多边形中各点到其内部生成点的距离,小于到其他生成点的距离。不过本例并不用维诺图来呈现任何数据,只是让随机生成的图形充当背景(图7-25a)
install.packages("ggvoronoi")
library(ggvoronoi) # 使用geom_voronoi
n=180 # 生成点的个数
set.seed(1); xpos=runif(n, 0, 10) # 随机产生多边形的生成点的坐标
set.seed(2); ypos=runif(n, 0, 5)
set.seed(3); rdcolor=sample(1: 2, n, TRUE) # 2个取值对应于后面将使用的2个颜色
set.seed(4); rdalpha=runif(n)
bg4=ggplot()+theme_void()+coord_cartesian(expand=FALSE)+
geom_voronoi(show.legend=FALSE, aes(x=xpos, y=ypos, fill= factor(rdcolor), alpha=rdalpha), color=NA)+
scale_fill_manual(values=c("#947FEE", "#F575B2"))+
scale_alpha_continuous(range=c(0.7, 1))
ggdraw()+draw_plot(bg4)+draw_plot(p, width=0.8, height=0.8, x=0.1, y=0.1)+theme(aspect.ratio=0.6)
# 同理,我们接下来也并非要用网络图呈现特定数据,而只是以它为图表背景(图7-2-5b)
# install.packages("ggraph")
library(ggraph) # 使用geom_edge_link、geom_node_point等
node_number=40
g=expand.grid(1: node_number, 1: node_number) # 生成节点
set.seed(1); link=sample(c(0, 1), node_number^2, TRUE, prob= c(0.97, 0.03)) # 生成边
g=data.frame(g, link)
g=g[g$link != 0, ]
g=graph_from_data_frame(g)
bg_graph=ggraph(g, layout="sphere")+
geom_edge_link(edge_color="red", edge_alpha=0.45)+ # 绘制边
geom_node_point(color="red", size=5, alpha=0.55)+ # 绘制节点
theme_void()
black_grey=color Ramp Palette(c("grey10", "grey30", "grey10"))(40)
black_grey=matrix(black_grey, nrow=1)
bg5=ggplot()+theme_void()+
annotation_raster(black_grey, -Inf, Inf, -Inf, Inf, interpolate= TRUE)(www.xing528.com)
ggdraw()+draw_plot(bg5)+draw_plot(bg_graph)+draw_plot(p, width=0.8, height=0.8, x=0.1, y=0.1)+theme(aspect.ratio=0.6)
图7-2-5 上=图a以维诺图为背景,下=图b以网络图为背景
我们接下来尝试把在极坐标系中绘制的饼图放到背景图上去,本例中的数据为全球艺术品拍卖市场的成交量占比(图7-2-6)。
图7-2-6 绘制饼图并添加背景
dat=read.csv("art volume.csv", row.names=1) # 课件中的文件
# 第一步:生成背景图层
img=image_read("write board.jpg") # 课件中的图片
img=image_colorize(img, opacity=15, color="black")
bg=ggplot()+theme_void()+
annotation_raster(img, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax= Inf)
# 第二步:生成呈现数据的图层
# 在极坐标系中的扇面的圆心角正比于在笛卡尔坐标系中的矩形在X轴上的宽度,因此我们首先用geom_tile来绘制矩形
v=dat$Volume
end=cumsum(v) # 矩形的右边界
mid=end-v/2 # 矩形的中心等于右边界减宽度的二分之一
mycolor=brewer.pal(n=nrow(dat), name="Paired") # 提取颜色
p=ggplot()+coord_polar(start=0, clip="off")+ # 设置clip="off"是为确保文字完整显示
geom_tile(show.legend=FALSE, aes(x=mid, y=0.5, width=v, height=1, fill=factor(1: length(v))), alpha=0.5)+ # 为方便起见,把矩形的上下边界设为1和0
scale_fill_manual(values=mycolor)+
geom_segment(aes(x=mid, y=0.9, xend=mid, yend=1.05), color="white", alpha=0.8)+ # 文字与扇面的连接线
labs(title="Fine Art Auction Market Global Share\nby Volume in 2017")
# 第三步:添加标签
lab_text=as.character(dat$Country)
lab_text=paste(lab_text, ": ", v*100, "%", sep="")
# 如果要把文字标注到扇面上,那么geom_text中的Y坐标应当是一个小于1的数,例如,我们可设置geom_text(aes(x=mid, y=0.5, label=lab_text))。不过现在我们要把文字都放到扇面外,所以需设置一个略大于1的数,并把vjust和hjust都设为"outward"
p=p+geom_text(aes(x=mid, y=1.05, label=lab_text), vjust="outward", hjust="outward", size=5, color="white")+
theme_void()+
theme(plot.title=element_text(hjust=0.5, color="white", size=22, face=2))
# 第四步:合并
ggdraw()+draw_plot(bg)+draw_plot(p, x=0.25, y=0, width=0.5, height=1)+theme(aspect.ratio=0.66)
利用本书第一章介绍的image_composite函数,我们还可以生成纹理效果(图7-2-7)。
图7-2-7 生成纹理效果
dat=read.csv("art volume.csv", row.names=1) # 课件中的文件
dat$Country=reorder(dat$Country, dat$Volume)
dat=data.frame(dat, PCT=paste(100*dat$Volume, "%", sep=""))
# 第一步:生成背景
img=image_read("canvas.jpg") # 课件中的图片
# 第二步:生成充当星光的随机点,画条形图,合并图表
set.seed(1); px=runif(200, 0, 1)
set.seed(2); py=runif(200, 0, 1)
set.seed(3); pcolor=sample(c("yellow", "khaki", "white", "gold"), 200, replace=TRUE)
star=ggplot()+geom_point(aes(px, py), size=3, color=pcolor)+theme_void()+theme(plot.background=element_rect(fill="midnightblue", color="midnightblue"))
p=ggplot(dat)+coord_cartesian(clip="off")+
geom_bar(show.legend=FALSE, aes(x=Volume, y=Country), stat="identity", fill="yellow", width=0.8, orientation="y")+
geom_text(aes(x=Volume, y=Country, label=PCT), hjust=-0.2, size=30, family="Hershey Script", fontface=2, color="khaki")+
labs(title="Fine Art Auction Market\n Global Share by Volume in 2017")+
theme_void()+
theme(axis.text.y=element_text(size=80, family="Hershey Script", face=2, color="khaki"),
plot.title=element_text(family="mono", size=80, face=3, color="khaki")
)
add_up=ggdraw()+draw_plot(star)+draw_plot(p, x=0.1, width=0.8, y=0.1, height=0.8)
# 第三步:用image_composite处理
res=image_graph(width=2400, height=1800, bg="transparent")
print(add_up)
dev.off()
img=resize_to_standard(img, res, scale=TRUE) # 确保两张图片尺寸一致
y=image_composite(img, res, gravity="center", operator="blend", compose_args="60") # 将operator设为"blend",并通过反复尝试找到compose_args的合适取值
#==========
# 练习:月亮图
#==========
# 月亮图,可以用不同圆缺程度的月亮形,代替包含两个分类的饼图,或者用于表示分数、比例、进度的条形图
# install.packages("gggibbous")
library(gggibbous)
# geom_moon有两个特殊的参数:ratio为0至1的数值,用于设定圆缺程度。right用于设定是否从圆形右侧开始绘制。我们有时可能需要用带有不同颜色或透明度的点来代表整个圆形,此时我们要明确设置月亮形和点的尺寸,以便使二者匹配起来
ggplot()+
geom_moon(aes(x=1: 5, y=1, ratio=seq(0.2, 1, 0.2)), fill="red", color="blue", right=TRUE, size=6: 10)+
geom_point(aes(1: 5, 1), color="red", alpha=0.2, size=6: 10)
# 我们以若干国家受访者政治知识测验得分数据为例,进行示范(图7-2-8)。单元格中的数值是各国/各不同教育水平受访者答题正确率的均值以及总题数比例的均值
dat=read.csv("political knowledge.csv", row.names=1) # 课件中的文件
dat=as.data.frame(as.table(as.matrix(dat))) # 整理数据
colnames(dat)=c("Country", "Education", "Score")
dat$Education=gsub("_", "\n", dat$Education)
p=ggplot(dat)+
geom_point(show.legend=FALSE, aes(Education, Country, color=Country), alpha=0.2, size=18)+ # 整个圆形
geom_moon(show.legend=FALSE, aes(Education, Country, ratio= Score, fill=Country, color=Country), size=18)+ # 月亮形
geom_text(aes(Education, Country, label=round(Score*100, 0)), size=5, vjust=-2.5, color="grey90", family="mono", fontface=2)+ # 用百分制表示分数
scale_color_manual(values=c("#7AA892", "yellowgreen", "indianred1","steelblue1"))+
scale_fill_manual(values=c("#7AA892", "yellowgreen", "indianred1","steelblue1"))+
scale_x_discrete(position="top")+
labs(title="Political Knowledge Test Score\n")+
theme_void()+
theme(
axis.line.x=element_line(color="grey85"),
axis.ticks.y=element_line(color="grey85"), axis.ticks.length= unit(2, "mm"),
axis.text=element_text(color="grey90", size=18, family="mono", face=2),
axis.text.y=element_text(hjust=1),
plot.title=element_text(color="grey85", size=21, hjust=1, family="serif"),
plot.margin=unit(rep(3, 4), "mm")
)
m=color Ramp Palette(c("#513252", "#005688"))(40)
bg=ggplot()+theme_void()+
annotation_raster(m, -Inf, Inf, -Inf, Inf, interpolate=TRUE)
ggdraw()+draw_plot(bg)+draw_plot(p)
图7-2-8 月亮图
#==========
# 练习:渐变环形图
#==========
# 除了月亮图外,我们还可使用环形图来对分数、比例、进度进行可视化。在下边的例子中,我们用渐变环形图来呈现两个百分比(图7-2-9)。由于用annotation_raster添加的渐变矩形无法在极坐标系中使用,所以我们使用的方法是绘制大量带有单一颜色的矩形。矩形的数量越多,渐变效果越好
library(cowplot)
library(dplyr)
library(magick)
value=data.frame(
all_score=c(81, 66), # 待呈现的百分比是81%和66%
all_name=c("Company", "Government")
)
full_score=100 # 可以取到的最大值是100%
all_use_n=1000 # 当数值为100%时,拟使用的矩形的数量
all_color=color Ramp Palette(c("aquamarine", "chartreuse", "indianred1","orangered"))(all_use_n) # 当数值为100%时,拟使用的全部颜色
end_color=all_color[1: ceiling(all_use_n*max(value$all_score)/full_score)] # 本例用到的全部颜色,即用于呈现本例中的最大值81%时用到的颜色
info=mutate(value, use_n=ceiling(all_use_n*all_score/full_score), width=all_score/use_n) # 代表81%和66%的图层使用的矩形数和矩形的宽
xmiddle=mapply(seq, from=info$width/2, to=info$all_score, by=info$width) # 计算矩形的中心点
# 生成符合geom_tile需要的数据
dat=data.frame(
info[rep(1: nrow(info), times=info$use_n), ],
xmiddle=unlist(xmiddle)
)
图7-2-9 渐变环形图
text_dat=mutate(value, add_text=paste(all_score, "%", sep="")) # 添加文字使用的数据框
# 第一步:生成环形图。注意:为了生成极坐标系中的环形,我们把Y轴值域设为0至1,把所有矩形设定为:中心点Y坐标为0.9,高为0.2
p=ggplot(dat)+coord_polar()+xlim(0, 100)+ylim(0, 1)+
facet_wrap(vars(all_name), nrow=1)+
geom_tile(show.legend=FALSE, aes(x=xmiddle, y=0.9, width=width, fill=xmiddle), height=0.2)+
scale_fill_gradientn(colors=end_color)+
geom_text(data=text_dat, aes(0, 0, label=add_text), size=13, color="grey95")+
labs(title="% people say risks of ___ collecting data\nabout them outweight the benefits.")+
theme_void()+
theme(strip.background=element_blank(),
strip.text=element_text(size=20, family="serif", margin= unit(rep(4, 4), "mm"), color="grey95"),
plot.title=element_text(size=25, family="serif", face=3, color="grey95")
)
# 第二步:生成背景
img=image_read("street.jpg")
img=image_colorize(img, opacity=55, color="black")
bg=ggplot()+theme_void()+
annotation_raster(img, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)
# 第三步:合并
ggdraw()+draw_plot(bg)+draw_plot(p, x=0, y=0.05, width=1, height=0.9)
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。