Intro to lavaanPlot

Alex Lishinski

2018-04-24

Introduction

The lavaan package is an excellent package for structural equation models, and the DiagrammeR package is an excellent package for producing nice looking graph diagrams. As of right now, the lavaan package has no built in plotting functions for models, and the available options from external packages don’t look as nice and aren’t as easy to use as DiagrammeR, in my opinion. Of course, you can use DiagrammeR to build path diagrams for your models, but it requires you to build the diagram specification manually. This package exists to streamline that process, allowing you to plot your lavaan models directly, without having to translate them into the DOT language specification that DiagrammeR uses.

Package example

The package is very straightforward to use, simply call the lavaanPlot function with your lavaan model, adding whatever graph, node and edge attributes you want as a named list (graph attributes are specified as a standard default value that shows you what the other attribute lists should look like). For your reference, the available attributes can be found here:

http://rich-iannone.github.io/DiagrammeR/graphviz_and_mermaid.html#node-attributes http://rich-iannone.github.io/DiagrammeR/graphviz_and_mermaid.html#edge-attributes

Here’s a quick example using the mtcars data set.

First fit your lavaan model. The package supports plotting lavaan regression relationships and latent variable - indicator relationships.

library(lavaan)
## This is lavaan 0.5-23.1097
## lavaan is BETA software! Please report any bugs.
library(lavaanPlot)

model <- 'mpg ~ cyl + disp + hp
          qsec ~ disp + hp + wt'

fit <- sem(model, data = mtcars)
summary(fit)
## lavaan (0.5-23.1097) converged normally after  36 iterations
## 
##   Number of observations                            32
## 
##   Estimator                                         ML
##   Minimum Function Test Statistic               18.266
##   Degrees of freedom                                 2
##   P-value (Chi-square)                           0.000
## 
## Parameter Estimates:
## 
##   Information                                 Expected
##   Standard Errors                             Standard
## 
## Regressions:
##                    Estimate   Std.Err  z-value  P(>|z|)
##   mpg ~                                                
##     cyl               -0.987    0.738   -1.337    0.181
##     disp              -0.021    0.010   -2.178    0.029
##     hp                -0.017    0.014   -1.218    0.223
##   qsec ~                                               
##     disp              -0.008    0.004   -2.122    0.034
##     hp                -0.023    0.004   -5.229    0.000
##     wt                 1.695    0.398    4.256    0.000
## 
## Covariances:
##                    Estimate   Std.Err  z-value  P(>|z|)
##  .mpg ~~                                               
##    .qsec               0.447    0.511    0.874    0.382
## 
## Variances:
##                    Estimate   Std.Err  z-value  P(>|z|)
##    .mpg                8.194    2.049    4.000    0.000
##    .qsec               0.996    0.249    4.000    0.000

Then using that model fit object, simply call the lavaanPlot function, specifying your desired graph parameters.

lavaanPlot(model = fit, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = F)

You can also specify different variable labels

labels <- list(mpg = "Miles Per Gallon", cyl = "Cylinders", disp = "Displacement", hp = "Horsepower", qsec = "Speed", wt = "Weight")

lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = F)

An example showing latent variable relationships

HS.model <- ' visual  =~ x1 + x2 + x3      
textual =~ x4 + x5 + x6
speed   =~ x7 + x8 + x9 
'

fit <- cfa(HS.model, data=HolzingerSwineford1939)

lavaanPlot(model = fit, edge_options = list(color = "grey"))

And now you can label the plot edges with the coefficient values (standardized or not) for significant paths (you can also specify whatever significance level you want so you can plot values for whatever coefficients you want).

model <- 'mpg ~ cyl + disp + hp
          qsec ~ disp + hp + wt'

fit <- sem(model, data = mtcars)
summary(fit)
## lavaan (0.5-23.1097) converged normally after  36 iterations
## 
##   Number of observations                            32
## 
##   Estimator                                         ML
##   Minimum Function Test Statistic               18.266
##   Degrees of freedom                                 2
##   P-value (Chi-square)                           0.000
## 
## Parameter Estimates:
## 
##   Information                                 Expected
##   Standard Errors                             Standard
## 
## Regressions:
##                    Estimate   Std.Err  z-value  P(>|z|)
##   mpg ~                                                
##     cyl               -0.987    0.738   -1.337    0.181
##     disp              -0.021    0.010   -2.178    0.029
##     hp                -0.017    0.014   -1.218    0.223
##   qsec ~                                               
##     disp              -0.008    0.004   -2.122    0.034
##     hp                -0.023    0.004   -5.229    0.000
##     wt                 1.695    0.398    4.256    0.000
## 
## Covariances:
##                    Estimate   Std.Err  z-value  P(>|z|)
##  .mpg ~~                                               
##    .qsec               0.447    0.511    0.874    0.382
## 
## Variances:
##                    Estimate   Std.Err  z-value  P(>|z|)
##    .mpg                8.194    2.049    4.000    0.000
##    .qsec               0.996    0.249    4.000    0.000
# significant standardized paths only
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE)
# significant unstandardized paths
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE, stand = FALSE)
# All paths unstandardized
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE, stand = FALSE, sig = 1.00)

Same works for latent variable loadings

HS.model <- ' visual  =~ x1 + x2 + x3      
textual =~ x4 + x5 + x6
speed   =~ x7 + x8 + x9 
'

fit <- cfa(HS.model, data=HolzingerSwineford1939)

labels = list(visual = "Visual Ability", textual = "Textual Ability", speed = "Speed Ability")

# significant standardized paths only
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE)
# significant unstandardized paths
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE, stand = FALSE)
# All paths unstandardized
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE, stand = FALSE, sig = 1.00)

You can also include double-sided edges to represent model covariances if you want:

HS.model <- ' visual  =~ x1 + x2 + x3      
textual =~ x4 + x5 + x6
speed   =~ x7 + x8 + x9 
'

fit <- cfa(HS.model, data=HolzingerSwineford1939)

labels = list(visual = "Visual Ability", textual = "Textual Ability", speed = "Speed Ability")

# significant standardized paths only
lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE, covs = TRUE)

You can include significance stars as well

lavaanPlot(model = fit, labels = labels, node_options = list(shape = "box", fontname = "Helvetica"), edge_options = list(color = "grey"), coefs = TRUE, covs = TRUE, stars = TRUE)