I am having a hard time figuring out the code to position the search box from a DT table in a Shiny app to the middle. I'm using a DT extension package, called DTedit, to create my table. Here is some example code:
library(shiny)
library(DTedit)
##### Create the shiny UI
ui <- fluidPage(
h3('DTedit Template'),
uiOutput('mycontacts')
)
##### Create the Shiny server
server <- function(input, output) {
mydata <- data.frame(name = character(),
email = character(),
useR = factor(levels = c('Yes', 'No')),
notes = character(),
stringsAsFactors = FALSE)
##### Callback functions.
my.insert.callback <- function(data, row) {
mydata <- rbind(data, mydata)
return(mydata)
}
my.update.callback <- function(data, olddata, row) {
mydata <- olddata
mydata[row, ] <- data[row, ]
return(mydata)
}
my.delete.callback <- function(data, row) {
mydata <- mydata[-row,]
return(mydata)
}
##### Create the DTedit object
DTedit::dtedit(input, output,
name = 'mycontacts',
thedata = mydata,
edit.cols = c('name', 'email', 'useR', 'notes'),
edit.label.cols = c('Name', 'Email Address', 'Are they an R user?', 'Additional notes'),
input.types = c(notes='textAreaInput'),
view.cols = c('name', 'email', 'useR'),
callback.update = my.update.callback,
callback.delete = my.delete.callback,
show.insert = FALSE,
show.copy = FALSE)
}
##### Start the shiny app
shinyApp(ui = ui, server = server)
Based on googling, I found this CSS to align the search box to the center:
div.dataTables_wrapper div.dataTables_filter {
width: 100%;
float: none;
text-align: center;
}
However, I'm not sure how to insert this CSS into the table. dtedit() has datatable.options parameter, so I think I'd have to use this parameter somehow.
Any help would be greatly appreciated!
Yes, the CSS you found works. Here is how to include it:
css <- "
div.dataTables_wrapper div.dataTables_filter {
width: 100%;
float: none;
text-align: center;
}
"
ui <- fluidPage(
tags$head(
tags$style(HTML(css))
),
......
The box is centered but only in the available space, so it is not "globally" centered because of the "Show" item:
If you want to remove the "Show" item, you can use the option dom = "frtip". Or if you want to keep it but globally center the search box, use this CSS instead:
css <- "
div.dataTables_wrapper div.dataTables_filter {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
"
Related
The code at the bottom works as desired except for widget alignment, as illustrated below. Any recommendations for how to align all widgets together in-line (except for the necessary wrapping which is working fine in the code) as illustrated and described below? In the illustration, the red describes what I'd like to change, and the black are just some casual observations.
Code:
library(rhandsontable)
library(shiny)
rowNames1 <- c("A", "B", "C", "Sum")
data1 <- data.frame(row.names = rowNames1, "Col 1" = c(1, 1, 0, 2), check.names = FALSE)
ui <- fluidPage(
actionButton("addTbl", "Add table"),
rHandsontableOutput("hottable1"),
tags$div(id = "placeholder")
)
server <- function(input, output) {
uiTbl1 <- reactiveValues(base = data1)
observeEvent(input$hottable1,{uiTbl1$base <- hot_to_r(input$hottable1)})
output$hottable1 <- renderRHandsontable({
rhandsontable(uiTbl1$base, rowHeaderWidth = 100, useTypes = TRUE)
})
observeEvent(input$addTbl, {
divID <- gsub("\\.", "", format(Sys.time(), "%H%M%OS3"))
dtID <- paste0(divID, "DT")
uiTbl1[[paste0(divID,"tbl")]] <- data1
insertUI(
selector = "#placeholder",
ui = tags$div(
id = divID,
style = "display:inline-block;
margin-right: 10px;
margin-top: 10px;
vertical-align: top;",
rHandsontableOutput(dtID),
hr()
)
)
output[[dtID]] <- renderRHandsontable({
req(uiTbl1[[paste0(divID,"tbl")]])
rhandsontable(uiTbl1[[paste0(divID,"tbl")]], rowHeaderWidth = 100, useTypes = TRUE)
})
})
}
shinyApp(ui, server)
Reflecting S. Laurent's solution in the comments, below is complete code including alignment parameters for super-clean output of multiple dynamic tables:
Code:
library(rhandsontable)
library(shiny)
rowNames1 <- c("A", "B", "C", "Sum")
data1 <- data.frame(row.names = rowNames1, "Col 1" = c(1, 1, 0, 2), check.names = FALSE)
ui <- fluidPage(
br(), actionButton("addTbl", "Add table"),
tags$div(id = "placeholder",
tags$div(
style = "display: inline-block;
margin-right: 6px;
margin-top: 10px;
vertical-align: top;",
rHandsontableOutput("hottable1")
)
)
)
server <- function(input, output) {
uiTbl1 <- reactiveValues(base = data1)
observeEvent(input$hottable1,{uiTbl1$base <- hot_to_r(input$hottable1)})
output$hottable1 <- renderRHandsontable({
rhandsontable(uiTbl1$base,rowHeaderWidth = 100, useTypes = TRUE)
})
observeEvent(input$addTbl, {
divID <- gsub("\\.", "", format(Sys.time(), "%H%M%OS3"))
dtID <- paste0(divID, "DT")
uiTbl1[[paste0(divID,"tbl")]] <- data1
insertUI(
selector = "#placeholder",
ui = tags$div(
id = divID,
style = "display:inline-block;
margin-right: 10px;
margin-top: 10px;
vertical-align: top;",
rHandsontableOutput(dtID)
)
)
output[[dtID]] <- renderRHandsontable({
req(uiTbl1[[paste0(divID,"tbl")]])
rhandsontable(uiTbl1[[paste0(divID,"tbl")]],rowHeaderWidth = 100, useTypes = TRUE)
})
})
}
shinyApp(ui, server)
Illustration of the addition of 10 dynamic tables:
Problem in centering table header in shiny, when centering my table the first column remains aligned to the left. How do I fix this? Just below I made available my CSS code. I'm in doubt as to how to align the first column of my table. I am also in doubt, if I called the CSS correctly in my code.
library(shiny)
library(dplyr)
bd= read.csv("bd.csv", sep = ";")
ui = fluidPage(
fixedRow(
column(12,
titlePanel("Tabelas"),
sidebarLayout(
sidebarPanel(selectInput("TABELA", "Selecione a Tabela:", choices = bd$TABELA),
downloadButton("downloadData", "Download")),
mainPanel(tags$link(
rel='stylesheet',
type='text/css',
href='custom.css'),
(tableOutput("bd")))
)
)
)
)
server = function(input, output) {
output$bd <- renderTable({
bd %>%
dplyr::filter(TABELA == input$TABELA)%>%
dplyr::select(LOCAL, ENTREVISTAS.PRE, ENTREVISTAS.POS, CITACOES.PRE, CITACOES.POS, PERCENT.PRE, PERCENT.POS)
}
)
output$downloadData <- downloadHandler(
filename = function() {
paste("bd-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(bd, file)
}
)
}
shinyApp(ui = ui, server = server)
.table.shiny-table>thead>tr>th,
.table.shiny-table>thead>tr>td,
.table.shiny-table>tbody>tr>th,
.table.shiny-table>tbody>tr>td,
.table.shiny-table>tfoot>tr>th,
.table.shiny-table>tfoot>tr>td {
padding-right: 12px;
padding-left: 12px;
font-size:80%;
text-align: center;
}
.table>caption+thead>tr:first-child>td,
.table>caption+thead>tr:first-child>th,
.table>colgroup+thead>tr:first-child>td,
.table>colgroup+thead>tr:first-child>th,
.table>thead:first-child>tr:first-child>td,
.table>thead:first-child>tr:first-child>th {
border-top: 0;
font-size:80%;
text-align: center;
}
What I like to do to format the table is to use the datatable function from the DT package.
I create a create_dt function with new variables to pass some values, which I use throughout the shiny application. I leave the format that I use in my tables, if you want to use it. There are many options to configure your table here.
create_dt <- function(x,y = NULL,z = NULL,w,v = NULL){
v <- if_else(is.null(v),TRUE,FALSE)
y <- if_else(is.null(y),16,y)
datatable(x,
rownames = FALSE,
class = "compact cell-border",
extensions = 'Buttons',
caption = z,
options = list(dom = 'rtB',
buttons = list(list(extend='excel',
filename = 'Nombre tabla',
text = '<i class="fas fa-download"></i>')),
pageLenght = y,
lengthMenu = list(c(y,25,50,-1),
c(y,25,50,"All")),
scrollX = TRUE,
initComplete = htmlwidgets::JS(
"function(settings, json) {",
"$(this.api().table().header()).css({'background-color': '#000', 'color': '#fff'});","}"),
columnDefs = list(list(className = 'dt-center', targets = '_all'))
),
container = w,
escape = v) %>%
formatStyle(columns = names(x),
color = "black",
fontSize = '8pt')
This is what my table looks like.
example of table
And this is how I apply the function with the data:
And the Ui part:
fluidRow(column(6,withSpinner(dataTableOutput("resume_tbl_entero",height = '100%'))))
The server part:
output$resume_tbl_entero <- renderDataTable(
{create_dt({React_ano_filter_general_entero() %>%
mutate(Resultado = str_to_sentence(Resultado)) %>%
pivot_wider(names_from = Resultado,values_from=Total)},
z = "Enterococcus")}
And the data used looks like this
I hope it serves you greetings!
I am learning how to use images as radiobuttons.
I found this page and have been playing around with it:
Can you have an image as a radioButton choice in shiny?
The answer here has been very useful but the app doesn't load the Rlogo for the radiobutton (when using the second part of the answer using the functions). I have saved the image into a www file. I have tried different variations of writing the line '<img src="Rlogo.png">' = 'logo' like removing the quotations, replacing it with img(src='Rlogo.png') = 'logo' , replace it with the web link, but have been unsuccessful. Please can someone point out where I am going wrong or if the original code works for you!
logo is here: http://i1.wp.com/www.r-bloggers.com/wp-content/uploads/2016/02/Rlogo.png?resize=300%2C263
code is copied over from the page:
library(shiny)
radioButtons_withHTML <- function (inputId, label, choices, selected = NULL, inline = FALSE,
width = NULL)
{
choices <- shiny:::choicesWithNames(choices)
selected <- if (is.null(selected))
choices[[1]]
else {
shiny:::validateSelected(selected, choices, inputId)
}
if (length(selected) > 1)
stop("The 'selected' argument must be of length 1")
options <- generateOptions_withHTML(inputId, choices, selected, inline,
type = "radio")
divClass <- "form-group shiny-input-radiogroup shiny-input-container"
if (inline)
divClass <- paste(divClass, "shiny-input-container-inline")
tags$div(id = inputId, style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"), class = divClass,
shiny:::controlLabel(inputId, label), options)
}
generateOptions_withHTML <- function (inputId, choices, selected, inline, type = "checkbox")
{
options <- mapply(choices, names(choices), FUN = function(value,
name) {
inputTag <- tags$input(type = type, name = inputId, value = value)
if (value %in% selected)
inputTag$attribs$checked <- "checked"
if (inline) {
tags$label(class = paste0(type, "-inline"), inputTag,
tags$span(HTML(name)))
}
else {
tags$div(class = type, tags$label(inputTag, tags$span(HTML(name))))
}
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)
div(class = "shiny-options-group", options)
}
choices <- c('\\( e^{i \\pi} + 1 = 0 \\)' = 'equation',
'<img src="Rlogo.png">' = 'logo')
ui <- shinyUI(fluidPage(
withMathJax(),
img(src='Rlogo.png'),
fluidRow(column(width=12,
radioButtons('test', 'Radio buttons with MathJax choices',
choices = choices, inline = TRUE),
br(),
h3(textOutput('selected'))
))
))
server <- shinyServer(function(input, output) {
output$selected <- renderText({
paste0('You selected the ', input$test)
})
})
shinyApp(ui = ui, server = server)
Here is a way.
library(shiny)
radioImages <- function(inputId, images, values){
radios <- lapply(
seq_along(images),
function(i) {
id <- paste0(inputId, i)
tagList(
tags$input(
type = "radio",
name = inputId,
id = id,
class = "input-hidden",
value = as.character(values[i])
),
tags$label(
`for` = id,
tags$img(
src = images[i]
)
)
)
}
)
do.call(
function(...) div(..., class = "shiny-input-radiogroup", id = inputId),
radios
)
}
css <- HTML(
".input-hidden {",
" position: absolute;",
" left: -9999px;",
"}",
"input[type=radio] + label>img {",
" width: 50px;",
" height: 50px;",
" transition: 500ms all;",
"}",
"input[type=radio]:checked + label>img {",
" border: 1px solid #fff;",
" box-shadow: 0 0 3px 3px #090;",
" transform: rotateZ(-10deg) rotateX(10deg);",
"}"
)
ui <- fluidPage(
tags$head(tags$style(css)),
br(),
wellPanel(
tags$label("Choose a language:"),
radioImages(
"radio",
images = c("java.svg", "javascript.svg", "julia.svg"),
values = c("java", "javascript", "julia")
)
),
verbatimTextOutput("language")
)
server <- function(input, output, session){
output[["language"]] <- renderPrint({
input[["radio"]]
})
}
shinyApp(ui, server)
Credit.
This will also work:
library(shiny)
library(shinyWidgets)
ui <- shinyUI(fluidPage(
withMathJax(),
tags$head(
tags$link(rel = "stylesheet", type = "text/css", href = "style.css")),
fluidRow(column(width=12,
radioGroupButtons('test', 'Radio buttons with MathJax choices',
choiceNames = c('\\( e^{i \\pi} + 1 = 0 \\)',
'<i class="icon_rlogo"></i>'),
choiceValues = c('equation', 'logo')),
br(),
h3(textOutput('selected'))
))
))
server <- shinyServer(function(input, output) {
output$selected <- renderText({
paste0('You selected the ', input$test)
})
})
shinyApp(ui = ui, server = server)
With in your www folder your Rlogo.png image and a style.css file with:
.icon_rlogo {background: url(Rlogo.png) no-repeat center;
background-size: contain;
display: inline-block;
width: 30px;
height: 20px;}
To be customised as you wish.
please I have a R shiny application and one of the pages have a really big table. For this reason, I would need to have the horizontal scrollbar both at the top as well as the bottom of the table.
Please, bear in mind I'm very little familiar with HTML, CSS and JS.
Also, I already managed to move the horizontal scrollbar to the top of the table using solution:
R DT Horizontal scroll bar at top of the table
I'm literally using the example explained there and it works perfectly. I would just need some help in adding the scrollbar at the bottom as well.
css <- HTML(
"#flipped > .dataTables_wrapper.no-footer > .dataTables_scroll > .dataTables_scrollBody {
transform:rotateX(180deg);
}
#flipped > .dataTables_wrapper.no-footer > .dataTables_scroll > .dataTables_scrollBody table{
transform:rotateX(180deg);
}"
)
ui <- fluidPage(
tags$head(tags$style(css)),
fluidRow(column(width = 6,
h4("Flipped Scrollbar"),
br(),
DT::dataTableOutput("flipped")
),
column(width = 6,
h4("Regular Scrollbar"),
br(),
DT::dataTableOutput("regular")
)
)
)
server <- function(input, output, session) {
output$flipped <- DT::renderDataTable({
DT::datatable(mtcars, rownames = FALSE,
options = list(
scrollX = TRUE
)
)
})
output$regular <- DT::renderDataTable({
DT::datatable(mtcars, rownames = FALSE,
options = list(
scrollX = TRUE
)
)
})
}
shinyApp(ui, server)
I managed to find a similar question (horizontal scrollbar on top and bottom of table) however, I can't understand how to apply that css and JS code to a Shiny application.
Many thanks
Update (that still doesn't work) as a follow-up to Stéphane Laurent suggested solution.
My current code now is:
library(shiny)
library(DT)
wideTable <- as.data.frame(matrix(rnorm(1000), nrow = 10, ncol = 100))
js <- "
$(document).ready(function(){
$('#dtable').on('shiny:value', function(e){
setTimeout(function(){
$('#dtable table').wrap('<div id=\"scrolldiv\"></div>');
$('#scrolldiv').doubleScroll({
contentElement: $('table'),
scrollCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
contentCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
resetOnWindowResize: true
});
setTimeout(function(){$(window).resize();}, 100);
}, 0);
});
});
"
CSS <- "
.doubleScroll-scroll-wrapper {
clear: both;
}
"
ui <- fluidPage(
tags$head(
tags$script(src = "jquery.doubleScroll.js"),
tags$script(HTML(js)),
tags$style(HTML(CSS))
),
br(),
dataTableOutput("dtable")
)
server <- function(input, output, session){
output$dtable <- DT::renderDataTable({
datatable(wideTable,
rownames = T,
filter = 'top',
caption = paste0("All columns of CSV report")
)
})
}
shinyApp(ui, server)
Here is a solution using the DoubleScroll JavaScript library.
Download the file jquery.doubleScroll.js from here. Put it in the www subfolder of your shiny app.
Then here is the app:
library(shiny)
library(DT)
wideTable <- as.data.frame(matrix(rnorm(1000), nrow = 10, ncol = 100))
js <- "
$(document).ready(function(){
$('#dtable').on('shiny:value', function(e){
setTimeout(function(){
$('#dtable table').wrap('<div id=\"scrolldiv\"></div>');
$('#scrolldiv').doubleScroll({
contentElement: $('table'),
scrollCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
contentCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
resetOnWindowResize: true
});
setTimeout(function(){$(window).resize();}, 100);
}, 0);
});
});
"
CSS <- "
.doubleScroll-scroll-wrapper {
clear: both;
}
"
ui <- fluidPage(
tags$head(
tags$script(src = "jquery.doubleScroll.js"),
tags$script(HTML(js)),
tags$style(HTML(CSS))
),
br(),
DTOutput("dtable")
)
server <- function(input, output, session){
output[["dtable"]] <- renderDT({
datatable(wideTable)
})
}
shinyApp(ui, server)
If the output id of your datatable is not "dtable", then in the JS code (js) replace dtable (two occurences) with the output id of your datatable.
I have a simple shiny-app with just a dropdown listing districts of Afghanistan and a leaflet map of the same.
The shape file can be accessed at this link - using AFG_adm2.shp from http://www.gadm.org/download
here's the app code:
library(shiny)
library(leaflet)
library(rgdal)
library(sp)
afg <- readOGR(dsn = "data", layer ="AFG_adm2", verbose = FALSE, stringsAsFactors = FALSE)
ui <- fluidPage(
titlePanel("Test App"),
selectInput("yours", choices = c("",afg$NAME_2), label = "Select Country:"),
actionButton("zoomer","reset zoom"),
leafletOutput("mymap")
)
server <- function(input, output){
initial_lat = 33.93
initial_lng = 67.71
initial_zoom = 5
output$mymap <- renderLeaflet({
leaflet(afg) %>% #addTiles() %>%
addPolylines(stroke=TRUE, color = "#00000", weight = 1)
})
proxy <- leafletProxy("mymap")
observe({
if(input$yours!=""){
#get the selected polygon and extract the label point
selected_polygon <- subset(afg,afg$NAME_2==input$yours)
polygon_labelPt <- selected_polygon#polygons[[1]]#labpt
#remove any previously highlighted polygon
proxy %>% removeShape("highlighted_polygon")
#center the view on the polygon
proxy %>% setView(lng=polygon_labelPt[1],lat=polygon_labelPt[2],zoom=7)
#add a slightly thicker red polygon on top of the selected one
proxy %>% addPolylines(stroke=TRUE, weight = 2,color="red",data=selected_polygon,layerId="highlighted_polygon")
}
})
observeEvent(input$zoomer, {
leafletProxy("mymap") %>% setView(lat = initial_lat, lng = initial_lng, zoom = initial_zoom) %>% removeShape("highlighted_polygon")
})
}
# Run the application
shinyApp(ui = ui, server = server)
EDIT: I'm actually trying to add an action button which resets zoom to a default value (using leafletproxy and setview) and I want to put this button on the top-right corner of the map instead of it being above the map.
Can I use addLayersControl to do this?
EDIT2:
Code in full-app:
# Create the map
output$mymap <- renderLeaflet({
leaflet(afg) %>% addTiles() %>%
addPolygons(fill = TRUE,
fillColor = ~factpal(acdf$WP_2012), #which color for which attribute
stroke = TRUE,
fillOpacity = 1, #how dark/saturation the fill color should be
color = "black", #color of attribute boundaries
weight = 1, #weight of attribute boundaies
smoothFactor = 1,
layerId = aid
#popup = ac_popup
) %>% addPolylines(stroke=TRUE, color = "#000000", weight = 1) %>%
addLegend("bottomleft", pal = factpal, values = ~WP_2012,
title = "Party",
opacity = 1
) %>% setView(lng = initial_lng, lat = initial_lat, zoom = initial_zoom) %>%
addControl(html = actionButton("zoomer1","Reset", icon = icon("arrows-alt")), position = "topright")
})
I can't see the map tiles from addTiles or the zoom reset button from addControl. Any ideas why this might be happening?
You can use the addControl function directly:
output$mymap <- renderLeaflet({
leaflet(afg) %>% #addTiles() %>%
addPolylines(stroke=TRUE, color = "#00000", weight = 1) %>%
addControl(actionButton("zoomer","Reset"),position="topright")
})
You can achieve this by using the shiny absolutePanel() function in your UI, E.g.
library(shiny)
library(leaflet)
library(rgdal)
library(sp)
afg <- readOGR(dsn = "data", layer ="AFG_adm2", verbose = FALSE, stringsAsFactors = FALSE)
ui <- fluidPage(
tags$head(
tags$style(
HTML(
'
.outer {
position: fixed;
top: 80px;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
padding: 0;
}
#controls-filters {
background-color: white;
border:none;
padding: 10px 10px 10px 10px;
z-index:150;
}
'
)
)
),
titlePanel("Test App"),
absolutePanel(
id = "controls-filters",
class = "panel panel-default",
fixed = TRUE,
draggable = TRUE,
top = 100,
left = "auto",
right = 20,
bottom = "auto",
width = 330,
height = "auto",
selectInput("yours", choices = c("", afg$NAME_2), label = "Select Country:"),
actionButton("zoomer", "reset zoom")
),
div(class = "outer", leafletOutput("mymap"))
)
server <- function(input, output){
initial_lat = 33.93
initial_lng = 67.71
initial_zoom = 5
output$mymap <- renderLeaflet({
leaflet(afg) %>% #addTiles() %>%
addPolylines(stroke=TRUE, color = "#00000", weight = 1)
})
proxy <- leafletProxy("mymap")
observe({
if(input$yours!=""){
#get the selected polygon and extract the label point
selected_polygon <- subset(afg,afg$NAME_2==input$yours)
polygon_labelPt <- selected_polygon#polygons[[1]]#labpt
#remove any previously highlighted polygon
proxy %>% removeShape("highlighted_polygon")
#center the view on the polygon
proxy %>% setView(lng=polygon_labelPt[1],lat=polygon_labelPt[2],zoom=7)
#add a slightly thicker red polygon on top of the selected one
proxy %>% addPolylines(stroke=TRUE, weight = 2,color="red",data=selected_polygon,layerId="highlighted_polygon")
}
})
observeEvent(input$zoomer, {
leafletProxy("mymap") %>% setView(lat = initial_lat, lng = initial_lng, zoom = initial_zoom) %>% removeShape("highlighted_polygon")
})
}
# Run the application
shinyApp(ui = ui, server = server)
This should get you started but I would recommend structuring your app in such a way that it has a stand alone CSS file.