2016-11-25 126 views
7

我熟悉閃亮的基礎知識,但在這裏掙扎着。我希望能夠添加一個ggplot圖層,當一個點被點擊時突出顯示該點。我知道這是可能與ggvis,並在畫廊有一個很好的例子,但我希望能夠使用nearPoints()作爲用戶界面輸入捕捉點擊。動態ggplot圖層閃亮nearPoints()

我嘗試了一些東西(見下文),它與ggplot圖層分開工作,然後消失。我曾嘗試對此進行各種編輯,例如reactive()eventReactive()等。

任何幫助深表感謝......

library(shiny) 
library(ggplot2) 

shinyApp(
    ui = shinyUI(
     plotOutput("plot", click = "clicked") 
    ), 

    server = shinyServer(function(input, output) { 
    output$plot <- renderPlot({ 
     ggplot(mtcars, aes(x = mpg, y = wt)) + 
     geom_point() + 
     geom_point(data = nearPoints(mtcars, input$clicked), colour = "red", size = 5) 
    }) 
    }) 
) 

我想我明白爲什麼概念這是行不通的。該圖依賴於input$clicked,這意味着當input$clicked更改該繪圖重新呈現時,但這又重置input$clicked。捕捉22位的情況。

回答

8

請試試這個:

方法1(推薦)

library(shiny) 
library(ggplot2) 

# initialize global variable to record selected (clicked) rows 
selected_points <- mtcars[0, ] 
str(selected_points) 


shinyApp(
    ui = shinyUI(
    plotOutput("plot", click = "clicked") 
), 

    server = shinyServer(function(input, output) { 

    selected <- reactive({ 
     # add clicked 
     selected_points <<- rbind(selected_points, nearPoints(mtcars, input$clicked)) 
     # remove _all_ duplicates if any (toggle mode) 
     # http://stackoverflow.com/a/13763299/3817004 
     selected_points <<- 
     selected_points[!(duplicated(selected_points) | 
          duplicated(selected_points, fromLast = TRUE)), ] 
     str(selected_points) 
     return(selected_points) 
    }) 

    output$plot <- renderPlot({ 
     ggplot(mtcars, aes(x = mpg, y = wt)) + 
     geom_point() + 
     geom_point(data = selected(), colour = "red", size = 5) 
    }) 
    }) 
) 

如果你點擊某個點時它被高亮顯示。如果您再次單擊該按鈕,高亮區會再次關閉(切換)。

該代碼使用全局變量selected_points來存儲實際突出顯示的點(選定)和一個反應性表達式selected(),每當單擊一個點時它就更新全局變量。

str(selected_points)可能有助於可視化工作,但可以刪除。

方法2(替代)

存在使用observe()代替reactive()和參考全局變量selected_points,而不是直接從函數返回該對象的一個​​稍微不同的方法:

library(shiny) 
library(ggplot2) 

selected_points <- mtcars[0, ] 
str(selected_points) 


shinyApp(
    ui = shinyUI(
    plotOutput("plot", click = "clicked") 
), 

    server = shinyServer(function(input, output) { 

    observe({ 
     # add clicked 
     selected_points <<- rbind(selected_points, nearPoints(mtcars, input$clicked)) 
     # remove _all_ duplicates (toggle) 
     # http://stackoverflow.com/a/13763299/3817004 
     selected_points <<- 
     selected_points[!(duplicated(selected_points) | 
          duplicated(selected_points, fromLast = TRUE)), ] 
     str(selected_points) 
    }) 

    output$plot <- renderPlot({ 
     # next statement is required for reactivity 
     input$clicked 
     ggplot(mtcars, aes(x = mpg, y = wt)) + 
     geom_point() + 
     geom_point(data = selected_points, colour = "red", size = 5) 
    }) 
    }) 
) 

當然,您可以直接在ggplot調用中使用全局變量selected_points,而不用調用反應函數selected()。但是,只要input$clicked更改,就必須確保renderPlot()已被執行。因此,的虛擬引用必須包含在renderPlot()內的代碼中。

現在,不再需要反應函數selected(),並且可以用observe()表達式替換。與reactive()相反,observe()不返回值。只要修改了input$clicked,它就會更新全局變量selected_points

方法3(反應值)

該方法避免了全局變量。相反,它使用reactiveValues創建一個類似列表的對象rv,具有用於響應式編程的特殊功能(請參閱?reactiveValues)。

library(shiny) 
library(ggplot2) 

shinyApp(
    ui = shinyUI(
    plotOutput("plot", click = "clicked") 
), 

    server = shinyServer(function(input, output) { 

    rv <- reactiveValues(selected_points = mtcars[0, ]) 

    observe({ 
     # add clicked 
     rv$selected_points <- rbind(isolate(rv$selected_points), 
              nearPoints(mtcars, input$clicked)) 
     # remove _all_ duplicates (toggle) 
     # http://stackoverflow.com/a/13763299/3817004 
     rv$selected_points <- isolate(
     rv$selected_points[!(duplicated(rv$selected_points) | 
           duplicated(rv$selected_points, fromLast = TRUE)), ]) 
     str(rv$selected_points) 
    }) 

    output$plot <- renderPlot({ 
     ggplot(mtcars, aes(x = mpg, y = wt)) + 
     geom_point() + 
     geom_point(data = rv$selected_points, colour = "red", size = 5) 
    }) 
    }) 
) 

請注意,在observer部分引用rv需要isolate()被封裝,以確保只有改變input$clicked將觸發代碼的執行中observer。否則,我們會得到一個無限循環。每當無效值rv被更改時,觸發renderPlot的執行。

結論

個人而言,我使用反應性官能團,其使得依賴關係(反應性)更明確的偏好的方法1。我發現在方法2中輸入$點擊的虛擬調用較不直觀。方法3需要徹底瞭解反應性,並在正確的地方使用isolate()

+0

謝謝你的完美。起初我不明白爲什麼第二個'geom_point'圖層有數據源'selected()',但現在我可以看到'selected()'函數返回'selected_points'對象。出於興趣,我是否可以將'selected_points'作爲數據源並且不從函數返回對象?如果是這樣,你爲什麼要這樣做,而不是另一種呢? – roman

+1

好吧,這完全是關於反應性或當特定數據被改變(反應性)時將執行哪一段代碼。是的,您可以使用'selected_points',但您必須通過向'input $ clicked'添加一個虛擬調用來實施反應性(請參閱我的編輯答案的_Approach 2_)。我更喜歡使用使得依賴更加明確的反應函數。 – Uwe

+0

感謝您的擴大答案 - 非常有幫助。 – roman