这是“投必得学术”推送的第71篇文章,专注科研技能和资讯分享!
相较于信息丰富的箱线图(箱线图及其变体),柱状图(强大的直方图和箱线图)由于展示信息较少而经常被诟病或者忽视,但近期我对做动图很有兴趣(用R绘制局部地区疫情分布图+时间序列动态图),学习到一种做出动态柱状图的方法,瞬间让柱状图变得高大上起来。
巧合的是,在我摸索出方法的几天后,看到有朋友在朋友圈里分享了他们公司的业绩图,正是用这种动态柱状图展示数据的,先贴出来给大家看看效果(这里没有广告嫌疑哟 :-P):
今天笔者就来跟大家分享这种能反映时间发展排名的动态柱状图,让数据像赛跑一样,一个赶超一个。
安装所需的R包
<code>library
(ggplot2)library
(gganimate)library
(tidyverse)library
(scales)library
(gifski)library
(viridis)/<code>
我们用一个数据包里的数据做例子
<code>library
(gapminder)View
(gapminder)/<code>
这个gapminder包里包含了从1952年到2007年期间各地区每5年的预期寿命(lifeExp)、总人口(pop)和人均GDP(gdpPercap),这三个数据都可以用动态柱状图很好的展示。加载这个数据包后,查看数据。
更多关于gapminder包的信息,请戳:
https://cran.r-project.org/web/packages/gapminder/README.html
整理数据
可以用预期寿命、总人口或人均GDP做图,但是我试了一下,这些数据要么因为本身数值差别不大要么在地区或年份之间差别不大,做出的动图不够“动”,所以用总人口乘以人均GDP计算出总GDP,以此为例,做出每年GDP排名最高的10个国家的情况。
<code>gapminder_formatted % mutate(value
= pop*gdpPercap) %>% group_by(year) %>% mutate(rank = rank(-value
), Value_lbl = paste0(" "
, round(value
/1e9
))) %>% group_by(country) %>% filter(rank <=10
) %>% ungroup()/<code>
向左滑动查看完整代码
做静态图
<code>staticplot
=
ggplot(gapminder_formatted,
aes(rank,
group
=
country,
fill
=
as.factor(country),
colour
=
as.factor(country)))
+
geom_tile(aes(y
=
value/2,
height
=
value,
width
=
0.8
),
alpha
=
0.8
,
colour
=
NA)
+
geom_text(aes(y
=
0
,
label
=
paste(country,
" "
)),
vjust
=
0.2
,
hjust
=
1
,
size
=
8
)
+
geom_text(aes(y
=
value,
label
=
Value_lbl,
hjust
=
0
),
size
=
8
)
+
coord_flip(clip
=
"off"
,
expand
=
FALSE
)
+
scale_x_reverse()
+
guides(colour
=
FALSE
,
fill
=
FALSE
)
+
theme(axis.line
=
element_blank(),
axis.text.x
=
element_blank(),
axis.text.y
=
element_blank(),
axis.ticks
=
element_blank(),
axis.title.x
=
element_blank(),
axis.title.y
=
element_blank(),
legend.position
=
"none"
,
panel.background
=
element_blank(),
panel.border
=
element_blank(),
panel.grid.major
=
element_blank(),
panel.grid.minor
=
element_blank(),
panel.grid.major.x
=
element_line(),
panel.grid.minor.x
=
element_line(),
plot.title
=
element_text(size
=
32
,
hjust
=
0.5
,
face
=
"bold"
,
colour
=
"black"
,
vjust
=
-1
),
plot.subtitle=element_text(size
=
32
,
hjust
=
0.5
,
face
=
"italic"
,
colour
=
"black"
),
plot.caption
=
element_text(size
=
16
,
hjust
=
0.5
,
face
=
"italic"
,
colour
=
"black"
),
plot.background
=
element_blank(),
plot.margin
=
margin(1,
3
,
1
,
6.5
,
"cm"
))staticplot
/<code>
向左滑动查看完整代码
可以看一下此时的静态图,乱糟糟的,暂时看不出什么来。
生成按时间发展的动图
这一步就是见证奇迹的时刻啦,其中的关键就是transition_states这个函数,我们用它来定义时间轴是year。设置其中的transition_length和state_length可以让柱子们或“平滑”或“跳动”地“赛跑”,以及在每一个状态(每一年)停留的时间,大家可以调整试试看。
<code>anim = staticplot + transition_states(year, transition_length =2
, state_length =1
) + view_follow(fixed_y = TRUE) +labs
(title ="GDP (Top 10 Countries): {closest_state}"
, subtitle =" "
, caption ="GDP in Billions Dollars | Data Source: R Package gapminder"
) anim/<code>
向左滑动查看完整代码
如果你急不可耐地想立刻见证奇迹,可以直接运行anim这个对象,在RStudio窗口查看。但我们还是要保存一下的,下一步也很重要。
保存
这里我用的是播放速度的默认值(nframes = 100, fps = 10),大家可以试着调整总帧数和每秒帧数,放慢或者加快动图。
<code>animate(anim,
nframes
=
100
,
fps
=
10
,
width
=
1200
,
height
=
600
,
renderer
=
gifski_renderer("Barplot_country.gif"))
/<code>
向左滑动查看完整代码
改变颜色
柱子的颜色是按照地区名字的字母顺序安排的,显得有些乱糟糟,让人摸不着头脑,下面用两种方式改变颜色。
(1)现在的颜色是按国家显示的,如果我想按大洲(continent)显示呢?
很简单,只需将执行staticplot的代码第一句改成:
<code>fill =as
.factor(continent), colour =as
.factor(continent)/<code>
向左滑动查看完整代码
(2)想彻底换个色板?
就换成流行的viridis色板吧,而且让最终时间的柱子颜色按数值梯度显示。
首先查看曾经跻身前十的到底有几个国家:
<code>country
$country) length(country)/<code>
向左滑动查看完整代码
哦!有11个呢,应该有一个国家在这些年间被挤出前十了。
查看一下viridis色板的11个颜色(我觉得这个色板黄色的那部分太浅,可能会看不清,所以加了end = 0.9去掉黄色这端的颜色):
<code>show_col
(viridis_pal(end =0.9
)(11
))/<code>
向左滑动查看完整代码
提取这11种颜色的RGB代码,编辑成一个色彩表格:
<code>viridis_11
colour_rank
virids_palette
% as_tibble()
/<code>
向左滑动查看完整代码
按最终时间的数值由大到小排序,跟色彩表格结合后,再按照地区名字的字母顺序排序,提取颜色的RGB代码。这一步有点绕,大家慢慢体会:
<code>colour % group_by(country) %>% summarise(value_max = max(value
)) %>% arrange(-value_max) %>% mutate(value_rank = rank(country)) %>% bind_cols(virids_palette) %>% arrange(value_rank) %>% pull(colour) %>%as
.character()/<code>
向左滑动查看完整代码
在刚才的静态图里加上新安排的颜色:
<code>staticplot<
-
staticplot
+scale_fill_manual
(values
=colour)
+scale_colour_manual
(values
=colour)
/<code>
向左滑动查看完整代码
后面生成动图的步骤都一样啦: