R-Shiny best practice voor grotere app

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
In ben geconfronteerd met een R-Shiny webapplicatie. Een omgeving die nieuw voor me is. Nu loop ik tegen het volgende aan en vraag me af hoe jullie hier tegenaan kijken?

Een deel van deze applicatie betreft een soort gastenboek. Je hebt dus een lijst reacties, en een eerste, vorige, volgende en laatste knop. Ook is er een veld dat aangeeft op welke pagina je zit.

In de applicatie is dit nu geprogrammeerd dat bij het openen van de reacties 6 keer alle reacties uit de database worden opgehaald. Een keer voor alle knoppen te bedienen (zijn ze wel of niet actief) en een keer voor het daadwerkelijk tonen van de reacties.

Nu ben ik aan het kijken hoe je dit nu anders zou kunnen aanpakken vanuit mijn ervaring met MVC en specifiek andere frameworks zoals Angular.

Het nadeel van R-Shiny is volgens mij echter dat het niet met expliciete controllers werkt. Het is niet makkelijk om data over meerdere GUI elementen te gelijk te delen.

Nu heb ik een opzet uitgewerkt die in de buurt van een controller komt zodat ik de interactie tussen GUI elementen beter kan compartimenteren in modules, pagina's modulair kan opzetten op basis van die compartimenten en ook efficiënt de communicatie tussen pagina's mogelijk maak.

Nu is alles aan alles geknoopt zonder enige vorm van modulariteit.

Ik vraag me af of wat ik probeer te bereiken niet veel makkelijker kan en of er niet best practices zijn die ik nog niet gevonden had. De zoekterm R-Shiny MVC levert echter maar weinig zinnige reacties op.

S:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
library(shiny)

service <- reactiveValues();

ui <- fluidPage(
   fluidRow(
      column(3,
         h3("Schakelaar 1"),
         actionButton("action1", "on")
      ),
      column(3,
         h3("Schakelaar 2"),
         actionButton("action2", "on")
      )
   )
)

blok1 <- function(input, output, session, acties) {
   values <- reactiveValues(status = 1);

   updateButton <- function() {
      if(valus$status == 0) {
         updateActionButton(session, "action1", "on");
         values$status <- 1;
      } else {
         updateActionButton(session, "action1", "off");
         values$status <- 0;
      }

      acties$blok1 = -1;
      observeEvent(input$action1, {
         updateButton();
      });

      observeEvent(acties$blok1, {
         updateButton();
      })
   }
}

blok2 <- function(input, output, session, acties) {
   values <- reactiveValues(status = 1);

   observeEvent(input$action2, {
      if(valus$status == 0) {
         updateActionButton(session, "action2", "on");
         values$status <- 1;
      } else {
         updateActionButton(session, "action2", "off");
         values$status <- 0;
      }
      if(!is.null(acties$blok1)) {
         acties$blok1 <- acties$blok1 + 1;
      }
   });
}

pagina <- function(input, output, session) {
   acties <- reactiveValues();

   blok1(input, output, session, acties);
   blok2(input, output, session, acties);
}

server <- function(input, output, session) {
   pagina(input, output, session);
}

shinyApp(ui = ui, server = server);


Als ik nu op schakelaar 1 druk dan schakelt alleen schakelaar 1. Als ik op schakelaar 2 druk dan schakelen beide schakelaars.

Voordelen van deze aanpak:
- Mijn caches zitten nu in een local scope en zijn te gebruiken voor alle UI elementen binnen mijn compartiment.
- Ik kan modulair mijn pagina's en compartimenten opbouwen met hun eigen scopes en vooraf gedefinieerde acties. Dat maakt het makkelijker om het geheel modulair te maken en te ontkoppelen.
- Het is vrij makkelijk te documenteren.
- Communicatie tussen pagina's zou op dezelfde manier kunnen worden vormgegeven zoals nu tussen mijn blokken.
- Angular 'services' zijn mogelijk door in mijn global scope een reactiveValues object te maken.

Uitdaging:
- Grootste uitdaging is nu om ook de ui van de app modulair te maken en mee te laten lopen met mijn controllers.

Ik hoop dat ik het een beetje helder heb kunnen toelichten, want R(-shiny) is niet echt mijn domein :)

Sinds de 2 dagen regel reageer ik hier niet meer

Alle reacties


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
Helemaal niemand hier ervaring met R-Shiny? Op zich kan ik daar ook wel een antwoord over het gewenste gebruik van R-Shiny uit destilleren :p

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Postman
  • Registratie: Februari 2000
  • Laatst online: 12-09 01:23
CurlyMo schreef op maandag 9 maart 2020 @ 08:11:
Helemaal niemand hier ervaring met R-Shiny? Op zich kan ik daar ook wel een antwoord over het gewenste gebruik van R-Shiny uit destilleren :p
Lijkt inderdaad een erg niche framework. Sowieso zijn er al niet veel mensen die met R werken in vergelijking met bijvoorbeeld C(derivaten) of Java.
Je kunt https://www.reddit.com/r/rshiny/ nog proberen. Of anders Stackoverflow.

Wel erg duidelijke en uitgebreide probleem formulering, jammer inderdaad dat je dan geen hulp krijgt.

Acties:
  • 0 Henk 'm!

  • GrooV
  • Registratie: September 2004
  • Laatst online: 16-09 16:01
Dit is gewoon een probleem en risico van niche frameworks. Grote frameworks zijn echt niet heilig maar hebben wel echt een hele grote community wat een hele grote plus is.

Het hoeft geen probleem te zijn als je veel kennis inhouse hebt maar zodra die weg is over het overgedragen moet worden wordt het lastig.

Acties:
  • +2 Henk 'm!

  • luxan
  • Registratie: April 2014
  • Laatst online: 10-09 10:37
Shiny is ook geen framework maar een manier om de resultaten van data analyses toegankelijk te maken via een web-browser. Een gastenboek maken op basis van Shiny is daarom ook een zeer slecht idee.

Onderstaand URL geeft een mogelijke oplossing voor het probleem waar je nu mee zit.
https://www.r-bloggers.com/the-shiny-module-design-pattern/

De beste oplossing IMHO is het gastenboek omschrijven naar een framework dat gemaakt is voor dit soort applicaties, je zit nu R code te schrijven die getranspiled word naar JavaScript code, niet echt efficient.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
@luxan ik ken je die pagina, maar dat heeft me niet overtuigd dat ik zo dichter bij mijn doel kom.

De omgeving is daarbij nu eenmaal voor me gekozen, dus ik moet het ermee doen.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • RobLemmens
  • Registratie: Juni 2003
  • Laatst online: 16-09 14:28
Ik heb helaas ooit een demo in R gegeven met een shiny interface voor een forecast.. had ik dat maar nooit in shiny gedaan, feature na feature kwam erbij en geen echte mogelijkheid om het modulair op te lossen behalve op de r manier.... include. Het is goed om een presentatie van je data mee te maken, meer moet je echt niet willen. Je zou met classes kunnen werken (S3/S4 of R6 :p) om het misschien begrijpelijk te houden (voor zover mogelijk in r classes) maar hoe groter het word hoe harder je jezelf in de voet gaat schieten als je er een jaar later onderhoud aan moet doen want de manier waarop het werkt forceert rampzalige code (ik eindig iig altijd met 1 grote spaghetti in een R/Shiny project en ben niet bepaald onervaren in R)

Wat als je iets wil dat shiny niet standaard kan? Het is in theorie allemaal mogelijk maar de implementatie is zo enorm ruk dat het niet normaal te doen is als je .net omgevingen gewend bent, begin maar niet over debuggen...

Sorry voor de rant op shiny, je hebt er niets aan maar hopelijk herschrijf je het in iets anders wat minder werk is dan shiny voor je laten werken in iets dat meer interactief is dan een [ok] knop.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
De consensus (tot nu toe is) dat R niet geschikt is voor web development. Als we het dan hebben over alternatieven?

R wordt niet voor niks gebruikt. Dat is niet gekozen om alleen maar website mee te maken. Dat zou heel raar zijn geweest. Er werd al R gebruikt voor alle statistische en data-analyse doeleinden, en toen is daar net als @RobLemmens schrijft van het een het ander gekomen.

Wat adviseren jullie binnen die context:
- R blijven gebruiken en aanvullen met een ander framework / taal? Welke?
- R helemaal vervangen door iets anders? Welke alternatieve zijn er die zowel data-analyse / statistiek kunnen als web development?
- R blijven gebruiken en de issues met R-Shiny voor lief nemen?

@RobLemmens wat heb jij gedaan in jouw situatie?

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Tk55
  • Registratie: April 2009
  • Niet online
Eens met @luxan.

Maar om toch iets nuttigs te zeggen:
- laad bij het openen van de pagina alle reacties in het geheugen.
- genereer de knoppen die naar vorige of volgende gaan en hun id meegeven.
- genereer de knop voor de laatste.
- bij het drukken van een knop, update je alle knoppen en de tekst.

Dus, in pseudo code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Laad alle reacties
reacties <- ["hoi", "mooie app!", "doei"]
current_index <- 1 # houd huidige index bij

text <- reacties[current_index]
updateText(text)
updatePrevButton(index=current_index-1)
updateNextButton(index=current_index+1)
setLastButton(index=-1) # altijd zelfde index

# observeer button clicks
observe( button click,
    current_index <<- clickedButton$index
    text <<- reacties[current_index]
    updateText(text)
    updatePrevButton(index=current_index-1)
    updateNextButton(index=current_index+1)
)

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
Tk55 schreef op zondag 15 maart 2020 @ 08:59:
Eens met @luxan.

Maar om toch iets nuttigs te zeggen:
- laad bij het openen van de pagina alle reacties in het geheugen.
- genereer de knoppen die naar vorige of volgende gaan en hun id meegeven.
- genereer de knop voor de laatste.
- bij het drukken van een knop, update je alle knoppen en de tekst.

Dus, in pseudo code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Laad alle reacties
reacties <- ["hoi", "mooie app!", "doei"]
current_index <- 1 # houd huidige index bij

text <- reacties[current_index]
updateText(text)
updatePrevButton(index=current_index-1)
updateNextButton(index=current_index+1)
setLastButton(index=-1) # altijd zelfde index

# observeer button clicks
observe( button click,
    current_index <<- clickedButton$index
    text <<- reacties[current_index]
    updateText(text)
    updatePrevButton(index=current_index-1)
    updateNextButton(index=current_index+1)
)
Er zijn meerdere dingen die me tegen staan aan zo'n oplossingen:
1. Je moet alle reacties inladen om relatief simpele metadata handelingen te kunnen doen.
2. Je moet allerlei synchronisatie mechanismes inrichten wanneer er reacties bijkomen. Anders zit je bij elke handeling weer de volledige set aan reacties in te laden om de metadata te kunnen bijwerken.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Tk55
  • Registratie: April 2009
  • Niet online
@CurlyMo
1. Je kan ook alleen de ID's inladen, en op basis van de gegeven id de text ophalen. Maar ik weet niet hoe groot je database is. Dit kan natuurlijk nog steeds lastig zijn met veel data.
2. Je kan je "last" knop ook altijd de reactie met max(id) op laten halen. Dan heb je alleen nog wat logica nodig voor de "next" knop wanneer je dicht bij het einde komt en er mogelijk al nieuwe reacties zijn.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
Tk55 schreef op zondag 15 maart 2020 @ 10:56:
@CurlyMo
1. Je kan ook alleen de ID's inladen, en op basis van de gegeven id de text ophalen. Maar ik weet niet hoe groot je database is. Dit kan natuurlijk nog steeds lastig zijn met veel data.
2. Je kan je "last" knop ook altijd de reactie met max(id) op laten halen. Dan heb je alleen nog wat logica nodig voor de "next" knop wanneer je dicht bij het einde komt en er mogelijk al nieuwe reacties zijn.
Punt blijft wel dat je altijd je volledige query aan het draaien bent. Of dat nu alleen voor de ID's is of voor de hele set aan gegevens. En dat is mogelijk ook van toepassing op punt twee.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Tk55
  • Registratie: April 2009
  • Niet online
@CurlyMo Het ligt echt volledig aan je toepassing of dat een probleem is/wordt. Hoeveel gebruikers en reacties heb je?

Acties:
  • 0 Henk 'm!

  • Postman
  • Registratie: Februari 2000
  • Laatst online: 12-09 01:23
En om helemaal terug te komen op je eigen topicstart: is het geen optie R te implementeren als een soort van (verkapte) REST api? En dan vervolgens een front-end MVC framework te gebruiken om de problemen die je nu ervaart op te vangen (je hebt al ervaring met Angular dus ik zie dat als een goede oplossing).
Gebruik je dan nog Shiny? Nee denk het niet. Stap je helemaal af van R? Ook niet. Lijkt mij een manier om het beste van twee werelden te verenigen.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
Tk55 schreef op zondag 15 maart 2020 @ 11:03:
@CurlyMo Het ligt echt volledig aan je toepassing of dat een probleem is/wordt. Hoeveel gebruikers en reacties heb je?
Wat nog niet is kan altijd komen. Niet is permanenter dan een tijdelijke oplossing ;)
Postman schreef op zondag 15 maart 2020 @ 11:28:
En om helemaal terug te komen op je eigen topicstart: is het geen optie R te implementeren als een soort van (verkapte) REST api? En dan vervolgens een front-end MVC framework te gebruiken om de problemen die je nu ervaart op te vangen (je hebt al ervaring met Angular dus ik zie dat als een goede oplossing).
R als API provider is ook wel een goed idee.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • RobLemmens
  • Registratie: Juni 2003
  • Laatst online: 16-09 14:28
CurlyMo schreef op zondag 15 maart 2020 @ 08:51:

@RobLemmens wat heb jij gedaan in jouw situatie?
Ik heb het gesplitst, R geintegreerd in het backend en daar laten rekenen. Vervolgens de data ontsloten in een .net frontend, dat hele stuk ontwikkeling heeft minder tijd gekost dan zoeken naar een fout in datumafhandeling door een package die ergens geinclude werd door weer een of ander package... zodra R projecten groot worden wordt het echt lastig.. het is er dan ook niet echt voor bedoeld.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
@RobLemmens En was de hele backend op python draaien met numpy en scipy geen optie geweest?

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • RobLemmens
  • Registratie: Juni 2003
  • Laatst online: 16-09 14:28
CurlyMo schreef op zondag 15 maart 2020 @ 15:27:
@RobLemmens En was de hele backend op python draaien met numpy en scipy geen optie geweest?
Jazeker, alleen had verder niemand bij ons echte kennis van python en zijn libraries dus leek het ons verstandiger in .net te blijven, ook omdat we veel andere software inhaken die ook onder .net draait.

Acties:
  • 0 Henk 'm!

  • Morrar
  • Registratie: Juni 2002
  • Laatst online: 08:20
Redelijk wat ervaring met R en Shiny en grotendeels eens met wat er al gezegd is. Grote applicaties in R is gewoon geen succes (oa vanwege name spacing) en Shiny al helemaal niet. Sowieso zou ik server en UI splitsen en eventueel via library() extra code inladen.

Maar dan nog blijft de UI opbouwen in Shiny een horkerige constructie met al die HTML wrapper functies. Overigens kan je er ook gewoon ruwe HTML in mixen, maar de vraag is of je daar blij van wordt.

Persoonlijk zou ik voor productie werk / grotere projecten eerder naar Python kijken. Daar kun je met Streamlit, of Dash / plotly redelijk snel wat opzetten. Of als je echt custom moet hebben is Flask altijd nog mogelijk. Heb je in ieder geval jinja als fatsoenlijke template engine.

R code kun je als het moet integreren in Python met rpy2, maar vrijwel alle ML modellen kun je ook in Python wel vinden (scikig-learn / statsmodels) en data prep is met pandas ook simpel.

Of inderdaad proberen R als API op te zetten (of scores te laten dumpen in file / DB). Dan kun je de visualisatie helemaal lostrekken en wellicht zelfs met bijvoorbeeld een PowerBI of Tableau doen.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 17-09 22:26
Ik zat zelf gisteren eens te kijken naar Python web development frameworks en waarbij men al snel Django noemt. De andere libraries die genoemd zijn ken ik qua webdev niet, alleen van horen zeggen. Ik zal me er eens in verdiepen.

Pandas en numpy ken ik natuurlijk wel.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Morrar
  • Registratie: Juni 2002
  • Laatst online: 08:20
Django is inderdaad het bekenste web framework voor Python; ik heb er nooit mee echt mee gewerkt, maar het schijnt behoorlijk feature complete te zijn.

Vraag is of het niet een beetje overkill is voor wat je probeert te bereiken; een (interactief) dashboardje kan je waarschijnlijk veel sneller in elkaar knutselen in een tool / package dat daar specifiek voor bedoeld is.

Streamlit (https://www.streamlit.io/) komt wat dat betreft nog het meest in de buurt bij Shiny qua opzet en werking. Het heeft echter ook een beetje last van dezelfde nadelen, al is het iets beter doordacht.

Dash (https://plot.ly/dash/) kent iets meer mogelijkheden, maar vergt ook wat meer werk. In feite is het Flask + jinja + react voor UI en Plotly voor de grafieken (als ik het me goed herinner). Denk dat je hier wat meer flexibel mee bent ten koste van een wat grotere tijdsinvestering.

[ Voor 3% gewijzigd door Morrar op 17-03-2020 11:09 ]


Acties:
  • 0 Henk 'm!

  • MissDenise
  • Registratie: Mei 2019
  • Laatst online: 17-06-2022
Mocht je nog niet het antwoord hebben wat je zoekt, er is een community speciaal voor programmeren met R (in R-studio) waar je misschien wat meer aan hebt..
https://community.rstudio.com/
Pagina: 1