@@ -102,9 +102,17 @@ doeAnalysis <- function(jaspResults, dataset, options, ...) {
102102
103103 .doeAnalysisCheckErrors(dataset , options , continuousPredictors , discretePredictors , blocks , covariates , dependent , ready )
104104
105- # Create containers for response variable(s)
106- for (dep in dependent ) {
107- jaspResults [[dep ]] <- createJaspContainer(title = dep )
105+ # Create containers for response variable(s). Persist across invocations so
106+ # display-only option changes (e.g. plot CI width) do not wipe the cached
107+ # model fit. Low position keeps model output above the factorial plots (12).
108+ for (depIdx in seq_along(dependent )) {
109+ dep <- dependent [[depIdx ]]
110+ if (is.null(jaspResults [[dep ]])) {
111+ modelContainer <- createJaspContainer(title = dep )
112+ modelContainer $ dependOn(options = .doeAnalysisBaseDependencies())
113+ modelContainer $ position <- depIdx
114+ jaspResults [[dep ]] <- modelContainer
115+ }
108116 }
109117
110118 p <- try(.doeAnalysisMakeState(jaspResults , dataset , options , continuousPredictors , discretePredictors , blocks , covariates , dependent , stepwiseMethod , ready ))
@@ -187,6 +195,10 @@ doeAnalysis <- function(jaspResults, dataset, options, ...) {
187195 }
188196
189197 for (dep in dependent ) {
198+ # Skip refit when the cached fit survived (base deps unchanged)
199+ if (! is.null(jaspResults [[dep ]][[" doeResult" ]]))
200+ next
201+
190202 currentDependent <- dep
191203
192204 result <- list ()
@@ -1524,7 +1536,7 @@ get_levels <- function(var, num_levels, dataset) {
15241536
15251537.doeAnalysisAnovaTable <- function (jaspResults , dependent , options , ready , coded ) {
15261538 for (dep in dependent ) {
1527- if (! is.null(jaspResults [[" tableAnova" ]])) {
1539+ if (! is.null(jaspResults [[dep ]][[ " tableAnova" ]])) {
15281540 return ()
15291541 }
15301542
@@ -2157,35 +2169,34 @@ get_levels <- function(var, num_levels, dataset) {
21572169}
21582170
21592171.doeAnalysisPlotFactorialPlots <- function (jaspResults , dependent , options , ready ) {
2160- if (( ! options [[" mainEffectsPlot" ]] && ! options [[" interactionPlot" ]]) || ! is.null( jaspResults [[ " factorialPlots " ]]) ) {
2172+ if (! options [[" mainEffectsPlot" ]] && ! options [[" interactionPlot" ]]) {
21612173 return ()
21622174 }
21632175
2164- container <- createJaspContainer(title = gettext(" Factorial Plots" ))
2165- container $ dependOn(options = c(" mainEffectsPlot" , " mainEffectsPlotCi" , " mainEffectsPlotCiLevel" ,
2166- " interactionPlot" , " interactionPlotCi" , " interactionPlotCiLevel" ,
2167- .doeAnalysisBaseDependencies()))
2168- container $ position <- 12
2169- jaspResults [[" factorialPlots" ]] <- container
2170-
2171- # Create one child container per dependent outcome.
2172- for (depIdx in seq_along(dependent )) {
2173- dep <- dependent [[depIdx ]]
2176+ # Nest a Factorial Plots container inside each response container.
2177+ for (dep in dependent ) {
2178+ if (! is.null(jaspResults [[dep ]][[" factorialPlots" ]])) {
2179+ next
2180+ }
21742181
2175- depContainer <- createJaspContainer(title = dep )
2176- depContainer $ position <- depIdx
2177- container [[dep ]] <- depContainer
2182+ container <- createJaspContainer(title = gettext(" Factorial Plots" ))
2183+ # Parent response container already carries the base (model) dependencies;
2184+ # only the plot-specific options need to invalidate this sub-container.
2185+ container $ dependOn(options = c(" mainEffectsPlot" , " mainEffectsPlotCi" , " mainEffectsPlotCiLevel" ,
2186+ " interactionPlot" , " interactionPlotCi" , " interactionPlotCiLevel" ))
2187+ container $ position <- 13
2188+ jaspResults [[dep ]][[" factorialPlots" ]] <- container
21782189
21792190 if (! ready || is.null(jaspResults [[dep ]][[" doeResult" ]]) || jaspResults [[dep ]]$ getError()) {
21802191 next
21812192 }
21822193
21832194 if (options [[" mainEffectsPlot" ]]) {
2184- .doeAnalysisPlotMainEffectsSubplots(depContainer , dep , options , jaspResults , ready )
2195+ .doeAnalysisPlotMainEffectsSubplots(container , dep , options , jaspResults , ready )
21852196 }
21862197
21872198 if (options [[" interactionPlot" ]]) {
2188- .doeAnalysisPlotInteractionEffectsSubplots(depContainer , dep , options , jaspResults , ready )
2199+ .doeAnalysisPlotInteractionEffectsSubplots(container , dep , options , jaspResults , ready )
21892200 }
21902201 }
21912202}
@@ -2384,7 +2395,17 @@ get_levels <- function(var, num_levels, dataset) {
23842395 emm
23852396 }
23862397
2387- p <- ggplot2 :: ggplot(emm , ggplot2 :: aes(x = x , y = emmean , color = trace , group = trace )) +
2398+ hasCi <- includeCi && all(c(" lower.CL" , " upper.CL" ) %in% names(emm ))
2399+
2400+ p <- ggplot2 :: ggplot(emm , ggplot2 :: aes(x = x , y = emmean , color = trace , group = trace ))
2401+
2402+ # Continuous x: faded confidence bands drawn underneath the traces
2403+ if (hasCi && xFactorType == " continuous" ) {
2404+ p <- p + ggplot2 :: geom_ribbon(ggplot2 :: aes(ymin = lower.CL , ymax = upper.CL , fill = trace ),
2405+ alpha = 0.3 , color = NA , show.legend = FALSE )
2406+ }
2407+
2408+ p <- p +
23882409 ggplot2 :: geom_line(linewidth = 0.95 ) +
23892410 ggplot2 :: geom_point(data = emmForPoints , shape = 21 , ggplot2 :: aes(fill = trace ), size = 3.2 , stroke = 0.2 ) +
23902411 ggplot2 :: scale_y_continuous(name = dep , expand = ggplot2 :: expansion(mult = c(0.15 , 0.15 ))) +
@@ -2399,7 +2420,8 @@ get_levels <- function(var, num_levels, dataset) {
23992420 p <- p + ggplot2 :: scale_x_discrete(name = factorA , expand = ggplot2 :: expansion(add = c(0.5 , 0.5 )))
24002421 }
24012422
2402- if (includeCi && all(c(" lower.CL" , " upper.CL" ) %in% names(emm ))) {
2423+ # Discrete x: error bars at each level
2424+ if (hasCi && xFactorType != " continuous" ) {
24032425 p <- p + ggplot2 :: geom_errorbar(ggplot2 :: aes(ymin = lower.CL , ymax = upper.CL ), width = 0.25 , linewidth = 0.6 )
24042426 }
24052427
0 commit comments