科技期刊论文数量排名 Top10 可视化

科技期刊论文数量排名 Top10 可视化

这篇不是学习笔记了哈,是自己第一次正式独立使用 ggplot 绘图的尝试,过程比较艰辛。

Stata 数据整理

我是如何想到要画这个图的呢,因为前天在 ECharts 上看到了一幅很不错的图表:2000-2017 年 SCI Top 10 国家论文增长,图是这样的:

本来是想从他的代码里把数据整理出来,但是发现太麻烦了,就找了份类似的数据:Knoema: 科技期刊论文数量

非会员不提供下载,所以就只能爬喽,最开始的想法是用 Stata 爬,毕竟用 Stata 爬 Knoema 数据库好多次了。熟悉的寻找请求方法:

然后用 Stata 下载整理:

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
!curl ...(此处略去冗长的代码)... --compressed | tr "{" "\n" > temp.txt
infix strL v 1-20000 using temp.txt, clear
keep if index(v, "Time")
gen year = ustrregexs(1) if ustrregexm(v, `"Time":"(.*)-01-01T0"')
gen country = ustrregexs(1) if ustrregexm(v, `""country":"(.*)","RegionId""')
gen value = ustrregexs(1) if ustrregexm(v, `""Value":(.*),"Unit""')
drop v
drop if year == ""

* 不知道value为什么会有小数,所以先删除了
destring value, replace
replace value = floor(value)

destring year, replace
compress
format country %20s
* 只保留Top10:
bysort year: keep if inrange(_n, 1, 10)

* 有些国家的名字叫着不舒服:
replace country = "美国" if country == "美利坚合众国"
replace country = "韩国" if country == "大韩民国"
replace country = "俄罗斯" if country == "俄罗斯联邦"

save 科技论文数量数据, replace
!rm temp.txt

按照上面的代码就整理好了这份数据:

可惜只有 8 年的数据,每年 10 个国家。

ggplot2 绘图

绘制动图的一个很好的方法是先绘制静态图片再合成。所以需要绘制每一个年份的静态条形图。

R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
library(readstata13)
library(ggplot2)
library(gganimate)
theme_set(theme_bw(base_family = "STSong", base_size = 20) +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.subtitle = element_text(hjust = 0.5)) +
theme(axis.title.y = element_blank()))

da <- read.dta13("科技论文数量数据.dta")

# 每个国家的颜色,和ECharts上的那幅图是一样的:
da$color = NA
da[da$country == "美国",]$color = "#1f78b4"
da[da$country == "中国",]$color = "#f91b1e"
da[da$country == "德国",]$color = "#00ced1"
da[da$country == "日本",]$color = "#b15928"
da[da$country == "英国",]$color = "#6a3d9a"
da[da$country == "法国",]$color = "#cab2d6"
da[da$country == "意大利",]$color = "#ff7f00"
da[da$country == "加拿大",]$color = "#fdbf6f"
da[da$country == "西班牙",]$color = "#34a02c"
da[da$country == "印度",]$color = "#ff1493"
da[da$country == "韩国",]$color = "#b2df8a"
da[da$country == "俄罗斯",]$color = "#fb9b99"

for(i in da$year){
datemp <- subset(da, year == i)
datemp <- datemp[order(datemp$value),]
datemp$country <- factor(datemp$country, levels = datemp$country)
ggplot(datemp) +
geom_bar(stat = "identity", aes(x = country, y = value, fill = I(color))) +
coord_flip() +
labs(y = "科技期刊发文量",
title = paste("图:", i, "年科技期刊发文总量Top10排名", sep = ""),
subtitle = "数据来源:Knoena数据库",
caption = paste("年份:", i)) +
ylim(0, 500000)
ggsave(paste("temp", i, ".png", sep = ""))
}
system("convert -delay 80 temp*.png 科技论文量.gif ")
system("rm temp*.png")

注意,这里面柱条的填充色的映射是fill = I(color),这是因为 color 变量本身就是颜色值,这样可以直接使用其本身绘图而不需要再进行颜色的映射。

动图效果:

要是数据更长一点就更好看了。

在 R 中完成所有的工作

为了锻炼自己的 R 语言使用能力,我把刚刚在 Stata 中爬取数据的思路用在了 R 上,过程挺不容易,通过这个过程我发现 Stata 的一个大优势是它的双层引号:

1
`""'

这个引号内部可以放置任何字符而不需要转义,但是如果你想在 R 的字符串里面使用双引号,你就必须使用\进行转义。

R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 虽然可以使用system函数直接运行curl请求,但是双引号的转义是非常头疼
# 的,所以如果想完全采用R完成这个工作流程,首先需要把curl语句在终端
# 运行以下请求需要的数据。
raw <- read.fwf("temp.txt", widths = 20000)
library(stringr)
raw$year <- str_extract(raw$V1, "Time\":\"(.*)-01-01T0")
raw <- subset(raw, !is.na(raw$year))
raw$country <- str_extract(raw$V1, "country\":\"(.*)\",\"RegionId")
raw$value <- str_extract(raw$V1, "Value\":(.*),\"Unit")
raw <- raw[, -1]
raw$year <- gsub(pattern = "Time\":\"", raw$year, replacement = "")
raw$year <- gsub(pattern = "-01-01T0", raw$year, replacement = "")

raw$country <- gsub(pattern = "country\":\"", raw$country, replacement = "")
raw$country <- gsub(pattern = "\",\"RegionId", raw$country, replacement = "")

raw$value <- gsub(pattern = ",\"Unit", raw$value, replacement = "")
raw$value <- gsub(pattern = "Value\":", raw$value, replacement = "")

raw$year <- as.numeric(raw$year)
raw$value <- as.numeric(raw$value)

raw$value <- floor(raw$value)
# 只保留每年发文量最多的是个国家
# 我的想法是分割、排序、保留前十个然后再合并
da = data.frame(year = NA, country = NA, value = NA)
for(i in c(2005, seq(2010, 2016, by = 1))){
rawtemp <- raw[which(raw$year == i),]
rawtemp <- rawtemp[order(-rawtemp$value),]
rawtemp <- rawtemp[1:10,]
da = rbind(da, rawtemp)
}
da <- subset(da, !is.na(year))

# 把几个比较长的国家名字换掉
da$country[which(da$country == "美利坚合众国")] = "美国"
da$country[which(da$country == "大韩民国")] = "韩国"
da$country[which(da$country == "俄罗斯联邦")] = "俄罗斯"
rm(rawtemp)
rm(raw)
rm(i)

至此数据就被整理的和刚才一模一样了,然后同样的绘图代码代码即可绘制刚刚的那幅图了。

一个插曲

实际上最开始我是想用 Stata 完成整个过程的,Stata 绘图能力虽然有限,但是通过精巧的设计也是可以实现这幅图的,但是我实在是懒得一幅一幅的设计了,所以就放弃了。然后我想用gganimate包绘制动图,结果绘制出一个不伦不类的图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
library(readstata13)
library(ggplot2)
library(gganimate)
theme_set(theme_bw(base_family = "STSong", base_size = 20) +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.subtitle = element_text(hjust = 0.5)) +
theme(axis.title.y = element_blank()))
da <- read.dta13("科技论文数量数据.dta")

da$country = factor(da$country, levels = c("俄罗斯", "韩国", "印度",
"西班牙", "加拿大",
"意大利", "法国", "德国", "英国",
"日本", "中国", "美国"))

da <- subset(da, year != 2005)
ggplot(da) +
geom_bar(stat = "identity", aes(y = value, x = country, fill = country)) +
coord_flip() +
transition_manual(year) +
labs(title = "年份:{frame + 2009}", y = "科技期刊论文总量") +
theme(axis.title.y = element_blank()) +
theme(legend.position = "none")

anim_save("科技期刊论文数量.gif")

不知道怎么这个柱条非要累计一下,但是也别有一番风味不是么?不知道 gganimate 的像素为什么这么差哎,要不然我肯定会喜欢上用它的。

结束语

通过今天的这个绘图实践,我意识到自己的 R 学习还是非常任重道远,不论是绘图还是数据整理能力都亟待提高。

# R, Stata

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×