請試試這個:
方法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()
。
謝謝你的完美。起初我不明白爲什麼第二個'geom_point'圖層有數據源'selected()',但現在我可以看到'selected()'函數返回'selected_points'對象。出於興趣,我是否可以將'selected_points'作爲數據源並且不從函數返回對象?如果是這樣,你爲什麼要這樣做,而不是另一種呢? – roman
好吧,這完全是關於反應性或當特定數據被改變(反應性)時將執行哪一段代碼。是的,您可以使用'selected_points',但您必須通過向'input $ clicked'添加一個虛擬調用來實施反應性(請參閱我的編輯答案的_Approach 2_)。我更喜歡使用使得依賴更加明確的反應函數。 – Uwe
感謝您的擴大答案 - 非常有幫助。 – roman