Shiny应用基础(3):页面布局 您所在的位置:网站首页 BIOS只显示一半页面 Shiny应用基础(3):页面布局

Shiny应用基础(3):页面布局

2024-07-03 03:21| 来源: 网络整理| 查看: 265

页面布局考虑HTML元素在浏览器窗口中的展示位置和顺序。一般情况下,一个shiny程序只需要一个展示窗口,其布局应该很简单随意。然而,shiny把这部分设计得相当复杂,提供了很多相关的函数。这些函数都是在shinyApp的ui参数内使用的,为了方便本文暂把它们称为“UI函数”。

在上一节的内容中我们知道,通过tags列表的设置我们完全可以解决HTML页面元素产生和页面布局的问题,为什么shiny还要提供辣么多的UI函数呢?为说明这一点,请比较下面两个shiny“程序”所产生的HTML代码:

## 程序1: shinyApp( ui = div(class="container"), server = function(input, output, session) {} ) ## 程序2: shinyApp( ui = fixedPage(), server = function(input, output, session) {} )

运行上面两个“程序”,分别查看页面的源代码,发现两者的 body 内具有相同的代码。但不同的是程序2的 head 部分多了下面几行代码:

这就是关键。 shiny的UI函数不仅产生了相应的HTML元素,还引入、规定或解决了HTML元素的依赖关系(HTML dependency) 。所以嘛,有些UI函数你可以视而不见,但有些你还不得不了解和使用。

1 Bootstrap框架

前面的例子已经看到,虽然我们可以使用div函数对HTML页面进行手工分块布局,但fixPage函数做的工作更多。很显然,Shiny页面布局引入了Bootstrap框架。有关Bootstrap介绍的网络资源非常多,这里就不详细介绍了。如果真的要好好应用shiny,我觉得先了解了解Bootstrap是很有必要的。

要理解shiny布局页面的原理并不难,其实就是bootstrapPage函数和上一篇文章讲过的tags标签。这些函数在shiny源代码包的bootstrap.R和bootstrap-layout.R中定义,很容易找到。简单起见,这里我们只讲用法。

1.1 bootstrapPage函数

shiny的源代码中有一个基本的bootstrapPage()函数,HTML的依赖性(CSS,js)由它确定:

bootstrapPage shinyDeprecated("The 'responsive' argument is no longer used with Bootstrap 3.") } ## required head tags for boostrap importBootstrap tags$head(tags$link(rel="stylesheet", type="text/css", href = theme)) }, ## remainder of tags passed to the function list(...) ), importBootstrap() ) }

bootstrapPage函数是可以直接调用的,前提是:你得熟悉HTML/CSS和bootstrap,否则建议用fixedPage或fluidPage。这两个函数其实也引用了bootstrapPage函数,调用这些函数就表明我们将在整个页面中应用bootstrap框架。如果你故意避开这些函数不用,那很可能在程序运行中会发生一些抓破脑袋也想不明白的意外情况。

1.2 fixedPage和fluidPage函数

Bootstrap有两种基本页面布局,即固定宽度布局和流式布局,其CSS样式分别由 container 类和 container-fluid 类设置。通常情况下,在固定宽度布局中页面内容的宽度通过固定像素设置;而流式布局中的页面内容则通过屏幕宽度的百分比设置。在Shiny中,页面布局函数 fixedpage() 产生具有 container 类属性的块,而 fluidPage() 则产生 container-fluid 块。

两个函数的调用方法都是一样的:

fixedPage(..., title = NULL, responsive = NULL, theme = NULL) fluidPage(..., title = NULL, responsive = NULL, theme = NULL)

… 参数:数量不限的页面内容,逗号分隔title 参数:页面标题theme参数:自定义页面的CSS主题样式文件。如果不设置自定义样式,则采用shiny包安装目录下www/shared/bootstrap/css子目录中的样式表文件。如果有自定义的样式表,则需要在应用程序的主目录下建立www目录,并把css文件放到该目录下(可以再设置子目录)。responsive参数:现行shiny版本已弃用该参数,因Bootstrap 3的媒体查询功能已升级。

以上参数没有一个是强制要求设置的。如果不设置任何参数,fixedPage的作用就是产生下面代码:

而fluidPage则获得:

title和theme产生的内容放置到HTML代码的 head 标签内,你可以自己尝试设置这些参数,通过查看HTML源代码检查它们的作用。

1.3 navbarPage

navbarPage() 函数用于产生具有顶部导航条页面,而导航条下方页面可以设为固定宽度或流式布局。

navbarPage(title, ..., id = NULL, header = NULL, footer = NULL, inverse = FALSE, collapsable = FALSE, fluid = TRUE, responsive = TRUE, theme = NULL)

header:所有标签页顶部均要显示的标题内容,其外部容器为div.rowfooter:所有标签页底部均要显示的脚注内容,其外部容器为div.rowinverse:bootstrap黑底白字风格的顶部导航条collapsable:当屏幕显示宽度小于940px时是否自动折叠导航条使所有的标签均位于导航条内。该参数对于触屏设备很有用。…:所有的其他参数都被当成标签页,产生对应的导航列表项目和内容块,但只有使用tabPanel函数(后面将介绍)设置的内容可以正确显示和切换。

这是一个非常奇怪的函数,试图包揽解决一大堆问题,设计思路很不清。如果你对bootstrap navbar的要求较高,你会发现它可以设置功能少得可怜,只能进行页面内的导航而不是网站的导航。

1.4 已弃用的页面设置函数 basicPage:已弃用,现在用fluidPage代替pageWithSidebar:已弃用,现使用fluidPage和sidebarLayout产生相同页面 2 页面布局函数

通过xxxPage函数引入bootstrap框架文件后,页面的内容布局可以灵活设置。如果你熟悉HTML/CSS,下面的绝大多数函数可用可不用。但不管怎么样,这些都应放在xxxPage函数内,因为它们需要bootstrap,除非你手工引物相应的css和js文件。

2.1 窗口与页面标题

有两个函数:headerPanel和titlePanel。它们的用法是一样的:

headerPanel(title, windowTitle = title) titlePanel(title, windowTitle = title)

title 设置内容标题windowTitle 设置浏览器窗口标题,默认为内容标题

这两个函数的细微差别可以通过查看它们的函数源代码看出来。headerPanel的源代码是:

headerPanel tagList( tags$head(tags$title(windowTitle)), h2(title) ) }

内容标题的标签类型不一样父容器不一样,headerPanel产生额外的div容器

总体感觉上面两个函数的灵活性太差,产生的标题千篇一律。如果你也认为是这样,可以考虑用tags直接设置,比如:

shinyApp( ui = fixedPage( tags$head( tags$title('窗口标题'), tags$style( rel = 'stylesheet', '.title-panel {background: #ABCDEF} ', '.title-panel h2 {text-align:center; color: #FF0000}' ) ), div( class='col-md-12 title-panel', h2('页面标题') ) ), server = function(input, output, session) {} )

2.2 标签页与导航

shiny应用程序往往只需要一个浏览器窗口,因此它绝大多数(可能是全部)“导航”都是指页面内部的标签页切换,包括前面介绍了navbarPage函数所产生的顶部导航条。

2.2.1 tabPanel

tabPanel(title, ..., value = NULL, icon = NULL)

设置标签页的基本函数,但不是一个简单的函数。除了设置标签页内的内容(… 参数)外还用于设置导航标签,title、value和icon是用于导航标签设置的参数。它需要在navbarPage、tabsetPanel、navbarMenu等函数内部使用,否则没有太大的意义。

2.2.2 navbarPage、tabsetPanel、navlistPanel

navbarPage函数已经看过了。看一下后两个函数的参数:

tabsetPanel(..., id = NULL, selected = NULL, type = c("tabs", "pills"), position = c("above", "below", "left", "right")) navlistPanel(..., id = NULL, selected = NULL, well = TRUE, fluid = TRUE, widths = c(4, 8))

为什么把navbarPage放在这里,你看看下面代码的效果就理解了:

shinyApp( ui = navbarPage( title="导航条风格", tabPanel("One", icon=icon("home")), tabPanel("Two"), navbarMenu( title = "Three", tabPanel("Four"), tabPanel("Five") ), navlistPanel( title = "导航面板风格", widths = c(3, 9), tabPanel("One", icon=icon("home")), tabPanel("Two"), navbarMenu( title = "Three", tabPanel("Four"), tabPanel("Five") ) ), h4("标签页风格"), tabsetPanel( type = "pills", tabPanel("One", icon=icon("home")), tabPanel("Two"), navbarMenu( title = "Three", tabPanel("Four"), tabPanel("Five") ) ), tags$head( tags$style(".tab-content .tab-content {border: 1px solid gray; min-height:200px;}") ) ), server = function(session, input, output) { } )

运行后得到的页面如下:

2.2.3 navbarMenu函数

用于产生下拉式导航标签,上面的例子已经看到它的使用方法:

navbarMenu(title, ..., icon = NULL)

2.3 行列设置 2.3.1 fixedRow和fluidRow

两者的代码是完全一样的,都是产生bootstrap的div.row类容器:

fixedRow div(class = "row", ...) }

2.3.2 column

产生bootstrap的div.col-sm-n类容器:

column(width, ..., offset = 0)

width:设置col-sm-n中的n值,参数没有默认值,必需设置,取值为1-12间的整数,了解bootstrap媒体查询的应该知道。offset:额外设置col-sm-offset-n中的n值,参数表示该列和前一列的间距,数值的单位意义和width一样,默认值为0。 2.4 特殊块

这些块的特殊之处只是预设了容器和样式,如果觉得内容太多你可以完全把它们忽略。

2.4.1 absolutePanel和fixedPanel

absolutePanel(..., top = NULL, left = NULL, right = NULL, bottom = NULL, width = NULL, height = NULL, draggable = FALSE, fixed = FALSE, cursor = c("auto", "move", "default", "inherit")) fixedPanel(..., top = NULL, left = NULL, right = NULL, bottom = NULL, width = NULL, height = NULL, draggable = FALSE, cursor = c("move", "default", "inherit"))

获取position属性分别为absolute和fixed的div容器,位置参数设置初始位置,draggable参数设置是否可以用鼠标拖动。

shinyApp( ui = fixedPage( fixedPanel( top = 50, right=50, width=200, draggable = TRUE, style="padding: 20px; border: 1px solid red;", "可以移动的框框1" ), absolutePanel( top = 150, right=150, width=200, draggable = TRUE, style="padding: 20px; border: 1px solid red;", "可以移动的框框2" ) ), server = function(session, input, output) { } )

2.4.2 conditionalPanel

条件显示区块。含condition条件参数,通过JS判断该条件以聚定显示或隐藏该区块。用户不用关心JS代码的编写。由于涉及到数据交互,我把它放到以后的文章介绍。

2.4.3 inputPanel

inputPanel div(class=paste0("col-sm-", width), tags$form(class="well", ... ) ) }

外部容器为div,只接收宽度width参数;内部容器为form,接收其他所有内容和参数。

2.4.5 mainPanel

mainPanel div(class="well", ...) }

产生一个预设样式的块,有点像代码块,但字体不特殊设置。

3 预设布局模板 3.1 两列模板:sidebarLayout

sidebarLayout(sidebarPanel, mainPanel, position = c("left", "right"), fluid = TRUE)

产生外部容器为div.row只能设置两栏,左右排列虽然参数为sidebarPanel和mainPanel,实际上可以使用其他方法设置div块fluid参数已废 3.2 垂直分割模板:splitLayout

splitLayout(..., cellWidths = NULL, cellArgs = list())

外部容器为div.shiny-split-layout每项内容使用独立div块,cellWidths用于设置每个子块的宽度,如不设置则按内容数量进行等分父容器 3.3 流式(自动折行)模板:flowLayout 外部容器为div.shiny-flow-layout每项内容使用独立div块,宽度固定为220px按屏幕显示区宽度自动折行 3.4 垂直排列模板:verticalLayout

这种模式将出现在该函数的每项内容(参数)都单独放在一行,即垂直排列。

运行下面程序,调整浏览器窗口大小,你会发现不同布局模式的变化:

shinyApp( ui = fixedPage( tags$style( ".container div {border: 1px solid gray; min-height:30px;}", "h4 {color:red; margin-top: 20px;}" ), h4("两栏模板"), sidebarLayout( sidebarPanel("side bar panel"), mainPanel("main panel") ), h4("垂直分割模板"), splitLayout("aaaa", "bbbb", "cccc", "dddd"), h4("垂直排列模板"), verticalLayout("aaaa", "bbbb", "cccc", "dddd"), h4("流式(自动折行)模板"), flowLayout("aaaa", "bbbb", "cccc", "dddd") ), server = function(session, input, output) { } )

     

Author: ZGUANG@LZU

Created: 2015-08-04 二 19:58

Emacs 24.5.1 (Org mode 8.2.10)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有