writing `render*()` and `*Output()` functions for UI output

I am the author of the equatiomatic R package. I would like to write and export renderEq() and eqOutput() functions to make it easier to use with Shiny. Unfortunately, I can't figure it out. The below works for a basic shiny app.

library(shiny)
library(shinyWidgets)
library(ggplot2)
library(equatiomatic)
library(gtsummary)
library(gt)

ui <- fluidPage(
  titlePanel("equatiomatic w/Shiny"),
  sidebarLayout(
    sidebarPanel(
      multiInput(
        inputId = "xvars", label = "Select predictor variables :",
        choices = names(mpg)[-8],
        selected = "displ"
      )
    ),
    
    mainPanel(
      uiOutput("eq"),
      gt_output("tbl")
    )
  )
)

server <- function(input, output) {
  
  model <- reactive({
    form <- paste("hwy ~ ", paste(input$xvars, collapse = " + "))
    lm(as.formula(form), mpg)
  })
  
  output$eq <- renderUI(
    withMathJax(
      helpText(
        equatiomatic:::format.equation(
          extract_eq(model(), wrap = TRUE, terms_per_line = 3)
        )
      )
    )
  )
  
  output$tbl <- render_gt({
    as_gt(tbl_regression(model()))
  })
  
}

shinyApp(ui = ui, server = server)

I'd really like to simplify this so the Ui part is just eqOutput("eq") and the server part is something like

output$eq <- renderEq(
  extract_eq(model(), wrap = TRUE, terms_per_line = 3)
)

I know of htmlwidgets::shinyWidgetOutput() but that doesn't seem to help in this case because I'm trying to modify a UI element.

Any help would be greatly appreciated.

2 Likes

Cross-posted here.

I think this is a great question, as there seems to be a lack of educational content / tutorials in this area.
From what I gather ' Shiny - Implement render functions — createRenderFunction (rstudio.com)' seems to be a key element.

1 Like

Thanks @nirgrahamuk! I wasn’t aware of that function so I’ll play around with it some and see if I can get anything to work.

Hi,

If you look at render_gt from gt, or renderText, and renderTable from shiny you can see a general pattern with
installExprFunction to install expr as a function in the env and then
createRenderFunction to process the value

In your example, everything is already processed thanks to withMathJax(helpText(equatiomatic:::format.equation(x)))

So if you use dedicated functions installExprFunction and createRenderFunction and combine it with the transform you use you can create your own rendering function,

library(shiny)
library(shinyWidgets)
library(ggplot2)
library(equatiomatic)
library(gtsummary)
library(gt)

renderEq <- function(expr, env = parent.frame(), quoted = FALSE, outputArgs = list()) {
  shiny::installExprFunction(expr = expr, name = "func", eval.env = env, quoted = quoted)
  shiny::createRenderFunction(func = func, function(value, session, name, ...) {
    as.character(withMathJax(helpText(equatiomatic:::format.equation(x = value))))
  }, eqOutput, outputArgs)
}

eqOutput <- function(outputId) {
  shiny::htmlOutput(outputId = outputId)
}

ui <- fluidPage(
  titlePanel("equatiomatic w/Shiny"),
  sidebarLayout(
    sidebarPanel(
      multiInput(
        inputId = "xvars", label = "Select predictor variables :",
        choices = names(mpg)[-8],
        selected = "displ"
      )
    ),
    mainPanel(
      eqOutput("eq_new"),
      uiOutput("eq"),
      gt_output("tbl")
    )
  )
)

server <- function(input, output) {
  model <- reactive({
    form <- paste("hwy ~ ", paste(input$xvars, collapse = " + "))
    lm(as.formula(form), mpg)
  })
  
  output$eq_new <- renderEq(expr = extract_eq(model(), wrap = TRUE, terms_per_line = 3))
  output$eq <- renderUI(
    withMathJax(
      helpText(
        equatiomatic:::format.equation(
          extract_eq(model(), wrap = TRUE, terms_per_line = 3)
        )
      )
    )
  )
  
  output$tbl <- render_gt({
    as_gt(tbl_regression(model()))
  })
  
}

shinyApp(ui = ui, server = server)

However, it still remains kind of a glitch where the equation is displayed but not correctly formatted ....

1 Like

Thank you so much! Do you mind elaborating on the equation not be being formatted correctly? At least on my end it looks perfect! I'm on a mac and tested it on safari, chrome, and brave (a bit redundant with chrome but... :man_shrugging:).

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.