学习路线:Start—Build—Improve—Share
中文转载:知乎R-Shiny
Shiny—Server:Shiny—Server教程
Get Started
Lesson 2 Build a user interface
library(shiny)
# Define UI ----
ui <- fluidPage(
)
# Define server logic ----
server <- function(input, output) {
}
# Run the app ----
shinyApp(ui = ui, server = server)
在所有的Lesson中均使用sidebar layout,若想了解更多的layout,请查看:Shiny Application Layout Guide
任何在HTML中使用的tag attribute都可以在这里使用:
ui <- fluidPage(
titlePanel("My Star Wars App"),
sidebarLayout(
sidebarPanel(),
mainPanel(
h2("their first victory against the", align = "center"),
p("p creates a paragraph of text."),
p("A new p() command starts a new paragraph. Supply a style attribute to change the format of the entire paragraph.", style = "font-family: 'times'; font-si16pt"),
strong("strong() makes bold text."),
em("em() creates italicized (i.e, emphasized) text."),
br(),
code("code displays your text similar to computer code"),
div("div creates segments of text with a similar style. This division of text is all blue because I passed the argument 'style = color:blue' to div", style = "color:blue"),
br(),
p("span does the same thing as div, but it works with",
span("groups of words", style = "color:blue"),
"that appear inside a paragraph.")
)
)
)
关于图片,在文件目录下建立一个www目录,把所有的图片文件都存到这个目录下。
其他的HTML的属性:通过HTML定制UI
Lesson 3 Add control widgets
每个widget函数具有多个参数:
- a name for the widget:character string,类似于html的id。
- a label:就是对widget进行一个解释性的说明,提示文字:prompt?
ui <- fluidPage(
titlePanel("Basic widgets"),
fluidRow(
column(3,
h3("Buttons"),
actionButton("action", "Action"),
br(),
br(),
submitButton("Submit")),
column(3,
h3("Single checkbox"),
checkboxInput("checkbox", "Choice A", value = TRUE)),
column(3,
checkboxGroupInput("checkGroup",
h3("Checkbox group"),
choices = list("Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3),
selected = 1)),
column(3,
dateInput("date",
h3("Date input"),
value = "2014-01-01"))
),
fluidRow(
column(3,
dateRangeInput("dates", h3("Date range"))),
column(3,
fileInput("file", h3("File input"))),
column(3,
h3("Help text"),
helpText("Note: help text isn't a true widget,",
"but it provides an easy way to add text to",
"accompany other widgets.")),
column(3,
numericInput("num",
h3("Numeric input"),
value = 1))
),
fluidRow(
column(3,
radioButtons("radio", h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2,
"Choice 3" = 3),selected = 1)),
column(3,
selectInput("select", h3("Select box"),
choices = list("Choice 1" = 1, "Choice 2" = 2,
"Choice 3" = 3), selected = 1)),
column(3,
sliderInput("slider1", h3("Sliders"),
min = 0, max = 100, value = 50),
sliderInput("slider2", "",
min = 0, max = 100, value = c(25, 75))
),
column(3,
textInput("text", h3("Text input"),
value = "Enter text..."))
)
)
helptext,lable可以考虑使用;除此之外,在Shiny Widget Gallery中,提供更多的模板。
Lesson 4 Display reactive output
为你的shiny项目添加交互功能!
- 在用户界面上添加R对象
- 告诉Shiny在server函数中如何构建对象,当代码可以调用窗口值的时候,对象可交互
Shiny为你的用户界面提供了一系列的函数,每个函数指定了一个特别的输出:
Output function | Creates |
---|---|
dataTableOutput | DataTable |
htmlOutput | raw HTML |
imageOutput | image |
plotOutput | plot |
tableOutput | table |
textOutput | text |
uiOutput | raw HTML |
verbatimTextOutput | text |
在sidebarPanel里选择,在mainPanel里输出:
ui <- fluidPage(
titlePanel("censusVis"),
sidebarLayout(
sidebarPanel(
helpText("Create demographic maps with
information from the 2010 US Census."),
selectInput("var",
label = "Choose a variable to display",
choices = c("Percent White",
"Percent Black",
"Percent Hispanic",
"Percent Asian"),
selected = "Percent White"),
sliderInput("range",
label = "Range of interest:",
min = 0, max = 100, value = c(0, 100))
),
mainPanel(
textOutput("selected_var")
)
)
)
交互的控制需要依赖于server函数中的操作:
server <- function(input, output) {
output$selected_var <- renderText({
"You have selected this"
})
}
The server
function plays a special role in the Shiny process; it builds a list-like object named output
that contains all of the code needed to update the R objects in your app. Each R object needs to have its own entry in the list.
You can create an entry by defining a new element for output
within the server
function, like below. The element name should match the name of the reactive element that you created in the ui
.
In the server
function below, output$selected_var
matches textOutput("selected_var")
in your ui
.
server 函数在Shiny中非常特别,它创建了一个类似于列表的output对象,该对象包含了所有在app中所有需要被更新的R对象;每个R对象的列表都需要它自己的entry(入口)?你可以在server函数中,通过定义一个新的元素创建一个entry(入口),元素的名字应该与在ui中创建的交互式元素名一致。在上面的server函数中,output$selected_var匹配ui中textOutput("selected_var)。
Each entry to output
should contain the output of one of Shiny’s render*
functions. These functions capture an R expression and do some light pre-processing on the expression. Use the render*
function that corresponds to the type of reactive object you are making.
每个output的entry(入口)应该包括一个Shiny render函数的的输出。这些函数捕捉R的表达式,并且在这些表达式上做一些预先处理。对不同类型的交互对象,应该使用不同的render函数:
render function | creates |
---|---|
renderDataTable | DataTable |
renderImage | images (saved as a link to a source file) |
renderPlot | plots |
renderPrint | any printed output |
renderTable | data frame, matrix, other table like structures |
renderText | character strings |
renderUI | a Shiny tag object or HTML |
每个render函数仅接受一个R表达式{},这个表达式可以为文本,或者很复杂的代码。或者为Shiny可以稍后执行的一系列的指令(更新时则执行)。
server <- function(input, output) {
output$selected_var <- renderText({
paste("You have selected", input$var)
})
output$slidered_range <- renderText({
paste("You have chosen a range that goes from ",
input$range[1], " to ", input$range[2])
})
}
Lesson 5 Use R scripts and data
在项目目录下建立一个文件夹:data
为了使用percent_map,需要下载1.数据 2.helpers.R,然后安装(由于网站比较慢,我在csdn中上传了资源(免费自取链接))
install.packages(c("maps", "mapproj"))
To use percent_map
, we first ran helpers.R
with the source
function, and then loaded counties.rds
with the readRDS
function. We also ran library(maps)
and library(mapproj)
.
- The
shinyApp
function is run once, when you launch your app(整个shinyApp项目在你运行的时候执行一遍) - The
server
function is run once each time a user visits your app(server函数在每一次有用户进入时执行) - The R expressions inside
render*
functions are run many times. Shiny runs them once each time a user change the value of a widget.(render函数里的东西在任意一个用户交互的时候执行)
从这三条我们可以得出
- 源脚本,库,数据这些东西,在server函数外,app.R最上头写,Shiny只会执行一遍这些内容;sever函数中的内容在服务器上执行
- 针对每个用户的内容写在server内,render外,这是每个用户独有的一份对象;类似于session,这个代码run once per user.
- 用户对每个widget操作,对操作的交互内容放在render函数内(re-run),为了提高效率,需要把不改变的内容放在render外,避免效率低下的问题
根据选择人种,显示相应的percent_map:
server <- function(input, output) {
output$map <- renderPlot({
data <- switch(input$var,
"Percent White" = counties$white,
"Percent Black" = counties$black,
"Percent Hispanic" = counties$hispanic,
"Percent Asian" = counties$asian
)
color <- switch(input$var,
"Percent White" = "darkgreen",
"Percent Black" = "black",
"Percent Hispanic" = "darkorange",
"Percent Asian" = "darkviolet"
)
legend <- switch(input$var,
"Percent White" = "% White",
"Percent Black" = "% Black",
"Percent Hispanic" = "%Hispanic",
"Percent Asian" = "% Asian"
)
percent_map(var = data, color = color, legend = legend, max = input$range[2], min = input$range[1])
})
}
更简便的写法:
server <- function(input, output) {
output$map <- renderPlot({
args <- switch(input$var,
"Percent White" = list(counties$white, "darkgreen", "% White"),
"Percent Black" = list(counties$black, "black", "% Black"),
"Percent Hispanic" = list(counties$hispanic, "darkorange", "% Hispanic"),
"Percent Asian" = list(counties$asian, "darkviolet", "% Asian"))
args$min <- input$range[1]
args$max <- input$range[2]
do.call(percent_map, args)
})
}
Lesson 6 Use Reactive expressions
通过使用交互式表达式,wow your user,避免不必要的计算!
# Load packages ----
library(shiny)
library(quantmod)
# Source helpers ----
source("helpers.R")
# User interface ----
ui <- fluidPage(
titlePanel("stockVis"),
sidebarLayout(
sidebarPanel(
helpText("Select a stock to examine.
Information will be collected from Yahoo finance."),
textInput("symb", "Symbol", "SPY"),
dateRangeInput("dates",
"Date range",
start = "2013-01-01",
end = as.character(Sys.Date())),
br(),
br(),
checkboxInput("log", "Plot y axis on log scale",
value = FALSE),
checkboxInput("adjust",
"Adjust prices for inflation", value = FALSE)
),
mainPanel(plotOutput("plot"))
)
)
# Server logic
server <- function(input, output) {
output$plot <- renderPlot({
data <- getSymbols(input$symb, src = "yahoo",
from = input$dates[1],
to = input$dates[2],
auto.assign = FALSE)
chartSeries(data, theme = chartTheme("white"),
type = "line", log.scale = input$log, TA = NULL)
})
}
# Run the app
shinyApp(ui, server)
这里的renderPlot,在每次widget改变的时候,都会重新加载一次数据(浪费)。
通过使用reactive function,就可以解决这个问题:
dataInput <- reactive({
getSymbols(input$symb, src = "yahoo",
from = input$dates[1],
to = input$dates[2],
auto.assign = FALSE)
})
output$plot <- renderPlot({
chartSeries(dataInput(), theme = chartTheme("white"),
type = "line", log.scale = input$log, TA = NULL)
})
Reactive表达式缓存值,并且了解什么时候这个值是过时的,第一次运行这个函数的时候,它会把结果(数据)保存在计算机内存里,当下一次调用这个函数的时候,它能不经过任何计算,返回保存的值(数据)。
Reactive表达式只会返回最新的结果,如果reactive表达式知道结果(数据)已经过时,因为widget已改变,这个表达式会重新计算结果,然后返回和保存最新的结果。reactive表达式使用这个新的拷贝直到它过时。
- A reactive expression saves its result the first time you run it.
- The next time the reactive expression is called, it checks if the saved value has become out of date (i.e., whether the widgets it depends on have changed).
- If the value is out of date, the reactive object will recalculate it (and then save the new result).
- If the value is up-to-date, the reactive expression will return the saved value without doing any computation.
通过这个方式防止Shiny重复运行代码,如果我们改变symb widget,Shiny还会知道input$symb过时了吗,会的,因为Shiny随时跟踪reactive 表达式,一旦它改变,Shiny会重构:
- an
input
value in the objects’srender*
function changes, or - a reactive expression in the objects’s
render*
function becomes obsolete
不过注意,只能在reactive里和render*里调用reactive表达式,因为只有这两个R函数具有处理reactive output的能力。
Lesson 7 Share your apps
我用的是Shiny—Server,用服务器就好了,比我之前学的的用Java,方便了一万倍!
Build
Introduction to R Markdown
还好之前接触过markdown,相当于把markdown embedded into R语言;
后缀是.Rmd;
R Markdown的优势:
- knit:您可以knit文件。 .rmarkdown软件包将调用knitr软件包。 knitr将运行文档中的每个R代码块,并将代码结果附加到代码块旁边的文档中。 此工作流程可以节省时间并简化可重复的报告。考虑作者通常如何在报告中包括图形(或表格或数字)。 作者制作图形,将其保存为文件,然后复制并将其粘贴到最终报告中。 此过程依赖于用户自己操作。 如果数据发生变化,那么作者必须重复整个过程以更新图形。(动态文档)在R Markdown范式中,每个报告都包含制作自己的图形,表格,数字等所需的代码。作者可以直接通过重新knit自动更新报告。
- convert:您可以转换文件。 .rmarkdown软件包将使用pandoc程序将文件转换为新格式。 例如,您可以将.Rmd文件转换为HTML,PDF或Microsoft Word文件。 您甚至可以将文件转换为HTML5或PDF幻灯片。 .rmarkdown将保留原始.Rmd文件中包含的文本,代码结果和格式。通过转换,您可以轻松地在Markdown中完成原始工作。 您可以包括要knit的R代码,并且可以以多种格式共享文档。
rmarkdown::render()
在Rstudio中,使用Knit HTML等按钮执行代码;
注意:RStudio不会从头开始构建PDF和Word文档。 您需要在计算机上安装发行版的Latex才能制作PDF,并需要安装Microsoft Word(或类似程序)来制作Word文件。
Knitr for embedded R code
呈现报告时,knitr将运行代码并将结果添加到输出文件中。 您可以使输出仅显示代码,仅显示结果或同时显示两者。
要将大块R代码嵌入到报表中,请用两行代码包围该代码,每行包含三个反引号。 在第一组反引号之后,包括{r},它会警告knitr您已经包含了一部分R代码。 结果将如下所示
Here's some code
```{r}
dim(iris)
```
eval = FALSE:表示不显示输出结果
echo = FALSE:表示不显示代码
行内代码:
Two plus two equals `r 2 + 2`.
YAML for render parameters
您可以使用YAML header来控制rmarkdown如何显示您的.Rmd文件。 YAML header以键值对来表达,如下所示
---
title: "Untitled"
author: "Garrett"
date: "July 10, 2014"
output: html_document
---
Some inline R code, `r 2 + 2`.
output表示在您调用rmarkdown::render()的时候,决定将您的.Rmd文件转化为何种格式,一共有三种形式:
- html_document
- pdf_document
- word_document
更多的YAML设置,请见:http://rmarkdown.rstudio.com/html_document_format.html
Introduction to interactive documents
An interactive documents:R Markdown文件中包含了Shiny widgets 和 outputs,通过Rmarkdown写报告,但是把它当做app运行。(R Markdown和Shiny的结合)
- 在YAML header 添加 runtime: shiny
- 在R代码块中添加Shiny widgets和Shiny render函数
---
runtime: shiny
output: html_document
---
### Here are two Shiny widgets
```{r echo = FALSE}
selectInput("n_breaks", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 20)
sliderInput("bw_adjust", label = "Bandwidth adjustment:",
min = 0.2, max = 2, value = 1, step = 0.2)
```
### ...that build a histogram.
```{r echo = FALSE}
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")
})
```
运行交互式文档时,rmarkdown会提取代码块中的代码,并将其放入伪server.R文件中。 R Markdown使用markdown文件的html输出作为index.html文件来放置交互性元素。
注意:如果您熟悉R Markdown,则可能希望RStudio将交互式文档的HTML版本保存在您的工作目录中。 但是,这仅适用于静态HTML文档。 每个交互式文档必须由管理该文档的计算机提供。 于是,交互式文档不能作为独立的HTML文件共享。
您可以使用R Markdown创建交互式幻灯片,而仅使用Shiny很难做到这一点。 要创建幻灯片,请在.Rmd文件的YAML前端将输出:html_document更改为输出:ioslides_presentation。 单击“运行文档”时,R Markdown会将您的文档分成幻灯片。每当出现标头或水平标尺(***)时,新的幻灯片就会开始。
更多有关R markdown的使用:https://rmarkdown.rstudio.com/
Build Dashboard