Възможно ли е да се показват конзолни съобщения (написани с `message`) в лъскав потребителски интерфейс?

Не разбирам твърде дълбоко съобщението на R срещу котка срещу печат срещу и т.н., но се чудя дали е възможно да заснемам съобщения и да ги покажа в лъскаво приложение?

Пример: следното приложение може да улавя изявления за котки (и също така да отпечатва изявления), но не и изявления за съобщения

runApp(shinyApp(
  ui = fluidPage(
    textOutput("test")
  ),
  server = function(input,output, session) {
    output$test <- renderPrint({
      cat("test cat")
      message("test message")
    })
  }
))

Кръстосана публикация от групата shiny-discuss Google, тъй като получих 0 отговора.


person DeanAttali    schedule 27.05.2015    source източник
comment
Предполагам, че можете да използвате withCallingHandlers(), за да улавяте съобщения в R израз, след което да ги отпечатвате/катирате.   -  person Yihui Xie    schedule 27.05.2015
comment
Благодаря Yihui, успях да го използвам, това е огромна помощ   -  person DeanAttali    schedule 27.05.2015


Отговори (2)


Yihui ми предложи да използвам withCallingHandlers и това наистина ми позволи да намеря решение. Не бях съвсем сигурен как да използвам тази функция по начин, който да прави точно това, от което се нуждаех, защото проблемът ми беше, че имах функция, която отпечатва няколко съобщения едно по едно и използвайки наивен подход отпечатва само последното съобщение. Ето първия ми опит (който работи, ако имате само едно съобщение за показване):

foo <- function() {
  message("one")
  message("two")
}

runApp(shinyApp(
  ui = fluidPage(
    actionButton("btn","Click me"),
    textOutput("text")
  ),
  server = function(input,output, session) {
    observeEvent(input$btn, {
      withCallingHandlers(
        foo(),
        message = function(m) output$text <- renderPrint(m$message)
      )
    })
  }
))

Забележете как се извежда само two\n. Така че окончателното ми решение беше да използвам функцията html от пакета shinyjs (отказ от отговорност: аз написах този пакет), която ми позволява да променям или добавям към HTML вътре в елемент. Работи перфектно - сега и двете съобщения се отпечатаха в реално време.

foo <- function() {
  message("one")
  Sys.sleep(0.5)
  message("two")
}

runApp(shinyApp(
  ui = fluidPage(
    shinyjs::useShinyjs(),
    actionButton("btn","Click me"),
    textOutput("text")
  ),
  server = function(input,output, session) {
    observeEvent(input$btn, {
      withCallingHandlers({
        shinyjs::html("text", "")
        foo()
      },
        message = function(m) {
          shinyjs::html(id = "text", html = m$message, add = TRUE)
      })
    })
  }
))
person DeanAttali    schedule 27.05.2015
comment
Накланям ви шапка, сър. - person geotheory; 20.05.2017
comment
Благодаря ти много. Имах функция, която отпечатваше текст на message(). С вашето решение мога да редактирам реда shinyjs::html(id = "text", html... с помощта на HTML тагове. - person Fábio; 24.02.2018
comment
Това в момента извежда съобщенията без връщане на ред между тях. Възможно ли е това да се направи? Как би го направил човек? - person kennyB; 27.03.2018
comment
@kennyB Успяхте ли да намерите начин да вмъкнете връщане на ред, така че съобщенията да се показват на различни редове? Благодаря! - person alvaropr; 29.08.2018
comment
Това изглежда не работи. Някой използвал ли е това наскоро? - person knapply; 18.03.2019
comment
@DeanAttali Тогава нещо е шантаво от моя страна. Благодаря ви за проверката! - person knapply; 18.03.2019
comment
Опитвам се да използвам това в модулна рамка... не изглежда, че пространството от имена ns() работи правилно с това решение...? - person quickreaction; 02.04.2020
comment
Възможно е, не съм пробвал. Въпреки че, честно казано, все още не съм виждал много неща, които се повреждат вътре в модулите, обикновено това е потребителска грешка. - person DeanAttali; 14.04.2020
comment
За да добавите нов ред след всяко съобщение, можете да коригирате на shinyjs::html(id = "text", html = paste0(m$message, '<br>'), add = TRUE) - person jbaums; 25.07.2020
comment
@DeanAttali: Това е много впечатляващо, благодаря ви много. Има ли начин да се показват съобщенията само в Shiny UI, но не и в R конзолата? Тоест, пълното им пренасочване към потребителския интерфейс. - person panman; 03.08.2020
comment
има ли начин Вероятно :) Дали ще е досадно да си играете с код, докато не го намерите? Също вероятно :) Мисля, че това би било различно решение от това, което измислих тук. Погледнете във функцията sink() и може би имате нещо като таймер, който проверява всички нови съобщения през редовен интервал, това би било първото нещо, което бих разгледал. - person DeanAttali; 03.08.2020
comment
@DeanAttali, възможно ли е да се заснемат cat и print в потребителския интерфейс в реално време? Ако нечия функция използва cat или print, withCallingHandlers или tryCatch не работи. - person lz100; 28.10.2020
comment
Изглежда, че това работи само с observeEvent. Липсва ли ми нещо, за да работи това на eventReactive? - person Jeff Parker; 04.03.2021
comment
Използвам sink() с reactiveFileReader() за генерирания лог файл на конзолния изход и след това използвам renderPrint() за показване на изход от verbatimTextOutput(), но той не е активен. Не можах да намеря добри примери, които могат да показват на живо ред по ред на конзолата в Shiny. @DeanAttali, ако имате някакъв пример за това, който можете да споделите, наистина ще го оценя. - person Tarun Parmar; 18.03.2021

Знам, че това не е толкова елегантно, но заобиколих малко подобен проблем, използвайки capture.output; за съжаление обаче sink не позволява едновременно заснемане на съобщенияи изход. Не ги получавате в оригиналния ред, но можете да извлечете поне двата потока (тук обърнати към HTML):

runApp(shinyApp(
  ui = fluidPage(
    uiOutput("test")
  ),
  server = function(input,output, session) {
    output$test <- renderUI({
      HTML(
      paste(capture.output(type = "message", expr = { 
        message(capture.output(type = "output", expr = {
          cat("test cat<br>")
          message("test message")
          cat("test cat2<br>")
          message("test message2")
        }))
      }), collapse="<br>")
  )})
 })
)

Изход:

test message
test message2
test cat
test cat2

Може би в случай, че потребителят иска да улови и двете, но и да ги раздели, това ще осигури удобно решение. (Вашият пакет shinyjs изглежда чист, трябва да го разгледате!)

person Teemu Daniel Laajala    schedule 21.11.2016
comment
Проблемът с този подход е, че целият изход се отпечатва в края, а не идва на живо. Така че, ако стартирате бавна функция, която отпечатва изход, докато работи, няма да я видите, докато не приключи - person DeanAttali; 21.11.2016