I am using shiny to plot different time series of precipitation and temperature.
ui.R
shinyUI(fluidPage(
# Application title
titlePanel("Parametres"),
plotOutput(outputId = "main_plot", height="500px"),
hr(),
fluidRow(
column(4,
selectInput(inputId = "Cellule",label = "Cellule:",choices = c(17,1404,2478,2792,3842,6103,7714,8442,8642),selected = 7714),
selectInput(inputId = "Variable",label = "Variable:",choices = c("Ptot", "TEMP"),selected = "Ptot")
),
)
))
Here is a part of my code for server.R, which doesn't work:
server.R
shinyServer(function(input, output, p. = p) {
output$main_plot <- renderPlot({
....
if(input$Variable =="TEMP")
{
Obs_inter$value <- Obs_inter$value-273.15
Sim25_inter$value <- Sim25_inter$value-273.15
Sim_1_inter$value <- Sim_1_inter$value-273.15
Sim_2_inter$value <- Sim_2_inter$value-273.15
ymin <- min(Obs_inter$value, Sim25_inter$value, Sim_1_inter$value, Sim_2_inter$value)
ytitle <- "TEMP (°C)"
} else {
if(input$Variable=="Ptot")
{
ymin <- 0
ytitle <- "Ptot (mm)"
}
}
p <- ggplot()
....
})
})
With Obs, Sim25, Sim_1 and Sim_2 my time series.
When I run my code, this is the error I get:
"Cannot find ymin"
So the loop with the if statement doesn't work. I tried to select ymin=0 before (no if statement) and I have what I want. What I do not understand is that I have another if statement before (not with input$Variable but another input) and it works.
I tried to print input$Variable to see what it returns but I don't know how to do that..
Thanks for the help!
Related
I've looked through R Shiny tutorials and stackoverflow for answers related to my query. I usually wait for 3-4 days to solve a coding problem before I attempt to post.
I have an animated slider in my UI that loops through time interval in a column (column a) . I'm trying to produce an animated line plot that plots y values of another column (column b), corresponding to the nrow() of that time interval. The slider works perfectly, but I haven't been able to plot the output.
I mightve missed some concepts related to reactivity in Shiny app. Appreciate any guidance I can get related to my query. I'll be happy to post more info if needed.
a <- c(0,1,2,3,4,5,6)
b <- c(50,100,40,30,20,80)
mydata <- cbind(a,b)
mydata <- as.data.frame(mydata())
ui <- fluidPage (
headerPanel("basic app"),
sidebarPanel(
sliderInput("slider",
label = "Time elapsed",
min = 0,
max = nrow(mydata()),
value = 1, step = 1,
animate =
animationOptions(interval = 200, loop = TRUE))
),
mainPanel(
plotlyOutput("plot")
)
)
server <- function(input, output) {
sliderValues <- reactive({
data.frame(
Name = "slider",
Value = input$slider)
})
output$plot <- renderPlot({
x<- as.numeric(input$slider)
y <- as.numeric(b[x])
ggplot(mydata,aes_string(x,y))+ geom_line()
})
}
Just as a demo, I wanted the animated plot to come out like this, but in correspondance to UI slider values :
library(gganimate)
library(ggplot2)
fake <- c(1,10)
goods <- c(11,20)
fakegoods <- cbind(fake,goods)
fakegoods <- data.frame(fakegoods)
ggplot(fakegoods, aes(fake, goods)) + geom_line() + transition_reveal(1, fake)
Does this accomplish what you are looking for? Note that I removed the first element, 0, from vector a as your original example had more elements in a than b, and in order for them to be cbind together they must be the same length.
library(ggplot2)
library(shiny)
a <- c(1,2,3,4,5,6)
b <- c(50,100,40,30,20,80)
mydata <- cbind(a,b)
mydata <- as.data.frame(mydata)
ui <- fluidPage (
headerPanel("basic app"),
sidebarPanel(
sliderInput("slider",
label = "Time elapsed",
min = min(mydata$a),
max = max(mydata$a),
value = min(mydata$a), step = 1,
animate =
animationOptions(interval = 200, loop = TRUE))
),
mainPanel(
plotOutput("plot")
)
)
server <- function(input, output) {
output$plot <- renderPlot({
plotdata <- mydata[1:which(input$slider==mydata$a),]
p <- ggplot(plotdata,aes(x = a,y = b))
if(nrow(plotdata)==1) {
p + geom_point()
} else {
p + geom_line()
}
})
}
I am trying to plot multiple plots on different pages in my shiny app. Here is a reproducible example:
My module code is :
library(ggplot2)
dfunc <- function(data, page_number) { p <- ggplot(data = data, aes(x = data[, 3], y = data[, 2])) +
geom_point() for (i in 1:page_number) {
print(p) } }
dfUI <- function(id) { ns <- NS(id)
tagList(titlePanel("Multi plots"),
sidebarLayout(
sidebarPanel(
numericInput(
ns("page_number"),
"Number of Plots",
1,
min = 1,
step = 1
),
actionButton(ns("generateplot"), "Generate Plot")
),
mainPanel(plotOutput(ns("view")))
)) }
df <- function(input, output, session) { observeEvent(input$generateplot, {
output$view <- renderPlot({
data = mtcars
dfunc(data = data,
page_number = input$page_number)
}) }) }
There is a global file which calls this file where these functions are stored:
through this:
library(shiny)
library(shinythemes)
source("modules/dfunc.R")
The server file is like this :
source('global.R')
shinyServer(function(input, output, session) {
callModule(df, "dfunc")
})
And ui.R is like this :
source('global.R')
shinyUI(fluidPage(
shinythemes::themeSelector(),
headerPanel("The Shiny App"),
tabsetPanel(
tabPanel("Multi page plot", dfUI('dfunc')),
type = "pills"
)
))
Now the issue is if I use my dfunc function it prints as many plots as I give in page_number but when I call similar function in shiny app it only prints the single one. Is there any way that shiny app can print as many plots required on same page or on multiple page.
Thanks in advance.
server.ui
shinyServer(
function(input, output) {
plot <- eventReactive(input$button, {
if (input$gtype == "Time to Change") {
dataset = subset(TDU, LBTEST == input$study, drop=FALSE)
ggplot(dataset, aes_string(x= 'VISITNUM', y = 'LBBLCHGR' , col='factor(ARMAN)')) +
geom_line(data = dataset, aes_string(x='VISITNUM',y = 'LBBLCHGR' ,group='SUBJID')) +
}
else {
dataset = subset(TDU, LBTEST == input$study, drop=FALSE)
ggplot(dataset, aes_string(x = 'ARMCD', y = 'LBBLCHGR', col='factor(VISITNUM)')) + geom_line()
}
output$plot <- renderPlot({
plot()
})
output$brush_info <- renderPrint({
brushedPoints(dataset, input$plot_brush)
})
})
})
I have a corresponding ui.r file which is supposed to display brush_info. But whenever I try to highlight a point in my graph, I get some error stating that the object dataset doesn't exist? Why is that? It clearly exists within a loop. Why would R make this an obstacle to allowing dataset to become a useable dataframe?
shinyUI(fluidPage(titlePanel('Biomarker Comparison'),
fluidRow(column(12, plotOutput('plot', brush = brushOpts(id = "plot_brush"), dblclick = "plot_dblclick"))),
fixedRow(column(3,selectInput('type', label='Select a Study',choices= c('', 'ADLB_TDU', 'ADLB_TDR', 'ADBM_TDR'))), column(3, uiOutput('selectUI'))),
fluidRow(column(3, radioButtons('gtype', label='Graph Type', choices = list('Dosage to Change', 'Time to Change'))) , column(3, uiOutput('UImeasure')), column(6, h4("Brushed points"),verbatimTextOutput("brush_info"))),
actionButton('button', 'Draw Graph')
))
In simpler terms, how do I access a dataframe, or any object embedded in a loop?
EDIT :
Here is a solution that I came up with.
data = reactive({
dataset = subset(TDU, LBTEST == input$study, drop=FALSE)
})
output$brush_info <- renderPrint({
brushedPoints(data(), input$plot_brush)
})
So I put the dataframe into a reactive function, and then I substituted the dataframe name for the function that generates it. I can't believe that I haven't tried this before.
I want to plot on the same graph one or more plots, depending on the boxes checked in my "checkboxGroupInput".
After checking a few topics on SO, I have found that a easy-to-use solution would be to add "add=TRUE" in the second, third...plots.
Here is a simplified copy of my code :
Server.R
function(input, output) {
dataInput <- reactive({
#I use getMyPlotValues with two parameters.
#idFcast is the one which doesn't work.
m_PARAM$idSite <- input$country
m_PARAM$idFcast <- input$model[i]
getMyPlotValues(m_PARAM)
})
output$plot1 <- renderPlot({
## We plot all the models on the same graph.
if(length(input$model) > 0)
{
firstplot<- TRUE
#To put add = TRUE for the second, third... plots
for(i in 1:length(input$model))
{
valueshere <- dataInput()
#We pick up the vectors (ts,obs) with the function
#And plot them.
if(firstplot)
{
plot(valueshere$ts,valueshere$obs)
}
else
{
plot(valueshere$ts,valueshere$obs,add=TRUE)
}
firstplot <- FALSE
}
}
})
}
And now the UI.R simplified :
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(
column((4),
selectInput("country", label = h3("Pays"),
choices = list("First" = 2,"Second" = 1), selected = 1)
)
fluidRow(
#checkboxGroupInput
column(6,
checkboxGroupInput("model",
choices = list("First" = 1,"Second"=2,"Third"=3),
selected = 1)
)
)
),
mainPanel
(
plotOutput("plot1")
)
)
)
)
I found on this topic (How can I pass data between functions in a Shiny app) that I could try to pass the variable "i" by writing valueshere <- dataInput()$i... Because I have the feeling this is where the error comes from. I try do display input$model and it works, input$model[i] doesn't.
There must be a problem in my code, as I am a beginner in Shiny, but I couldn't fix, even with all the topics about Shiny on SO.
Thanks for your help and have a nice day !
Seems that add argument isn't work. I finished with the solution that consists in creating plots for all your models and only displays them when it's value is selected. So here is:
I have tried to make your example reproduceble so you will observe some changes
UPDATE: Supposing your SQL statement will give you a vector with your model names (models_list) you could generate Shiny objects using lapply (like here)
library(shiny)
# Simulate data
set.seed(189)
df <- data.frame("obs" = 1:30, "ts" = (rnorm(30)+100)
, "country" = rep(c("First", "Second"), 15)
, "models" = rep(c("First", "Second", "Third"), 10),
stringsAsFactors = F)
# Suppose your SQL query returns this kind of output
models_list <- c("First", "Second", "Third")
models_num <- length(models_list)
# Run App
shiny::runApp(list(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("country", label = "Countries",
choices = c("First", "Second"), selected = "First"),
checkboxGroupInput("model", label = "Models",
choices = c("First", "Second", "Third"),
selected = "First")
),
mainPanel(
lapply(1:models_num, function(i) {
plotOutput(paste0('plot', i))
})
)
)
),
server = function(input, output) {
dataInput <- reactive({
df_out <- df[(df$country == input$country), ]
return(df_out)
})
lapply(1:models_num, function(i) {
output[[paste0('plot', i)]] <- renderPlot({
if(any(input$model %in% models_list[i])){
valueshere <- dataInput()[df$models == models_list[i],]
plot(valueshere$ts,valueshere$obs)
}
})
})
}
))
I have a task where i need to build an rShiny app that allows the user to choose which kind of R plotting package is used in-order to display a plot.
Currently the only way i have gotten it to work (semi-decently) is using package specific functions for each package on the server side and using a series of conditional panels on the UI side.
However the problem is that when the user enters the page for the first time then all plots are initialized. Second problem is when the user changes some plot input values and after that chooses another package then the old plot will be displayed until a new plot is created.
Questions:
Is this the only available approach?
I feel that there must be a way to use reactive functions for the package selection?
I feel that it should be possible to use a single rShiny's htmlOutput (or something similar) in the ui and therefore not needing the switchPanel?
I have created a small app to demonstrate my current implementation and both problems:
server.R
library(shiny)
#library(devtools)
#install_github("ramnathv/rCharts")
library(rCharts)
shinyServer(function(input, output) {
names(iris) = gsub("\\.", "", names(iris))
#Render the Generic plot
output$GenericPlot <- renderPlot({
data = iris[0:input$variable,]
plot(data$SepalLength ~ data$SepalWidth)
})
#Render the Polychart plot
output$PolychartPlot <- renderChart({
plotData <- rPlot(SepalLength ~ SepalWidth, data = iris[0:input$variable,], color = 'Species', type = 'point')
plotData$addParams(dom = 'PolychartPlot')
return(plotData)
})
#Render the NDV3 plot
output$NDV3Plot <- renderChart({
plotData <- nPlot(SepalLength ~ SepalWidth, data = iris[0:input$variable,], group = 'Species', type = 'scatterChart')
plotData$addParams(dom = 'NDV3Plot')
return(plotData)
})
})
ui.R
library(shiny)
library(rCharts)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("lib", label = "Library:",
choices = list("Generic", "rCharts Polychart", "rCharts NDV3"),
selected = "Generic"
),
numericInput("variable", "Observations:",
min = 5,
max = 150,
value = 10
)
),
mainPanel(
conditionalPanel(
condition = "input.lib == 'Generic'",
h3("Generic plot"),
plotOutput("GenericPlot")
),
conditionalPanel(
condition = "input.lib == 'rCharts Polychart'",
h3("rCharts Polychart plot"),
showOutput("PolychartPlot", "polycharts")
),
conditionalPanel(
condition = "input.lib == 'rCharts NDV3'",
h3("rCharts NDV3 plot"),
showOutput("NDV3Plot", "nvd3")
)
)
)
))
The final version will use a different dataset and more charting packages. The provided code is more of a toy example, with most of the stuff stripped out.
Make a single part in the output part of the app that includes some logic based on the input. For example,
library(shiny)
library(ggplot2)
data(cars)
server <- function(input, output) {output$plot<- renderPlot({
if (input$lib == "base") {
p <- plot(cars$speed, cars$dist)
} else if (input$lib == "ggplot") {
p <- ggplot(cars, aes(x = speed, y = dist)) + geom_point()
}
p
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("lib", "Library: ", choices = list("base", "ggplot"),
selected = "base")
),
mainPanel(plotOutput("plot"))
)
)
shinyApp(ui = ui, server = server)
This provides one plot and as soon as I change the lib option it regenerates.
Found a solution to my problem. The solution is basically to use uiOutput() in the ui.R and move the plotOutput(), showOutput() methods to the server.R.
The solution based on iacobus code:
ui.R
library(shiny)
library(rCharts)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("lib", "Library: ", choices = list("base", "ggplot", "Polychart"),
selected = "base")
),
mainPanel(uiOutput("plot"))
)
))
server.R
library(shiny)
library(ggplot2)
library(rCharts)
data(cars)
server <- function(input, output) {
output$plot<- renderUI({
if (input$lib == "base") {
plotOutput("base")
} else if (input$lib == "ggplot") {
plotOutput("ggplot")
} else if (input$lib == "Polychart") {
showOutput("polychart", "polycharts")
}
})
output$base <- renderPlot({
plot(cars$speed, cars$dist)
})
output$ggplot <- renderPlot({
ggplot(cars, aes(x = speed, y = dist)) + geom_point()
})
output$polychart <- renderChart({
p <- rPlot(speed ~ dist, data = cars, type = "point")
p$addParams(dom = 'plot')
p
})
}
The difficulty arose for me, because i assumed that plotOutput(), showOutput() etc methods can only be used in the ui.R. This however is not the case.
EDIT:
It turned out that this was not enough for pollyCharts to work properly along with other rCharts packages.
instead i am using renderUI and rCharts $show to display the chart inline. The following link was helpful for me: https://github.com/ramnathv/rCharts/issues/373. In the ui i'm using htmlOutput