Shiny tabPanel datatable including filter options - shiny

I have created a tabPanel and want to give the chance to filter by different variables (e.g., show All, gender (male or female), gaming frequency (never, sometimes, often). Giving a filter possibility on the right side of the table.
The tabPanel alone is working fine, however, I do not know how to add the select Input filter (a) multiple variables as well as b) used the output$data for output$mytable.
Gender <- c(2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1) # 1 male, 2 female
Gaming_freq <- c(2, 3, 3, 3, 6, 4, 5, 5, 3, 5, 6, 5, 3, 3, 3, 2, 5, 6, 6, 3) # 2 = less than once a month, 3= once a month, 4 = once a week, 5 = more than once a week, 6 = daily
color_white <- c(0.14939, -0.40033, 0.638, -0.40328, -0.5725, 0.77422, 0.47419, -0.14982, 0.61388, 0.29264, 1.63992, 1.69396, -0.76722, 0.2279, 1.8937, 1.05535, -0.02912, -0.98787, -0.08184, 0.02536)
color_black_red <- c(-0.22686, 1.0993, 1.31564, 1.79799, 0.58323, -0.20128, 0.28315, 0.65687, -0.28894, 1.03393, 0.19963, -0.14561, 0.889, 1.5685, 0.15463, 0.74984, 0.42837, 1.31831, 0.82064, 1.13308)
color_black_blue <- c(-0.19905, -0.12332, -0.3628, 0.04108, -0.51553, -0.74827, -0.73246, -1.15794, -1.05443, -0.79687, -0.43895, -0.48986, -0.25574, -1.55343, -0.52319, -0.31203, -0.62926, -1.0094, -0.11217, -0.76892)
Controller_none <- c(-0.83456, -2.1176, -2.09919, -2.30543, -1.8594, -1.83014, -2.67447, -2.25647, -0.33004, 1.04676, -0.0674, -1.22428, -0.61644, -2.49707, 0.1737, -1.38711, -0.86417, -0.9775, -0.86747, -0.13341)
Controller_white <- c(0.51451, 0.49362, 1.17843, -0.03151, 1.27484, 0.74152, 0.07918, 1.18577, 0.50183, -0.1483, 0.22328, 1.1426, 0.46526, 1.94735, -0.60943, 1.02407, 0.55938, 1.10468, -0.12908, -0.00329)
Controller_red <- c(0.93577, 1.92379, 0.8746, 1.02084, 1.08547, 0.74312, 1.53032, 0.74821, -0.10777, 0.48774, 0.29206, 0.09947, 0.21528, 1.41961, 1.59125, -0.21777, 0.56455, 0.83702, 1.2306, 0.51277)
All <- rep(1, 20)
d <- as.data.frame(cbind(Gender, Gaming_freq, color_white, color_black_red, color_black_blue, Controller_none, Controller_white, Controller_red, All))
library(shiny)
library(shinythemes)
library(shinydashboard)
ui <- fluidPage(theme = shinytheme("sandstone"),
dashboardPage(skin = "red",
header = dashboardHeader(title = "Dashboard of Survey Results"),
sidebar = dashboardSidebar(
sidebarMenu(
menuItem("Overview", tabName = "overview", icon = icon("dashboard")),
menuItem("Utilities", icon = icon("th"), tabName = "utilities"),
menuItem("Importances", icon = icon("th"), tabName = "importances")
)
),
body = dashboardBody(tabItems(
tabItem(tabName = "utilities",
h2("Utilities of attribute levels"),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("Color", DT::dataTableOutput("mytable1")),
tabPanel("Extra Controller", DT::dataTableOutput("mytable2"))
)
)),
tabItem(tabName = "importances",
h2("Importance for attributes")
))))
)
server <- function(input, output) {
output$mytable1 <- DT::renderDataTable({
DT::datatable(round(d[,3:5], digits = 3), options = list(lengthMenu = c(5, 30, 50, 90), pageLength = 10, bFilter=0))
})
output$mytable2 <- DT::renderDataTable({
DT::datatable(round(d[,6:8], digits = 3),options = list(lengthMenu = c(5, 30, 50, 90), pageLength = 10, bFilter=0))
})
}
shinyApp(ui = ui, server = server)
Thanks in advance.

You can filter your data and wrap it in a reactive element, so you can later use it for any subsequent output plots/tables. You can read more about working with reactive expressions on Rstudio website.
Here as a demo, I get an input on the 'Gender', for further filtering the data out (I've used radio buttons but you can use your widget of choice: slider, select button, etc.)
radioButtons("gender", "filter for gender",
choices = c("One" = '1',
"Two" = '2')),
Then in the server, I use this input to filter the data based on the gender, and wrap it up in a reactive element:
filteredData <- reactive({
tempDataTable <- d %>% dplyr::filter(Gender==input$gender)
tempDataTable
})
Next you can use this reactive element containing your filtered data for generating output tables:
output$mytable1 <- DT::renderDataTable({
d <- filteredData()
DT::datatable(round(d[,3:5], digits = 3), options = list(lengthMenu = c(5, 30, 50, 90), pageLength = 10, bFilter=0))
})
You can use similar strategy to add additional filters or features, find the entire demo ui+server code here:
library(shiny)
library(shinythemes)
library(shinydashboard)
library(tidyverse)
library(DT)
ui <- fluidPage(theme = shinytheme("sandstone"),
dashboardPage(skin = "red",
header = dashboardHeader(title = "Dashboard of Survey Results"),
sidebar = dashboardSidebar(
sidebarMenu(
menuItem("Overview", tabName = "overview", icon = icon("dashboard")),
menuItem("Utilities", icon = icon("th"), tabName = "utilities"),
menuItem("Importances", icon = icon("th"), tabName = "importances")
)
),
body = dashboardBody(tabItems(
tabItem(tabName = "utilities",
h2("Utilities of attribute levels"),
mainPanel(
radioButtons("gender", "filter for gender",
choices = c("One" = '1',
"Two" = '2')),
tabsetPanel(
id = 'dataset',
tabPanel("Color", DT::dataTableOutput("mytable1")),
tabPanel("Extra Controller", DT::dataTableOutput("mytable2"))
)
)),
tabItem(tabName = "importances",
h2("Importance for attributes")
))))
)
server <- function(input, output) {
filteredData <- reactive({
tempDataTable <- d %>% dplyr::filter(Gender==input$gender)
tempDataTable
})
output$mytable1 <- DT::renderDataTable({
d <- filteredData()
DT::datatable(round(d[,3:5], digits = 3), options = list(lengthMenu = c(5, 30, 50, 90), pageLength = 10, bFilter=0))
})
output$mytable2 <- DT::renderDataTable({
d <- filteredData()
DT::datatable(round(d[,6:8], digits = 3),options = list(lengthMenu = c(5, 30, 50, 90), pageLength = 10, bFilter=0))
})
}
shinyApp(ui = ui, server = server)

Related

R Shiny - uiOutput causes numericInput to deselect when user is still typing in

I'm trying to create a data collection tool on R Shiny where the user can select as many categories as apply to them and then enter values for each. I've used uiOutput to allow the user to add a new category choice after clicking an action button.
For some reason, the numericInput that is created after clicking the action button will deselect after a split-second when the user is typing in a number, so it only catches one digit and you have to click it repeatedly to type in a full number.
I've tried changing the numericInput to a textInput and the same thing happens, so it's something to do with how I'm generating the uiOutput in the server, does it continually refresh and is there any way to stop it?
Example code given below, click on the new row button then try typing in the numericInput and you'll see. I have been stuck on this for ages and can't find any other questions similar so any help massively appreciated, thanks
library(tidyverse)
library(shiny)
library(shinyjs)
ui <- fluidPage(
fluidRow(wellPanel(h3("Category and quantity input"))),
wellPanel(fluidRow(column(width=4,selectInput("type0",label = h4("type"), choices= list("choice1" = 1,"choice2" = 2, "choice3"=3))),
column(width=4,numericInput("quantity0", label = h4("quantity"), value = 0, min=0)),
column(width=4,actionButton("New_row",label="Add new row"))),
uiOutput("new_row_added")
))
server <- function(input, output) {
ids <<- NULL
observeEvent(input$New_row,{
if (is.null(ids)){
ids <<- 1
}else{
ids <<- c(ids, max(ids)+1)
}
output$new_row_added <- renderUI({
tagList(
lapply(1:length(ids),function(i){
check_input_type <- paste0("type", ids[i])
check_input_quantity <- paste0("quantity", ids[i])
if(is.null(input[[check_input_type]])){
# Create a div that contains 3 new sub divs
div(fluidRow(column(width=4,
div(selectInput(paste0("type",ids[i]),label = "", choices= list("choice1" = 1,"choice2" = 2, "choice3"=3)))),
column(width=4,div(numericInput(paste0("quantity",ids[i]), label = "", value = 00, min=0))))
)
} else {
# Create a div that contains 3 existing sub divs
div(fluidRow(column(width=4,
div(selectInput(paste0("type",ids[i]),label = "", choices= list("choice1" = 1,"choice2" = 2, "choice3"=3), selected = input[[check_input_type]]))),
column(width=4,div(numericInput(paste0("quantity",ids[i]), label = "", min=0, value = input[[check_input_quantity]]))))
)
}
})
)
})
})
}
shinyApp(ui = ui, server = server)
You need to isolate input[[check_input_type]]. By doing isolate(input[[check_input_type]]). If not, every time a new number is inserted inside that input, the ui will re render and cause the deselection.
App:
library(tidyverse)
library(shiny)
library(shinyjs)
ui <- fluidPage(
fluidRow(wellPanel(h3("Category and quantity input"))),
wellPanel(
fluidRow(
column(width = 4, selectInput("type0", label = h4("type"), choices = list("choice1" = 1, "choice2" = 2, "choice3" = 3))),
column(width = 4, numericInput("quantity0", label = h4("quantity"), value = 0, min = 0)),
column(width = 4, actionButton("New_row", label = "Add new row"))
),
uiOutput("new_row_added")
)
)
server <- function(input, output) {
ids <<- NULL
observeEvent(input$New_row, {
if (is.null(ids)) {
ids <<- 1
} else {
ids <<- c(ids, max(ids) + 1)
}
output$new_row_added <- renderUI({
tagList(
lapply(1:length(ids), function(i) {
check_input_type <- paste0("type", ids[i])
check_input_quantity <- paste0("quantity", ids[i])
if (is.null(isolate(input[[check_input_type]]))) {
# Create a div that contains 3 new sub divs
div(fluidRow(
column(
width = 4,
div(selectInput(paste0("type", ids[i]), label = "", choices = list("choice1" = 1, "choice2" = 2, "choice3" = 3)))
),
column(width = 4, div(numericInput(paste0("quantity", ids[i]), label = "", value = 00, min = 0)))
))
} else {
# Create a div that contains 3 existing sub divs
div(fluidRow(
column(
width = 4,
div(selectInput(paste0("type", ids[i]), label = "", choices = list("choice1" = 1, "choice2" = 2, "choice3" = 3), selected = isolate(input[[check_input_type]])))
),
column(width = 4, div(numericInput(paste0("quantity", ids[i]), label = "", min = 0, value = input[[check_input_quantity]])))
))
}
})
)
})
})
}
shinyApp(ui = ui, server = server)

How can I plot the model output in shiny

This is the output, that I would like to plot with shiny.
<constr <- c(+4,-3,-2,-5)
# Uhlig rejection
model1s <- uhlig.reject(Y=uhligdata, nlags=12, draws=200, subdraws=200, nkeep=100, KMIN=1,
KMAX=5, constrained = constr, constant=FALSE, steps=60)
irf1s <- model1s$IRFS
irfplot(irf1s)
# Uhlig penalty
model1d <- uhlig.penalty(Y=uhligdata, nlags=12, draws=200, subdraws=1000,nkeep=100, KMIN=1, KMAX=5, constrained=constr,
constant=FALSE, steps=60, penalty=100, crit=0.001)
irf1d <- model1d$IRFS
irfplot(irf1d)>
and below is my attemp. I am trying to have the test, lags and periods dynamic and based on them to have the IRFs plotted.
ui <- dashboardPage(
dashboardHeader(title = "НАЧАЛО"),
dashboardSidebar(
sidebarMenu(
menuItem("BVAR",
tabName = "test_tab",
icon = icon("dashboard"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "test_tab",
box(column(10,
radioButtons("test1",
label = "Изберете тест",
choices = c("Uhlig rejection", "Uhlig penalty")),
numericInput("nlags", "NLAGS", min = 1, max = 20, value = 1, step = 1),
numericInput("kmin", "KMIN", min = 1, max = 10, value = 1, step = 1),
numericInput("kmax", "KMAX", min = 2, max = 10, value = 2, step = 1),
submitButton("Submit"))),
box(column(12,
plotOutput("plot2",8))),)
)
))
server <- function(input, output){
modelselect <- reactive({
if(input$test1 == "Uhlig Rejection"){
fit <- uhlig.reject(uhligdata, nlags = input$nlags,constrained = constr, KMIN = input$kmin, KMAX = input$kmax)
return(fit)
}else
if(input$test1 == "Uhlig Penalty"){
fit <- uhlig.penalty(uhligdata,nlags = input$nlags, KMIN = input$kmin, KMAX = input$kmax)
return(fit)
}
})
myplot1 <- reactive({
if(input$test1 == "Uhlig Rejection"){
irfs <- modelselect()$IRFS
irfs} else
if(input$test1 == "Uglig Penalty"){
irfs <-modelselect()$IRFS
irfs}
})
output$plot2 <- renderPlot({
irfplot(myplot1())
})
}
shinyApp(ui = ui, server = server)
The dashboard loads fine but I cannot access the IRF plot. I wonder if the problem is with the reactive function or I do not access the model output correctly(I am quite a newbie to shiny)?

Radio button with radar plot shiny

I'm trying to make a shiny dashboard with attributes of superheros graphed in a radar plot. I'd also like to be able to use radio buttons to select which of the superheros I'd like to see in the graph. However, when I run this code, I get an error that says: Error in polygon: invalid value specified for graphical parameter "lwd". There is no lwd command that I'm aware of for radar charts so I'm not sure how to correct this. Does anyone have a suggestion on how to handle this error?
library(fmsb)
data<-data.frame(Strength = c(7, 0, 6, 7, 4, 3),
Speed = c(7, 0 , 5, 7, 3, 2),
Intelligence = c(7, 0, 6, 2, 4, 3),
Fighting_Skills = c(7, 0, 4, 4, 4, 6),
Energy = c(7, 0, 6, 6, 1, 1),
Durability = c(7, 0, 6, 6, 3, 3),
row.names = c("max", "min", "Iron Man", "Thor", "Spiderman", "Captain America"))
head(data)
colors_fill<-c(scales::alpha("gray", 0.1))
#scales::alpha("gold", 0.1),
#scales::alpha("tomato", 0.2),
#scales::alpha("skyblue", 0.2))
colors_line<-c(scales::alpha("darkgray", 0.9))
#scales::alpha("gold", 0.9),
#scales::alpha("tomato", 0.9),
#scales::alpha("royalblue", 0.9))
#radarchart(data,
#seg =7,
#title = "Radar Chart",
#pcol = colors_line,
#pfcol = colors_fill,
#plwd = 1)
#legend(x = 0.6,
#y=1.35,
#legend = rownames(data[-c(1,2),]),
# bty = "n", pch = 20, col = colors_line, cex = 1.2, pt.cex = 3)
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Radar chart"),
# Sidebar with a radio buttons for person
sidebarLayout(
sidebarPanel(
radioButtons("variablechoice", "People Choice",
choices = c("Iron Man", "Thor", "Spiderman", "Captain America"),
selected = "Thor")
),
# Show a plot
mainPanel(
plotOutput("radar")
)
)
)
# Define server logic required to draw a radar plot
server <- function(input, output) {
output$radar <- renderPlot({
if( input$variablechoice=="Iron Man"){new<-data[c(3),] }
if( input$variablechoice=="Thor"){new<-data[c(4),] }
if( input$variablechoice=="Spiderman"){new<-data[c(5),] }
if( input$variablechoice=="Captain America"){new<-data[c(6),] }
radarchart(new,
seg = 7,
#title = "Radar Chart",
pcol = colors_line,
pfcol = colors_fill,
plwd = 0.5)
})
}
# Run the application
shinyApp(ui = ui, server = server)
The issue is that you have missed to include the first two rows of your data which contain the min and max values for the categories in your new dataframe. That's why radarchart throws an error:
library(fmsb)
library(shiny)
data <- data.frame(
Strength = c(7, 0, 6, 7, 4, 3),
Speed = c(7, 0, 5, 7, 3, 2),
Intelligence = c(7, 0, 6, 2, 4, 3),
Fighting_Skills = c(7, 0, 4, 4, 4, 6),
Energy = c(7, 0, 6, 6, 1, 1),
Durability = c(7, 0, 6, 6, 3, 3),
row.names = c("max", "min", "Iron Man", "Thor", "Spiderman", "Captain America")
)
colors_fill <- c(scales::alpha("gray", 0.1))
colors_line <- c(scales::alpha("darkgray", 0.9))
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Radar chart"),
# Sidebar with a radio buttons for person
sidebarLayout(
sidebarPanel(
radioButtons("variablechoice", "People Choice",
choices = c("Iron Man", "Thor", "Spiderman", "Captain America"),
selected = "Thor"
)
),
# Show a plot
mainPanel(
plotOutput("radar")
)
)
)
# Define server logic required to draw a radar plot
server <- function(input, output) {
output$radar <- renderPlot({
if (input$variablechoice == "Iron Man") {
new <- data[c(1:2, 3), ]
}
if (input$variablechoice == "Thor") {
new <- data[c(1:2, 4), ]
}
if (input$variablechoice == "Spiderman") {
new <- data[c(1:2, 5), ]
}
if (input$variablechoice == "Captain America") {
new <- data[c(1:2, 6), ]
}
radarchart(new,
seg = 7,
# title = "Radar Chart",
pcol = colors_line,
pfcol = colors_fill,
plwd = 0.5
)
})
}
# Run the application
shinyApp(ui = ui, server = server)

Is there a way to track user activity on the shiny application

Below is the shiny application. Is there a way to track how the user interacts with the application, for example, from three inputs there,
what all he selects
Can we capture point 1 in a table
To be very specific, the user selects below combinations, so I need to capture this in a table . Is this possible?
if (interactive()) {
# Classic Iris clustering with Shiny
ui <- fluidPage(
headerPanel("Iris k-means clustering"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "xcol",
label = "X Variable",
choices = names(iris)
),
selectInput(
inputId = "ycol",
label = "Y Variable",
choices = names(iris),
selected = names(iris)[[2]]
),
numericInput(
inputId = "clusters",
label = "Cluster count",
value = 3,
min = 1,
max = 9
)
),
mainPanel(
plotOutput("plot1")
)
)
)
server <- function(input, output, session) {
# classic server logic
selectedData <- reactive({
iris[, c(input$xcol, input$ycol)]
})
clusters <- reactive({
kmeans(selectedData(), input$clusters)
})
output$plot1 <- renderPlot({
palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
"#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))
par(mar = c(5.1, 4.1, 0, 1))
plot(selectedData(),
col = clusters()$cluster,
pch = 20, cex = 3)
points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
})
}
shinyApp(ui, server)
}

Column headers of Shiny data table gets shifted

When I run my Shiny app, the headers of my data tables get shifted to the left. See below.Say this table is on Tab A.
The headers get aligned correctly when I click on a different tab (Tab B),then click on Tab A again. See below for the corrected headers.
Any idea what's causing it? Below is a simplified version of my code. Thanks in advance!
ui.R
library("shinythemes")
fluidPage(title = "Segmentation App", theme = shinytheme("spacelab"),
navbarPage("Segmentation", id = "allResults",
tabPanel(value='result_scorecard', title='ScoreCard',
sidebarLayout(
sidebarPanel(
h4("Select a cluster solution to profile"),
width = 3
),
mainPanel(
verticalLayout(
helpText(strong('Summary of Cluster Solutions')),
column(DT::dataTableOutput('out_best'), width = 12),
helpText(strong('ScoreCard Table')),
column(DT::dataTableOutput('out_scorecard'), width = 12)
)
)
)
),
tabPanel(value='profile', title='Profile',
verticalLayout(
column(DT::dataTableOutput('prop_by_cluster_ind'), width=10)
)
)
)
)
server.R
function(input, output, session) {
best_sols <- reactive({
A <- c(100, 101, 201)
B <- c(100, 101, 201)
C <- c(100, 101, 201)
temp <- as.matrix(cbind(A, B, C))
colnames(temp) <- c("A", "B", "C")
rownames(temp) <- c("k=1","k=2","k=3")
return(temp)
})
score_seg <- reactive({
A <- c("solution=1","solution=2","solution=3","solution=4","solution=5")
B <- c(100, 101, 201, 333, 444)
C <- c(100, 101, 201, 333, 444)
temp <- data.frame(A, B, C)
colnames(temp) <- c("A", "B", "score_seg")
return(temp)
})
profile_result_ind <- reactive({
A1 <- c("var1","var2","var3","var4","var5")
A2 <- c("var1","var2","var3","var4","var5")
B <- c(100, 101, 201, 333, 444)
C <- c(100, 101, 201, 333, 444)
temp <- data.frame(A1, A2, B, C)
colnames(temp) <- c("","","1","2")
return(temp)
})
# Table 1
output$out_best <- DT::renderDataTable({
DT::datatable(best_sols(), caption = "", rownames = TRUE, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(width = '100px', targets = 1)), paging = FALSE, searching = FALSE), selection='none') %>% formatRound(1:5, 3)
#}
})
# Table 2
output$out_scorecard <- DT::renderDataTable({
DT::datatable(score_seg(), caption = "", rownames = F, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(width = '200px', targets = 1)), paging = FALSE, searching = FALSE), selection='single') %>% formatRound(1:5, 3)
})
# Table 3
output$prop_by_cluster_ind <- DT::renderDataTable({
DT::datatable(profile_result_ind(), class= 'compact stripe', caption = '', rownames = F, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(width = '300px', targets = 1), list(className = 'dt-left', targets="_all")), paging = FALSE, searching = FALSE)) %>% formatStyle(as.character(seq(1:2)))
})
}
I figured it out.
The headers will be aligned correctly if we change the autoWidth option to FALSE.
I had a table with long rownames such as you and had a similar problem with offset column names, but setting autoWidth=FALSE did not solve the problem. I discovered that it was being caused by scrollX=TRUE. I changed ScrollX=FALSE and wrapped the datatable in a div with overflow-x=TRUE to regain the scroll feature:
div(style="overflow-x:auto",renderDataTable({tableName},options=list(scrollX=FALSE))