Shiny应用基础(7):图像互动
来源:互联网 发布:base64.decode java 编辑:程序博客网 时间:2024/05/17 04:43
shiny应用程序中的图像互动目前主要有两种类型:
- R绘图:完全由R在服务器端生成图像并产生互动效果
- js绘图:服务器端R处理并提供数据到客户端,由客户端浏览器通过js插件完成绘图和互动
js图像互动方法跟R图形系统毛关系都没有,但和R绘图相比,它的数据传输量小速度快,很适合网络展示,感兴趣的可以看看 rCharts 。本文只关心原生的R绘图互动效果的产生方法。但应用这种方法之前首先警告:
- 纯R绘图产生的每次“互动”都要重新绘制图像,需要考虑流量和速度的场合一定要谨慎使用!!
原因是什么,你看完就知道了。
1 鼠标动作与坐标捕获
我们重新看看shiny中plotOutput和imageOutput这两个图像输出控件函数的参数:
library('shiny')args(plotOutput)
## function (outputId, width = "100%", height = "400px", click = NULL, ## dblclick = NULL, hover = NULL, hoverDelay = NULL, hoverDelayType = NULL, ## brush = NULL, clickId = NULL, hoverId = NULL, inline = FALSE) ## NULL
args(imageOutput)
## function (outputId, width = "100%", height = "400px", click = NULL, ## dblclick = NULL, hover = NULL, hoverDelay = NULL, hoverDelayType = NULL, ## brush = NULL, clickId = NULL, hoverId = NULL, inline = FALSE) ## NULL
它们的参数是完全一样的。这里我们要注意四个参数: click , dblclick , hover 和brush ,分别表示鼠标的单击、双击、悬停和刷取区域这四种动作,参数的值可使用clickOpts(),hoverOpts() 或burshOpts() 函数设定。
以上四个参数的作用只有一个:获取鼠标在图像上的位置(或区域)坐标并传递给服务器。坐标信息需要一个变量来传递,这个变量的名称就是 xxxOpts() 函数的id参数的设定值,或者参数值仅写id名称。下面两个语句等价:
## NOT RUNplotOutput('pl', click=clickOpts(id='pl_click'))plotOutput('pl', click='pl_click')
在server端,已捕获的鼠标位置可通过input列表读取。为方便以后编写应用程序代码,我们下面程序可用于查看和分析四种不同鼠标动作的返回值:
shinyApp( ui = fixedPage( plotOutput('pl', click='pl_click', dblclick='pl_dclick', hover='pl_hover', brush='pl_brush'), column(3, textOutput('dtclk', container=pre)), column(3, textOutput('dtdcl', container=pre)), column(3, textOutput('dthov', container=pre)), column(3, textOutput('dtbsh', container=pre)) ), server = function(input, output, session) { output$pl <- renderPlot({ plot(1:10) }) output$dtclk <- renderPrint({ str(input$pl_click) }) output$dtdcl <- renderPrint({ str(input$pl_dclick) }) output$dthov <- renderPrint({ str(input$pl_hover) }) output$dtbsh <- renderPrint({ str(input$pl_brush) }) })
运行程序,发现下面情况:
- 在图像上单击鼠标,发生改变的数据有click和hover
- 在图像上双击鼠标,发生改变的数据有dblclick和hover
- 在图像上移动鼠标,发生改变的只有hover
- 在图像上刷取一个矩形区域,发生改变的有click、hover和brush
2 更新图像
有了图像坐标信息,接下来的工作应该很容易了。比如在鼠标处显示坐标数字:
shinyApp( ui = fixedPage( plotOutput('pl', click='pl_click') ), server = function(input, output, session) { cords <- reactive({ if(is.null(input$pl_click)) return(NULL) clk <- input$pl_click list(x=clk$x, y=clk$y) }) output$pl <- renderPlot({ plot(1:10) xy <- cords() if(!is.null(xy)) text(xy, labels=paste(xy, collapse=', ')) }) })
代码看起来没什么问题,但运行后你会发现图像上 text 语句输出的坐标信息总是一闪而过。 把click换成dblclick或hover也一样的效果。
到底怎么回事?我们再次分析鼠标动作导致图像更新后客户端返回的值,代码仅比前面的多了一个语句(因为每种动作都会有hover动作):
shinyApp( ui = fixedPage( plotOutput('pl', click='pl_click', dblclick='pl_dclick', hover='pl_hover', brush='pl_brush'), column(3, textOutput('dtclk', container=pre)), column(3, textOutput('dtdcl', container=pre)), column(3, textOutput('dthov', container=pre)), column(3, textOutput('dtbsh', container=pre)) ), server = function(input, output, session) { output$pl <- renderPlot({ input$pl_hover ## 新增语句 plot(1:10) }) output$dtclk <- renderPrint({ str(input$pl_click) }) output$dtdcl <- renderPrint({ str(input$pl_dclick) }) output$dthov <- renderPrint({ str(input$pl_hover) }) output$dtbsh <- renderPrint({ str(input$pl_brush) }) })
测试结果显示,图像更新后:
- hover、click、dblclick等数据被清除
- brush数据仍然保留
再回到前一个例子的代码分析,由于hover、click、dblclick清除也是“变化”,而服务器端绘图响应是针对“变化”的,图像对鼠标响应的过程是这样的:
- 鼠标动作使图像重新绘制
- 上一步图像更新导致鼠标动作变化(清除),再绘制一个图像
- 图像更新导致鼠标动作清除,但和上一步状态相同(处于清除状态),不再更新图像
所以每次点击鼠标要绘制两个图,最终得到的仍是没有鼠标点击的图像。
也就是说,不能直接使用hover、click、dblclick触发重新绘图。如果要在随后的图像中使用本次hover、click或dblclick的返回数据,必需在图像更新前先暂时保存它们的值。
只要设一个中间变量过滤无效的鼠标动作,就可以实现在图像中显示鼠标点的坐标:
shinyApp( ui = fixedPage( plotOutput('pl', click='pl_click') ), server = function(input, output, session) { cords <- reactiveValues(xy=NULL) observeEvent( ## 不要使用observe,否则pl_click和cords都会触发响应,可能产生死循环 input$pl_click, { if(!is.null(input$pl_click)) cords$xy <- input$pl_click[c('x', 'y')] }) output$pl <- renderPlot({ plot(1:10) xy <- cords$xy if(!is.null(xy)) text(xy, labels=paste(as.list(xy), collapse=', '), xpd=TRUE, adj=c(0.5,-2)) }) } )
上面程序中plotOutput参数click换成dblclick或hover都是可以的。由于brush数据在图像更新后仍然存在,不需要设置中间变量。
但中间变量只能解决部分问题,如果多个鼠标动作同时在一个图像中使用,“频闪”问题可能会不断。期待将来的shiny版本可以彻底解决这些问题。
3 反向获取数据
nearPoints()和burshedPoints()分别用于获取鼠标附近或已刷取区域内的数据点。它们的使用参数为:
library('shiny')args(nearPoints)
## function (df, coordinfo, xvar = NULL, yvar = NULL, panelvar1 = NULL, ## panelvar2 = NULL, threshold = 5, maxpoints = NULL, addDist = FALSE, ## allRows = FALSE) ## NULL
args(brushedPoints)
## function (df, brush, xvar = NULL, yvar = NULL, panelvar1 = NULL, ## panelvar2 = NULL, allRows = FALSE) ## NULL
- df:是要查询的数据,需要转成 data.frame 类型
- coordinfo:从ui端传过来的鼠标input,如上面的 input$pl_click
- xvar/yvar:如果不是用ggplot2绘图,或者df用于绘制x/y轴数据的名称不是‘x’/‘y’,则必需指定x/y数据在df中的列名称
- panelvar1/2:ggplot2中为facet变量,其他绘图类似于subset功能
- addDist:TRUE/FALSE,是否在原df中添加距离计算结果(列,像素表示)
- allRows:如果为FALSE(默认),返回值为仅包含临近点所在行的数据框;如果为TRUE,返回值是添加了selected列的原数据框df
- threshold, maxpoints:设定最大距离阈值和最多选取的点数(默认最多5个点)
最后请看一个例子:
set.seed(100)dt <- data.frame(x=1:20, y=abs(rnorm(20) * 100))shinyApp( ui = fixedPage( plotOutput('pl', click='pl_click', brush='pl_brush') ), server = function(input, output, session) { pts <- reactiveValues(sel=rep(FALSE, nrow(dt))) observeEvent( input$pl_click, { if(!is.null(input$pl_click)) { df <- nearPoints(dt, input$pl_click, x='x', y='y', allRows=TRUE) pts$sel <- xor(pts$sel, df$selected) } }) observeEvent( input$pl_brush, { if(!is.null(input$pl_click)) { ## 此处判断的是pl_click! df <- brushedPoints(dt, input$pl_brush, x='x', y='y', allRows=TRUE) pts$sel <- xor(pts$sel, df$selected) } }) output$pl <- renderPlot({ plot(dt, cex=ifelse(pts$sel, 10, 1)) }) })
为什么brush中还要判断click?我懒得分析了,反正它们俩共用时如果不判断就会出现“频闪”。
4 SessionInfo
print(sessionInfo(), locale=FALSE)
## R version 3.2.2 (2015-08-14)## Platform: x86_64-pc-linux-gnu (64-bit)## Running under: Debian GNU/Linux 8 (jessie)## ## attached base packages:## [1] stats graphics grDevices utils datasets methods base ## ## other attached packages:## [1] shiny_0.12.2 zblog_0.1.0 knitr_1.11 ## ## loaded via a namespace (and not attached):## [1] R6_2.1.1 magrittr_1.5 formatR_1.2 htmltools_0.2.6## [5] tools_3.2.2 Rcpp_0.12.0 stringi_0.5-5 highr_0.5 ## [9] digest_0.6.8 stringr_1.0.0 xtable_1.7-4 httpuv_1.3.3 ## [13] mime_0.4 evaluate_0.7.2
Created: 2015-09-16 三 18:25
Emacs 24.4.1 (Org mode 8.2.10)
- Shiny应用基础(7):图像互动
- Shiny应用基础(4):数据与图像输出
- Shiny应用基础(1):导言
- Shiny应用基础(3):页面布局
- Shiny应用基础(8):杂项
- Shiny应用基础(2):HTML元素产生方法
- Shiny应用基础(5):数据获取与响应
- Shiny应用基础(6):数据响应的触发与阻止
- 如何使用ShinyApps部署Shiny应用?
- DT&进度条在shiny中的应用
- 【Shiny】基于R-Shiny制作地图App(百度地图)
- Shiny框架小结(1)
- 图像资源(Drawable)基础应用
- R语言用Shiny包快速搭建交互网页应用
- shiny动态仪表盘应用 | 中国世界自然文化遗产可视化案例
- opencv图像基础(1)图像深度
- shiny server (免费版)部署访问密码设置
- 傅里叶变换(互动百科)
- java程序执行过程中动态加载jar包
- java SE复习笔记6
- 测试工具JMeter使用心得1
- 关于 AlphaGo 论文的阅读笔记
- HDU 4638 Group [离线+树状数组]
- Shiny应用基础(7):图像互动
- 杭电1236排名
- 利用手机距离感应器来切换是用扬声器听音乐还是听筒听音乐
- TCP/IP 教程(针对LINUX的网络基础请参看 《鸟哥的Linux私房菜 服务器架设篇(第三版) 》)
- log4j日志问题
- 简单计算机的设计(代码)
- huffman编码压缩算法
- System.arraycopy方法的使用
- 《炉石传说》架构设计赏析(7):使用Google.ProtocolBuffers处理网络消息