Sourcer des fichiers dans une app Shiny

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Fred Santos
Messages : 233
Enregistré le : 11 Avr 2009, 10:00
Contact :

Sourcer des fichiers dans une app Shiny

Messagepar Fred Santos » 18 Juin 2019, 09:09

Bonjour à tous,

Je retravaille actuellement une appli shiny visible ici : https://gitlab.com/f.santos/anthropmmd/tree/devel
La plupart des fonctions R figurent dans le dossier inst/AnthropMMDShinyApp et ne sont pas exportées. Elles sont donc sourcées directement dans le fichier server.R, qui utilise un grand nombre de fonctions annexes.
Désormais, je souhaiterais exporter la plupart des fonctions et implémenter des tests unitaires. J'ai cru comprendre que pour faciliter l'implémentation des tests unitaires, il faudrait que mes fonctions se situent dans le dossier /R/ plutôt que le dossier /inst/. Bon, je prévois donc de déménager tout ça.

Le problème est le suivant : mon fichier server.R ne semble plus "voir" les fonctions annexes une fois qu'elles sont dans le dossier /R/. J'ai testé un grand nombre de variantes et de solutions, mais typiquement, indiquer ceci en préambule du fichier server.R :

Code : Tout sélectionner

source("../../R/max3.R", local = TRUE)
source("../../R/binary_to_table.R", local = TRUE)

ne fonctionne pas (alors qu'il s'agit bien du chemin relatif vers mes fonctions R en partant du fichier server.R), puisque j'obtiens ceci si je tente de lancer l'appli :

Code : Tout sélectionner

> StartMMD()
Loading required package: shiny

Listening on http://127.0.0.1:4518
Warning in file(filename, "r", encoding = encoding) :
  impossible d'ouvrir le fichier '../../R/max3.R' : Aucun fichier ou dossier de ce type
Warning: Error in file: impossible d'ouvrir la connexion
  50: file
  49: source
  48: server [/home/fsantos/R/x86_64-pc-linux-gnu-library/3.6/AnthropMMD/AnthropMMDShinyApp/server.R#8]
Error in file(filename, "r", encoding = encoding) :
  impossible d'ouvrir la connexion



Lorsque le fichier server.R est dans un dossier donné, et qu'on souhaite sourcer des fonctions R se situant dans un dossier complètement différent dans l'arborescence du package, comment est-on censé procéder ?

Merci !

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Sourcer des fichiers dans une app Shiny

Messagepar Mickael Canouil » 18 Juin 2019, 10:52

Bonjour,

Pourquoi vouloir sourcer les fonctions de votre package au sein même de celui-ci ?
Toutes les fonctions d'un package ont accès à l'ensemble des fonction du dit package ("/R"), que ces fonctions soient ou non exportées.

Les tests unitaire ne sont pas vraiment fonctionnelles (du moins avec le package "testhat") pour les fonctions (app) shiny.
Il y a "shinytest" (pas encore utilisé).

J'ai personnellement opté pour que l'application shiny soit intégralement contenu dans une fonction, i.e., sans appel à "system.file".

https://github.com/mcanouil/NACHO
Fonction shiny: https://github.com/mcanouil/NACHO/blob/ ... isualise.R

Au cas où vous n'auriez pas connaissance, je vous recommande le livre R packages, d'autant plus si vous voulez publier votre package sur le CRAN.

edit: au passage testhat "travaille" dans l'environnement du package, il ne se soucis donc pas que les fonctions soit exportés (accessible via package::fonction) ou non (accessible via package:::fonction)

Cordialement,
Mickaël
mickael.canouil.fr | rlille.fr

Fred Santos
Messages : 233
Enregistré le : 11 Avr 2009, 10:00
Contact :

Re: Sourcer des fichiers dans une app Shiny

Messagepar Fred Santos » 18 Juin 2019, 11:44

Bonjour Mickael et merci pour la réponse !
Mickael Canouil a écrit :Pourquoi vouloir sourcer les fonctions de votre package au sein même de celui-ci ?
Toutes les fonctions d'un package ont accès à l'ensemble des fonction du dit package ("/R"), que ces fonctions soient ou non exportées.

À priori, ça semble particulier dans le cadre d'une appli shiny (ou alors un truc m'échappe vraiment). C'est assez simple à vérifier : si je supprime ou commente l'ensemble de mes commandes "source" dans server.R, j'obtiens immédiatement un crash dès que je veux importer un fichier dans l'appli :

Code : Tout sélectionner

> StartMMD()
Loading required package: shiny

Listening on http://127.0.0.1:5110
Warning: Error in validDataMMD: impossible de trouver la fonction "validDataMMD"
  73: observeEventHandler [/home/fsantos/R/x86_64-pc-linux-gnu-library/3.6/AnthropMMD/AnthropMMDShinyApp/server.R#32]
   2: runApp
   1: StartMMD

(validDataMMD étant tout simplement la première fonction externe appelée par server.R, et donc la première erreur produite : clairement, le "source" était donc nécessaire.)
Certes, validDataMMD n'est pas exportée, et il semble que ce soit le cœur du problème (et que ça m'oblige donc à sourcer cette fonction manuellement).

Mickael Canouil a écrit :edit: au passage testhat "travaille" dans l'environnement du package, il ne se soucis donc pas que les fonctions soit exportés (accessible via package::fonction) ou non (accessible via package:::fonction

À condition effectivement (toujours si j'ai bien pigé) que les fonctions considérées se trouvent dans "/R/" et pas dans "/inst/", auquel cas testthat ne les trouvera pas non plus.
D'où mon blocage : je suis contraint de déplacer mes fonctions depuis "inst" vers "R" afin que testthat les trouve ; mais du coup c'est mon server.R qui ne les trouve plus... Ça reste un peu opaque pour moi en l'état :-)

J'ai personnellement opté pour que l'application shiny soit intégralement contenu dans une fonction, i.e., sans appel à "system.file".

Je vais regarder ça, merci ! Mais cette approche me semble produire d'énormes fichiers nettement plus difficiles à maintenir. Ceci dit, s'il faut en passer par là, ça ne me gêne pas outre mesure.

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Sourcer des fichiers dans une app Shiny

Messagepar Mickael Canouil » 18 Juin 2019, 14:54

edit: Voici un petit exemple d'un package avec deux fonctions, une interne, et une exportée qui lance une application shiny utilisant une feuille de style css dans le dossier /inst/css:
https://gist.github.com/mcanouil/aa49a4 ... 966ce367a8

Code : Tout sélectionner

usethis::create_package(path = "~/mypackage", rstudio = FALSE, open = FALSE)
usethis::use_package(package = c("stats", "graphics"), type = "Imports")
usethis::use_package(package = "shiny", type = "Depends")

dir.create(path = "~/mypackage/inst/css", recursive = TRUE)
cat("\n", file = "~/mypackage/inst/css/file.css")

cat("#' show_app
#'
#' @export
show_app <- function() {
  shiny::addResourcePath('my_style', system.file('css', package = 'mypackage'))
  ui <- shiny::fluidPage(theme = 'my_style/file.css',
    shiny::titlePanel('Hello Shiny!'),
    shiny::sidebarLayout(
      shiny::sidebarPanel(
        shiny::sliderInput(
          inputId = 'obs',
          label = 'Number of observations:',
          min = 0,
          max = 1000,
          value = 500
        )
      ),
      shiny::mainPanel(
        shiny::plotOutput('distPlot')
      )
    )
  )
 
  server <- function(input, output) {
    output$distPlot <- shiny::renderPlot({
      obj <- identity(input$obs)
      graphics::hist(stats::rnorm(obj))
    })
  }
   
  app <- shiny::shinyApp(
    ui = ui,
    server = server
  )
  shiny::runApp(app)
}",  file = "~/mypackage/R/show_app.R")

cat("#' identity
#'
#' @param x any R object
#' @keywords internal
#'
#' @return x
identity <- function(x) x",  file = "~/mypackage/R/identity.R")

devtools::document("~/mypackage")
devtools::build("~/mypackage")

install.packages("~/mypackage_0.0.0.9000.tar.gz")

library(mypackage)
show_app()
Mickaël
mickael.canouil.fr | rlille.fr

Fred Santos
Messages : 233
Enregistré le : 11 Avr 2009, 10:00
Contact :

Re: Sourcer des fichiers dans une app Shiny

Messagepar Fred Santos » 18 Juin 2019, 18:40

Woh, merci d'avoir pris le temps de faire tout ça ! ;-) Il faut que je me pose un peu pour étudier ça, mais je devrais pouvoir me débrouiller ! Merci infiniment !

PS : j'avais vu ta première réponse où tu disais que le code R ne devait pas se trouver dans le répertoire "inst", et dans le fond je suis d'accord. Mais j'avais suivi ce que disait cette réponse sur SO : https://stackoverflow.com/a/37833866/11238320
Globalement, cette organisation des fichiers marchait très bien... tant qu'il n'était pas question d'essayer des tests unitaires :-) Merci d'avoir proposé autre chose donc !

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Sourcer des fichiers dans une app Shiny

Messagepar Mickael Canouil » 19 Juin 2019, 08:22

PS : j'avais vu ta première réponse où tu disais que le code R ne devait pas se trouver dans le répertoire "inst", et dans le fond je suis d'accord. Mais j'avais suivi ce que disait cette réponse sur SO : https://stackoverflow.com/a/37833866/11238320
Globalement, cette organisation des fichiers marchait très bien... tant qu'il n'était pas question d'essayer des tests unitaires :-)


Tout fonctionne, si on bidouille suffisamment ...

C'est plus une question de bonne pratique de développement et pour une publication sur le CRAN, il vaut mieux suivre certains principes pour le publier rapidement (c.-à-d., entre les tests automatisés et les vérifications manuelles, pour soumettre une première version, cela peut nécessiter quelques soumissions).
Mickaël
mickael.canouil.fr | rlille.fr


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité