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
Related
I have imported the dataset = students for generating the reactive plots but proper plot is not generated .I am using ggplot for plots so could you
please tell me whats wrong in my code.
library(shiny)
library(ggplot2)
ui <- navbarPage("A SHINY APP!! ",
tabPanel("Plots",headerPanel("Different plots of data"),
sidebarLayout(
sidebarPanel(
selectInput("x.col","x.variable",choices=names(students))
),
mainPanel(plotOutput("histPlot")))
)
)
server <- function(input, output) {
plot <- reactive({ ggplot(students,aes(x=input$x.col))
})
output$histPlot <- renderPlot({
plot() + geom_histogram(stat = "count",bins = 30)
})
}
shinyApp(ui = ui, server = server
Try with get() function like the following:
ggplot(students, aes(x = get(input$x.col)))
I am struggling trying to graph two overlaying plots and add checkboxes fro displaying them in my Rshiny app. I am using the following code:
library(shiny)
library(shinyjs)
mpgData <- mtcars
ui <- fluidPage(
# Application title
titlePanel("Test"),
# Sidebar with checkboxes to select plot
sidebarLayout(
sidebarPanel(
helpText("Select type of plot:"),
checkboxGroupInput("checkPlot",
label = ("Plots"),
choices=c("Baseline","Scenario A"),
selected = c("Baseline","Scenario A")
)
),
mainPanel(
textOutput("overview"),
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
#get Check group input (type of plot)
checkedVal <- reactive({
as.vector(input$checkPlot)
})
#plot
output$plot <- renderPlot({
if(("Baseline" %in% checkedVal()) & ("Scenario A" %in% checkedVal()))
# first plot
plot(mpgData$mpg, mpgData$cyl, type='l',col="steelblue",ylim=range(c(mpgData$cyl,mpgData$disp)))
# second plot
par(new = TRUE)
plot(mpgData$mpg, mpgData$disp, type = "l",col="red", ylim=range(c(mpgData$cyl,mpgData$disp)), axes = FALSE, xlab = "", ylab = "")
if ("Baseline" %in% checkedVal())
plot(mpgData$mpg, mpgData$cyl, type='l',col = "steelblue")
if ("Scenario A" %in% checkedVal())
plot(mpgData$mpg, mpgData$disp, type='l',col = "red")
})
}
shinyApp(ui, server)
My checkboxes seem to be working out alright when I just want one graph to be displayed, however, there's definitely an issue when I want to display both on the same axes. Most examples I saw were a little too complex for me to understand and break down, so I tired to infer from previous R knowledge, but clearly I'm off.
any help is much appreciated !
If you were trying to add the baseline on the existing graph, you could use the lines function, as below. Although if for your particular data-set, the base line is really negligible compared to the original plot, you need to use a package other than 'base', like 'ggplot'.
library(shiny)
library(shinyjs)
mpgData <- mtcars
ui <- fluidPage(
# Application title
titlePanel("Test"),
# Sidebar with checkboxes to select plot
sidebarLayout(
sidebarPanel(
helpText("Select type of plot:"),
checkboxGroupInput("checkPlot",
label = ("Plots"),
choices=c("Baseline","Scenario A"),
selected = c("Baseline","Scenario A")
)
),
mainPanel(
textOutput("overview"),
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
#get Check group input (type of plot)
checkedVal <- reactive({
as.vector(input$checkPlot)
})
#plot
# first plot
output$plot <- renderPlot({
if(("Baseline" %in% checkedVal()) & ("Scenario A" %in% checkedVal()))
{ plot(mpgData$mpg, mpgData$cyl, type='l',col="steelblue",ylim=range(c(mpgData$cyl,mpgData$disp)))
lines(mpgData$mpg, mpgData$disp, type = "l",col="red")
}
else if("Baseline" %in% checkedVal())
{
plot(mpgData$mpg, mpgData$cyl, type='l',col = "steelblue")
}
else if("Scenario A" %in% checkedVal())
{
plot(mpgData$mpg, mpgData$disp, type='l',col = "red")
}
})
}
shinyApp(ui, server)
Please let me know if this works for you.
I'm running into some issues in my work. To iullustrate the problem, I'm using the diamonds data as an example.
I made a function sca.plot. If the argument color.by=NULL, then make a scatter plot and color all points red. If color.by is some factor variable, make scatter plot and color points by the variable.
My question is when I make interactive scatter plot in shiny. How can I include the NULL option in selectinput widget, so that I can choose whether or not those points are colored by some variable?
If I include NULL in choices in selectinput, I got errors. Could not figure it out....
Thanks a lot in advance.
Below is my code:
library(ggplot2)
sca.plot <- function (color.by=NULL) {
if (is.null(color.by)) {
diamonds %>% ggplot(aes(x, y))+
geom_point (color='red')
} else {
color.by = sym(color.by)
diamonds %>% ggplot(aes_(~x, ~y, color=color.by))+
geom_point ()
}
}
sca.plot(color.by='clarity')
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput('colorby', label = h5(strong('Color By')),
choices = list('clarity', 'cut'),
selected = NULL)
),
mainPanel(
plotOutput('plot')
)
)
)
server <- function(input, output) {
output$plot <- renderPlot ({
sca.plot(color.by=input$colorby)
})
}
runApp(shinyApp(ui, server))
Here is the solution for you:
library(ggplot2)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput('colorby', label = h5(strong('Color By')),
choices = list('NULL','clarity', 'cut'),
selected = NULL)
),
mainPanel(
plotOutput('plot')
)
)
)
server <- function(input, output) {
output$plot <- renderPlot ({
if(!input$colorby == 'NULL'){
ggplot(diamonds, aes_string(x="x",y="y", color=input$colorby)) +
geom_point()
}else{
ggplot(diamonds, aes(x=x,y=y)) +
geom_point(color='red')
}
})
}
shinyApp(ui = ui, server = server)
You can use NULL as an argument in selectInput but as a string --> 'NULL'
You actually do not need such a function as you wrote at the beginning of shiny app, you can easily use if...else... statement directly in renderPlot() to get the desired color of the geom_point().
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.
I am building a Shiny app that helps user to create pie chart with ggplot2 on their own. Therefore, it would have a selector input for user to select variables from different dataframes. I was stuck with the input$ statements, it seemed that Shiny took the input$ with double quotes as a character, instead of a variable. Below is a simplified version of code, kindly let me know how to fix this. Thanks in advance!
library(ggplot2)
server <- function(input, output) {
output$var_selector <- renderUI({
selectInput('var_selector', 'Please select:', choices = names(mtcars))
})
output$pie_plot <- renderPlot({
ggplot(mtcars, aes(x = factor(1), fill = factor(input$var_selector))) + geom_bar(width = 1) + coord_polar(theta = "y")
})
output$text <- renderText({
print(input$var_selector)
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
h3('ggplot2 pie chart'),
uiOutput('var_selector')
),
mainPanel(
plotOutput('pie_plot')
)
)
)
shinyApp(ui = ui, server = server)