在Shiny的初级课程中,我们了解到了Shiny的程序的构成,分为Ui和Server两个部分。在Ui中,定义了页面是如何布局的,定义了有哪些部件,定义了有什么输出;在Server中,定义了网页背后是如何计算的。我们还了解到Ui和Server是如何建立联系的。最后,我们建立了一个自己的Shiny程序,使用的是默认布局,并最终部署到了服务器上面。
通过Shiny初级课程的学习,我们能够开发一个Shiny程序,并且部署到网络上面。
本课程是Shiny的中高级课程,通过本课程的学习,同学们可以构建一个更加复杂的,更多功能的Shiny程序。
本课程所包含的内容有
Shiny中有很多的页面布局方式,默认的布局方式是边栏布局,指的是页面分为左侧的去和中间的区域,左边一般设置输入,中间一般设置为输出。还有更多的页面布局方式:
网格布局通过fluidRow函数进行创建,列通过colnum进行定义,colnum的第一个参数是其宽度,也可以是偏移的位置,通过offset进行设定。
实现这个页面布局的方式是:
library(shiny)
library(ggplot2)
dataset <- diamonds
ui <- fluidPage(
title = "Diamonds Explorer",
plotOutput('plot'),
hr(),
fluidRow(
column(3,
h4("Diamonds Explorer"),
sliderInput('sampleSize', 'Sample Size',
min=1, max=nrow(dataset), value=min(1000, nrow(dataset)),
step=500, round=0),
br(),
checkboxInput('jitter', 'Jitter'),
checkboxInput('smooth', 'Smooth')
),
column(4, offset = 1,
selectInput('x', 'X', names(dataset)),
selectInput('y', 'Y', names(dataset), names(dataset)[[2]]),
selectInput('color', 'Color', c('None', names(dataset)))
),
column(4,
selectInput('facet_row', 'Facet Row', c(None='.', names(dataset))),
selectInput('facet_col', 'Facet Column', c(None='.', names(dataset)))
)
)
)
需要注意的是,网格布局和边栏布局可以相互嵌套
如果我们需要将页面分为不连续的几个部分,在Shiny中可以使用tabsetsPanel来完成,比如:
这一部分的代码是如下:
ui <- fluidPage(
titlePanel("Tabsets"),
sidebarLayout(
sidebarPanel(
# Inputs excluded for brevity
),
mainPanel(
tabsetPanel(
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
选项卡可以位于其他位置,比如上方(默认),下方,左侧和右侧。比如,要将选项卡放到内容的下方,可以使用下面这个代码:
tabsetPanel(position = "below",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
#### 2.3 Navlists
当我们有了多个tabPanel的时候,这个时候我们就需要Navlists,这是导航列表,导航列表将各个组件显示成为侧边栏的列表,而不是使用选项卡。
下面是一个例子:
实现这个例子的代码如下(tabPanel为空是为了保持整洁,通常包含其他的UI部件)
ui <- fluidPage(
titlePanel("Application Title"),
navlistPanel(
"Header A",
tabPanel("Component 1"),
tabPanel("Component 2"),
"Header B",
tabPanel("Component 3"),
tabPanel("Component 4"),
"-----",
tabPanel("Component 5")
)
)
有的时候我们可能想要创建一个由多个不同子组件组成的Shiny应用程序(每个子组件都有自己的侧边栏,tabset或其他布局结构)。通过navbarPage()函数创建一个页面导航,来囊括多个shiny程序
代码如下:
ui <- navbarPage("My Application",
tabPanel("Component 1"),
tabPanel("Component 2"),
tabPanel("Component 3")
)
添加二级页面
您可以使用该navbarMenu()功能向页面添加第二级导航。这会向顶级导航栏添加一个菜单,该菜单又可以引用其他tabPanel。
ui <- navbarPage("My Application",
tabPanel("Component 1"),
tabPanel("Component 2"),
navbarMenu("More",
tabPanel("Sub-Component A"),
tabPanel("Sub-Component B"))
)
Shiny 中除了默认的主题之外,还可以定义更过的主题,比如:
install.packages("shinythemes")
## ui.R ##
library(shinythemes)
fluidPage(theme = shinytheme("cerulean"),
...
)
Details
cerulean
cosmo
cyborg
darkly
flatly
journal
lumen
paper
readable
sandstone
simplex
slate
spacelab
superhero
united
yeti
如果要单击图画获取鼠标的位置。
plotOutput("plot1", click = "plot_click")
在plotOutput中添加一个参数,来获取图片鼠标点的位置。这样定义一个新的输入input$plot_click
,这就包含了上一次鼠标单击的位置
案例
单击图片,获取x,y的坐标
library(shiny)
ui <- basicPage(
plotOutput("plot1", click = "plot_click"),
verbatimTextOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
})
output$info <- renderText({
paste0("x=", input$plot_click$x, "\ny=", input$plot_click$y)
})
}
shinyApp(ui, server)
需要注意的是,x和y坐标是缩放的数据的,而不是简单的图片的像素点。
还有其他的交互方式:双击,悬停和框选
可以通过启用:dblclick,hover和brush选项
案例
ui <- basicPage(
plotOutput("plot1",
click = "plot_click",
dblclick = "plot_dblclick",
hover = "plot_hover",
brush = "plot_brush"
),
verbatimTextOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
})
output$info <- renderText({
xy_str <- function(e) {
if(is.null(e)) return("NULL\n")
paste0("x=", round(e$x, 1), " y=", round(e$y, 1), "\n")
}
xy_range_str <- function(e) {
if(is.null(e)) return("NULL\n")
paste0("xmin=", round(e$xmin, 1), " xmax=", round(e$xmax, 1),
" ymin=", round(e$ymin, 1), " ymax=", round(e$ymax, 1))
}
paste0(
"click: ", xy_str(input$plot_click),
"dblclick: ", xy_str(input$plot_dblclick),
"hover: ", xy_str(input$plot_hover),
"brush: ", xy_range_str(input$plot_brush)
)
})
}
shinyApp(ui, server)
Shiny提供两种便捷功能来选择数据行: * nearPoints():使用交互数据中的x和y值; 与其一起使用click,dblclick和hover。 * brushedPoints():使用xmin,xmax,ymin,和ymax从所述交互数据值;
需要注意的是,只有当数据框中存在x,y变量以及没有任何变换的时候才可以使用。
首先是对于nearPoints的讲解,通过这个函数可以返回包含选定行的数据框。
ui <- basicPage(
plotOutput("plot1", click = "plot_click"),
verbatimTextOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
})
output$info <- renderPrint({
# With base graphics, need to tell it what the x and y variables are.
nearPoints(mtcars, input$plot_click, xvar = "wt", yvar = "mpg")
# nearPoints() also works with hover and dblclick events
})
}
shinyApp(ui, server)
默认情况下,nearPoints将返回鼠标事件的5个像素内的所有数据行,并且它们将按距离排序,最近的第一行。半径可以自定义threshold,返回的行数可以自定义maxpoints。
如果是使用的是GGPLOT2创建地块,这是没有必要指定xvar和yvar,因为它们可以自动检测。注意不要使用数据的变换,例如aes(x = wt/2)将不起作用
然后是对于brushedPoints(),它的基本用法类似于nearPoints()类似:
ui <- basicPage(
plotOutput("plot1", brush = "plot_brush"),
verbatimTextOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
})
output$info <- renderPrint({
# With base graphics, need to tell it what the x and y variables are.
brushedPoints(mtcars, input$plot_brush, xvar = "wt", yvar = "mpg")
})
}
shinyApp(ui, server)
shinydashboard是一种特殊的Shiny页面布局,其详细的内容可以另外开一门课程,本课程讲解shinydashboard 基本用法
安装
install.packages("shinydashboard")
shinydashboard包含:标题,侧边栏和正文。这是仪表板页面的最小可能UI。
## app.R ##
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output) { }
shinyApp(ui, server)
shinydashboard 通常都会包含dashboardHeader,dashboardSidebar,dashboardBody,上面的只是基本的结构,我们还需要添加一些东西进去
dashboardBody 中所放的内容和一般的shiny程序一样:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
sidebarLayout(
# Sidebar panel
sidebarPanel(
# 这里是定义一个slider 作为输入
sliderInput(inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30)
),
# 主页面,这里主页面是一个绘图
mainPanel(
# Output: Histogram ----
sliderInput(inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30)
)
)
)
)
server <- function(input, output) { }
shinyApp(ui, server)
如果我们向通过输入来控制UI的输出,同样也是可以做到的。Shiny中一共有四种方式来构建对应的UI:
本课程介绍的是renUI,下面通过一个例子来介绍:
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
# 这里指定的是什么布局方式
sidebarLayout(
# Sidebar panel
sidebarPanel(
# 这里是定义一个slider 作为输入
numericInput(inputId = "num",label = "数字输入",value = 1),
uiOutput(outputId = 'slider')
),
# 主页面,这里主页面是一个绘图
mainPanel(
# Output: Histogram ----
plotOutput(outputId = "distPlot")
)
)
)
server <- function(input, output) {
output$slider <- renderUI({
sliderInput(inputId = "bins",
label = "Number of bins:",
min = input$num,
max = input$num+50,
value = 30)
})
output$distPlot <- renderPlot({
x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times")
})
}
shinyApp(ui, server)
3