(各个省肺炎感染类型及人数可视化)R语言基于地理位置进行分面
不知道大家有没有看过这样的图:乍一看还以为是元素周期表(哈哈哈,化学都还给老师了)。实际上他这个是根据美国各个州的地理位置进行分面(在R语言里面一般使用facet_grid()
或者facet_wrap()
来做,其实还有很多,我一般只用这两个)
接下来就是来分析一下,如何画这个图,当然单纯靠ggplot2
包肯定可以,但是重复造轮子太麻烦了,今天也就是介绍一个R包——geofacet
。
这个包就是可以快速的基于地理信息画出上面的案例(实际上上面的图也就是这个包的一个demo)。我只会一点点R语言,我就从我的理解角度进行画图。
我觉得,像R语言这个编程,在不考虑统计、数学这些知识下,只要掌握数据结构和函数的一些主要要求,基本上都可以满足需求。
library(geofacet)
library(ggplot2)
ggplot(state_ranks, aes(variable, rank, fill = variable))
geom_col()
coord_flip()
theme_bw()
facet_geo(~state)
画出上面这个图,只需要这么多代码,一行一行分解
第一行到第三行肯定不要解释了,从安装包到加载包,这个是基础的。
从第五行到第九行,一共5行代码,第五行的ggplot(state_ranks, aes(variable, rank, fill = variable))
这句话是说加载state_ranks
这个数据,然后选择x轴为state_ranks
的variable
变量,y轴为rank
变量,填充颜色是variable
。
geom_col()
函数是画条形图,coord_flip()
是将坐标轴旋转一下,theme_bw()
函数是设置一下这个绘画的主题,然后告诉facet_geo()
函数(geofacet
包提供的),让这个图根据state_ranks里面的state这个变量进行分面,然后就得出这个图了,实际上确实很简单(只要是你数据格式正确!!!)。如果你以为只要数据框有这几个变量,就可以画出图来,简直是大错特错。我们真正应该值得注意的是state_ranks
这个数据框,好好看一看这个数据框是什么样的。
# > state_ranks
# state name variable rank
# 1 AK Alaska education 28
# 2 AK Alaska employment 50
# 3 AK Alaska health 25
# 4 AK Alaska wealth 5
# 5 AK Alaska sleep 27
# 6 AK Alaska insured 50
# 7 AL Alabama education 45
# > str(state_ranks)
# 'data.frame': 306 obs. of 4 variables:
# $ state : chr "AK" "AK" "AK" "AK" ...
# $ name : chr "Alaska" "Alaska" "Alaska" "Alaska" ...
# $ variable: chr "education" "employment" "health" "wealth" ...
# $ rank : num 28 50 25 5 27 50 45 49 48 47 ...
仔细看看这个数据表就知道了,这个数据表的state
都是各个州的缩写,name
都是各个州的全称, variable
是变量属性(只有六种),rank对应的是数值。facet_geo(~state)
什么意思??“state_ranks
这个数据框对facet_geo()
函数说,你就按照我的state进行分面就可以啦,然后facet_geo()
就根据state_rank
的state
这列进行匹配,按照预先设定好的位置进行分面。”
那么他是按照什么来进行分面的?预先设置的位置数据怎么储存的??实际上看一下facet_geo
函数就知道啦,看到下面有个grid = "us_state_grid1"
。说明就是按照us_state_grid1
来分面的(我是在看完官方写的demo,我才知道的,刚开始我也是蒙蔽)
那么us_state_grid1
是什么样子的?
# > us_state_grid1
# row col code name
# 1 6 7 AL Alabama
# 2 7 2 AK Alaska
# 3 5 2 AZ Arizona
# 4 5 5 AR Arkansas
# 5 4 1 CA California
# 6 4 3 CO Colorado
实不相瞒,他就是长得这样的,当state_ranks
对facet_geo
函数说:“你就按照我的state进行分类”。然后facet_geo
函数就将state_ranks
的state
变量和us_state_grid1
的name
进行匹配,发现都一样,然后就按照us_state_grid1
的各个州对应的row
、col
(也就是行列位置)进行分面,把不同的州的位置根据row
、col
数值,一一放到对应的位置上。最终成功展出这样的美国地图。
第二个案例
# > head(state_unemp)
# year rate state
# 1 2000 4.6 AL
# 2 2001 6.0 AL
# 3 2002 5.8 AL
# 4 2003 6.0 AL
# 5 2004 5.2 AL
# 6 2005 4.2 AL
# > head(us_state_grid2)
# row col code name
# 1 6 7 AL Alabama
# 2 1 1 AK Alaska
# 3 6 2 AZ Arizona
# 4 6 5 AR Arkansas
# 5 6 1 CA California
# 6 5 3 CO Colorado
ggplot(state_unemp, aes(year, rate))
geom_line()
facet_geo(~ state, grid = "us_state_grid2", label = "code")
scale_x_continuous(labels = function(x) paste0("'", substr(x, 3, 4)))
labs(title = "Seasonally Adjusted US Unemployment Rate 2000-2016",
caption = "Data Source: bls.gov",
x = "Year",
y = "Unemployment Rate (%)")
theme(strip.text.x = element_text(size = 6))
上面的代码中从第一行到第九行,都是观察两个数据框,state_unemp
是我们要可视化的数据,us_state_grid2
是网格。根据这个网格标记的位置来找各个州的位置。第17、18行是说根据state_unemp
的year
为横坐标,rate
为纵坐标,画出折线图。第19行是分面,以state_unemp
的state
变量为依据,按照网格us_state_grid2
来画位置,各个位置的面的名称依据us_state_grid2
的code
变量,然后第20行到25行都是对坐标轴的标签进行修改。
最后图如下:
实际上确实很简单。
用疫情和中国各个省的一个分面地图
但是目前数据还不好找,先待定,到时候,我会介绍如何自己做一个中国地图的版本。虽然现在也已经有了。
昨晚(放弃看春晚,连夜写代码,终于画出来啦)
为了符合当今时事,我们使用新浪新闻提供的数据:https://news.sina.cn/zt_d/yiqing0121
将上面的数据手动输入Rstudio里面, 代码如下:
library(geofacet)
library(ggplot2)
pro <- c("湖北", "北京", "广东", "上海", "浙江",
"云南", "四川", "山东", "广西", "贵州",
"安徽", "海南", "宁夏", "吉林", "江西",
"天津", "河南", "重庆", "山西", "黑龙江",
"湖南", "辽宁", "澳门", "台湾", "福建",
"香港", "河北", "内蒙古", "江苏", "陕西",
"新疆", "甘肃", "青海")
pro_eng <- sort(tolower(china_prov_grid2$name))[c(14,2,6,26,34,
33,28,25,7,8,
1,9,22,19,18,
30,12,3,27,11,
15,20,21,29,4,
13,10,16,17,24,
32,5,23)]
`确诊` <- c(549, 36, 53, 20, 43,
1, 15, 15, 13, 4,
15, 5, 3, 3, 7,
8, 9, 27, 1, 4,
24, 4, 2, 2, 10,
2, 2,1,9,5,
2, 2, 0)
`疑似` <- c(0, 0, 0, 22,
0, 0, 4,
0, 0, 0, 4, 32, 1,
0, 0, 0, 42, 13, 0,0,0,0,0,0,2, 36,
0, 2, 0, 0, 0, 0,1)
my_data <- data.frame(province = pro, province_eng = pro_eng,
`确诊` = `确诊`, `疑似` = `疑似`)
> head(my_data)
# province province_eng 确诊 疑似
# 1 湖北 hubei 549 0
# 2 北京 beijing 36 0
# 3 广东 guangdong 53 0
# 4 上海 shanghai 20 22
# 5 浙江 zhejiang 43 0
# 6 云南 yunnan 1 0
上面第11行代码是将各个省的中文名字和拼音联系到一起。为了省事,我都用了小写,最后,要展现得数据是32行开始的。
这个时候my_data
是宽数据,要将宽数据转换为长数据。因为是ggplot2
做图本来就要求的, 代码如下:
library(tidyverse)
my_data_long <- reshape2::melt(my_data, id.vars = c("province", "province_eng"))
head(my_data_long)
# province province_eng variable value
# 1 湖北 hubei 确诊 549
# 2 北京 beijing 确诊 36
# 3 广东 guangdong 确诊 53
# 4 上海 shanghai 确诊 20
# 5 浙江 zhejiang 确诊 43
# 6 云南 yunnan 确诊 1
实际上facet_geo
包提供的中国地图是34个省,但是新浪新闻提供的数据是33个省,通过代码简单看一下就知道:西藏没有被包含。那么舍去掉,自己定义一个grid。
setdiff(tolower(china_prov_grid2$name), my_data$province_eng)
# [1] "tibet"
接下来就是定义自己的grid
,然后画出来, code如下:
my_grid <- china_prov_grid2 %>%
mutate(name = tolower(name)) %>%
filter(name != "tibet")
my_data <- my_data %>%
mutate_if(is.factor, as.character)
head(my_data)
# province province_eng 确诊 疑似
# 1 湖北 hubei 549 0
# 2 北京 beijing 36 0
# 3 广东 guangdong 53 0
# 4 上海 shanghai 20 22
# 5 浙江 zhejiang 43 0
# 6 云南 yunnan 1 0
head(my_grid)
# code row col name
# 1 XJ 4 1 xinjiang
# 2 GS 4 2 gansu
# 3 QH 5 2 qinghai
# 4 SC 6 2 sichuan
# 5 YN 7 2 yunnan
# 6 NX 5 3 ningxia
看到上面的my_grid
和my_data
, 就可以得出,这两个表通过name
和province_eng
变量进行匹配。
然后图如下:
ggplot(my_data_long, aes(x = variable, y = value, fill = variable))
geom_col() geom_text(aes(x = variable, y = value, label = value), hjust = 0.9)
facet_geo(~ province_eng, grid = my_grid)
theme_bw() coord_flip()
labs(title = "武汉疫情分布",
subtitle = "截止2020年1月24日23时",
caption = "Data Source: https://news.sina.cn/zt_d/yiqing0121",
x = "症状",
y = "数量")
theme(plot.title = element_text(hjust = 0.5, size = 16))
上面各个表每一个块是代表各个省(我怎么设置都没办法将标签从拼音改为中文)不同的颜色代表确诊人数和疑似人数。
最后声明一下:
数据来源为新浪新闻,时事数据更新:网站为:https://news.sina.cn/zt_d/yiqing0121。可能我在手动输入的过程中,会有误差,主要是提供分析方法,请不要相信我的统计图反映的数据!!!
最后可以去安装这个包试一试:
https://hafen.github.io/geofacet/