วิธีรับฟังนิพจน์เหตุการณ์มากกว่าหนึ่งรายการภายใน Shiny eventReactive handler


88

ฉันต้องการให้สองเหตุการณ์ที่แตกต่างกันเพื่อกระตุ้นการอัปเดตข้อมูลที่ใช้โดยพล็อต / เอาต์พุตต่างๆในแอปของฉัน ปุ่มหนึ่งคือปุ่มที่คลิก ( input$spec_button) และอีกปุ่มคือจุดบนจุดที่คลิก ( mainplot.click$click)

โดยทั่วไปฉันต้องการแสดงรายการทั้งสองอย่างในเวลาเดียวกัน แต่ฉันไม่แน่ใจว่าจะเขียนโค้ดอย่างไร นี่คือสิ่งที่ฉันมีตอนนี้:

ในเซิร์ฟเวอร์ R:

data <- eventReactive({mainplot.click$click | input$spec_button}, {
    if(input$spec_button){
      # get data relevant to the button
    } else {
      # get data relevant to the point clicked
    }
  })

แต่ประโยค if-else ไม่ทำงาน

Error in mainplot.click$click | input$spec_button : operations are possible only for numeric, logical or complex types

-> มีฟังก์ชั่นผสมแอคชั่นบางประเภทที่ฉันสามารถใช้กับmainplot.click$click | input$spec_buttonประโยคนี้ได้หรือไม่?


คุณสามารถตรวจสอบผลลัพธ์ของ! is.null (input $ spec_button) ได้หรือไม่
Gopala

คำตอบ:


97

ฉันรู้ว่านี่เก่า แต่ฉันก็มีคำถามเหมือนกัน ในที่สุดฉันก็คิดออก คุณรวมนิพจน์ไว้ในวงเล็บปีกกาและแสดงรายการเหตุการณ์ / วัตถุปฏิกิริยา ของฉัน (พร้อมเพรียง) เดาว่าเป็นเงาเพียงแค่ดำเนินการวิเคราะห์ตัวชี้เดียวกันปฏิกิริยาที่แสดงออกบล็อกนี้เป็นไปมาตรฐานreactiveบล็อก

observeEvent({ 
  input$spec_button
  mainplot.click$click
  1
}, { ... } )

แก้ไข

อัปเดตเพื่อจัดการกรณีที่บรรทัดสุดท้ายในนิพจน์ส่งกลับค่า NULL เพียงแค่คืนค่าคงที่


1
การเปลี่ยนคำตอบที่ยอมรับเป็นคำตอบนี้เนื่องจากดูเหมือนว่าจะเป็นทางออกที่ดีกว่าคำตอบเดิมของฉัน
Hillary Sanders

3
คุณสามารถระบุได้หรือไม่ว่าเหตุการณ์ใดถูกกระตุ้น
PeterVermont

ไม่ใช่ว่าฉันรู้ ฉันได้ทำสิ่งนี้ในบางกรณีโดยการติดตามตัวแปรเหล่านี้ในตัวแปรแยกต่างหากและทำการเปรียบเทียบด้วยตัวเองเพื่อดูว่ามีการเปลี่ยนแปลงใดบ้าง แต่มันน่าเกลียด. น่าจะดีกว่าที่จะใส่โค้ดหลักในฟังก์ชันจากนั้นให้มี followEvents สองรายการที่เรียกใช้ fn จากนั้นทำสิ่งที่เฉพาะเจาะจงสำหรับแต่ละเหตุการณ์
Duncan Brown

8
เพียงคำเตือน: observeEventใช้ignoreNULL = TRUEโดยค่าเริ่มต้นซึ่งหมายความว่าถ้าmainplot.click$click(ค่าส่งคืน) เป็นNULLตัวจัดการจะไม่ถูกเรียกแม้ว่าจะinput$spec_buttonมีการเปลี่ยนแปลงก็ตาม ฉันขอแนะนำคำตอบของ @ JustAnother เพื่อป้องกันไม่ให้ตกหลุมพรางนี้
greg L

1
คำเตือนอื่น: ในการทดสอบของฉันฉันพบว่าไวยากรณ์วงเล็บนี้ ( {}) ต้องการให้แต่ละเหตุการณ์อยู่ในบรรทัดใหม่ของตัวเองมิฉะนั้นจะล้มเหลวด้วย "ข้อผิดพลาดในการแยกวิเคราะห์ ... " ทันทีที่โปรแกรมแยกวิเคราะห์พบเหตุการณ์ที่สอง เช่นทั้งหมดในบรรทัดเดียว: observeEvent({input$spec_button mainplot.click$click}, {...})ล้มเหลว คำตอบของ @ JustAnother โดยใช้ไวยากรณ์การรวม S3 Generic ( c()) ทำงานโดยไม่คำนึงถึงการขึ้น
Brian D

57

นอกจากนี้:

observeEvent(c( 
  input$spec_button,
  mainplot.click$click
), { ... } )

6
แม้ว่าสิ่งนี้จะดูคล้ายกับคำตอบของ @DuncanBrown มาก แต่ฉันพบสถานการณ์ที่ปุ่มการทำงาน 2 ปุ่มทริกเกอร์โมดอลสิ่งนี้ใช้งานได้และ{เวอร์ชันไม่ ฉันไม่สามารถอธิบายได้ว่าทำไมจึงเป็นเช่นนั้น
John Paul

2
เพิ่มความคิดเห็นในคำตอบของ @Duncan Brown ว่าคำตอบนี้แตกต่างกันอย่างไร (และ IMO ที่ดีกว่า)
greg L

อันนี้ใช้ไม่ได้สำหรับฉัน - ฉันได้รับข้อผิดพลาด (มันวาว 1.0.5)
potockan

มีวิธีค้นหาว่าเหตุการณ์ใดถูกกระตุ้นหรือไม่? สมมติว่าฉันมีสองปุ่มinput$button1และinput$button2มันทำสิ่งที่คล้ายกันมากเพียงแค่ใช้ดัชนีที่แตกต่างกัน ฉันต้องการหลีกเลี่ยงการคัดลอกโค้ดหลาย ๆ ครั้งเพียงเพราะฉันไม่รู้ดัชนี ขอบคุณ!
Nikos Bosse

11

ฉันได้แก้ไขปัญหานี้ด้วยการสร้างวัตถุที่ตอบสนองและใช้ในนิพจน์การเปลี่ยนแปลงเหตุการณ์ ดังต่อไปนี้:

xxchange <- reactive({
paste(input$filter , input$term)
})

output$mypotput <- eventReactive( xxchange(), {
...
...
...
} )

5
นี่เป็นคำตอบที่ดีมากซึ่งจะได้รับประโยชน์จากคำอธิบายเพิ่มเติม แม้ว่าคำตอบที่ได้รับการยอมรับจะตรงไปตรงมามากขึ้นซึ่งทำให้โปรแกรมพื้นฐานดีขึ้น แต่คำตอบนี้เหมาะกับรหัสที่มีขนาดใหญ่และซับซ้อนมากกว่า ดูเหมือนจะขาดสองจุดจากคำตอบ (1) วาง (หรือรายการ) ทำให้ทั้งสองเหตุการณ์อยู่ในบรรทัดเดียวกันทำให้โค้ดมีขนาดกะทัดรัดมากขึ้น (2) วัตถุที่มีปฏิกิริยาช่วยประหยัดความพยายามในการทำซ้ำสองเหตุการณ์เดียวกันซ้ำแล้วซ้ำอีกหากมีผู้ฟังมากกว่าหนึ่งคนกำลังฟังเหตุการณ์ชุดเดียวกัน
เกษตรกร

5

นี่คือวิธีแก้ปัญหาที่ฉันคิดขึ้น: โดยพื้นฐานแล้วสร้างที่reactiveValuesเก็บข้อมูลว่างเปล่าแล้วแก้ไขค่าตามสองobserveEventอินสแตนซ์ที่แยกจากกัน

  data <- reactiveValues()
  observeEvent(input$spec_button, {
    data$data <- get.focus.spec(input=input, premise=premise, 
                                itemname=input$dropdown.itemname, spec.info=spec.info)
  })
  observeEvent(mainplot.click$click, {
    data$data <- get.focus.spec(input=input, premise=premise, mainplot=mainplot(),
                                mainplot.click_focus=mainplot.click_focus(),
                                spec.info=spec.info)  
  })

3
จะlist(mainplot.click$click, input$spec_button)ทำงานตามวิธีของ OP
John

1

สิ่งนี้ยังสามารถทำได้ด้วย eventReactive เพียงแค่ใส่การกระทำของคุณในเวกเตอร์

eventReactive(
  c(input$spec_button, mainplot.click$click), 
{ ... } )

0

แนวคิดในที่นี้คือการสร้างฟังก์ชันรีแอคทีฟซึ่งจะดำเนินการตามเงื่อนไขที่คุณต้องการส่งผ่านในการสังเกตเหตุการณ์จากนั้นคุณสามารถส่งผ่านฟังก์ชันปฏิกิริยานี้เพื่อตรวจสอบความถูกต้องของคำสั่ง ตัวอย่างเช่น:

validate_event <- reactive({
    # I have used OR condition here, you can use AND also
    req(input$spec_button) || req(mainplot.click$click)
})

observeEvent(validate_event(), 
    { ... } 
)

ให้เข้ารหัส!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.