Cristiano de Carvalho Santos
O Shiny é um sistema para desenvolvimento de aplicações web usando o R, um pacote do R (shiny) e um servidor web (shiny server). O Shiny é exatamente isso e nada mais, portanto Shiny não é uma página web.
inputPanel(
# configurando o objeto n_breaks
selectInput("n_breaks", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 20),
# configurando o objeto bw_adjust
sliderInput("bw_adjust", label = "Bandwidth adjustment:",
min = 0.2, max = 2, value = 1, step = 0.2)
)
renderPlot({
hist(faithful$eruptions, probability = TRUE, breaks = as.numeric(input$n_breaks),
xlab = "Duration (minutes)", main = "Geyser eruption duration")
dens <- density(faithful$eruptions, adjust = input$bw_adjust)
lines(dens, col = "blue")
})Cria o painel para que o usuário possa interagir. Para isso, precisamos adicionar os inputs.
Na prática, inputs são widgets que possibilitam a interação do usuário com o app. Eles recebem um valor escolhido pelo usuário e o envia para o server side. Segue uma lista dos principais inputs utilizados num Shiny app:
Os outputs devem ser construídos com funções render_(). Existe uma função render_() para cada tipo de objeto.
As principais são:
shinyAppDir(
system.file("examples/06_tabsets", package = "shiny"),
options = list(
width = "100%", height = 550
)
)O aplicativo que está sendo carregado esta em {C://Program Files//R//R-3.5.1//library//shiny//examples//06_tabsets}.
Mas é possível fazer a mesma coisa em um documento ou apresentação sem ter que fazer um aplicativo.
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select the random distribution type ----
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
# br() element to introduce extra vertical spacing ----
br(),
# Input: Slider for the number of observations to generate ----
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
d <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB", border = "white")
})
# Generate an HTML table view of the data ----
output$table <- renderTable({
d()
})
# Generate a summary of the data ----
output$summary <- renderPrint({
summary(d())
})runExample("01_hello") # a histogram
runExample("02_text") # tables and data frames
runExample("03_reactivity") # a reactive expression
runExample("04_mpg") # global variables
runExample("05_sliders") # slider bars
runExample("06_tabsets") # tabbed panels
runExample("07_widgets") # help text and submit buttons
runExample("08_html") # Shiny app built from HTML
runExample("09_upload") # file upload wizard
runExample("10_download") # file download wizard
runExample("11_timer") # an automated timerlibrary(shiny)
# Define a interface do usuário para o app que gera um histograma.
ui <- fluidPage(
# Título do app.
titlePanel("Meu primeiro shiny app!"),
# Barra lateral com as definições do input e do output.
sidebarLayout(
# Barra lateral para os inputs.
sidebarPanel(
# Input: número de classes do histograma.
sliderInput(inputId = "classes",
label = "Número de classes:",
min = 1,
max = 30,
value = 10)
),
# Painel principal para mostrar os outputs.
mainPanel(
# Output: Histograma
plotOutput(outputId = "distPlot")
)
)
)
# Define o código necessário para a construção de um histograma.
server <- function(input, output) {
# Função que gera o histograma e devolve para o user side.
# Essa função é reativa. Isso significa que o histograma
# vai mudar sempre que o valor do número de classes mudar.
output$distPlot <- renderPlot({
x <- mtcars$mpg
bins <- seq(min(x), max(x), length.out = input$classes + 1)
hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Milhas por galão",
main = "Histograma do número de milhas rodadas por galão de combustível.")
})
}
shinyApp(ui = ui, server = server)ui <- fluidPage(
titlePanel("Título"),
sidebarLayout(
sidebarPanel("Painel lateral"),
mainPanel("Painel principal")
)
)Tudo o que será apresentado ao usuário está guardado no objeto ui, que nada mais é do que um código HTML.
A função fluidPage() utilizada como exemplo acima é utilizada pelo Shiny para criar um display que automaticamente ajusta as dimensões da janela do navegador do usuário. Os elementos da interface do usuário são então colocados dentro dessa função.
As funções titlePanel() e sidebarLayout() são os argumentos da função fluidPage(). A primeira gera o título “Título”, enquanto a segunda estrutura um layout com barra lateral para o app.
A função sidebarLayout() recebe dois argumentos:
ui <- fluidPage(
titlePanel("Meu primeiro shiny app!"),
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "classes",
label = "Número de classes:",
min = 1,
max = 30,
value = 10)
),
mainPanel(
plotOutput(outputId = "distPlot")
)
)
)Repare que a função sliderInput() recebe alguns argumentos.
Cada input terá argumentos específicos da própria função. Assim, se você nunca usou um determinado input, procure no help() da função quais são os argumentos que ela recebe.
No exemplo do histograma, o input do nosso app era o número de classes e o output era o próprio histograma. Veja que no objeto ui temos o seguinte código:
mainPanel(
plotOutput(outputId = "distPlot")
)Isso quer dizer que vamos receber um output do tipo “plot” (gráfico) do servidor e colocá-lo dentro do mainPanel().
Da mesma forma que há uma função para cada tipo de input, há uma função para cada tipo de output:
Assim como as funções de input, funções de output recebem um argumento de identificação, o outputId=. Esse argumento recebe uma string que representa o nome utilizado no server side para se referir a esse output. Consulte o help() de cada função para saber mais sobre os argumentos adicionais.
Criados os inputs e outputs do app, agora precisamos manipulá-los no server side.
Com a interface do usuário estruturada, precisamos agora implementar a função server(). Nela, colocaremos as instruções para gerar os outputs que nós vemos no user side a partir dos valores dos inputs que o usuário escolher.
A primeira coisa que precisamos fazer é defini-la. A função server() será sempre uma função que recebe dois argumentos: input e output.
server <- function(input, output) {
# Código
}A partir daí, precisamos seguir três regras:
server <- function(input, output) {
output$distPlot <- renderPlot({
x <- mtcars$mpg
bins <- seq(min(x), max(x), length.out = input$classes + 1)
hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Milhas por galão",
main = "Histograma do número de milhas rodadas por galão de combustível.")
})
}Repare nas {} dentro da função renderPlot().
Sempre que você usar um input dentro de uma função render_(), o seu output se tornará reativo ao valor do input. Isso significa que, sempre que o usuário mudar o valor do input, o Shiny atualizará automaticamente o valor dentro da lista e também todas as funções render_() que dependam dele.
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput(inputId = "num",
label = "Número de observações",
value = 100)
),
mainPanel(plotOutput(outputId = "hist"))
)
)
server <- function(input, output) {
output$hist <- renderPlot({hist(rnorm(input$num))})
}
shinyApp(ui = ui, server = server)O fluxo de reatividade será sempre conduzido por valores e funções reativas. Os objetos dentro da lista input são os principais objetos reativos e as funções render_() são as principais funções reativas.
Um fluxo básico seria o seguinte:
O Shiny disponibiliza funções para manipular a reatividade, alterando o fluxo básico apresentado acima.
Em http://material.curso-r.com/shiny/ encontramos: