R shiny invalid formula - r

I have a problem. I want to use sidebar to curb time series plot, however, I get invalid formula error when trying to do the plot. Can someone pls help?
server.r
library(shiny)
library(BCA)
data(Eggs)
# Define server logic required to plot
shinyServer(function(input, output) {
formulaX <- reactive({
tmp <- paste(input$range,collapse = ":")
paste("Eggs[",tmp,",1]")
})
formulaY <- reactive({
tmp1 <- paste(input$range,collapse = ":")
paste("Eggs[",tmp1,",5]")
})
# Return the formula text for printing as a caption
output$caption <- renderText({
paste(formulaX(),formulaY(),sep = " ")
})
#creating plot -ERROR
output$mpgPlot <- renderPlot({
plot(as.formula(formulaX()),as.formula(formulaY()))
})
})
ui.r
library(shiny)
# Define UI
shinyUI(pageWithSidebar(
# Application title
headerPanel("Eggs"),
sidebarPanel(
# Specification of range within an interval
sliderInput("range", "Range:",
min = 1, max = 105, value = c(20,50))
),
mainPanel(
h3(textOutput("caption")),
plotOutput("mpgPlot")
)
))

"Eggs[1:10,1]" is not a formula, it is a character-representation of a subset. Since you are always choosing columns 1 and 5, your "formula" is always "Cases ~ Week" (I don't have BCA installed, I think that's correct), and you are intending to use a subset of rows from the data.
Perhaps this would work instead (hasty, some programming safeguards would be appropriate):
# no need for formulaX(), formulaY()
# not certain what you want/need from output$caption
dataX <- reactive({ Eggs[input$range[1]:input$range[2],,drop = FALSE] })
and your plot:
output$mpgPlot <- renderPlot({
plot(Cases ~ Week, data = dataX())
})
or
output$mpgPlot <- renderPlot({
x <- dataX()
plot(x$Week, x$Cases)
})

Related

Simulate real time data visualization using Shiny

I am creating a POC, where real time update will reflect on my shiny application. The idea is to plot the frequency distribution of the data that is being generated from a server. Since I do not have access to the server yet, I have simulated a data creation which I am feeding to my plot. I can see the data properly on my console, but nothing is being displayed on my application. I am sure that there is something I am missing out. I think the reason I am unable to view the plot is because the data is getting updated faster than the rendering speed. Is there any way to modify that.
library(shiny)
library(magrittr)
library(plotly)
ui <- shinyServer(fluidPage(
plotOutput("plot")
))
alarms = c("NodeDown","GrowthRate","DecayRate","DiskFull","ServiceDown","Planned_shutdown","etc.....etc","ServerOutage",
"No Casue")
server <- shinyServer(function(input, output, session){
# Function to get new observations
get_new_data <- function(){
new = sample(alarms,1)
# data <- new %>% rbind %>% data.frame
return(new)
}
# Initialize my_data
my_data <<- get_new_data()
# Function to update my_data
update_data <- function(){
my_data <<- c(get_new_data(), my_data)
}
output$plot <- renderPlotly({
invalidateLater(1000, session)
update_data()
# print(my_data)
dd = update_data()
dd = as.data.frame(table(dd))
print(dd)
plot_ly(dd, x = ~dd, y = ~Freq)
})
# Plot the 30 most recent values
# output$first_column <- renderPlot({
# print("Render")
# invalidateLater(1000, session)
# update_data()
# print(my_data)
# plot(X1 ~ 1, data=my_data[1:30,], ylim=c(-3, 3), las=1, type="l")
# })
})
shinyApp(ui=ui,server=server)
You should use reactiveValues to append your vector, and use reactiveTimer with observeEvent to trigger it every second
Also, if you want to use renderPlotly in server, you should use plotlyOutput rather than plotOutput in ui
Try this:
library(shiny)
library(magrittr)
library(plotly)
ui <- shinyServer(fluidPage(
plotlyOutput("plot")
))
alarms = c("NodeDown","GrowthRate","DecayRate","DiskFull","ServiceDown","Planned_shutdown","etc.....etc","ServerOutage",
"No Casue")
server <- shinyServer(function(input, output, session){
get_new_data <- function(){
new = sample(alarms,1)
return(new)
}
my_data <-reactiveValues(data=get_new_data())
observeEvent(reactiveTimer(2000)(),{ # Trigger every 2 seconds
my_data$data<-c(get_new_data(),my_data$data)
print(my_data$data)
})
output$plot <- renderPlotly({
dd=as.data.frame(table(my_data$data))
print(dd)
plot_ly(dd, x = ~Var1, y = ~Freq)
})
})
shinyApp(ui=ui,server=server)

How to render ggplot from a function that returns a list of multiple objects in Shiny

I have an r script includes a Identify_IP() that returns a list of dataframe and a ggplot. I want to call the script and render both the dataframe and the plot.
This is Identify_IP() function. I took off unrelative code and kept only the plot, lines and ggplot code to give a clear example of my type of ggplot.
library(ggplot2)
library(matrixStats)
library(fda.usc)
#df <- read.table("name.XLS", header = FALSE)
Identify_IP = function(df1){
mlearn <- df1[,'V7']
formul <- plot(blue_curve$x, blue_curve$y * 30, type = 'l', col = 'blue')
formula_deriv <- lines(blue_curve$x, red_curve$y1 * 30, col = 'red')
p <- ggplot(df1, aes(blue_curve$x)) +
geom_line(aes(y = blue_curve$y, colour = "0 Deriv")) +
geom_line(aes(y = red_curve$y1, colour = "1st Deriv")) +
geom_vline(xintercept = x_loc) + geom_hline(yintercept = 0)
return(list(df1,p))
}
Now, this is a modified Shiny code based on amrr and micstr suggestion.
source('InflectionP2.R', local = TRUE)
library(ggplot2)
library(shiny)
runApp(
list(
ui = fluidPage(
titlePanel("Upload your file"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xls file',
accept = c(".XLS")),
actionButton("btn", "Update Table"),
actionButton("btn1", "Display Plot")
),
mainPanel(
tableOutput('what'),
plotOutput('pl'))
)
)
,
server = function(input, output, session){
dataOP <- reactive({
inFile <- input$file1
if (is.null(input$file1))
return(NULL)
dfs <- Identify_IP(read.table(inFile$datapath))
return(dfs)
})
observeEvent(input$btn, output$what <- renderTable({
dataOP()[[1]]
}))
observeEvent(input$btn1, output$pl <- renderPlot({
pp <- dataOP()
pp[[2]]
}))
}))
This was really helpful in teaching me how to call r script in reactive(). And it makes sense to me. Yet, it render the table but the Display Plot button is not rendering the plot. Does my ggplot in Identify_IP function has anything to do with not being able to display the plot? I also tried print(ggplot(pp[[2]])) and still the same.
I managed to get this working.
Note I used the internal data set iris and made a toy Identify_IP function as I do not have your code.
Note you still need to choose a file to trigger the events but it will ignore that file and use iris data.
Workaround I used [[1]] to get the table not dataOP()$tble
CODE
library(shiny)
library(ggplot2)
# source('InflectionP2.R', local = TRUE)
# MAKE TEST FUNCTION
Identify_IP <- function(mydata) {
#shrink data
tble <- head(mydata)
plt <- ggplot(data = head(mydata),
mapping = aes(y = Sepal.Length,
x = Petal.Length)) + geom_point()
return(list(tble, plt))
}
runApp(
list(
ui = fluidPage(
titlePanel("Upload your file"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xls file',
accept = c(".XLS")),
actionButton("btn", "Update Table"),
actionButton("btn1", "Display Plot")
),
mainPanel(
tableOutput('what'),
plotOutput('pl'))
)
)
,
server = function(input, output, session){
dataOP <- reactive({
inFile <- input$file1
if (is.null(input$file1))
return(NULL)
# ORIGINAL dfs <- Identify_IP(read.table(inFile$datapath))
# using internal dataset for example
dfs <- Identify_IP(iris)
# ORIGINAL list(tble = dfs, plt = dfs)
# lets just return your dfs, its already a list in code above
return(dfs)
})
observeEvent(input$btn, output$what <- renderTable({
#print(dataOP()) # debug line that led to [[1]] idea
# ORIGINAL dataOP()$tble
# just say first in list
dataOP()[[1]]
}))
observeEvent(input$btn1, output$pl <- renderPlot({
#ggplot(dataOP()$plt)
# since already a plot just need to index it
# I found [[2]] worked better than explicit dataOP()$plt
pp <- dataOP()
pp[[2]]
}))
}))
RESULT
Voila!
1) Try print (ggplot(dataOP()$plt))
Take a look at this answer I wrote.
2) Sorry its hard to interpret without your ggplot code bit and data. Given #amrrs questions can you try debug in your Shiny code with print() and str() temporary lines to see what your data is returning. i.e.
print(dataOP()$plt)
str(dataOP())
Worse case, try split your code in two. So Identify_IP code to do the data leg and then make a Print_IP with the ggplot code that just returns the plot. It might rule out your chart is not the problem.
3) Take a look at reactiveValues()
https://shiny.rstudio.com/reference/shiny/0.11/reactiveValues.html
It "bakes" a result that was reactive. The type coming out of your chart may be a reactive type not a chart type. Perhaps share any error messages you are getting.

Dynamically choose inputs based on reactive subset data in shiny

Setup: I already have build a shiny-app with two plots. I used the flexdashboard-package to create two plots in two tabs. In addition I programmed the whole shiny-app in R-markdown.
Now I want to create an interface where the user can subset the data. That part itself works. However I also need to perform some calculations with the subsetted data, before I do my two plots.
Is there any way I can transform some subsetted object like mydata to a dataframe? My problem is that I need to use this subsetted object also in the UI part of the other plots.
EDIT: I specifically need some way to transport my selection from checkboxGroupInput to selectInput("cat_1"," category 1:",choices = levels(mydata()$mycat).
### 1. Create some sample data
myrows<-sample(letters,12)
exdata<- data.frame(mycat=rep(myrows,2),yr=rep(1:2,each=12),KPI_1=rnorm(24),
KPI_2=round(runif(24,1,20)),KPI_3=rbinom(24,6,0.5))
### 2. UI part
fluidPage(fluidRow(
checkboxGroupInput("comp", "Categories",myrows,myrows,inline=TRUE),
actionButton("go", "Update"),
textOutput("txt"),
tableOutput("head"))
)
### 3. Server part
mydata<-eventReactive(input$go,{
res<-subset(exdata,mycat%in%input$comp)
return(res)
})
output$txt <- renderText({
paste("You chose", paste(input$comp, collapse = ", "))
})
output$head <- renderTable({
mydata()
})
In the next chunk I do this:
library(plotly)
library(shiny)
### 4. UI part of my plot
fluidRow(sidebarLayout(sidebarPanel(
selectInput("cat_1",
" category 1:",
choices = levels(mydata()$mycat),
selected = levels(mydata()$mycat)[1]),
selectInput("cat_2",
" category 2:",
choices = levels(mydata()$mycat),
selected = levels(mydata()$mycat)[2])),
mainPanel(plotlyOutput("plot3", height = 300, width = 700))))
### 5. Server part of my plot
output$plot3 <- renderPlotly({
## 5.1 Create plot data
cat1<-input$cat_1
cat2<-input$cat_2
y1<-as.numeric(mydata()[mydata()$mycat==cat1])
y2<-as.numeric(mydata()[mydata()$mycat==cat2])
x0<-c(1,2)
## 5.2 Do plot
plot_ly(x = x0,y = y1, type="scatter",mode='lines+markers',name=Firm1) %>%
add_trace(y = y2, name = Firm2, mode = 'lines+markers') %>%
layout(dragmode = "select")
It took me a while to figure out your code. So:
1) Make use of renderUI which will allow you to dynamically create controls
2) Stick with one ui
3) Make sure you understand the renderPlotly and what you're trying to plot
library(shiny)
library(plotly)
### 1. Create some sample data
myrows<-sample(letters,12)
exdata<- data.frame(mycat=rep(myrows,2),yr=rep(1:2,each=12),KPI_1=rnorm(24),
KPI_2=round(runif(24,1,20)),KPI_3=rbinom(24,6,0.5))
ui <- fluidPage(
sidebarPanel(
uiOutput("c1"),uiOutput("c2")),
mainPanel(
column(6,
checkboxGroupInput("comp", "Categories",myrows,myrows,inline=TRUE),
actionButton("go", "Update"),
textOutput("txt"),
tableOutput("head")),
column(6,
plotlyOutput("plot3", height = 300, width = 700)))
)
server <- function(input, output) {
### 3. Server part
mydata <- eventReactive(input$go,{
res<-subset(exdata,mycat%in%input$comp)
return(res)
})
output$txt <- renderText({
paste("You chose", paste(input$comp, collapse = ", "))
})
output$head <- renderTable({
mydata()
})
conrolsdata <- reactive({
unique(as.character(mydata()$mycat))
})
output$c1 <- renderUI({
selectInput("cat_1", "Variable:",conrolsdata())
})
output$c2 <- renderUI({
selectInput("cat_2", "Variable:",conrolsdata())
})
output$plot3 <- renderPlotly({
if(is.null(input$cat_1)){
return()
}
y1<- mydata()$KPI_1[as.character(mydata()$mycat) %in% input$cat_1]
y2<- mydata()$KPI_2[as.character(mydata()$mycat) %in% input$cat_2]
x0<-c(1,2)
#use the key aesthetic/argument to help uniquely identify selected observations
plot_ly(x = x0,y = y1, type="scatter",mode='lines+markers',name="Firm1") %>%
add_trace(y = y2, name = "Firm2", mode = 'lines+markers') %>%
layout(dragmode = "select")
})
}
shinyApp(ui, server)

R shiny: How to create an output which serves as an input in shiny?

My task is to:
random two independent variables (A and B) from their normal distributions
display their histograms,
random 3rd variable (C) which distribution depends on the value B,
display the histogram of C.
I'd like all three histograms to be sensitive to changes in inputs.
The histograms of A and B are reactive.
What can I do with C? Any help would be appreciated.
Here is my try:
ui:
library(shiny)
fluidPage(
titlePanel("Random"),
sidebarLayout(
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 100,
value = 50)
),
mainPanel(
tabsetPanel(type="tabs",
tabPanel("plot 1 and plot 2",plotOutput("plot1"), plotOutput("plot2")),
tabPanel("plot 3",plotOutput("plot3"))
))))
server:
shinyServer(function(input, output) {
output$plot1 <- renderPlot({
{
values_B <-rnorm(input$obs, 25,6)
assign('B_values', round(values_B), envir=.GlobalEnv)
hist(B_values, main="Histogram of B values", xlab="values")}
})
output$plot2 <- renderPlot({
values_A<-rnorm(input$obs,20, 4.5)
assign('A_values', round(values_A), envir=.GlobalEnv)
hist(A_values, main="Histogram of A values", xlab="values")
})
output$plot3 <- renderPlot({
category <- function(x) if ( x <=10) round(rnorm(1,50,10)) else round(rnorm(1,10,2))
assign('C_values', as.numeric(lapply(B_values, category)))
hist(C)
})
})
The reason this isn't working is because you need to create a reactive variable with your B_values as you cannot define a reactive variable within the renderPlot function and use it again therefore your code won't work in plot 3 as you have the dependency on the variable in plot1. You must define this as a reactive value as shown and then call it in your renderPlot.
Note that when calling a reactive variable you must use brackets after the variable name.
I would recommend that you watch the shiny tutorial on the shiny website it is very helpful in understanding how reactivity works.
Here is the server side for your example such that it works.
shinyServer(function(input, output) {
reactiveB <- reactive({
rnorm(input$obs, 25,6)
})
output$plot1 <- renderPlot({
{
values_B <- reactiveB()
assign('B_values', round(values_B), envir=.GlobalEnv)
hist(B_values, main="Histogram of B values", xlab="values")}
})
output$plot2 <- renderPlot({
values_A<-rnorm(input$obs,20, 4.5)
assign('A_values', round(values_A), envir=.GlobalEnv)
hist(A_values, main="Histogram of A values", xlab="values")
})
output$plot3 <- renderPlot({
B_values <- reactiveB()
category <- function(x) if ( x <=10) round(rnorm(1,50,10)) else round(rnorm(1,10,2))
assign('C_values', as.numeric(lapply(B_values, category)))
hist(C_values)
})
})

Click to get coordinates from multiple histogram in shiny

How can we get interactive coordinates(x and y) of multiple histograms in shiny. I have tried this code
#server.R
library(xts)
shinyServer(function(input, output,session) {
output$info <- renderText({
paste0("x=", input$plot_click$x, "\ny=", input$plot_click$y)
})
output$plot<- renderPlot({
set.seed(3)
Ex <- xts(1:100, Sys.Date()+1:100)
df = data.frame(Ex,matrix(rnorm(100*3,mean=123,sd=3), nrow=100))
df<-df[,-1]
par(mfrow = c(2,2))
for(i in names(df)){
hist(df[[i]] , main=i,xlab="x",freq=TRUE,label=TRUE,plot = TRUE)
}
})
})
ui.R
#ui.r
mainPanel(
tabsetPanel(type="tab",tabPanel("plot", plotOutput("plot",click = "plot_click"), verbatimTextOutput("info"))
)
The problem with above code is I get random coordinates of the whole plot like this
x=124.632301932263
y=20.4921068342051
instead I want to get coordinates of individual plots with its corresponding values. For example if I click any place in X1's chart I should get x and y coordinates of that chart . How can I do this?
I originally was going to say that this occurs because the click is governed by the pixels of the plot instead of the data, but I am proved wrong here:
Notice that the x and y coordinates are scaled to the data, as opposed to simply being the pixel coordinates. This makes it easy to use those values to select or filter data.
I instead am going to honestly guess that within a graphics device Shiny can't tell the difference between the individual plots, to which a solution would be to create individual devices for each plot:
ui.R
library(shiny)
shinyUI(
tabsetPanel(type="tab",
tabPanel("plot",
uiOutput("coords"),
uiOutput("plots")
)
)
)
server.R
library(xts)
set.seed(3)
Ex <- xts(1:100, Sys.Date() + 1:100)
df <- data.frame(Ex, matrix(rnorm(100*3, mean = 123, sd = 3), nrow = 100))
cn <- colnames(df)
df <- df[, cn[cn != "Ex"]]
n_seq <- seq(ncol(df))
shinyServer(function(input, output, session) {
output$plots <- renderUI({
plot_output_list <- lapply(n_seq, function(i) {
plotOutput(paste0("plot", i), click = paste0("plot_click", i),
height = 250, width = 300)
})
})
for (i in n_seq) {
output[[paste0("plot", i)]] <- renderPlot({
hist(df[[i]] , main = i, xlab = "x", freq = TRUE, label = TRUE)
})
}
output$coords <- renderUI({
coords_output_list <- lapply(n_seq, function(i) {
renderText({
set <- input[[paste0("plot_click", i)]]
paste0("Plot ", i, ": x=", set$x, "\ny=", set$y)
})
})
})
})

Resources