I have a tabpanelSet in a shiny application. One of the tabs contains a datatable. Id like the number of rows in the datatable to show in a nice circular icon next to the the tab header text so the user can see see the number in the datatable within the tab before clicking on the tab.
Here is the basic app. Its the 'Details' tab that I would like the circular notification icon library
library(shiny)
library(DT)
library(data.table)
ui <- fluidPage(
# Application title
titlePanel("Circular notification icon app"),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Empty"),
tabPanel("Details",
DT::dataTableOutput("iris"))
)
)
)
server <- function(input, output) {
output$iris = DT::renderDT({
datatable(iris,class = "display wrap",selection = "single",
options = list(
scrollX = TRUE,
scrollY = TRUE,
pageLength = 15,
select = "api",
dom = 'Bfrtip')
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Like this?
library(shiny)
library(DT)
library(shinyjs)
CSS <- "
#tabHeader {
display: inline-block;
}
.circle {
display: inline-block;
width: 25px;
height: 25px;
border-radius: 50%;
font-size: 12px;
color: #fff;
line-height: 25px;
text-align: center;
background: #000
}"
js <- function(nrows){
sprintf("$('#tabHeader .circle').html('%s');", nrows)
}
ui <- fluidPage(
useShinyjs(),
tags$head(
tags$style(HTML(CSS))
),
# Application title
titlePanel("Circular notification icon app"),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Empty"),
tabPanel(div(id = "tabHeader", span("Details"),
div(class = "circle")),
DTOutput("iris"))
)
)
)
server <- function(input, output) {
runjs(js(nrow(iris)))
output$iris = renderDT({
datatable(iris, class = "display wrap", selection = "single",
options = list(
scrollX = TRUE,
scrollY = TRUE,
pageLength = 15,
select = "api",
dom = 'Bfrtip')
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Related
Using a Shiny app, I would like to implement a slider with slickR to switch from one image to the other.
I managed to implement the slider but I'm having trouble in displaying the images correctly because of their different sizes.
In the following example, the stackexchange logo is way bigger than the stackoverflow logo. When displaying them with slickR(), the bigger logo makes inroads into the first one like this:
I would also like to have the size of the pictures relative to the size of the screen.
Here is a reproducible example of the Shiny app used to generate the above image:
library(shiny)
library(slickR)
# User interface ----
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
slickROutput("slickr", width = "auto")
)
)
)
# Server ----
server <- function(input, output) {
imgs_links <- list(
"https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
"https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png")
output$slickr <- renderSlickR({
photo_list <- lapply(imgs_links, function(x){
tags$div(
tags$img(src = x, width = "10%", height = "10%")
)
})
imgs <- do.call(tagList, photo_list)
slickR(imgs)
})
}
# Run the application ----
shinyApp(ui = ui, server = server)
What would be the correct way to have each image resized according the size of the screen?
I don't manage to get it with the 'slickR' package. Here is a solution which doesn't use this package, it uses the 'slick' JavaScript library. You have to download the library files and put them in the www/slick-1.8.1/slick folder.
library(shiny)
ui <- fluidPage(
tags$head(
tags$link(rel="stylesheet", type="text/css",
href="slick-1.8.1/slick/slick-theme.css"),
tags$link(rel="stylesheet", type="text/css",
href="slick-1.8.1/slick/slick.css"),
tags$script(type="text/javascript",
src="slick-1.8.1/slick/slick.js"),
tags$script(HTML(
"$(document).ready(function(){
$('#images').slick({
arrows: true,
dots:true
});
});")),
tags$style(HTML(
"#images .slick-prev {
position:absolute;
top:65px;
left:-50px;
}
#images .slick-next {
position:absolute;
top:95px;
left:-50px;
}
.slick-prev:before, .slick-next:before {
color:red !important;
font-size: 30px;
}
.content {
margin: auto;
padding: 2px;
width: 90%;
}"))
),
sidebarLayout(
sidebarPanel(
####
),
mainPanel(
tags$div(
class = "content",
tags$div(
id = "images",
tags$img(
src = "https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
width = "50vw"
),
tags$img(
src = "https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png",
width = "50vw"
)
)
)
)
)
)
server <- function(input, output) {
}
# Run the application
shinyApp(ui = ui, server = server)
EDIT: dynamic number of images
library(shiny)
ui <- fluidPage(
tags$head(
tags$link(rel="stylesheet", type="text/css",
href="slick-1.8.1/slick/slick-theme.css"),
tags$link(rel="stylesheet", type="text/css",
href="slick-1.8.1/slick/slick.css"),
tags$script(type="text/javascript",
src="slick-1.8.1/slick/slick.js"),
tags$style(HTML(
"#carousel .slick-prev {
position:absolute;
top:65px;
left:-50px;
}
#carousel .slick-next {
position:absolute;
top:95px;
left:-50px;
}
.slick-prev:before, .slick-next:before {
color:red !important;
font-size: 30px;
}
.content {
margin: auto;
padding: 2px;
width: 90%;
}"))
),
sidebarLayout(
sidebarPanel(
checkboxGroupInput(
"images",
"Select images",
choiceNames = c("Stackoverflow", "Stackexchange", "Asymptote"),
choiceValues = c(
"https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
"https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png",
"https://www.clipartmax.com/png/small/203-2038151_asymptote-vector-graphics-language-wikipedia-rh-en-asymptote.png"
)
)
),
mainPanel(
tags$div(
class = "content",
uiOutput("carousel-ui"),
)
)
)
)
server <- function(input, output) {
output[["carousel-ui"]] <- renderUI({
imgs <- lapply(input[["images"]], function(x){
tags$img(src = x, width = "50vw")
})
imgs_div <- do.call(function(...) div(id = "carousel", ...), imgs)
script <- tags$script(HTML(
"$('#carousel').slick({
arrows: true,
dots:true
});"))
do.call(tagList, list(imgs_div, script))
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm finishing up my dashboard atm, and I'm trying to show a tweet on my page. I'm using the tweetrmd package to do this, but it doesn't seem to work
here is part of my UI code
library(tidyverse)
library(shiny)
library(rtweet)
library(tweetrmd)
screenshot <- tweet_screenshot(tweet_url("Metro", "1251153881209307136"))
# UI
list(
ui <- tagList(
includeCSS("style.css"),
navbarPage("#Corona",
windowTitle = "#Corona",
tabPanel("Twitter",
sidebarLayout(
sidebarPanel(
h2("Algemene twitter data", align = "left"),
),
mainPanel(
tabsetPanel(
id = "Tabs",
tabPanel(
title = "Kranten",
h3("Frequentie tweets over corona door populaire kranten", align = "center"),
plotOutput("plot1")%>% withSpinner(color="#dca108"),
div(img(src= screenshot, align = "center"), style="text-align: center;", id= "screenshot"),
), )
)
)
))
)
)
Question is: can I make the tweet_screenshot function work in a shiny app (default is rmarkdown) and how?
If I check out the screenshot object it shows this:
(screenshot <- tweet_screenshot(tweet_url("Metro", "1251153881209307136")))
file://C:\Users\jolien\AppData\Local\Temp\RtmpKeTPxU\file47383c65585c.html screenshot completed
Thanks in advance
A solution using twitframe.com:
library(shiny)
tweet <- "https://twitter.com/Twitter/status/1144673160777912322"
url <- URLencode(tweet, reserved = TRUE)
src <- paste0("https://twitframe.com/show?url=", url)
js <- '
$(window).on("message", function(e) {
var oe = e.originalEvent;
if (oe.origin !== "https://twitframe.com")
return;
if (oe.data.height && oe.data.element.id === "tweet"){
$("#tweet").css("height", parseInt(oe.data.height) + "px");
}
});'
ui <- fluidPage(
fluidRow(
tags$head(
tags$script(HTML(js)),
tags$style(HTML(
"
.content {
margin: auto;
padding: 20px;
width: 60%;
}"))
),
uiOutput("frame")
)
)
server <- function(input, output, session) {
output[["frame"]] <- renderUI({
tagList(
tags$div(
class = "content",
tags$div(tags$iframe(
id = "tweet",
border=0, frameborder=0, height=50, width=550,
src = src
))
),
singleton(tags$script(HTML(
"$(document).ready(function(){
$('iframe#tweet').on('load', function() {
this.contentWindow.postMessage(
{ element: {id:this.id}, query: 'height' },
'https://twitframe.com');
});
});")))
)
})
}
shinyApp(ui, server)
I want to display Last Updated time in the navbar of shiny R. For that I'm storing the last updated time in csv file which I will be using to read in the server.R but I'm unable to figure out how to display that time on the rightmost side of the navbar. Any help would be highly appreciated. Thank You
shinyUI(
navbarPage(
title = 'Welcome',
tabPanel('Overview',
tabsetPanel(
tabPanel('Forward',
fluidRow(
DT::dataTableOutput("view_fwd"),width = 6
)
),
tabPanel('Reverse',
fluidRow(
DT::dataTableOutput("view_rvo"),width = 6
))
))
library(shiny)
ui <- fluidPage(
navbarPage(
title = 'Welcome',
tabPanel('Overview',
tabsetPanel(
tabPanel('Forward',
fluidRow(
DT::dataTableOutput("view_fwd"),width = 6
)
),
tabPanel('Reverse',
fluidRow(
DT::dataTableOutput("view_rvo"),width = 6
))
)),
tabPanel(tags$ul(class='nav navbar-nav',
style = "padding-left: 550px;", htmlOutput("time"))) # here you output time, need to positions on the left side by 550px
)
)
# Define server logic
server <- function(input, output) {
output$time <- renderUI({
as.character(strptime(Sys.time(), "%Y-%m-%d %H:%M:%S", tz = "EET"))
})
}
# Run the application
shinyApp(ui = ui, server = server)
With some css and Javascript you can let the time float to the right and disable click events on that tab. You would need the package shinyjs for it.
library(shiny)
library(shinyjs)
jscode <- '
shinyjs.init = function() {
$(".nav").on("click", ".disabled", function (e) {
e.preventDefault();
return false;
});
}
'
ui <- fluidPage(
tags$head(tags$style(HTML("
.navbar-nav {
float: none;
}
.navbar ul > li:nth-child(2) {
float: right;
}
.navbar ul > li:nth-child(2) {
color: black !important;
}
"))),
useShinyjs(),
extendShinyjs(text = jscode, functions = "init"),
navbarPage(
title = 'Welcome',
tabPanel('Overview',
tabsetPanel(
tabPanel('Forward',
fluidRow(
DT::dataTableOutput("view_fwd"),width = 6
)
),
tabPanel('Reverse',
fluidRow(
DT::dataTableOutput("view_rvo"),width = 6
))
)),
tabPanel(tags$ul(class='nav navbar-nav',
style = "padding-left: 5px; float: right;", htmlOutput("time")))
)
)
# Define server logic
server <- function(input, output) {
observe({
toggleClass(condition = input$foo,
class = "disabled",
selector = ".navbar ul > li:nth-child(2)")
})
output$time <- renderUI({
as.character(strptime(Sys.time(), "%Y-%m-%d %H:%M:%S", tz = "EET"))
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have developed a shiny app, where we are using various box object in the ui. Currently the boxes expand/Collapse by clicking on the "+/-" sign on the right of the box header, but we need the expand/collapse on click on the header (anywhere on the box header).
Below code (sample code)
If you look at the box with chart, I want the expansion & collapse to be performed on clicking the header i.e. "Histogram box title" and not just the "+/-" sign on right side of the header:
## Only run this example in interactive R sessions
if (interactive()) {
library(shiny)
# A dashboard body with a row of infoBoxes and valueBoxes, and two rows of boxes
body <- dashboardBody(
# Boxes
fluidRow(
box(title = "Histogram box title",
status = "warning", solidHeader = TRUE, collapsible = TRUE,
plotOutput("plot", height = 250)
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
hist(rnorm(50))
})
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
),
server = server
)
}
This is easily achievable using javascript. You just have to create a javascript function and call the same in your header code. Refer to below code for better understanding. I have provided 3 options, let me know if this works for you.
## Only run this example in interactive R sessions
if (interactive()) {
library(shiny)
# javascript code to collapse box
jscode <- "
shinyjs.collapse = function(boxid) {
$('#' + boxid).closest('.box').find('[data-widget=collapse]').click();
}
"
# A dashboard body with a row of infoBoxes and valueBoxes, and two rows of boxes
body <- dashboardBody(
# Including Javascript
useShinyjs(),
extendShinyjs(text = jscode),
# Boxes
fluidRow(
box(id="box1",title = actionLink("titleId", "Histogram box title",icon =icon("arrow-circle-up")),
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot", height = 250)
),
box(id="box2",title = p("Histogram box title",
actionButton("titleBtId", "", icon = icon("arrow-circle-up"),
class = "btn-xs", title = "Update")),
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot1", height = 250)
),
box(id="box3",title = actionButton("titleboxId", "Histogram box title",icon =icon("arrow-circle-up")),
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot2", height = 250)
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
hist(rnorm(50))
})
output$plot1 <- renderPlot({
hist(rnorm(50))
})
output$plot2 <- renderPlot({
hist(rnorm(50))
})
observeEvent(input$titleId, {
js$collapse("box1")
})
observeEvent(input$titleBtId, {
js$collapse("box2")
})
observeEvent(input$titleboxId, {
js$collapse("box3")
})
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
),
server = server
)
}
You can do this for all boxes in an app with a few lines of external css and javascript.
The JS triggers a click on the widget when you click on the header title. It has to be the h3 element because the widget is inside .box-header, which would cause infinite recursion.
$('.box').on('click', '.box-header h3', function() {
$(this).closest('.box')
.find('[data-widget=collapse]')
.click();
});
But then we need to make the h3 element fill the full .box-header, so get rid of the header padding (except on the right), add it to the h3, and make the h3 fill 100% of the width of the box.
.box-header {
padding: 0 10px 0 0;
}
.box-header h3 {
width: 100%;
padding: 10px;
}
I think Lisa DeBruine answer is the better one since you can click the whole header and not just the title.
Pasted it into a small example:
if (interactive()) {
body <- dashboardBody(
useShinyjs(),
tags$style(HTML("
.box-header {
padding: 0 10px 0 0;
}
.box-header h3 {
width: 100%;
padding: 10px;
}")),
fluidRow(
box(id="box1", title = "Histogram box title",
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot", height = 250)
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
hist(rnorm(50))
})
runjs("
$('.box').on('click', '.box-header h3', function() {
$(this).closest('.box')
.find('[data-widget=collapse]')
.click();
});")
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
),
server = server
)
}
This is an issue with the package DT in R, for Shiny apps.
I noticed that with the option fixedHeader = TRUE, the frozen header will appear on all tabs of a Shiny app. Here is an example illustrating the problem. Simply go to "Tab2" and scroll down, and the header from "Tab1" should be visible (unwanted). I would like the header to only appear on "Tab1".
library(shiny)
library(DT)
data("volcano")
ui = shinyUI(navbarPage(title = 'Navbar',
tabPanel('Table',
fluidPage(
fluidRow(
column(width = 12,
DT::dataTableOutput('table'))
)
)
),
tabPanel('Tab2',
fluidPage(
fluidRow(
column(width = 4,
style = "height:1500px;background-color:#f0f0f5;border-radius:6px 0px 0px 6px;
box-shadow:1px 1px 8px #888888")
)
)
)
))
server = shinyServer(function(input, output){
output$table <- DT::renderDataTable(
volcano,
extensions = c('Buttons', 'FixedHeader'),
options = list(
pageLength = 100,
fixedHeader = TRUE
)
)
})
runApp(list(ui=ui, server=server), launch.browser = TRUE)