Skip to content

Commit

Permalink
* IMPROVED: umxPlotIP now relies on matrix cells, not the labels th…
Browse files Browse the repository at this point in the history
…ey contain

FYI: old plotIP function stored as xmuOldPlotIP

closes #61
  • Loading branch information
tbates committed Oct 15, 2020
1 parent 2235f70 commit 1a21eef
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 148 deletions.
1 change: 0 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ export(umxPlotDoC)
export(umxPlotGxE)
export(umxPlotGxEbiv)
export(umxPlotIP)
export(umxPlotIP2)
export(umxPlotSexLim)
export(umxPlotSimplex)
export(umxPower)
Expand Down
115 changes: 50 additions & 65 deletions R/fit_and_reporting.R
Original file line number Diff line number Diff line change
Expand Up @@ -2875,6 +2875,12 @@ plot.MxModelCP <- umxPlotCP
#' @md
#' @examples
#' \dontrun{
#' require(umx)
#' data(GFF)
#' mzData = subset(GFF, zyg_2grp == "MZ")
#' dzData = subset(GFF, zyg_2grp == "DZ")
#' selDVs = c("gff","fc","qol","hap","sat","AD") # These will be expanded into "gff_T1" "gff_T2" etc.
#' m1 = umxIP(selDVs = selDVs, sep = "_T", dzData = dzData, mzData = mzData)
#' plot(model)
#' umxPlotIP(model, file = NA)
#' }
Expand All @@ -2886,66 +2892,47 @@ umxPlotIP <- function(x = NA, file = "name", digits = 2, means = FALSE, std = TR
if(std){
model = xmu_standardize_IP(model)
}
# TODO Check I am handling nFac > 1 properly!!
nVar = dim(model$top$ai$values)[[1]]

# 1. get vars from rows of as matrix
nFac = dim(model$top$ai$labels)[[2]] # added! (but won't work, right? can have different numbers of a c, e )
nVar = dim(model$top$as$values)[[1]]
selDVs = dimnames(model$MZ$data$observed)[[2]]
selDVs = selDVs[1:(nVar)]
selDVs = sub("(_T)?[0-9]$", "", selDVs) # trim "_Tn" from end

parameterKeyList = omxGetParameters(model, free = TRUE);
cSpecifics = c();
latents = c()
out = "";
for(thisParam in names(parameterKeyList) ) {
if( grepl("^[ace]i_r[0-9]", thisParam)) {
# top level a c e
# "ai_r1c1" note: c1 = factor1, r1 = variable 1
grepStr = '^([ace]i)_r([0-9]+)c([0-9]+)'
from = sub(grepStr, '\\1_\\3', thisParam, perl = TRUE);
targetindex = as.numeric(sub(grepStr, '\\2', thisParam, perl=T));
target = selDVs[as.numeric(targetindex)]
latents = append(latents, from);
} else if (grepl("^[ace]s_r[0-9]", thisParam)) { # specific
grepStr = '([ace]s)_r([0-9]+)c([0-9]+)'
from = sub(grepStr, '\\1\\3', thisParam, perl = T);
targetindex = as.numeric(sub(grepStr, '\\2', thisParam, perl = T));
target = selDVs[as.numeric(targetindex)]
cSpecifics = append(cSpecifics,from);
latents = append(latents,from);
} else if (grepl("^expMean", thisParam)) { # means probably "expMean_gff_T1" (was "expMean_r1c1")
grepStr = '^expMean_(.*_T1)'
from = "one";
target = sub(grepStr, '\\1', thisParam, perl = TRUE)
if(means){
latents = append(latents, from)
}
} else if (grepl("_dev[0-9]+$", thisParam)) { # probably a threshold
# grepStr = '^expMean_(.*_T1)'
# from = "one";
# target = sub(grepStr, '\\1', thisParam, perl = TRUE)
# if(means){
# latents = append(latents, from)
# }
} else {
message("While making the plot, I found a path labeled ", thisParam, "I don't know where that goes.\n",
"If you are using umxModify to make newLabels, instead of making up a new label, use, say, the first label in update as the newLabel to help plot()")
}

# look for CIs if they exist...
if(!means & from == "one"){
# not adding means...
} else {
# look for standardized values to replace the raw ones...
# TODO std ==?
CIstr = xmu_get_CI(model, label = thisParam, prefix = "top.", suffix = "_std", digits = digits, SEstyle = SEstyle, verbose = FALSE)
if(is.na(CIstr)){
val = round(parameterKeyList[thisParam], digits)
}else{
val = CIstr
}
out = paste0(out, ";\n", from, " -> ", target, " [label=\"", val, "\"]")
}
out = list(str = "", latents = c(), manifests = c())

# TODO Check I am handling nFac > 1 properly!!

# from = <name><rowNum>; target = common<colNum>; latents = append(latents, from)
# out = list(str = "", latents = c(), manifests = c())

# 1. Collect ai (the independent latent factors)
out = xmu_dot_mat2dot(model$top$ai, cells = "any", from = "cols", fromType = "latent", toLabel = selDVs, showFixed = showFixed, p = out)
out = xmu_dot_mat2dot(model$top$ci, cells = "any", from = "cols", fromType = "latent", toLabel = selDVs, showFixed = showFixed, p = out)
out = xmu_dot_mat2dot(model$top$ei, cells = "any", from = "cols", fromType = "latent", toLabel = selDVs, showFixed = showFixed, p = out)

# 2 collect as (the specific latent factors)
out = xmu_dot_mat2dot(model$top$as, cells = "diag", toLabel = selDVs, from = "rows", fromType = "latent", showFixed = showFixed, p = out)
out = xmu_dot_mat2dot(model$top$cs, cells = "diag", toLabel = selDVs, from = "rows", fromType = "latent", showFixed = showFixed, p = out)
out = xmu_dot_mat2dot(model$top$es, cells = "diag", toLabel = selDVs, from = "rows", fromType = "latent", showFixed = showFixed, p = out)


# Process "expMean" 1 * nVar matrix e.g. "expMean_gff_T1"
if(means){
out = xmu_dot_mat2dot(model$top$expMean, cells = "left", toLabel = selDVs, from = "rows", fromLabel = "one", fromType = "latent", showFixed = showFixed, p = out)
}

# TODO: Could extract thresholds? "_dev[0-9]+$"

# TODO Add CIs to parameter values
# this code picks out the CIs if available... Now would need to be embedded in xmu_dot_mat2dot() now?
# CIstr = xmu_get_CI(model, label = thisParam, prefix = "top.", suffix = "_std", digits = digits, SEstyle = SEstyle, verbose = FALSE)
# CIstr = xmu_get_CI(model= tmp, label = "S[1,1]", prefix = "Holzinger_and_Swineford_1939.", SEstyle = TRUE, digits = 3)

# ==============
# = up to here =
# ==============

preOut = "\t# Latents\n"
latents = unique(latents)
Expand All @@ -2956,23 +2943,21 @@ umxPlotIP <- function(x = NA, file = "name", digits = 2, means = FALSE, std = TR
preOut = paste0(preOut, "\t", var, " [shape = circle];\n")
}
}
preOut = paste0(preOut, "\n\t# Manifests\n")
for(n in c(1:nVar)) {
preOut = paste0(preOut, "\n", selDVs[n], " [shape=square];\n")
}

ranks = paste(cSpecifics, collapse = "; ");
ranks = paste0("{rank=sink; ", ranks, "}");
preOut = xmu_dot_define_shapes(latents = out$latents, manifests = selDVs[1:nVar])
top = xmu_dot_rank(out$latents, "^[ace]i", "min")
bottom = xmu_dot_rank(out$latents, "^[ace]s", "max")

label = model$name
splines = "FALSE"

digraph = paste0(
"digraph G {\n\t",
'label="', label, '";\n\t',
"splines = \"", splines, "\";\n",
preOut,
ranks,
out, "\n}"
preOut,
top,
bottom,
out$str, "\n}"
)

if(format != "current"){ umx_set_plot_format(format) }
Expand Down
82 changes: 0 additions & 82 deletions R/umx new ip PLot.r

This file was deleted.

132 changes: 132 additions & 0 deletions R/xmuOldPlotIP.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#' Draw a graphical figure for a Independent Pathway model
#'
#' Options include digits (rounding), showing means or not, standardization, and which output format is desired.
#'
#' @param x The [umxIP()] model to plot
#' @param file The name of the dot file to write: NA = none; "name" = use the name of the model
#' @param digits How many decimals to include in path loadings (defaults to 2)
#' @param means Whether to show means paths (defaults to FALSE)
#' @param std Whether to standardize the model (defaults to TRUE)
#' @param format = c("current", "graphviz", "DiagrammeR")
#' @param SEstyle Report "b (se)" instead of "b \[lower, upper\]" (Default)
#' @param strip_zero Whether to strip the leading "0" and decimal point from parameter estimates (default = TRUE)
#' @param ... Optional additional parameters
#' @return - optionally return the dot code
#' @seealso - [plot()], [umxSummary()] work for IP, CP, GxE, SAT, and ACE models.
#' @seealso - [umxIP()]
#' @family umx deprecated
#' @references - <https://tbates.github.io>
#' @md
#' @examples
#' \dontrun{
#' require(umx)
#' data(GFF)
#' mzData = subset(GFF, zyg_2grp == "MZ")
#' dzData = subset(GFF, zyg_2grp == "DZ")
#' selDVs = c("gff","fc","qol","hap","sat","AD") # These will be expanded into "gff_T1" "gff_T2" etc.
#' m1 = umxIP(selDVs = selDVs, sep = "_T", dzData = dzData, mzData = mzData)
#' xmuOldPlotIP(model, file = NA)
#' }
xmuOldPlotIP <- function(x = NA, file = "name", digits = 2, means = FALSE, std = TRUE, format = c("current", "graphviz", "DiagrammeR"), SEstyle = FALSE, strip_zero = TRUE, ...) {
format = match.arg(format)
model = x # Just to emphasise that x has to be a model
umx_check_model(model, "MxModelIP", callingFn = "umxPlotIP")

if(std){
model = xmu_standardize_IP(model)
}
# TODO Check I am handling nFac > 1 properly!!
nVar = dim(model$top$ai$values)[[1]]
selDVs = dimnames(model$MZ$data$observed)[[2]]
selDVs = selDVs[1:(nVar)]
selDVs = sub("(_T)?[0-9]$", "", selDVs) # trim "_Tn" from end

parameterKeyList = omxGetParameters(model, free = TRUE);
cSpecifics = c();
latents = c()
out = "";
for(thisParam in names(parameterKeyList) ) {
if( grepl("^[ace]i_r[0-9]", thisParam)) {
# top level a c e
# "ai_r1c1" note: c1 = factor1, r1 = variable 1
grepStr = '^([ace]i)_r([0-9]+)c([0-9]+)'
from = sub(grepStr, '\\1_\\3', thisParam, perl = TRUE);
targetindex = as.numeric(sub(grepStr, '\\2', thisParam, perl=T));
target = selDVs[as.numeric(targetindex)]
latents = append(latents, from);
} else if (grepl("^[ace]s_r[0-9]", thisParam)) { # specific
grepStr = '([ace]s)_r([0-9]+)c([0-9]+)'
from = sub(grepStr, '\\1\\3', thisParam, perl = T);
targetindex = as.numeric(sub(grepStr, '\\2', thisParam, perl = T));
target = selDVs[as.numeric(targetindex)]
cSpecifics = append(cSpecifics,from);
latents = append(latents,from);
} else if (grepl("^expMean", thisParam)) { # means probably "expMean_gff_T1" (was "expMean_r1c1")
grepStr = '^expMean_(.*_T1)'
from = "one";
target = sub(grepStr, '\\1', thisParam, perl = TRUE)
if(means){
latents = append(latents, from)
}
} else if (grepl("_dev[0-9]+$", thisParam)) { # probably a threshold
# grepStr = '^expMean_(.*_T1)'
# from = "one";
# target = sub(grepStr, '\\1', thisParam, perl = TRUE)
# if(means){
# latents = append(latents, from)
# }
} else {
message("While making the plot, I found a path labeled ", thisParam, "I don't know where that goes.\n",
"If you are using umxModify to make newLabels, instead of making up a new label, use, say, the first label in update as the newLabel to help plot()")
}

# look for CIs if they exist...
if(!means & from == "one"){
# not adding means...
} else {
# look for standardized values to replace the raw ones...
# TODO std ==?
CIstr = xmu_get_CI(model, label = thisParam, prefix = "top.", suffix = "_std", digits = digits, SEstyle = SEstyle, verbose = FALSE)
if(is.na(CIstr)){
val = round(parameterKeyList[thisParam], digits)
}else{
val = CIstr
}
out = paste0(out, ";\n", from, " -> ", target, " [label=\"", val, "\"]")
}
}

preOut = "\t# Latents\n"
latents = unique(latents)
for(var in latents) {
if(var == "one"){
preOut = paste0(preOut, "\t", var, " [shape = triangle];\n")
} else {
preOut = paste0(preOut, "\t", var, " [shape = circle];\n")
}
}
preOut = paste0(preOut, "\n\t# Manifests\n")
for(n in c(1:nVar)) {
preOut = paste0(preOut, "\n", selDVs[n], " [shape=square];\n")
}

ranks = paste(cSpecifics, collapse = "; ");
ranks = paste0("{rank=sink; ", ranks, "}");

label = model$name
splines = "FALSE"
digraph = paste0(
"digraph G {\n\t",
'label="', label, '";\n\t',
"splines = \"", splines, "\";\n",
preOut,
ranks,
out, "\n}"
)

if(format != "current"){ umx_set_plot_format(format) }
xmu_dot_maker(model, file, digraph, strip_zero = strip_zero)

}


4 changes: 4 additions & 0 deletions man/umx-deprecated.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions man/umxPlotIP.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1a21eef

Please sign in to comment.