Models fitted to a complex survey design with survey::svyglm() are supported. Declare the design, fit the model to it and pass the fit: the variance is the design-based one the fit carries, and the intervals and tests are referred to a t and an F on the degrees of freedom of the design, as survey itself reports them. The interaction is tested by the Rao-Scott working likelihood ratio test that survey::anova() takes over two nested fits, the ordinary likelihood ratio test having no meaning for a design-weighted pseudo-likelihood; test = "wald" gives the F test survey::regTermTest() reports. vcov and cluster are refused for such a fit, the clustering being part of the design. The counts beside the rows are the unweighted numbers of people in the sample, taken over the rows the fit gave weight to, so a design that was subset() counts the subset. The report names the standard errors as design-based, and the R code tab of foresty_app() writes the same test in survey's own terms.
A quasibinomial family with a logit link is read as an odds ratio, as a binomial one is. It was left as a coefficient, drawn about zero, though the report already called the model a logistic regression.
An F test of the interaction is written with both of its degrees of freedom, F = 8.93 on 1 and 113 df, in summary(), the HTML report and the app.
foresty_data(color = ) names a column of the data saying what color each row is drawn in, which is how a figure drawn from a table colors the rows it chooses rather than the ones a rule would have chosen. color_by in foresty_layout() works the color out from the labels, which it can do for a figure that came off a model and its levels; a table of estimates carries whatever the author put in it, so it says instead. The column holds either the colors themselves -- "red", "#B24745" -- or the names of categories, drawn in the layout's colors one color per name; which of the two it is, is read off the values rather than asked for again, and a column holding some of each is refused where it was named. The mark, its interval and the summary diamond are all drawn in it, the reference level of a categorical exposure stays hollow, and no legend is drawn, every row being labelled already.
First release. Published on CRAN on 2026-09-12.
foresty_app() provides a Shiny interface for interactively selecting exposures, modifiers, contrasts, colors, and plot layouts. Its R code tab writes the code twice over: the foresty calls that drew the figures, and the same estimates worked out in base R and the car package with nothing from this package in them -- the interaction term, the linear combination of the coefficients each subgroup estimate is, and the joint test beside it. For a multinomial fit that linear combination is a difference of blocks of coefficients, one block per equation, and the script writes that out too.foresty_data() draws the same figure -- the forest plot and the table of numbers beside it, aligned row for row, in any of the journal styles -- from estimates you already have: a data.frame, tibble or data.table with one row per row of the figure. It is the entry point for numbers that did not come out of a model this package can read: a meta-analysis, a table being redrawn from a paper, a model fitted by something else.glm(), lm(), survival models, and lme4 models, with robust and cluster-robust standard errors through sandwich.MASS::polr() and nominal outcomes through nnet::multinom(). A multinomial fit holds one equation per non-reference level of the outcome, so the figure carries one row per level. outcome_reference says which level they are all read against and outcome_reference_row draws that level as a row of its own. The interaction is tested jointly across the equations, so its p-value is a chunk test spending one degree of freedom for each coefficient the interaction added.822 vs 468 people and 125 vs 59 events, those being the groups its odds ratio was estimated from. A multinomial row, which compares two levels of the outcome, reads 637 vs 1,050 under the sizes and drops the events column, which would have repeated the first of them. foresty_layout(counts = "row") holds the row's own group alone, as before. The rows that compare no two groups of people -- a step along a continuous exposure, and the reference rows -- are unchanged.?foresty_main: they are taken over the rows the model was fitted to, so a complete case on the outcome, the exposure and the covariates. The figures whose rows compare two groups say which two under the plot in foresty_app() and under the table of estimates in foresty_report(), and say of a multinomial fit that the estimate did not come out of those two groups alone. The figure itself is unchanged, so the downloads are what they always were.summary(), as.data.frame(), broom::tidy(), broom::glance(), coef(), vcov(), predict(), formula(), and nobs() are supported for foresty results.