Plotting in Rshiny for newly created variable - r

I have a dataset with categorical data (let's use Arthritis from vcd package for exmaple purposes).
I want to obtain a barplot where for two variables and colouring by a third one.
In base R this would be:
library(vcd)
library(ggplot2)
data(Arthritis)
tab <- as.data.frame(prop.table(table(Arthritis$Treatment, Arthritis$Improved), margin = 1))
ggplot(tab,aes(x=Var1,y=Freq, fill=Var2, label = round(Freq,3)))+
geom_bar(stat = 'identity')+
geom_text(position = position_stack(vjust=0.5))+
scale_fill_manual(values=c('cyan3','tomato', 'blue'), guide = guide_legend(reverse=TRUE))
Which would give the result:
In my shinyApp the user should be able to choose the variables to plot.
For this I've created:
# Shiny
library(shiny)
library(shinyWidgets)
library(shinyjqui)
library(shinyjs)
# Data
library(readxl)
library(dplyr)
library(vcd)
# Plots
library(ggplot2)
not_sel <- "Not Selected"
ui <- navbarPage(
title = "Plotter",
windowTitle = "Plotter",
tabPanel(
"Plotter",
fluidPage(
fluidRow(
sidebarPanel(
title = "Inputs",
fileInput("xlsx_input", "Select XLSX file to import", accept = c(".xlsx")),
selectInput("num_var_1", "Variable X axis", choices = c(not_sel)),
selectInput("num_var_2", "Variable Y axis", choices = c(not_sel)),
uiOutput("factor"),
br(),
actionButton("run_button", "Run Analysis", icon = icon("play"))
),
# Main panel
mainPanel(
tabsetPanel(
tabPanel(
"Plot",
br(),
plotOutput("plot_1"),
br(),
verbatimTextOutput("data")
)
)
)
)
)
)
)
################# --------------------------------------------------------------
# Server
################# --------------------------------------------------------------
server <- function(input, output){
# Dynamic selection of the data
data_input <- reactive({
#req(input$xlsx_input)
#inFile <- input$xlsx_input
#read_excel(inFile$datapath, 1)
Arthritis
})
# We update the choices available for each of the variables
observeEvent(data_input(),{
choices <- c(not_sel, names(data_input()))
updateSelectInput(inputId = "num_var_1", choices = choices)
updateSelectInput(inputId = "num_var_2", choices = choices)
})
num_var_1 <- eventReactive(input$run_button, input$num_var_1)
num_var_2 <- eventReactive(input$run_button, input$num_var_2)
# data
data_discrete_plot <- reactive({
req(data_input(), input$num_var_1, input$num_var_2)
df <- data_input()
df1 <- as.data.frame(prop.table(table(df[[input$num_var_1]], df[[input$num_var_2]]), margin = 1))
df1
})
# Function for printing the plots
draw_barplot <- function(data_input)
ggplot(data = data_input, aes(x=data_input[1], y=data_input[3], fill=data_input [2], label = round(Freq, 3))) +
geom_bar(stat = "identity") +
scale_fill_manual(guide = guide_legend(reverse=TRUE)) +
ylim(0, 100) +
theme_bw()
## BarPlot -------------------------------------------------------------------
plot_1 <- eventReactive(input$run_button,{
req(data_input())
draw_barplot(data_discrete_plot())
})
output$plot_1 <- renderPlot(plot_1())
output$data <- renderPrint(data_discrete_plot())
}
# Connection for the shinyApp
shinyApp(ui = ui, server = server)
As you can see in the previous RepEx we are obtaining the contingency table, however, I'm finding some trouble when calling for the variables to plot,
as it is a new dataframe with different names for the data.
If I run the code above, I get an error that says: default method not implemented for type 'list'
But if I try to do something like:
data_input[1] <- unlist(data_input[1])
data_input[2] <- unlist(data_input[2])
data_input[3] <- unlist(data_input[3])
The application crashes.

As the columns of your new dataframe have names Var1, Var2 and Freqyou could do:
draw_barplot <- function(data_input) {
ggplot(data = data_input, aes(x = Var1, y = Freq, fill = Var2, label = round(Freq, 3))) +
geom_bar(stat = "identity") +
scale_fill_discrete(guide = guide_legend(reverse = TRUE)) +
ylim(0, 1) +
theme_bw()
}
Additionally I replaced scale_fill_manual by scale_fill_discrete as for the first one you have to provide a vector of color values and set ylim(0, 1) as the proportions in the ´Freq` column are on a 0 to 1 scale.

Related

undefined column selected error in Shiny app

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?

renderPlot with specific height doesn't allow to show a table next (Shiny)

I am trying to plot an histogram and next, a table. However, since I want a specific height, the table (which must appear after the histogram) starts in the middle of the histogram. Moreover, I would like to show a title before the table. (How could I a write a proper title before the table? Because I wrote "renderText" but it doesn't look very good).
What should I do?
If I delete "height" the table appears well.
Here you have an example of my code.
library(shiny)
library(ggplot2)
library(scales)
################### DATA ########################
val <- c(2.1490626,3.7928443,2.2035281,1.5927854,3.1399245,2.3967338,3.7915825,4.6691277,3.0727319,2.9230937,2.6239759,3.7664386,4.0160378,1.2500835,4.7648343,0.0000000,5.6740227,2.7510256,3.0709322,2.7998003,4.0809085,2.5178086,5.9713330,2.7779843,3.6724801,4.2648527,3.6841084,2.5597235,3.8477471,2.6587736,2.2742209,4.5862788,6.1989269,4.1167091,3.1769325,4.2404515,5.3627032,4.1576810,4.3387921,1.4024381,0.0000000,4.3999099,3.4381837,4.8269218,2.6308474,5.3481382,4.9549753,4.5389650,1.3002293,2.8648220,2.4015338,2.0962332,2.6774765,3.0581759,2.5786137,5.0539080,3.8545796,4.3429043,4.2233248,2.0434363,4.5980727)
df1 <- data.frame(val)
df1$type <- "Type 1"
val <- c(3.7691229,3.6478055,0.5435826,1.9665861,3.0802654,1.2248374,1.7311236,2.2492826,2.2365337,1.5726119,2.0147144,2.3550348,1.9527204,3.3689502,1.7847986,3.5901329,1.6833872,3.4240479,1.8372175,0.0000000,2.5701453,3.6551315,4.0327091,3.8781182)
df2 <- data.frame(val)
df2$type <- "Type 2"
df3 <- rbind(df1, df2)
################ SHINY APP ########################
ui <- fluidPage(
titlePanel("Histogram"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("hist"),
textOutput("text"),
tableOutput("table")
)
)
)
server <- function(input, output) {
output$hist <- renderPlot(height=700,{
p <- ggplot(df3, aes(val, fill=type)) +
geom_histogram(position = "identity", colour = "grey40", bins = 10) +
ggtitle("Here must be a title") +
xlab("Values") +
ylab("Frequency") +
facet_grid(type ~ .) +
scale_x_continuous(breaks=pretty(as.matrix(df3$val), n=10))
p + theme(strip.text.x = element_blank(),
strip.text.y = element_blank())
})
output$text <- renderText("People with these values: ")
output$table <- renderTable(df3)
}
shinyApp(ui = ui, server = server)
Here you can see the problem:
Thanks very much in advance,
Regards
I have solved it.
The idea is that I should have moved "height" in the ui instead of being in the server. plotOutput("hist", height=700)
To put some space between the plot and the table, it can be solved writing br()
library(shiny)
library(ggplot2)
library(scales)
################### DATA ########################
val <- c(2.1490626,3.7928443,2.2035281,1.5927854,3.1399245,2.3967338,3.7915825,4.6691277,3.0727319,2.9230937,2.6239759,3.7664386,4.0160378,1.2500835,4.7648343,0.0000000,5.6740227,2.7510256,3.0709322,2.7998003,4.0809085,2.5178086,5.9713330,2.7779843,3.6724801,4.2648527,3.6841084,2.5597235,3.8477471,2.6587736,2.2742209,4.5862788,6.1989269,4.1167091,3.1769325,4.2404515,5.3627032,4.1576810,4.3387921,1.4024381,0.0000000,4.3999099,3.4381837,4.8269218,2.6308474,5.3481382,4.9549753,4.5389650,1.3002293,2.8648220,2.4015338,2.0962332,2.6774765,3.0581759,2.5786137,5.0539080,3.8545796,4.3429043,4.2233248,2.0434363,4.5980727)
df1 <- data.frame(val)
df1$type <- "Type 1"
val <- c(3.7691229,3.6478055,0.5435826,1.9665861,3.0802654,1.2248374,1.7311236,2.2492826,2.2365337,1.5726119,2.0147144,2.3550348,1.9527204,3.3689502,1.7847986,3.5901329,1.6833872,3.4240479,1.8372175,0.0000000,2.5701453,3.6551315,4.0327091,3.8781182)
df2 <- data.frame(val)
df2$type <- "Type 2"
df3 <- rbind(df1, df2)
################ SHINY APP ########################
ui <- fluidPage(
titlePanel("Histogram"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("hist", height=700),
br(),
br(),
textOutput("text"),
br(),
tableOutput("table")
)
)
)
server <- function(input, output) {
output$hist <- renderPlot({
p <- ggplot(df3, aes(val, fill=type)) +
geom_histogram(position = "identity", colour = "grey40", bins = 10) +
ggtitle("Here must be a title") +
xlab("Values") +
ylab("Frequency") +
facet_grid(type ~ .) +
scale_x_continuous(breaks=pretty(as.matrix(df3$val), n=10))
p + theme(strip.text.x = element_blank(),
strip.text.y = element_blank())
})
output$text <- renderText("People with these values: ")
output$table <- renderTable(df3)
}
shinyApp(ui = ui, server = server)

Subset dataframe based on selectInput in R Shiny

I have a shiny app in which I generate scagnostics based on the relationship between variables in a dataframe, as follows
library(binostics)
scagnostics(df$x1,
df$x2)$s
However, I want to dynamically select these variables from a drop down list. But when I do so I'm not able to subset the data frame based on the input variables
selectInput("v1", label = "Select Variable 1", choices = selection, selected = "x1"),
selectInput("v2", label = "Select Variable 2", choices = selection, selected = "x2")
scagnostics(df$input$v1,
df$input$v2)$s
Reproducible Example :
library(readr)
library(binostics)
library(tidyverse)
library(gridExtra)
big_epa_cars_2019 <- readr::read_csv("https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-10-15/big_epa_cars.csv") %>%
filter(year == 2019)
my_vars <- c("barrels08", "cylinders", "city08", "highway08", "feScore", "fuelCost08", "co2TailpipeGpm", "youSaveSpend")
ui <- fluidPage(
fluidRow(
column(1),
column(3, selectInput("v1", label = "Select x Variable", choices = my_vars, selected = "barrels08")),
column(3, selectInput("v2", label = "Select y Variable", choices = my_vars, selected = "city08"))
),
fluidRow(
column(1),
column(10, plotOutput("scagnosticsplots")),
column(1))
)
server <- function(input, output, session) {
output$scagnosticsplots <- renderPlot({
p1 <- ggplot(big_epa_cars_2019,
aes(x = get(input$v1),
y = get(input$v2))) +
geom_point() +
theme_bw() +
labs(x = input$v1,
y = input$v2)
s <- scagnostics(big_epa_cars_2019$input$v1,
big_epa_cars_2019$input$v2)$s
df_s <- tibble(scag = names(s), value = s) %>%
mutate(scag = fct_reorder(scag, value))
p2 <- ggplot(df_s, aes(x=value, y=scag)) +
geom_point(size=4, colour="orange") +
geom_segment(aes(x=value, xend=0,
y=as.numeric(scag),
yend=as.numeric(scag)), colour="orange") +
theme_bw() +
labs(x = "Scagnostic value",
y = "")
grid.arrange(p1, p2, ncol=2)
})
}
shinyApp(ui, server)
#Ben's answer commented above worked.
s <- scagnostics(big_epa_cars_2019[[input$v1]], big_epa_cars_2019[[input$v2]])$s

How do I get my train() function to operate in shiny to evaluate model performance?

I'm working on a project to create a shiny app that allows users to do some modeling, choose a model and make some predictions.
When I run the train() function in the r console on my data it works fine. When I run it in my shiny app, I consistently get an error: contrasts can be applied only to factors with 2 or more levels. My dataframe has no factors. Can't figure out why it works in console but not shiny. Any help would be appreciated!
Here is my code:
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Variables Impacting Hate Crime Rates"),
# define main panel layout
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Information",
textOutput("introduction")),
tabPanel("Data Exploration",
textOutput("data"),
selectInput("x","Explanatory variable:",
choices = colnames(crimes),
selected = "median_household_income"),
selectInput("y","Response variable:",
selected = "median_household_income",
choices = colnames(crimes)),
plotOutput("scatterplot"),
selectInput("y2", "Variable to compare:",
selected = "median_household_income",
choices = colnames(crimes)),
plotOutput("boxplot"),
selectInput("var","Summary variable:",
choices = colnames(crimes),
selected = "median_household_income"),
verbatimTextOutput("summary"))
,
tabPanel("Unsupervised Learning",
selectInput("k","Number of clusters:",
choices = c(1,2,3),
selected = 1),
plotOutput("cluster"),
selectInput("dmethod","Distance method:",
choices = c("euclidian","binary","minkowski",
"canberra","manhattan","maximum"),
selected = "euclidian"),
selectInput("cmethod", "Cluster method:",
choices = c("single","complete"),
selected = "single"),
plotOutput("tree")),
tabPanel("Modeling",
selectInput("xvar", "x variable:",
choices = colnames(crimes),
selected = "gini_index"),
selectInput("yvar", "y variable:",
choices = colnames(crimes),
selected = "median_household_income"),
verbatimTextOutput("model")),
tabPanel("Data",
DT::dataTableOutput("mytable1"))
)
)
))
source("C:/Users/W447075/Documents/ST558/Comora_final/helpers.R")
shinyServer(function(input, output,session){
output$introduction <- renderText({
"This is my introduction"
})
output$data <- renderText({
"This page allows you to create some basic graphical
and numeric summaries including a scatter plot, boxplot,
and statistical summary for any of the variables in the
'crimes' dataset."
})
selectedData <- reactive({
crimes %>% filter(region ==input$region)
})
selectData2 <- reactive({
crimes[ , c("region",input$y)]
})
selectData3 <- reactive({
crimes[ , c("region", input$y2)]
})
mydata <- reactive({
crimes[ ,input$var]
})
mycluster <- reactive({
kmeans(df_scale, centers = input$k, nstart = 25)
})
d <- reactive({
dist(df, method = input$dmethod)
})
clusterplot <- reactive({
plot(hclust(d(), method = input$cmethod))
})
model <- reactive({
train(input$yvar ~ input$xvar, crimes,
method = "lm",
trControl = trainControl(
method = "cv", number = 10,
verboseIter = TRUE))
})
#render a barplot
output$scatterplot <- renderPlot({
ggplot(crimes, aes_string(x = input$x,
y = input$y)) +
geom_point(size = 3) +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank())
})
output$boxplot <- renderPlot({
ggplot(selectData3(), aes(x = region, y = selectData3()[ ,input$y2])) +
geom_boxplot(aes(fill = region)) + ylab(input$y2)+
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank())
})
output$summary <- renderPrint({
dataset <- na.omit(mydata())
summary(dataset)
})
output$cluster <- renderPlot({
fviz_cluster(mycluster(),data = df)
})
output$tree <- renderPlot({
clusterplot()
})
output$mytable1 <- DT::renderDataTable({
DT::datatable(df)
})
output$model <- renderText({
model()
})
})

R-shiny: How to add a slider to filter the numeric input?

So I am using mpg dataset to practice my R-shiny skills, but I encountered a problem.
I want to write a app which I could choose different variables to make graph, if it involves at least one discrete variable, then I draw a geom_boxplot, else, I will just draw a geom_point.
Now I want to add a slider to filter numeric inputs, but how?
My ui.R looks like this:
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput(inputId = "var1",
label = "Choose x variable",
choices =
names(mpg)
),
selectInput(inputId = "var2",
label = "Choose y variable",
choices =
names(mpg))
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
And
My server.R looks like this:
server <- function(input,output){
output$distPlot <- renderPlot({
# browser()
if(typeof(mpg[[input$var1]]) == "character")
{
ggplot(mpg) +
xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2)) +
geom_boxplot(mapping =
aes_string(x = input$var1,
y = input$var2))
}
else
{
ggplot(mpg) +
xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2)) +
geom_point(mapping =
aes_string(x = input$var1,
y = input$var2))
}
})
}
Now, how could I add a slider to filter numeric input?
I am a new learner, please help me.
Thank you very much
I'm sorry that I don't have time to flesh out this demo into a better example but hopefully this will show you the methodology:
library(shiny)
library(ggplot2)
library(magrittr)
ui <- fluidPage(
# Application title
titlePanel("Optional Numeric Slider Demo"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "var1",
label = "Choose x variable",
choices =
names(mpg)
),
uiOutput('Var1Slider'),
br(),
selectInput(inputId = "var2",
label = "Choose y variable",
choices =
names(mpg)[sapply(mpg,class)=="character"])
),
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input,output){
output$distPlot <- renderPlot({
if(typeof(mpg[[input$var1]]) == "character")
{
ggplot(mpg) +
xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2)) +
geom_boxplot(mapping =
aes_string(x = input$var1,
y = input$var2))
}
else
{
mpg %>%
dplyr::filter(get(input$var1)>input$Var1Slide[1]) %>%
dplyr::filter(get(input$var1)<input$Var1Slide[2]) %>%
ggplot() +
xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2)) +
geom_point(mapping =
aes_string(x = input$var1,
y = input$var2))
}
})
output$Var1Slider <- renderUI({
if(typeof(mpg[[input$var1]]) == "character"){
return(NULL)
}else{
sliderInput('Var1Slide',
label=paste("selected:",input$var1),
min=min(mpg[[input$var1]]),
max=max(mpg[[input$var1]]),
value=c(min(mpg[[input$var1]]),max(mpg[[input$var1]])),
step = 1)}
})
}
# Run the application
shinyApp(ui = ui, server = server)
The key points are the use of renderUI and uiOutput to move computation to the server side. I've also added a line to the numeric graph code to show how to use the input (even if the edit is nonsensical at the moment). Let me know if anything is unclear.
EDIT:I've changed this example so that the slider values actually filter the data going into the plot.

Resources