Stata绘图:复现组间均值差异图

发布时间:2022-08-05 阅读 2504

Stata连享会   主页 || 视频 || 推文 || 知乎 || Bilibili 站

温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。

New! lianxh 命令发布了:
随时搜索推文、Stata 资源。安装:
. ssc install lianxh
详情参见帮助文件 (有惊喜):
. help lianxh
连享会新命令:cnssc, ihelp, rdbalance, gitee, installpkg

课程详情 https://gitee.com/lianxh/Course

课程主页 https://gitee.com/lianxh/Course

⛳ Stata 系列推文:

PDF下载 - 推文合集

作者:方森辉 (南开大学)
邮箱nkfangsenhui@163.com

编者按:本文参考自下文,特此致谢!
Source:Collins C, Landivar L C, Ruppanner L, et al. COVID‐19 and the gender gap in work hours[J]. Gender, Work & Organization, 2021, 28: 101-112. -PDF- -Link-


目录


1. 引言

在阅读文献的过程中,我们时常会被一些精美的图表所吸引,但是这些图表背后的代码逻辑,却是作者们少有呈现的部分。Stata 作为一款统计软件,自然也拥有强大的绘图功能。在本文中,我们将结合 Collins 等 (2021) 这篇文献,使用 Stata 最基本的官方绘图命令 twoway,尝试复现文中的 Figure 1。

2. 思路介绍

原文中 Figure 1 如下:

该图形由 3 个结构一样的子图组成。因此,可以通过绘制其中一个子图 (如下图),再重复绘制多个子图实现图形复现。

通过观察该子图,初步发现其由直方图 (橙色矩形),散点图 (蓝色的圆形点和绿色的棱形点),以及虚线折线图 (灰色的虚线) 三个要素组成。根据 Stata 绘图过程,我们可以依次绘制每个要素,再结合初步绘制的图形调整相对大小。

接下来,我们将顺着这一思路复现该子图。由于文章原作者并未公布原始调查数据,我们将根据人口微观调查数据的常规数据结构和数据特征,生成与原图中统计特征相近的模拟数据,并加总得到调查年龄组-调查月度-家长类型层面数据,以符合图形绘制的要求。

3. 数据整理

一般来讲,人口调查数据是个体 ID 维度的数据,如果是多年或多个追踪调查期的数据,则为个体 ID 和调查期维度。本案例数据为同一年度内 2 月至 4 月每月连续追踪调查获得的数据,其原始数据维度为个体 ID 和月度维度。不过,我们观察 Figure 1 可以发现,原始数据并未直接提供纵轴与横轴的数据维度,需要对其进行加总。

首先,导入原始数据并观察数据维度。可以发现,原始数据为 Month-ChildID-ParentIdentity 维度。

. lxhuse data_for_survey.dta, clear
. des 

 Observations:            90                  
    Variables:             6                  8 Jun 2022 19:21
----------------------------------------------------------------------------------
Variable      Storage   Display    Value
    name         type    format    label      Variable label
----------------------------------------------------------------------------------
Month           byte    %10.0g     Month      调查月份:2-4月
ChildID         byte    %10.0g                个体ID:1-30
Age             byte    %10.0g                年龄:1-17岁
AgeGroup        byte    %8.0g      AgeGroup   年龄层分组:1=[1,5],2=[6,12],3=[13,17]
ParentIdentity  byte    %8.0g      ParentIdentity
                                              家长身份:1=父亲,2=母亲
ParentWorkHour  double  %4.1f                 家长每周工作时间:小时/周
----------------------------------------------------------------------------------
Sorted by: Month  ChildID

其次,加总为 Month-AgeGroup-ParentIdentity 维度的数据。

. * 生成 Month-AgeGroup-ParentIdentity 维度的数据
. net install gtools.pkg, replace // 安装命令 gcollapse
. gcollapse (mean) ParentWorkHour, by(Month AgeGroup ParentIdentity) 
. des

 Observations:            18                  
    Variables:             4                  8 Jun 2022 19:21
---------------------------------------------------------------------------------
Variable      Storage   Display    Value
    name         type    format    label      Variable label
----------------------------------------------------------------------------------
Month           byte    %10.0g     Month      调查月份:2-4月
AgeGroup        byte    %8.0g      AgeGroup   年龄层分组:1=[1,5],2=[6,12],3=[13,17]
ParentIdentity  byte    %8.0g      ParentIdentity
                                              家长身份:1=父亲,2=母亲
ParentWorkHour  double  %4.1f                 (mean) 家长每周工作时间:小时/周
----------------------------------------------------------------------------------
Sorted by: Month  AgeGroup  ParentIdentity
     Note: Dataset has changed since last saved.

最后,转置为 Month-AgeGroup 维度的数据,并保存为新的数据集。

. * 转置为 Month-AgeGroup 维度的数据
. ssc install fastreshape, replace
. fastreshape wide ParentWorkHour, i(Month AgeGroup) j(ParentIdentity) 
. ren (ParentWorkHour1 ParentWorkHour2) (WorkHourFather WorkHourMother) 
. /*根据此前设定的标签重命名变量*/

. gen WorkHourGap=abs(WorkHourFather-WorkHourMother) 
. /*计算两组均值的差异, 这里 WorkHourFather 的取值均大于 WorkHourMother, 
>   但实际数据中两个组别的均值相对大小是未知的, 
>   因此添加一个 abs() 运算符以取两个组别均值差异的绝对值*/

. la var WorkHourFather "Fathers' Work Hours"
. la var WorkHourMother "Mothers' Work Hours"
. la var WorkHourGap "Gender Gap in Work Hours"

. gen invWorkHourGap=51-WorkHourGap*0.85 // 60 为图像的右端点, 也参与构成 xlab 的范围区间
. la var invWorkHourGap "Gender Gap in Work Hours" 
. /*对新生成的 "逆" (inv=inverse) WorkHourGap 采用相同标签命名, 以标识其含义与 WorkHourGap 一致*/
 
. replace Month=Month+4 if AgeGroup==2
. replace Month=Month+8 if AgeGroup==1
. la def Month 2 "February" 3 "March" 4 "April" 6 "February" 7 "March" 8 "April" ///
>     10 "February" 11 "March" 12 "April", replace 
. la val Month Month 
. /*由于本案例是三组数据构成三个子图纵向拼接到一起, 因此需要对调查月份变换取值并添加新的值标签*/

. des
 Observations:             9                  
    Variables:             6                  25 Jul 2022 16:48
---------------------------------------------------------------------------------
Variable      Storage   Display    Value
    name         type    format    label      Variable label
----------------------------------------------------------------------------------
Month           byte    %10.0g     Month      调查月份:2-4月
AgeGroup        byte    %8.0g      AgeGroup   年龄层分组:1=[1,5],2=[6,12],3=[13,17]
WorkHourFather  double  %4.1f                 Fathers' Work Hours
WorkHourMother  double  %4.1f                 Mothers' Work Hours
WorkHourGap     float   %9.0g                 Gender Gap in Work Hours
invWorkHourGap  float   %9.0g                 Gender Gap in Work Hours
----------------------------------------------------------------------------------
Sorted by: 
     Note: Dataset has changed since last saved.

. list // 显示绘图前的最后数据, 其中 Month 和 AgeGroup 显示的是值标签
     +-----------------------------------------------------------------+
     |    Month   AgeGroup   Wo~ather   Wo~other   WorkHo~p   invWor~p |
     |-----------------------------------------------------------------|
  1. | February      [1,5]       41.1       36.2        4.9     46.835 |
  2. | February     [6,12]       41.7       37.0        4.7     47.005 |
  3. | February    [13,17]       42.6       38.3        4.3     47.345 |
  4. |    March      [1,5]       41.6       36.1        5.5     46.325 |
  5. |    March     [6,12]       41.5       36.4        5.1     46.665 |
     |-----------------------------------------------------------------|
  6. |    March    [13,17]       42.6       38.4        4.2      47.43 |
  7. |    April      [1,5]       40.6       34.4        6.2      45.73 |
  8. |    April     [6,12]       41.5       35.2        6.3     45.645 |
  9. |    April    [13,17]       41.4       36.8        4.6      47.09 |
     +-----------------------------------------------------------------+

. list, nolabel // 显示绘图前的最后数据, 其中 Month 和 AgeGroup 显示的是数值, 绘图时选项 if 使用的是数值
     +--------------------------------------------------------------+
     | Month   AgeGroup   Wo~ather   Wo~other   WorkHo~p   invWor~p |
     |--------------------------------------------------------------|
  1. |    10          1       41.1       36.2        4.9     46.835 |
  2. |     6          2       41.7       37.0        4.7     47.005 |
  3. |     2          3       42.6       38.3        4.3     47.345 |
  4. |    11          1       41.6       36.1        5.5     46.325 |
  5. |     7          2       41.5       36.4        5.1     46.665 |
     |--------------------------------------------------------------|
  6. |     3          3       42.6       38.4        4.2      47.43 |
  7. |    12          1       40.6       34.4        6.2      45.73 |
  8. |     8          2       41.5       35.2        6.3     45.645 |
  9. |     4          3       41.4       36.8        4.6      47.09 |
     +--------------------------------------------------------------+

. di _N 
. compress
. save data_for_Figure, replace

4. 图形复现

本部分主要依托于 twoway 的子命令 droplinescatter,对某个年龄层组别 (AgeGroup) 绘制多个图层来构成一个子图,然后对其他年龄层组别重复操作实现 Figure 1 的绘制。总体来看属于使用基本官方命令绘制复杂图形的一个案例。

. use data_for_Figure, clear
. tw (dropline WorkHourFather Month if AgeGroup==1, base(30) ms(i) lc(gray*0.6%80)        ///
>     lp(shortdash) lw(*2.5) horizontal)                                                  /// 
>     /*dropline 用于绘制灰色线, 选项 lp(shortdash) 与 lw(*2.5) 搭配绘制出类似散点的效果,     ///
>     可以更换为其他线型*/                                                                  ///
>     (dropline WorkHourMother Month if AgeGroup==1, base(30) ms(i) lc(gray*0.6%80)       ///
>     lp(shortdash) lw(*2.5) horizontal)                                                  ///
>     (sc Month WorkHourFather if AgeGroup==1, ms(O) msize(*1.2) mc(ebblue*2)             ///
>     mlabel(WorkHourFather) mlabc(black)  mlabs(*1.1) mlabp(12)  mlabg(*1.5))            /// 
>     /*sc=scatter 用于绘制蓝色的圆形点*/                                                   ///
>     (sc Month WorkHourMother if AgeGroup==1, ms(d) msize(*1.2) mc(dkgreen*0.75)         ///
>     mlabel(WorkHourMother) mlabc(black)  mlabs(*1.1) mlabp(12)  mlabg(*1.5))            /// 
>     /*sc=scatter 用于绘制绿色的棱形点*/                                                   ///
>     (dropline invWorkHourGap Month if AgeGroup==1, base(51) ms(i) lc(dkorange*0.8)      ///
>     lp(solid) lw(*12) horizontal mlabel(WorkHourGap) mlabc(black) mlabs(*1.1) mlabp(9)) /// 
>    /*dropline 用于绘制橙黄色的直方图, 选项 lp(solid) 与 lw(*12) 搭配,                      ///
>    可以实现将线变宽实现类似直方图的效果, 也可以使用 addplot 与 graph hbar 的组合命令*/       ///
>    (dropline WorkHourFather Month if AgeGroup==2, base(30) ms(i) lc(gray*0.6%80)        ///
>    lp(shortdash) lw(*2.5) horizontal)                                                   ///
>     (dropline WorkHourMother Month if AgeGroup==2, base(30) ms(i) lc(gray*0.6%80)       ///
>     lp(shortdash) lw(*2.5) horizontal)                                                  ///
>     (sc Month WorkHourFather if AgeGroup==2, ms(O) msize(*1.2) mc(ebblue*2)             ///
>     mlabel(WorkHourFather) mlabc(black)  mlabs(*1.1) mlabp(12)  mlabg(*1.5))            ///
>     (sc Month WorkHourMother if AgeGroup==2, ms(d) msize(*1.2) mc(dkgreen*0.75)         ///
>     mlabel(WorkHourMother) mlabc(black)  mlabs(*1.1) mlabp(12)  mlabg(*1.5))            ///
>     (dropline invWorkHourGap Month if AgeGroup==2, base(51) ms(i) lc(dkorange*0.8)      ///
>     lp(solid) lw(*12) horizontal mlabel(WorkHourGap) mlabc(black) mlabs(*1.1) mlabp(9)) ///
>     (dropline WorkHourFather Month if AgeGroup==3, base(30) ms(i) lc(gray*0.6%80)       ///
>     lp(shortdash) lw(*2.5) horizontal)                                                  ///
>     (dropline WorkHourMother Month if AgeGroup==3, base(30) ms(i) lc(gray*0.6%80)       ///
>     lp(shortdash) lw(*2.5) horizontal)                                                  ///
>     (sc Month WorkHourFather if AgeGroup==3, ms(O) msize(*1.2) mc(ebblue*2)             ///
>     mlabel(WorkHourFather) mlabc(black)  mlabs(*1.1) mlabp(12)  mlabg(*1.5))            ///
>     (sc Month WorkHourMother if AgeGroup==3, ms(d) msize(*1.2) mc(dkgreen*0.75)         ///
>     mlabel(WorkHourMother) mlabc(black)  mlabs(*1.1) mlabp(12)  mlabg(*1.5))            ///
>     (dropline invWorkHourGap Month if AgeGroup==3, base(51) ms(i) lc(dkorange*0.8)      ///
>     lp(solid) lw(*12) horizontal mlabel(WorkHourGap) mlabc(black) mlabs(*1.1) mlabp(9)) ///
>     , xlab(30(25)55 30 " " 55 " " 37 "Work Hours" 47 "Gender Gap in Work Hours", nogrid ///
>     noticks labsize(*0.8))                                                              ///
>     /*横轴的标签, 选项 nogrid 去除图内的网格线, 选项 noticks 去除横轴的刻度*/               ///
>     ylab(1(11.5)12.5 1 " " 12.5 " " 2 "February" 3 "March" 4 "April" 6 "February"       ///
>     7 "March" 8 "April" 10 "February" 11 "March" 12 "April", nogrid noticks angle(0)    ///
>     labsize(*0.8)) ytitle("Survey Month") yscale(reverse)                               ///
>     /*选项 yscale(reverse) 让纵轴刻度大小反转, 从上到下的数值依次增大*/                     ///
>     graphregion(color(white)) title("Gender Gap in Hours Worked among Parents")         ///
>     legend(order(4 "Mothers' Work Hours" 3 "Fathers' Work Hours"                        ///
>     5 "Gender Gap in Work Hours") cols(2) rows(2) size(*0.8))                           ///   
>     /*选项 legend(order()) 设定图例, 注意这里需要结合绘制的曲线顺序来设置需要的图例*/        ///
>     text(3 54 "[13,17]") text(7 54 "[6,12]") text(11 54 "[1,5]") text(1 54 "Children")  ///
>     text(1.5 54 "Aged Group")                                                           ///
>     /*选项 text 设定图像右侧的组别说明, 需要根据图像显示效果手动调整位置和字体大小*/          ///
>     xsize(12) ysize(10)                                                                 ///
>     /*选项 xsize 和 ysize 设置图像的长宽比例, 建议与要输出的 png 等格式图片的长宽比例一致, 
>     以保证绘制出来的图像显示效果与最终导出的图像效果一致*/

. gr save "FigureGenderGap", replace
. gr export "FigureGenderGap.png", replace as(png) height(2000) width(2400) 
. /*选项 height(2000) 和 width(2400) 设置图像纵向高度和横向宽度, 默认单位为像素*/

与论文中 Figure 1 相比,本次图形复现结合 Stata 的绘图特点进行了一定修改,最终绘制的图形如下:

5. 结语

以上就是 Figure 1 图形复现的基本介绍,本案例为我们如何复现已有文献的图形提供了一些思路:不论已有图形多复杂,只要化整为零,即使采用 twoway 命令也可以复现出较为复杂的图形。当然,在论文中展示精美图形的同时,也需要对图形作出恰到好处的释义,以更好服务于论文故事的讲述,起到一种锦上添花的效果。

6. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh 绘图, m
安装最新版 lianxh 命令:
ssc install lianxh, replace

相关课程

免费公开课

最新课程-直播课

专题 嘉宾 直播/回看视频
最新专题 文本分析、机器学习、效率专题、生存分析等
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
面板模型 连玉君 直击面板数据模型 [免费公开课,2小时]
  • Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。

课程主页

课程主页

关于我们

  • Stata连享会 由中山大学连玉君老师团队创办,定期分享实证分析经验。
  • 连享会-主页知乎专栏,700+ 推文,实证分析不再抓狂。直播间 有很多视频课程,可以随时观看。
  • 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标,输入简要关键词,以便快速呈现历史推文,获取工具软件和数据下载。常见关键词:课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法

连享会小程序:扫一扫,看推文,看视频……

扫码加入连享会微信群,提问交流更方便

✏ 连享会-常见问题解答:
https://gitee.com/lianxh/Course/wikis

New! lianxhsongbl 命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh