Odds ratios (eform)

By default, coefplot displays the results as they have been stored by the estimation command in e(b). These raw coefficients may not always be what you want to see. For example, in case of a logit model, you may want to use the eform option to transform the raw log odds to odds ratios:

. sysuse auto, clear
(1978 Automobile Data)

. logit foreign mpg trunk length turn
(output omitted)

. coefplot, drop(_cons) xline(1) eform xtitle(Odds ratio)
Code
estimates/eform.svg

Similarly, eform computes hazard ratios after stcox, relative-risk ratios after mlogit, or incidence-rate ratios after poisson. You can also transform just a selection of coefficients; see eform() in the help file.

[top]

Rescaling

The rescale() option allows you to rescale the estimates by a multiplicative factor. For example, to plot percentages instead of fractions after proportion, type:

. sysuse auto, clear
(1978 Automobile Data)

. proportion rep78

Proportion estimation             Number of obs   =         69

--------------------------------------------------------------
             | Proportion   Std. Err.     [95% Conf. Interval]
-------------+------------------------------------------------
rep78        |
           1 |   .0289855   .0203446      .0070061    .1121326
           2 |    .115942   .0388245      .0580159    .2183014
           3 |   .4347826   .0601159      .3207109     .556206
           4 |   .2608696   .0532498      .1690271    .3798066
           5 |   .1594203   .0443922       .089188    .2686455
--------------------------------------------------------------

. coefplot, rescale(100) xtitle(Percent) recast(bar) barwidth(0.5) finten(60) ///
>     citop citype(logit) ciopt(recast(rcap))
Code
estimates/rescale.svg

Note that option citype(logit) was specified to compute the confidence limits using a logit transformation, as this is the default method used by proportion.

You can also rescale single coefficients, as in the following example:

. sysuse auto, clear
(1978 Automobile Data)

. generate gpm = 1 / mpg 

. regress price weight gpm turn

      Source |       SS           df       MS      Number of obs   =        74
-------------+----------------------------------   F(3, 70)        =     18.28
       Model |   279009499         3  93003166.4   Prob > F        =    0.0000
    Residual |   356055897        70  5086512.81   R-squared       =    0.4393
-------------+----------------------------------   Adj R-squared   =    0.4153
       Total |   635065396        73  8699525.97   Root MSE        =    2255.3

------------------------------------------------------------------------------
       price |      Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
      weight |   2.480716   .8380717     2.96   0.004     .8092351    4.152198
         gpm |   110541.8   39814.31     2.78   0.007     31134.71      189949
        turn |  -410.4216   116.9504    -3.51   0.001    -643.6719   -177.1713
       _cons |   9399.092    3101.64     3.03   0.003     3213.066    15585.12
------------------------------------------------------------------------------

. coefplot, drop(_cons) xline(0) rescale(weight = 100 gpm = .01) ///
>     coeflabels(weight = "Weight (in 100 lbs.)" gpm = "Gallon per 100 miles")
Code
estimates/rescale2.svg

Or here is an example in which the effects are rescaled by the standard deviations of the predictors (semi-standardized effects):

. sysuse auto, clear
(1978 Automobile Data)

. regress price mpg weight length turn
(output omitted)

. foreach v of var mpg weight length turn {
  2.     quietly summarize `v'
  3.     local sd_`v' = r(sd)
  4. }

. coefplot, drop(_cons) xline(0)           ///
>     rescale(mpg    = `sd_mpg'            ///
>             weight = `sd_weight'         ///
>             length = `sd_length'         ///
>             turn   = `sd_turn') 
Code
estimates/rescale3.svg
[top]

Transformations

More generally, you can use the transform() option to apply arbitrary transformations (using endpoint transformation for confidence limits). Within the expressions in transform(), use @ as a placeholder for the value to be transformed. For example, transform(* = exp(@)) does the same as the eform option discussed above:

. sysuse auto, clear
(1978 Automobile Data)

. logit foreign mpg trunk length turn
(output omitted)

. coefplot (., eform label(eform)) ///
>          (., transform(* = exp(@)) label(transform)) ///
>          , drop(_cons) xline(1) xtitle(Odds ratio)
Code
estimates/transform.svg

Likewise, to plot standard deviations and correlations of random effects after a mixed-effects model (mixed), type:

. webuse pig, clear
(Longitudinal analysis of pig weights)

. mixed weight week || id: week, covariance(unstructured)

Performing EM optimization: 

Performing gradient-based optimization: 

Iteration 0:   log likelihood = -868.96185  
Iteration 1:   log likelihood = -868.96185  

Computing standard errors:

Mixed-effects ML regression                     Number of obs     =        432
Group variable: id                              Number of groups  =         48

                                                Obs per group:
                                                              min =          9
                                                              avg =        9.0
                                                              max =          9

                                                Wald chi2(1)      =    4649.17
Log likelihood = -868.96185                     Prob > chi2       =     0.0000

------------------------------------------------------------------------------
      weight |      Coef.   Std. Err.      z    P>|z|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
        week |   6.209896   .0910745    68.18   0.000     6.031393    6.388399
       _cons |   19.35561   .3996387    48.43   0.000     18.57234    20.13889
------------------------------------------------------------------------------

------------------------------------------------------------------------------
  Random-effects Parameters  |   Estimate   Std. Err.     [95% Conf. Interval]
-----------------------------+------------------------------------------------
id: Unstructured             |
                   var(week) |   .3715251   .0812958      .2419532    .5704859
                  var(_cons) |   6.823363   1.566194      4.351297    10.69986
             cov(week,_cons) |  -.0984378   .2545767     -.5973991    .4005234
-----------------------------+------------------------------------------------
               var(Residual) |   1.596829    .123198      1.372735    1.857505
------------------------------------------------------------------------------
LR test vs. linear model: chi2(3) = 764.58                Prob > chi2 = 0.0000

Note: LR test is conservative and provided only for reference.

. coefplot, noeqlabels keep(ln*: at*:)                        ///
>     transform(ln*: = exp(@) at*: = tanh(@))                 ///
>     coeflabels(ln*1: = "se(week)" ln*2: = "se(_cons)"       ///
>                at*: = "corr(week,_cons)" ln*e: = "sd(Residual)")
Code
estimates/transform1.svg

Note that eform, rescale(), and transform() operate independently from each other. If all three are specified, eform is applied first, then rescale(), then transform().

There are a number of temporary variables you can refer to within the transform() option. Here is an example in which the lower and upper parts of the confidence intervals is displayed in different colors:

. sysuse auto, clear
(1978 Automobile Data)

. regress price ibn.rep78, nocons
(output omitted)

. coefplot (., cionly transform(* = min(@,@b)) pstyle(p2)) ///
>          (., cionly transform(* = max(@,@b)) pstyle(p3)) ///
>          (., noci pstyle(p1)) ///
>          , nooffsets ciopts(lwidth(*10) lcolor(*.5)) legend(off)
Code
estimates/transform2.svg
[top]

Selecting coefficients

The keep() and drop() options determine the equations and coefficients that will be included in the graph based on their names (see the examples in Getting started). Sometimes, however, it is useful to select coefficients based on their values. In this case, the if() option can be employed. For example, suppose you want to use a different plot style for significant and nonsignificant coefficients. You could type:

. sysuse auto, clear
(1978 Automobile Data)

. regress price mpg trunk length turn if foreign==1
(output omitted)

. coefplot (., if(@ll<0 & @ul>0)) /// nonsignificant (0 included in CI)
>          (., if(@ll>0 | @ul<0)) /// significant (0 not in CI)
>     , drop(_cons) nooffset xline(0) legend(off)
Code
estimates/ifopt.svg

@ll and @ul are internal variables containing the lower and upper limits of confidence intervals (see here).

[top]

Standardized coefficients

coefplot does not support standardizing coefficients. If you want to plot standardized coefficients, you have to compute the standardized coefficients before applying coefplot. An approach that works for linear regression is to standardize all variables before estimating the model, as in the following example:

. sysuse auto, clear
(1978 Automobile Data)

. preserve

. center price mpg weight length turn foreign, inplace standardize

. regress price mpg weight length turn, noconstant
(output omitted)

. restore

. coefplot, xline(0) xtitle(Standardized Coefficients)
Code
estimates/std.svg

Command center from the SSC Archive has been used to standardize the variables (type ssc install center to install the command). When standardizing the variables, make sure to use the same set of observations as are used in the model. The noconstant option has been added to the regression command, because the constant is zero by construction in the standardized model.

Another approach is to use sem to estimate the model, which stores standardized coefficients and variances in e(b_std) and e(V_std) (results for the confidence intervals will be slightly different). In coefplot, use options b() and v() to refer to these results:

. sysuse auto, clear
(1978 Automobile Data)

. sem (price <- mpg weight length turn)

Endogenous variables

Observed:  price

Exogenous variables

Observed:  mpg weight length turn

Fitting target model:

Iteration 0:   log likelihood = -1879.0685  
Iteration 1:   log likelihood = -1879.0685  

Structural equation model                       Number of obs     =         74
Estimation method  = ml
Log likelihood     = -1879.0685

------------------------------------------------------------------------------
             |                 OIM
             |      Coef.   Std. Err.      z    P>|z|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
Structural   |
  price <-   |
         mpg |  -94.65136   78.09846    -1.21   0.226    -247.7215    58.41881
      weight |   5.029726   1.114147     4.51   0.000     2.846039    7.213414
      length |  -73.14738   38.82984    -1.88   0.060    -149.2525    2.957707
        turn |  -323.8606   122.5203    -2.64   0.008     -563.996   -83.72509
       _cons |   19581.42   5798.795     3.38   0.001     8215.988    30946.85
-------------+----------------------------------------------------------------
 var(e.price)|    5039170   828434.4                       3651088     6954977
------------------------------------------------------------------------------
LR test of model vs. saturated: chi2(0)   =      0.00, Prob > chi2 =      .

. coefplot, drop(_cons) xline(0) b(b_std) v(V_std)    ///
>     xtitle(Standardized Coefficients)
Code
estimates/std2.svg

Yet another solution is to manually specify scaling factors for the different coefficients using the rescale() option (see above).

[top]

Results from margins

coefplot can plot results computed by margins if it is specified with the post option. For example, if you want to plot average marginal effects instead of log odds or odds ratios from a logit model, you can apply margins as follows:

. sysuse auto, clear
(1978 Automobile Data)

. logit foreign mpg trunk length turn 
(output omitted)

. margins, dydx(*) post

Average marginal effects                        Number of obs     =         74
Model VCE    : OIM

Expression   : Pr(foreign), predict()
dy/dx w.r.t. : mpg trunk length turn

------------------------------------------------------------------------------
             |            Delta-method
             |      dy/dx   Std. Err.      z    P>|z|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
         mpg |  -.0132652    .008305    -1.60   0.110    -.0295426    .0030122
       trunk |   -.000315   .0126011    -0.02   0.980    -.0250128    .0243828
      length |  -.0047259   .0041489    -1.14   0.255    -.0128577    .0034059
        turn |  -.0526197   .0148773    -3.54   0.000    -.0817788   -.0234607
------------------------------------------------------------------------------

. coefplot, xline(0) xtitle(Average maginal effects)
Code
estimates/margins.svg

It is essential to specify the post option with margins so that it posts its results in e() from where coefplot collects the results to be displayed. If you do not specify the post option, then margins leaves e() unchanged and coefplot uses the raw coefficients from the logit model that still reside in e().

[top]

Margins and mlogit

Here is an example for plotting average marginal effects for all equations of an mlogit. The code is a bit involved because margins has a complicated way of naming things:

. webuse sysdsn1, clear
(Health insurance data)

. mlogit insure i.male i.nonwhite i.site
(output omitted)

. margins, dydx(*) post

Average marginal effects                        Number of obs     =        616
Model VCE    : OIM

dy/dx w.r.t. : 1.male 1.nonwhite 2.site 3.site
1._predict   : Pr(insure==Indemnity), predict(pr outcome(1))
2._predict   : Pr(insure==Prepaid), predict(pr outcome(2))
3._predict   : Pr(insure==Uninsure), predict(pr outcome(3))

------------------------------------------------------------------------------
             |            Delta-method
             |      dy/dx   Std. Err.      z    P>|z|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
1.male       |
    _predict |
          1  |  -.1222033   .0452073    -2.70   0.007     -.210808   -.0335985
          2  |   .1106393   .0456373     2.42   0.015     .0211918    .2000869
          3  |   .0115639   .0247844     0.47   0.641    -.0370126    .0601405
-------------+----------------------------------------------------------------
1.nonwhite   |
    _predict |
          1  |  -.2001526   .0485656    -4.12   0.000    -.2953394   -.1049658
          2  |   .2189894   .0497992     4.40   0.000     .1213847    .3165941
          3  |  -.0188368   .0230976    -0.82   0.415    -.0641073    .0264337
-------------+----------------------------------------------------------------
2.site       |
    _predict |
          1  |   .0009568   .0479225     0.02   0.984    -.0929696    .0948833
          2  |   .0667526   .0480807     1.39   0.165    -.0274839    .1609891
          3  |  -.0677094    .023939    -2.83   0.005     -.114629   -.0207898
-------------+----------------------------------------------------------------
3.site       |
    _predict |
          1  |    .114833   .0506483     2.27   0.023     .0155641     .214102
          2  |   -.120154   .0491288    -2.45   0.014    -.2164447   -.0238633
          3  |    .005321   .0312838     0.17   0.865    -.0559941     .066636
------------------------------------------------------------------------------
Note: dy/dx for factor levels is the discrete change from the base level.

. coefplot (, keep(*:1._predict) label(Indemnity)) ///
>          (, keep(*:2._predict) label(Prepaid))   ///
>          (, keep(*:3._predict) label(Uninsure))  ///
>     , swapnames xline(0) legend(rows(1)) 
Code
estimates/mlogit.svg

In Stata 13 or older, margins did not support computing marginal effects for all equations in one run. Here is an example that shows you how to compute the results by looping over the outcomes:

. webuse sysdsn1, clear
(Health insurance data)

. mlogit insure i.male i.nonwhite i.site
(output omitted)

. estimates store mlogit

. forvalues o = 1/3 {
  2.     local oname: word `o' of Indemnity Prepaid Uninsure
  3.     quietly margins, dydx(*) post predict(outcome(`o'))
  4.     estimates store `oname'
  5.     quietly estimates restore mlogit
  6. }

. coefplot Indemnity Prepaid Uninsure, xline(0) legend(rows(1)) 
Code
estimates/mlogit2.svg