% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/semTable.R
\name{semTable}
\alias{semTable}
\title{Creates Structural Equation Modeling Tables}
\usage{
semTable(object, file = NULL, paramSets = "all", paramSetLabels,
  columns = c(est = "Estimate", se = "SE", z = "z", p = "p"),
  columnLabels, fits = c("chisq", "cfi", "tli", "rmsea"),
  fitLabels = toupper(fits), varLabels = NULL, groups = NULL,
  type = "latex", table.float = FALSE, caption = NULL,
  label = NULL, longtable = FALSE, print.results = TRUE,
  centering = "siunitx", alpha = c(0.05, 0.01, 0.001))
}
\arguments{
\item{object}{A lavaan object (e.g., returned by cfa() or sem()),
or a named list of lavaan objects, e.g., \code{list("Model A"
= obj1, "Model B" = obj2)}. Results will be displayed side by
side.}

\item{file}{Base name for output file. This function will insert
suffix, either "tex", "html" and "csv".}

\item{paramSets}{Parameter sets to be included for each fitted
object.  Valid values of the vector are \code{"all"} or a any
of the following: \code{c("loadings", "slopes", "intercepts",
"residualvariances", "residualcovariances", "latentmeans",
"latentvariances", "latentcovariances", "thresholds",
"constructed", "fits")}. Default is "all", any of the
estimates present in the fitted model that are listed in the
previous sentence will be included in the output. For the sake
of simplicity, we now allow one vector here, which applies to
all models in the object list.}

\item{paramSetLabels}{Named vector, used to supply alternative
pretty printing labels for parameter sets. The default values
are \code{c("loadings"= "Factor Loadings", "slopes" =
"Regression Slopes", "intercepts" = "Intercepts", "means"=
"Means", "residualvariances" = "Residual Variances",
"residualcovariances" = "Residual Covariances", "variances" =
"Variances", "latentvariances" = "Latent Variances",
"latentcovariances" = "Latent Covariances", "latentmeans" =
"Latent Intercepts", "thresholds" = "Thresholds",
"constructed" = "Constructed", "fits" = "Fit Indices")}.  The
paramSetLabels argument must be a named vector that overrides
some or all of the default names.}

\item{columns}{A vector naming estimates to appear for each model.
The allowed columns are "est", "se", "z", "p", "rsquare",
"estse", "eststars", "estsestars". The first 5 have the usual
meanings, while "estse" (can also be written \code{"est(se)"})
displays as, for example "1.21(0.23)", and the last 2 are to
include "significance stars".  \code{"eststars"} shows as
"1.21***" and \code{"estsestars"} (or \code{"est(se)stars"})
displays as "1.21(0.23)**". See parameter \code{alpha}. One
may request different columns for each model by providing a
named list of vectors.  Use model names in the list,
\code{list("Model A" = c("est", "se"), "Model B" = c("estse",
"p"))}.}

\item{columnLabels}{A named vector of "pretty labels" for the
headings in the table. The default labels are \code{c("est" =
"Estimate", se = "Std. Err.", z = "z", p = "p", rsquare =
"R Square", estse = "Estimate(Std.Err."), eststars =
"Estimate", estsestars = "Estimate(Std.Err.)")}.}

\item{fits}{Summary indicators to be included. May be a list, one
for each model provided, otherwise the same fit indicators
will be presented for each model. Any of the fit indicators
provided by \code{lavaan::fitMeasures(object)} are allowed:
\code{c("npar", "fmin", "chisq", "df", "pvalue",
"baseline.chisq", "baseline.df", "baseline.pvalue", "cfi",
"tli", "nnfi", "rfi", "nfi", "pnfi", "ifi", "rni", "logl",
"unrestricted.logl", "aic", "bic", "ntotal", "bic2", "rmsea",
"rmsea.ci.lower", "rmsea.ci.upper", "rmsea.pvalue", "rmr",
"rmr_nomean", "srmr", "srmr_bentler", "srmr_bentler_nomean",
"srmr_bollen", "srmr_bollen_nomean", "srmr_mplus",
"srmr_mplus_nomean", "cn_05", "cn_01", "gfi", "agfi", "pgfi",
"mfi", "ecvi")}. The return for "chisq" will include markup
for degrees of freedom and p value. If user specifies
\code{NULL}, or if "fits" is excluded from \code{paramSets},
all fit indicators are omitted.}

\item{fitLabels}{Labels for some or all of the fit measures
requested by the fits parameter, e.g. \code{c(rmsea =
"Root Mean Square Error of Approximation", cli = "CLI")}. The
default labels are the upper-case fits names (except for
"chisq", where a Greek letter is supplied when possible).}

\item{varLabels}{Named vector of labels to replace variable names
in column 1 of SEM table.}

\item{groups}{All groups will be printed, unless a subset is
requested here. Estimates for all groups will be displayed
side by side. If ONLY SOME groups should be included, then
specify groups as either names of fit objects or as integers
for elements of the groups vector.}

\item{type}{Choose "latex", "html", or "csv"}

\item{table.float}{If TRUE, create a LaTeX floating table object
in which the tabular created here will reside. Default is
FALSE.}

\item{caption}{Caption for table (if table.float=TRUE) or
longtable output. Ignored otherwise.}

\item{label}{LaTeX label for this object (for
cross-references). Only used if table.float = TRUE or
longtable = TRUE.}

\item{longtable}{If TRUE, use longtable for LaTeX
documents. Default is FALSE. If true, \code{table.float}
argument is ignored.}

\item{print.results}{If TRUE, marked up result will be displayed
within the session. Otherwise, result is returned silently and
user can use \code{cat} to dislay it. Don't use \code{print}
because it inserts unwanted decorations.}

\item{centering}{Default "siunitx". For method used in previous
editions, replace with "none".}

\item{alpha}{Thresholds for p-values that determine number of
stars.  Defaults as \code{c(0.05, 0.01, 0.001)} for
\code{c("*", "**", "***")}.}
}
\value{
Markup for SEM table. Includes an attribute
    "markedResults", which can be converted to other markup
    formats by the function markupConvert.
}
\description{
Creates LaTeX markup for structural equation modeling output
tables in the style of the American Psychological
Association(APA). Input objects should be created by the
"\code{lavaan}" package.
}
\details{
The argument paramSets determines the inclusion of estimate sections.
One can specify "all", which means that all types of parameters that
we can find in the fitted model are presented.  Otherwise, a subset
of parameter sets can be chosen by the user.
\itemize{
\item "loadings" are the factor loadings in the model.
\item "slopes" are the regression slopes in the model.
\item "intercepts" are the estimated constants in the measurement
     models.
\item "residualvariances" are the observed variable residual variances.
\item "residualcovariances" are the observed covariances among
residuals of observed variables.
\item "latentvariances" are the variances of unobserved variables.
\item "latentcovariances" are the covariances between unobserved variables.
\item "latentmeans" are means of unobserved variables
\item "thresholds" arise in latent
response variates (non-numeric indicator data).
\item "constructed" are parameters that are calculated from a formula
      in the model specification, such as an indirect path c=a*b.
\item "fits" the summary indicators of the mismatch between
the theoretical and observed covariance matrices, such as
RMSEA, CLI, TFI. While the fits are not technically parameters, they
are displayed in the same block style as parameters
}

The columns parameter is used to specify different columns,
while columnLabels will alter the displayed labels for them.
}
\examples{
\donttest{
## These run longer than 5 seconds
## CFA model
require(lavaan)

tempdir <- tempdir()
## The example from lavaan's docs
HS.model <- ' visual  =~ x1 + x2 + x3
              textual =~ x4 + x5 + x6
              speed   =~ x7 + x8 + x9'
fit1 <- cfa(HS.model, data = HolzingerSwineford1939,
            std.lv = TRUE, meanstructure = TRUE)
## Try a LaTeX file first
fit1.t1 <- semTable(fit1, columns = c("estse", "p"),
                    fits = c("chisq", "rmsea"), file = file.path(tempdir, "fit1.t1"),
                    varLabels = c("x1" = "hello"), type = "latex", print.results = FALSE)
## If you have a working version of pdflatex in your system path, 
if (interactive()) testtable("fit1.t1.tex", tempdir)
fit1.t1 <- semTable(fit1, columns = c("estse", "p"),
                    fits = c("chisq", "rmsea"), file = file.path(tempdir, "fit1.t1.html"),
                    varLabels = c("x1" = "hello"), type = "html", print.results = FALSE)
## Use file attribute to get full file name
browseURL(attr(fit1.t1, "file"))
## Try CSV output next
fit1.t1 <- semTable(fit1, columns = c("estse", "p"),
                    fits = c("chisq", "rmsea"), file = file.path(tempdir, "fit1.t1"),
                    varLabels = c("x1" = "hello"), type = "csv", print.results = FALSE)
## Go inspect this file with a spread sheet program:
attr(fit1.t1, "file")
## Now demonstrate variable labels
vl <- c(visual = "Visual", textual = "Textual", speed = "Speed",
       x1 = "V1", x2 = "V2", x3 = "V3")
fit1.t2 <- semTable(fit1, columns = c("est", "estse"),
                    fits = c("chisq", "rmsea"), file = file.path(tempdir, "fit1.t2"),
                    varLabels = vl)
if (interactive()) testtable("fit1.t2", tempdir)
## floating table
fit1.t3 <- semTable(fit1, columns = c("est", "estse"),
                    fits = c("chisq", "rmsea"), file = file.path(tempdir, "fit1.t3"),
                    varLabels = vl, table.float = TRUE,
                    caption = "Holzinger Swineford 1939",
                    label = "tab:hs1939")
if (interactive()) testtable("fit1.t3", tempdir)
fit1.t4 <- semTable(fit1, columns = c("est", "estse"),
                    fits = c("chisq", "rmsea"), file = file.path(tempdir, "fit1.t3"),
                    varLabels = vl, longtable = TRUE,
                    caption = "Holzinger Swineford 1939",
                    label = "tab:hs1939")
if (interactive()) testtable("fit1.t4", tempdir)
fit1.t5 <- semTable(fit1, fits = c("chisq", "rmsea"),
               columns = c("est", "se"), columnLabels = c(se = "S.E."),
               file = file.path(tempdir, "fit1.t5"))
if (interactive()) testtable("fit1.t5", tempdir)
fit1.t6 <- semTable(fit1, fits = c("chisq", "rmsea"),
               columns = c("estsestars"),
               columnLabels = c("estsestars" = "Est(SE)"),
               file = file.path(tempdir, "fit1.t6"))
if (interactive()) testtable("fit1.t6", tempdir)
vl <- c(x1 = "happy 1", x2 = "happy 2", x3 = "happy 3",
        visual = "Seeing", textual = "Thumb Texting")
fit1.t7 <- semTable(fit1, fits = c("chisq", "rmsea"),
               columns = c("eststars", "p"),
               columnLabels = c("eststars" = "Est(SE)"),
               file = file.path(tempdir, "fit1.t7"),
               varLabels = vl, longtable = TRUE, type = "latex")

if (interactive()) testtable("fit1.t7", tempdir)
# Change output format to csv
cat(markupConvert(attr(fit1.t7, "markedResults"), type = "csv"))

## 2 groups
fit1.g <- cfa(HS.model, data = HolzingerSwineford1939,
                        std.lv = TRUE, group = "school", estimator = "MLR")
fit1.gt1 <- semTable(fit1.g, columns = c("estsestars", "p"),
               columnLabels = c(estsestars = "Est w/stars", p = "p-value"),
               file = file.path(tempdir, "fit1.gt1"))
if (interactive()) testtable("fit1.gt1", tempdir)
## Now name particular group by name
fit1.gt2 <- semTable(fit1.g, columns = c("estsestars", "p"),
               columnLabels = c(estsestars = "Est w/stars", p = "p-value"),
               file = file.path(tempdir, "fit1.gt2"), groups = "Pasteur")
if (interactive()) testtable("fit1.gt2", tempdir)
## Name particular group by number
fit1.gt3 <- semTable(fit1.g, columns = c("estsestars", "p"),
               columnLabels = c(estsestars = "Est w/stars", p = "p-value"),
               file = file.path(tempdir, "fit1.gt3"), groups = 1)
if (interactive()) testtable("fit1.gt3", tempdir)

## Fit same model with standardization
fit1.std <- update(fit1, std.lv = TRUE, std.ov = TRUE, meanstructure = TRUE) 
## include 2 models in table request
fit1.t2 <- semTable(list("Ordinary" = fit1, "Standardized" = fit1.std),
                    file = file.path(tempdir, "fit1.2.1"))
semTable(list("Ordinary" = fit1, "Standardized" = fit1.std),
    columns = list("Ordinary" = c("est", "se"), "Standardized" = c("est")),
    columnLabels = c(est = "Est", se = "SE"), file = file.path(tempdir, "fit1.2.2"))
if (interactive()) testtable("fit1.2.2", tempdir)

fit1.t2 <- semTable(fit1, fits = c("chisq", "rmsea"), print.results = FALSE)
cat(fit1.t2)
fit1.t3 <- semTable(fit1, fits = c("chisq", "rmsea", "tli"),
               columns = c("est", "se"))

## Can create file with cat
cat(fit1.t3, file = file.path(tempdir, "fit1.t3.tex"))

## Basic SEM
regmodel1 <- 'visual  =~ x1 + x2 + x3 
             textual =~ x4 + x5 + x6
             speed   =~ x7 + x8 + x9
             visual ~ textual + speed
'

fit2 <- sem(regmodel1, data = HolzingerSwineford1939, std.lv = TRUE,
            meanstructure = TRUE)

fit2.std <- update(fit2, std.lv = TRUE, std.ov = TRUE, meanstructure = TRUE) 

fit2.t <- semTable(list("Ordinary" = fit2, "Standardized" = fit2.std), fits = "rmsea",
                   columns = list("Ordinary" = c("est", "se", "p"),
                                   "Standardized" = c("estsestars")),
                   columnLabels = c("est" = "Est", "se" = "Std.Err.", "p" = "p",
                                    "estsestars" = "Standardized Est."),
                   paramSets = c("loadings", "intercepts", "slopes", "latentcovariances"),
                   file = file.path(tempdir, "fit2.t1"), type = "latex")

if (interactive()) testtable("fit2.t1", tempdir)

# Change output format to csv
cat(markupConvert(attr(fit2.t, "markedResults"), type = "csv"))
cat(markupConvert(attr(fit2.t, "markedResults"), type = "html"))

fit2.t <- semTable(list("Ordinary" = fit2, "Standardized" = fit2.std),
              type = c("html"),
              file = file.path(tempdir, "fit2.t"),
              varLabels = c(x1 = "happy 1", x2 = "happy 2", x3 = "happy 3"),
              print.results = FALSE)

if (interactive()) browseURL(file.path(tempdir, "fit2.t.html"))


regmodel2 <- 'visual  =~ x1 + x2 + x3
              textual =~ x4 +  x6
              speed   =~  x8 + x9
              visual ~ textual 
'
fit3 <- sem(regmodel2, data = HolzingerSwineford1939, std.lv = TRUE,
            meanstructure = TRUE)

fit3.t1 <-  semTable(fit3, type = c("latex"),
                     columns = c("estsestars", "rsquare"), 
                     file = file.path(tempdir, "fit3.1"),
                     print.results = FALSE)

cat(fit3.t1)
if (interactive()) testtable("fit3.1", tempdir)

fit3.std <- update(fit2, std.lv = TRUE, std.ov = TRUE)

fit3.std.t1 <- semTable(list("Mod 1" = fit2, "Mod 1 std" = fit2.std, "Mod 2" = fit3,
              "Mod 3 std" = fit3.std), columns = c("estsestars"), type = "html",
               file = file.path(tempdir, "fit3.std.t1"), print.results = FALSE)
if(interactive()) browseURL(file.path(tempdir, "fit3.std.t1.html"))

fit3 <- sem(regmodel1, data = HolzingerSwineford1939, group = "school")
## if specify 2 types, get a list of them back
fit3.t1 <- semTable(fit3, type = "latex")
fit3.t2 <- semTable(fit3, columns = c("est", "se"),
                     columnLabels = c(est = "Est.", se = "S.E."))

fit3.t2 <- semTable(fit3, fits = c("chisq", "rmsea", "cfi"), print.results = FALSE)
cat(fit3.t2)

fit3.t2 <- semTable(fit3, columns = c("estsestars"),
            fits = c("chisq", "rmsea", "cfi"), type = "html",
            file = file.path(tempdir, "fit3.t2"))
if(interactive()) browseURL(file.path(tempdir, "fit3.t2.html"))
 
fit3.t2 <- semTable(fit3, fits = c("rmsea", "cfi"))

model <- "factor =~ .7*y1 + .7*y2 + .7*y3 + .7*y4
                 y1 | -1*t1 + 1*t2
                 y2 | -.5*t1 + 1*t2
                 y3 | -.2*t1 + 1*t2
                 y4 | -1*t1 + 1*t2"
dat <- simulateData(model, sample.nobs = 300)

testmodel <- "ExampleFactor =~ y1 + y2 + y3 + y4"

fit4 <- cfa(testmodel, data = dat, ordered = colnames(dat),
            std.lv = FALSE)

fit4.t1 <- semTable(fit4, paramSets = c("loadings", "thresholds",
    "residualvariances"), fits = c("tli", "chisq"),
    fitLabels = c(tli = "TLI", chisq = "chisq"), type = "html")

fit4.t2 <- semTable(fit4, fits = c("rmsea", "cfi", "chisq"),
              fitLabels = c(rmsea = "Root M.SQ.E.A", cfi = "CompFitIdx", chisq = "chisq"),
              type = "latex")

## Model 5 - Mediation model with equality constraints
model5 <-
    '
    # latent variable definitions
    ind60 =~ x1 + x2 + x3
    dem60 =~ y1 + e*y2 + d*y3 + y4
    dem65 =~ y5 + e*y6 + d*y7 + y8
    # regressions
    dem60 ~ a*ind60
    dem65 ~ c*ind60 + b*dem60
    # residual correlations
    y1 ~~ y5
    y2 ~~ y4 + y6
    y3 ~~ y7
    y4 ~~ y8
    y6 ~~ y8

    # indirect effect (a*b)
    ## := operator defines new parameters
    ab := a*b

    ## total effect
    total := c + (a*b)
    '

fit5 <- sem(model5, data=PoliticalDemocracy)
fit5boot <- sem(model5, data=PoliticalDemocracy, se = "bootstrap", bootstrap = 100)

fit5.t1 <- semTable(list("Democracy" = fit5), columns = c("estsestars", "rsquare"),
           file = file.path(tempdir, "fit5.1t"), type = "html",
           print.results = FALSE)
if(interactive()) browseURL(file.path(tempdir, "fit5.t1.html"))

## convert same object to LaTeX, save file, then test
cat(markupConvert(attr(fit5.t1, "markedResults"), type = "latex"),
         file = file.path(tempdir, "fit5.t1.tex"))
if (interactive()) testtable("fit5.t1", tempdir)

semTable(list("Democracy" = fit5, "Bootstrapped SE" = fit5boot),
         columns = c("estsestars", "rsquare"),
         file = file.path(tempdir, "fit5.2"), type = "latex",
         longtable = TRUE)

semTable(list("Democracy" = fit5, "Bootstrapped SE" = fit5boot),
         columns = c("estsestars", "rsquare"),
         paramSets = c("loadings", "slopes", "residualvariances", "constructed"),
         file = file.path(tempdir, "fit5.3"), type = "latex",
         longtable = TRUE)

## Model 5b - Revision of Model 5s
model5b <-
    '
    # Cut some indicators from the measurement model
    ind60 =~ x1 + x2 
    dem60 =~ y1 + e*y2 + d*y3 + y4
    dem65 =~ y5 + e*y6 + d*y7 
    # regressions
    dem60 ~ a*ind60
    dem65 ~ c*ind60 + b*dem60
    # cut out the residual correlations
    # indirect effect (a*b)
    ## := operator defines new parameters
    ab := a*b

    ## total effect
    total := c + (a*b)
    '

fit5b <- sem(model5b, data=PoliticalDemocracy, se = "bootstrap",
bootstrap = 100)
semTable(list("Model 5" = fit5boot, "Model 5b" = fit5b),
         columns = c("estsestars", "rsquare"),
         file = file.path(tempdir, "fit5.5"),
          type = "latex",
         longtable = TRUE)
if(interactive()) testtable("fit5.5", tempdir)

list.files(tempdir)
}
}
\author{
Ben Kite <bakite@ku.edu> Paul Johnson <pauljohn@ku.edu>
}
