I saw this app https://rich.shinyapps.io/regression/ and I wanted to do something similar displaying the regression output as html.
I divided my app in three parts as below.
server.R has no "engine" problems and the regression result is correct and pander is converting summary() to markdown correctly.
ui.R is also working ok but the markdown displayed after htmlOutput("model") is suppossed to be obtained from
output$model <- renderPrint({
pander(summary(model()))
})
in server.R, and the table is not well displayed even when its a valid markdown table.
How can I display my markdown summary as a common table like in R Markdown? my current output is:
Full MWE of the app
global.R
#library(shinyapps)
library(googleVis)
library(knitr)
library(pander)
library(shiny)
#library(shinysky)
ui.R
# Define UI for application
shinyUI(fluidPage(
# Application title
titlePanel("Bivariate Regression"),
# Sidebar
sidebarLayout(
sidebarPanel(
textInput("name", label = h5("Name"), value = "Name"),
HTML('</br>'),
#selectInput("dataset", h5("Choose a dataset:"), choices = c("cars", "longley", "MLB","rock", "pressure")),
selectInput("dataset", h5("Choose a dataset:"), choices = c("cars", "longley","rock", "pressure")),
HTML('</br>'),
uiOutput('dv'),
HTML('</br>'),
uiOutput('iv'),
HTML('</br>')),
#radioButtons('format', h5('Document format'), c('PDF', 'HTML', 'Word'), inline = TRUE),
#downloadButton('downloadReport')),
#includeHTML('help.html')),
# main panel
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Data",
HTML("</br>Select a data set from the 'Choose a dataset menu' or enter your own data below </br> </br>"),
numericInput("obs", label = h5("Number of observations to view"), 10),
tableOutput("view")),
tabPanel("Summary Statistics",
verbatimTextOutput("summary"),
textInput("text_summary", label = "Interpretation", value = "Enter text...")),
tabPanel("Model",
htmlOutput("model"),
textInput("text_model", label = "Interpretation", value = "Enter text..."))
)
))
))
server.R
shinyServer(function(input, output) {
# list of data sets
datasetInput <- reactive({
switch(input$dataset,
"cars" = mtcars,
"longley" = longley,
"MLB" = mlb11,
"rock" = rock,
"pressure" = pressure,
"Your Data" = df())
})
# dependent variable
output$dv = renderUI({
selectInput('dv', h5('Dependent Variable'), choices = names(datasetInput()))
})
# independent variable
output$iv = renderUI({
selectInput('iv', h5('Independent Variable'), choices = names(datasetInput()))
})
# regression formula
regFormula <- reactive({
as.formula(paste(input$dv, '~', input$iv))
})
# bivariate model
model <- reactive({
lm(regFormula(), data = datasetInput())
})
# create graphics
# data view
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})
# summary statistics
output$summary <- renderPrint({
summary(cbind(datasetInput()[input$dv], datasetInput()[input$iv]))
})
# bivariate model
output$model <- renderPrint({
pander(summary(model()))
})
# residuals
output$residuals_hist <- renderPlot({
hist(model()$residuals, main = paste(input$dv, '~', input$iv), xlab = 'Residuals')
})
output$residuals_scatter <- renderPlot({
plot(model()$residuals ~ datasetInput()[,input$iv], xlab = input$iv, ylab = 'Residuals')
abline(h = 0, lty = 3)
})
output$residuals_qqline <- renderPlot({
qqnorm(model()$residuals)
qqline(model()$residuals)
})
})
Related
I created a shiny app for logistic regression model.
My idea is allow user define formular by typing in textInput box ex. 'Response ~ Pred1 + Pred2' and then convert to formula by function 'as.formula(paste0(input$formula))'.
It works in RStudio, but not work in shinydashboard render.
The error is 'y values must be 0 <= y <= 1'. Any body help?
This work well in Rstudio
s <- 'Direction ~ Lag1+ Lag2'
model <- glm(as.formula(paste0(s)),
data = Smarket,
family = binomial,
subset = train_data$id)
But in shinydashboard, the formula render from textInput box is not working.
My code below
My ui.R
library(tidyverse)
library(shiny)
library(shinydashboard)
library(ISLR2)
ui <- dashboardPage(
dashboardHeader(title = 'Classification'),
dashboardSidebar(width = '275',
sidebarMenu(
menuItem('Instruction', tabName = 'instruction', icon = icon('hammer', lib = 'font-awesome')),
menuItem('Table & Correlation', tabName = 'table', icon = icon('table', lib = 'font-awesome')),
menuItem('DS', tabName = 'ds', icon = icon('desktop', lib = 'font-awesome')),
fileInput(inputId = 'f_input', label = 'Upload File'),
div(class='col-lg-12 col-md-12',
hr()),
# Correlation
uiOutput(outputId = 'corre'),
actionButton(inputId = 'button1', label = 'Correlation'),
div(class='col-lg-12 col-md-12',
hr()),
# Train-Test
sliderInput("data_split", label = "Percent Train", min = 0,
max = 100, value = 70, step = 5),
# Fit Model
textInput(inputId = 'formula',
label = 'Creat formula',
placeholder = 'y ~ X1 + X2 + ...'),
actionButton(inputId = 'button2', label = 'Run Model'),
div(class='col-lg-12 col-md-12',
hr())
)
),
dashboardBody(
tabItems(
tabItem(tabName = 'instruction'),
tabItem(tabName = 'table',
fluidRow(
DT::dataTableOutput('view_table')
),
fluidRow(
plotOutput('corr_plot')
)),
tabItem(tabName = 'ds',
fluidRow(
box(verbatimTextOutput('summary')),
box(plotOutput('conf.matrix'))
)
)
)
)
)
My server.R
server <- function(input, output, session){
### RAW MATERIALS
#upload csv file
data <- reactive({
file <- input$f_input
data <- if(!is.null(file)){
read.csv(file$datapath)
} %>%
as_tibble()%>%
mutate(id = row_number())
})
#render RAW table
output$view_table <- DT::renderDataTable(
data(),
options = (list(scrollX = TRUE))
)
###-----------------------------------------
### CORRELATION
#user select Xi to generate correlation plot
output$corre <- renderUI({
data <- data()
if(!is.null(data)){
CHOICES <- names(data)
shinyWidgets::pickerInput('var',
label = 'Select to generated correlation of variables',
choices = CHOICES,
options = list(`actions-box` = TRUE),
multiple = TRUE)
}
})
#filter table matched selection from pickerInput
df <- eventReactive(input$button1, {
data <- data()
if(!is.null(data)){
data %>%
select(dplyr::matches(input$var))
}
})
#corr plot
output$corr_plot <-renderPlot({
df() %>%
ggcorr()
})
###-----------------------------------------
### TRAIN-TEST DATA SPLIT
i <- reactive({
set.seed(112)
data() %>%
rsample::initial_split(prop = as.numeric(input$data_split)/100)
})
###-----------------------------------------
### FIT MODEL
model <- eventReactive(input$button2, {
train_data <- rsample::training(i())
test_data <- rsample::testing(i())
##Logistic Regression
glm(as.formula(paste0(input$formula)),
data = data(),
family = binomial,
subset = train_data$id) #parse index of train
})
output$summary <- renderPrint({
if(!is.null(model())){
summary(model())
}
})
}
shinyApp(ui = ui, server = server)
I am quite new in Shiny, so forgive me for asking a so basic question.
I am trying to develop a basic data analysis app, in order to deal with big databases. I have already been able of importing the DDBB and to visualize it as a table. However, when trying to perform a summary statistics about the variables, I have the error of: "Undefinded columns selected" and I cannot see anything. If I do not add any code in the server, I can see the output (boxplot, histogram and summary) in the app, but I cannot see variable names (only 1,2,3...). I show my code below.
I will really appreciate any help to solve this issue. Thank you very much.
shinyUI(fluidPage(
main_page <- tabPanel(
title = "Statistics",
titlePanel("Statistical Analysis"),
sidebarLayout(
sidebarPanel(
# Añado el archivo que quiero cargar
fileInput('DDBB', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
#checkboxInput('header', 'Header', TRUE),
#tags$hr(),
selectInput('Variable', 'Select a variable', "",
choice=c((1:33)), multiple = FALSE,
selectize = TRUE
),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 200,
value = 30)
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Data Visualization",
DT::dataTableOutput("sample_table")
),
tabPanel(
title = "Summary Statistics",
verbatimTextOutput("sum"),
fluidRow(splitLayout(cellWidths = c("50%", "50%"),
plotOutput("box"),
plotOutput('hist'))
)
)
)
)
)
)
))
# Define server logic required to draw a histogram
shinyServer(function(input, output, session) {
# Output a file input (cargar archivo).
df_products_upload <- reactive({
inFile <- input$DDBB
print(inFile)
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = TRUE,sep = ';')
# updateSelectInput(session, "Variable", choices = names(df))
return(df)
})
output$sample_table<- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df,
filter = 'top') %>%
formatRound(columns= c(1:ncol(df)), digits = 2)
})
observeEvent(df_products_upload(), {
updateSelectInput(session, "Variable", choices = colnames(df_products_upload()))
})
output$sum <- renderPrint({
updateSelectInput(session, "Variable", choices = colnames(df)
summary(df[,as.numeric(input$Variable)])
})
output$box <- renderPlot({
updateSelectInput(session, "Variable", choices = colnames(df_products_upload))
x<-summary(df[,as.numeric(input$Variable)])
boxplot(x,col="sky blue",border="purple",main=names(df[as.numeric(input$Variable)]))
})
output$hist <- renderPlot({
updateSelectInput(session, "Variable", choices = colnames(df_products_upload))
# generate bins based on input$bins from ui.R
x<-df[,as.numeric(input$Variable)]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x,
main=names(df[as.numeric(input$Variable)]) ,
breaks = bins, col = 'darkgray', border = 'black',
xlab = 'samples')
})
})
Welcome to Stack-Overflow, Enrique :) I added a line to save iris dataset as ';'-separated csv and used that as uploadable data example. I must say, your code had multiple errors, both shiny and also a bit basic base R data.frame manipulation. I have corrected them and added comments. All beginnings are hard. I would suggest you to go back and do some more shiny exercises and tutorials. I think you will advance faster that way.
Especially revisit reactive expressions:
https://shiny.rstudio.com/tutorial/written-tutorial/lesson6/
It matters if you pass as parameter the value of a reactive sum(my_reactive_numbers()) or the reactive it self sum(my_reactive_numbers).
Also check out scope rules for shiny reactive contexts. Basically like functions, what is defined within one reactive context, is not automatically exposed to others, hence the df issues. If you would want to (probably not) make a variable global, here is a deeper intro into that:
https://shiny.rstudio.com/articles/scoping.html
library(DT)
write.table(iris,file = "./sample_upload_data_set.csv",sep = ";") #; because assmed in code
ui <- shinyUI(fluidPage(
main_page <- tabPanel(
title = "Statistics",
titlePanel("Statistical Analysis"),
sidebarLayout(
sidebarPanel(
# Añado el archivo que quiero cargar
fileInput('DDBB', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
#checkboxInput('header', 'Header', TRUE),
#tags$hr(),
selectInput('Variable', 'Select a variable', NULL,
choices = NULL, #edits start with NULL as no data set yet
multiple = FALSE,
selectize = TRUE
),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 200,
value = 30)
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Data Visualization",
DT::dataTableOutput("sample_table")
),
tabPanel(
title = "Summary Statistics",
verbatimTextOutput("sum"),
fluidRow(splitLayout(cellWidths = c("50%", "50%"),
plotOutput("box"),
plotOutput('hist'))
)
)
)
)
)
)
))
# Define server logic required to draw a histogram
server <- function(input, output, session) {
#expose an uplaoded csv file as a reactive data.frame
df_products_upload <- reactive({ #todo consider a shorter name e.g. r_prod_up.df
inFile <- input$DDBB #
print(inFile)
#if (!is.null(inFile))
# return(NULL) do not use return in any shiny reactive context, it is not a function
#req is practical replacement of if '(is.null(inFile)) return(NULL)'-pattern
req(inFile$datapath) #must be not null, non_empty character, or reactive will not complete
df <- read.csv(inFile$datapath, header = TRUE,sep = ';')
# updateSelectInput(session, "Variable", choices = names(df))
#return(df) ## EDIT do not use return
df
})
#let data.frame column names be choices of an input
observe({ #edit observeEvent was redundant, just use observe here
df <- df_products_upload()
#the following code expects numeric columns
the_numeric_columns <- colnames(df)[sapply(df,is.numeric)]
updateSelectInput(session, "Variable", choices = the_numeric_columns)
})
#render the data.frme with data.table
output$sample_table <- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df, filter = 'top') %>%
#formatRound will mask non numeric columns
formatRound(
columns = which(sapply(df,is.numeric)), #only format numeric columns
digits = 2
)
})
# but this render makes absolutely no sense, you should
output$sum <- renderPrint({
#edit it is bad behavior to do side effects in render scopes
# updateSelectInput(session, "Variable", choices = colnames(df_products_upload()) #edit df was not assign in scope
# summary(df[,as.numeric(input$Variable)])
# })
}) # edit missing bracket
output$box <- renderPlot({
#browser()
#edit bad behaviour, maybe you missunderstood the update functionSelectInput
#updateSelectInput(session, "Variable", choices = colnames(df_products_upload())) #edit reactive must be read not passed directly to colnames
#edit df is not assigened in this scope
df <- df_products_upload()
#x<-summary(df[,as.numeric(input$Variable)]) #edit this is no bueno, what if varaible names were ... names
# edit since plucking only one column and dropping data.frame wrap
# you may just use [[]] brackets to make it more explicit to the reader
x<-df[[input$Variable]] #this can only return the vector of one column or NULL
x<-summary(x)
boxplot(
x,
col="sky blue",
border="purple",
#comma was missing here, and why not just use Varaible
main = input$Variable
)
})
output$hist <- renderPlot({
#browser()
#edit df is not assigened in this scope
df <- df_products_upload()
#update makes no sense here
#updateSelectInput(session, "Variable", choices = colnames(df)) #edit if introducing df anyways just use that
# generate bins based on input$bins from ui.R
# edit since plucking only one column and dropping data.frame wrap
# you may just use [[]] brackets to make it more explicit to the reader
x<-df[[input$Variable]] #this can only return the vector of one column or NULL
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x,
#main=names(df[as.numeric(input$Variable)]) , # you're assuming columns would be named by numbers...
#...and it is quite like crossing the river to get water,
main = input$Varible,
breaks = bins, col = 'darkgray', border = 'black',
xlab = 'samples'
)
})
}
shiny::shinyApp(ui = ui, server = server)
I want to display a latex equation in a shiny application. I saw an example where mathjax is used to display latex equations. But for some reason the equation generated from equatiomatic package does not display correctly. Following is a reproducible example:
library(shiny)
library(tidyverse)
library(broom)
library(equatiomatic)
## Loading Dataset
data(mpg)
mpg2 <- mpg %>%
select(where(is.numeric))
## User Interface
ui <- fluidPage(
withMathJax(),
sidebarPanel(
selectInput(inputId = "xcol",
label = "Select an explanatory variable",
choices = colnames(mpg2),
selected = "cty"),
selectInput(inputId = "ycol",
label = "Select a response variable",
choices = colnames(mpg2),
selected = "hwy")
),
mainPanel(
plotOutput('plot'),
br(),
uiOutput('eq'),
br(),
tableOutput('table1'),
br(),
tableOutput('table2')
)
)
## Server
server <- function(input, output, session) {
data <- reactive({
mpg2 %>%
select(col1 = input$xcol, col2 = input$ycol)
})
output$plot <- renderPlot({
ggplot(data()) +
geom_point(aes(col1, col2)) +
labs(x = input$xcol, y = input$ycol)
})
output$table1 <- renderTable({
m1 <- lm(reformulate(input$xcol, input$ycol), data = mpg2)
broom::tidy(m1)
})
output$table2 <- renderTable({
m1 <- lm(reformulate(input$xcol, input$ycol), data = mpg2)
broom::glance(m1)[, 1:2]
})
output$eq <- renderUI({
m1 <- lm(reformulate(input$xcol, input$ycol), data = mpg2)
withMathJax(helpText(extract_eq(m1)))
})
}
shinyApp(ui, server)
Interesting, it seems like shiny is expecting the equation as raw character string. Hence it is missing a \ for all Latex operators.
One (not very pretty) way to fix it would be:
output$eq <- renderUI({
m1 <- lm(reformulate(input$xcol, input$ycol), data = mpg2)
withMathJax(helpText(
paste0("$$", as.character(extract_eq(m1)), "$$")
)
)
})
However I am not too familiar with the package so not sure if this is intended or a bug... Have you considered opening an issue at the equatiomatic GitHub?
I am trying to plot a line graph and a dot using ggplot2. The dot is created using the two inputs that the visitor types into ui.R. The ggplot equation works if I substitute numbers, e.g 18 and 24, for Zp and Kp. But I get an error, when I try to use the actual input values from the input fields "yrsales" and "yrinventory" into the ggplot expression. Please help. The code is shown below.
Server.R
library(shiny)
library(datasets)
library(ggplot2)
sapparel <- read.csv("Apparel.csv")
ssdrinks <- read.csv("Soft_drinks.csv")
Zp = 0
Kp = 0
shinyServer(function(input, output) {
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars,
"apparel" = sapparel,
"soft drinks"= ssdrinks,
)
})
current <- reactive ({
Zp <- input$yrsales
Kp <- input$yrinventory
})
output$newplot <- renderPlot ({
# setting variables for default variable
indInter <- 0.65
indslope <- 0.87
MinSale <- 13.37
MaxSale <- 22.83
PredictInvtMin <- indInter+I(indslope*MinSale)
PredictInvtMax <- indInter+I(indslope*MaxSale)
Inventory <- c(PredictInvtMin, PredictInvtMax)
Sales <- c(MinSale, MaxSale)
DatasetPredict.data <- data.frame(Sales, Inventory)
## plot a line graph for new input
print(
((ggplot(data = DatasetPredict.data, aes(x = Sales, y = Inventory)) + geom_line())+geom_point(aes(x= Zp, y = Kp, size=6))))
})
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
})
Ui.R
library(shiny)
shinyUI(fluidPage(
#Application project title
titlePanel("My reactivity project"),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset to use:", choices = c("rock", "pressure", "cars", "apparel", “drinks”)),
helpText("If your sales was $ 30,450,000 million, enter 30.45 in the field"),
numericInput("yrsales", "Enter your sales data:", value=20, step=.01),
numericInput("yrinventory", "Enter your inventory data:", value=10, step=.01)
),
mainPanel(
verbatimTextOutput("summary"),
plotOutput("newplot")
)
)
))
I am a little confused about printing the dynamic output while using R in shiny. The following are my code in shiny, it can just print out the ggplot2 charts, but not along with the new data frame. I just wanna know how to print out "mydata" at the same time. Thanks.
library("reshape2")
library("ggplot2")
Server.R
shinyServer(function(input, output) {
output$main_plot <- renderPlot({
#Draw gragh to compare the forecast values with real data
mydata <- data.frame(years, A, B)
df <- melt(mydata, id = 'years', variable = 'series')
print(ggplot(df, aes(years,value)) + geom_line(aes(colour = series), size=1.5))
})
Ui.R
shinyUI(pageWithSidebar(
# Sidebar with controls to select a dataset
# of observations to view
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("Netflix"))),
plotOutput(outputId = "main_plot", height = "500px")
))
Pull out the data frame into a reactive expression, so you can use it from two different outputs. (This is the reactive analog to introducing and reusing a variable.)
server.R
shinyServer(function(input, output) {
mydata <- reactive({
data.frame(years, A, B)
})
output$main_plot <- renderPlot({
#Draw gragh to compare the forecast values with real data
df <- melt(mydata(), id = 'years', variable = 'series')
print(ggplot(df, aes(years,value)) + geom_line(aes(colour = series), size=1.5))
})
output$data <- renderTable({ mydata() })
})
ui.R
shinyUI(pageWithSidebar(
# Sidebar with controls to select a dataset
# of observations to view
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("Netflix"))),
plotOutput(outputId = "main_plot", height = "500px"),
tableOutput(outputId = "data")
))