Recapitulare: pornim de la sablon
library(shiny)
# interfata utilizator
ui <- fluidPage('Text oarecare')
# server
server <- function(input, output) {}
# rulare
shinyApp(ui = ui, server = server)
intuitiv: functioneaza similar cu Excel;
obiectele de tip output se modifica la fiecare schimbare a celor de tip input;
vrem sa controlam modul in care se fac aceste modificari (implicit instant);
la modificarile facute de utilizator, valorile lui input$nume se actuallizeaza instant
valorile input$… functioneaza doar in interiorul functiilor reactive de tip render(); nu pot fi apelate reactiv in afara unei functii render();
output$hist <- renderPlot({hist(rnorm(input$num))})
output$hist <- hist(rnorm(input$num))
in codul
library(shiny)
ui <- fluidPage(
sliderInput(inputId = 'num', label='alegeti un numar:', value=4, min=-10, max=10),
plotOutput('hist')
)
server <- function(input, output) {
output$hist <- hist(rnorm(input$num))
}
shinyApp(ui = ui, server = server)
obtinem eroarea:
Error in .getReactiveEnvironment()$currentContext() : Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
Reactivitatea se realizeaza in 2 pasi:
Utilizatorul modifica o valoare controlata de o functie Input(); In acel moment vechea valoare este considerata invalida;
Functia render(), care are rol de observator, corecteaza valoarea in codul ei (ruleaza tot codul) - de fiecare data cand o valoare este invalidata.
folosim functii render() pentru a afisa obiecte in ui;
rezultatul lor este salvat ca si componente ale output$;
Functiile render() se asociaza cu valori reactive;
Returneaza un obiect in functie de tipul de render() folosit (plot, table, etc…vezi Shiny Cheat Sheet)
functiile render() au un singur argument:
renderPlot( {} )
reprezentat de codul R dintre acolade:
- putem avea oricate linii de cod;
- va raspunde la toate modificarile valorilor reactive;
- codul va fi rulat in intregime la fiecare modificare a unei valori reactive input$...
library(shiny)
ui <- fluidPage(
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100),
textInput(inputId = "title",
label = "Write a title",
value = "Histogram of Random Normal Values"),
plotOutput("hist")
)
server <- function(input, output) {
output$hist <- renderPlot({
hist(rnorm(input$num), main = input$title)
})
}
shinyApp(ui = ui, server = server)
Sa luam un exemplu cu doua outputs:
library(shiny)
ui <- fluidPage(
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100),
plotOutput("hist"),
verbatimTextOutput("stats")
)
server <- function(input, output) {
output$hist <- renderPlot({
hist(rnorm(input$num))
})
output$stats <- renderPrint({
summary(rnorm(input$num))
})
}
shinyApp(ui = ui, server = server)
avem 1 input, 2 outputs
dar la fiecare modificare de input, fiecare render() genereaza alt set de date;
am vrea sa afisam summary pentru acelasi set pentru care desenam histograma
dar putem folosi input doar in interiorul unei functii reactive
pentru a putea folosi obiecte reactive in mai multe functii render() folosim reactive() pentru a defini obiecte reactive pe baza valorilor din input:
data <- reactive({rnorm(input$num)})
data este o expresie reactiva
reactive() functioneaza ca si render() dar creeaza expresii reactive (data)
library(shiny)
ui <- fluidPage(
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100),
plotOutput("hist"),
verbatimTextOutput("stats")
)
server <- function(input, output) {
data <- reactive({
rnorm(input$num)
})
output$hist <- renderPlot({
hist(data())
})
output$stats <- renderPrint({
summary(data())
})
}
shinyApp(ui = ui, server = server)
Acum histograma si summary sunt calculate pe baza acelorasi date, data().
De exemplu in aplicatia
library(shiny)
ui <- fluidPage(
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100),
textInput(inputId = "title",
label = "Write a title",
value = "Histogram of Random Normal Values"),
plotOutput("hist")
)
server <- function(input, output) {
output$hist <- renderPlot({
hist(rnorm(input$num), main = input$title)
})
}
shinyApp(ui = ui, server = server)
la fiecare modificare a unei litere din titlu se recalculeaza histograma…
library(shiny)
ui <- fluidPage(
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100),
textInput(inputId = "title",
label = "Write a title",
value = "Histogram of Random Normal Values"),
plotOutput("hist")
)
server <- function(input, output) {
output$hist <- renderPlot({
hist(rnorm(input$num), main = isolate(input$title))
})
}
shinyApp(ui = ui, server = server)
rezultatul lui isolate nu este actualizat de fiecare data cand input$title se modifica;
dar se actualizeaza de fiecare data cand alta valoare reactiva se modifica!
Folosim observeEvent() cand dorim sa efectuam operatii pe server, care nu afiseaza nimic in ui (salvare fisiere, incarcare date, etc.)
actionButton(inputId='clicks', label='click me, please!')
Daca il adaugam asa la template:
library(shiny)
ui <- fluidPage(
actionButton(inputId='clicks',label='click me, please!' )
)
server <- function(input, output){}
shinyApp(ui=ui, server=server)
apare un buton care nu face nimic.
Reactivitatea pentru buton se construieste cu
observeEvent(input$clicks, {print(input$clicks)})
primul argument este o lista de valori reactive a caror modificare conduce la rularea codului din {}
creeaza un obiect fara afisare pe ui, dar reactioneaza la schimbarile din lista input.
Daca in cod {} apar si alte valori reactive, acelea nu se vor actualiza;
codul e tratat ca si cum ar fi in functia isolate();
library(shiny)
ui <- fluidPage(
actionButton(inputId = "clicks",
label = "Click me")
)
server <- function(input, output) {
observeEvent(input$clicks, {
print(as.numeric(input$clicks))
})
}
shinyApp(ui = ui, server = server)
similar cu observeEvent(), render() si isolate() la un loc
are doar un argument, cod R in {}
observe({print(input$clicks)})
library(shiny)
ui <- fluidPage(
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100),
actionButton(inputId = "go",
label = "Update"),
plotOutput("hist")
)
server <- function(input, output) {
data <- eventReactive(input$go, {
rnorm(input$num)
})
output$hist <- renderPlot({
hist(data())
})
}
shinyApp(ui = ui, server = server)
folosim actionButton()
functia eventReactive() raspunde doar la anumite schimbari;
creeaza o expresie reactiva (la fel ca si reactive())
data <- eventReactive(input$go,
{
rnorm(input$num)
})
reactioneaza doar la modificarea lui input$go, dar ia in calcul valorile actualizate ale tuturor celorlaltor input..
In renderPlot folosim data().
input este o lista de valori reactive;
nu putem modifica aceste valori in partea de server;
putem insa sa ne creem noi o lista de valori reactive pe care apoi sa le modificam in cod
library(shiny)
ui <- fluidPage(
actionButton(inputId = "norm", label = "Normal"),
actionButton(inputId = "unif", label = "Uniform"),
plotOutput("hist")
)
server <- function(input, output) {
rv <- reactiveValues(data = rnorm(100))
observeEvent(input$norm, { rv$data <- rnorm(100) })
observeEvent(input$unif, { rv$data <- runif(100) })
output$hist <- renderPlot({
hist(rv$data)
})
}
shinyApp(ui = ui, server = server)
folosim observeEvent() pentru a modifica valorile reactive create de reactiveValues();
rv e o lista in care putem adauga si alte componente:
library(shiny)
ui <- fluidPage(
actionButton(inputId = "norm", label = "Normal"),
actionButton(inputId = "unif", label = "Uniform"),
plotOutput("hist")
)
server <- function(input, output) {
rv <- reactiveValues(data =rnorm(100), data1='normal')
observeEvent(input$norm, {
rv$data <- rnorm(100)
rv$data1='normal'
})
observeEvent(input$unif, {
rv$data <- runif(100)
rv$data1='uniform'
})
output$hist <- renderPlot({
hist(rv$data, main=rv$data1)
})
}
shinyApp(ui = ui, server = server)