{"id":277,"date":"2015-01-12T14:20:56","date_gmt":"2015-01-12T13:20:56","guid":{"rendered":"http:\/\/perso.ens-lyon.fr\/lise.vaudor\/?p=277"},"modified":"2017-05-23T15:45:00","modified_gmt":"2017-05-23T13:45:00","slug":"creer-une-interface-clique-boutons-sous-r","status":"publish","type":"post","link":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/creer-une-interface-clique-boutons-sous-r\/","title":{"rendered":"Cr\u00e9er une interface \u00ab\u00a0clique-boutons\u00a0\u00bb sous R"},"content":{"rendered":"<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Interface_TclTk\/Lise_Vaudor_headband.png\" alt=\"plot of chunk\nLise_Vaudor_headband\" \/><\/p>\n<p><em>EDIT: Ce billet date d&rsquo;une \u00e9poque o\u00f9 je n&rsquo;avais pas encore d\u00e9couvert la magie de <a href=\"http:\/\/shiny.rstudio.com\/\">Shiny<\/a>&#8230; D\u00e9sormais, je conseillerais \u00e0 quiconque souhaite faire une petite interface interactive sous R d&rsquo;aller voir de ce c\u00f4t\u00e9 l\u00e0&#8230; Il y a d\u00e9j\u00e0 des tutoriels tr\u00e8s bien faits <a href=\"http:\/\/shiny.rstudio.com\/tutorial\">ici<\/a>.<\/em><\/p>\n<p>Ce billet vise \u00e0 vous montrer comment construire une <strong>interface \u00ab\u00a0clique-boutons\u00a0\u00bb<\/strong> pour R.<\/p>\n<p>Pour un utilisateur r\u00e9gulier de R, le recours \u00e0 une telle interface est plut\u00f4t \u00ab\u00a0gadget\u00a0\u00bb (ou en tout cas d&rsquo;un rapport utilit\u00e9\/temps d&rsquo;\u00e9criture tr\u00e8s peu int\u00e9ressant). MAIS il peut se r\u00e9v\u00e9ler utile de fournir une telle interface \u00e0 un <strong>utilisateur novice<\/strong> de R, auquel on souhaite permettre d&rsquo;utiliser des scripts R sans qu&rsquo;il ait \u00e0 mettre le nez dedans&#8230;<\/p>\n<h1>Exemple: construction d&rsquo;une interface simple<\/h1>\n<p>Pour ce billet, je vais montrer, \u00e0 travers un exemple, comment construire une petite interface \u00e0 l&rsquo;aide du package <code>tcltk<\/code>.<\/p>\n<p>Il s&rsquo;agira de faire un mini-jeu consistant \u00e0 deviner un chiffre (tir\u00e9 au hasard par l&rsquo;ordinateur) en faisant le moins d&rsquo;essais possibles. Le joueur sera guid\u00e9 par des indications de type \u00ab\u00a0Le nombre est plus grand\u00a0\u00bb\/\u00a0\u00bbLe nombre est plus petit\u00a0\u00bb.<\/p>\n<p><sub><sup> Soyons clairs, on a d\u00e9j\u00e0 vu des jeux plus amusants (par exemple &#8211; message subliminal &#8211; Zelda : A Link between Worlds sous Nintendo 3DS). Mais bon, commen\u00e7ons notre carri\u00e8re de d\u00e9veloppeur informatique doucement.<\/sup><\/sub><\/p>\n<p>L&rsquo;interface, <em>in fine<\/em>, aura l&rsquo;apparence suivante:<\/p>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Interface_TclTk\/int_comp.PNG\" alt=\"Interface tcltk sous\nR\" \/><\/p>\n<p>Elle est compos\u00e9e de divers composants d&rsquo;interface graphiques (les <strong>widgets<\/strong>). Ici, elle est compos\u00e9e en particulier:<\/p>\n<ul>\n<li>de plusieurs courts textes (<strong>labels<\/strong>)<\/li>\n<li>d&rsquo;une bo\u00eete permettant \u00e0 l&rsquo;utilisateur d&rsquo;entrer une cha\u00eene de caract\u00e8re (<strong>entry<\/strong>)<\/li>\n<li>d&rsquo;un bouton poussoir \u00ab\u00a0OK\u00a0\u00bb (<strong>button<\/strong>)<\/li>\n<\/ul>\n<p>Voici comment construire l&rsquo;interface de base:<\/p>\n<pre><code>#d\u00e9commenter la ligne ci-dessous pour installer le package\n#install.packages(\"tcltk\")\nrequire(tcltk)\nbase=tktoplevel()\ntkwm.title(base, \"supergameR\")\n<\/code><\/pre>\n<p>A ce stade, l&rsquo;interface est totalement vide.<\/p>\n<p>On va pouvoir afficher les widgets dans un cadre (<strong>frame<\/strong>). On cr\u00e9e donc un premier <strong>frame<\/strong>, fr1.<\/p>\n<p>On le remplit simplement avec un court texte (un <strong>label<\/strong>).<\/p>\n<pre><code># creation et affichage du frame\nfr1=tkframe(base)\ntkpack(fr1)\n\n# creation et affichage du label\nt1=tklabel(fr1, text=\"SupergameR, a super game on R!\")\ntkpack(t1)\n<\/code><\/pre>\n<p>La fonction <code>tklabel<\/code> permet de cr\u00e9er le widget, mais ne l&rsquo;affiche pas directement dans l&rsquo;interface. C&rsquo;est l&rsquo;appel de la fonction <code>tkpack<\/code> qui permet de l&rsquo;afficher dans l&rsquo;interface.<\/p>\n<p>A ce stade, l&rsquo;interface ressemble simplement \u00e0 ceci:<\/p>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Interface_TclTk\/int_2.PNG\" alt=\"Interface + 1\nframe\" \/><\/p>\n<p>On cr\u00e9e un deuxi\u00e8me frame, fr2. On va le remplir avec un court text (<strong>label<\/strong>) et avec une bo\u00eete de saisie (<strong>entry<\/strong>).<\/p>\n<pre><code># creation et affichage du deuxieme frame\nfr2=tkframe(base)\ntkpack(fr2)\n\n# creation et affichage du deuxieme label \nt2=tklabel(fr2,text=\"Find mystery number (between 0 &amp; 100)\")\ntkpack(t2, side=\"left\")\n\n# creation et affichage de l'entry\nv_prop_n=tclVar(\"\")\ne1=tkentry(fr2, textvariable=v_prop_n)\ntkpack(e1,side=\"right\")  \n<\/code><\/pre>\n<p>A ce stade, l&rsquo;interface ressemble \u00e0 ceci<\/p>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Interface_TclTk\/int_3.PNG\" alt=\"Interface +\nentry\" \/><\/p>\n<p>Le widget de type <strong>entry<\/strong> est associ\u00e9 \u00e0 une <strong>variable tcl<\/strong> (il s&rsquo;agit de la variable correspondant \u00e0 la valeur \u00e9crite par l&rsquo;utilisateur dans le widget).<\/p>\n<p>Pour cr\u00e9er le widget, il faut donc commencer par cr\u00e9er cette variable (qu&rsquo;on a appel\u00e9 ici <code>v_prop_n<\/code> pour \u00ab\u00a0variable correspondant \u00e0 la proposition de nombre\u00a0\u00bb). Ici, on a initialis\u00e9 cette valeur pour qu&rsquo;elle soit non renseign\u00e9e a priori. Si l&rsquo;on avait indiqu\u00e9 <code>v_prop_n=tclVar(\"50\")<\/code>, alors la valeur par d\u00e9faut propos\u00e9e dans l&rsquo;interface serait 50:<\/p>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Interface_TclTk\/int_5.PNG\" alt=\"Interface + 1 frame + defaut\n50\" \/><\/p>\n<p>On peut r\u00e9cup\u00e9rer la valeur de cette variable <code>v_prop_n<\/code> \u00e0 travers la commande:<\/p>\n<pre><code>tclvalue(v_prop_n)\n<\/code><\/pre>\n<p>Vous pouvez faire le test consistant \u00e0:<\/p>\n<ul>\n<li>taper une valeur dans l&rsquo;interface que vous avez cr\u00e9\u00e9e<\/li>\n<li>v\u00e9rifier la valeur renvoy\u00e9e par la commande ci-dessus si vous l&rsquo;ex\u00e9cutez dans l&rsquo;invite de commande R<\/li>\n<\/ul>\n<p>Enfin, cr\u00e9ons le troisi\u00e8me et dernier frame, qui contient le bouton poussoir (<strong>button<\/strong>). L&rsquo;activation du bouton poussoir lance un certain nombre de processus, qui sont regroup\u00e9s dans une <strong>fonction R<\/strong>. Ici, le bouton \u00ab\u00a0OK\u00a0\u00bb va \u00eatre li\u00e9 \u00e0 une fonction que j&rsquo;ai appel\u00e9 <code>ok<\/code>.<\/p>\n<p>Il faut donc \u00e9crire la fonction <code>ok<\/code> avant de cr\u00e9er le bouton poussoir&#8230; C&rsquo;est l&rsquo;\u00e9tape la plus d\u00e9licate!<\/p>\n<pre><code># creation et affichage du troisieme frame\nfr3=tkframe(base)\ntkpack(fr3)\n\n# tirage au hasard d'un nombre entier entre 0 et 100\nn=sample(0:100,1)\n\n# nombre d'essais\nk=0\n\n# fonction \u00e0 executer lorsque l'utilisateur appuie sur le bouton \"OK\"\nok=function(){\n  ## R\u00e9cup\u00e8re la valeur de la variable v_prop_n\n  prop_n&lt;&lt;-as.numeric(tclvalue(v_prop_n))\n  ## Compare cette valeur \u00e0 la valeur de n\n  if(prop_n&lt;n){ans=\"No! it's more!\"}\n  if(prop_n&gt;n){ans=\"No! it's less!\"}\n  if(prop_n==n){ans=\"Yes! exactly!\"}\n  ## Augmente le nombre d'essais de 1\n  k&lt;&lt;-k+1\n  ## Cr\u00e9e un texte comprenant \n  ## d'une part l'indication \"plus grand ou plus petit\"\n  ## d'autre part le nombre d'essais.\n\n  ans=paste(ans,\"(number of trials:\", k, \")\", sep=\"\")\n  ## Si une telle \u00e9tiquette a d\u00e9j\u00e0 \u00e9t\u00e9 cr\u00e9\u00e9e lors d'un essai pr\u00e9c\u00e9dent, \n  ## elle est d\u00e9truite \n  if(exists(\"lab\", env=globalenv())){tkdestroy(lab)}\n  ## L'etiquette est cr\u00e9\u00e9e et affich\u00e9e\n  lab&lt;&lt;-tklabel(fr3,text=ans)\n  tkpack(lab)\n}\nokbutton=tkbutton(fr3, text=\"OK\", command=ok)\ntkpack(okbutton)    \n<\/code><\/pre>\n<p><sub><sup> Notez l&rsquo;usage du symbole <code>&lt;&lt;-<\/code> \u00e0 la place de <code>=<\/code> ou <code>&lt;-<\/code>. Il est li\u00e9 \u00e0 la notion d&rsquo;<strong>environnement<\/strong> (c&rsquo;est une notion un petit peu compliqu\u00e9e \u00e0 expliquer comme \u00e7a entre la poire et le fromage, mais je vais quand-m\u00eame en dire quelques mots en attendant de faire un billet sur le sujet). <\/sup><\/sub><\/p>\n<p><sub><sup> Sous R, un environnement est en quelque sorte l'\u00a0\u00bbendroit\u00a0\u00bb comprenant les objets. Par d\u00e9faut, la plupart des objets cr\u00e9\u00e9s sont stock\u00e9s sous l&rsquo;environnement \u00ab\u00a0de base\u00a0\u00bb. Les objets cr\u00e9\u00e9s lors de l&rsquo;ex\u00e9cution d&rsquo;une fonction font exception (un nouvel environnement local et temporaire est cr\u00e9\u00e9 \u00e0 chaque ex\u00e9cution de la fonction). Le symbole <code>&lt;&lt;-<\/code> permet de passer outre cette propri\u00e9t\u00e9 et de cr\u00e9er les objets dans l&rsquo;environnement de base. <\/sup><\/sub><\/p>\n<h1>Pour aller plus loin<\/h1>\n<p>Il existe beaucoup d&rsquo;<strong>autres types de widgets<\/strong> que je n&rsquo;ai pas abord\u00e9s ici: radiobuttons, checkbuttons, menus, listboxes, etc. Il existe \u00e9galement une infinit\u00e9 de mani\u00e8re de modifier l&rsquo;<strong>arrangement g\u00e9om\u00e9trique<\/strong> et les <strong>propri\u00e9t\u00e9s graphiques<\/strong> (taille, couleur, polices, etc.) de votre interface.<\/p>\n<p>Ici, par souci de simplicit\u00e9, je n&rsquo;ai pas abord\u00e9 ces aspects, mais vous pouvez trouver tout un tas d&rsquo;exemples compl\u00e9mentaires sur le net&#8230;<\/p>\n<ul>\n<li><a href=\"http:\/\/stat-www.berkeley.edu\/classes\/s244\/gui\/Gui1.html\">ici<\/a> (cours de Phil Spector)<\/li>\n<li><a href=\"http:\/\/www.sciviews.org\/_rgui\/tcltk\/\">ici<\/a> (collection d&rsquo;exemples cr\u00e9\u00e9e par James Wettenhal et maintenue par Philippe Grosjean)<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>EDIT: Ce billet date d&rsquo;une \u00e9poque o\u00f9 je n&rsquo;avais pas encore d\u00e9couvert la magie de Shiny&#8230; D\u00e9sormais, je conseillerais \u00e0 quiconque souhaite faire une petite interface interactive sous R d&rsquo;aller voir de ce c\u00f4t\u00e9 l\u00e0&#8230; Il y a d\u00e9j\u00e0 des tutoriels tr\u00e8s bien faits ici. Ce billet vise \u00e0 vous montrer comment construire une interface \u00ab\u00a0clique-boutons\u00a0\u00bb pour R. Pour un utilisateur r\u00e9gulier de R, le recours \u00e0 une telle interface.. <a href=\"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/creer-une-interface-clique-boutons-sous-r\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-277","post","type-post","status-publish","format-standard","hentry","category-tous-les-posts"],"_links":{"self":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/277","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/comments?post=277"}],"version-history":[{"count":20,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/277\/revisions"}],"predecessor-version":[{"id":565,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/277\/revisions\/565"}],"wp:attachment":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/media?parent=277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/categories?post=277"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/tags?post=277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}