Rendering Latex using MathJax in Shiny - r

I am trying to create a dynamic Shiny app that uses the yacas Computer Algebra System to process entered functions. As a first step, I want the UI to confirm what it understands has been typed in.
However, the following Shiny code is not displaying the entered function in Latex format.
library(shiny)
library(Ryacas) # for the TeXForm command
library(Ryacas0)
library(mathjaxr) # for rendering Latex expressions in Shiny
ui <- fluidPage(
sidebarPanel(
textInput(
inputId = "ui_function",
label = 'f(x) = ',
value = "x^2",
placeholder = "Enter function here"),
),
mainPanel(
uiOutput("entered")
)
)
server <- function(input, output) {
output$entered = renderUI({
withMathJax(
helpText(yac_str(paste0("TeXForm(",
input$ui_function,
")")
)
)
)
})
} # end server function
shinyApp(ui = ui, server = server)
When I remove the 'withMathJax' commands from the above code, it behaves exactly the same way, so it's as if the 'withMathJax' command is not having any effect on the output.
By way of a simple example, I'm looking for the user to enter 'x^2' and it should displays
x²
I welcome any help that anyone can offer.
I'm running this on latest RStudio 2022.02.1 Build 461, with R4.1.3, Shiny 1.7.1 and MathJax 1.6-0

You can do as follows:
library(shiny)
library(Ryacas) # for the TeXForm command
ui <- fluidPage(
sidebarPanel(
textInput(
inputId = "ui_function",
label = 'f(x) = ',
value = "x^2",
placeholder = "Enter function here"),
),
mainPanel(
helpblock(withMathJax(uiOutput("entered", inline = TRUE)))
)
)
server <- function(input, output) {
output$entered = renderUI({
paste0(
"\\(",
yac_str(paste0("TeXForm(", input$ui_function, ")")),
"\\)"
)
})
} # end server function
shinyApp(ui = ui, server = server)
The mathjaxr package is not for Shiny, it is used for help files (Rd).

Following on from Stephane's suggestion, I re-looked at my code and this version now works, as intended:
library(shiny)
library(Ryacas)
library(Ryacas0)
library(mathjaxr) # for rendering Latex expressions in Shiny
ui <- fluidPage(
sidebarPanel(
textInput(
inputId = "ui_function",
label = 'f(x) = ',
value = "x^2",
placeholder = "Enter function here"),
),
mainPanel(
withMathJax(uiOutput("entered"))
)
)
server <- function(input, output) {
output$entered = renderUI({
withMathJax(
helpText(
paste0(
"\\(",
yac_str(paste0("TeXForm(", input$ui_function, ")")),
"\\)"
)
)
)
})
} # end server function
shinyApp(ui = ui, server = server)
The inclusion of withMathJax inside mainPanel in the ui seemed to make the difference. It also seems that the "\\(" strings that are concatenated to the string inside the server are critical to its success.

Related

Cannot paste network path to list files

i've built an app that allow users to paste a folder path so that files inside that folder can be listed and selected. The app works when i set the path globally but i really need users to be able to stipulate their path. The path needs to be a network path as we use Azure/Databricks...
library(dplyr)
library(shinyWidgets)
library(shinythemes)
library(DT)
fpath <- '/dbfs/dbfs/Analytics/ShinyApp' #example path
# Define UI
ui <- fluidPage(
theme = shinytheme("spacelab"),
navbarPage(
"App",
tabPanel(
"Setup Project",
sidebarPanel(
textInput("v_inpath", "Specify File Path:", ""),
actionButton("Setpath", "Set Path"),
selectInput("selectfile", "Select File to Analyse",choice = list.files("ppath", pattern = ".csv")) #list of files should show up here
), # sidebarPanel
mainPanel(verbatimTextOutput("ppath")) # mainPanel
) #tabPanel
) # navbarPage
) # fluidPage
# Define server function
server <- function(input, output, session) {
observeEvent(input$Setpath,{
output$ppath <-reactive({paste0(input$v_inpath)})
})
} # server
# Create Shiny object
shinyApp(ui = ui, server = server)
In the mainPanel, i can see the path being pasted correctly as text (as you can see i'm using verbatimTextOutput("ppath")). The list of files contained in the specified folder should show up but it does not work as no list is available... Thank you in advance for your help
You need renderUI
You should avoid to put an output element inside an observer
You could use the shinyFiles package or the jsTreeR package to select the path
Code:
library(shiny)
# Define UI
ui <- fluidPage(
navbarPage(
"App",
tabPanel(
"Setup Project",
sidebarPanel(
textInput("v_inpath", "Specify File Path:", ""),
actionButton("Setpath", "Set Path"),
uiOutput("selectfileUI")
), # sidebarPanel
mainPanel(verbatimTextOutput("ppath")) # mainPanel
) #tabPanel
) # navbarPage
) # fluidPage
# Define server function
server <- function(input, output, session) {
output[["selectfileUI"]] <- renderUI({
req(input[["Setpath"]])
files <- list.files(input[["v_inpath"]], pattern = ".csv")
selectInput("selectfile", "Select File to Analyse", choices = files)
})
output[["ppath"]] <- renderPrint({
input[["v_inpath"]]
})
} # server
# Create Shiny object
shinyApp(ui = ui, server = server)
EDIT: feedback
Also, you can use the shinyFeedback package to print a message when the path is not valid:
library(shiny)
library(shinyFeedback)
# Define UI
ui <- fluidPage(
useShinyFeedback(), # don't forget this line
navbarPage(
"App",
tabPanel(
"Setup Project",
sidebarPanel(
textInput("v_inpath", "Specify File Path:", ""),
actionButton("Setpath", "Set Path"),
uiOutput("selectfileUI")
), # sidebarPanel
mainPanel(verbatimTextOutput("ppath")) # mainPanel
) #tabPanel
) # navbarPage
) # fluidPage
# Define server function
server <- function(input, output, session) {
Check <- eventReactive(input[["Setpath"]], {
dir.exists(input[["v_inpath"]])
})
Files <- reactive({
req(Check())
list.files(input[["v_inpath"]], pattern = ".csv")
})
observeEvent(input[["Setpath"]], {
hideFeedback("v_inpath")
show <- !Check() || length(Files()) == 0
if(show) {
if(Check()) {
text <- "No CSV file in this folder"
} else {
text <- "Invalid path"
}
showFeedbackWarning("v_inpath", text)
} else {
hideFeedback("v_inpath")
}
})
output[["selectfileUI"]] <- renderUI({
req(Files())
selectInput("selectfile", "Select File to Analyse", choices = Files())
})
output[["ppath"]] <- renderPrint({
input[["v_inpath"]]
})
} # server
# Create Shiny object
shinyApp(ui = ui, server = server)

How to have a user input text and create a list with shiny? R

I have the following app which allows for text to be entered and it is then saved as VALUE and printed on a panel.
Although it looks like I can only do this with one text input at a time - even if I click add (so I don't believe this button is working). On top of that I would like for the user to be able to add multiple inputs (like I have below).
And then my VALUE function should be list with multiple inputs.
code below
library(shiny)
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
# selectInput("options", "options", choices=c('abc','def')),
textInput("textbox", "Enter R Package Name", ""),
actionButton("add","Add")
),
mainPanel(
textOutput("caption")
)
)
server <- function(input, output, session) {
observe({
VALUE <- ''
if(input$add>0) {
isolate({
VALUE <- input$textbox
})
}
updateTextInput(session, inputId = "textbox", value = VALUE)
})
output$caption <- renderText({
input$textbox
})
}
shinyApp(ui = ui, server = server)
Have you considered using selectizeInput with it's create option?
library(shiny)
packagesDF <- as.data.frame(installed.packages())
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
selectizeInput(
inputId = "selectedPackages",
label = "Enter R Package Name",
choices = packagesDF$Package,
selected = NULL,
multiple = TRUE,
width = "100%",
options = list(
'plugins' = list('remove_button'),
'create' = TRUE,
'persist' = TRUE
)
)
),
mainPanel(textOutput("caption"))
)
server <- function(input, output, session) {
output$caption <- renderText({
paste0(input$selectedPackages, collapse = ", ")
})
}
shinyApp(ui = ui, server = server)

Call the UI of R built-in functions

I want to be able to design a set of UI that can call R's built-in functions, but the current problem lies in the data selection when calling the function. I need to return the calculation result of a function to my UI interface so that another function can be arbitrary Select the variables in the current environment as the input of the function. This is my current code. Can anyone give me some suggestions or some cases?
library(shiny)
function_choose = c("sin","cos")
ui <- fluidPage(
selectInput('f', 'function_choose', function_choose,
selected = function_choose[[1]]),
sidebarPanel(
conditionalPanel(condition = "input.f=='sin'",
mainPanel(
selectInput('sin_dat','data',c("I want to show all the variables in the workspace here ")),
actionButton(inputId = "sin_run",label = "RUN")
)
),
conditionalPanel(condition = "input.f=='cos'",
mainPanel(
selectInput('workspace','data',c("I want to show all the variables in the workspace here "))),
actionButton(inputId = "cos_run",label = "RUN")
)
),
mainPanel(
textOutput("text")
)
)
server <- function(input, output,session) {
data <- c(0.1,0.2,0.3)
observeEvent(input$sin_run,{
data_sined <- sin(data)
output$text <- renderText({
"data_sined is created"
})
})
observeEvent(input$cos_run,{
data_cosed<- cos(data)
output$text <- renderText({
"data_cosed is created"
})
})
}
shinyApp(ui = ui, server = server)
I changed the logic of your app to make it less complicated, I hope this is still ok for your purpose. We can use ls() to get a character vector of all variables in the global (or any other) environment. If we define a vector function_choose in the global environment, then this will be available too. We could easily circumvent this by defining the choices argument inside selectInput or by specifying a names pattern that is selected by ls(). Once we have selected a variable, the input$data returns a character vector. To access the underyling data based on a character vector we use get().
library(shiny)
function_choose = c("sin","cos")
shinyApp(
ui = fluidPage(
sidebarPanel(
selectInput('f', 'function_choose', choices = function_choose,
selected = function_choose[1]),
selectInput('data','data', choices = ls()),
actionButton(inputId = "run",label = "RUN")
),
mainPanel(
textOutput("text")
)
),
server = function(input, output,session) {
res <- eventReactive(input$run, {
dat <- get(input$data)
switch(input$f,
sin = sin(dat),
cos = cos(dat)
)
})
output$text <- renderText({
res()
})
})

How can I solve this bug in R shiny?

i want to run an r shiny app using the typical command runApp(). I made sure that i am in the correct working directory and that the shiny package is loaded. when running the app, i get this error message here:
Error in p(class = "text-right", textOutput(outputId = "callsCount")) :
unused argument (class = "text-right")```
What can i do to solve that error ?
Thanks
This is the closest I got at reproducing your error:
library(shiny)
ui <- fluidPage(
br(),
uiOutput(outputId = "myUI")
)
server <- function(input, output, session) {
p <- reactive(3)
output$myUI <- renderUI({
p(class = "text-right", textOutput(outputId = "callsCount"))
})
}
shinyApp(ui, server)
Warning: Error in p: unused arguments (class = "text-right", textOutput(outputId = "callsCount"))
There are two fixes you need to make:
fix1:
It seems you have a reactive expression named p. Change it's name to something else. An alternative is to specify explicitly from which environment shiny should get the function p():
output$myUI <- renderUI({
shiny::p(class = "text-right", textOutput(outputId = "callsCount"))
})
fix2:
Replace textOutput(outputId = "callsCount") with the text you want to render.
For example:
output$myUI <- renderUI({
shiny::p(class = "text-right", "This is the text to render")
})
final ui and server:
library(shiny)
ui <- fluidPage(
br(),
uiOutput(outputId = "myUI")
)
server <- function(input, output, session) {
p <- reactive(3)
output$myUI <- renderUI({
shiny::p(class = "text-right", "This is the text to render")
})
}
shinyApp(ui, server)

Not able to remove input using removeUI

I have two inputs to be removed from the ui.R
fileInput(inputId = "FileInput",label = "Choose a csv file",accept = '.csv'),
uiOutput("SKU")
Inside server i am using an observeEvent to remove these 2 inputs and insert one. Though the insertUi is working I am not able to remove the other 2.
PFB the code:
observeEvent(input$Save,{
removeUI(
selector = "div:has(> #FileInput)"
)
insertUI(
selector = "#Save",
where = "afterEnd",
ui =fluidPage(
tags$hr(),
fluidRow(column(offset=0,1,actionButton("clean","Start cleaning the Data")))
)
)
})
It seems you have to treat it the same way in which the shiny blog example treats text by wrapping it in a div with id.
tags$div(
fileInput(inputId = "FileInput",label = "Choose a csv file",accept = '.csv'),
id='FileInput'
)
Example
ui <- fluidPage(
mainPanel(
tags$div(fileInput('element1','Input file...'),id='element1'),
actionButton('remove','Remove File Input')
)
)
server <- function(input, output) {
observeEvent(input$remove,{
removeUI(selector = '#element1')
})
}
shinyApp(ui = ui, server = server)

Resources