G8. 27个Stata绘图范例

作者: 孙晓艺 (厦门大学)
邮箱:

本文摘译自以下文章,特此致谢! Source: Fahad Mirza, 2022. Blog. Top 25 Stata Visualizations — With Full Code, -Link-

数据可视化可以帮助我们将大量的数据以易于理解的方式呈现给读者,我们学完 stata 后,在实操时可能经常会遇到这样一个问题:我应该选取哪种可视化方式才能呈现出我想要的效果?实际上,数据可视化的目的可能有很多,但概括起来大致包括以下四种:描述关联性关系、偏差关系、排序关系或分布关系,我们需要达到的可视化效果很可能属于其中一个或多个类别。笔者在正文具体展示了四种可视化效果下共 25 种 stata 图表类型,并附有完整代码,希望可以帮助读者找到适合的可视化工具。  

A. 命令安装

我们在开始介绍之前,需要先在 stata 中安装各类绘图命令:

 ssc install schemepack, replace
 ssc install colrspace, replace
 ssc install palettes, replace
 ssc install labutil, replace

 ssc install violinplot, replace
 ssc install dstat, replace
 ssc install moremata, replace

接着,我们将对关联关系图(Correlation)、偏差关系图 (Deviation)、排序关系图(Ranking)和分布关系图(Distribution)四类分别展开介绍。

B. 关联关系图

通过以下八种可视化工具,我们可以检验两个变量之间的相关性强度。

1. 散点图 (Scatterplot)

散点图是数据可视化最常用的方法之一,它主要用于研究两个变量之间的关系和性质。

基本命令:twoway scatter

同时,twoway (scatter y x) (lowess y x) 可以绘制散点图和拟合曲线的叠加图。

范例如下:

sysuse auto, clear
twoway (scatter price mpg, mcolor(%60) mlwidth(0))  ///
  (lowess price mpg), /// 
  title("{bf}Scatterplot", pos(11) size(2.75)) ///  标题
  subtitle("Price Vs. MPG", pos(11) size(2.5)) /// 副标题
  legend(off) /// 图例说明,`legend(off)` 表示无图例
  scheme(white_tableau)  // 绘图模板使用白色

关于各选项 (option) 的具体说明可详见推文 给你的图形化个妆:Stata绘图常用选项汇总-上篇给你的图形化个妆:Stata绘图常用选项汇总-下篇 或在 \(Stata\) 中查看帮助文件:help twowayhelp scatter

命令运行结果见下图:

2. 分组散点图 (Scatterplot by Group)

如果我们想要分别绘制两组的散点图,并在一张图表中展示,可以使用下面的代码实现。

基本命令: twoway scatter

不同于一般散点图,分组散点图需要提前指定或创建分组变量,并在绘制前使用 foreach 命令循环生成并存储两组散点图的代码。

范例如下:

sysuse auto, clear
  
levelsof foreign, local(foreign)
foreach category of local foreign {
   local scatter `scatter' scatter price mpg if foreign == `category', ///
   mcolor(%60) mlwidth(0) ||
}
 
twoway  `scatter' (lowess price mpg), ///
  title("{bf}Scatterplot", pos(11) size(2.75)) ///
  subtitle("Price Vs. MPG", pos(11) size(2.5)) ///
  legend(order(1 "Domestic" 2 "Foreign") size(2)) ///
  scheme(white_tableau)

命令运行结果见下图:

根据 \(foreign\) 变量分为 \(Domestic\)\(Foreign\) 两组,分别绘制国产车和进口车行车里程 (mileage) 与价格 (price) 的散点图,并添加整体数据的拟合曲线。

另外,如果我们想要同时分组绘制散点图和拟合曲线,只需要在循环生成散点图代码时加上 lowess 命令行即可。

依照上例,范例代码为:

sysuse auto, clear
  
levelsof foreign, local(foreign)
foreach category of local foreign {
   local  scatter `scatter' scatter price mpg if foreign == `category', ///
   mcolor(%60) mlwidth(0) ||
local  lowess `lowess' lowess price mpg if foreign == `category', ///
   mcolor(%60) mlwidth(0) ||
}
twoway  `scatter' `lowess', ///
  title("{bf}Scatterplot", pos(11) size(2.75)) ///
  subtitle("Price Vs. MPG", pos(11) size(2.5)) ///
  legend(order(1 "Domestic" 2 "Foreign") size(2)) ///
  scheme(white_tableau)

命令运行结果如下图:

3. 抖动图 (Jitter Plot)

在散点图中,所有数据都用垂直线对齐,虽然看起来更加整洁,但是我们可以发现绘图区域上的点数与数据观测值的数量并不相等,主要是因为这些点相互重叠,扭曲了基础数据。为了观测完整数据,我们需要使用 jitter 命令来随机分散这些点。

基本命令:scatter y x, jitter()

抖动图命令与散点图类似,但需要在后面加上 jitter() 选项,括号内填写抖动值,抖动值越大,这些点就越分散。

范例代码如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

twoway  (scatter hwy cty, jitter(5) mcolor(%60) mlwidth(0)) ///
  (lfit hwy cty), ///
  title("{bf}Jittered points", pos(11) size(2.75)) ///
  subtitle("mpg: City vs Highway mileage", pos(11) size(2.5)) ///
  legend(off) ///
  scheme(white_tableau)
// `lift` 为拟合直线,上述 `lowess` 为拟合曲线
// pos(11) 表示将标题放在图形11点钟附近,即左上角

命令运行结果见下图:

4. 计数图 (Counts Chart)

对于散点图中无法展示的重叠数据,除了使用抖动图分散观测数据这个方法之外,我们也可以使用计数图展示。在计数图中,将重叠数据标记加权,随着重叠点数的增加,标记的大小也随之扩大。

基本命令:scatter y x [aw = count]

其中,[aw = count] 是一种权重选项,用于指定观测值的权重。 \(count\) 表示某数据值出现的次数,在散点图中,该权重选项将根据变量 \(count\) 的值为每个观测点分配权重。这意味着具有更高 \(count\) 值的观测点将在图形中显示为更大的点,而具有较低 \(count\) 值的观测点将显示为更小的点。

需要注意的是,在使用基本命令绘制计数图之前,我们需要通过以下两步创建权重变量 \(count\)第一步: 使用 group 函数,标识 y 和 x 变量中的唯一值; 第二步: 使用 count() 函数对 y 和 x 变量中的各个唯一值计数,生成权重变量 \(count\)

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

egen total = group(cty hwy)
bysort total: egen count = count(total)
  
twoway  (scatter hwy cty [aw = count],mcolor(%60) mlwidth(0) msize(1))  ///
  (lfit hwy cty), ///
  title("{bf}Counts plot", pos(11) size(2.75)) ///
  subtitle("mpg: City vs Highway mileage", pos(11) size(2.5)) ///
  legend(off) ///
  scheme(white_tableau) 

命令运行结果见下图:

5. 气泡图 (Bubble Chart)

气泡图是散点图的变体,可以同时展示三个变量之间的关系,其中,x 轴和 y 轴分别代表两个变量的信息,气泡的大小反映了第三个变量的信息。

基本命令:twoway scatter y x [fw = weight] 其中,\(weight\) 为权重变量,需要指定或提前生成

为了使气泡图更好地展示变量之间的关系,我们可以另外增加以下工作: 1. 指定类别变量,分组绘制不同类别下的气泡图; 2. 添加 linelifitlowess 指令,绘制散点图和拟合线的叠加图; 3. 在 scatter 命令后增加 jitter() 选项,可以在散点图中添加抖动,以避免重叠,观测完整数据; 4. 在 scatter 命令后增加 mcolor() 选项,指定散点颜色,有助于区分不同类别的气泡图。

范例代码如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

** 明确绘制气泡图的分组变量 manufacturer
keep if inlist(manufacturer, "audi", "ford", "honda", "hyundai")

** 生成权重变量 `weight` 
recode hwy  (15 16 17 18 19 = 1) (20 21 22 23 24 = 4) (25 26 27 28 29 = 8) ///
  (30 31 32 33 34 = 16) (35 36 = 32), gen(weight)

** 使用循环,分组绘制四种 manufacturer 的气泡图
levelsof manufacturer, local(options)
local wordcount : word count `options'
  
local i = 1
foreach option of local options {
 
 colorpalette tableau, n(`wordcount') nograph
 
 local  scatter `scatter' scatter cty displ [fw = weight] ///
 if manufacturer == "`option'", ///
   mcolor("`r(p`i')'%60") mlwidth(0) jitter(10) ||
   
 local  line `line' lfit cty displ  ///
 if manufacturer == "`option'", lcolor("`r(p`i')'") ||
 
 local ++i
}
  
twoway  `scatter' `line', ///
  title("{bf}Bubble Chart", pos(11) size(2.75)) ///
  subtitle("mpg: Displacement vs City mileage", pos(11) size(2.5)) ///
  ytitle("City Mileage", size(2)) ///
  legend(order(3 "Honda" 4 "Hyundai" 1 "Audi" 2 "Ford" ) size(2)) ///
  scheme(white_tableau)

命令运行结果见下图:

该气泡图描述了四家不同制造商(\(manufacturer\))生产的车辆,发动机排量(\(Displacement\))和城市里程(\(City Mileage\))、公路里程(\(Highway mileage\))之间的关系。x 轴和 y 轴分别为发动机排量(\(Displacement\))和城市里程(\(City Mileage\)),气泡大小代表不同等级的公路里程(\(Highway mileage\))。

6. 边缘直方图 (Marginal Histogram)

边缘直方图可以同时展示两个变量之间的关系和各自的分布情况。

绘制边缘直方图,需要分别绘制出计数图和 \(x\) 轴、 \(y\) 轴变量各自的直方图。基本步骤如下:

第一步: 绘制计数图,命名为 \(main\) ,基本命令: twoway (scatter y x [aw = count]) (lfit y x) name(main, replace)

第二步: 绘制 x 轴变量的直方图,命名为 \(xhist\),基本命令: twoway (histogram x, name(xhist, replace)

第三步: 绘制 y 轴变量的直方图,命名为 \(yhist\),基本命令同上: twoway (histogram y, horizontal, name(yhist, replace)

其中,horizontal 表示直方图是水平的,而非默认的垂直,便于后面叠加。 (在绘制直方图时需要注意的是,以上只是基本命令,由于直方图需要分别叠加在计数图的上方和右侧,在绘制时,需要添加 fysizefxsize 以及 graphregion 等选项,调整直方图的高度和宽度等,具体代码见如下范例。)

第四步: 叠加计数图和两个直方图,基本命令: graph combine xhist main yhist

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

egen total = group(cty hwy)
bysort total: egen count = count(total)

** 绘制主图-计数图
twoway  (scatter hwy cty [aw = count],  ///
  mcolor(%60) mlwidth(0) msize(1) legend(off)) ///
  (lfit hwy cty), legend(off) name(main, replace) ///
  ytitle("Highway MPG") xtitle("City MPG") ///
  graphregion(margin(t=-5))  
    // graphregion() 指定图形的区域参数

** 绘制 x 轴变量直方图
twoway  (histogram cty, yscale(off) xscale(off) ///
  ylabel(, nogrid) xlabel(, nogrid) bin(30)),  ///
  name(cty_hist, replace) graphregion(margin(l=16)) fysize(15) 
    // fysize() 设置图形的高度

** 绘制 y 轴变量直方图
twoway  (histogram hwy, horizontal yscale(off) xscale(off) /// 
  ylabel(, nogrid) xlabel(, nogrid) bin(30)),  ///
  name(hwy_hist, replace) graphregion(margin(b=15 t=-5)) fxsize(20)
    // fxsize() 设置图形的宽度

** 三图叠加 
graph combine cty_hist main hwy_hist,  ///
  hole(2) commonscheme scheme(white_tableau) ///
  title("{bf}Marginal Histogram - Scatter Count plot", size(2.75) pos(11))  ///
  subtitle("mpg: Highway vs. City Mileage", size(2.5) pos(11))

命令运行结果见下图:

7. 边缘箱图 (Marginal Boxplot)

边缘箱图也可以同时展示两个变量之间的关系和各自的分布情况,与边缘直方图的不同之处在于,边缘箱图使用箱图代替直方图,看起来更加简约。主要绘制步骤如下:

第一步: 绘制计数图,命名为 \(main\),基本命令: twoway (scatter y x [aw = count]) (lfit y x) name(main, replace)

第二步: 绘制 \(x\) 轴变量的箱图,命名为 \(xbox\),主要包括三部分: ① 绘制一条从上四分位数到最大异常值之间的线段,基本命令为:

scatteri `p75_`var'' 1 `max_`var'uq' 1, recast(line)

其中,scatteri 命令用于绘制散点图,但可以通过指定 recast (line) 选项用于绘制线条图。 ② 绘制一个代表变量中位数的方块,基本命令:

scatteri 1 `med_p_`var'', ms(square)

③ 绘制一条从下四分位数到最小异常值之间的线段,基本命令:

scatteri `p25_`var'' 1 `min_`var'lq' 1, recast(line)

第三步: 绘制 \(y\) 轴变量的箱图,命名为 \(ybox\),基本命令同上;

第四步: 叠加计数图和两个箱图,基本命令: graph combine xbox main ybox

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear
egen total = group(cty hwy)
bysort total: egen count = count(total)

** 绘制计数图  
twoway  (scatter hwy cty [aw = count],  ///
  mcolor(%60) mlwidth(0) msize(1) legend(off)) ///
  (lfit hwy cty), legend(off) name(main, replace)  ///
  ytitle("Highway MPG") xtitle("City MPG") ///
  graphregion(margin(t=-5))

** 使用循环分别绘制 x 轴和 y 轴变量的箱图 
local i = 1
local j = 10
foreach var of varlist hwy cty {
  sort `var', stable
 
  quietly summarize `var', detail
  
  local mean_`var' = `r(mean)'
  local med_p_`var' = `r(p50)'
  local p75_`var' = `r(p75)'
  local p25_`var' = `r(p25)'
  local iqr_`var' = `p75_`var'' - `p25_`var''
    
  generate `var'uq = `var' if `var' <= `=`p75_`var''+(1.5*`iqr_`var'')'
  generate `var'lq = `var' if `var' >= `=`p25_`var''-(1.5*`iqr_`var'')'
    
  quietly summarize `var'uq
  local max_`var'uq = `r(max)'
  quietly summ `var'lq
  local min_`var'lq = `r(min)'
    
  if `i' == 1 {
  colorpalette tableau, nograph
  local  lines`i' ///
    (scatteri `p75_`var'' 1 `max_`var'uq' 1, recast(line) lpattern(solid) lcolor("`r(p`j')'") lwidth(1)) || ///
    (scatteri `p25_`var'' 1 `min_`var'lq' 1, recast(line) lpattern(solid) lcolor("`r(p`j')'") lwidth(1)) || ///
    (scatteri `med_p_`var'' 1, ms(square) mcolor(background) msize(2)) || ///
    (scatteri `med_p_`var'' 1, ms(square) mcolor("`r(p`j')'")) || 
  }
  
  else {
  colorpalette tableau, nograph
  local  lines`i' ///
    (scatteri 1 `p75_`var'' 1 `max_`var'uq', recast(line) lpattern(solid) lcolor("`r(p`j')'") lwidth(1)) || ///
    (scatteri 1 `p25_`var'' 1 `min_`var'lq', recast(line) lpattern(solid) lcolor("`r(p`j')'") lwidth(1)) || ///
    (scatteri 1 `med_p_`var'', ms(square) mcolor(background) msize(2)) || ///
    (scatteri 1 `med_p_`var'', ms(square) mcolor("`r(p`j')'")) || 
  }
    
    
    drop *lq *uq
    
    local ++i
    local j = `j' + 4
  }
 
twoway `lines1', legend(off) xlabel(, nogrid)  ///
  ylabel(, nogrid) yscale(off) xscale(off)  ///
  name(hwy_box, replace) graphregion(margin(b=15 t=-5)) fxsize(5)
twoway `lines2', legend(off) xlabel(, nogrid) ylabel(, nogrid)  ///
  yscale(off) xscale(off)   ///
  name(cty_box, replace) graphregion(margin(l=16)) fysize(5)

** 三图叠加,绘制边缘箱图
graph  combine cty_box main hwy_box,  ///
  hole(2) commonscheme ycommon xcommon scheme(white_tableau) ///
  title("{bf}Marginal Box Plot - Scatter Count plot", size(2.75) pos(11))  ///
  subtitle("mpg: Highway vs. City Mileage", size(2.5) pos(11))

命令运行结果见下图:

8. 相关性热图 (Correlogram)

相关性热图用于描述多个变量之间的相关性,目前 \(Stata\) 中没有包含这一命令,因此需要手动编码,具体见范例,修改代码时只需要在 local var_corr 后面加入新的变量名,余下工作下面的代码会自动完成。

sysuse auto, clear 
  
local var_corr price mpg trunk weight length turn foreign  // 定义变量列表
local countn : word count `var_corr'
  
** 计算相关系数,保存在相关系数矩阵C
quietly correlate `var_corr'
matrix C = r(C)
local rnames : rownames C
  
** 清除当前数据集
clear
   
** 创建并填充新数据集
local tot_rows : display `countn' * `countn'
set obs `tot_rows'

generate corrname1 = ""
generate corrname2 = ""
generate y = .
generate x = .
generate corr = .
generate abs_corr = .
   
local row = 1
local y = 1
local rowname = 2
    
foreach name of local var_corr {
 forvalues i = `rowname'/`countn' { 
  local a : word `i' of `var_corr'
  replace corrname1 = "`name'" in `row'
  replace corrname2 = "`a'" in `row'
  replace y = `y' in `row'
  replace x = `i' in `row'
  replace corr = round(C[`i',`y'], .01) in `row'
  replace abs_corr = abs(C[`i',`y']) in `row'
  
  local ++row
  
 }
 
 local rowname = `rowname' + 1
 local y = `y' + 1

}
   
drop if missing(corrname1)
replace abs_corr = 0.1 if abs_corr < 0.1 & abs_corr > 0.04
  
colorpalette HCL pinkgreen, n(10) nograph intensity(0.65)

generate colorname = ""
local col = 1
forvalues colrange = -1(0.2)0.8 {
 replace colorname = "`r(p`col')'" if corr >= `colrange' & corr < `=`colrange' + 0.2'
 replace colorname = "`r(p10)'" if corr == 1
 local ++col
} 
  
** 循环生成散点图代码
forvalues i = 1/`=_N' {

 local slist "`slist' (scatteri `=y[`i']' `=x[`i']' "`: display %3.2f corr[`i']'", mlabposition(0) msize(`=abs_corr[`i']*15') mcolor("`=colorname[`i']'"))"

}
   
** 收集 y 轴标签
labmask y, val(corrname1)
labmask x, val(corrname2)

levelsof y, local(yl)
foreach l of local yl {
 local ylab "`ylab' `l'  `" "`:lab (y) `l''" "'" 
 
} 

** 收集 x 轴标签
levelsof x, local(xl)
foreach l of local xl {
 local xlab "`xlab' `l'  `" "`:lab (x) `l''" "'" 
 
}  
  
**绘图
twoway `slist', title("Correlogram of Auto Dataset Cars", size(3) pos(11)) ///
  note("Dataset Used: Sysuse Auto", size(2) margin(t=5)) ///
  xlabel(`xlab', labsize(2.5)) ylabel(`ylab', labsize(2.5)) ///
  xscale(range(1.75 )) yscale(range(0.75 )) ///
  ytitle("") xtitle("") ///
  legend(off) ///
  aspect(1) ///
  scheme(white_tableau)

命令运行结果见下图:

C. 偏差关系图(Deviation)

9. 发散条形图 (Diverging Bars)

发散条形图可以直观地显示数据集中某变量正值和负值的分布情况,通过绘制水平发散条形图,正值有序集中在条形图上半方,绿色显示,负值则排列在下半方,红色显示。

基本命令:

twoway (bar y x if D == 1, horizontal  ///
    lwidth(0) barwidth(1.5) bcolor("`r(p3)'"))  ///
    (bar y x if D == 0, horizontal  ///
    lwidth(0) barwidth(1.5) bcolor("`r(p4)'"))

其中,bar 命令用于绘制条形图,\(y\) 为我们想要展示的变量,\(x\) 为类别变量,\(D\) 为虚拟变量,通常,当 \(y>=0\) 时,\(D=1\),否则为 0,horizontal 表示绘制水平条形图,bcolor 选项用于调整颜色 。

范例如下:

sysuse auto, clear
  
** 计算变量标准差
egen double mpg_z = std(mpg)
  
** 生成虚拟变量,分别绘制正值和负值集合
generate above = (mpg_z >= 0)
  
** 对 mpg_z 排序并分配排名
sort mpg_z, stable
generate rank_des = _n * 2
  
** 根据排名赋以标签
labmask rank_des, value(make)
  
** 绘图
colorpalette tableau, nograph intensity(0.8)
twoway  (bar mpg_z rank_des if above == 1,  ///
  horizontal lwidth(0) barwidth(1.5) bcolor("`r(p3)'")) ///
  (bar mpg_z rank_des if above == 0,  ///
  horizontal lwidth(0) barwidth(1.5) bcolor("`r(p4)'")), ///
  ytitle("") xtitle("") ///
  ylabel(2(2)148, valuelabel labsize(1.25) nogrid)  ///
  xlabel(-4(1)4, nogrid) ///
  xscale(range(-4 4)) ///
  legend(off) ///
  title("{bf}Diverging Bars (Normalized MPG)",  ///
  size(2.75) pos(11)) ///
  scheme(white_tableau)

命令运行结果见下图:

10. 发散型棒棒糖图 (Diverging Lollipop Graph)

发散型棒棒糖图与发散条形图整体类似,不同之处在于,发散型棒棒糖图更为精简,并标出每一类别的变量值。

基本命令为:

twoway rspike y1 y2 x

其中,\(y_1\) 为参考变量,\(y_2\) 为想要描述或展示的变量,\(x\) 为类别变量。

范例如下:

sysuse auto, clear
keep in 1/20

** 计算变量标准差
egen double mpg_z = std(mpg)
  
** 对 mpg_z 排序并分配排名
sort mpg_z, stable
generate rank_des = _n   
  
** 根据排名赋以标签
labmask rank_des, value(make)

** 生成零点——参考点
generate zero = 0
  
** 数据格式化并压缩
tostring mpg_z, gen(mpg_z_lab) force format(%3.2f)
compress
  
** 绘图 
twoway (rspike zero mpg_z rank_des, horizontal) ///
  (scatter rank_des mpg_z,  ///
  msize(5.3) mlabel(mpg_z_lab) mlabsize(1.5) mlabposition(0)), ///
  xlabel(-2.5(1)-0.5 0 0.5(1)2.5, labsize(2))  ///
  ylabel(1(1)20, valuelabel labsize(2)) ///
  legend(off) ///
  ytitle("Car Name") ///
  title("{bf}Diverging Lollipop Chart (Normalized MPG)", size(2.75) pos(11)) ///
  scheme(white_tableau)

命令运行结果见下图:

11. 发散点图 (Diverging Dot Plot)

相比与前面两张图,发散点图也可以描述相似的信息,但是相对更加精简。

它的基本命令为:

twoway (scatter x y if D == 1,  ///
  mcolor("`r(p4)'") msize(5)  ///
  mlabel() mlabsize(1.3) mlabposition(0))  /// 
  (scatter x y if D == 0,  ///
  mcolor("`r(p3)'") msize(5)  ///
  mlabel() mlabsize(1.3) mlabposition(0))

其中,bar 命令用于绘制条形图,\(y\) 为我们想要展示的变量,\(x\) 为类别变量,\(D\) 为虚拟变量,通常,当 \(y>=0\) 时,\(D=1\),否则为 0。

范例如下:

sysuse auto, clear
keep in 1/20
  
** 计算变量标准差
egen double mpg_z = std(mpg)
  
** 对 mpg_z 排序并分配排名
sort mpg_z, stable
generate rank_des = _n   
  
** 根据排名赋以标签
labmask rank_des, value(make)

** 生成虚拟变量,分别绘制正值和负值集合 
generate above = (mpg_z >= 0)
  
** 数据格式化并压缩
tostring mpg_z, gen(mpg_z_lab) force format(%3.2f)
compress
  
** 绘图 
colorpalette tableau, nograph intensity(0.8)
twoway  (scatter rank_des mpg_z if above == 0,  ///
  mcolor("`r(p4)'") msize(5) mlabel(mpg_z_lab) mlabsize(1.3) mlabposition(0)) ///
  (scatter rank_des mpg_z if above == 1,  ///
  mcolor("`r(p3)'") msize(5) mlabel(mpg_z_lab) mlabsize(1.3) mlabposition(0)) ///
  , ///
  xlabel(-2.5(1)-0.5 0 0.5(1)2.5, labsize(2))  ///
  ylabel(1(1)20, valuelabel labsize(2)) ///
  legend(off) ///
  ytitle("Car Name") ///
  title("{bf}Diverging Dot Plot (Normalized MPG)",  ///
  size(2.75) pos(11)) ///
  scheme(white_tableau)

命令运行结果见下图:

12. 发散条形图 - 相关图 (Diverging Bars — Correlation Plot)

与相关性热图相比,发散条形图也可以用来描述各变量之间的相关程度,只是将表现形式由矩阵换为了条形图。目前 \(stata\) 中还没有相关命令的安装包,因此代码较为冗杂,我们绘制发散条形图时,只需要修改 local var_corr 后面的变量名即可,余下代码会帮助完成其他的工作。

范例代码如下:

sysuse auto, clear 
    
local var_corr price mpg trunk weight length turn foreign   // 定义变量列表
local countn : word count `var_corr'
  
** 计算相关系数,保存在相关系数矩阵C
quietly corrci `var_corr'
matrix C = r(corr)
local rnames : rownames C
  
** 清除当前数据集
clear
   
  ** 创建并填充新数据集
local tot_rows : display `countn' * `countn'
set obs `tot_rows'

generate corrname1 = ""
generate corrname2 = ""
generate byte y = .
generate byte x = .
generate double corr = .
generate double abs_corr = .

local row = 1
local y = 1
local rowname = 2
 
foreach name of local var_corr {
 forvalues i = `rowname'/`countn' { 
  local a : word `i' of `var_corr'
  replace corrname1 = "`name'" in `row'
  replace corrname2 = "`a'" in `row'
  replace y = `y' in `row'
  replace x = `i' in `row'
  replace corr = C[`i',`y'] in `row'
  replace abs_corr = abs(C[`i',`y']) in `row'
  
  local ++row
  
 }
 
 local rowname = `rowname' + 1
 local y = `y' + 1

}
 
drop if missing(corrname1)
  
colorpalette CET CBD1, n(20) nograph //Color Blind Friendly option
generate colorname = ""
local col = 1
forvalues colrange = -1(0.1)0.9 {
 replace colorname = "`r(p`col')'" if corr >= `colrange' & corr < `=`colrange' + 0.1'
 replace colorname = "`r(p20)'" if corr == 1
 local ++col
} 
  
generate group_corr = corrname1 + " - " + corrname2
compress
  
sort corr, stable
generate rank_corr = _n
labmask rank_corr, values(group_corr)
  
  
* 绘图
** 在本地宏保存绘图代码
forvalues i = 1/`=_N' {

 local barlist "`barlist' (scatteri `=rank_corr[`i']' 0 `=rank_corr[`i']' `=corr[`i']' , recast(line) lcolor("`=colorname[`i']'") lwidth(*6))"

}
  
** 在本地宏保存 y 轴标签
levelsof rank_corr, local(yl)
foreach l of local yl {

 local ylab "`ylab' `l'  `" "`:lab (rank_corr) `l''" "'" 
 
} 
  
twoway `barlist', ///
  legend(off) scheme(white_tableau) ylabel(`ylab', labsize(2.5)) ///
  xlab(, labsize(2.5)) ///
  ytitle("Pairs") xtitle("Correlation Coeff.") ///
  title("{bf}Correlation Coefficient (Diverging Bar Plot)", size(2.75) pos(11))

命令运行结果见下图:

条形图分为两个部分,上方黄色部分表示变量之间为正相关关系,下方蓝色部分表示变量之间为负相关关系,且颜色是渐进的,相关性越强,颜色越深。

13. 发散条形图 - 带有置信区间的相关图 (Diverging Bars — Correlation Plot with Confidence Intervals)

该图和上图都属于发散条形图,但该图在展示相关系数之外,增加了置信区间的显示。基本命令见范例,同上述发散条形图,目前 \(stata\) 中还没有相关命令的安装包,我们绘制发散条形图时,只需要修改 local var_corr 后面的变量名即可,余下代码会帮助完成其他的工作。

范例如下:

sysuse auto, clear 
    
local var_corr price mpg trunk weight length turn foreign   // 定义变量列表
local countn : word count `var_corr'
  
** 计算相关系数,保存在相关系数矩阵C  
quietly corrci `var_corr'
matrix C = r(corr)
local rnames : rownames C
matrix LB = r(lb)
matrix UB = r(ub)
matrix Z = r(z) 

egen miss = rowmiss(`var_corr')
count if miss == 0
local N = r(N)
  
** 清除当前数据集
clear
   
** 创建并填充新数据集 
local tot_rows : display `countn' * `countn'
set obs `tot_rows'

generate corrname1 = ""
generate corrname2 = ""
generate byte y = .
generate byte x = .
generate double corr = .
generate double lb = .
generate double ub = .
generate double z = .
generate double abs_corr = .

local row = 1
local y = 1
local rowname = 2
   
foreach name of local var_corr {
 forvalues i = `rowname'/`countn' { 
  local a : word `i' of `var_corr'
  replace corrname1 = "`name'" in `row'
  replace corrname2 = "`a'" in `row'
  replace y = `y' in `row'
  replace x = `i' in `row'
  replace corr = C[`i',`y'] in `row'
  replace lb = LB[`i',`y'] in `row'
  replace ub = UB[`i',`y'] in `row'
  replace z = Z[`i',`y'] in `row'
  replace abs_corr = abs(C[`i',`y']) in `row'
  
  local ++row
  
 }
 
 local rowname = `rowname' + 1
 local y = `y' + 1

}
   
drop if missing(corrname1)
  
** 生成 p 值及显著性符号
generate N = `N'
generate double p = min(2 * ttail(N - 2, abs_corr * sqrt(N - 2) / sqrt(1 - abs_corr^2)), 1)
  
generate stars = "*" if p <= 0.1 & p > 0.05
replace stars = "**" if p <= 0.05 & p > 0.01
replace stars = "***" if p <= 0.01
  
** 生成颜色代码  
colorpalette CET CBD1, n(20) nograph //Color Blind Friendly option
generate colorname = ""
local col = 1
forvalues colrange = -1(0.1)0.9 {
 replace colorname = "`r(p`col')'" if corr >= `colrange' & corr < `=`colrange' + 0.1'
 replace colorname = "`r(p20)'" if corr == 1
 local ++col
} 
  
** 生成新变量,组合描述变量相关系数
generate group_corr = corrname1 + " - " + corrname2
compress
  
  
** 对相关系数进行排序并分配排名
sort corr, stable
generate rank_corr = _n
labmask rank_corr, values(group_corr)
  
  
** 在本地宏保存绘图代码
forvalues i = 1/`=_N' {

 local barlist "`barlist' (scatteri `=rank_corr[`i']' 0 `=rank_corr[`i']' `=corr[`i']' , recast(line) lcolor("`=colorname[`i']'") lwidth(*6))"

}
  
** 在本地宏保存 y 轴标签
levelsof rank_corr, local(yl)
foreach l of local yl {

 local ylab "`ylab' `l'  `" "`:lab (rank_corr) `l''" "'" 
 
} 
  
  ** 绘制图表
twoway `barlist' ///
  (rspike lb ub rank_corr, horizontal lcolor(white) lwidth(*2)) ///
  (rspike lb ub rank_corr, horizontal lcolor(black*.5)), ///
  legend(off) scheme(white_tableau) ylabel(`ylab', labsize(2.5)) ///
  xlab(, labsize(2.5)) ///
  ytitle("Pairs") xtitle("Correlation Coeff.") ///
  title("{bf}Correlation Coefficient with Confidence Interval (Diverging Bar Plot)", size(2.75) pos(11))

命令运行结果见下图:

14. 面积图 (Area Chart)

面积图适用于描述某指标与特定基线比较的百分比变化情况。

基本命令为:twoway area

范例如下:

import delimited "https://github.com/tidyverse/ggplot2/raw/main/data-raw/economics.csv", clear

** 计算年度同比增长率
generate yoy = (psavert[_n] - psavert[_n-1]) / psavert[_n-1]  
  
** 生成新日期变量 - 年月
generate monthyear = ym(year(date(date, "YMD")), month(date(date, "YMD")))
format monthyear %tm
  
** 绘制面积图
twoway (area yoy monthyear if monthyear <= tm(1975m12), lwidth(0)), ///
  xla(84(12)185, format(%tmCY)) ///
  plotregion(lstyle(solid) lwidth(.1)) ///
  xtitle("") ///
  ytitle("% Returns for Personal savings", size(2.75)) ///
  xscale(noline) yscale(noline) ///
  title("{bf}Area Chart", pos(11) size(3)) ///
  subtitle("% Returns for Personal Savings", pos(11) size(2.5)) ///
  scheme(white_tableau) 

命令运行结果见下图:

D. 排序关系图(Ranking)

15. 排序柱状图 (Ordered Bar Charts)

排序柱状图和一般柱状图基本相同,只是根据 \(y\) 轴变量值进行了排序。

基本代码为:

graph bar (asis) y, over(x, sort(1))

其中,graph bar 命令用于绘制条形图,sort(1) 代表根据graph bar 命令后的第一个变量排序,\(y\) 为条形图中展示的变量, \(x\)\(x\) 轴表示的分类变量。

范例代码如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

collapse (mean) cty, by(manufacturer)
  // 根据 manufacturer 分别计算 cty 平均值

** 绘图
graph bar (asis) cty, over(manufacturer, sort(1) label(labsize(1.75)))  ///
  scheme(white_w3d) ///
  title("{bf}Ordered Bar Chart", pos(11) size(2.75)) ///
  ytitle("City" "Mileage", orient(horizontal) size(2)) ///
  ylabel(, labsize(2)) ///
  subtitle("Make Vs. Avg. Mileage", pos(11) size(2.5))

命令运行结果见下图:

16. 棒棒糖图 (垂直)(Lollipop Charts - Vertical)

棒棒糖图的表达效果与排序条形图相似,但使用了“棒棒糖 (Lollipop) ”的表现形式,看起来更加简洁。

基本命令为:twoway dropline y x

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear
  
** 为不同制造商 (manufacturer) 排序,并分配排名
collapse (mean) cty, by(manufacturer)
sort cty, stable 
generate order = _n
labmask order, values(manufacturer)
  
** 绘图 
quietly summarize order
twoway  dropline cty order,  ///
  msize(2)  /// 设置点的大小为2
  yscale(range(0 25)) ///
  ylabel(0(5)25) ///
  ytitle("City" "Mileage", orient(horizontal)) ///    
  xscale(range(0.25)) ///
  xlabel(`r(min)'(1)`r(max)', valuelabel labsize(1.75)) ///
  xtitle("") /// 
  title("{bf}Lollipop Chart", pos(11) size(2.75)) ///
  subtitle("Make Vs. Avg. Mileage", pos(11) size(2.5)) ///
  scheme(white_w3d)

命令运行结果见下图:

17. 点阵图 (水平) (Dot Plot - Horizontal)

点阵图与棒棒糖图相似,只是减去了线段,并将图转为水平方向,它可以更加直观地显示某变量的排序情况。

基本代码: twoway dot y x, horizontal 其中,twoway dot 命令后面需要加 horizontal 选项,目的是将图形转为水平显示。

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

collapse (mean) cty, by(manufacturer)
sort cty, stable 
generate order = _n
labmask order, values(manufacturer)
  
quietly summarize cty
local xmin = `r(min)'
  // 将 summarize 的最小值存储到本地宏 xmin 中
  
  ** 绘图 
quietly summarize order
twoway  dot cty order, horizontal ///
  msize(2) ///
  yscale(range(`r(min)' `r(max)')) ///
  ylabel(`r(min)'(1)`r(max)', valuelabel labsize(1.75)) ///
  ytitle("Make", orient(horizontal) size(2)) ///    
  xscale(range(`xmin')) ///
  xlabel(10(5)25, nogrid) ///
  xtitle("Mileage", size(2)) ///
  title("{bf}Dot Plot", pos(11) size(2.75)) ///
  subtitle("Make Vs. Avg. Mileage", pos(11) size(2.5)) ///
  scheme(white_w3d)

命令运行结果见下图:

18. 斜率图 (Slope Chart)

斜率图经常用来比较某指标两个时间点之间的变化情况。

基本命令为:

twoway pcspike y1 x1 y2 x2

其中, pcspike 命令用于绘制斜率图的线条,起点是 (\(x_1, y_1\)),终点是 (\(x_2, y_2\)),不同于上文边缘箱图用到的 rspike 命令,rspike 要求所有对象的连线需要两端对齐,即绘制水平或垂直线段,pcspike 可以绘制斜线。

同时,在绘制斜率图时,通常需要在斜线两端起点和终点处标记标签,此时使用 scatter 命令即可:

scatter y1 x1, ms(i) mlabposition(9) mlabel(lab1952) 
scatter y2 x2, ms(i) mlabposition(9) mlabel(lab1952) 

其中,ms(i) 表示不使用标记符号;mlabposition(9) 代表数据点对应的标签分别位于九点钟方向,即图表左侧;mlabel(lab1952) 表示标签的文本内容由变量 \(lab1952\) 提供。

范例如下:

import delimited "https://raw.githubusercontent.com/selva86/datasets/master/gdppercap.csv", varnames(1) clear
 
rename (v2 v3) (y1952 y1957)  //变量重新命名
generate negative = (y1957 < y1952)
 // 创建新变量 negative ,negative=1 if y1957 < y1952
 
generate lab1952 = continent + ", " + string(round(y1952))
generate lab1957 = continent + ", " + string(round(y1957))
 
generate continent1 = 1
generate continent2 = 2
 // 用来标识时间点的变量,以便在斜率图中标识出两个不同时间点的数据
 
colorpalette w3, nograph
 // 设置颜色方案为 w3,此处 nograph 表示不生成图形

 ** 绘图
twoway  (pcspike y1952 continent1 y1957 continent2 if negative == 0,  ///
  legend(off) lcolor("`r(p11)'"))  ///
  (pcspike y1952 continent1 y1957 continent2 if negative == 1,  ///
  legend(off) lcolor("`r(p1)'")) ///
  (scatter y1952 continent1, ms(i) mlabposition(9) mlabel(lab1952)) ///
  (scatter y1957 continent2, ms(i) mlabposition(3) mlabel(lab1957)) ///
  (scatteri 12700 1 "{bf}Year 1952", ms(i) mlabpos(9)) ///
  (scatteri 12700 2 "{bf}Year 1957", ms(i) mlabpos(3)) ///   
   , ///
  ylabel(0(4000)12000, labsize(2) nogrid) ///
  ytitle("Avg." "GDP/Capita", size(2) orient(horizontal)) ///
  yscale(range(0 13000)) ///
  xlabel(1(1)2) ///
  xscale(off) ///
  xtitle("") ///
  xscale(range(0.2 2.8)) ///
  aspect(1.3) ///
  title("{bf}Slope Chart", pos(11) size(2.75)) ///
  subtitle("Mean GDP per capita: 1952 Vs. 1957" " ", pos(11) size(2)) ///
  graphregion(margin(r=25)) ///
  scheme(white_w3d)

命令运行结果见下图:

19. 哑铃图 (Dumbbell Plot)

哑铃图可以帮助我们在同一行直观地展示某变量两个时间点的变化情况。

它的基本绘图代码为:

twoway (rspike x1 x2 y, horizontal lcolor("`r(p6)'*0.4")) ///
  (scatter y x1, mcolor("`r(p6)'*0.4")) ///
  (scatter y x2, mcolor("`r(p6)'*0.4"))

respike 为绘制水平或垂直线条的基本命令,通常默认绘制垂直线条,但由于哑铃图是水平线条,因而需要在命令后面添加 horizontal 选项,\(x_1\)\(x_2\) 分别为 \(x\) 轴表示的两个时间点的连续变量,\(y\)\(y\) 轴表示的类别变量; sactter 命令则用于绘制线条两端的端点 \((x_1, y) 、 (x_2, y)\)

范例代码如下:

import delimited "https://raw.githubusercontent.com/selva86/datasets/master/health.csv", varnames(1) clear 

** 创建类别变量 - y 轴标签
generate srno = _n * 3
labmask srno, values(area)

foreach var of varlist pct* {
 replace `var' = `var' * 100
}
 
** 绘图
colorpalette w3, nograph
twoway  (rspike pct_2013 pct_2014 srno, horizontal lcolor("`r(p6)'*0.4")) ///
  (scatter srno pct_2013, mcolor("`r(p6)'*0.4")) ///
  (scatter srno pct_2014, mcolor("`r(p6)'")) ///
  , ///
  ylabel(3(3)78, valuelabel angle(horizontal) labsize(2)) ///
  legend(order(3 "2014" 2 "2013") pos(11) row(1) size(2)) ///
  ytitle("") ///
  title("{bf}Dumbbell Plot", pos(11) size(2.75)) ///
  subtitle("% Change in Health Indicators by Area: 2014 vs. 2013", pos(11) size(2)) ///
  scheme(white_tableau)

命令运行结果见下图:

E. 分布关系图(Distribution)

20. 连续变量堆积直方图 (Histogram on Continuous Variable)

\(Stata\) 用于绘制直方图的原始命令只能做到为一个变量生成直方图,连续变量堆积直方图可以同时描述连续变量和类别变量的分布关系,展示连续变量特定水平下不同类别的分布情况。

关于连续变量堆积直方图的代码,原作者运用 \(stata\)undocumented 命令运行,因而,使用时可能不够稳定,也不一定适用所有情况,如果命令有问题或者需要更新,可以给原文章的作者留言解决(Data Envelopment Analysis (DEA)Visualization using Stata, -Link-)。

范例代码如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

replace class = subinstr(class, "2", "two", .)
 
** 创建一个默认框架的副本 original ,用于备份数据
frame copy default original, replace

** 获取 class 变量的唯一值,并存储在本地宏 cls 中
levelsof class, local(cls) 

** 遍历 cls 中的每个类别,绘制 displ 的直方图并存储
foreach l of local cls {
 
 frame put displ class, into(`l')
 frame change `l'
 
 twoway__histogram_gen displ if class == "`l'", start(1) width(0.1) frequency generate(h x, replace)
 rename (h) (h_`l')
 
 keep x h_`l'
 drop if missing(x)
 
 save `l', replace
 
 frame change original

}
 
** 将当前框架设置回 original,生成不分组的直方图并存储
frame change original
twoway__histogram_gen displ, start(1) width(0.1) frequency generate(h x, replace)
drop h
generate tag = 1 if missing(x)   // 创建一个标签变量,标识缺失值
replace x = _n if missing(x)     // 将缺失值用观测编号 _n 替换

foreach l of local cls {
 merge 1:1 x using `l', nogen
}
 
replace x = . if tag == 1
drop tag 

** 重新组织数据集,宽变长,生成 type 新变量
keep x h_*
drop if missing(x)
reshape long h_, i(x) j(type) string 
bysort x (type) : gen cumul_sum_ = sum(h_) if !missing(h_)
 
** 长变宽,将累积和变量 cumul_sum_ 转为多个变量
drop h_*
reshape wide cumul_sum_, i(x) j(type) string
 
** 计数以 "cumul" 开头的所有变量
ds cumul*
local wcount: word count `r(varlist)'
 
** 根据不同的 "cumul" 变量生成条形图命令,存储在本地宏 `bar` 
forvalues i = `wcount'(-1)1 {
 
 ds cumul*
 local a : word `i' of `r(varlist)'
 display "`a'"
 colorpalette tableau, nograph n(`i')
 local bar "`bar' (bar `a' x, fcolor("`r(p`i')'") barwidth(0.1) lwidth(0.1) lcolor(gs4))"
 
} 

// 绘制直方图
twoway  `bar', xlabel(1(1)7) scheme(white_tableau) ///
  legend(order(1 "2 Seater" 2 "SUV" 3 "Subcompact" 4 "Pickup" 5 "Minivan" 6 "Midsize" 7 "Compact")  ///
  rowgap(0) size(2)) ///
  xlabel(, labsize(2)) ylabel(, labsize(2)) ///
  ytitle("Count", size(2)) xtitle("Displacement", size(2)) ///
  title("{bf}Histogram with Auto Binning", pos(11) size(2.75)) ///
  subtitle("Engine Displacement across Vehicle Classes", pos(11) size(2)) 

命令运行结果见下图:

\(x\) 轴代表发动机排量(\(displacement\)),\(y\) 轴代表不同类型车辆的总数量(\(count\)),同时按照不同型号(\(class\))分类展示,该图表描述了特定发动机排量水平的车辆型号组成情况。

21. 类别变量堆积直方图 (Histogram on Categorical Variable)

不同于连续变量堆积直方图,类别变量堆积直方图 \(x\) 轴展示的是类别变量,描述给定类别变量的频率分布。

基本代码:

graph bar (count),  over(y1)  ///
    over(y2, label(alternate labsize(2))) asyvars stack

其中, graph bar (count) 为基本命令,当基于两个分组变量 \(y_1、y_2\)时,要用两个 over() 选项,stack 选项用于将变量 \(y_1\) 堆叠为一个条形图,使图表更为精简易读。

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

** 构建本地宏 barlwidth,存储不同类别下条形图的线宽度设置 
forvalues i = 1/7 {
 local barlwidth "`barlwidth' bar(`i', lwidth(0)) "
}
 
** 绘图
graph bar (count),  over(class)  ///
  over(manufacturer, label(alternate labsize(2))) asyvars stack  ///
  scheme(white_w3d) ///
  ylabel(, nogrid) ///
  legend(order(7 "SUV" 6 "Subcompact" 5 "Pickup" 4 "Minivan" 3 "Midsize" 2 "Compact" 1 "2 Seater")  ///
  rowgap(0.25) size(2)) ///
  lintensity(*0) ///
  `barlwidth' ///
  title("{bf}Histogram on Categorical Variable", pos(11) size(2.75)) ///
  subtitle("Manufacturer across Vehicle Classes", pos(11) size(2)) 

命令运行结果见下图:

22. 密度图 (按类别划分) Density Plot (By Category)

绘制步骤主要包括两步: 第一步: 使用 foreach 命令,循环指定不同类别的密度图代码并存储在本地宏 kden 中。密度图绘制代码为 :kdensity y,其中, kdensity 为密度图基本命令, \(y\) 为描述的连续变量; 第二步: 调用存储在本地宏 kden 的绘制代码,使用 twoway 命令绘制密度图。

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

levelsof cyl, local(cylinders)
foreach cylinder of local cylinders {
 
 quietly summarize cty
 local kden "`kden' (kdensity cty if cyl == `cylinder', range(`r(min)' `r(max)') recast(area) fcolor(%70) lwidth(*0.25))"
   
}
 
twoway `kden',  scheme(white_w3d) ///
  legend(subtitle("Cylinders", size(2)) label(1 "4") label(2 "5") label(3 "6") label(4 "8") rowgap(0.25) size(2)) ///
  title("{bf}Density Plot", pos(11) size(2.75)) ///
  ytitle("Density", size(2) orient(horizontal)) ///
  ylabel(, nogrid labsize(2)) ///
  xtitle("City Mileage", size(2)) ///
  xlabel(, nogrid labsize(2)) ///
  subtitle("City Mileage over number of cylinders", pos(11) size(2)) 

命令运行结果见下图:

该图绘制了不同气缸类别 \((cylinder)\) 的城市里程 \((City Mileage)\) 密度图。

23. 箱形图 (The Box Plot)

箱形图,也称盒图,箱线图,常用于反映数据的分布特征,该图是常规箱形图,使用 \(Stata\) 内置命令可以轻松绘制。

基本代码为:

graph box y,  over()

其中,graph box 为基本命令,\(y\) 为想要描述的变量,over() 选项中为分组的类别变量。

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

graph box cty,  over(class) ///
  ytitle("City Mileage", size(2.25)) ///
  ylabel(, nogrid) ///
  title("{bf}Box Plot", pos(11) size(2.75)) ///
  b1title(" " "Class of vehicle", size(2.5)) ///
  subtitle("City Mileage grouped by class of vehicle",  ///
  pos(11) size(2)) ///
  scheme(white_w3d)

命令运行结果见下图:

该图描述了不同汽车型号 (class) 的城市行车里程 (City Mileage) 情况。

下图红框中的横线代表中位数,红框顶部为第 75 百分位数,红框底部为第 25 百分位数,箱框上下的垂直线为“晶须”,为四分位数间距(1.5*IQR),晶须上端的水平线代表上边缘,下端的水平线代表下边缘,上下边缘以外的红点为异常值。

24. Tufte箱形图 (Tufte Style Box Plot)

Tufte箱形图与上个展示的常规箱形图都可以用来反映数据的分布情况,但Tufte箱形图相对更为简约。

基本命令: graph box

同时,需要添加以下选项: - medtype(marker) 指定中位数的显示方式为标记; - medmarker(mcolor(black) mlwidth(0)) 指定中位数标记的属性,颜色为黑色,线宽度为 0,即不显示中位数标记的边框; - cwhiskers 表示使用自定义晶须; - alsize() 指定相邻线宽,alsize(0) 表示相邻线宽为0; - intensity() 指定填充箱框的颜色强度,intensity(0) 表示不填充箱框; - lines(lpattern(solid) lwidth(medium)) 指定箱图的线条样式为实线,线宽为中等。 (具体可查看 \(Stata\) 帮助文件 help graph box

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

graph box cty,  over(class) ///
  box(1, color(white%0)) ///
  medtype(marker) ///
  medmarker(mcolor(black) mlwidth(0)) ///
  cwhiskers ///
  alsize(0) ///
  intensity(0) ///
  lintensity(1) ///
  lines(lpattern(solid) lwidth(medium)) ///
  ylabel(, nogrid) ///
  yscale(noline) ///
  title("{bf}Box Plot", pos(11) size(2.75)) ///
  subtitle("City Mileage over number of cylinders",  ///
  pos(11) size(2)) ///
  scheme(white_w3d)

命令运行结果见下图:

25. 简约箱形图 (Minimalistic Box Plot)

简约箱形图也属于常规箱形图的一种简单表现形式,但是,相对于 Tufte箱形图,简约箱形图可以同时根据多个分组变量绘制不同类别的箱形图。

基本命令: graph box

同时,需要在后面添加指定的分组变量,over() 选项指定 \(x\) 轴代表的类别变量,by() 选项指定每一个方框内的不同类别。

graph box cty,  
      over(cyl) 
      by(class, row(1)) 
        // row(1) 代表以一行的形式排列不同类别的箱图

范例如下:

import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

levelsof cyl, local(cylinders)
local catcount: word count `cylinders'
forvalues i = 1/`catcount' {
 
 colorpalette tableau, nograph n(`catcount')
 local boxopt "`boxopt' box(`i', color("`r(p`i')'")) "
 
}
 
display `"`boxopt'"'
 
graph box cty,  over(cyl) ///
  by(class, ///
   row(1) legend(pos(3)) imargin(l=1.5 r=1.5) style(compact) ///
   title("{bf}Box Plot", pos(11) size(2.75)) ///
   subtitle("City Mileage over number of cylinders" " ", pos(11) size(2)) ///
   note(, size(2)) ///
  ) ///
  asyvars ///
  `boxopt' ///
  boxgap(50) ///
  medtype(marker) ///
  medmarker(mcolor() mlwidth(0) msize(1)) ///
  cwhiskers ///
  alsize(0) ///
  intensity(0) ///
  lintensity(1) ///
  lines(lpattern(solid) lwidth(medium)) ///
  ylabel(, nogrid) ///
  yscale(noline) ///
  ytitle("City Mileage", size(2.25)) ///
  subtitle(, size(2.5)) ///          //size of group headers
  legend(size(2.25) rowgap(0.25) subtitle("Cylinders", size(2.25))) ///
  scheme(white_tableau)

命令运行结果见下图:

26. 小提琴图 (Violin Plot)

与箱形图的不同之处在于,小提琴图可以同时看到数据的分布密度,小提琴图可以分为两种:带箱框型和不带箱框型。

带箱框的小提琴图:

基本命令:violinplot,需要添加 over() 选项指定分组变量,添加 vertical 表示绘制垂直方向上的小提琴图。

不带箱框的小提琴图:

基本命令同上 violinplot ,但是,除 over()vertical 之外,需要在后面添加选项 nobox nomedian noline nowhiskers ,分别表示不绘制箱体、不展示中位数、不绘制箱线图的线条、不绘制晶须。

范例如下:

** 带箱框的小提琴图
import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

violinplot cty,  over(class) vertical scheme(white_w3d) ///
  ytitle("City Mileage", size(2.25)) ///
  ylabel(, nogrid) ///
  title("{bf}Box Plot", pos(11) size(2.75)) ///
  b1title(" " "Class of vehicle", size(2.5)) ///
  subtitle("City Mileage grouped by class of vehicle", pos(11) size(2))
      
 
** 不带箱框的小提琴图
import delimited "https://raw.githubusercontent.com/tidyverse/ggplot2/master/data-raw/mpg.csv", clear

violinplot cty,  over(class) vertical scheme(white_w3d) nobox nomedian noline nowhiskers ///
  ytitle("City Mileage", size(2.25)) ///
  ylabel(, nogrid) ///
  title("{bf}Box Plot (Density Only)", pos(11) size(2.75)) ///
  b1title(" " "Class of vehicle", size(2.5)) ///
  subtitle("City Mileage grouped by class of vehicle", pos(11) size(2))

命令运行结果见下图:

带箱框的小提琴图:

不带箱框的小提琴图:

27. 人口金字塔图 (Population Pyramid Plot)

金字塔图可以用来反映某变量在不同时间或阶段的特征,常用于表示人口的婚姻状况、受教育程度、不同产业部门的产值、不同部门的职工人数、收入和消费水平等。

基本命令:

twoway (bar x y if D == 1, horizontal lwidth(0) barwidth(0.8))  ///
   (bar x y if D == 0, horizontal lwidth(0) barwidth(0.8))

金字塔图的基本绘制命令同条形图 twoway bar ,不同之处在于,金字塔图需要添加 horizontal 选项,指定水平绘制,同时设置分类变量 \(D\) ,分组绘制水平条形图。金字塔图的水平柱表示 \(x\) 变量的数量特征,垂直柱表示类别变量 \(y\)

范例如下:

import delimited "https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv", clear 

format users %20.0g  
replace users = round(users)  
replace users = -(users) if users < 0 & gender == "Female"  
replace users = -(users) if users > 0 & gender == "Male"
 
encode stage, gen(stage_n)
 
** 循环生成 xlab 变量,用于设置x轴的刻度标签
forvalues i = -15000000(5000000)15000000 {
 
 if `i' != 0 {
  local xlab "`xlab' `i' `"`=abs(`i')/1000000'm"'"  //Use of compound quotes to work with labels with absolute (abs) values
 }
 
 else {
  local xlab "`xlab' 0 `"0"'"
 }
}
 
** 绘图
twoway (bar users stage_n if gender == "Female", horizontal lwidth(0) barwidth(0.8)) ///
  (bar users stage_n if gender == "Male", horizontal lwidth(0) barwidth(0.8)) ///
  , ///
  yscale(noline) ///
  xlabel(`xlab', nogrid) ///
  ylabel(1(1)18, nogrid noticks valuelabel labsize(2)) ///
  ytitle("Stage") ///
  legend(order(1 "Female" 2 "Male") size(2)) ///
  title("{bf}Email Campaign Funnel", size(2.75)) ///
  scheme(white_tableau)

命令运行结果见下图:

注意:文中范例代码所需数据需要从网页导入,如果在导入数据时遇到代理问题,可以将先进入网页查看数据,复制并保存到本地 \(.txt\)\(.csv\) 文件,使用数据时直接从本地导入即可。 import delimited using "C:\Users\Lenovo\Desktop\抖动图数据.txt", delimiter(",") clear

6. 参考资料

  • Data Envelopment Analysis (DEA) Visualization using Stata, -Link-

7. 相关推文

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