Stata绘图:环形柱状图-实时全球新冠确诊人数
👇 连享会 · 推文导航 | www.lianxh.cn
🍎 Stata:Stata基础 | Stata绘图 | Stata程序 | Stata新命令 📘 论文:数据处理 | 结果输出 | 论文写作 | 数据分享 💹 计量:回归分析 | 交乘项-调节 | IV-GMM | 时间序列 | 面板数据 | 空间计量 | Probit-Logit | 分位数回归 ⛳ 专题:SFA-DEA | 生存分析 | 爬虫 | 机器学习 | 文本分析 🔃 因果:DID | RDD | 因果推断 | 合成控制法 | PSM-Matching 🔨 工具:工具软件 | Markdown | Python-R-Stata 🎧 课程:公开课-直播 | 计量专题 | 关于连享会
连享会 · 2022暑期班
作者: 范思妤 (南京大学)
邮箱: fansiyu@smail.nju.edu.cn
温馨提示: 文中链接在微信中无法生效。请点击底部「阅读原文」。或直接长按/扫描如下二维码,直达原文:
致谢: 本文摘自以下文章,特此感谢!Source: Asjad Naqvi, 2022, Blog, Stata graphs: Circular bar graphs
目录
1. 简介
2. 准备工作
3. 获取数据
4. 绘制基础环形柱状图
5. 国家/地区标签
6. 洲名标签
7. 附:完整绘图代码
8. 相关推文
1. 简介
说起柱状图大家并不陌生,但如果柱状图需要展示的项目过多而无法在一条直线上进行有效地平铺展示时,环形柱状图就不失为一种简洁美观展示数据特征的手段。环形柱状图是指每个条形都沿圆而不是直线显示的图形。
环形柱状图没有y轴显示,因而样本对应的数值写在每个条形上,也可以在与图表的交互中表示。总的来说,环形柱状图因其可视化效果而颇受欢迎,但需要谨慎使用,因为群体不共享相同的y轴。
基于 Our World in Data 提供的新型冠状病毒数据集,本文将详细解析以下环形柱状图的编绘过程,来帮助读者了解使用 Stata 编绘环形柱状图的基本步骤和实操代码。
建议读者使用 Stata15 及以上版本进行本文的操作。
2. 准备工作
在进行正式绘图前,我们需要设定以下项目,进行准备工作。
首先安装如下命令,并进行相关设置
ssc install schemepack, replace
set scheme white_tableau //将背景设置为简洁的白色
安装调色板工具palettes
,命令详情可以参见连享会往期推文:Stata绘图:自定义绘图利器-palettes
ssc install palettes, replace
ssc install colrspace, replace
//将默认图形字体设置为 Arial Narrow
graph set window fontface "Arial Narrow"
3. 获取数据
我们首先需要从 Our World in Data 提供的新型冠状病毒数据集中读入数据,对数据进行简单的清洗,并转化成 dta 格式。
//从网络读入数据
import delim using "https://covid.ourworldindata.org/data/owid-covid-data.csv", clear
gen date2 = date(date, "YMD")
format date2 %tdDD-Mon-yy
drop date
ren date2 date
gen date2 = date
order date date2
keep date continent location new_* total*
// 对数据进行清洗
drop if continent==""
replace location = "Bonaire Sint Eustatius" if location =="Bonaire Sint Eustatius and Saba"
replace location = "Bosnia & Herzeg." if location =="Bosnia and Herzegovina"
replace location = "Turks & Caicos Is." if location =="Turks and Caicos Islands"
compress
save owid.dta, replace
生成我们需要的变量。其中,变量 newcases 为某国家(地区)过去 7 日内新增确诊病例数,变量 newdeaths 为某国家(地区)过去 7 日内新增死亡病例数。
newcases_100k 和 newdeaths_100k 为对应的标准化后(每百万人口)的变量。
use owid.dta, clear
sort continent location date
by continent location: gen double newcases = total_cases - total_cases[_n-7]
by continent location: gen double newdeaths = total_deaths - total_deaths[_n-7]
by continent location: gen double newcases_100k = total_cases_per_million - total_cases_per_million[_n-7]
by continent location: gen double newdeaths_100k = total_deaths_per_million - total_deaths_per_million[_n-7]
由于一张图中只绘制一个时间点,因此我们只保留数据集中最近的日期:
summ date
keep if date == `r(max)' - 1
keep date continent location newcases* newdeaths*
我们通过去除空值来进一步缩小我们的样本,以最大化利用环形上的空间。我们删除过去7天的新增死亡病例为零值的样本:
drop if newdeaths_100k < 1
我们按照大洲分组,再按照标准化后的过去 7 日内新增死亡病例数升序排列:
sort continent newdeaths_100k
4. 绘制基础环形柱状图
我们通过以下操作为每一个样本在圆上分配一个位置,即某一样本在圆上对应的角度。其中,2*_pi
( ) 代表 360 度的圆形,而 _n/_N
则代表某一样本在全样本中所占位置。
cap drop angle
gen double angle = (2*_pi)*(_n/_N)
在确定了角度以后,我们需要生成两组点。第一组表示圆上的一个点,第二组表示圆上该点的高度。
summ newdeaths_100k, d
global circ = `r(p99)'
// 圆上的点
gen double xcir = ($circ * cos(angle))
gen double ycir = ($circ * sin(angle))
// 圆上该点的高度
gen double xval = ((newdeaths_100k + $circ ) * cos(angle))
gen double yval = ((newdeaths_100k + $circ ) * sin(angle))
//绘制对应散点图
twoway ///
(scatter yval xval) ///
(scatter ycir xcir) ///
, aspect(1) legend(off)
我们将散点图的散点绘转换成柱状图的条柱,环形柱状图就已经具备了基础的“骨骼”。
twoway ///
(pcspike yval xval ycir xcir, lw(0.6)) ///
, aspect(1) legend(off)
虽然我们的图形已经初现雏形,但还存在以下瑕疵:
坐标轴的范围不一样。由于我们不知道条柱的尖峰会出现在圆上的哪个位置,我们需要确保两个轴上的最小值和最大值是完全相同的数字。换句话说,我们需要以原点 (0,0) 为圆心,并确保图形的范围是完全的正方形。 我们需要为数据标签预留一些空间。
对此,我们进行如下调整:
summ xval
local xmax = `r(max)'
local xmin = `r(min)'
summ yval
local ymax = `r(max)'
local ymin = `r(min)'
global edge = max(`xmax',`ymax', abs(`xmin'), abs(`ymin')) * 1.1
twoway ///
(pcspike yval xval ycir xcir, lw(0.5) ) ///
, ///
xlabel(-$edge $edge) ///
ylabel(-$edge $edge) ///
aspect(1)
经过调整后,我们的环形柱状图变成了如下的样子:
接下来,我们为不同大洲分配不同样色:
// 为不同大洲分配不同样色
local cont
local i
levelsof continent, local(lvls)
local items = `r(r)'
local i = 1
foreach x of local lvls {
colorpalette w3, n("`items'") nograph
local cont `cont' (pcspike yval xval ycir xcir if continent=="`x'", lc("`r(p`i')'") lw(0.5)) ||
local ++i
}
twoway ///
`cont' ///
, ///
xlabel(-$edge $edge) ///
ylabel(-$edge $edge) ///
aspect(1) legend(off)
5. 国家/地区标签
在绘制好环形柱状图的基本框架以后,我们需要为每一样本添加对应的国家安全/地区标签,标签和样本之间应当保持一定距离,我们将偏移距离设置为 30% 。
此外,为了让标签更加简洁美观,我们需要进行如下处理:
首先,我们对样本值进行四舍五入以避免显示太多信息 其次,我们仅将标签限制在那些值为 10 或更高的国家/地区,避免将所有国家/地区的标签堆叠挤压在一起
//设置标签所在位置
cap drop xlab ylab
gen xlab = ((newdeaths_100k + $circ * 1.3) * cos(angle))
gen ylab = ((newdeaths_100k + $circ * 1.3) * sin(angle))
//让标签更加简洁美观
cap drop mylab
gen mylab = location + " (" + string(newdeaths_100k, "%8.0f") + ")" if newdeaths_100k >= 10
//绘图
twoway ///
(pcspike yval xval ycir xcir, lw(0.5) ) ///
(scatter ylab xlab, mlab(mylab) mlabsize(1) mlabpos(0) ms(none) ) ///
, ///
xlabel( -$edge $edge) ///
ylabel(-$edge $edge) ///
aspect(1) legend(off)
可以看到,由于所有的标签都是水平方向,所以标签有所重叠,我们需要根据标签所处的位置在不同方向上旋转标签。
具体地,我们进行如下处理:
将图像划分为四个象限 不同象限的标签旋转不同角度
对应命令如下:
//我们首先按如下方式分配象限
cap drop quad
gen quad = . // quadrants
replace quad = 1 if xcir >= 0 & ycir >= 0
replace quad = 2 if xcir <= 0 & ycir >= 0
replace quad = 3 if xcir <= 0 & ycir <= 0
replace quad = 4 if xcir >= 0 & ycir <= 0
//旋转对应象限的标签角度
cap drop angle2
gen double angle2 = .
replace angle2 = (angle * (180 / _pi)) - 180 if angle > _pi & !inlist(quad,2,4)
replace angle2 = (angle * (180 / _pi)) if angle <= _pi & !inlist(quad,2,4)
replace angle2 = (angle * (180 / _pi)) - 180 if angle <= _pi & quad==2
replace angle2 = (angle * (180 / _pi)) if angle > _pi & quad==4
之后我们重新进行绘图
// 标签
local labs2
qui levelsof mylab , local(lvls) //
foreach x of local lvls {
qui summ angle2 if mylab== "`x'"
local labs2 `labs2' (scatter ylab xlab if mylab== "`x'" , mc(none) mlabel(mylab) mlabangle(`r(mean)') mlabpos(0) mlabcolor() mlabsize(1))
}
// 大洲颜色
local cont
local i
levelsof continent, local(lvls)
local items = `r(r)'
local i = 1
foreach x of local lvls {
colorpalette w3, n("`items'") nograph
local cont `cont' (pcspike yval xval ycir xcir if continent=="`x'", lc("`r(p`i')'") lw(0.5)) ||
local ++i
}
// 绘图
twoway ///
`cont' ///
`labs2' ///
, ///
xlabel(-$edge $edge) ///
ylabel(-$edge $edge) ///
aspect(1) legend(off)
6. 洲名标签
不同的颜色对应不同的大洲,我们需要在图片上添加洲名的标签。洲名的标签需要居中位于对应地区最大值和最小值之间。
cap drop tag
egen tag = tag(continent)
recode tag (0=.)
// 生成变量
cap drop *cont
gen double xcont = .
gen double ycont = .
gen double anglecont = .
// 生成角度
levelsof continent if tag==1, local(lvls)
foreach x of local lvls {
qui summ angle if continent== "`x'"
replace anglecont = (`r(max)' + `r(min)') / 2 if tag==1 & continent== "`x'"
replace xcont = ($circ * 0.9 * cos(anglecont)) if tag==1 & continent== "`x'"
replace ycont = ($circ * 0.9 * sin(anglecont)) if tag==1 & continent== "`x'"
}
上面代码中0.9
是标签的位移值,这样它才不会和图形本身重叠。然后我们还需要将洲名的标签旋转90度,让它和圆弧相切:
replace anglecont = (anglecont * (180 / _pi)) - 90 if tag==1
我们将洲名添加到绘图中
local labcont
levelsof continent if tag==1, local(lvls)
foreach x of local lvls {
summ anglecont if continent== "`x'" & tag==1, meanonly
local labcont `labcont' (scatter ycont xcont if continent== "`x'" & tag==1, mc(none) mlabel(continent) mlabangle(`r(mean)') mlabpos(0) mlabcolor(black) mlabsize(1.8)) ||
}
twoway ///
(pcspike yval xval ycir xcir, lw(0.5) ) ///
`labcont' ///
, ///
xlabel(-$edge $edge) ///
ylabel(-$edge $edge) ///
aspect(1) legend(off)
7. 附:完整绘图代码
最后,我们将所有以上代码进行汇总,绘制环形柱状图,并在圆形中心添加图名和绘图日期。
*************************
** 最终绘图 **
*************************
// 基础环形柱状图框架
local cont
local i
levelsof continent, local(lvls)
local items = `r(r)'
local i = 1
foreach x of local lvls {
colorpalette w3, n("`items'") nograph
local cont `cont' (pcspike yval xval ycir xcir if continent=="`x'", lc("`r(p`i')'") lw(0.5)) ||
local ++i
}
// 国家/地区标签
local labs2
qui levelsof mylab , local(lvls) //
foreach x of local lvls {
qui summ angle2 if mylab== "`x'"
local labs2 `labs2' (scatter ylab xlab if mylab== "`x'" , mc(none) mlabel(mylab) mlabangle(`r(mean)') mlabpos(0) mlabcolor() mlabsize(1))
}
// 大洲标签
local labcont
levelsof continent if tag==1, local(lvls)
foreach x of local lvls {
qui summ anglecont if continent== "`x'" & tag==1, meanonly
local labcont `labcont' (scatter ycont xcont if continent== "`x'" & tag==1, mc(none) mlabel(continent) mlabangle(`r(mean)') mlabpos(0) mlabcolor(black) mlabsize(1.2)) ||
}
// 数据日期
summ date
local date = r(max)
local date : di %tdDD_Mon_yy `date'
// 绘图
twoway ///
`cont' ///
`labs2' ///
`labcont' ///
, ///
xlabel(-$edge $edge, nogrid) ///
ylabel(-$edge $edge, nogrid) ///
legend(off) ///
aspect(1) xsize(1) ysize(1) ///
yscale(off) xscale(off) ///
text( 15 0 "{fontface Merriweather Bold:COVID-19}", size(2.5) box just(center) margin(t+2 b+2) fcolor(none) lw(none) color()) ///
text(-10 0 "deaths per one million pop" "in the past 7 days", size(1.5) box just(center) margin(t+2 b+2) fcolor(none) lw(none) color()) ///
text(-30 0 "(`date')", size(1.1) box just(center) margin(t+2 b+2) fcolor(none) lw(none) color()) ///
note("Source: Our World in Data. Countries with no reported deaths are dropped from the graph. Only countries with over 10 deaths are labeled.", size(1.2))
我们得到了最终的全球多个国家/地区过去7日内新增死亡病例(每百万人口)的环形柱状图:
以上就是本文分享的全部内容了。读者可以仔细探索环形柱状图的一些绘图技巧,熟稔于心,为研究中数据的图形可视化提供更多可能性!
8. 相关推文
Note:产生如下推文列表的 Stata 命令为:
lianxh 柱状图 直方图 可视化
安装最新版lianxh
命令:
ssc install lianxh, replace
专题:专题课程 ⏩连享会公开课:实证研究中的数据可视化 专题:数据处理 Stata:边际处理效应及其可视化-mtefe-T309 Stata: 约翰霍普金斯大学 COVID-19 疫情数据处理及可视化 专题:Stata绘图 Stata可视化:能用图形就不用表格 Stata绘图:回归系数可视化-multicoefplot Stata绘图-可视化:组间差异比较散点图 Stata可视化:biplot一图看尽方差、相关性和主成分 Stata绘图-组间差异可视化:不良事件火山图、点阵图 forest-森林图:分组回归系数可视化 Stata绘图:柱状图专题-T212 Stata绘图:回归系数可视化-论文更出彩 Stata绘图:世行可视化案例-条形图-密度函数图-地图-断点回归图-散点图 Stata:读懂直方图 Stata绘图:随机推断中的系数可视化 Stata绘图:多维柱状图绘制 专题:结果输出 Stata可视化:让他看懂我的结果! 专题:回归分析 Stata:在线可视化模拟-OLS-的性质 专题:Python-R-Matlab Python 调用 API 爬取百度 POI 数据小贴士——坐标转换、数据清洗与 ArcGIS 可视化 专题:工具软件 知乎热议:有哪些一用就爱上的可视化工具?
课程推荐:因果推断实用计量方法
主讲老师:丘嘉平教授
🍓 课程主页:https://gitee.com/lianxh/YGqjp
New! Stata 搜索神器:
lianxh
和songbl
GIF 动图介绍
搜: 推文、数据分享、期刊论文、重现代码 ……
👉 安装:
. ssc install lianxh
. ssc install songbl
👉 使用:
. lianxh DID 倍分法
. songbl all
🍏 关于我们
连享会 ( www.lianxh.cn,推文列表) 由中山大学连玉君老师团队创办,定期分享实证分析经验。 直通车: 👉【百度一下: 连享会】即可直达连享会主页。亦可进一步添加 「知乎」,「b 站」,「面板数据」,「公开课」 等关键词细化搜索。