简体   繁体   中英

R Shiny reactive environment error when building Apps using Neo4j graph data

I am building an interactive Shiny app using Neo4j graph data by using RNeo4j package to connect Neo4j with R.

The app contains a table showing properties of graph data pulled from Neo4j, users can view and change table content (properties of graph data). The changes can be written back to Neo4j as an update of graph data properties. This function can be completed using updateProp & getOrCreateNode functiona in RNeo4j package.

However, I have a reactive error.

Below is my code:

library(RNeo4j)
library(dplyr)
library(shiny)
library(shinydashboard)
library(visNetwork)
library(tidyr)
library(sqldf)
library(igraph)
library(plotly)
library(stringi)
library(stringr)

graph = startGraph("http://localhost:7474/db/data/", username = "xxx", password = "xxx")
summary(graph)

# build dashboard
# UI items list 
header <- dashboardHeader(
  title = "Neo4j"
)

sidebar <- dashboardSidebar(
  sidebarMenu (
  )
)

body <- dashboardBody(
  tabItems(
    tabItem(tabName = "dashboard1",
            box(textOutput("aa")),
            box(title = "CATEGORY", DT::dataTableOutput("category")),
            box(uiOutput("category_status"))

    )
  )
)

# UI
ui <- dashboardPage(header, sidebar, body)

# Server
server <- function(input, output, session) {

  # Query graph data and properties from Neo4j and store them in table format in R 
  query = "
  MATCH (c:Category)
  RETURN c.id AS Category, c.Price AS Price, c.status AS Category_Status
  "
  info = cypher(graph, query) # R Table to store Neo4j data

  # Build Shiny output tables
  output$i1 <- renderTable(info)
  output$category = DT::renderDataTable(info, selection = 'single')
  # This is to build the function of change the status of category with 3 options
  output$category_status = renderUI({
    x = info[input$category_rows_selected, ]
    if (length(x)){
      selectInput("category_status", "", 
                  c( "Sold", "On Sale","Out of Stock"), 
                  selected = x$Category_Status)
    }
  })
  # Table to examine if the status change was made successfully
  output$aa<-renderText(input$category_status)

  # Write back the changes made in Shiny to Neo4j using "updateProp" & "getOrCreateNode" function in RNeo4j
  if(info$Category_Status[input$category_rows_selected] != input$category_status) {
    category_num = as.numeric(substring(info$Category[input$category_rows_selected], 16))
    updateProp(getOrCreateNode(graph, "Category", Category = paste("CC_CCAA_AAC.0C-", category_num, sep="")), 
               status = input$status)
  }
}

# Shiny dashboard
shiny::shinyApp(ui, server)

Below is the error message:

Listening on http://127.0.0.1:4401
Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
  55: stop
  54: .getReactiveEnvironment()$currentContext
  53: .subset2(x, "impl")$get
  52: $.reactivevalues
  50: server [#44]
Error in .getReactiveEnvironment()$currentContext() : 
  Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)

By trail and error, the Shiny app can work properly if I remove the code of written the changes back to Neo4j, which is the last part of the code. However, this is the core function of this project.

Also, this written-back function worked properly by standing alone outside of Shiny. So the problem is the interaction between 2 parts.

I am wondering if I can add observeEvent in Shiny to solve this problem.

Thanks in advance.

As you said the last part of your code caused the problem. The reason behind is that you use reactives in this code chunk. That is you use input$category_rows_selected , input$category_status and input$status which do not have a fixed value but depend on your interaction with the app.

Depending on what you want to do you have basically 2 options:

  1. Include the code chunk in isolate . In this case, however, your code will never be updated when you change the respective inputs.
  2. Include the code chunk in observe . In this case whenever either of the inputs (as listed above) change its value, this code will be executed. If you want your code chunk to run only if some of the inputs change you can isolate the inputs you do not want to take a dependency on.

For instance this code will be executed whenever input$category_rows_selected or input$category_status change but not if input$status change because it is wrapped in isolate :

observe({
   if(info$Category_Status[input$category_rows_selected] != input$category_status) {
       category_num = as.numeric(substring(info$Category[input$category_rows_selected], 16))
       updateProp(getOrCreateNode(graph, "Category", 
                  Category = paste("CC_CCAA_AAC.0C-", category_num, sep="")), 
                  status = isolate(input$status))
  }
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM