Closed lf-araujo closed 2 years ago
nice!
So to make this work in umx, you would want to set a class for the model, right above call to xmu_safe_run_summary
# set class so that S3s dispatch e.g. umxSummary, plot
model = as(model, "MxModelDoC2")
And copy a umxSummary
method, and set it to this new class
#' @aliases umxSummary.MxModelDoC2
Now it will try and dispatch on your neat new DoC model.
At the simplest level, you could simply bury a call to print(summary()) in the normal model.
To do what the other umxSummary models do - i.e a more customised output, you need to process all your custom matrices and algebras like SPh
in the ways you want to show the user.
Same with plot: Need to copy an existing umxPlot function, recluse it, and then rework the internals to find the cells that correspond to circles and boxes and paths in your model, loop through the model assembling those into a graphviz description of edges and nodes, and print it using DiagrammeR
Cool!
In brief, for non RAM models, you. Have to write a model specific umxSummary function to do what you want with it (I.e there no generic way to know which matrices mean what etc). So umx has umxSummaryACE CP DoC etc
They get called using R’s object methods because I also set a unique type for each model, so the generic unxSummary methods dispatches to the right owner. And that falls back to RAM, which is why you get the error you got.
Same sorry for plot (which would be nice to implement for DoC
You might have a look at some of the umxSummary* functions (search the package code) and get back to me if you have questions?
You could copy one that seems close, and change the .suffix to .MxModelDoC2
Thanks, I will look into this soon, as we are working to apply the model to real data. I spent some time trying understanding S3 and S4, there were some concepts that went above my head. These are not similar to methods in other languages.
S3 is pretty simple, and I would ignore S4.
S3 calls the right version of a function by looking at the class of the first parameter.
Setting the class is as simple as model = as(model, "MxModelDoC2")
then when you say plot(model)
, R will look for a function called plot.MxModelDoC2()
and call that for you.
So you also need to write those umxSummary.MxModelDoC2
and plot.MxModelDoC2
functions.
Thanks,
I am ready to tackle this. It seems I just need to make small modifications to the umxSummary general function. The issue I face currently is in the line (fit_and_reporting.R):
parameterTable = mxStandardizeRAMpaths(model, SE = SE) # Compute standard errors
As I don't follow that typical RAM matrix structure, see code below. How you suggest is the easiest way of getting the list of parameters in this case?
Hi coef() is a handy way to get the list of free parameters from an mxModel.
Cheers Mike
great to see!
A couple of things. For summary, I sketch out the table/plot I want, and work backward to populate that from the model (which is usually just walking over the matrices grabbing the (small for DOC2) set of parameters you want.
But, your model code already generates a small summary: Perhaps pull that into a umxSummary.MxModelDOC2
function and then iterate?
FYI, umx contains no hadleyverse/pipe style code. It's also unsafe to rely on T being TRUE.
Most umx summary models are non-RAM. Look in those to borrow some useful patterns. It those also show how to use umx helpers like umxPrint
Here's a stub summary with roxygen that might work?
#' Present the results of a Direction of Causation Model in table and graphical form
#'
#' Summarizes a Direction of Causation model, as returned by [umxDOC2()]
#'
#' @aliases umxSummary.MxModelDOC2
#' @param model A fitted [umxDOC2()] model to summarize
#' @param digits Round to how many digits (default = 2)
#' @param std Whether to show the standardized model (TRUE) (ignored: used extended = TRUE to get unstandardized)
#' @param CIs Confidence intervals (default FALSE)
#' @param comparison Run mxCompare on a comparison model (default NULL)
#' @param report Print tables to the console (as 'markdown'), or open in browser ('html')
#' @param file The name of the dot file to write: NA = none; "name" = use the name of the model
#' @param ... Optional additional parameters
#' @return - nothing
#' @export
#' @family Summary functions
#' @seealso - \code{\link{umxCP}()}, [plot()], [umxSummary()] work for IP, CP, GxE, SAT, and ACE models.
#' @md
#' @examples
#' # examples here
umxSummary.MxModelDOC2 <- function(model, digits = 2, std = TRUE, CIs = FALSE, comparison = NULL, report = c("markdown", "html"), file = getOption("umx_auto_plot"), ...) {
if (CIs){ model = umxCI(model, run = "if necessary")}
model_summary = summary(model, refModels = mxRefModels(model, run = TRUE))
if (CIs == TRUE) {
model_summary$parameters |>
left_join(model_summary$CI, by = c("Estimate" = "estimate")) |>
select(1,5:6,11:12) |>
kable(digits = 3, caption = "Parameter estimates") |>
print()
} else {
model_summary$parameters |> select(1,5:8) |> kable(digits = 3) |> print()
}
model_summary[c("fit", "numObs","degreesOfFreedom", "AIC.Mx", "BIC.Mx", "CFI", "TLI", "optimizerEngine", "RMSEA", "RMSEACI")] |> as_tibble() |> mutate(lower = RMSEACI[1], upper = RMSEACI[2]) |>
select(-RMSEACI) |> slice(-2) |> t() |>
kable(col.names="", format = "simple", digits = 3, capion = "Model fit") |>
print()
Thanks,
This is exactly what I needed to start on it! Will remove the pipes and try to get as close as I can to usual umx summary output. Best, Luis
#' Present the results of a Direction of Causation Model in table and graphical form
#'
#' Summarizes a Direction of Causation model, as returned by [umxDOC2()]
#'
#' @aliases umxSummary.MxModelDOC2
#' @param model A fitted [umxDOC2()] model to summarize
#' @param digits Round to how many digits (default = 2)
#' @param std Whether to show the standardized model (TRUE) (ignored: used extended = TRUE to get unstandardized)
#' @param CIs Confidence intervals (default FALSE)
#' @param comparison Run mxCompare on a comparison model (default NULL)
#' @param report Print tables to the console (as 'markdown'), or open in browser ('html')
#' @param file The name of the dot file to write: NA = none; "name" = use the name of the model
#' @param ... Optional additional parameters
#' @return - nothing
#' @export
#' @family Summary functions
#' @seealso - \code{\link{umxCP}()}, [plot()], [umxSummary()] work for IP, CP, GxE, SAT, and ACE models.
#' @md
#' @examples
#' # examples here
umxSummary.MxModelDOC2 <- function(model, digits = 2, std = TRUE, CIs = FALSE, comparison = NULL, report = c("markdown", "html"), file = getOption("umx_auto_plot"), ...) {
if (CIs){ model = umxCI(model, run = "if necessary")}
model_summary = summary(model, refModels = mxRefModels(model, run = TRUE))
if (CIs == TRUE) {
tmp = left_join(model_summary$parameters, model_summary$CI, by = c("Estimate" = "estimate"))
tmp = tmp[, c(1, 5:6, 11:12))
} else {
tmp = model_summary$parameters
tmp[, c(1, 5:8))
}
umx_print(tmp, digits = digits, zero.print = ".", report =report, caption = "Parameter estimates")
tmp = model_summary[c("fit", "numObs","degreesOfFreedom", "AIC.Mx", "BIC.Mx", "CFI", "TLI", "optimizerEngine", "RMSEA", "RMSEACI")]
tmp = as_tibble(tmp)
tmp = mutate(tmp, lower = RMSEACI[1], upper = RMSEACI[2])
tmp = select(tmp, -RMSEACI)
tmp = tmp[-2, ]
umx_print(tmp, digits = digits, zero.print = ".", report =report, caption = "Model fit")
}
Just fyi for your umxDOC2
model function, umx has support for human-friendly tryHard options, and also uses xmu_safe_run_summary
to give error-safe execution (copes with models that fail, supports no-summary mode for simulations).
your_function(tryHard = c( "yes", "no", "ordinal", "search"), summary = !umx_set_silent(silent = TRUE) ){
tryHard = match.arg(tryHard)
model = xmu_safe_run_summary(model, autoRun = TRUE, summary = summary, tryHard = tryHard)
}
Thanks! This was all very useful, and I think I got it!
But still struggling with umx_make(). Asking it for tests did not return errors, but when I try to install the package with the changes it complains of not being able to install srcdir
:
> umx_make("~/R/x86_64-solus-linux-gnu-library/4.1/umx",what= "quick_install")
ℹ Updating umx documentation
Warning: Version of roxygen2 last used with this package is 7.1.2. You only have version 7.1.1
ℹ Loading umx
Writing NAMESPACE
Running /usr/lib64/R/bin/R CMD INSTALL \
/home/luis/R/x86_64-solus-linux-gnu-library/4.1/umx --install-tests \
--no-docs --no-multiarch --no-demo
* installing to library ‘/home/luis/R/x86_64-solus-linux-gnu-library/4.1’
ERROR: cannot install to srcdir for package ‘umx’
* removing ‘/home/luis/R/x86_64-solus-linux-gnu-library/4.1/umx’
Error in (function (command = NULL, args = character(), error_on_status = TRUE, :
System command 'R' failed, exit status: 1, stdout & stderr were printed
Type .Last.error.trace to see where the error occurred
In addition: Warning messages:
1: S3 methods ‘RMSEA.MxModel’, ‘RMSEA.summary.mxmodel’, ‘extractAIC.MxModel’, ‘loadings.MxModel’, ‘loadings.default’, ‘plot.MxLISRELModel’, ‘plot.MxModel’, ‘plot.MxModelACE’, ‘plot.MxModelACEco
v’, ‘plot.MxModelACEv’, ‘plot.MxModelCP’, ‘plot.MxModelDoC’, ‘plot.MxModelGxE’, ‘plot.MxModelGxEbiv’, ‘plot.MxModelIP’, ‘plot.MxModelSexLim’, ‘plot.MxModelSimplex’, ‘plot.MxModelTwinMaker’, ‘pl
ot.MxRAMModel’, ‘plot.percent’, ‘print.RMSEA’, ‘print.money’, ‘print.oddsratio’, ‘print.percent’, ‘print.reliability’, ‘residuals.MxModel’, ‘tmx_show.MxMatrix’, ‘tmx_show.MxModel’, ‘umxReduce.M
xModelACE’, ‘umxReduce.MxModelGxE’, ‘umxReduce.default’, ‘umxRotate.MxModelCP’, ‘umxRotate.default’, ‘umxSummary.MxModel’, ‘umxSummary.MxModelACE’, ‘umxSummary.MxModelACEcov’, ‘umxSummary.MxMod
elACEv’, ‘umxSummary.MxModelCP’, ‘umxSummary.MxModelDoC’, ‘umxSummary.MxM [... truncated]
2: In setup_ns_exports(path, export_all, export_imports) :
Objects listed as exports, but not present in namespace: FishersMethod, RMSEA, SE_from_p, bucks, deg2rad, dl_from_dropbox, fin_NI, fin_interest, fin_percent, fin_valuation, geometric_mean, ha
rmonic_mean, install.OpenMx, libs, loadings, namez, noNAs, oddsratio, parameters, power.ACE.test, qm, rad2deg, reliability, summaryAPA, tmx_genotypic_effect, tmx_is.identified, tmx_show, tvars,
umx2ord, umxACE, umxACEcov, umxACEv, umxAPA, umxAlgebra, umxBrownie, umxCI, umxCI_boot, umxCP, umxCompare, umxConfint, umxCov2cor, umxDiagnose, umxDoC, umxDoCp, umxEFA, umxEquate, umxExamples,
umxExpCov, umxExpMeans, umxFactanal, umxFactor, umxFactorScores, umxFitIndices, umxFixAll, umxGetLatents, umxGetManifests, umxGetModel, umxGetParameters, umxGxE, umxGxE_window, umxGxEbiv, umxH
etCor, umxIP, umxJiggle, umxLav2RAM, umxMI, umxMR, umxMatrix, umxModel, umxModelNames, umxModify, umxParameters, umxPath, umxPlotACE, umxPlotACEcov, umxPlotACEv, umxPlotCP, umxPlotDoC, umxPlotF
un, umxPlotGxE, umxPlotGxEbiv, umxPlo [... truncated]
Nevermind, too dumb to figure out that I should have passed the umx folder I was working in! LOL.
Ok, so the function is done, together with a nice umxSummary report. Very useful to learn how S3 works, thanks for the help! No test unit in this PR, although I run the tests and the changes did not introduce new problems it seems.
Thanks again!
Looks like a permission problems in srcdir?
Yes, I figured out what I was doing incorrectly. Also, forgot to link the PR https://github.com/tbates/umx/pull/211
I should add a link to this when umx_make() is called with a bad directory :-)
But probably should also make the users preferred directory sticky with a preference setting. It's hard because most people don't use R startup scripts which are as far as I can tell the only place to store customisable stuff like that.
Maybe if the error says Call umx_set_umx_loc("~/my/path/to/umx" to store location of your umx development directory
Dear Tim,
We have recently put out a DoC variation that allows bidirectional causality and full confounding here and I wanted to see if I could make a umx wrapper for it.
It works partially, but it does not conform to what umxSummary expects to provide a pretty print out.
You can find data to test in this gist
and a MWE: