shiny plotly no graph - r

I'm switching to plotly from ggplot for my shiny app, but when I run app from Rstudio the plots are not showing in browser, if I use print(gg) the plotly shows correctly in Rstudio viewer. The following minimal example works if I switch back to ggplot. Thanks!
ui.R
library(shiny)
library(httr)
library(jsonlite)
# get the list of all packages on CRAN
package_names = names(httr::content(httr::GET("http://crandb.r-
pkg.org/-/desc")))
shinyUI(fluidPage(
# Application title
"R Package Downloads",
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
br(),
selectInput("package",
label = "Packages",
selected = "ggplot2", # initialize the graph with a random package
choices = package_names,
multiple = TRUE),
selectInput("plot1",
label = "Select Plot Type",
choices = c("","Downloads vs Time (monthly)","Downloads vs Time (cumulative)","Map (cumulative)","Map (dominance)"),
multiple = FALSE)),
# Show a plot of the generated distribution
mainPanel(
plotlyOutput("plot1")
))
))
server.R
library(shiny,quietly = T); library(stringr,quietly = T)
library(dplyr,quietly = T); library(plotly,quietly = T)
library(ggplot2,quietly = T); library(lubridate,quietly = T)
library(cranlogs,quietly = T); library(zoo,quietly = T)
library(scales,quietly = T); library(broom,quietly = T)
library(rworldmap,quietly = T); library(countrycode,quietly = T)
library(data.table,quietly = T)
shinyServer(function(input, output) {
load("CRANlog_cleaned_month.RData")
output$plot1 <- renderPlotly({
dat.p <<- subset(dat,package %in% input$package)
dat.ts <<- aggregate(times~package+month,data=dat.p,sum)
DTmonthly <<- ggplot(dat.ts, aes(month, times, color = package)) +
geom_line() + xlab("Date") + scale_y_continuous(name="Number of downloads", labels = comma)
gg <- ggplotly(DTmonthly)
gg
})
})

I managed to solve this by changing the name of selectInput from "plot1" to another name, might be because of the plotlyOutput is also using "plot1". This was fine if I just use plotOutput. Probably due to some error checking code is missing in plotlyOutput.

Related

Interactive Bar Chart Using Shiny - Graph changes based on selected columns

I am teaching myself r and shiny and trying to make an interactive bar chart where the user can change the chart based on columns. I keep getting errors with this code. Any help would be appreciated! My data has four columns: v, one, two, three. The first column is characters and the last three are numbers. I want to change the bar chart based on the y axis (columns: one, two and three). Right now, the error I am getting is: missing value where TRUE/FALSE needed.
library(shiny)
library(readr)
library(ggplot2)
data <- read.csv('scoring.csv')
data$v <- as.character(data$v)
ui <- fluidPage(
titlePanel("Scoring"),
sidebarPanel(
selectInput(inputId = "scoring", label = "Select a score:", c("Scoring Method 1", "Scoring Method 2", "Scoring Method 3"))),
mainPanel(
plotOutput(outputId = "bar")
)
)
#browser()
server <- function(input, output) {
new_data <- reactive({
selected_score = as.numeric(input$"scoring")
if (selected_score == "Scoring Method 1"){(data[data$one])}
if (selected_score == "Scoring Method 2"){(data[data$two])}
if (selected_score == "Scoring Method 3"){(data[data$three])}
})
#browser()
output$bar <- renderPlot({
newdata <- new_data()
p <- ggplot(newdata, aes(x=reorder(v, -selected_score), selected_score, y = selected_score, fill=v)) +
geom_bar(stat = 'identity', fill="darkblue") +
theme_minimal() +
ggtitle("Sports")
barplot(p, height = 400, width = 200)
})
}
Run the application
shinyApp(ui = ui, server = server)
You have a few errors in your code. In the server part, please use input$scoring, instead of input$"scoring".
First, in ui selectInput could be defined as
selectInput(inputId = "scoring", label = "Select a score:", c("Scoring Method 1"="one",
"Scoring Method 2"="two",
"Scoring Method 3"="three")))
Second, your reactive dataframe new_data() could be defined as shown below:
new_data <- reactive({
d <- data %>% mutate(selected_score = input$scoring)
d
})
Third, ggplot could be defined as
output$bar <- renderPlot({
newdata <- new_data()
p <- ggplot(newdata, aes(x=v, y = newdata[[as.name(selected_score)]], fill=v)) +
geom_bar(stat = 'identity', position = "dodge", fill="blue") +
theme_bw() +
#scale_fill_manual(values=c("blue", "green", "red")) +
scale_y_continuous(limits=c(0,10)) +
ggtitle("Sports")
p
})
Please note that you had an extra selected_score variable within aes. My suggestion would be to play with it to reorder x, and review some online or youtube videos on R Shiny.

How to display ggplot2 on Rshiny main panel

The ggplot2 object doesnt display properly in RShiny mainpanel. For recreation, the below code uses iris dataset. Need help
I checked the link - RShiny ggplot2 not showing , but this didnt help. I also ran through https://shiny.rstudio.com/ website, but nothing had explanation with example on how to display the ggplot2 object. I used renderPlot and renderImage functions, but none gave required results.
'''
library(shiny)
library(shinydashboard)
ui <- fluidPage(titlePanel("Sample Shiny"),
navbarPage(
br(),
tabPanel(h4("Iris Data"),
sidebarPanel(
radioButtons("var1",
label = "Choose a FILL field",
choices = c("Species"),
selected = "Species"),
mainPanel(plotOutput("plot",click = "plot_click")))
)
))
server <- function(input, output) {
output$plot <- renderPlot(
{
#browser()
sw <- input$var1
### "a" below is iris dataset which I pass on as input**
ggplot(data = a) +
aes(x = Sepal.Length, fill = sw) +
geom_bar() +
theme_minimal() +
coord_flip()
},width = "auto",height = "auto",res = 72)
}
# Run app ----
shinyApp(ui, server)
'''
I was hoping to see the graph in the middle of mainpanel, but all I see is a small graph with no proper margins.
Expected: (Something like this on RShiny)
Here is what I see now:
input$var1 is a string => use aes_string:
ggplot(data = a) +
aes_string(x = "Sepal.Length", fill = sw) + ......

Unable to plot stacked barplot using R Shiny

I am new to R Shiny. Actually i have drawn Stacked Barplot using ggplot in my
R code. I want to draw the same using shiny. Below is my R code:
ggplot(data = df, aes(x = OutPut, y = Group, fill = Group)) +
geom_bar(stat = "identity") +
facet_grid(~ Environment)
In my R code it is giving correct results.But i am trying to draw in shiny. Below is my shiny R code.
ui <- fluidPage(theme = shinytheme("lumen"),
titlePanel("Data Analysis"),
selectInput("variable", "Variable:", c("OutPut", "Member", "Levels")),
mainPanel(plotOutput("plot")))
# Define server function
server <- function(input, output){
x = ggplot(data = df, aes(x = variable.names(), y = Group, fill = Group)) +
geom_bar(stat = "identity") +
facet_grid(~ Environment)
plot(x)
}
# Create Shiny object
shinyApp(ui = ui, server = server)
It is throwing an error,here i have created a dropdown box where all the variables have been stored. So when i select one variable, it should plot the Stacked barplot. Could anyone please help me.
Like it was mentioned in the comments, you need to use the rendering functions and actually assign them to the output to get the outputs you need.
I believe an example of using plots in rshiny would help, since it wouldn't make sense to have it in the comments, here it is:
library(shiny)
library(ggplot2)
ui <- fluidPage(titlePanel("Fast Example with mtcars"),
# inputs
selectInput("x", "Choose x:", choices = names(mtcars), selected = 'mpg'),
selectInput("y", "Choose y:", choices = names(mtcars), selected = 'hp'),
selectInput("fill", "Choose fill:", choices = names(mtcars), selected = 'carb'),
mainPanel(
#outputs
h2("Chosen variables are:"),
h4(textOutput("vars")),
plotOutput("plot")))
server <- function(input, output) {
df <- mtcars
# here's how you would use the rendering functions
# notice that I used aes_string
output$plot <- renderPlot({
ggplot(data=df,
aes_string(x= input$x, y= input$y, fill=input$fill)) +
geom_point()
})
output$vars <- renderText(paste0('x: ', input$x, " , ",
'y: ', input$y, " , ",
'fill: ', input$fill))
}
shinyApp(ui = ui, server = server)
The Rshiny tutorial is pretty helpful, you can take a look at it here https://shiny.rstudio.com/tutorial/

Lists containing reactive items not fully generating in shiny

I fixed a bug, but I do not understand why it happened in the first place. Can anyone help clarify?
I am building an interactive data explorer app, with each figure contained in its own module. Under my first approach ("old version that does not work") I first build a look-up list and then use it to display the correct control and plot.
However, no plot is displayed until you have clicked on all the options in the figure selection list.
I fixed this by switching to the "new version that works" without an intermediate look-up list. But do not understand why this happened.
Minimal reproducible example below, sorry about the length.
# required packages
library(shiny)
library(tidyverse)
## ui ----
ui = fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput("plot_controls"),
width=3
),
mainPanel(
selectInput("selected_plot", "Select figure:", choices = c("Histogram", "Scatter")),
plotOutput("plot_plot", height = "700px"),
width=9
)))
## server ----
server = function(input, output, session) {
data(starwars)
### modules ----
fig_histogram = callModule(figure_histogram_plot, "histogram", datafile = starwars)
fig_scatter = callModule(figure_Scatter_Plot, "scatter", datafile = starwars)
module_list = list( fig_histogram, fig_scatter )
### old version that does not work ----
resource.map_text_to_plot = reactive({
map = list("Histogram" = module_list[[1]]$plot(), "Scatter" = module_list[[2]]$plot())
})
output$plot_plot = renderPlot({ resource.map_text_to_plot()[input$selected_plot] })
resource.map_text_to_control = reactive({
map = list("Histogram" = module_list[[1]]$control, "Scatter" = module_list[[2]]$control)
})
output$plot_controls = renderUI({ resource.map_text_to_control()[input$selected_plot] })
### new version that works ----
# output$plot_controls = renderUI({
# for(module in module_list)
# if(module$text == input$selected_plot)
# return(module$control)
# })
#
# output$plot_plot = renderPlot({
# for(module in module_list)
# if(module$text == input$selected_plot)
# return(module$plot())
# })
}
shinyApp(ui = ui, server = server)
The figure modules are as follows:
### histogram - server ----
figure_histogram_plot = function(input, output, session, datafile){
text = "Histogram"
control = sliderInput(session$ns("num_bins"), "Number of bins", min = 5, max = 50, value = 30)
plot = reactive({
p = ggplot(data = datafile) + geom_histogram(aes_string(x = "height"), bins = input$num_bins)
return(p)
})
return(list(text = text, plot = plot, control = control))
}
### scatter - server ----
figure_Scatter_Plot = function(input, output, session, datafile){
text = "Scatter"
control = radioButtons(session$ns("plot_design"), "Plot design", choices = c("points", "lines", "both"))
plot = reactive({
p = ggplot(data = datafile)
if(input$plot_design != "lines")
p = p + geom_point(aes_string( x = "mass", y = "height" ))
if(input$plot_design != "points")
p = p + geom_line(aes_string( x = "mass", y = "height" ))
return(p)
})
return(list(text = text, plot = plot, control = control))
}
So I think the problem is when exactly you are evaluating the reactive element. When you use () to "call" a reactive element, it's not really reactive any more. When you set up the list, use
resource.map_text_to_plot = reactive({
map = list("Histogram" = module_list[[1]]$plot,
"Scatter" = module_list[[2]]$plot)
map
})
and when you set up the renderPlot, use
output$plot_plot = renderPlot({
resource.map_text_to_plot()[[input$selected_plot]]() })
Note we removed the () from the list, and put it in the render function instead.
Also, your controls aren't being initialized before the first plot is drawn, so the input$plot_design value can be NULL and you don't seem to check for that which causes a problem at the first draw (you will briefly see an error most likely)

Export R Shiny Page to PDF

I have a large Shiny application that has a number of prompts, then generates tables and plot based on those inputs. I don't use rmarkdown or knitr or anything to format the output. I just use the standard Shiny elements (sidebarPanel, mainPanel, etc.). For the plots and tables I use the standard reactive renderPlot and renderTable objects.
I'm looking for an easy way to have a button called "Export to PDF" that exports the elements on the page to a PDF document.
I've looked into using knitr and rmarkdown to generate a document with some fancy formatting (see here and here for examples).
The problem is that it appears that I'll need to regenerate the tables and plots either within the Rmd file or the server.R within a downloadHandler object, and I'd like to avoid that.
Is there any way to output the page as a pdf more easily. More specifically, is there any way to directly reference the output tables and plots (i.e. the output$ objects) from within the Rmd file so that plots and tables don't need to be generated twice.
Edit: Here is some simplified code. Note getDataset() is a reactive function that queries a database based on the inputs.
My goal is to simply add an "Export" button that exports the already-generated plots and table. (Also as a side note, is there any way I can get a reactive dataset that is shared among all reactive elements? i.e. not need to have ds <- getDataset() in every object?)
Server
output$hist <- renderPlot({
ds <- getDataset()
# do data transformations
ggplot(ds, aes(val)) +
geom_histogram(binwidth = binSize, aes(fill = ..count..)) +
labs(title = "val dist", x = "val", y = "Count") +
scale_fill_gradient("Count", low = "green", high = "red", guide = FALSE) +
scale_x_continuous(limits = c(min(ds$val), quantile(ds$val, 0.99))) +
geom_hline(yintercept=maxY, linetype=3)
})
output$time <- renderPlot({
ds <- getDataset()
# do data transformations
ggplot(ds, aes(as.POSIXlt(unixTime, origin="1970-01-01", tz="UTC"), val), colour = val) +
scale_y_continuous(limits = c(min(ds$val), quantile(ds$val, 0.99))) +
labs(title = "Val Over Time", x = "Time (UTC)", y = "val (ms)") +
geom_point(alpha = 0.3, size = 0.7) +
geom_smooth()
})
output$stats <- renderTable({
statsDf = getDataset()
# do data transformations
statsDf
})
UI
ui <- fluidPage(
titlePanel("Results"),
sidebarLayout(
sidebarPanel(
dateInput("startDateTime", "Start Date:", value = "2016-10-21"),
textInput("startTime", "Start Time", "00:00:00"),
br(),
dateInput("endDateTime", "End Date:", value = "2016-10-21"),
textInput("endTime", "End Time", value = "02:00:00"),
br(),
submitButton("Submit")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plots",
plotOutput("hist"),
plotOutput("time"),
tabPanel("Statistics", tableOutput("stats"))
)
)
)
)
First of all , you should really produce a reproducible example not just a sample of your code. We should copy and paste your code and it will run.
The idea
Since you are using ggplot2 which is king of grid plots, I think one easy option to save plots/tables is to use gridExtra package. Using grid.arrange or arrangeGrobs you can save your grobs to predefined device. Then, downloadhandler will do the download.
To not regenerate all the plots each time, I think one solution is to save them in a global variable that you update each time you change the plot. Here reactiveValues come in rescue to store plots and tables ad dynamic variable.
Solution
ui.R
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Save ggplot plot/table without regenration"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
downloadButton('export')
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("p1"),
plotOutput("p2"),
tableOutput("t1")
)
)
))
server.R
library(shiny)
library(ggplot2)
library(gridExtra)
shinyServer(function(input, output) {
## vals will contain all plot and table grobs
vals <- reactiveValues(p1=NULL,p2=NULL,t1=NULL)
## Note that we store the plot grob before returning it
output$p1 <- renderPlot({
vals$p1 <- qplot(speed, dist, data = cars)
vals$p1
})
output$p2 <- renderPlot({
vals$p2 <- qplot(mpg, wt, data = mtcars, colour = cyl)
vals$p2
})
## same thing for th etable grob
output$t1 <- renderTable({
dx <- head(mtcars)
vals$t1 <- tableGrob(dx)
dx
})
## clicking on the export button will generate a pdf file
## containing all grobs
output$export = downloadHandler(
filename = function() {"plots.pdf"},
content = function(file) {
pdf(file, onefile = TRUE)
grid.arrange(vals$p1,vals$p2,vals$t1)
dev.off()
}
)
})

Resources