问题
I am using Shiny and R to visualize my data interactively. I would like to draw an interactive scatter plot of Petal.Width versus Petal.Length in Iris dataset and cluster the points based on k clusters (user input) and p, the percentage of data rows dedicated to the training dataset (user input). I added a hover feature to the scatterplot so that by clicking on each point, the whole dataset for that point will be demonstrated.
The output should look like this:
# Loading Libraries
library(shiny)
library(caret)
library(ggplot2)
data(iris)
ui <- pageWithSidebar(
headerPanel("Clustering iris Data"),
sidebarPanel(
sliderInput("k", "Number of clusters:",
min = 1, max = 5, value = 3),
sliderInput("prob", "Training percentage:",
min=0.5, max=0.9, value = 0.7)),
mainPanel(
# img(src='iris_types.jpg', align = "center", height="50%", width="50%"),
plotOutput("plot1", click = "plot_click"),
verbatimTextOutput("info")
)
)
server <- function(input, output) {
inTrain <- createDataPartition(y=iris$Species,
p=input$prob,
list=FALSE)
training <- iris[ inTrain,]
testing <- iris[-inTrain,]
kMeans1 <- kmeans(subset(training,
select=-c(Species)),
centers=input$k)
training$clusters <- as.factor(kMeans1$cluster)
output$plot1 <- renderPlot({
qplot(Petal.Width,
Petal.Length,
colour = clusters,
data = training,
xlab="Petal Width",
ylab="Petal Length")
})
output$info <- renderPrint({
# With ggplot2, no need to tell it what the x and y variables are.
# threshold: set max distance, in pixels
# maxpoints: maximum number of rows to return
# addDist: add column with distance, in pixels
nearPoints(iris, input$plot_click, threshold = 10, maxpoints = 1,
addDist = FALSE)
})
}
shinyApp(ui, server)
When I run the app in R Studio, I receive the following error:
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.)
回答1:
As mentioned by @Clemsang you are using reactives values outside an oberserver/render*
function.
What you want to do is to create a reactive
environment, where you use your inputs. That is, something which gets recalculated whenever the inputs change. Thus, you need to wrap your training calculation in reactive
and when you want to use it in your render function, you "call" it by adding ()
. I like to name my reactives with a verb, to highlight the fact that I actually do something when these functions are called, hence the name get_training_data
:
server <- function(input, output) {
get_training_data <- reactive({ ## now your inputs are in a reactive environment
inTrain <- createDataPartition(y=iris$Species,
p=input$prob,
list=FALSE)
training <- iris[ inTrain,]
testing <- iris[-inTrain,]
kMeans1 <- kmeans(subset(training,
select=-c(Species)),
centers=input$k)
training$clusters <- as.factor(kMeans1$cluster)
training
})
output$plot1 <- renderPlot({
qplot(Petal.Width,
Petal.Length,
colour = clusters,
data = get_training_data(),
xlab="Petal Width",
ylab="Petal Length")
})
output$info <- renderPrint({
# With ggplot2, no need to tell it what the x and y variables are.
# threshold: set max distance, in pixels
# maxpoints: maximum number of rows to return
# addDist: add column with distance, in pixels
nearPoints(iris, input$plot_click, threshold = 10, maxpoints = 1,
addDist = FALSE)
})
}
来源:https://stackoverflow.com/questions/55531377/error-in-running-r-shiny-app-operation-not-allowed-without-an-active-reactive-c