9  绘制图形

图形展示是探索变量之间相互关系的重要的方法。本章中,我们首先介绍Stata中的graph包括哪些组成部分,然后介绍常见的图形类别包括:散点图(saccter)、折线图(line)、条形图(bar)、直方图(histogram)、箱线图(box),随后介绍如何一次做多个图和将多个图形连接在一起。

数据和命令准备

请新建目录C:/StataClass/chap_graph作为本章的工作目录

capture mkdir "C:/StataClass/chap_graph"
cd "C:/StataClass/chap_graph"

. capture mkdir "C:/StataClass/chap_graph"

. cd "C:/StataClass/chap_graph"
C:\StataClass\chap_graph

. 

本章中的一些例子使用了A Visual Guide to Stata Graphics, Second Edition 一书中的命令vguse和数据集allstates.dta,通过如下命令安装它们:

// getting support materials of book A Visual Guide to Stata Graphics, Second Edition
//   ref: https://www.stata-press.com/data/vgsg.html
net from http://www.stata-press.com/data/vgsg2/
net install vgsg2, replace 
net get vgsg2, replace 

9.1 Stata中绘图的构成

一个完整的图包括:

  1. 曲线(点、线、面)
  2. 标题(正、副)
  3. 图例
  4. 脚注
  5. 插文
  6. 坐标轴
  7. 主题(外观)

下图是利用示例数据auto.dta画出来的散点图。

sysuse auto, clear 
graph twoway (scatter mpg weight if foreign == 0) ///
             (scatter mpg weight if foreign == 1, msymbol(Sh)), ///
   title("标题: 行驶里程与车重关系") ///
   subtitle("副标题: 11574年美国的国产和进口汽车") ///
   ytitle("纵坐标标题:里程") ///
   xtitle("横坐标里程:重量") ///
   note("注释:数据来自美国汽车协会") ///
   legend(title("图例") label(1 "国产车") label(2 "进口车")) ///
   text(35 3400 "曲线类型:散点图") /// 
   scheme(s1rcolor)

. sysuse auto, clear 
(1978 automobile data)

. graph twoway (scatter mpg weight if foreign == 0) ///
>              (scatter mpg weight if foreign == 1, msymbol(Sh)), ///
>    title("标题: 行驶里程与车重关系") ///
>    subtitle("副标题: 11574年美国的国产和进口汽车") ///
>    ytitle("纵坐标标题:里程") ///
>    xtitle("横坐标里程:重量") ///
>    note("注释:数据来自美国汽车协会") ///
>    legend(title("图例") label(1 "国产车") label(2 "进口车")) ///
>    text(35 3400 "曲线类型:散点图") /// 
>    scheme(s1rcolor)

. 

9.1.1 绘图命令结构拆解

所有的绘图都可以通过graph和一些子命令完成,以下是help graph查看到的帮助页面。

help graph界面

绘图命令可以总结为如下模板:

graph-command (plot-command, plot-options) (plot-command, plot-options), graph-options

可以看到,绘图的命令可以分为两个层次。从层次来看,分为图形(graph-command)和绘图(plot-command) 其中:

  • graph-command定义图的类型(twoway, matrix, bar, dot, box, pie,…),twoway是非常常见的图形。绝大多数情况下,graph关键词可以省略,例如graph twoway可以简写为twoway;还有一些图形命令例如histogram不可以写成graph histogram,这类图形在help graph的帮助文档中被归类为other
  • graph-options是graph层面的选项,可以控制图形层面的特征。在本章开始时给出例子中,标题(titlesubtitle)、坐标轴标题(ytitle)、注释(note)、图例(legend)、添加自定义文字(text)、主题(scheme)等都是图形(graph)层面的option;
  • plot-command定义绘图类型
    • 例如在twoway图类型下,有散点图、折线图等等(scatter, line, connected, area, bar,…)等多种绘图类型(plot);
    • 如果图内有多种类型的绘图(plot),可以用小括号分隔开,依此列出。在本章开始时给出例子中,twoway是graph-command,scatter是plot-command;
    • 绘图本身可以有自身的option(plot-options)。在本章开始时给出例子中,msymbol(Sh)scatter这一;

下面是以散点图(scatter)的命令:

graph twoway (scatter mpg weight), title("美国汽车") // 图的option,标题(title)
twoway (scatter mpg weight), title("美国汽车") // 图的option,标题(title) 
twoway (scatter mpg weight, msymbol(Oh)) // 曲线的选项,定义点的类型 (Oh,代表circle_hollow,空心圆)
twoway (scatter mpg weight, msymbol(Oh)), title("美国汽车") // 图的option和曲线的option可以同时使用

你可以分别运行上面的代码,再次直观体会绘图命令的差异,这里有很多option的含义你可能还不清楚,可以根据结果去猜测一下,后续会有介绍。

查看具体绘图(plot)的功能可以通过help+具体绘图类型名的方式查看,例如help twowayhelp histogram命令查看

help graph 
help twoway 
cd "C:/StataClass/chap_graph"
use "TRD_Yearm.dta", clear 
keep if Markettype==1
drop Markettype 
destring Trdynt, replace 
save "A股沪市年收益率.dta", replace

. cd "C:/StataClass/chap_graph"
C:\StataClass\chap_graph

. use "TRD_Yearm.dta", clear 

. keep if Markettype==1
(109 observations deleted)

. drop Markettype 

. destring Trdynt, replace 
Trdynt already numeric; no replace

. save "A股沪市年收益率.dta", replace
file A股沪市年收益率.dta saved

. 

9.2 通过定绘图的各个组成部分——以散点图为例

这里修改的大都都是属于twoway_options,如果是属于散点图曲线(plot)的option,会单独指出。前文提到,twoway是我们考察两个变量之间关系的重要的图类型,在这类绘图命令中graph twoway可以省略,只写出曲线的类型命令(例如,scatter, line, histogram等),例如graph twoway scatter y x 可以简写成twoway scatter y x,也可以进一步简写成scatter y x

9.2.1 标题

标题是整个图的标题,有主标题和副标题两个, title()和subtitle()

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight) , ///
  title("行驶里程和车重的关系") ///
  subtitle("1978")

9.2.2 坐标轴

可以控制是否显示坐标轴、刻度和双坐标轴显示

9.2.2.1 坐标轴标题

纵坐标标题通过ytitle() option,横坐标标题通过xtitle() option来设定。

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight), ///
  ytitle("汽车里程") ///
  xtitle("汽车重量") 

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight), ///
>   ytitle("汽车里程") ///
>   xtitle("汽车重量") 

. 

9.2.2.2 坐标轴标签值

纵坐标的标签值通过ylabel() option设定,横坐标刻度值通过xlabel() option设定。

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight), ///
  ylabel(10(10)40) ///
  xlabel(1500(500)4500)

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight), ///
>   ylabel(10(10)40) ///
>   xlabel(1500(500)4500)

. 

9.2.2.3 坐标轴刻度

纵坐标刻度县通过ytick()ymtick() option设定,相应的,横坐标刻度线xtick()xmtick() option来设定。

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight), ///
  ytick(10(2)40) ///
  xtick(1500(100)4500)

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight), ///
>   ytick(10(2)40) ///
>   xtick(1500(100)4500)

. 

9.2.3 多图(plot)与双坐标轴

如果要考察两个变量 y_1y_2x 的关系,而 y_1y_2 的单位量纲差距很大,就需要把两个 y 变量放置不同的纵轴。 例如,我们同时将mpg和price作为 y 变量,x 仍然是重量,如果用同一个纵轴会导致mpg显示为一条直线,但其实mpg的波动还是挺大的,只是由于 price相比mpg数值过大的原因。

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight, sort connect(l)) ///
            (scatter price weight, sort connect(l))

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight, sort connect(l)) ///
>             (scatter price weight, sort connect(l))

. 

将mpg和price放在两个纵坐标轴,就可以清晰展示两个变量和weight变量的关系。

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight, sort connect(l) yaxis(1)) ///
            (scatter price weight, sort connect(l) yaxis(2))

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight, sort connect(l) yaxis(1)) ///
>             (scatter price weight, sort connect(l) yaxis(2))

. 

需要指出的是,这里的三个option:sort, connect(l)yaxis(#) 都是曲线的选项(plot-options) ,各自的功能如下:

  • sort:将数据按照 x 变量排序(可以试一下不加sort,图很混乱,因为原始数据是按照foreign-make来排序的。
  • connect(l):将散点图的点用直线连接起来
  • yaxis(#):指定 y 变量用哪个纵坐标轴

9.2.4 添加横线和竖线

通过yline() option可以添加横线,通过xline() option可以添加竖线

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight), ///
  yline(30) ///
  xline(3000)

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight), ///
>   yline(30) ///
>   xline(3000)

. 

9.2.5 图例

默认是有图例的,可以通过legend(off)不显示图例,也可以手动调整图例的显示内容,以及调整图例出现的位置

9.2.5.1 不显示图例

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight) ///
            (scatter headroom weight), ///
   legend(off) 

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight) ///
>             (scatter headroom weight), ///
>    legend(off) 

. 

9.2.5.2 自定义图例内容

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight) ///
            (scatter headroom weight), ///
   legend(label(1 "里程") label(2 "驾驶室空间")) 

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight) ///
>             (scatter headroom weight), ///
>    legend(label(1 "里程") label(2 "驾驶室空间")) 

. 

9.2.5.3 修改图例的位置

可以按照中标中12个小时对应的方位,通过legend的pos option实现。例如legend(pos(3))会将图例放置于图的3点钟方向。

sysuse auto, clear 
graph twoway ///
            (scatter mpg weight) ///
            (scatter headroom weight), ///
   legend(label(1 "里程mpg") label(2 "驾驶室空间headroom") pos(12)) 

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>             (scatter mpg weight) ///
>             (scatter headroom weight), ///
>    legend(label(1 "里程mpg") label(2 "驾驶室空间headroom") pos(12)) 

. 

9.2.6 脚注

默认是没有脚注,可以通过note() option来设定脚注内容

sysuse auto, clear 
graph twoway ///
           (scatter mpg weight) ///
           (scatter headroom weight), ///
   legend(label(1 "里程mpg") label(2 "驾驶室空间headroom")) ///
   note("Source: 1978 automobile data")

. sysuse auto, clear 
(1978 automobile data)

. graph twoway ///
>            (scatter mpg weight) ///
>            (scatter headroom weight), ///
>    legend(label(1 "里程mpg") label(2 "驾驶室空间headroom")) ///
>    note("Source: 1978 automobile data")

. 

9.3 常见graph类型

我们将介绍三种类型的图:直方图histogram,柱状图graph bar和散点图graph twoway scatter

9.3.1 直方图 histogram

histogram 的帮助文档通过help histogram即可打开。

下面的代会录入如下身高数据,将数据分为10 组,统计落入每组的频数,然后绘制直方图。

clear
input x1-x10
142.3 156.6 142.7 145.7 138.2 141.6 142.5 130.5 134.5 148.8
134.4 148.8 137.9 151.3 140.8 149.8 145.2 141.8 146.8 135.1
150.3 133.1 142.7 143.9 151.1 144.0 145.4 146.2 143.3 156.3
141.9 140.7 141.2 141.5 148.8 140.1 150.6 139.5 146.4 143.8
143.5 139.2 144.7 139.3 141.9 147.8 140.5 138.9 134.7 147.3
138.1 140.2 137.4 145.1 145.8 147.9 150.8 144.5 137.1 147.1
142.9 134.9 143.6 142.3 125.9 132.7 152.9 147.9 141.8 141.4
140.9 141.4 160.9 154.2 137.9 139.9 149.7 147.5 136.9 148.1
134.7 138.5 138.9 137.7 138.5 139.6 143.5 142.9 129.4 142.5
141.2 148.9 154.0 147.7 152.3 146.6 132.1 145.9 146.7 144.0
135.5 144.4 143.4 137.4 143.6 150.0 143.3 146.5 149.0 142.1
140.2 145.4 142.4 148.9 146.7 139.2 139.6 142.4 138.7 139.9
end
stack x1-x10,into(y) clear /*把数据从横向转换成纵向*/
ren _sta n
// 把身高变量y分成10组,组号仍然用n表示
forvalues i=1/10 {
replace n=`i' if (y>124+`i'*4)&(y<124+4*(`i'+1))
}
histogram y,normal

. clear

. input x1-x10

            x1         x2         x3         x4         x5         x6         x
> 7         x8         x9        x10
  1. 142.3 156.6 142.7 145.7 138.2 141.6 142.5 130.5 134.5 148.8
  2. 134.4 148.8 137.9 151.3 140.8 149.8 145.2 141.8 146.8 135.1
  3. 150.3 133.1 142.7 143.9 151.1 144.0 145.4 146.2 143.3 156.3
  4. 141.9 140.7 141.2 141.5 148.8 140.1 150.6 139.5 146.4 143.8
  5. 143.5 139.2 144.7 139.3 141.9 147.8 140.5 138.9 134.7 147.3
  6. 138.1 140.2 137.4 145.1 145.8 147.9 150.8 144.5 137.1 147.1
  7. 142.9 134.9 143.6 142.3 125.9 132.7 152.9 147.9 141.8 141.4
  8. 140.9 141.4 160.9 154.2 137.9 139.9 149.7 147.5 136.9 148.1
  9. 134.7 138.5 138.9 137.7 138.5 139.6 143.5 142.9 129.4 142.5
 10. 141.2 148.9 154.0 147.7 152.3 146.6 132.1 145.9 146.7 144.0
 11. 135.5 144.4 143.4 137.4 143.6 150.0 143.3 146.5 149.0 142.1
 12. 140.2 145.4 142.4 148.9 146.7 139.2 139.6 142.4 138.7 139.9
 13. end

. stack x1-x10,into(y) clear /*把数据从横向转换成纵向*/

. ren _sta n

. // 把身高变量y分成10组,组号仍然用n表示
. forvalues i=1/10 {
  2. replace n=`i' if (y>124+`i'*4)&(y<124+4*(`i'+1))
  3. }
(2 real changes made)
(8 real changes made)
(19 real changes made)
(34 real changes made)
(22 real changes made)
(13 real changes made)
(3 real changes made)
(2 real changes made)
(1 real change made)
(0 real changes made)

. histogram y,normal
(bin=10, start=125.9, width=3.4999992)

. 

9.3.2 散点图

通过 help scatter可以查看散点图的帮助文档。该命令的语法结构为:

[twoway] scatter varlist [if] [in] [weight] [, options]

varlist 中需要指定至少两个变量的名称;ifin都是制定参与绘图的数据需要满足的条件;weight是权重的大小,可以改变散点的大小。

scatter options有很多,在help scatter打开帮助截面后,点击,中包括如下内容:

options Description
marker_options change look of markers (color, size, etc.)
marker_label_options add marker labels; change look or position
connect_options change look of lines or connecting method
composite_style_option overall style of the plot
jitter_options jitter marker positions using random noise
axis_choice_options associate plot with alternate axis
twoway_options titles, legends, axes, added lines and text, by, regions, name, aspect ratio, etc.

9.3.2.1 散点标记图形(marker)相关的option

点击marker_options,会定位到所有与marker有关的options。相应的点击marker_label_options, connect_opionts都可以定位到相应的选项。

可以看到,marker_options中有10个option,分别是

marker_options Description
msymbol(symbolstylelist) shape of marker
mcolor(colorstylelist) color and opacity of marker, inside and out
msize(markersizestylelist) size of marker
msangle(anglestyle) angle of marker symbol
mfcolor(colorstylelist) inside or “fill” color and opacity
mlcolor(colorstylelist) color and opacity of outline
mlwidth(linewidthstylelist) thickness of outline
mlalign(linealignmentstyle) outline alignment (inside, outside, center)
mlstyle(linestylelist) overall style of outline
mstyle(markerstylelist) overall style of marker

这里msymbol(symbolstylelist)指定了散点的形状,可以点击symbolstylelist会打开一个新的界面,提供了所有symbol style的说明,也就是所有的形状。下面的表格整理了常用的散点形状说明:

圆圈 菱形 正方形 三角形 加号 乘号 小点
大、实心 O D S T + X
大、空心 Oh Dh Sh Th
小、实心 o d s t x p
小、空心 oh dh sh th

其他的marker_options中较为常用的有:

  • mcolor:指定marker的填充颜色和外框颜色
  • msize:指定marker的大小
  • msangle:指定marker的方向
  • mfcolor:指定marker填充颜色
  • mlcolor:指定marker边框颜色
  • mlwidth:指定marker边框的宽度

类似的,请通过help学习marker_label_options,connect_options等。

接下来我们通过一些示例学习散点图的用法。

例如,下面的代码基于allstates.dta数据,分别实现了三种散点图:

  • 绘制美国各州贫困发生率(pov)的散点图,以人口作为权重(这也是大家常见的气泡图
  • 绘制美国各州贫困发生率(pov)的散点图,在散点周围标注州名
  • 绘制美国各州贫困发生率(pov)的散点图,高亮显示某个周的贫困发生率
9.3.2.1.1 设定marker形状
// 散点图,散点形状为小空心圆
use allstates.dta, clear 
graph twoway ///
            (scatter pov statefips, msymbol(oh)) 

. // 散点图,散点形状为小空心圆
. use allstates.dta, clear 
(Data on 50 States)

. graph twoway ///
>             (scatter pov statefips, msymbol(oh)) 

. 

9.3.2.1.2 设定marker颜色
// 散点图,制定散点区填充色和外框颜色
use allstates.dta, clear 
graph twoway ///
             (scatter pov statefips, msymbol(O) mfcolor(green) mlcolor(red)) 

. // 散点图,制定散点区填充色和外框颜色
. use allstates.dta, clear 
(Data on 50 States)

. graph twoway ///
>              (scatter pov statefips, msymbol(O) mfcolor(green) mlcolor(red)) 

. 

注意,这里如果将msymbol(O)写成了mysymbol(Oh),填充颜色是不会变成绿色的,请思考为什么?

9.3.2.1.3 标注marker信息
// 散点图,标注州名
use allstates.dta, clear 
twoway ///
   (scatter pov statefips, mlabel(stateab)) 

. // 散点图,标注州名
. use allstates.dta, clear 
(Data on 50 States)

. twoway ///
>    (scatter pov statefips, mlabel(stateab)) 

. 

use allstates.dta, clear 
graph twoway ///
            (scatter pov statefips, mlabel(pov) ///
               mlabformat(%9.2f) mlabsize(tiny) ///
               mlabpos(12)) 

. use allstates.dta, clear 
(Data on 50 States)

. graph twoway ///
>             (scatter pov statefips, mlabel(pov) ///
>                mlabformat(%9.2f) mlabsize(tiny) ///
>                mlabpos(12)) 

. 

这里mlabel()就指定了将变量pov的内容展示在marker周围,默认是展示在marker的右侧,可以通过mlabpos(12)将标注内容调整到marker的12点钟方向(即正上方)。

// 散点图,单独高亮显示"DC"州
use allstates.dta, clear 
graph twoway ///
            (scatter pov statefips, mlabel(stateab)) ///
            (scatter pov statefips if stateab == "DC"), ///
   legend(off)

. // 散点图,单独高亮显示"DC"州
. use allstates.dta, clear 
(Data on 50 States)

. graph twoway ///
>             (scatter pov statefips, mlabel(stateab)) ///
>             (scatter pov statefips if stateab == "DC"), ///
>    legend(off)

. 

9.3.2.2 散点图连线(connect)

散点图还可以通过connect()这一option将点之间连起来。在scatter的帮助文档(help scatter)中提到的connect_options就是这些功能:

connect_options Description
connect(connectstylelist) how to connect points
sort[(varlist)] how to order data before connecting
cmissing({y|n} …) missing values are ignored
lpattern(linepatternstylelist) line pattern (solid, dashed, etc.)
lwidth(linewidthstylelist) thickness of line
lcolor(colorstylelist) color and opacity of line
lalign(linealignmentstyle) line alignment (inside, outside, center)
lstyle(linestylelist) overall style of line

其中connect(connectstylelist)就指定了通过什么样的线来连接marker。点击connectstylelist即可打开一个新的窗口,展示了所有的connectstylelist。其中最长建的是用直线连接,connect(l)。此外还可以通过lpattern()定义虚线实线的类型,例如lpattern(dash)就是虚线。可以通过点击lineparrternstylelist查看。

// 散点图,点之间用短线相连
use allstates.dta, clear 
twoway ///
   (scatter pov statefips, connect(l) lpattern(dash))

. // 散点图,点之间用短线相连
. use allstates.dta, clear 
(Data on 50 States)

. twoway ///
>    (scatter pov statefips, connect(l) lpattern(dash))

. 

9.3.2.3 散点图加上线性拟合直线

// 散点图+拟合直线图
use allstates.dta, clear 
twoway ///
   (scatter pov statefips, mlabel(stateab)) ///
   (lfit pov statefips)

. // 散点图+拟合直线图
. use allstates.dta, clear 
(Data on 50 States)

. twoway ///
>    (scatter pov statefips, mlabel(stateab)) ///
>    (lfit pov statefips)

. 

拟合直线lift也是一种twoway这一plot类型下的细分绘图类型,可以在 help graph twoway中找到

9.3.3 柱状图 bar

需要注意的是,barhelp graph中的箱线图(box)、other下的直方图(histogram)等都不属于graph twoway类别。柱状图bartwoway是并列的。这里的graph bar的功能是为了展示变量y在变量x的每一个取值分组内的统计量(如均值、中位数、标准差,最大值、最小值等),默认展示的是均值。

但是严格来说,其实在graph twoway中同样有一个曲线类型是bar,即graph twoway bar 也是合法的图形,但是与这里的bar不同

通过 help graph bar可以查看散点图的帮助文档。该命令的语法结构为:

graph bar yvars [if] [in] [, options]

9.3.3.1 单个分组变量

我们希望基于allstates.dta数据的图形展示三大区域(nsw变量)9个普查区域(division变量)住房平均成本(propval100变量的平均值)。

下面的代码是一个初步尝试:

use allstates.dta, clear 
tab nsw 
graph bar propval100, over(nsw)

. use allstates.dta, clear 
(Data on 50 States)

. tab nsw 

     Region |
     North, |
  South, or |
       West |      Freq.     Percent        Cum.
------------+-----------------------------------
      North |         21       42.00       42.00
      South |         16       32.00       74.00
       West |         13       26.00      100.00
------------+-----------------------------------
      Total |         50      100.00

. graph bar propval100, over(nsw)

. 

use allstates.dta, clear 
tab division 
graph bar propval100, over(division)

. use allstates.dta, clear 
(Data on 50 States)

. tab division 

     Census |
   division |      Freq.     Percent        Cum.
------------+-----------------------------------
    N. Eng. |          6       12.00       12.00
    Mid Atl |          3        6.00       18.00
     E.N.C. |          5       10.00       28.00
     W.N.C. |          7       14.00       42.00
    S. Atl. |          8       16.00       58.00
     E.S.C. |          4        8.00       66.00
     W.S.C. |          4        8.00       74.00
   Mountain |          8       16.00       90.00
    Pacific |          5       10.00      100.00
------------+-----------------------------------
      Total |         50      100.00

. graph bar propval100, over(division)

. 

在上面的命令里的propval100是要展示的变量,默认展示的是不同分组内该变量的均值。over()option指定了分组的变量,这里我们分别根据nsw变量(大区域,取值分别为 North, South和West)和division(取值别为 N.eng.,MidAtl,E.N.c,W.N.C,S. Atl., E.S.C.,W.S.C. Mountain和Pacific)变量分组展示。

9.3.3.2 多个分组变量

当然,我们也可以按照多个变量进行分组:

use allstates.dta, clear 
tab nsw division 
graph bar propval100, over(nsw) over(division)

. use allstates.dta, clear 
(Data on 50 States)

. tab nsw division 

    Region |
    North, |
 South, or |                    Census division
      West |   N. Eng.    Mid Atl     E.N.C.     W.N.C.    S. Atl. |     Total
-----------+-------------------------------------------------------+----------
     North |         6          3          5          7          0 |        21 
     South |         0          0          0          0          8 |        16 
      West |         0          0          0          0          0 |        13 
-----------+-------------------------------------------------------+----------
     Total |         6          3          5          7          8 |        50 


    Region |
    North, |
 South, or |               Census division
      West |    E.S.C.     W.S.C.   Mountain    Pacific |     Total
-----------+--------------------------------------------+----------
     North |         0          0          0          0 |        21 
     South |         4          4          0          0 |        16 
      West |         0          0          8          5 |        13 
-----------+--------------------------------------------+----------
     Total |         4          4          8          5 |        50 

. graph bar propval100, over(nsw) over(division)

. 

在这个命令里的propval100是要展示的变量,默认展示的是不同分组内该变量的均值。over()option指定了分组的变量,这里需要根据两个变量分组:首先根据nsw(大区域,共3个取值,分别为 North, South和West)分组,然后根据division变量分组(共9个取值,别为 N.eng.,MidAtl,E.N.c,W.N.C,S. Atl., E.S.C.,W.S.C. Mountain和Pacific),两个变量一共将数据分为9个分组。在每个分组内展示了propval100的均值。

上面的图较为难看,横坐标的内容糊成了一团,可以使用nofill命令将分类变量中的缺失值忽略掉(不用nofill option的话,会将分组变量中缺失值作为一组):

use allstates.dta, clear 
sort division nsw 
graph bar propval100, over(nsw) over(division) nofill

. use allstates.dta, clear 
(Data on 50 States)

. sort division nsw 

. graph bar propval100, over(nsw) over(division) nofill

. 

然而,上面各个柱状图的距离较大,而且不够直观区分。而下面通过asyvars选项是的第一个分组变量变换成相应的若干个 y 变量:ynorth, ysouth, yweast

use allstates.dta, clear 
sort nsw division 
graph bar propval100, over(nsw) over(division) nofill asyvars

. use allstates.dta, clear 
(Data on 50 States)

. sort nsw division 

. graph bar propval100, over(nsw) over(division) nofill asyvars

. 

命令graph bar propval100, over(nsw) over(division) nofill asyvars等价于:

use allstates.dta, clear 
gen yNorth=propval100 if nsw==1
gen ySouth=propval100 if nsw==2
gen yWest=propval100 if nsw==3
graph bar yNorth ySouth yWest, over(division) nofill

. use allstates.dta, clear 
(Data on 50 States)

. gen yNorth=propval100 if nsw==1
(30 missing values generated)

. gen ySouth=propval100 if nsw==2
(35 missing values generated)

. gen yWest=propval100 if nsw==3
(38 missing values generated)

. graph bar yNorth ySouth yWest, over(division) nofill

. 

下面的命令可以进一步美化柱状图:

use allstates.dta, clear 
sort nsw division 
graph bar propval100, over(nsw) over(division) nofill asyvars ///
  ytitle(平均居住成本) ylabel(0(10)80) b1title(Region) ///
  legend(rows(1) position(1) ring(0))

. use allstates.dta, clear 
(Data on 50 States)

. sort nsw division 

. graph bar propval100, over(nsw) over(division) nofill asyvars ///
>   ytitle(平均居住成本) ylabel(0(10)80) b1title(Region) ///
>   legend(rows(1) position(1) ring(0))

. 

横坐标上的label有些较长,导致一行无法显示,可以将横坐标上的label倾斜展示,同时也可以显示柱状图每个柱子代表的数值。

use allstates.dta, clear 
sort nsw division 
graph bar propval100, over(nsw) ///
  over(division, label(angle(45))) /*将分组变量标识倾斜45度*/ /// 
  nofill asyvars ///
  ytitle(平均居住成本) ylabel(0(10)80) b1title(Region) ///
  legend(rows(1) position(1) ring(0)) ///
  blabel(bar, format(%4.2f)) //给每个条形图加上数据并规定数据格式

. use allstates.dta, clear 
(Data on 50 States)

. sort nsw division 

. graph bar propval100, over(nsw) ///
>   over(division, label(angle(45))) /*将分组变量标识倾斜45度*/ /// 
>   nofill asyvars ///
>   ytitle(平均居住成本) ylabel(0(10)80) b1title(Region) ///
>   legend(rows(1) position(1) ring(0)) ///
>   blabel(bar, format(%4.2f)) //给每个条形图加上数据并规定数据格式

. 

9.3.3.3 柱状图分组对比

下面的代码实现了两组bar的功能。

clear
input str5 age m f
16-24 .9 .2
25-44 .8 .8
45-66 3.8 2.9
67-79 8.2 5.4
80+ 9.1 7.2
end //以上程序录入数据
graph bar m f /// /*绘条形图命令graph bar*/
, ///
over(age) /// /*按年龄绘制*/
title(不同年龄组发病率) ///
b1title("Age") /// /*底部标题*/
ytitle(发病率) ///
legend( label(1 "Males") label(2 "Females") ) ///
bar(2 , color(gs0)) /*第二类条形图的色彩方案*/

. clear

. input str5 age m f

           age          m          f
  1. 16-24 .9 .2
  2. 25-44 .8 .8
  3. 45-66 3.8 2.9
  4. 67-79 8.2 5.4
  5. 80+ 9.1 7.2
  6. end //以上程序录入数据

. graph bar m f /// /*绘条形图命令graph bar*/
> , ///
> over(age) /// /*按年龄绘制*/
> title(不同年龄组发病率) ///
> b1title("Age") /// /*底部标题*/
> ytitle(发病率) ///
> legend( label(1 "Males") label(2 "Females") ) ///
> bar(2 , color(gs0)) /*第二类条形图的色彩方案*/

. 

注意,与twoway的图中不同,bar图中不存在横轴变量,当想加上横轴标题是,需要使用b1title()这一option。

另外,bar(2, bscolor(gs3))单独设定了第二个变量bar图的色彩方案。可以不用这条使用默认色彩方案

9.4 同时画多个图 by(varname)

前面提到,如果要在一个图中画多条曲线,只需要用括号分隔开即可。最常用于描述两个变量之间关系的图形为散点图与拟合图。

use allstates.dta, clear 
twoway (scatter propval100 popden) (lfit propval100 popden) (qfit propval100 popden)

twoway (scatter propval100 popden) (mspline propval100 popden) ///
(fpfit propval100 popden) (mband propval100 popden)(lowess propval100 popden)

twoway (lfitci propval100 popden) (scatter propval100 popden)

by(varname)这一选项则是在绘图时按照指定变量分组,利用每个分组内的数据分别绘制图形。by(varname)功能适用于matrix 和star 以外所有图形。。一般情况下,对bar 和box,按指定变量分组的多个图共用一套坐标轴,对其它图形,将分别绘制独立的图形并列陈列。Rescale 与by()合用,要求图形使用不同的刻度。默认为所有图形使用相同的刻度。

例如下面的代码利用auto.dta,在进口车样本和国产车样本内分别考察了mpg和weight的关系。

sysuse auto, clear 
graph twoway (scatter mpg weight) ///
             (lfit mpg weight), ///
  by(foreign, legend(position(12))) legend(row(1))

. sysuse auto, clear 
(1978 automobile data)

. graph twoway (scatter mpg weight) ///
>              (lfit mpg weight), ///
>   by(foreign, legend(position(12))) legend(row(1))

. 

sysuse auto, clear 
graph twoway (scatter mpg weight) ///
             (lfit mpg weight), ///
  by(rep78, legend(position(12))) legend(row(1))

. sysuse auto, clear 
(1978 automobile data)

. graph twoway (scatter mpg weight) ///
>              (lfit mpg weight), ///
>   by(rep78, legend(position(12))) legend(row(1))

. 

9.5 将图片的保存、导出与合并

通过命令graph save可以将图片保存为*.gph文件。该格式为Stata特有。

保存后可以通过graph use打开gph图片文件

通过命令graph export可以将graph导出到其他常见图片格式,例如svg, pdf, eps等。

通过命令graph close可以关闭打开的图片窗口。

sysuse auto, clear 
scatter mpg weight 
graph save temp, replace 
graph use temp
graph export temp.svg, replace 
graph export temp.pdf, replace 
graph close 

. sysuse auto, clear 
(1978 automobile data)

. scatter mpg weight 

. graph save temp, replace 
file temp.gph saved

. graph use temp

. graph export temp.svg, replace 
file temp.svg saved as SVG format

. graph export temp.pdf, replace 
file temp.pdf saved as PDF format

. graph close 

. 

我们还可以将多个gph文件(即Stata绘图文件)合并在一张图里,效果如下:

sysuse uslifeexp, clear 
graph twoway line le_male year, saving(male, replace)
graph twoway line le_female year, saving(female, replace)
graph combine male.gph female.gph 

. sysuse uslifeexp, clear 
(US life expectancy, 1900–1999)

. graph twoway line le_male year, saving(male, replace)
file male.gph saved

. graph twoway line le_female year, saving(female, replace)
file female.gph saved

. graph combine male.gph female.gph 

. 

需要指出的是,在保存图片文件时,我们使用了saving(male)这一option,它会在当前工作目录下保存文件名为 male.gph 的文件。它等价于如下命令graph save "./male.gph"

9.6 绘图模板

图的各种设定可以组合成模板,当选定模板后,线性、颜色等各种参数设定相应固定。Stata系统中默认提供了s2color(系统默认), s2mono, s2manual, s1color, s1mono, s1rcolor, s1manual, sj, economist等几种类型,可以通过scheme()这一option来指定绘图模板。

利用下面代码去看看不同类型模板的区别

sysuse auto, clear 
graph twoway scatter mpg weight
graph twoway scatter mpg weight,scheme(s2color)
graph twoway scatter mpg weight,scheme(s2mono)
graph twoway scatter mpg weight,scheme(s1color)
graph twoway scatter mpg weight,scheme(s1manual)
graph twoway scatter mpg weight,scheme(s1mono)
graph twoway scatter mpg weight,scheme(s1rcolor)
graph twoway scatter mpg weight,scheme(sj)
graph twoway scatter mpg weight,scheme(economist)

除了系统自带的scheme之外,还有很多第三方提供的模板,能够产生更美观的绘图。资料: https://www.lianxh.cn/news/37ea99dab6efb.html

https://zhuanlan.zhihu.com/p/363385248

ssc install blindschemes // 安装plotplain, plotplainblind, plottig, plottigblind 主题

https://github.com/asjadnaqvi/stata-schemepack 给出了一些可能的美化主题。

当然,主题的更换并不是必须的,默认的主题已经足够优秀;而且美观永远是次要的,内容和输出永远是第一位的

9.7 练习题

1.数据文件分省年度数据-CPI.xls分省年度数据-GDP.xlsx分省年度数据-Pop.xlsx是从国家统计局网站下载的过去20年(即2003-2022年)内我国分省年度CPI(居民消费价格指数)、GDP(国内生产总值)和Pop(年末常住人口总数)数据。1 三个数据文件可以在课程QQ群文件-data目录下的chap_graph_exc_q1_data.zip内找到。 请基于这些数据文件,编辑代码,完成如下数据分析和绘图任务:

(a)[数据导入与文件合并]。将3个原始数据文件读入Stata,分别得到全国各个省份2003-2022年的CPI、GDP和Pop指标。然后将3个文件合并在一起得到一个数据文件该数据为省份x年度的面板数据(long型),共包含如下5个变量:

  • prov:省 (例如:北京市、辽宁省等)
  • year:年度
  • CPI:居民价格消费指数
  • GDP:国内生产总值
  • Pop:年末常住人口总数

(提示:在导入之后可以通过rename修改变量名称,但是变量名不能以数字开头,例如2022年不是一个合法的变量名)

(b)[增长率指标计算]。计算三个指标(即CPIGDPPop每年的增长率指标:CPIGGDPGPopG,增长率定义为每个指标相对于上一年度取值的增长率,例如: GDPG_t=GDP_t/GDP_{t-1}-1注意:由于指标定义的关系,CPI指标增长率的计算方法略有不同)。仅保留2010年到2022年之间的数据。保存为文件data.dta

(c)[绘图展示1] 基于数据data.dta,绘制指标CPIG的直方图(histogram),,效果如下:

注意以下要点:

  • 标题为“CPIG直方图合并”
  • 左下角为包含你的学号和姓名的个人信息,例如“张三+2210000000”
  • 增加了一条基于核密度的正态曲线
  • 上面的示意图中的数据为随机模拟得到,请以你的计算结果为准

(d)[绘图展示2] 基于数据data.dta,使用柱状图(注意:是graph bar而不是graph twoway bar),分别展示各个省份和各个年度内GDPGPopG的均值,然后将两个图形合并在一个图形中,效果如下:

注意以下要点:

  • 两张图合并后,为上下结构
  • 标题为“柱状图合并”
  • 左下角为包含你的学号和姓名的个人信息,例如“张三+2210000000”
  • 横轴的标签方向不是横向排列,而是竖向排列
  • 横轴中的省份信息去除了“省”、“xx自治区”等以简化表达
  • 上面的示意图中的数据为随机模拟得到,请以你的计算结果为准

(e)[绘图展示3]。分别计算各省在样本期(2010-2022)内的GDP增长率GDPG的算数平均值AvgGDPG、Pop增长率PopG的算数平均值AvgPopG。以散点图+拟合直线展示两个指标的关系,效果如下:

注意以下要点:

  • AvgGDPG为纵轴、以AvgPopG为横轴
  • 以空心三角形展示AvgGDPG和指标AvgPopG的变动关系,
  • 在每个散点的合适位置(例如上方)添加省份名称作为标签(为了节约空间,可以将省份名称中的“省”、“xx自治区”去掉)
  • 标题为“平均GDP增长率、平均人口增长率变动关系”
  • 副标题为“分省2010-2022”
  • 纵轴标题为“GDP增长率”
  • 横轴标题为“人口增长率”
  • 图例内容分别为“GDP增长率”和“拟合直线”
  • 左下角为包含你的学号和姓名的个人信息,例如“张三+2210000000”
  • 上面的示意图中的数据为随机模拟得到,请以你的计算结果为准

  1. 数据参见课程QQ群。↩︎