shinyR学习R数据可视化

Shiny: R语言来建立开源交互式数据分析微服务的神器

2017-11-03  本文已影响671人  史春奇

​先来说个应用场景: 假设你需要快速Prototype一个数据分析的服务, 而且需要给业务客户一定的自由度来理解数据分析的强大, 例如更换数据, 更换分析手段。  但是你就只有几个小时的时间去准备。 你该怎么办?   Shiny就是你要的那个神器!

题目有点长, 需要稍微解释一下。

一, 交互式微服务

首先, 服务!

Web Service 这个概念比较成功了, 在SOAP服务之后, Restful服务的普及, 使得数据库的CRUD操作通过网络无限延伸。 普遍的好处是:

1) 你不需要安装任何程序, 携带数据, 只要有网的地方, 你就能演示。(远程)

2) 只要安装一次, 可以多人使用, 可以让别人试用。(多用户)

3) 不用担心软件或者代码泄密, 可以控制用户使用时间和权限。 (服务)


其次,微服务!!

Microservice的概念和大部分微概念提出一样, 例如微机, 微内核等等, 就是要脱离庞大的依赖而单独运行。 服务框架,也就是Service Oriented Architecture (SOA) 正在变得越来越复杂。 微服务就是解耦合这种复杂性的时髦概念。 简单来说就是要独立任务独立项目独立运行。




再次,交互式微服务!!!

其实这里借用了概念, 交互式主要是针对交互式数据分析, 而交互式数据分析和传统的静态数据分析的最重要的差异就是,是不是把"模型选择和评估的快速迭代"作为内嵌的实时的需求。

当然了, 这种实时的操作的反馈,在服务框架下, 必然要求前后台有个交互设计。



R VS Java VS Python

在如上的需求下, Java用户需要怎么设计前后台?  利用Spring-Servlet框架, 后台可以利用WEKA,SPARK, 前台用AJAX和D3.js?一听就工程量不小。 更不要谈部署了Tomcat/Resin,还是Maven的Jetty插件吧。   总之几天才能搞定的样子。 要不Python吧, 现有的Flask/CherryPy, 以后很容易升级Pyramid/Django等, 后台Scikit-Learn, 前台呢?可以用Senborn的图片或者MPLD3等等, 看上去至少也是1整天的活,还得很熟悉相关框架。  Shiny就是这么强大的登场了, 对的几个小时!!!

二, Shiny如何做到的?

Shiny之Hello World

Shiny就可以作为专一的微服务框架, 很容易实现如下的架构。


运行上面这样的服务, Shiny只要两行代码。

library(shiny)

runApp("my_app_name")

或者你可以先试试hello-world。也是类似的两行代码。

library(shiny)

runExample("01_hello")


立马你可以得到一个可以通过浏览器使用的Shiny的应用APP。 可以利用Histogram来展示观察值得分布。 并且这是一个可以交互的App, 你可以调整观察总数来变换得到一个新的图。

还有其他很多例子可以参考。可以通过如下命令来找到对应的App名字和源码。

system.file("examples",package="shiny")

Shiny之实现

那么Shiny是如何实现这种强大的功能的呢?

Shiny本身是基于R和Node.js的一个应用服务,有了强大的javascript异步后台, 那么如何把Shiny解析后交由R解释器运行后台数据分析和可视化生成, 交由node.js运行前台的展示和交互。


Node.js 本身是对Chrome的V8引擎的封装的异步事件引擎。


Shiny之代码结构

根据前面对Shiny的后台实现的分析, Shiny代码可以分成两部分, 一部分主要由R解释器去执行的server.R, 另外一部分是主要由node.js去执行的ui.R。 这样通过Socket建立一个独立的端口服务, 一个微服务系统就构建完成了。


除了上面的双文件结构, 我们也可以直接定义一个shinyApp, 单一文件结构:

shinyApp(ui=fluidPage(sidebarLayout(sidebarPanel(sliderInput("bins","Number of bins:",min=1,max=75,value=30)),mainPanel(plotOutput("distPlot")))),server=function(input,output,session){output$distPlot<-renderPlot({hist(faithful$eruptions,breaks=input$bins)})})

更多例子参考: http://zevross.com/blog/2016/04/19/r-powered-web-applications-with-shiny-a-tutorial-and-cheat-sheet-with-40-example-apps/

三, 如何才能速度的完成Shiny服务部署?

Shiny安装

1. 直接通过包管理器安装

install.packages("shiny")

2. 利用devtools通过github安装

if(!require("devtools"))  install.packages("devtools")devtools::install_github("rstudio/shiny")

这里要注意, 如果需要利用代理

library(httr)set_config(use_proxy(url="18.91.12.23",port=8080,username="user",password="password"))

或者要设定专门的版本号

devtools::install_version("shiny",version="0.10.2.2")

Shiny 代码结构和放置

前面提到Shiny主要是两个文件ui.R和server.R。 这两个文件都是典型的Domain Specific Lanugage(DSL)。 通常DSL都是关键词引领的模块化语言, 可以参考Groovy的DSL设计。 这样的好处是解释器实现简单高效。

用户接口user interface设计主要是利用declarative语言来描述页面如何布局, 有哪些图标,哪些控件。

# ui.R

library(shiny)

shinyUI(fluidPage(

))

# server.R

library(shiny)

shinyServer(function(input,output){

})

而服务器端server.R主要是一个接口函数的实现。 简单来说就是输入是什么, 我希望运行的输出是什么。

ui 和 server直接是怎么来进行通信的呢?  主要是通过input 和 output  NameSpace来进行通信的。譬如我们在ui.R中定义一个输入控件,命名为"bins", 那么在server.R中就通过"input$bins"来获取这个控件的值。

# ui.R

sliderInput("bins","Number of bins:",min=1,max=50,value=30)

# server.Rbins<-seq(min(x),max(x),length.out=input$bins+1)

而同样, 在server.R中想返回的对象, 也放到output Namespace下面。 然后再ui.R中直接通过名称获取。 例如,在server.R中定义了一个renderPlot的绘图,  放到“output$distPlot”。 然后再ui.R中直接获取“distPlot”进行展示。

# server.R

output$distPlot<-renderPlot({x<-faithful[,2]bins<-seq(min(x),max(x),length.out=input$bins+1)hist(x,breaks=bins,col='darkgray',border='white')})

# ui.R

plotOutput("distPlot")

所以我们只要选好匹配的输入输出的Shiny控件, 例如输入的“sliderInput”, 返回的对绘图进行封装的“renderPlot”, 和展示的“plotOutput”。

部署的话, 把server.R和ui.R放到同一个目录下面, 譬如"App-1", 然后运行runApp来运行就可以了。

> setwd("Project_HOME")

>

library(shiny)

>runApp("App-1")


如果是在RStudio环境下面,RStudio会自动识别runApp命令。当你打开ui.R的时候, 直接点击Run App按钮就好了。 非常方便。


甚至, 可以直接从github上直接运行, 只要指定用户, Repository,和文件夹就可以定位一个App对应的文件夹了。

runGitHub(“ShinyAppsForR”, “msiddiqi”, subdir=”upperCaseText”)


因此某种意义上来说github是一种非常好的管理shiny app的工具。

四, Shiny常用技巧

布局(Layout)

在布局中需要考虑Panel是如何放置的, 主要有titlePanel, sidebarPanel, mainPanel。 还有其他Panel,例如tabsetPanel,navlistPanel,navbarPanel

在考虑Panel的时候, 我们可以利用Layout布局器,譬如sidebarLayout(),或者更复杂的网格布局器fluidRow()

shinyUI(fluidPage(titlePanel("title panel"),

sidebarLayout(sidebarPanel("sidebar panel",

selectInput('element_id',label='Select one option',choices=LETTERS[1:10]),

textInput('title_text_box_id',label='Enter a title for the plot')),

mainPanel("main panel",h1('The title of some text'),p('And here is some content that is put into the first paragraph'),p(textOutput('dynamicText')),

plotOutput

('dynamicPlot')))

))

更多的布局可以参考:http://shiny.rstudio.com/articles/layout-guide.html

构件(Widget)

各种输入只能通过Shiny定义好的丰富的widget来实现。


各种细节就不细说了, 更为高级的部分可以到“画廊 Gallery”里面去找

http://shiny.rstudio.com/gallery/

主题(Theme)

当然我们可以指定一些主题,通过自定义css。

shinyUI(fluidPage(theme="bootstrap.css",titlePanel("My Application")# application UI))

另外, “shinythemes” 包提供更多更好用的主题。 安装以后,很方便使用。

install.packages("shinythemes")

不是直接指定一个css文件, 而是通过名字来指定主题。 本人比较喜欢simplex

(http://bootswatch.com/simplex/)

## ui.R ##

library(shinythemes)

fluidPage(theme =shinytheme("simplex"),  ...)

优化(Optimization)

Shiny提供一些缓存优化的机制, 其中最有效的是Reactive Expression 反冲表达式。

Reactive机制使得交互渲染的效率大幅度提高。 举个例子, server.R返回一个数据绘图, 但是每次运行需要重新读取数据。 但是当如果输入没有变化的时候, 这种重复的数据读取会极大的延迟反应, 浪费资源。

# server.R

library(ggplot2)

shinyServer(function(input,output){output$dynamicPlot<-renderPlot({dat=get_data(input$ui_element1,input$ui_element2)plot(dat,input$ui_element3)})})

基于这种考虑, 我们使用reactive关键词重写了数据读取模块。reactive像一个带cache的模块, 并且当reactive检查到数据输入没有任何变化, 那么输出也不会有变化的时候, reactive就会使用缓存的数据,避免了重复运算, 加速了反应。

# server.R  # use reactive

library

(ggplot2)

shinyServer(function(input,output){input_data=reactive({dat=get_data(input$ui_element1,input$ui_element2)})output$dynamicPlot<-renderPlot({plot(input_data(),input$ui_element3)})})

更深入的reactive理解, 可以参考 http://shiny.rstudio.com/articles/reactivity-overview.html。

还有一些其他的优化技巧包括: streamline computation, warm up, dependency 技巧可以参考 http://shiny.rstudio.com/tutorial/lesson6/

交互管理(Session)

在早期的Shiny交互中, 如果服务器和浏览器有中断, 那么所有的前期交互全部丢失了。  在最新的版本中, Shiny加入了session和重连的机制,只要在server.R的函数中加入 “session$allowReconnect(TRUE)”, 很简单吧。

# server.R  # use session

library

(ggplot2)

shinyServer(function(input,output){input_data=reactive({dat=get_data(input$ui_element1,input$ui_element2)})output$dynamicPlot<-renderPlot({plot(input_data(),input$ui_element3)})

session$allowReconnect(TRUE)

})

更多细节参考:http://shiny.rstudio.com/articles/reconnecting.html

扩展(Extending)

有一部分重要的扩展,主要是画图和交互的,譬如rCharts, DataTables, 会让Shiny的交互性变得非常强大。

shinydashboard – Shiny powered dashboards

shinyURL – Facilities for saving and restoring user input values by encoding them in the app’s URL query string

htmlwidgets – A framework for embedding JavaScript visualizations into R. Ready to use examples include:

leaflet – Geo-spatial mapping

dygraphs – Time series charting

MetricsGraphics – Scatterplots and line charts with D3

networkD3 – Graph data visualization with D3

DataTables – Tabular data display

threejs – 3D scatterplots and globes

rCharts – Multiple JavaScript charting libraries

五, Shiny 服务器

假如你有创建了很多的Shiny服务, 那么一个专门的Shiny服务器会方便部署。

一般可以有两种部署, 一种是自己搭建一个Shiny Server。 这样就可以同时使用很多的Shiny 应用了。


另外一种是直接部署到Shiny云服务上去, 譬如“www.shinyapps.io” 注册一个云账号, 然后把服务部署到云上去。在注册完成后, 你只要遵照详细的链接, 授权, 和部署的步骤,就可以把本地Shiny App上传部署。


综上, Shiny提供一个迅速原型化交互数据分析的工具。  用好Shiny会使得你的数据分析的创意和设计备受关注,更快迭代。如果想更深入理解,请阅读Shiny文章 http://shiny.rstudio.com/articles/。


参考:

http://shiny.rstudio.com/tutorial/

http://shiny.rstudio.com/tutorial/lesson1/

http://docs.rstudio.com/shiny-server/

https://github.com/rstudio/shiny-server

http://shiny.rstudio.com/articles/

https://github.com/jcheng5/user2016-tutorial-shiny

https://www.shinyapps.io

https://rstudio.github.io/shinythemes/

http://shiny.rstudio.com/gallery/

http://deanattali.com/blog/building-shiny-apps-tutorial/

http://stcorp.nl/R_course/tutorial_shiny.html

https://www.bioconductor.org/help/course-materials/2015/CSAMA2015/lab/shiny.html

上一篇下一篇

猜你喜欢

热点阅读