I am currently trying to make an interactive app on shiny where with my data frame "keep_df" you can choose which kind of plot you want to use and for the x and y axes you can choose any of the columns from keep_df. Below is my code. I'm not getting any error messages, but the code is not running as desired. I was wondering if anyone had any suggestions. Thanks!
ui <- navbarPage ("Title",
tabPanel("Chart builder",
sidebarLayout(
sidebarPanel(
pickerInput(inputId = 'chart', label = '1. Select chart type', choices = c("Scatter plot", "Bar chart", "Histogram", "Pie chart", "Box plot"), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'xaxis', label = '2. Select X-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'yaxis', label = '3. Select Y-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE),
uiOutput("picker2"),
actionButton("view", "View selection"),
),
mainPanel(ui <- DT::dataTableOutput("charttable"), plotOutput("plots")),
)
)
)
server <- function(input, output, session) {
data <- reactive(
keep_df
)
plots <- reactive({
if (input$chart == 'Scatter plot') {
ggplot(data(), aes(x = input$xaxis, y = input$yaxis)) +
geom_point(colour = "black")
}
if (input$chart == 'Bar chart') {
ggplot(data(), aes(x = input$xaxis, y = input$yaxis)) +
geom_point(colour = "black")
}
})
output$plots <- renderPlot(
plots()
)
}
You were pretty close with your code, I noticed a few issues. First, you have an extra ui <- which I could see causing an error. Second, in the plots reactive, where you had x = input$xaxis, it would send a string to the ggplot, rather than a variable. Meaning it wouldn't read the column. I also made the plots reactive as an if and else if, rather than two if statements. Hope this helps!
Note that I didn't have the dataframe, so I just used mtcars for simplicity. There were a few lines I blocked out too. I also added the library and the shinyApp call too, since it wasn't in your example.
library(shiny)
library(ggplot2)
library(shinyWidgets)
keep_df<-mtcars #Don't have the data, just using mtcars
ui <- navbarPage ("Title",
tabPanel("Chart builder",
sidebarLayout(
sidebarPanel(
pickerInput(inputId = 'chart', label = '1. Select chart type', choices = c("Scatter plot", "Bar chart", "Histogram", "Pie chart", "Box plot"), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'xaxis', label = '2. Select X-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'yaxis', label = '3. Select Y-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE)#,
# uiOutput("picker2"), #Not doing anything
# actionButton("view", "View selection") #Not doing anything
),
mainPanel(DT::dataTableOutput("charttable"), plotOutput("plots")), #Removed the ui <-
)
)
)
server <- function(input, output, session) {
data <- reactive(
keep_df
)
plots <- reactive({
if (input$chart == 'Scatter plot') {
#without the eval(parse(text =)), it reads as string, not variable
ggplot(data(), aes(x = eval(parse(text = input$xaxis)), y = eval(parse(text = input$yaxis)))) +
geom_point(colour = "black")
} else if (input$chart == 'Bar chart') {
ggplot(data(), aes(x = eval(parse(text = input$xaxis)), y = eval(parse(text = input$yaxis)))) +
geom_boxplot(colour = "black")
}
})
output$plots <- renderPlot(
plots()
)
}
shinyApp(ui, server)
Related
I just want to imitate to make a little shiny app.
but it does not work at all.
ERORR is: Warning: Error in [.data.frame: undefined columns selected
I load a df I created.
data.frame : df_pris_salary
colnames : region , år , Antal ,Medelpris, Medianpris ,MedelLön year_per_lgh
Code looks like this:
library(shiny)
library(tidyverse)
library(ggplot2)
load("data/shiny2.RData")
# load df: df_pris_salary
ui <- fluidPage(
titlePanel("Utveckling av lägenhetspris & Lön"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "VarX",
label = "Select X-axis Variable:",
choices = list("år", "MedelLön")),
selectInput(inputId = "VarY",
label = "Select Y-axis Variable:",
choices = list("Medelpris", "MedelLön")),
selectInput(inputId = "Color",
label = "Select Color Variable:",
choices = as.list(c("region", "år")))
),
mainPanel(
plotOutput("scatter")
)
)
)
server <- function(input, output, session) {
output$scatter <- renderPlot({
mtc <- df_pris_salary[,c(input$VarX, input$VarY, input$Color)]
mtc[,3] <- as.factor(mtc[,3])
ggplot()+
geom_line(data = mtc, aes(x = mtc[,1], y = mtc[,2], color = mtc[,3]))+
geom_point(data = mtc, aes(x = mtc[,1], y = mtc[,2], color = mtc[,3]))+
labs(x = colnames(mtc)[1], y = colnames(mtc)[2],
color = colnames(mtc)[3],
title = paste("Scatter Plot of", input$VarX, "vs", input$VarY),
subtitle = "Under åren 2000 - 2021",
caption = "Data Source: SCB")
})
}
shinyApp(ui, server)
Could someone help me to figure out how to solve this problem?
New to shiny. I am trying to create a plot based on chosen x and y values. Basically, whatever the user selects for the select1 and select2 selectInput function will graph it accordingly. My original data has many columns, not just two. When I try to graph very specific things, my code works great, but when I try to graph what the user "selects" it does not work.
library(shiny)
library(readr)
library(ggplot2)
library(dplyr)
data0 <- rnorm(n = 10, mean = 100, sd = 5)
data1 <- rnorm(n = 10, mean = 50, sd = 10)
data2 <- data.frame(data0, data1)
attach(data2)
ui <- fluidPage(
selectInput(inputId = "select1",
label = "select the x-axis",
choices = c(" ", "data0", "data1")
),
selectInput(inputId = "select2",
label = "select the y-axis",
choices = c(" ", "data0", "data1")
),
submitButton(text = "Apply Changes", icon = NULL, width = NULL),
plotOutput(outputId = "myplot")
)
server <- function(input, output) {
output$myplot <- renderPlot({
data2 %>%
ggplot(aes(input$select1 ~ input$select2))+
geom_point(alpha = 0.8)
})
}
shinyApp(ui = ui, server = server)
I had to add ggplot(aes(x = get(paste(input$select1)), y = get(paste(input$select2)) to make the input selects work.
library(shiny)
library(readr)
library(ggplot2)
library(dplyr)
data0 <- read_csv("DeltaX_Soil_Properties_Fall2020_Spring2021_Fall2021.csv")
data1 <- data0[!(data0$time_marker_sampled == "-9999"),]
attach(data1)
ui <- fluidPage(
selectInput(inputId = "select1",
label = "select the x-axis",
choices = c(" ", "elevation_navd88", "sediment_accretion", "days_between_sampling_and_deployment", "normalized_accretion", "soil_bulk_density", "soil_organic_matter_content", "soil_organic_carbon", "soil_organic_carbon_density")
),
selectInput(inputId = "select2",
label = "select the y-axis",
choices = c(" ", "elevation_navd88", "sediment_accretion", "days_between_sampling_and_deployment", "normalized_accretion", "soil_bulk_density", "soil_organic_matter_content", "soil_organic_carbon", "soil_organic_carbon_density")
),
submitButton(text = "Apply Changes", icon = NULL, width = NULL),
plotOutput(outputId = "myplot")
)
server <- function(input, output) {
output$myplot <- renderPlot({
data1 %>%
ggplot(aes(x = get(paste(input$select1)), y = get(paste(input$select2)), col = hydrogeomorphic_zone))+
geom_point(alpha = 0.8)
})
}
shinyApp(ui = ui, server = server)
If you want to use a variable as x or y, you can alternatively use aes_() instead of aes().
This would then result in:
ggplot(aes_(x = input$select1, y = input$select2))
Beware, that you need to add a tilde if you want to use a normal column name with aes_(), e.g.:
ggplot(aes_(x = ~elevation_navd88, y = input$select2))
I am trying to save a ggplot2 object made in a shiny app. Basically this code allows .xlsx files to be uploaded and plots created after selecting from some options. I have then included a download button so that the user may download the plot they have created. I am using downloadHandler() and grDevices::png(). Pressing the button does cause a .png file to be downloaded, but when I open it, it is just a blank, white square. I am so close! Any help would be much appreciated. Thank you.
#initialize
library(shiny)
library(ggplot2)
library(purrr)
library(dplyr)
library(plotly)
#example data
data(iris)
#make some factors
#easier to let ggplot2 control plotting (color, fill) based on type
data(mtcars)
uvals<-sapply(mtcars,function(x){length(unique(x))})
mtcars<-map_if(mtcars,uvals<4,as.factor) %>%
as.data.frame()
#plotting theme for ggplot2
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
# UI for app
ui<-(pageWithSidebar(
# title
headerPanel("Select Options"),
#input
sidebarPanel
(
# Input: Select a file ----
fileInput("file1", "Choose xlsx File",
multiple = TRUE,
accept = c(".xlsx")),
# Horizontal line ----
tags$hr(),
#download button
fluidPage(downloadButton('down')),
# Input: Select what to display
selectInput("dataset","Data:",
choices =list(iris = "iris", mtcars = "mtcars",
uploaded_file = "inFile"), selected=NULL),
selectInput("xaxis","X axis:", choices = NULL),
selectInput("yaxis","Y axis:", choices = NULL),
selectInput("fill","Fill:", choices = NULL),
selectInput("group","Group:", choices = NULL),
selectInput("plot.type","Plot Type:",
list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
),
checkboxInput("show.points", "show points", TRUE)
),
# output
mainPanel(
h3(textOutput("caption")),
#h3(htmlOutput("caption")),
uiOutput("plot") # depends on input
)
))
# shiny server side code for each call
server<-function(input, output, session){
#update group and
#variables based on the data
observe({
#browser()
if(!exists(input$dataset)) return() #make sure upload exists
var.opts<-colnames(get(input$dataset))
updateSelectInput(session, "xaxis", choices = var.opts)
updateSelectInput(session, "yaxis", choices = var.opts)
updateSelectInput(session, "fill", choices = var.opts)
updateSelectInput(session, "group", choices = var.opts)
})
output$caption<-renderText({
switch(input$plot.type,
"boxplot" = "Boxplot",
"histogram" = "Histogram",
"density" = "Density plot",
"bar" = "Bar graph")
})
output$plot <- renderUI({
plotOutput("p")
})
#get data object
get_data<-reactive({
if(!exists(input$dataset)) return() # if no upload
check<-function(x){is.null(x) || x==""}
if(check(input$dataset)) return()
obj<-list(data=get(input$dataset),
yaxis=input$yaxis,
xaxis=input$xaxis,
fill=input$fill,
group=input$group
)
#require all to be set to proceed
if(any(sapply(obj,check))) return()
#make sure choices had a chance to update
check<-function(obj){
!all(c(obj$yaxis,obj$xaxis, obj$fill,obj$group) %in% colnames(obj$data))
}
if(check(obj)) return()
obj
})
#plotting function using ggplot2
output$p <- renderPlot({
plot.obj<-get_data()
#conditions for plotting
if(is.null(plot.obj)) return()
#make sure variable and group have loaded
if(plot.obj$yaxis == "" | plot.obj$xaxis =="" | plot.obj$fill ==""| plot.obj$group =="") return()
#plot types
plot.type<-switch(input$plot.type,
"boxplot" = geom_boxplot(),
"histogram" = geom_histogram(alpha=0.5,position="identity"),
"density" = geom_density(alpha=.75),
"bar" = geom_bar(position="dodge")
)
if(input$plot.type=="boxplot") { #control for 1D or 2D graphs
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
y = plot.obj$yaxis,
fill = plot.obj$fill,# let type determine plotting
group = plot.obj$group
)
) + plot.type
if(input$show.points==TRUE)
{
p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
}
} else {
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
fill = plot.obj$fill,
group = plot.obj$group
#color = as.factor(plot.obj$group)
)
) + plot.type
}
p<-p+labs(
fill = input$fill,
x = "",
y = input$yaxis
) +
.theme
print(p)
})
# set uploaded file
upload_data<-reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
#could also store in a reactiveValues
read_excel(inFile$datapath)
})
observeEvent(input$file1,{
inFile<<-upload_data()
})
# downloadHandler contains 2 arguments as functions, namely filename, content
output$down <- downloadHandler(
filename = function() {
paste(input$dataset,"png" , sep=".")
},
# content is a function with argument file. content writes the plot to the device
content = function(file) {
png(file) # open the png device
p # for GGPLOT
dev.off() # turn the device off
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
I responded as a comment, but I recognize it's a little hard to follow, so I'll post the full revised code to make it clearer.
I generally recommend to not do too much within render*() calls. Rather, set up the object you're looking to create in a separate reactive() object, and just refer to that in renderPlot(). In the code below, I moved all your code that creates the plot into a reactive object named p, and then I can refer to it in ggsave() for the downloading.
#initialize
library(shiny)
library(ggplot2)
library(purrr)
library(dplyr)
library(plotly)
#example data
data(iris)
#make some factors
#easier to let ggplot2 control plotting (color, fill) based on type
data(mtcars)
uvals<-sapply(mtcars,function(x){length(unique(x))})
mtcars<-map_if(mtcars,uvals<4,as.factor) %>%
as.data.frame()
#plotting theme for ggplot2
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
# UI for app
ui<-(pageWithSidebar(
# title
headerPanel("Select Options"),
#input
sidebarPanel
(
# Input: Select a file ----
fileInput("file1", "Choose xlsx File",
multiple = TRUE,
accept = c(".xlsx")),
# Horizontal line ----
tags$hr(),
#download button
fluidPage(downloadButton('down')),
# Input: Select what to display
selectInput("dataset","Data:",
choices =list(iris = "iris", mtcars = "mtcars",
uploaded_file = "inFile"), selected=NULL),
selectInput("xaxis","X axis:", choices = NULL),
selectInput("yaxis","Y axis:", choices = NULL),
selectInput("fill","Fill:", choices = NULL),
selectInput("group","Group:", choices = NULL),
selectInput("plot.type","Plot Type:",
list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
),
checkboxInput("show.points", "show points", TRUE)
),
# output
mainPanel(
h3(textOutput("caption")),
#h3(htmlOutput("caption")),
uiOutput("plot") # depends on input
)
))
# shiny server side code for each call
server<-function(input, output, session){
#update group and
#variables based on the data
observe({
#browser()
if(!exists(input$dataset)) return() #make sure upload exists
var.opts<-colnames(get(input$dataset))
updateSelectInput(session, "xaxis", choices = var.opts)
updateSelectInput(session, "yaxis", choices = var.opts)
updateSelectInput(session, "fill", choices = var.opts)
updateSelectInput(session, "group", choices = var.opts)
})
output$caption<-renderText({
switch(input$plot.type,
"boxplot" = "Boxplot",
"histogram" = "Histogram",
"density" = "Density plot",
"bar" = "Bar graph")
})
output$plot <- renderUI({
plotOutput("p")
})
#get data object
get_data<-reactive({
if(!exists(input$dataset)) return() # if no upload
check<-function(x){is.null(x) || x==""}
if(check(input$dataset)) return()
obj<-list(data=get(input$dataset),
yaxis=input$yaxis,
xaxis=input$xaxis,
fill=input$fill,
group=input$group
)
#require all to be set to proceed
if(any(sapply(obj,check))) return()
#make sure choices had a chance to update
check<-function(obj){
!all(c(obj$yaxis,obj$xaxis, obj$fill,obj$group) %in% colnames(obj$data))
}
if(check(obj)) return()
obj
})
p <- reactive({
plot.obj<-get_data()
#conditions for plotting
if(is.null(plot.obj)) return()
#make sure variable and group have loaded
if(plot.obj$yaxis == "" | plot.obj$xaxis =="" | plot.obj$fill ==""| plot.obj$group =="") return()
#plot types
plot.type<-switch(input$plot.type,
"boxplot" = geom_boxplot(),
"histogram" = geom_histogram(alpha=0.5,position="identity"),
"density" = geom_density(alpha=.75),
"bar" = geom_bar(position="dodge")
)
if(input$plot.type=="boxplot") { #control for 1D or 2D graphs
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
y = plot.obj$yaxis,
fill = plot.obj$fill,# let type determine plotting
group = plot.obj$group
)
) + plot.type
if(input$show.points==TRUE)
{
p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
}
} else {
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
fill = plot.obj$fill,
group = plot.obj$group
#color = as.factor(plot.obj$group)
)
) + plot.type
}
p<-p+labs(
fill = input$fill,
x = "",
y = input$yaxis
) +
.theme
print(p)
})
#plotting function using ggplot2
output$p <- renderPlot({
p()
})
# set uploaded file
upload_data<-reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
#could also store in a reactiveValues
read_excel(inFile$datapath)
})
observeEvent(input$file1,{
inFile<<-upload_data()
})
# downloadHandler contains 2 arguments as functions, namely filename, content
output$down <- downloadHandler(
filename = function() {
paste(input$dataset,"png" , sep=".")
},
# content is a function with argument file. content writes the plot to the device
content = function(file) {
ggsave(file, p())
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
I have this shiny code and the plot is not showing for some reason. Can you please extend me a hand?
Is a basic shiny plot to render in the Main Panel. Checked loads of times and still not plotting.
library(shiny)
library(plotly)
library(ggplot2)
ui <- fluidPage(
(titlePanel("APP & MEP | Size (m2) ~ Hours", windowTitle = "app")),
sidebarLayout(
sidebarPanel(
checkboxGroupInput(inputId = "checkgroup",
label = "Select Deparments",
choices = c("All", "ELE", "HVAC", "MAN", "PH", "LV"),
selected = "All", inline = F),
radioButtons(inputId = "radio",
label = "ADD Stat_Smooth?",
choices = c("YES","NO"),
inline = T),
sliderInput(inputId = "slider",
label = "SPAN Setting",
min = 0.2, max = 2, value = 1,
ticks = T)
),
mainPanel(plotOutput(outputId = "plot33"))
)
)
server <- function(input, output){
output$plot33 <- renderPlotly({
gg <- ggplot(sizedf, aes(SIZE, Hours)) + geom_point(aes(color = Department)) + ggtitle("Size(m2) vs Hours per department")
p <- ggplotly(gg)
p
})
}
shinyApp(ui = ui, server = server)
I have seen this same mistake a few time already.
plotlyOutput() should be used, not plotOutput()
Shiny newbie here.
I am trying to write a R shiny script, and one of things I want to do is generate various plots.
I have a written this code for plotting by taking input from user but getting error of
Error in exists(name, envir = env, mode = mode) :
argument "env" is missing, with no default
Need Help to solve this
I am uploading my server and ui code.
Server.r
shinyServer(function(input,output){
data<-reactive({
file1<-input$file
if(is.null(file1)){return()}
read.table(file=file1$datapath,sep = input$sep,header = input$header,stringsAsFactors = input$stringAsFactors)
})
output$variable <- renderUI({
obj<-data()
if (is.null(obj))
return(NULL)
var.opts<-namel(colnames(obj))
selectInput("variable","Variable:", var.opts)
})
# y variable
output$group <- renderUI({
obj<-data()
if (is.null(obj))
return(NULL)
var.opts<-namel(colnames(obj))
selectInput("group","Groups:", var.opts)
})
#caption
output$caption<-renderText({
switch(input$plot.type,
"boxplot" = "Boxplot",
"histogram" = "Histogram",
"density" = "Density plot",
"bar" = "Bar graph")
})
#plot
output$plot <- renderUI({
plotOutput("p")
})
#plotting function using ggplot2
output$p <- renderPlot({
obj<-data()
plot.type<-switch(input$plot.type,
"boxplot" = geom_boxplot(),
"histogram" = geom_histogram(alpha=0.5,position="identity"),
"density" = geom_density(alpha=.75),
"bar" = geom_bar(position="dodge")
)
require(ggplot2)
#plotting theme
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
if(input$plot.type=="boxplot") { #control for 1D or 2D graphs
p<-ggplot(data=obj,
aes(
x = obj$group,
y = obj$variable,
fill = as.factor(obj$group)
)
) + plot.type
if(input$show.points==TRUE)
{
p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
}
} else {
p<-ggplot(data=obj,
aes(
x = obj$variable,
fill = as.factor(obj$group),
group = as.factor(obj$group)
#color = as.factor(plot.obj$group)
)
) + plot.type
}
p<-p+labs(
fill = input$group,
x = "",
y = input$variable
) +
.theme
print(p)
})
})
ui.R
shinyUI(fluidPage(
#Heading panel
titlePanel(title="Machine Learning and Statistics",),
#input data set
sidebarLayout(position = "right",
sidebarPanel(fileInput('file', 'Choose a File', multiple = T, accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
#default size for dataset
helpText("Default max. size is 7mb"),
#input number of observations
numericInput("obs", "Number of observations to view:", 10),
tags$hr(),
checkboxInput(inputId = 'header',label = 'Header',value = TRUE),
checkboxInput(inputId = "stringAsFactors","stringAsFactors",TRUE),
br(),
radioButtons(inputId = 'sep',label = 'Seprator',choices=c(comma=',',Semicolon=';',Tab='\t',Space=' '),selected = ','),
sliderInput("train_percent",
"Training Percentage:",
min = 10, max = 90,
value = 20, step = 10),
uiOutput("variable"), # depends on dataset ( set by output$variable in server.R)
uiOutput("group"), # depends on dataset ( set by output$group in server.R)
selectInput("plot.type","Plot Type:",
list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
),
checkboxInput("show.points", "show points", TRUE)
),
mainPanel(
("output"),
h3(textOutput("caption")),
uiOutput("plot")
)
)))
Help?Thanks.
My solution to this error message when using ggplot in Shiny is:
ggplot(data = obj, aes(...), environment = environment())
Would appreciate if someone could explain the reason behind the extra need for this in a Shiny app.