Вызвать функцию при вызове сервера RShiny и отобразить результат как вывод на печать - PullRequest
0 голосов
/ 20 марта 2020

Я написал скрипт, который использует 2 функции для расчета продолжительности, необходимой для запуска теста, например, анализ мощности.

Входы и код следующим образом:

## RUN POWER CALCULATION
average_daily_traffic <-  3515/30
control <- 0.47
uplift <- 0.02
num_vars <- 2 

sample_size_calculator <- function(control, uplift){
  variant <- (uplift + 1) * control
  baseline <- ES.h(control, variant)
  sample_size_output <- pwr.p.test(h = baseline,
                                   n = ,
                                   sig.level = 0.05,
                                   power = 0.8)
  if(variant >= 0)
  {return(sample_size_output)}
  else
  {paste("N/A")}
}


## RUN DAYS CALCULATOR FUNCTION 
days_calculator <- function(sample_size_output, average_daily_traffic){
  days_required <- c((sample_size_output)*num_vars)/(average_daily_traffic)
  if(days_required >= 0)
  {paste0("It will take ", round(days_required, digits = 0)*num_vars, " days for this test to reach significance, with a daily average of " , round(average_daily_traffic, digits = 0), " visitors to this page over a 30 day period.")}
  else
  {paste("N/A")}
}


## RUN FUNCTIONS AND OUTPUT ANSWER
sample_size_calculator <- sample_size_calculator(control, uplift)
sample_size_output <-   sample_size_calculator$n

answer <- days_calculator(sample_size_output, average_daily_traffic)
answer

Этот код является быстродействующим и подходит для моей цели в автономном сценарии R.

Однако мне нужно сделать эти функции исполняемыми из приложения Shiny. Моя попытка заключается в следующем:

library(shiny)

ui <- fluidPage(

  actionButton("exe", "Run", 
               style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),



  mainPanel(

    textOutput("answer")

  ))


server <- function(input, output, session) {

  sample_size_calculator <- eventReactive(input$exe,{

    average_daily_traffic <-  3515/30
    control <- 0.47
    uplift <- 0.02
    num_vars <- 2 

    variant <- (uplift + 1) * control
    baseline <- ES.h(control, variant)
    sample_size_output <- pwr.p.test(h = baseline,
                                     n = ,
                                     sig.level = 0.05,
                                     power = 0.8)
    if(variant >= 0)
    {return(sample_size_output)}
    else
    {paste("N/A")}

  })

  days_calculator <- eventReactive  (input$exe,{
    days_required <- c((sample_size_output)*num_vars)/(average_daily_traffic)
    if(days_required >= 0)
    {paste0("It will take approximately ", round(days_required, digits = 0)*num_vars, " days or ", round((round(days_required, digits = 0)*num_vars)/365, digits = 1) ," years for this test to reach significance, based on a daily average of " , round(average_daily_traffic, digits = 0), " users to this page in the last 30 days.")}
    else
    {paste("N/A")}
  })

  outputs_ <- eventReactive( input$exe, {
    req(sample_size_calculator())
    req(days_calculator())
  sample_size_calculator <- sample_size_calculator(control, uplift)
  sample_size_output <-   sample_size_calculator$n


  answer <- days_calculator(sample_size_output, average_daily_traffic)

  output$answer <- renderText(outputs_$answer) 

})

}


shinyApp(ui = ui, server = server)

Когда я запускаю этот код, я вижу кнопку выполнения, но вывод не отображается. Это очень вероятно из-за ограничения в моем понимании того, как Shiny вызывает функции, поэтому, если есть лучший способ, я был бы очень рад услышать это.

Заранее спасибо.

* РЕДАКТИРОВАНИЕ ДЛЯ ВКЛЮЧЕНИЯ ПОЛНОГО ФУНКЦИОНАЛЬНОГО КОДА *

Цель кода - использовать googleAnalyticsR и googleAuthR Марка Эдмонсона, чтобы включить поиск данных о посещении веб-сайта для определенного URL / страницы из аккаунта Google Analytics для последние 30 дней и показывают тенденцию этих данных. Это работает нормально, когда пользователь вводит URL и нажимает «Выполнить».

Существует дополнительный вызов GA, который извлекает дополнительные данные для конкретного действия преобразования (см. other_data). Это необходимо для того, чтобы получить коэффициент конверсии, который будет использован позже при расчете мощности.

Расчет равен cvr <- aeng$users/totalusers

#options(shiny.port = 1221)


## REQUIRED LIBS 
library(shiny)
library(googleAnalyticsR)
library(plotly)
library(googleAuthR)
library(markdown)
library(pwr)

gar_set_client(scopes = c("https://www.googleapis.com/auth/analytics.readonly"))

daterange <- function(x) {
  as.Date(format(x, "%Y-%m-01"))
}

## DATE PARAMETERS 
date_start <- as.Date(Sys.Date(),format='%d-%B-%Y')-31
date_end <- as.Date(Sys.Date(),format='%d-%B-%Y')-1
date_range <- c(date_start, date_end) 



## UI SECTION
ui <- fluidPage(
  googleAuth_jsUI("auth"),

  tags$head(
    tags$link(rel = "stylesheet", type = "text/css", href = "dur_calc.css")
  ),




  tags$br(),
  sidebarLayout(
    sidebarPanel(
      code("To begin, select from 'Accounts' and enter URL of page to be tested:"),
      tags$p(),

      column(width = 12, authDropdownUI("auth_dropdown", 
                                        inColumns = FALSE)),



            textInput("url", label = h5(strong("Page to be tested")), value = "Enter full page URL..."),

      hr(),
      fluidRow(column(3, verbatimTextOutput("value")
      )


      ),


      actionButton("exe", "Run Calculator", 
                   style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),


    ),



    mainPanel(
      plotlyOutput("trend_plot"),

      textOutput("page"),

      textOutput("answer")

    )


  )
)




## SERVER SECTION

server <- function(input, output, session) {

  auth <- callModule(googleAuth_js, "auth")



  ## GET GA ACCOUNTS 
  ga_accounts <- reactive({
    req(auth()
    )

    with_shiny(
      ga_account_list,
      shiny_access_token = auth()
    )

  })



  view_id <- callModule(authDropdown, "auth_dropdown", 
                        ga.table = ga_accounts)



  ga_data <- eventReactive( input$exe, {
    x <- input$url

    #reactive expression

    output$page <- renderText({ 
      paste("You have selected the page:", input$url) })



    filterPageurl <- dim_filter("dimension97" , "REGEX", x ,not = FALSE)
    filts <- filter_clause_ga4(list( filterPageurl))

    req(view_id())
    req(date_range)

    with_shiny(
      google_analytics,
      view_id(),
      date_range = date_range, 
      dimensions = "date",
      metrics = "users",
      dim_filters = filts,
      max = -1,
      shiny_access_token = auth()
    )



  })

  other_data <- eventReactive( input$exe, {
    x <- input$url


    filterPageurl <- dim_filter("dimension97" , "REGEX", x ,not = FALSE)
    filts <- filter_clause_ga4(list( filterPageurl))

    seg_id <- "gaid::uzKGvjpFS_Oa2IRh6m3ACg" #AEUs
    seg_obj <- segment_ga4("AEUs", segment_id = seg_id)

    req(view_id())
    req(date_range)
    #req(filts)

    with_shiny(
      google_analytics,
      view_id(),
      date_range = date_range, 
      dimensions = "date",
      metrics = "users",
      dim_filters = filts,
      segments = seg_obj, 
      max = -1,
      shiny_access_token = auth()
    )



})


  outputly <- eventReactive( input$exe, {

  req(other_data())
  req(ga_data())

  aeng <- other_data()
  ga_data <- ga_data()


  totalusers <<- sum(ga_data$users)
  cvr <- aeng$users/totalusers


  average_daily_traffic <-  totalusers/30
  control <- cvr
  uplift <- 0.02
  num_vars <- 2 
  })


  sample_size_calculator <- eventReactive(input$exe,{
    variant <- (uplift + 1) * control
    baseline <- ES.h(control, variant)
    sample_size_output <- pwr.p.test(h = baseline,
                                     n = ,
                                     sig.level = 0.05,
                                     power = 0.8)
    if(variant >= 0)
    {return(sample_size_output)}
    else
    {paste("N/A")}

  })


  days_calculator <- eventReactive  (input$exe,{
    days_required <- c((sample_size_output)*num_vars)/(average_daily_traffic)
    if(days_required >= 0)
    {paste0("It will take approximately ", round(days_required, digits = 0)*num_vars, " days or ", round((round(days_required, digits = 0)*num_vars)/365, digits = 1) ," years for this test to reach significance, based on a daily average of " , round(average_daily_traffic, digits = 0), " users to this page in the last 30 days.")}
    else
    {paste("N/A")}
  })


  output$trend_plot <- renderPlotly({
    req(ga_data())
    ga_data <- ga_data()

    plot_ly(
      x = ga_data$date,
      y = ga_data$users, 
      type = 'scatter',
      mode = 'lines') %>%

      layout(title = "Page Visitors by Day (last 30 days)",
             xaxis=list(title="Date", tickformat='%Y-%m-%d', showgrid=FALSE, showline=TRUE),
             yaxis=list(title = "Users", showgrid=FALSE, showline=TRUE)

      )


  })



  calc_answer <- eventReactive(input$exe, {

    req(outputly)
    outputly <- outputly()

    sample_size_calculator <- sample_size_calculator()
    sample_size_output <- sample_size_calculator$n
    days_calculator(sample_size_output, average_daily_traffic)
  })

  output$answer <- renderText(calc_answer()) 




}

shinyApp(ui = ui, server = server)

1 Ответ

1 голос
/ 20 марта 2020

Несколько предложений, которые могут помочь.

  • Начал бы с упрощенного блестящего приложения перед добавлением всех вычислений, на данный момент с ним проще работать
  • Избегал бы ставить output операторов внутри eventReactive. Смотрите ниже, например.
  • Рассмотрите возможность использования только одного observeEvent или eventReactive для нажатия кнопки вместо нескольких, тем более, что результаты некоторых функций зависят от других.
  • В настоящее время нет входов, поэтому не надо Нужны дополнительные reactive выражения. Однако при добавлении входных данных вы, вероятно, это сделаете.

Если вы еще этого не сделали, просмотрите учебник R Studio Shiny по Кнопки действий и Реакционная способность .

Надеюсь, это поможет двигаться вперед.

library(shiny)
library(pwr)

ui <- fluidPage(
  actionButton("exe", "Run", style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
  mainPanel(
    textOutput("answer")
  )
)

server <- function(input, output, session) {

  average_daily_traffic <-  3515/30
  control <- 0.47
  uplift <- 0.02
  num_vars <- 2 

  sample_size_calculator <- function() {
    variant <- (uplift + 1) * control
    baseline <- ES.h(control, variant)
    sample_size_output <- pwr.p.test(h = baseline,
                                     n = ,
                                     sig.level = 0.05,
                                     power = 0.8)
    if(variant >= 0)
      {return(sample_size_output)}
    else
      {return(NA)}
  }

  days_calculator <- function (sample_size_output, average_daily_traffic) {
    days_required <- c((sample_size_output)*num_vars)/(average_daily_traffic)
    if(days_required >= 0)
      {paste0("It will take approximately ", round(days_required, digits = 0)*num_vars, " days or ", round((round(days_required, digits = 0)*num_vars)/365, digits = 1) ," years for this test to reach significance, based on a daily average of " , round(average_daily_traffic, digits = 0), " users to this page in the last 30 days.")}
    else
      {paste("N/A")}
  }

  calc_answer <- eventReactive(input$exe, {
    sample_size_calculator <- sample_size_calculator()
    sample_size_output <- sample_size_calculator$n
    days_calculator(sample_size_output, average_daily_traffic)
  })

  output$answer <- renderText(calc_answer()) 

}

shinyApp(ui = ui, server = server)
...