Pablo Cervantes
Pablo Cervantes

Reputation: 13

in shiny, How to insert math symbols in a text input so that my r code performs the equations?

I have built a shiny app in which my inputs only recognize numeric values. For example, in the text box I insert 2^7 and it doesn´t perform the procedure in my function from the R code. On the other hand if I insert 128 it does perform the procedure.

library(shiny)
library(shinythemes)
library(shinydashboard)
library(stringr)
library(ggplot2)     

ui = navbarPage(

  theme = shinytheme("superhero"),
  title = "Generador de Numeros Aleatorios",
         tabPanel(title = h5("Generadores"),

sidebarPanel(
  selectInput("metodo", "Selecciona el m?todo",
              selected= "Multiplicativo",
              choices = c("Multiplicativo","Lineal","SimuladorR")
  ),
  textInput("z0","Ingresa una semilla:",value = 3),
  texticInput("n","Ingresa 'n':",value=10),
  textInput("a","Ingresa 'a':",value=2),
  textInput("m","Ingresa 'm':", value=15),
  textInput("c","Ingresa 'c':",value=10),
  actionButton("generador", label = "Generar"),
  br(),
  radioButtons("type", "Formato de descarga:",
               choices=c("Excel(CVS)", "Text(TSV)"),selected = "Excel(CVS)", inline=T),
  helpText("Click en el boton de Exportar para descragar los datos."),
  downloadButton('downloaddata','Exportar')

  #downloadButton("exportador", label = "Exportar")
  #actionButton("exportador", label = "Exportar"),
  #br(),
  #helpText("Click en el boton de Exportar para descargar los datos"),

), #Cierra sidebarPanel


mainPanel(
  h5("Valores Generados:"),
  plotOutput("grafica"),
  tableOutput("tablaValores")
) #Cierra mainPanel

   ),   

server = function(input, output,session){



 ## Generador Multiplicativo
  Congruencial.Multiplicativo = function(z0,a,m,n){
   z<-c()
   u<-c()
   z[1]<-z0
   u[1]<-z[1]/m

   if(n>1){
     for (i in 1:n+1) {
       z[i]<-(a*z[i-1]) - floor((a*z[i-1])/m)*m
     }

     for(i in 1:n+1){
       u[i]<-z[i]/m
     }

   }

   return(u[-1])
  }

  ## Generador Lineal
  Congruencial.Lineal<-function(z0,m,a,c,n){
    z=c()
    k=c()
    u=c()

    z[1]=z0
    k[1]=floor(((a*z[1])+c)/m)


    for(i in seq(2,n+1,by=1)){

      z[i]=((a*z[i-1])+c)-(m*k[i-1])
      k[i]=floor(((a*z[i])+c)/m)
      u[i]=z[i]/m

      }

      return(u[-1])
  }

   ## Generador de R
    Simulador.R = function(n){
      r<-runif(n=n,min=0,max=1)
      return(r)
     }

   ### Ahora para mostrar los valores guardados:
   observeEvent(input$generador, { 


    output$grafica = renderPlot ({

      datos = valores()
      datos = as.data.frame(datos)

     ggplot(datos)+geom_histogram(aes(x=datos,y=..density..),
                               breaks=seq(0, 1, .01),closed="left",
                               color="white", fill="orange")+
       labs(title="Funcion de Densidad",
            x=" x ", 
            y = "Densidad"
        )+theme_bw()+
        scale_x_continuous(breaks =seq(0, 1, 0.1))+
        scale_y_continuous(breaks =seq(0, 1, 0.1))+
        stat_function(fun=dunif,xlim=c(-.5,1.5),size=1,color="red",
                  args =list(min=0, max=1) )

    })

   valores = reactive({ switch (input$metodo, 
   Multiplicativo = 
   Congruencial.Multiplicativo(input$z0,input$a,input$m,input$n),
   Lineal = Congruencial.Lineal(input$z0,input$m,input$a,input$c,input$n),
   SimuladorR = Simulador.R(input$n) )})   #Cierra valores


   numord = valores() #Llamamos los valores aleatorios generados
   mostrar = as.data.frame(cbind(seq(1,input$n,by=1),numord))
   colnames(mostrar)=c("i", "u")
   output$tablaValores = renderTable(mostrar)

  }) #Cierra observeEvent

Now this is part of the code in which I need the text input to be recognized as numeric so that the app can work. The values I need the app to read as a string and turn them into numeric are z0, n, m, c. I have tried to put them into the observe event and neither they work.

The app creates a series of semirandom values with generators, that need some entry values which are specified in the paragraph above.

Upvotes: 0

Views: 1338

Answers (2)

Ben
Ben

Reputation: 30474

Here is a demo that might be helpful. You can input a character string, and then use eval(parse(text = ... to evaluate the expression.

library(shiny)

ui <- fluidPage(
  textInput("ti_math", "Enter formula:"),
  textOutput("to_result")
)

server <- function(input, output, session) {
  output$to_result <- renderText({
    eval(parse(text = input$ti_math))
  })
}

shinyApp(ui, server)

Disclaimer: while this should work, the assumption is that the app will be running locally. Using eval on user input can be a security risk. See this post for more information.

Edit: Thank you for providing additional code. I was not able to reproduce completely (missing valores()) but I think I can make a couple suggestions.

For z0, n, m, c, you can access the inputs through input$z0, etc.

Try this:

observeEvent(input$generador, { 
  z0 = eval(parse(text = input$z0))
  print(z0)
})

You should see in your console, that if you provide something like 3^4 for z0 it should show 81 and be numeric.

You could do the same for n, m, c - I'm guessing you might be accessing these variables in valores() or other reactive expression.

I also noticed you have output$grafica and output$tablaValores inside of your observeEvent - I would recommend moving them out of observeEvent. One strategy is to use something <- eventReactive(input$generador, {... and then call something() from plot and table outputs.

Edit: Thank you for providing valores(). I can now provide something more reproducible.

I included eval(parse(text = input$...)) for z0, n, a, m, c. This is inside valores() so that all functions using these values for calculations will be evaluated for mathematical symbols first.

Note that I moved the renderTable and renderPlot from observeEvent, and changed observeEvent to eventReactive which will be responsive to the action button.

I also changed ui and server to separate components, and then call shinyApp in the end (just a preference).

This does provide a table and plot when button pressed. Please let me know if this is closer.

library(shiny)
library(shinythemes)
library(shinydashboard)
library(stringr)
library(ggplot2)     

ui = navbarPage(
  
  theme = shinytheme("superhero"),
  title = "Generador de Numeros Aleatorios",
  tabPanel(title = h5("Generadores"),
           
           sidebarPanel(
             selectInput("metodo", "Selecciona el m?todo",
                         selected= "Multiplicativo",
                         choices = c("Multiplicativo","Lineal","SimuladorR")
             ),
             textInput("z0","Ingresa una semilla:",value = 3),
             textInput("n","Ingresa 'n':",value=10),
             textInput("a","Ingresa 'a':",value=2),
             textInput("m","Ingresa 'm':", value=15),
             textInput("c","Ingresa 'c':",value=10),
             actionButton("generador", label = "Generar"),
             br(),
             radioButtons("type", "Formato de descarga:",
                          choices=c("Excel(CVS)", "Text(TSV)"),selected = "Excel(CVS)", inline=T),
             helpText("Click en el boton de Exportar para descragar los datos."),
             downloadButton('downloaddata','Exportar')
             
             #downloadButton("exportador", label = "Exportar")
             #actionButton("exportador", label = "Exportar"),
             #br(),
             #helpText("Click en el boton de Exportar para descargar los datos"),
             
           ), #Cierra sidebarPanel
           
           
           mainPanel(
             h5("Valores Generados:"),
             plotOutput("grafica"),
             tableOutput("tablaValores")
           ) #Cierra mainPanel
           
  )
)

server = function(input, output,session){
    
    ## Generador Multiplicativo
    Congruencial.Multiplicativo = function(z0,a,m,n){

      z<-c()
      u<-c()
      z[1]<-z0
      u[1]<-z[1]/m
      
      if(n>1){
        for (i in 1:n+1) {
          z[i]<-(a*z[i-1]) - floor((a*z[i-1])/m)*m
        }
        
        for(i in 1:n+1){
          u[i]<-z[i]/m
        }
        
      }
      
      return(u[-1])
    }
    
    ## Generador Lineal
    Congruencial.Lineal<-function(z0,m,a,c,n){
      z=c()
      k=c()
      u=c()
      
      z[1]=z0
      k[1]=floor(((a*z[1])+c)/m)
      
      
      for(i in seq(2,n+1,by=1)){
        
        z[i]=((a*z[i-1])+c)-(m*k[i-1])
        k[i]=floor(((a*z[i])+c)/m)
        u[i]=z[i]/m
        
      }
      
      return(u[-1])
    }
    
    ## Generador de R
    Simulador.R = function(n){
      r<-runif(n=n,min=0,max=1)
      return(r)
    }
    
    valores = eventReactive(input$generador, { 
      
      z0 = eval(parse(text = input$z0))
      a = eval(parse(text = input$a))
      m = eval(parse(text = input$m))
      c = eval(parse(text = input$c))
      n = eval(parse(text = input$n))
      
      switch  (input$metodo, 
               Multiplicativo = Congruencial.Multiplicativo(z0,a,m,n),
               Lineal = Congruencial.Lineal(z0,m,a,c,n),
               SimuladorR = Simulador.R(n)
      )
    })   #Cierra valores
    
    output$tablaValores = renderTable({
      numord = valores() #Llamamos los valores aleatorios generados
      mostrar = as.data.frame(cbind(seq(1,input$n,by=1),numord))
      colnames(mostrar)=c("i", "u")
      mostrar
    })
    
    output$grafica = renderPlot ({
      
      datos = valores()
      datos = as.data.frame(datos)
      
      ggplot(datos)+geom_histogram(aes(x=datos,y=..density..),
                                   breaks=seq(0, 1, .01),closed="left",
                                   color="white", fill="orange")+
        labs(title="Funcion de Densidad",
             x=" x ", 
             y = "Densidad"
        )+theme_bw()+
        scale_x_continuous(breaks =seq(0, 1, 0.1))+
        scale_y_continuous(breaks =seq(0, 1, 0.1))+
        stat_function(fun=dunif,xlim=c(-.5,1.5),size=1,color="red",
                      args =list(min=0, max=1) )
      
    })
}
    
shinyApp(ui, server)

Upvotes: 1

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84529

eval(text = parse(......)) works fine but it is dangerous. You can turn any string to an evaluated R command with this way, for example a command which deletes some files...

Since the strings you enter are mathematical expressions, you can use the Ryacas package to evaluate them. Ryacas will fail if the string is not a mathematical expression.

library(Ryacas)
.......

valores = eventReactive(input$generador, { 

  z0 = as.numeric(yac_str(sprintf("N(%s)", input$z0)))
  a = as.numeric(yac_str(sprintf("N(%s)", input$a)))
  m = as.numeric(yac_str(sprintf("N(%s)", input$m)))
  c = as.numeric(yac_str(sprintf("N(%s)", input$c)))
  n = as.numeric(yac_str(sprintf("N(%s)", input$n)))
  ......

Upvotes: 2

Related Questions