From e05a35f4a7172721e182919bcec2c8cfa4b9d29b Mon Sep 17 00:00:00 2001 From: kss2k Date: Tue, 17 Dec 2024 15:46:57 +0100 Subject: [PATCH] add test-examples --- DESCRIPTION | 4 +- NAMESPACE | 1 + man/plot_surface.Rd | 105 ++++++++++++++++++++++++++++++++ tests/testthat/test_lms.R | 1 + tests/testthat/test_qml.R | 3 +- vignettes/plot_interactions.Rmd | 36 +++++++++-- 6 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 man/plot_surface.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 1622f0a..30dce61 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -47,7 +47,7 @@ Description: . "Structural equation models of latent interactions: evaluation of alternative estimation strategies and indicator construction." Muthén, L.K. and Muthén, B.O. (1998-2017). - "'Mplus' User’s Guide. Eighth Edition." + "'Mplus' User’s Guide. Eighth Edition." . Rosseel Y (2012). . @@ -58,7 +58,7 @@ LazyData: true RoxygenNote: 7.3.2 LinkingTo: Rcpp, RcppArmadillo Imports: Rcpp, purrr, stringr, lavaan, rlang, MplusAutomation, nlme, dplyr, - mvnfast, stats, fastGHQuad, mvtnorm, ggplot2, parallel + mvnfast, stats, fastGHQuad, mvtnorm, ggplot2, parallel, plotly Depends: R (>= 3.5.0) URL: https://modsem.org diff --git a/NAMESPACE b/NAMESPACE index b406839..6198059 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -75,6 +75,7 @@ export(multiplyIndicatorsCpp) export(parameter_estimates) export(plot_interaction) export(plot_jn) +export(plot_surface) export(standardized_estimates) export(trace_path) export(var_interactions) diff --git a/man/plot_surface.Rd b/man/plot_surface.Rd new file mode 100644 index 0000000..cd230ee --- /dev/null +++ b/man/plot_surface.Rd @@ -0,0 +1,105 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plot_interaction.R +\name{plot_surface} +\alias{plot_surface} +\title{Plot Surface for Interaction Effects} +\usage{ +plot_surface( + x, + z, + y, + xz = NULL, + model, + min_x = -3, + max_x = 3, + min_z = -3, + max_z = 3, + detail = 0.01, + ... +) +} +\arguments{ +\item{x}{A character string specifying the name of the first predictor variable.} + +\item{z}{A character string specifying the name of the second predictor variable.} + +\item{y}{A character string specifying the name of the outcome variable.} + +\item{xz}{Optional. A character string or vector specifying the interaction term between `x` and `z`. +If `NULL`, the interaction term is constructed as `paste(x, z, sep = ":")` and adjusted for specific model classes.} + +\item{model}{A model object of class `'modsem_pi'`, `'modsem_da'`, `'modsem_mplus'`, or `'lavaan'`. The model should +include paths for the predictors (`x`, `z`, and `xz`) to the outcome (`y`).} + +\item{min_x}{Numeric. Minimum value of `x` in z-scores. Default is -3.} + +\item{max_x}{Numeric. Maximum value of `x` in z-scores. Default is 3.} + +\item{min_z}{Numeric. Minimum value of `z` in z-scores. Default is -3.} + +\item{max_z}{Numeric. Maximum value of `z` in z-scores. Default is 3.} + +\item{detail}{Numeric. Step size for the grid of `x` and `z` values, determining the resolution of the surface. +Smaller values increase plot resolution. Default is `1e-2`.} + +\item{...}{Additional arguments passed to `plotly::plot_ly`.} +} +\value{ +A `plotly` surface plot object displaying the predicted values of `y` across the grid of `x` and `z` values. + The color bar shows the values of `y`. +} +\description{ +Generates a 3D surface plot to visualize the interaction effect of two variables (`x` and `z`) on an outcome (`y`) +using parameter estimates from a supported model object (e.g., `lavaan` or `modsem`). +The function allows specifying ranges for `x` and `z` in standardized z-scores, which are then transformed +back to the original scale based on their means and standard deviations. +} +\details{ +The input `min_x`, `max_x`, `min_z`, and `max_z` define the range of `x` and `z` values in z-scores. +These are scaled by the standard deviations and shifted by the means of the respective variables, obtained +from the model parameter table. The resulting surface shows the predicted values of `y` over the grid of `x` and `z`. + +The function supports models of class `modsem` (with subclasses `modsem_pi`, `modsem_da`, `modsem_mplus`) and `lavaan`. +For `lavaan` models, it is not designed for multigroup models, and a warning will be issued if multiple groups are detected. +} +\note{ +The interaction term (`xz`) may need to be manually specified for some models. For non-`lavaan` models, +interaction terms may have their separator (`:`) removed based on circumstances. +} +\examples{ +\dontrun{ +m1 <- " +# Outer Model + X =~ x1 + X =~ x2 + x3 + Z =~ z1 + z2 + z3 + Y =~ y1 + y2 + y3 + +# Inner model + Y ~ X + Z + X:Z +" +est1 <- modsem(m1, data = oneInt) +plot_surface("X", "Z", "Y", model = est1) + +tpb <- " +# Outer Model (Based on Hagger et al., 2007) + ATT =~ att1 + att2 + att3 + att4 + att5 + SN =~ sn1 + sn2 + PBC =~ pbc1 + pbc2 + pbc3 + INT =~ int1 + int2 + int3 + BEH =~ b1 + b2 + +# Inner Model (Based on Steinmetz et al., 2011) + # Causal Relationsships + INT ~ ATT + SN + PBC + BEH ~ INT + PBC + # BEH ~ ATT:PBC + BEH ~ PBC:INT + # BEH ~ PBC:PBC +" + +est2 <- modsem(tpb, TPB, method = "lms") +plot_surface(x = "INT", z = "PBC", y = "BEH", model = est1) +} + +} diff --git a/tests/testthat/test_lms.R b/tests/testthat/test_lms.R index 9715499..c9d6cd2 100644 --- a/tests/testthat/test_lms.R +++ b/tests/testthat/test_lms.R @@ -17,6 +17,7 @@ est1 <- modsem(m1, oneInt, method = "lms", optimize = TRUE, verbose = TRUE, convergence = 1e-2, R.max = 50000) plot_interaction("X", "Z", "Y", "X:Z", -3:3, c(-0.5, 0.5), est1) print(summary(est1, adjusted.stat = TRUE)) +plot_surface(x = "X", z = "Z", y = "Y", model = est1) # PROBLEM: # I have no clue why, but changing the ordering of how the interaction terms diff --git a/tests/testthat/test_qml.R b/tests/testthat/test_qml.R index 07fdb36..97bcba7 100644 --- a/tests/testthat/test_qml.R +++ b/tests/testthat/test_qml.R @@ -12,7 +12,8 @@ est1 <- modsem(m1, data = oneInt, convergence = 1e-2, method = "qml", robust.se = TRUE) print(summary(est1, scientific = TRUE)) plot_interaction(x = "X", z = "Z", y = "Y", xz = "X:Z", vals_z = c(-0.5, 0.5), model = est1) -plot_surface(x = "X", z = "Z", y = "Y", model = est) +plot_surface(x = "X", z = "Z", y = "Y", model = est1) + tpb <- ' # Outer Model (Based on Hagger et al., 2007) diff --git a/vignettes/plot_interactions.Rmd b/vignettes/plot_interactions.Rmd index 9cbac53..4234662 100644 --- a/vignettes/plot_interactions.Rmd +++ b/vignettes/plot_interactions.Rmd @@ -43,7 +43,8 @@ m1 <- " Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) -plot_interaction("X", "Z", "Y", "X:Z", vals_z = -3:3, range_y = c(-0.2, 0), model = est1) +plot_interaction("X", "Z", "Y", "X:Z", vals_z = -3:3, + range_y = c(-0.2, 0), model = est1) ``` Here is a different example using the `lms` approach in the theory of planned behavior model: @@ -91,13 +92,12 @@ m1 <- ' visual ~ speed + textual + speed:textual ' -est <- modsem(m1, data = lavaan::HolzingerSwineford1939, method = "ca") -plot_jn(x = "speed", z = "textual", y = "visual", model = est, max_z = 6) +est1 <- modsem(m1, data = lavaan::HolzingerSwineford1939, method = "ca") +plot_jn(x = "speed", z = "textual", y = "visual", model = est1, max_z = 6) ``` Here is another example using the `qml` approach in the theory of planned behavior model: ```{r} - tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 @@ -113,7 +113,31 @@ tpb <- " " est2 <- modsem(tpb, TPB, method = "qml") -plot_jn(x = "INT", z = "PBC", y = "BEH", model = est2, - min_z = -1.5, max_z = -0.5) +plot_jn(x = "INT", z = "PBC", y = "BEH", model = est2, + min_z = -1.5, max_z = -0.5) ``` +# Plotting (3D) Surface Plots +The `plot_surface()` function can be used to plot 3D surface plots for a given interaction effect. +This function takes a fitted model object, the names of the two variables that are interacting, +and the name of the dependent variable. The function will plot the 3D surface plot for the interaction effect. + +```{r} +tpb <- " +# Outer Model (Based on Hagger et al., 2007) + ATT =~ att1 + att2 + att3 + att4 + att5 + SN =~ sn1 + sn2 + PBC =~ pbc1 + pbc2 + pbc3 + INT =~ int1 + int2 + int3 + BEH =~ b1 + b2 + +# Inner Model (Based on Steinmetz et al., 2011) + INT ~ ATT + SN + PBC + BEH ~ INT + PBC + BEH ~ PBC:INT +" + +est2 <- modsem(tpb, TPB, method = "qml") + +plot_surface(x = "X", z = "Z", y = "Y", model = est1) +```