Graphiques interactifs Shiny : événements clic et sélection en R

Faites réagir un graphique aux entrées, puis lisez les événements de clic et de sélection rectangulaire sur plotOutput() et utilisez nearPoints() et brushedPoints() pour récupérer les lignes de données derrière ce que l’utilisateur a touché.

Programming
Shiny

Un graphique Shiny peut faire plus que se redessiner quand un curseur bouge — il peut vous dire ce que l’utilisateur a cliqué ou sélectionné. Cette leçon revient sur la paire renderPlot/plotOutput, fait réagir un graphique aux entrées, puis ajoute les événements de clic et de sélection rectangulaire : plotOutput(“p”, click = …, brush = …) côté ui, et nearPoints()/brushedPoints() côté server pour récupérer les lignes de données sous-jacentes. Elle se termine par un renvoi vers plotly pour un survol et un zoom plus riches.

Date de publication

28 juin 2026

Modifié

17 juillet 2026

AstucePoints clés
  • Un graphique réagit aux entrées gratuitement. Référencez un input$<id> à l’intérieur de renderPlot() et la figure se redessine chaque fois que cette entrée change — aucun code d’événement nécessaire.
  • Le clic et la sélection rectangulaire sont optionnels. Ajoutez click = "id" ou brush = "id" à plotOutput() et Shiny signale où l’utilisateur a cliqué ou ce qu’il a sélectionné sous forme de input$id, une petite list de coordonnées.
  • Transformez les coordonnées en lignes de données avec les fonctions auxiliaires. nearPoints(df, input$click) renvoie les lignes proches d’un clic ; brushedPoints(df, input$brush) renvoie les lignes à l’intérieur d’un rectangle de sélection — aucun calcul de coordonnées à la main.
  • Les fonctions auxiliaires ont besoin du même data frame et des mêmes x/y que ceux que vous avez tracés. Passez le data frame que vous avez dessiné et, pour les graphiques de base, nommez xvar/yvar ; ggplot2 lit le mappage automatiquement.
  • Les événements valent NULL tant que l’utilisateur n’agit pas. Au démarrage input$plot_click vaut NULL ; protégez les lectures avec req() pour que les sorties attendent tranquillement au lieu de générer une erreur.
  • Pour le survol, le zoom et le déplacement, recourez à plotlyrenderPlotly/plotlyOutput — qui suit la même règle d’association.

Introduction

Un graphique Shiny fait déjà une chose interactive avec brio : lisez un input$<id> à l’intérieur de renderPlot() et il se redessine de lui-même quand cette entrée change. Mais souvent vous voulez aussi que le graphique fonctionne dans l’autre sens — qu’il vous dise ce que l’utilisateur a cliqué ou sélectionné, pour pouvoir afficher la ligne derrière un point, filtrer un tableau sur une région sélectionnée, ou explorer un sous-ensemble.

Shiny de base vous donne les deux directions sans package supplémentaire. Un graphique réagit aux entrées via le graphe réactif que vous connaissez déjà ; et plotOutput() peut signaler les événements de clic et de sélection rectangulaire au server, où deux fonctions auxiliaires — nearPoints() et brushedPoints() — transforment les coordonnées brutes en véritables lignes de données. Cette leçon construit cela dans l’ordre : la paire de rendu, un graphique piloté par une entrée, puis les événements de clic et de sélection, et enfin un renvoi vers plotly pour une interactivité de survol et de zoom plus riche.

NoteCopiez n’importe quel bloc dans app.R et exécutez-le en local

Le code de cette page n’est pas exécuté ici — une application Shiny a besoin d’une session R active, elle ne peut donc pas tourner à l’intérieur d’une page web statique. Copiez n’importe quel bloc dans un fichier app.R et exécutez-le en local avec shiny::runApp() (ou cliquez sur Run App dans RStudio). Chaque extrait s’insère dans le ui et le server d’une application ; les exemples utilisent les jeux de données intégrés mtcars et faithful, ils tournent donc tels quels.

Pas de R installé ? Essayez un graphique interactif en direct dans votre navigateur — cliquez et sélectionnez des points, rien à configurer. Ouvrir dans le Playground ▸

La paire de rendu, rappel

Chaque graphique est constitué des deux mêmes moitiés que vous avez rencontrées dans affichages de sortie : un renderPlot() dans le server qui dessine la figure, et un plotOutput() dans le ui qui l’affiche, reliés par un id partagé. Cela fonctionne de la même façon pour base R et ggplot2 — renvoyez (ou dessinez) le graphique dans le corps.

# ui
plotOutput("scatter")

# server — base R
output$scatter <- renderPlot({
  plot(mtcars$wt, mtcars$mpg, xlab = "Weight", ylab = "MPG")
})
# server — ggplot2 (return the plot object)
output$scatter <- renderPlot({
  library(ggplot2)
  ggplot(mtcars, aes(wt, mpg)) +
    geom_point() +
    theme_minimal()
})

C’est tout le contrat — plotOutput("id") réserve l’emplacement, output$id <- renderPlot({ ... }) le remplit. Voir affichages de sortie pour chaque famille de rendu et les emplacements correspondants. Le reste de cette leçon consiste à faire agir ce graphique.

Faire réagir un graphique à une entrée

L’interactivité la plus simple ne nécessite aucune gestion d’événement. Référencez un input$<id> à l’intérieur du corps de renderPlot(), et Shiny redessine le graphique chaque fois que cette entrée change. Un curseur qui fixe le nombre de classes d’un histogramme, une liste déroulante qui choisit la variable — chacun réexécute le rendu automatiquement.

ui <- fluidPage(
  sliderInput("bins", "Bins:", min = 5, max = 50, value = 20),
  plotOutput("hist")
)

server <- function(input, output, session) {
  output$hist <- renderPlot({
    hist(faithful$waiting, breaks = input$bins,
         col = "#3a86d4", border = "white",
         main = "Old Faithful waiting times", xlab = "Minutes")
  })
}

Déplacez le curseur et l’histogramme se reclasse de lui-même. Il n’y a ni observateur, ni appel de mise à jour — input$bins se trouve à l’intérieur du corps de rendu, il devient donc une dépendance et Shiny réexécute le rendu chaque fois qu’il change. C’est le modèle réactif de programmation réactive à l’œuvre : la sortie dépend de l’entrée, elle se recalcule donc d’elle-même.

La même astuce pilote un nuage de points depuis une liste déroulante :

ui <- fluidPage(
  selectInput("xvar", "X variable:", choices = c("wt", "hp", "disp")),
  plotOutput("scatter")
)

server <- function(input, output, session) {
  output$scatter <- renderPlot({
    plot(mtcars[[input$xvar]], mtcars$mpg,
         xlab = input$xvar, ylab = "MPG", pch = 19, col = "#3a86d4")
  })
}

Choisissez une variable X différente et le graphique se redessine en fonction d’elle. Toute entrée que vous lisez dans le corps devient un déclencheur — c’est tout ce que signifie « graphique réactif ».

Événements de clic : lire où l’utilisateur a cliqué

Pour savoir sur le graphique l’utilisateur a cliqué, ajoutez un id click à plotOutput(). Shiny signale alors chaque clic sous forme de input$<id> — une petite list avec les coordonnées de tracé (x, y) et des informations de panneau. Vous ne calculez pas la position vous-même ; vous la lisez.

ui <- fluidPage(
  plotOutput("scatter", click = "plot_click"),
  verbatimTextOutput("info")
)

server <- function(input, output, session) {
  output$scatter <- renderPlot({
    plot(mtcars$wt, mtcars$mpg, pch = 19, col = "#3a86d4")
  })

  output$info <- renderPrint({
    req(input$plot_click)                 # wait until the user clicks
    cat("x =", input$plot_click$x, "  y =", input$plot_click$y)
  })
}

L’argument click = "plot_click" est ce qui rend le graphique cliquable ; sans lui le clic est ignoré. Après un clic, input$plot_click contient les coordonnées dans les unités propres du graphique, donc un clic près du coin supérieur droit du nuage mtcars donne un x élevé (poids) et un y élevé (MPG). Le req() a son importance : avant le premier clic input$plot_click vaut NULL, et lire input$plot_click$x sur NULL générerait une erreur — req() fait attendre la sortie tranquillement jusqu’à ce qu’il y ait un vrai clic.

D’un clic à la véritable ligne de données avec nearPoints()

Les coordonnées sont rarement ce que vous voulez — vous voulez la ligne sur laquelle l’utilisateur a cliqué. nearPoints() fait exactement cela : donnez-lui le data frame que vous avez tracé et l’objet de clic, et il renvoie les lignes proches du clic sous forme de data frame.

ui <- fluidPage(
  plotOutput("scatter", click = "plot_click"),
  tableOutput("near")
)

server <- function(input, output, session) {
  output$scatter <- renderPlot({
    plot(mtcars$wt, mtcars$mpg, pch = 19, col = "#3a86d4")
  })

  output$near <- renderTable({
    req(input$plot_click)
    nearPoints(mtcars, input$plot_click, xvar = "wt", yvar = "mpg")
  })
}

Cliquez sur un point et le tableau affiche la ligne complète de cette voiture. Deux choses font fonctionner nearPoints(), et se tromper sur l’une ou l’autre est la cause habituelle d’un résultat vide : passez le même data frame que celui que vous avez tracé (mtcars), et nommez les mêmes x et y avec xvar/yvar pour un graphique de base. Avec ggplot2 vous pouvez omettre xvar/yvar entièrement — nearPoints() lit le mappage aes() à partir du graphique :

output$scatter <- renderPlot({
  library(ggplot2)
  ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_minimal()
})

output$near <- renderTable({
  req(input$plot_click)
  nearPoints(mtcars, input$plot_click)   # mapping inferred from the ggplot
})

Événements de sélection rectangulaire : lire une région sélectionnée

Une sélection rectangulaire est un rectangle que l’utilisateur trace sur le graphique — l’outil pour sélectionner plusieurs points à la fois. Ajoutez un id brush à plotOutput() et Shiny signale la sélection sous forme de input$<id> : une list avec les limites du rectangle (xmin, xmax, ymin, ymax).

ui <- fluidPage(
  plotOutput("scatter", brush = "plot_brush"),
  tableOutput("selected")
)

server <- function(input, output, session) {
  output$scatter <- renderPlot({
    plot(mtcars$wt, mtcars$mpg, pch = 19, col = "#3a86d4")
  })

  output$selected <- renderTable({
    req(input$plot_brush)
    brushedPoints(mtcars, input$plot_brush, xvar = "wt", yvar = "mpg")
  })
}

Tracez une boîte sur un amas de points et le tableau se remplit de chaque ligne située à l’intérieur. brushedPoints() est le pendant de nearPoints() pour la sélection rectangulaire : même data frame, même règle de nommage x/y (et le même raccourci ggplot2 — omettez xvar/yvar et il lit le mappage). Là où nearPoints() renvoie la ou les quelques lignes proches d’un seul clic, brushedPoints() renvoie tout le sous-ensemble sélectionné — que vous pouvez ensuite alimenter dans un autre graphique, un résumé, ou un tableau filtré.

Un graphique peut porter les deux à la fois — nommez un id click et un id brush sur le même plotOutput(), et lisez chacun depuis son propre input$<id> :

plotOutput("scatter", click = "plot_click", brush = "plot_brush")

Survol et double-clic, brièvement

Deux autres événements suivent le même schéma, pour quand vous en avez besoin. Ajoutez hover = "id" et Shiny signale la position du curseur à mesure que l’utilisateur se déplace sur le graphique — utile pour une infobulle en direct, bien qu’il se déclenche souvent, gardez donc son gestionnaire léger. Ajoutez dblclick = "id" pour un double-clic — une association courante avec une sélection rectangulaire pour implémenter le zoom (double-clic pour réinitialiser). Les deux signalent la même list de coordonnées qu’un clic et se lisent de la même façon :

plotOutput("scatter", hover = "plot_hover", dblclick = "plot_dblclick")

Recourez d’abord à click et brush — ils couvrent la plupart des besoins « laisser l’utilisateur choisir quelque chose ». hover et dblclick sont là quand l’interaction l’exige.

Quand vous voulez le survol, le zoom et le déplacement : plotly

Les événements ci-dessus constituent la couche d’interactivité de Shiny de base — la sélection, pas la navigation dans le graphique. Quand vous voulez que le graphique lui-même soit interactif — infobulles au survol, zoom à la molette, déplacement, une barre d’outils — recourez à plotly, qui rend de véritables graphiques interactifs dans le navigateur. Il suit exactement la même règle d’association Shiny, juste avec ses propres fonctions de rendu et de sortie :

# ui
plotly::plotlyOutput("chart")

# server — wrap a ggplot, or build a plotly chart directly
output$chart <- plotly::renderPlotly({
  library(ggplot2)
  p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_minimal()
  plotly::ggplotly(p)        # hover, zoom, and pan come for free
})

ggplotly() convertit une figure ggplot2 existante en un graphique plotly interactif, vous gardez donc votre code de tracé familier et gagnez le survol/zoom. plotly a aussi son propre système d’événements (event_data() pour le survol, le clic et la sélection) — un sujet plus vaste que les événements de base et qui mérite une leçon à part entière. La règle empirique : utilisez click/brush de base pour sélectionner des points de données sur lesquels le server agira ; utilisez plotly quand le graphique doit être explorable de lui-même.

Quel événement pour quelle tâche

Une carte rapide des outils de graphique interactif et de ce à quoi sert chacun.

Vous voulez… Utilisez Récupérez les données avec
Redessiner le graphique quand une entrée change input$<id> à l’intérieur de renderPlot() — (réactif, automatique)
Savoir quel point l’utilisateur a cliqué plotOutput("p", click = "id") nearPoints(df, input$id)
Savoir quels points sont dans une région sélectionnée plotOutput("p", brush = "id") brushedPoints(df, input$id)
Suivre le curseur pour une infobulle en direct plotOutput("p", hover = "id") lire les coordonnées de input$id
Réinitialiser un zoom / une seconde action plotOutput("p", dblclick = "id") lire input$id
Infobulles au survol, zoom, déplacement dans le graphique plotly::renderPlotly / plotlyOutput plotly::event_data()

Le motif qui sous-tend tout cela ne change jamais : nommez l’événement sur plotOutput(), lisez-le depuis input$<id>, et — pour le clic et la sélection rectangulaire — laissez nearPoints() / brushedPoints() transformer les coordonnées en lignes.

Problèmes fréquents

input$plot_click vaut NULL et la sortie génère une erreur au démarrage. Un événement de clic ou de sélection rectangulaire n’a aucune valeur tant que l’utilisateur n’interagit pas réellement — au lancement input$plot_click et input$plot_brush valent NULL, et lire input$plot_click$x sur NULL lève une erreur. Mettez req(input$plot_click) (ou req(input$plot_brush)) en haut de la sortie pour qu’elle attende tranquillement une vraie interaction au lieu d’afficher brièvement une erreur rouge.

nearPoints() / brushedPoints() renvoie un data frame vide. Presque toujours une non-concordance : vous avez passé un data frame différent de celui que vous avez tracé, ou les mauvais xvar/yvar. La fonction auxiliaire a besoin du même data frame que celui que vous avez dessiné et, pour un graphique de base, des mêmes noms de colonnes que ceux mis sur les axes (xvar = "wt", yvar = "mpg"). Pour un graphique ggplot2 vous pouvez omettre xvar/yvar — mais seulement parce que la fonction auxiliaire lit le mappage aes(), le mappage doit donc correspondre aux données que vous passez.

Cliquer ne fait rien. Le plotOutput() n’a pas d’id click (ou brush). Ajouter nearPoints() dans le server ne suffit pas à lui seul — le graphique ne signale les clics que lorsque vous lui donnez plotOutput("p", click = "plot_click"). Vérifiez que l’id sur plotOutput() correspond à l’input$<id> que vous lisez dans le server.

Questions fréquentes

Ajoutez un id click à l’emplacement : plotOutput("scatter", click = "plot_click"). Shiny signale alors chaque clic sous forme de input$plot_click, une list avec les coordonnées x/y. Pour récupérer la ligne de données sur laquelle l’utilisateur a cliqué, passez cet objet à nearPoints(df, input$plot_click) dans le server (en nommant xvar/yvar pour un graphique de base). Protégez la lecture avec req(input$plot_click) pour qu’elle attende le premier clic.

Ajoutez un id brushplotOutput("scatter", brush = "plot_brush") — et passez le input$plot_brush résultant à brushedPoints(df, input$plot_brush). Il renvoie chaque ligne de df qui tombe à l’intérieur du rectangle tracé sous forme de data frame, que vous pouvez ensuite afficher dans un tableau, un graphique ou un résumé. Utilisez le même data frame que celui que vous avez tracé et, pour un graphique de base, les mêmes xvar/yvar.

Les deux transforment des coordonnées de graphique en lignes de données, mais pour des événements différents. nearPoints() fonctionne avec un clic et renvoie la ou les quelques lignes proches de l’endroit où l’utilisateur a cliqué. brushedPoints() fonctionne avec une sélection rectangulaire (un rectangle tracé) et renvoie toutes les lignes à l’intérieur de la sélection. Choisissez nearPoints() pour identifier un point unique, brushedPoints() pour saisir un sous-ensemble entier.

Pour un graphique qui réagit aux entrées, lisez simplement un input$<id> à l’intérieur de renderPlot() — il se redessine automatiquement quand l’entrée change. Pour la sélection par clic et par rectangle, ajoutez des ids click/brush à plotOutput() et lisez-les dans le server avec nearPoints()/brushedPoints(). Pour l’interactivité dans le graphique (infobulles au survol, zoom, déplacement), utilisez les renderPlotly/plotlyOutput de plotly, en enveloppant éventuellement un ggplot existant avec ggplotly().

La cause habituelle est une non-concordance de données ou d’axes. nearPoints() doit recevoir le même data frame que celui que vous avez tracé, et pour un graphique base R vous devez nommer les mêmes colonnes avec xvar et yvar (nearPoints(mtcars, input$plot_click, xvar = "wt", yvar = "mpg")). Avec ggplot2 vous pouvez les omettre parce que la fonction auxiliaire lit le mappage aes() — mais le mappage doit correspondre aux données que vous passez. Confirmez aussi que le plotOutput() a un id click ; sans lui il n’y a aucun clic à lire.

Testez vos connaissances

Partez d’un nuage de points de mtcars$wt contre mtcars$mpg. Rendez le graphique cliquable, et en dessous affichez un tableau avec la ligne de données complète de la voiture sur laquelle l’utilisateur clique. Utilisez le tracé base R, et protégez la sortie pour qu’elle ne génère pas d’erreur avant le premier clic.

Ajoutez click = "plot_click" à plotOutput(). Dans le server, dessinez le graphique avec plot(mtcars$wt, mtcars$mpg), puis dans un renderTable() appelez nearPoints(mtcars, input$plot_click, xvar = "wt", yvar = "mpg"). Mettez req(input$plot_click) en haut pour qu’il attende un clic. Les xvar/yvar doivent correspondre aux colonnes que vous avez tracées.

ui <- fluidPage(
  plotOutput("scatter", click = "plot_click"),
  tableOutput("clicked_row")
)

server <- function(input, output, session) {
  output$scatter <- renderPlot({
    plot(mtcars$wt, mtcars$mpg, pch = 19, col = "#3a86d4",
         xlab = "Weight", ylab = "MPG")
  })

  output$clicked_row <- renderTable({
    req(input$plot_click)                                   # wait for a click
    nearPoints(mtcars, input$plot_click,
               xvar = "wt", yvar = "mpg")
  })
}

shinyApp(ui, server)

Le click = "plot_click" fait signaler les clics par le graphique sous forme de input$plot_click ; nearPoints() utilise le même data frame et les mêmes colonnes wt/mpg pour renvoyer la ligne de la voiture cliquée ; et req() garde le tableau vide jusqu’à ce que l’utilisateur clique réellement.

Vous tracez un rectangle sur plusieurs points et voulez les lignes situées à l’intérieur. Le graphique est plotOutput("p", brush = "plot_brush") et vous avez tracé un nuage ggplot2 de wt contre mpg. Quelle ligne du server renvoie les lignes sélectionnées ?

A. nearPoints(mtcars, input$plot_brush) — elle récupère les points du graphique. B. brushedPoints(mtcars, input$plot_brush) — la sélection rectangulaire s’associe à brushedPoints. C. brushedPoints(mtcars, input$plot_click) — lire l’objet de clic. D. subset(mtcars, input$plot_brush) — filtrer avec base R.

B. Un événement de sélection rectangulaire s’associe à brushedPoints(), qui renvoie chaque ligne à l’intérieur du rectangle tracé ; parce que le graphique est une figure ggplot2, vous pouvez omettre xvar/yvar et la fonction auxiliaire lit le mappage aes(). A utilise la fonction auxiliaire de clic (nearPoints) sur un objet de sélection — la mauvaise fonction. C lit input$plot_click, qui n’est pas défini ici (il n’y a pas d’id click). D traite l’objet de sélection comme une condition de filtre, ce qu’il n’est pas — c’est une list de coordonnées, pas un vecteur logique.

Conclusion

Un graphique Shiny interactif a deux faces. Il réagit aux entrées gratuitement — lisez un input$<id> à l’intérieur de renderPlot() et la figure se redessine quand cette entrée change. Et il peut signaler ce que l’utilisateur fait : ajoutez un id click ou brush à plotOutput(), lisez l’événement depuis input$<id>, et transformez les coordonnées en véritables lignes de données avec nearPoints() (un clic) ou brushedPoints() (une région sélectionnée) — en passant le même data frame et les mêmes x/y que ceux que vous avez tracés, et en protégeant avec req() jusqu’à ce que l’utilisateur agisse. Quand vous avez besoin que le graphique lui-même soit explorable — survol, zoom, déplacement — plotly prend le relais avec la même règle d’association. La sélection est le travail de Shiny de base ; la navigation riche dans le graphique est celle de plotly.

Ensuite, vous donnerez à l’utilisateur un tableau triable et cherchable pour accompagner ces graphiques — le tableau de données interactif.

Leçons connexes

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Graphiques interactifs Shiny : événements clic et sélection
    en R},
  date = {2026-06-28},
  url = {https://www.datanovia.com/learn/programming/shiny/interactivity/plots-charts},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Graphiques interactifs Shiny : événements clic et sélection en R.” 2026. June 28. https://www.datanovia.com/learn/programming/shiny/interactivity/plots-charts.