R Грешка в лъскава реактивна среда при изграждане на приложения, използващи графични данни на Neo4j

Създавам интерактивно приложение Shiny, използвайки графични данни на Neo4j, като използвам RNeo4j пакет, за да свържа Neo4j с R.

Приложението съдържа таблица, показваща свойствата на графичните данни, извлечени от Neo4j, потребителите могат да преглеждат и променят съдържанието на таблицата (свойства на графичните данни). Промените могат да бъдат записани обратно в Neo4j като актуализация на свойствата на графичните данни. Тази функция може да бъде изпълнена с помощта на updateProp & getOrCreateNode функция в RNeo4j пакет.

Имам обаче реактивна грешка.

По-долу е моят код:

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)

По-долу е съобщението за грешка:

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.)

По следи и грешки приложението Shiny може да работи правилно, ако премахна кода на записаните промени обратно в Neo4j, което е последната част от кода. Това обаче е основната функция на този проект.

Също така, тази записана функция работеше правилно, като стоеше сама извън Shiny. Така че проблемът е взаимодействието между 2 части.

Чудя се дали мога да добавя observeEvent в Shiny, за да реша този проблем.

Благодаря предварително.


person MMAASS    schedule 12.03.2019    source източник


Отговори (1)


Както казахте, последната част от вашия код причини проблема. Причината е, че използвате reactives в тази част от кода. Това означава, че използвате input$category_rows_selected, input$category_status и input$status, които нямат фиксирана стойност, но зависят от взаимодействието ви с приложението.

В зависимост от това какво искате да направите, имате основно 2 възможности:

  1. Включете фрагмента код в isolate. В този случай обаче вашият код никога няма да бъде актуализиран, когато промените съответните входове.
  2. Включете фрагмента код в observe. В този случай всеки път, когато някой от входовете (както е изброено по-горе) промени стойността си, този код ще бъде изпълнен. Ако искате вашата част от кода да се изпълнява само ако някои от входовете се променят, можете да isolate входовете, от които не искате да поемате зависимост.

Например този код ще се изпълнява при всяка промяна на input$category_rows_selected или input$category_status, но не и при промяна на input$status, защото е обвит в 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))
  }
})
person thothal    schedule 12.03.2019
comment
Благодаря ти, тотал! Опитах се да използвам функцията за наблюдение като това, което описахте, но получих грешката по-долу: Слушам на 127.0.0.1:3918 Предупреждение: Грешка в if: аргументът е с дължина нула [Няма налична следа на стека] - person MMAASS; 13.03.2019
comment
най-вероятно защото някой от вашите input$ е NULL по време на стартиране и не можете да подмножествате от NULL. Лесно qorkaround увийте всичко input$ в req(), например: info$Category_Status[req(input$category_rows_selected)] - person thothal; 13.03.2019