Shiny是Rstudio里用来做demo的,相当于一个前端框架,可以连接R里的元素。我是这么理解的。一直想试一试Shiny,这次做用户画像,正好可以用它做一个demo给开发同学看,所以就学习了一下它的使用逻辑。目标很简单,这个demo由两个部分组成,第一部分是一个输入框,可以输入会员号。第二部分就是一个标签集(tag cloud),用了wordcloud2包,根据输入的会员号显示这个用户的标签集。大致效果如下:
教程看的是Shiny官方的七节课,看完就给人一种错觉,好像自己已经会了。Shiny Gallery里还有一个wordcloud的demo,但这个就看得云里雾里了,根据它的代码改了下,总是报错,因为没有真正掌握Shiny的思路。再研究和尝试了很多下,终于调试出来了。
Shiny的一个app由两个文件构成,一个控制前端显示ui.R,一个控制后台server.R。他们的关系比较复杂,有点像鸡生蛋蛋生鸡的关系。ui.R通过widgets得到用户输入的值,每一个widget需要自定义名称widget_name,用户输入的值就用input$widget_name来引用。然后后台的server.R使用前端输入的值,产生各种output,比如图,表格,输出文本等等。在我们的例子里,前端输入的是会员号,output是一个tag cloud。每一个output的东西也都要命名,比如给我们的tag cloud命名为output$plot,但这个output$plot只是以一个R元素存储了起来,展示的工作还是要交给前端的ui.R。所以这个时候呢,要再回到前端的ui.R去,告诉它我这个plot要放在什么位置,然后要它把这个元素展示出来。到此,就是我理解的shiny的主要思路。
废话不多说,先贴代码。
#### server.R ####
load('C:/app/test0223.RData')
library(wordcloud2)
shinyServer(
function(input, output) {
output$plot <- renderWordcloud2({
getdata<-function(cid){
dataList[[cid]]
}
word_color<-getdata(input$selection)
wordcloud2(word_color$data, size=0.12, fontFamily = '微软雅黑', rotateRatio =0,
gridSize=15, shuffle=F, color = word_color$colorVec )
})
}
)
#### ui.R ####
fluidPage(
# Application title
titlePanel("Word Cloud"),
# sidebar
sidebarLayout(
# Sidebar with a slider and selection inputs
sidebarPanel(
selectInput("selection", label = "请输入会员号",
choices = as.list(names(dataList)))
),
# Show Word Cloud
mainPanel(
wordcloud2Output("plot")
)
)
)
代码解释
1
首先简单解释一下wordcloud2包的用法。
wordcloud2(data, size, fontFamily = '微软雅黑', rotateRatio =0,
gridSize=15, shuffle=F)
适用的dataset要有两列,第一列叫word,第二列叫freq,即每个单词的频次。因为这里我只是做一个tag cloud,每个tag的权重都给它1,即不区分大小。如:
word | freq |
---|---|
Tag 1 | 1 |
Tag 2 | 1 |
Tag 3 | 1 |
... | ... |
其他的参数可查询文档。
2
load的test0224.RData中包含一个叫dataList的list,它里面有1000个会员的标签信息,结构如下:
str(dataList)
List of 1000
$ Customer1 :List of 2
..$ data :'data.frame': 20 obs. of 2 variables:
.. ..$ word: chr [1:20] "Tag 1" "Tag 2" "Tag 3" "Tag 4" ...
.. ..$ freq: num [1:20] 1 1 1 1 1 1 1 1 1 1 ...
..$ colorVec: chr [1:20] "#757575" "#D32F2F" "#212121" "#FFCDD2" ...
$ Customer2 :List of 2
..$ data :'data.frame': 19 obs. of 2 variables:
.. ..$ word: chr [1:19] "Tag 1" "Tag 2" "Tag 3" "Tag 4" ...
.. ..$ freq: num [1:19] 1 1 1 1 1 1 1 1 1 1 ...
..$ colorVec: chr [1:19] "#757575" "#D32F2F" "#212121" "#FFCDD2" ...
可以看到dataList里每个元素也都是一个list,包含两个元素,一个data
,一个colorVec
。data
就是上面说的包含了word和freq两列的dataframe,而colorVec
是一个和data
一样长的character vector,它指示data
中每个tag所使用的颜色。如果不指明color,wordcloud2会随机给每个tag一个颜色。我们在这里用颜色来代表不同种类的tag,如基本信息,交易信息等等。
3
先看ui.R中的这段代码:
sidebarLayout(
# Sidebar with a slider and selection inputs
sidebarPanel(
selectInput("selection", label = "请输入会员号",
choices = as.list(names(dataList)))
),
我们在侧边栏sidebar里使用了一个叫selectInput的组件,它是一个下拉框,下拉框中是1000个会员的会员号,同时也支持直接输入会员号。本来想用一个直接输入会员号的组件,因为毕竟真实会员有几百上千万,下拉框其实是浪费的,但暂时还没有找到将输入的文本和dataList中元素对应起来的方法,如有朋友知道,请不吝赐教。
我们给这个selectInput组件起名为selection,组件上显示的文字是“请输入会员号”,可供选择的选择项必须是一个list,这里的as.list(names(dataList))
就是把dataList中每个元素的名称(即会员号)组成一个list。
4
再来看server.R中的这一段:
output$plot <- renderWordcloud2({
getdata<-function(cid){
dataList[[cid]]
}
word_color<-getdata(input$selection)
wordcloud2(word_color$data, size=0.12, fontFamily = '微软雅黑', rotateRatio =0,
gridSize=15, shuffle=F, color = word_color$colorVec )
})
这一段代码是为了生成一个wordcloud2对象,使用的是wordcloud2包里专门用于shiny的函数renderWordcloud2
。这个wordcloud2对象我们给它取了个名字叫plot
,即第一行最开始的output$plot
。要生成这个对象,我们先自定义了一个函数getdata
, 用来得到一个指定会员的data
和colorVec
。随后生成一个叫word_color
的list,getdata
函数里的变量cid
就是之前ui.R里的selectInput组件里的值,即input$selection
(selection是我们自定义的selectInput组件的名字)。这一段代码也可以更简洁地写成:
output$plot <- renderWordcloud2({
wordcloud2(dataList[[input$selection]]$data, size=0.12, fontFamily = '微软雅黑', rotateRatio =0,
gridSize=15, shuffle=F, color = dataList[[input$selection]]$colorVec )
})
5
之后,让我们再回到ui.R中,看这一段代码:
mainPanel(
wordcloud2Output("plot")
)
wordcloud2Output
也是wordcloud2
包里的一个专用于shiny的函数,用于将wordcloud2对象output出来。因此这一段很好理解,plot
是我们先前在server.R中生成的wordcloud2对象,这里就是将这个对象output出来,放在mainPanel里。
至此,一个简单的制作用户标签的Shiny App就完成了。