Comment attendre une pression sur une touche en R?

139

Je souhaite mettre mon script R en pause jusqu'à ce que l'utilisateur appuie sur une touche.

Comment puis-je faire cela?

Contango
la source
Avez-vous trouvé une réponse que vous pouvez accepter?
Léo Léopold Hertz 준영

Réponses:

127

Comme quelqu'un l'a déjà écrit dans un commentaire, vous n'avez pas besoin d'utiliser le chat avant readline(). Écrivez simplement:

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

Si vous ne souhaitez pas l'affecter à une variable et ne souhaitez pas qu'un retour soit imprimé dans la console, enveloppez le readline()dans un invisible():

invisible(readline(prompt="Press [enter] to continue"))
nnn
la source
Je pense que c'est la meilleure réponse ici.
Léo Léopold Hertz 준영
1
que diriez-vous d'ajouter une fonctionnalité supplémentaire? press esc keep to exit loop?
I_m_LeMarque
4
@nnn cela ne fonctionne pas si j'exécute un script dans rstudio, par exemple print ("hi") readline ("Appuyez sur une touche pour continuer") print ("ho") C'est probablement parce que la session n'est pas interactive. Comment faire cela dans une session non interactive?
PascalIv
79

Méthode 1

Attend que vous appuyiez sur [entrée] dans la console:

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

Emballage dans une fonction:

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

Cette fonction est le meilleur équivalent de Console.ReadKey()C #.

Méthode 2

Faites une pause jusqu'à ce que vous tapiez la touche [entrée] sur le clavier. L'inconvénient de cette méthode est que si vous tapez quelque chose qui n'est pas un nombre, il affichera une erreur.

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

Emballage dans une fonction:

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

Méthode 3

Imaginez que vous vouliez attendre une pression sur une touche avant de tracer un autre point sur un graphique. Dans ce cas, nous pouvons utiliser getGraphicsEvent () pour attendre une pression de touche dans un graphe.

Cet exemple de programme illustre le concept:

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]")
}

Ici vous pouvez voir le graphique, avec la moitié de ses points colorés, attendant la prochaine frappe sur le clavier.

Compatibilité: Testé sous des environnements, utilisez win.graph ou X11 . Fonctionne avec Windows 7 x64 avec Revolution R v6.1. Ne fonctionne pas sous RStudio (car il n'utilise pas win.graph).

entrez la description de l'image ici

Gravitas
la source
6
La méthode 1 peut être raccourcie en utilisant l' promptargument to readline. La méthode 2 fonctionnerait avec n'importe quelle entrée (pas seulement des nombres) si elle what=""était ajoutée à l'appel à scan. getGraphicsEventne fonctionne que sur des périphériques graphiques spécifiques sur certaines plates-formes (mais si vous utilisez l'un de ces périphériques, cela fonctionne bien).
Greg Snow
2
Si vous utilisez cette fonction (Méthode 1) dans une boucle et que vous souhaitez arrêter la boucle, incluez par exemple:if(line == "Q") stop()
Dorian Grv
18

Voici une petite fonction (utilisant le package tcltk) qui ouvrira une petite fenêtre et attendra que vous cliquiez sur le bouton Continuer ou que vous appuyiez sur n'importe quelle touche (pendant que la petite fenêtre a toujours le focus), puis cela laissera votre script continuer.

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)
}

Mettez simplement mywait()votre script à l'endroit où vous souhaitez que le script se mette en pause.

Cela fonctionne sur n'importe quelle plate-forme qui prend en charge tcltk (qui, je pense, est tous les plus courants), répondra à toute pression de touche (pas seulement entrer), et fonctionne même lorsque le script est exécuté en mode batch (mais il s'arrête toujours en mode batch , donc si vous n'êtes pas là pour continuer cela attendra pour toujours). Un minuteur peut être ajouté pour le faire continuer après un laps de temps défini s'il n'est pas cliqué ou si une touche est enfoncée.

Il ne renvoie pas la touche enfoncée (mais peut être modifié pour ce faire).

Greg Snow
la source
C'est génial. Mais juste un avertissement, il ne fonctionnera pas sur le client Web de RStudio-Server, pour une raison quelconque ( Error in structure(.External(.C_dotTclObjv, objv), class = "tclObj") : [tcl] invalid command name "toplevel". )
milia
2
@milia, c'est correct. Le code basé sur tcltk doit s'exécuter sur la machine locale et ne fonctionnera pas sur RStudio-Server.
Greg Snow
14

R et Rscript envoient tous deux ''vers readline et balaient en mode non interactif (voir ? readline). La solution est de forcer l' stdinutilisation de scan.

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

Exemple:

$ Rscript t.R 
Solution to everything? > 42
Read 1 item
Simon A. Eugster
la source
2
Impressionnant! Cela résout presque mon problème . Ce serait toujours bien si la console n'attend pas le texte + retour, mais réagit plutôt à la première pression sur une touche (comme dans «Appuyez sur n'importe quelle touche pour continuer»).
Vorac
3

Cette réponse est similaire à celle de Simon , mais ne nécessite aucune entrée supplémentaire autre qu'une nouvelle ligne.

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

En utilisant nlines=1au lieu de n=1, l'utilisateur peut simplement appuyer sur Entrée pour continuer le Rscript.

Dennis YL
la source
+1 c'est la seule réponse qui fonctionne réellement comme souhaité pour moi. À l'intérieur Rscript: il s'arrête et ne nécessite que de frapper Enterpour continuer.
arielf
2
cela a cassé R et j'ai dû mettre fin à la session
blobbymatt
1
en mode interactif, cela interrompt R et nécessite la fin de la session. Veuillez ajouter un avertissement sur votre entrée, auquel cas je supprimerai le vote défavorable.
HoneyBuddha
A travaillé pour moi comme prévu sur Windows !. La solution acceptée (ci-dessus) a été ignorée et n'a pas été interrompue. Celui-ci a fait une pause et a attendu que je clique sur Entrée.
Matt D
0

Une façon de le faire (un peu, vous devez appuyer sur un bouton plutôt qu'une touche, mais assez près) est d'utiliser brillant:

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")

D'après mon expérience, cela a une caractéristique unique: même si vous avez exécuté un script contenant du code écrit après la runAppfonction, il ne fonctionnera pas tant que vous n'aurez pas appuyé sur le bouton de l'application (bouton qui arrête les applications de l'intérieur stopApp).

Sébastien Wouters
la source