Displaying a vector of values wrapping at screen width [Shiny] - html

I have a vector of values and each value is associated with a name; length of vector changes as per the user input. Although I used table related commands, I like to know other ways to display this kind of data, which is essentially a vector (a single row) of values with names). The problem shows up when selected sample size produces the output that is greater than screen width. Scrolling horizontally allows flexibility to glance over the data, but I am looking for a solution that wraps up the data at the screen width and prints in multiple rows without the need to scroll. Here is the code to play:
ui <- fluidPage(
tabPanel("Test",
numericInput("samsize","specify sample size",4,1,52),
tableOutput('table')
))
server <- function(input, output) {
data <- reactive({
# create a vector of lower- and upper- case alphabets
# create a vector assigning numbers to alphabets
alphabets <- c(letters,LETTERS)
Index <- seq(1,length(alphabets),1)
names(Index) <- alphabets
# sample values
SampleIndex <- sample(Index,input$samsize)
# convert it into a matrix
data <- matrix(SampleIndex,nrow=1)
colnames(data)=names(SampleIndex)
data
})
output$table <- renderTable(data(),digits = 0)
}
shinyApp(ui, server)
As you see in the below picture, for a sample size '36' one need to scroll the page horizontally to see all the values. width in renderTable did not offer any solution Converting data into a html object/text might be one option, but not sure how to retain the names.

You can use renderUI together with uiOutput to create yourself the HTML object you want to display for example using div:
library(shiny)
ui <- fluidPage(
tabPanel("Test",
numericInput("samsize","specify sample size",4,1,52),
uiOutput('myTable')
))
server <- function(input, output) {
data <- reactive({
alphabets <- c(letters,LETTERS)
Index <- seq(1,length(alphabets),1)
names(Index) <- alphabets
# Notice I don't put the vector in a one row matrix as in you example
sample(Index,input$samsize)
})
library(purrr) # map is a nice alternative to lapply
output$myTable <- renderUI(map(names(data()),~div(strong(.),
div(data()[.]),
style="float:left;padding:10px 20px;")))
}
shinyApp(ui, server)

Related

Build a workflow in R shiny

Hope all are safe there :slight_smile:
In the below simple application (rather my question should hold for all applications as well), is there a way to build workflow, so that we can get to know about the application well. For example
In this app,
In terms of UI.R
1) There is 1 actionbutton (So can we list the number of action buttons in the app, along with there ID's)
2) There is 1 dataTableoutput (So can we list the number of dataTableoutput in the app, along with there ID's)
So in general, can we list the number of inputs and there type(actionbutton, radiobutton etc)
Interms of Server.R
3) Can we show that dataTableOutput("Test") is dependent on actionButton("plot"). I mean can we extract a list of outputs that is dependent on observerEvents?
So basically, just by running the small chunk of code, the user should know that this output(test) is dependent on observeEvent(plot).?
library(shiny)
library(dplyr)
library(shinycssloaders)
library(DT)
ui <- fluidPage(
actionButton("plot","plot"),
dataTableOutput("Test")
)
server <- function(input, output, session) {
observeEvent(input$plot, {
output$Test <- DT::renderDT(DT::datatable(head(iris),
rownames = FALSE, options = list(dom = 't',
ordering=FALSE)))
})
}
shinyApp(ui = ui, server = server)

How to get descriptive table for both continuous and categorical variables?

I want to get descriptive table in html format for all variables that are in data frame. I need for continuous variables mean and standard deviation. For categorical variables frequency (absolute count) of each category and percentage of each category. Also I need the count of missing values to be included.
Lets use this data:
data("ToothGrowth")
df<-ToothGrowth
df$len[2]<-NA
df$supp[5]<-NA
I want to get table in html format that will look like this:
----------------------------------------------------------------------
Variables N (missing) Mean (SD) / %
----------------------------------------------------------------------
len 59 (1) 18.9 (7.65)
supp
OJ 30 50%
VC 29 48.33%
NA 1 1.67%
dose 60 1.17 (0.629)
I need also to set the number of digits after decimal point to show.
If you know better variant to display that information in html in better way than please provide your solution.
Here's a programatic way to create separate summary tables for the numeric and factor columns. Note that this doesn't make note of NAs in the table as you requested, but does ignore NAs to calculate summary stats as you did. It's a starting point, anyway. From here you could combine the tables and format the headers however you want.
If you knit this code within an RMarkdown document with HTML output, kable will automatically generate the html table and a css will format the table nicely with a horizontal rules as pictured below. Note that there's also a booktabs option to kable that makes prettier tables like the LaTeX booktabs package. Otherwise, see the documentation for knitr::kable for options.
library(dplyr)
library(tidyr)
library(knitr)
data("ToothGrowth")
df<-ToothGrowth
df$len[2]<-NA
df$supp[5]<-NA
numeric_cols <- dplyr::select_if(df, is.numeric) %>%
gather(key = "variable", value = "value") %>%
group_by(variable) %>%
summarize(count = n(),
mean = mean(value, na.rm = TRUE),
sd = sd(value, na.rm = TRUE))
factor_cols <- dplyr::select_if(df, is.factor) %>%
gather(key = "variable", value = "value") %>%
group_by(variable, value) %>%
summarize(count = n()) %>%
mutate(p = count / sum(count, na.rm = TRUE))
knitr::kable(numeric_cols)
knitr::kable(factor_cols)
I found r package table1 that does what I want. Here is a code:
library(table1)
data("ToothGrowth")
df<-ToothGrowth
df$len[2]<-NA
df$supp[5]<-NA
table1(reformulate(colnames(df)), data=df)

Get column name in apply function

I am trying to make a function that makes a small report for every column in a data frame by using apply. In the report I want to use the name of the column so I have to 'extract' it somehow and that is what my question is about. How do I get the name of the column in my apply function?
Here is a simple example where I want to use the name of the column in the graph title: (for now I just hardcoded the name as 'x')
x <- c(1,1,2,2,2,3)
y <- c(2,3,4,5,4,4)
Tb <- data.frame(x,y)
Dq_Hist <- function(Tab){
Name <- 'x'
Ttl <- paste('Variable: ',Name,'')
hist(Tab,main=Ttl,col=c('grey'),xlab=Name)
}
D <- apply(Tb,MARGIN=2,FUN=Dq_Hist)
Well, if nobody answers you got to find out yourself... And I found out that you can call sapply with an index list and use this index in the function. So the solution is:
x <- c(1,1,2,2,2,3)
y <- c(2,3,4,5,4,4)
Tb <- data.frame(x,y)
Dq_Hist <- function(i){
Name <- colnames(Tb)[i]
Ttl <- paste('Variable: ',Name,'')
hist(Tb[,i],main=Ttl,col=c('grey'),xlab=Name)
}
D <- sapply(1:ncol(Tb),Dq_Hist)

display of text in a new line below the uioutput display [Shiny]

uiOutput('myTable') followed by p("Here is some text....") puts the text next to uioutput display, but I like to print the text in a new line starting from left side of the page. Adding br() is simply adding empty space equivalent to screen width, therefore, text starts from a new line but not from from the left side of the page. Interestingly, adding any control widget, e.g., dateInput displays the widget in a new line. In my case, uioutput input comes from map [ package purrr]. I combined map output and HTML("<br>") via list, but no solution. Here is reproducible code:
library(shiny)
ui <- fluidPage(
tabPanel("Test",
numericInput("samsize","specify sample size",4,1,52),
uiOutput('myTable'),
#dateInput("date", label = "Today's Date")
#br(""),
p("Here is some text...")
))
server <- function(input, output) {
data <- reactive({
alphabets <- c(letters,LETTERS)
Index <- seq(1,length(alphabets),1)
names(Index) <- alphabets
# Notice I don't put the vector in a one row matrix as in you example
sample(Index,input$samsize)
})
library(purrr) # map is a nice alternative to lapply
output$myTable <- renderUI(map(names(data()),~div(strong(.),
div(data()[.]),
style="float:left;padding:10px 20px;")))
}
shinyApp(ui, server)
Here is screen shot. As it is seen, Here is some text is next to uioutput display, which I want to be in a new line below the display
After using div with style float:left, you need to clear the floating, for example with clear:left:
ui <- fluidPage(
tabPanel("Test",
numericInput("samsize","specify sample size",4,1,52),
uiOutput('myTable'),
div("Here is some text...", style="clear:left;"),
dateInput("date", label = "Today's Date")
))
You will find more info about floating div here

Removing multiple elements with removeUI / wrapping multiple elements with tags$div() assigning an id for each variable

I was suggested using insertUI here and found that it is a great feature. The following code allows to generate control widgets for a single or multiple elements using insertUI, but struck on incorporating removeUI related part. Tried jQuery options to remove inserted UI elements but did not work out. I found the following from Shiny dynamic UI, i.e., Note that, if you are inserting multiple elements in one call, you must wrap them in either a tagList() or a tags$div() (the latter option has the advantage that you can give it an id to make it easier to reference or remove it later on). Also, comments here gave some clues, i.e., tags$div(id="sepal.width.div", sliderInput("sepal.width.slider", ...)), but my lack of HTML/CSS knowledge stops me going forward. I'm looking at (a) wrapping multiple widget element(s) with tags$div() assigning a unique id for each variable, which will be used in removeUI; (b) calling multiple elements via removeUI.
varnames <- names(iris[,1:4]) # names
varinit <- apply(iris[,1:4],2,median) # initival value used in slider
varmin <- apply(iris[,1:4],2,min) # min.
varmax <- apply(iris[,1:4],2,max) # max.
ListofSelVars <<- vector(mode="character")
# control widgets for all elements
allControls <- lapply(setNames(varnames, varnames), function(x) {
sliderInput(x, x, varmin[x], varmax[x], c(varmin[x], varinit[x]),
round = -2)
})
ui <- navbarPage(
tabPanel("Plot",
sidebarLayout(
sidebarPanel(
checkboxGroupInput("ConditioningVariables", "Conditioning variables (choose one or more):",
varnames,inline = TRUE),
# add an action button
actionButton("add", "Update UI elements")
),
mainPanel()
)
)
)
server <- function(input, output, session) {
observeEvent(input$add, {
insertUI(
selector ='#add',
where = "afterEnd",
ui = allControls[setdiff(input$ConditioningVariables,ListofSelVars)]
)
## removeUI related goes, here
## removeUI(selector=paste0())
## setdiff(ListofSelVars,input$ConditioningVariables) gives elements to be removed
## Global variable, keep track of elements that are selected
ListofSelVars <<- input$ConditioningVariables
})
}
shinyApp(ui, server)
Here is the working code. The main issue is with the names here, i.e. Sepal.Width. I wrapped each slider with a div with id like div.Sepal.Width so that it is easier to remove. removeUI requires a jQuery selector, so it appears that something like #div.Sepal.Width would work, except that it does not, because . is itself a jQuery selector that means class, so we need to double escape the .. Of course you can also remove the . when you first create the divs, thus avoiding the trouble...
varnames <- names(iris[,1:4]) # names
varinit <- apply(iris[,1:4],2,median) # initival value used in slider
varmin <- apply(iris[,1:4],2,min) # min.
varmax <- apply(iris[,1:4],2,max) # max.
ListofSelVars <<- vector(mode="character")
# control widgets for all elements
allControls <- lapply(setNames(varnames, varnames), function(x) {
tags$div(id=paste0("div.",x), sliderInput(x, x, varmin[x], varmax[x], c(varmin[x], varinit[x]),
round = -2))
})
ui <- fluidPage(
titlePanel("Dynamic sliders"),
sidebarLayout(
sidebarPanel(
checkboxGroupInput("ConditioningVariables", "Conditioning variables (choose one or more):",
varnames,inline = TRUE),
# add an action button
actionButton("add", "Update UI elements")
),
mainPanel(
uiOutput("plot_out")
)
)
)
server <- function(input, output, session) {
observeEvent(input$add, {
insertUI(
selector ='#add',
where = "afterEnd",
ui = allControls[setdiff(input$ConditioningVariables,ListofSelVars)]
)
ListofRemoval <- setdiff(ListofSelVars,input$ConditioningVariables)
for (item in ListofRemoval) {
item = gsub(".", "\\.", item, fixed=TRUE)
item = paste0("#div\\.", item)
removeUI(item)
}
ListofSelVars <<- input$ConditioningVariables
})
}
shinyApp(ui, server)