You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
19KB

  1. ---
  2. title: CRHAP
  3. runtime: shiny
  4. output:
  5. html_document:
  6. toc: true
  7. toc_float: true
  8. ---
  9. ```{r init, warning = F, message = F, echo = F}
  10. library(tidyverse)
  11. library(DT)
  12. library(magrittr)
  13. library(stringr)
  14. library(knitr)
  15. library(lubridate)
  16. library(plotly)
  17. opts_chunk$set(warning = F,
  18. message = F,
  19. fig.width = 9,
  20. fig.height = 6,
  21. echo = F)
  22. options(DT.options = list(paging = F,
  23. info = F,
  24. searching = F,
  25. dom = "Bfrtip",
  26. buttons = c('copy', 'excel')),
  27. shiny.maxRequestSize = 500*1024^2)
  28. pdf(NULL)
  29. ```
  30. # {.tabset}
  31. ## Méthode
  32. ### Chargement des données
  33. Le fichier doit être fournis au format CSV avec les paramètres suivants :
  34. * séparateur de champs = ,
  35. * guillemets = "
  36. * encodage = UTF-8
  37. * séparateur de décimales = ,
  38. Il doit être issu de la [requête suivante](CRHAP.wid).
  39. ```{r data}
  40. inputPanel(
  41. numericInput("mois", "Mois", (Sys.Date() %>% month) - 1),
  42. numericInput("annee", "Année", Sys.Date() %>% year),
  43. fileInput("crhap", "CRHAP", accept = "text/csv"),
  44. downloadButton("report", "Générer le rapport")
  45. )
  46. CRH <- reactive(
  47. {
  48. req(input$crhap, input$annee, input$mois)
  49. read_csv(input$crhap$datapath, col_types = cols(`Numéro d'hospitalisation` = col_character()), progress = F) %>%
  50. setNames(c("RUM", "NDA", "DP", "GHM", "Notes", "Pole", "Service", "Date_DP", "Date_sortie")) %>%
  51. mutate(Notes = Notes %>%
  52. str_to_upper %>%
  53. str_replace_all(" ", "") %>%
  54. str_replace("CHR", "CRH") %>%
  55. str_extract("CRH."),
  56. Notes = ifelse(Notes %in% c("CRHP", "CRHA"), Notes, NA),
  57. Date_DP = as.Date(Date_DP),
  58. Date_sortie = as.Date(Date_sortie),
  59. Delai = as.numeric(Date_DP - Date_sortie),
  60. Pole = ifelse(Pole == "GSP : GÉRONTOLOGIE ET SOINS PALLIATIFS", "GSP", Pole),
  61. Pole = ifelse(Pole == "POLE LORRAIN DE CHIRURGIE DE L'APPAREIL LOCOMOTEUR", "CCEG", Pole)) %>%
  62. filter(!(Service %in% c("MEDECINE INFANTILE", "NEPHROLOGIE") & DP == "Z49.1"),
  63. !(Service %in% c("AMP CLINIQUE", "ORTHOGENIE"))) %>%
  64. filter(Date_sortie < ceiling_date(as.Date(str_c(input$annee, "-", input$mois, "-01")), unit = "month"),
  65. Date_sortie > floor_date(as.Date(str_c(input$annee - 1, "-", input$mois, "-01")), unit = "month")) %>%
  66. mutate(Notes = ifelse(Service == "STRUCTURE D'URGENCES" & Delai <= 15 & is.na(Notes), "CRHP", Notes),
  67. Mois = str_c(year(Date_sortie), "-", str_pad(month(Date_sortie), 2, "left", "0")))
  68. }
  69. )
  70. CRH_sans_seance <- reactive(
  71. {
  72. req(CRH())
  73. CRH() %>%
  74. filter(!(GHM %>% str_detect("^28")))
  75. }
  76. )
  77. CRH_seance <- reactive(
  78. {
  79. req(CRH())
  80. CRH() %>%
  81. filter(GHM %>% str_detect("^28"))
  82. }
  83. )
  84. mois_label <- c("Janvier",
  85. "Février",
  86. "Mars",
  87. "Avril",
  88. "Mai",
  89. "Juin",
  90. "Juillet",
  91. "Août",
  92. "Septembre",
  93. "Octobre",
  94. "Novembre",
  95. "Décembre")
  96. ```
  97. ```{r report}
  98. output$report <- downloadHandler(filename = "CRHAP.html",
  99. content = function(file)
  100. {
  101. tempReport <- file.path(tempdir(), "CRHAP.Rmd")
  102. file.copy("CRHAP.Rmd", tempReport, overwrite = T)
  103. rmarkdown::render(tempReport, output_file = file, params = list(CRH = CRH(), CRH_seance = CRH_seance(), CRH_sans_seance = CRH_sans_seance()))
  104. })
  105. ```
  106. ### Présence du CRH pour le codage des séjours
  107. Ces tableaux concernent les RUMs sur une année glissante.
  108. Les RUMs **sans DP** et **codés en erreur** (CMD 90) sont **exclus** de l'analyse.
  109. Le pourcentage d'absents est calculé sur la **totalité** des RUMs, *Non renseignés* compris.
  110. Le délai médian est le délai médian entre la date de fin du RSS et la date de codage du DP pour le RUM.
  111. Les données sont disponibles avec les **séances incluses**, et les **séances excluses**.
  112. Les séances automatiquement codées (dialyse en néphrologie et médecine infantile) sont *exclues*.
  113. Les séjours en AMP clinique et orthogénie sont également *exclus*.
  114. Les séjours automatiquement codés d'UHCD (séjour en UHCD avec délai de codage <= 15j et sans marque de codage) sont considérés comme *#CRHP*.
  115. Il est possible pour chaque tableau de **trier** chaque colonne en cliquant sur son intitulé.
  116. Pour les tableaux par service, il est également possible de **filtrer** par pôle ou selon les valeurs (par exemple, ne faire apparaître que les services avec plus de 50% de CRH absents).
  117. Les tableaux sont **exportables** sous Excel à l'aide du bouton en haut à gauche de chaque tableau.
  118. **Attention : les *tris* et *filtres* sont pris en compte pour l'export !**
  119. ----
  120. ### Saisie
  121. Les marques **#CRHA** (CRH absent) et **#CRHP** (CRH présent) sont saisies dans les **Notes** lors du codage des séjours dans WebPIMS.
  122. #### Format
  123. Les marques sont saisies selon le format suivant :
  124. * marque en début de Notes
  125. * précédée du #
  126. * tout attaché
  127. * attention aux fautes de frappe ! (#C*HR*P, #CR*PH*)
  128. * **seules ces marques seront analysées !**
  129. #### Conditions
  130. Les marques sont saisies selon les conditions suivantes :
  131. * **\#CRHP** dès lors qu'un compte-rendu permettant le codage du séjour est présent :
  132. * au moins un CRH lors de l'hospitalisation
  133. * CRH papier accepté
  134. * CRH au «mauvais» format accepté
  135. * CRH pour venues multiples (séances) accepté
  136. * **\#CRHA** dès lors qu'il n'existe aucun compte-rendu d'aucune forme permettant le codage du séjour, et **en respectant un délai d'au moins une semaine après la fin de l'hospitalisation**.
  137. Il est recommandé de coder les séjours par ordre **chronologique**.
  138. ----
  139. ### Analyse
  140. #### Extraction
  141. Les marques sont extraites par le médecin DIM responsable de la clôture, à l'aide d'une requête BO dans l'univers **WebPIMS MCO Prod**. Cette requête est exécutée tous les mois, *une semaine après la clôture mensuelle*. Les marques sont tirées des RUMs remplissant les conditions suivantes :
  142. * RUM de RSS sorti durant la période allant du début de ce recueil (avril 2016) à la fin du mois de la dernière clôture
  143. * les RUMs sans DP (non codés) sont *exclus*
  144. * les RUMs de RSS groupés en erreur sont *exclus*
  145. #### Traitement
  146. Les données extraites sont séparées en trois groupes pour l'analyse :
  147. * tous RUMs confondus
  148. * RUMs séances uniquement
  149. * RUMs à l'exclusion des séances
  150. Pour chaque jeu de données, les tableaux suivants sont générés :
  151. * par mois de sortie du **RSS**
  152. * par pôle
  153. * par service
  154. Chaque tableau présente les indicateurs suivants :
  155. * le nombre de RUMs dans le mois/pôle/service concerné
  156. * le nombre de RUMs avec marque #CRHP
  157. * le nombre de RUMs avec marque #CRHA
  158. * le nombre de RUMs non marqués
  159. * le **pourcentage de #CRHA**, calculé par rapport au nombre total de RUMs (y compris RUMs non marqués)
  160. ## Rapport
  161. ### Tous RUMs confondus
  162. #### Par mois
  163. ```{r}
  164. renderDataTable({
  165. CRH() %>%
  166. count(Mois, Notes) %>%
  167. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  168. spread(Notes, n) %>%
  169. full_join(CRH() %>% count(Mois)) %>%
  170. select(Mois, RUM = n, CRHP, CRHA, Manquant) %>%
  171. full_join(CRH() %>% group_by(Mois) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  172. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  173. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  174. `% absents` = CRHA / RUM) %>%
  175. datatable(rownames = F,
  176. extensions = 'Buttons',
  177. colnames = c("Non renseigné" = "Manquant",
  178. "#CRHA" = "CRHA",
  179. "#CRHP" = "CRHP")) %>%
  180. formatPercentage(7)
  181. })
  182. ```
  183. <br/>
  184. ```{r}
  185. renderPlotly({
  186. CRH() %>%
  187. ggplot(aes(x = Mois, fill = Notes)) +
  188. geom_bar(position = "fill") +
  189. ylab("Proportion") +
  190. ggtitle("Proportion des #CRHA et #CRHP par mois de sortie du RSS") -> p
  191. ggplotly(p)
  192. })
  193. ```
  194. #### Par Pôle
  195. ```{r}
  196. renderDataTable({
  197. CRH() %>%
  198. count(Pole, Notes) %>%
  199. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  200. spread(Notes, n) %>%
  201. full_join(CRH() %>% count(Pole)) %>%
  202. select(Pole, RUM = n, CRHP, CRHA, Manquant) %>%
  203. full_join(CRH() %>% group_by(Pole) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  204. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  205. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  206. `% absents` = CRHA / RUM) %>%
  207. datatable(rownames = F,
  208. extensions = 'Buttons',
  209. colnames = c("Pôle" = "Pole",
  210. "Non renseigné" = "Manquant",
  211. "#CRHA" = "CRHA",
  212. "#CRHP" = "CRHP")) %>%
  213. formatPercentage(7)
  214. })
  215. ```
  216. <br/>
  217. ```{r}
  218. renderPlotly({
  219. CRH() %>%
  220. ggplot(aes(x = Pole, fill = Notes)) +
  221. geom_bar(position = "fill") +
  222. ylab("Proportion") +
  223. ggtitle("Proportion des #CRHA et #CRHP par pôle, depuis avril 2016") +
  224. theme(axis.text.x = element_text(angle = -45, hjust = 1)) -> p
  225. ggplotly(p)
  226. })
  227. ```
  228. #### Par Pôle, par service et par mois
  229. ```{r}
  230. renderDataTable({
  231. CRH() %>%
  232. count(Pole, Service, Mois, Notes) %>%
  233. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  234. spread(Notes, n) %>%
  235. full_join(CRH() %>% count(Pole, Service, Mois)) %>%
  236. ungroup %>%
  237. select(Pole, Service, Mois, RUM = n, CRHP, CRHA, Manquant) %>%
  238. full_join(CRH() %>% group_by(Pole, Service, Mois) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  239. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  240. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  241. `% absents` = CRHA / RUM,
  242. Pole = Pole %>% factor,
  243. Mois = Mois %>% factor) %>%
  244. datatable(rownames = F,
  245. extensions = 'Buttons',
  246. colnames = c("Pôle" = "Pole",
  247. "Non renseigné" = "Manquant",
  248. "#CRHA" = "CRHA",
  249. "#CRHP" = "CRHP"),
  250. filter = "top",
  251. options = list(searching = T, paging = T)) %>%
  252. formatPercentage(9)
  253. })
  254. ```
  255. <br/>
  256. ```{r}
  257. renderPlotly({
  258. CRH() %>%
  259. count(Pole, Mois, Notes) %>%
  260. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  261. spread(Notes, n) %>%
  262. mutate(Manquant = ifelse(is.na(Manquant), integer(1), Manquant),
  263. CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  264. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  265. pourcent = CRHA / (CRHA + CRHP + Manquant)) %>%
  266. ggplot(aes(x = Mois, y = pourcent, colour = Pole, group = Pole)) +
  267. geom_line(stat = "identity") +
  268. geom_point() +
  269. ylab("Proportion de #CRHA") +
  270. ggtitle("Évolution des proportions de #CRHA par pôle") -> p
  271. ggplotly(p, tooltip = c("x", "y", "colour"))
  272. })
  273. ```
  274. ----
  275. ### RUMs non séance
  276. #### Par mois
  277. ```{r}
  278. renderDataTable({
  279. CRH_sans_seance() %>%
  280. count(Mois, Notes) %>%
  281. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  282. spread(Notes, n) %>%
  283. full_join(CRH_sans_seance() %>% count(Mois)) %>%
  284. select(Mois, RUM = n, CRHP, CRHA, Manquant) %>%
  285. full_join(CRH_sans_seance() %>% group_by(Mois) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  286. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  287. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  288. `% absents` = CRHA / RUM) %>%
  289. datatable(rownames = F,
  290. extensions = 'Buttons',
  291. colnames = c("Non renseigné" = "Manquant",
  292. "#CRHA" = "CRHA",
  293. "#CRHP" = "CRHP")) %>%
  294. formatPercentage(7)
  295. })
  296. ```
  297. <br/>
  298. ```{r}
  299. renderPlotly({
  300. CRH_sans_seance() %>%
  301. ggplot(aes(x = Mois, fill = Notes)) +
  302. geom_bar(position = "fill") +
  303. ylab("Proportion") +
  304. ggtitle("Proportion des #CRHA et #CRHP par mois de sortie du RSS") -> p
  305. ggplotly(p)
  306. })
  307. ```
  308. #### Par Pôle
  309. ```{r}
  310. renderDataTable({
  311. CRH_sans_seance() %>%
  312. count(Pole, Notes) %>%
  313. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  314. spread(Notes, n) %>%
  315. full_join(CRH_sans_seance() %>% count(Pole)) %>%
  316. select(Pole, RUM = n, CRHP, CRHA, Manquant) %>%
  317. full_join(CRH_sans_seance() %>% group_by(Pole) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  318. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  319. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  320. `% absents` = CRHA / RUM) %>%
  321. datatable(rownames = F,
  322. extensions = 'Buttons',
  323. colnames = c("Pôle" = "Pole",
  324. "Non renseigné" = "Manquant",
  325. "#CRHA" = "CRHA",
  326. "#CRHP" = "CRHP")) %>%
  327. formatPercentage(7)
  328. })
  329. ```
  330. <br/>
  331. ```{r}
  332. renderPlotly({
  333. CRH_sans_seance() %>%
  334. ggplot(aes(x = Pole, fill = Notes)) +
  335. geom_bar(position = "fill") +
  336. ylab("Proportion") +
  337. ggtitle("Proportion des #CRHA et #CRHP par pôle, depuis avril 2016") +
  338. theme(axis.text.x = element_text(angle = -45, hjust = 1)) -> p
  339. ggplotly(p)
  340. })
  341. ```
  342. #### Par Pôle, par service et par mois
  343. ```{r}
  344. renderDataTable({
  345. CRH_sans_seance() %>%
  346. count(Pole, Service, Mois, Notes) %>%
  347. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  348. spread(Notes, n) %>%
  349. full_join(CRH_sans_seance() %>% count(Pole, Service, Mois)) %>%
  350. ungroup %>%
  351. select(Pole, Service, Mois, RUM = n, CRHP, CRHA, Manquant) %>%
  352. full_join(CRH_sans_seance() %>% group_by(Pole, Service, Mois) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  353. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  354. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  355. `% absents` = CRHA / RUM,
  356. Pole = Pole %>% factor,
  357. Mois = Mois %>% factor) %>%
  358. datatable(rownames = F,
  359. extensions = 'Buttons',
  360. colnames = c("Pôle" = "Pole",
  361. "Non renseigné" = "Manquant",
  362. "#CRHA" = "CRHA",
  363. "#CRHP" = "CRHP"),
  364. filter = "top",
  365. options = list(searching = T, paging = T)) %>%
  366. formatPercentage(9)
  367. })
  368. ```
  369. <br/>
  370. ```{r}
  371. renderPlotly({
  372. CRH_sans_seance() %>%
  373. count(Pole, Mois, Notes) %>%
  374. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  375. spread(Notes, n) %>%
  376. mutate(Manquant = ifelse(is.na(Manquant), integer(1), Manquant),
  377. CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  378. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  379. pourcent = CRHA / (CRHA + CRHP + Manquant)) %>%
  380. ggplot(aes(x = Mois, y = pourcent, colour = Pole, group = Pole)) +
  381. geom_line(stat = "identity") +
  382. geom_point() +
  383. ylab("Proportion de #CRHA") +
  384. ggtitle("Évolution des proportions de #CRHA par pôle") -> p
  385. ggplotly(p, tooltip = c("x", "y", "colour"))
  386. })
  387. ```
  388. ----
  389. ### RUMs séance
  390. #### Par mois
  391. ```{r}
  392. renderDataTable({
  393. CRH_seance() %>%
  394. count(Mois, Notes) %>%
  395. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  396. spread(Notes, n) %>%
  397. full_join(CRH_seance() %>% count(Mois)) %>%
  398. select(Mois, RUM = n, CRHP, CRHA, Manquant) %>%
  399. full_join(CRH_seance() %>% group_by(Mois) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  400. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  401. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  402. `% absents` = CRHA / RUM) %>%
  403. datatable(rownames = F,
  404. extensions = 'Buttons',
  405. colnames = c("Non renseigné" = "Manquant",
  406. "#CRHA" = "CRHA",
  407. "#CRHP" = "CRHP")) %>%
  408. formatPercentage(7)
  409. })
  410. ```
  411. <br/>
  412. ```{r}
  413. renderPlotly({
  414. CRH_seance() %>%
  415. ggplot(aes(x = Mois, fill = Notes)) +
  416. geom_bar(position = "fill") +
  417. ylab("Proportion") +
  418. ggtitle("Proportion des #CRHA et #CRHP par mois de sortie du RSS") -> p
  419. ggplotly(p)
  420. })
  421. ```
  422. #### Par Pôle
  423. ```{r}
  424. renderDataTable({
  425. CRH_seance() %>%
  426. count(Pole, Notes) %>%
  427. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  428. spread(Notes, n) %>%
  429. full_join(CRH_seance() %>% count(Pole)) %>%
  430. select(Pole, RUM = n, CRHP, CRHA, Manquant) %>%
  431. full_join(CRH_seance() %>% group_by(Pole) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  432. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  433. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  434. `% absents` = CRHA / RUM) %>%
  435. datatable(rownames = F,
  436. extensions = 'Buttons',
  437. colnames = c("Pôle" = "Pole",
  438. "Non renseigné" = "Manquant",
  439. "#CRHA" = "CRHA",
  440. "#CRHP" = "CRHP")) %>%
  441. formatPercentage(7)
  442. })
  443. ```
  444. <br/>
  445. ```{r}
  446. renderPlotly({
  447. CRH_seance() %>%
  448. ggplot(aes(x = Pole, fill = Notes)) +
  449. geom_bar(position = "fill") +
  450. ylab("Proportion") +
  451. ggtitle("Proportion des #CRHA et #CRHP par pôle, depuis avril 2016") +
  452. theme(axis.text.x = element_text(angle = -45, hjust = 1)) -> p
  453. ggplotly(p)
  454. })
  455. ```
  456. #### Par Pôle, par service et par mois
  457. ```{r}
  458. renderDataTable({
  459. CRH_seance() %>%
  460. count(Pole, Service, Mois, Notes) %>%
  461. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  462. spread(Notes, n) %>%
  463. full_join(CRH_seance() %>% count(Pole, Service, Mois)) %>%
  464. ungroup %>%
  465. select(Pole, Service, Mois, RUM = n, CRHP, CRHA, Manquant) %>%
  466. full_join(CRH_seance() %>% group_by(Pole, Service, Mois) %>% summarise(`Délai médian (j)` = median(Delai))) %>%
  467. mutate(CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  468. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  469. `% absents` = CRHA / RUM,
  470. Pole = Pole %>% factor,
  471. Mois = Mois %>% factor) %>%
  472. datatable(rownames = F,
  473. extensions = 'Buttons',
  474. colnames = c("Pôle" = "Pole",
  475. "Non renseigné" = "Manquant",
  476. "#CRHA" = "CRHA",
  477. "#CRHP" = "CRHP"),
  478. filter = "top",
  479. options = list(searching = T, paging = T)) %>%
  480. formatPercentage(9)
  481. })
  482. ```
  483. <br/>
  484. ```{r}
  485. renderPlotly({
  486. CRH_seance() %>%
  487. count(Pole, Mois, Notes) %>%
  488. mutate(Notes = ifelse(is.na(Notes), "Manquant", Notes)) %>%
  489. spread(Notes, n) %>%
  490. mutate(Manquant = ifelse(is.na(Manquant), integer(1), Manquant),
  491. CRHA = ifelse(is.na(CRHA), integer(1), CRHA),
  492. CRHP = ifelse(is.na(CRHP), integer(1), CRHP),
  493. pourcent = CRHA / (CRHA + CRHP + Manquant)) %>%
  494. ggplot(aes(x = Mois, y = pourcent, colour = Pole, group = Pole)) +
  495. geom_line(stat = "identity") +
  496. geom_point() +
  497. ylab("Proportion de #CRHA") +
  498. ggtitle("Évolution des proportions de #CRHA par pôle") -> p
  499. ggplotly(p, tooltip = c("x", "y", "colour"))
  500. })
  501. ```