首页 理论教育 基于ggplot的政经数据可视化:添加背景

基于ggplot的政经数据可视化:添加背景

时间:2023-11-19 理论教育 版权反馈
【摘要】:如果我们只希望在面板上添加背景,那么使用annotation_raster即可。dat=read_excel # 课件中的文件dat=as.data.frame# 第一步:通过annotation_raster添加图片并生成背景图层# 为防止图片颜色与其他图层的颜色混在一起,我们在图片上添加一个半透明矩形white=matrixbg=ggplot()+theme_void()+annotation_raster+annotation_raster# 第二步:生成呈现数据的图层。

基于ggplot的政经数据可视化:添加背景

如果我们只希望在面板上添加背景,那么使用annotation_raster即可。

library(cowplot) # 需使用ggdrawdraw_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_linkgeom_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)

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

我要反馈