Как ждать нажатия клавиши в R?

139

Я хочу приостановить мой сценарий R, пока пользователь не нажмет клавишу.

Как мне это сделать?

Контанго
источник
Вы нашли какой-нибудь ответ, который вы можете принять?
Лео Леопольд Герц,

Ответы:

127

Как кто-то уже написал в комментарии, вам не нужно использовать кошку раньше readline(). Просто напишите:

readline(prompt="Press [enter] to continue")

Если вы не хотите назначать его переменной и не хотите, чтобы возвращаемый результат выводился в консоли, поместите readline()в invisible():

invisible(readline(prompt="Press [enter] to continue"))
NNN
источник
Я думаю, что это лучший ответ здесь.
Лео Леопольд Герц,
1
как насчет добавления еще одной функции к нему? press esc keep to exit loop?
I_m_LeMarque
4
@nnn это не работает, если я запускаю скрипт в rstudio, например, print ("hi") readline ("Нажмите клавишу для продолжения") print ("ho") Это вероятно потому, что сеанс не является интерактивным. Как это сделать в неинтерактивной сессии?
Паскалив,
79

Способ 1

Ожидает, пока вы не нажмете [enter] в консоли:

cat ("Press [enter] to continue")
line <- readline()

Оборачивание в функцию:

readkey <- function()
{
    cat ("Press [enter] to continue")
    line <- readline()
}

Эта функция является лучшим эквивалентом Console.ReadKey()в C #.

Способ 2

Пауза, пока вы не нажмете клавишу [enter] на клавиатуре. Недостаток этого метода заключается в том, что если вы введете что-то, что не является числом, оно будет отображать ошибку.

print ("Press [enter] to continue")
number <- scan(n=1)

Оборачивание в функцию:

readkey <- function()
{
    cat("[press [enter] to continue]")
    number <- scan(n=1)
}

Способ 3

Представьте, что вы хотите подождать нажатия клавиши, прежде чем наносить на карту другую точку. В этом случае мы можем использовать getGraphicsEvent () для ожидания нажатия клавиши на графике.

Этот пример программы иллюстрирует концепцию:

readkeygraph <- function(prompt)
{
    getGraphicsEvent(prompt = prompt, 
                 onMouseDown = NULL, onMouseMove = NULL,
                 onMouseUp = NULL, onKeybd = onKeybd,
                 consolePrompt = "[click on graph then follow top prompt to continue]")
    Sys.sleep(0.01)
    return(keyPressed)
}

onKeybd <- function(key)
{
    keyPressed <<- key
}

xaxis=c(1:10) # Set up the x-axis.
yaxis=runif(10,min=0,max=1) # Set up the y-axis.
plot(xaxis,yaxis)

for (i in xaxis)
{
    # On each keypress, color the points on the graph in red, one by one.
    points(i,yaxis[i],col="red", pch=19)
    keyPressed = readkeygraph("[press any key to continue]")
}

Здесь вы можете увидеть график с половиной цветных точек, ожидающих следующего нажатия на клавиатуре.

Совместимость: протестировано в средах с использованием win.graph или X11 . Работает с Windows 7 x64 с Revolution R v6.1. Не работает под RStudio (так как не использует win.graph).

введите описание изображения здесь

Гравитас
источник
6
Способ 1 можно сократить, используя promptаргумент для readline. Метод 2 будет работать с любым вводом (не только с цифрами), если what=""его добавить в вызов scan. getGraphicsEventработает только на определенных графических устройствах на определенных платформах (но если вы используете одно из этих устройств, оно работает нормально).
Грег Сноу
2
Если вы используете эту функцию (метод 1) в цикле и хотите остановить цикл, if(line == "Q") stop()
включите,
18

Вот небольшая функция (с использованием пакета tcltk), которая откроет маленькое окно и подождет, пока вы либо не нажмете кнопку продолжения, либо нажмете любую клавишу (пока небольшое окно все еще имеет фокус), затем она позволит вашему сценарию продолжиться.

library(tcltk)

mywait <- function() {
    tt <- tktoplevel()
    tkpack( tkbutton(tt, text='Continue', command=function()tkdestroy(tt)),
        side='bottom')
    tkbind(tt,'<Key>', function()tkdestroy(tt) )

    tkwait.window(tt)
}

Просто вставьте mywait()ваш сценарий в любое место, где вы хотите, чтобы сценарий приостановился.

Это работает на любой платформе, которая поддерживает tcltk (которая, я думаю, является наиболее распространенной), будет реагировать на любое нажатие клавиши (не только вводить), и даже работает, когда скрипт запускается в пакетном режиме (но он все равно останавливается в пакетном режиме). так что, если вы не там, чтобы продолжить это будет ждать вечно). Можно добавить таймер, чтобы он продолжался через заданный промежуток времени, если не нажать или не нажать клавишу.

Он не возвращает, какая клавиша была нажата (но может быть изменена для этого).

Грег Сноу
источник
Это круто Но только предупреждение, по какой-то причине он не будет работать на Error in structure(.External(.C_dotTclObjv, objv), class = "tclObj") : [tcl] invalid command name "toplevel".
веб-клиенте
2
@milia, это правильно. Код, основанный на tcltk, должен запускаться на локальной машине и не будет запускаться на RStudio-Server.
Грег Сноу
14

R и Rscript отправляют ''на readline и сканируют в неинтерактивном режиме (см. ? readline). Решением является принудительное stdinиспользование сканирования.

cat('Solution to everything? > ')
b <- scan("stdin", character(), n=1)

Пример:

$ Rscript t.R 
Solution to everything? > 42
Read 1 item
Саймон А. Эугстер
источник
2
Потрясающие! Это почти решает мою проблему . Тем не менее, было бы неплохо, если бы консоль не ожидала текст + возврат, а скорее реагировала на первое нажатие клавиши (как в «Нажмите любую клавишу для продолжения»).
Vorac
3

Этот ответ похож на ответ Саймона , но не требует дополнительного ввода, кроме новой строки.

cat("Press Enter to continue...")
invisible(scan("stdin", character(), nlines = 1, quiet = TRUE))

Используя nlines=1вместо n=1, пользователь может просто нажать Enter, чтобы продолжить Rscript.

Деннис Ю.Л.
источник
+1 это единственный ответ, который на самом деле работает, как мне нужно. Внутри Rscript: пауза и требуется только удар, Enterчтобы продолжить.
Ариэльф
2
это сломало R, и мне пришлось прекратить сеанс
blobbymatt
1
в интерактивном режиме это прерывает R и требует завершения сеанса. Пожалуйста, добавьте предупреждение к вашей записи, в этом случае я удалю понижающий голос.
HoneyBuddha
Работал для меня, как и ожидалось на Windows !. Принятое решение (выше) было пропущено и не остановилось. Этот на самом деле сделал паузу и ждал, пока я нажму на вход.
Мэтт Д
0

Способ сделать это (вроде бы, вы должны нажимать кнопку, а не клавишу, но достаточно близко), это использовать блестящий:

library(shiny)

ui     <- fluidPage(actionButton("button", "Press the button"))
server <- function(input, output) {observeEvent(input$button, {stopApp()})}

runApp(shinyApp(ui = ui, server = server))

print("He waited for you to press the button in order to print this")

По моему опыту, это имеет уникальную особенность: даже если вы запустили скрипт, код которого был написан после runAppфункции, он не будет работать, пока вы не нажмете кнопку в приложении (кнопка, которая останавливает использование приложений изнутри stopApp).

Себастьян Ваутерс
источник