How to show embedded tweet in R shiny app? - r

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)

Related

Shiny.i18n not translate the modal dialoge rendered within module

I want to translate parts of my UI in a modularized shiny app. As I summarized my simplified code,
in the first module I have no problem with i18n as it is enters to the module 1 with argument i18n and
translation works well in registerUI(based on recommendation here). But my problem is with the UI of module 2 (M2UI) which this function
itself called within the server of module 1 (register) to return a modal dialogue. But i18n not detected and translation not works on displayed new modal. Any suggestions why this happens? thanks in advance...
I edited my example and it is now completely reproducible. Translation csv files are available here. Just copy them in "translations" forlder. And, the modules should be copied to "modules" folder.
## CSV translation files are available at : https://github.com/Appsilon/shiny.i18n/tree/master/examples/data
# Copy "translation_it.csv" and "translation_pl.csv" files to "translations" folder
###### make modules and copy them into folder "modules"
source("modules/register.R")
source("modules/M2.R")
#####
library(shiny)
library(shiny.i18n)
library(shinydashboard)
i18n <- Translator$new(translation_csvs_path = "translations")
i18n$set_translation_language("en")
shiny.i18n::usei18n(i18n)
############################ UI
header <- dashboardHeader(title = i18n$t('Hello Shiny!'), titleWidth = 400 ,
tags$li( fluidRow(
shiny.i18n::usei18n(i18n),
div(style="display: inline-block;vertical-align:top; font-size: 10px; height=30px;width: 150px;",selectInput(
inputId='selected_language',
label=i18n$t('Change language'),
choices = i18n$get_languages(),
selected = i18n$get_key_translation()
))
),
class = "dropdown")
)
# Sidebar Menu ------------------------------------------------------------
sidebar <- dashboardSidebar(width = 220,
sidebarMenu(
menuItem( i18n$t("Hello Shiny!"), tabName = "diary", icon = icon("align-justify")),
menuItem("Help", tabName = "help", icon = icon("table")),
#menuItem("Data analysis", tabName = "descriptive", icon = icon("chart-bar")),
menuItem("About", tabName = "about", icon = icon("info-circle"))
)
)
body <- dashboardBody(
tabItems(
tabItem("diary",
# includeMarkdown("Introduction.Rmd"),
# includeMarkdown("Contact.Rmd")
titlePanel(i18n$t("Hello Shiny!")),
sidebarLayout(
sidebarPanel(
sliderInput("bins",
i18n$t("Number of bins:"),
min = 1,
max = 50,
value = 30)
),
mainPanel(
plotOutput("distPlot"),
actionButton("test","test"),
p(i18n$t("This is description of the plot."))
)
),
tags$style(type = "text/css", ".recalculating {opacity: 1.0;}"), # Prevents gray screen during Sys.sleep()
),
tabItem("help",
),
tabItem("about",
)
)
)
ui <- dashboardPage(title = 'Coronavirus', header, sidebar, body, skin='blue')
#################################### SERVER
server <- function(input, output,session) {
observeEvent(input$selected_language, {
update_lang(session, input$selected_language)
})
shiny::observeEvent(input$test, {
registerUI(id = "REG",reg_title=i18n$t("Hello Shiny!"),i18n=i18n ) #This ID should be mached with ID in server
})
callModule(register,id = "REG", title= i18n$t("Hello Shiny!"), i18n=i18n )
output$distPlot <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins,
col = "darkgray", border = "white",
main = i18n$t("Histogram of x"), ylab = i18n$t("Frequency"))
})
}
shinyApp(ui = ui, server = server)
registerUI <- function(id, reg_title=NULL ,i18n) {
ns <- shiny::NS(id)
shiny.i18n::usei18n(i18n)
showModal(tags$div( modalDialog(title = "" ,size="s",
shiny::div(id =ns("regpanel"),
shiny::wellPanel(
shiny::tags$h2(reg_title, class = "text-center", style = "padding-top: 0;"),
shinyjs::disabled(shiny::textInput(ns("user_name1"), value= "", shiny::tagList(shiny::icon("user"), "suggested user name"))) ,#
shiny::actionButton(ns("regSubmit"), i18n$t("Submit") , class = "btn-primary", style = "color: white;")
)
)
),
easyClose = TRUE, footer = NULL ))
}
###### Module 1
register <- function(input, output, session ,title,i18n) {
ns <- session$ns
shiny::observeEvent(input$regSubmit, {
shiny.i18n::usei18n(i18n)
removeModal()
M2UI(id = ns("M2") ,reg_title=i18n$t("Hello Shiny!" ),i18n=i18n )
})
callModule(M2,id = "M2" , title= i18n$t("Hello Shiny!"),i18n=i18n)
}
###### Module 2
M2UI <- function(id, reg_title=NULL,i18n ) {
ns <- shiny::NS(id)
shiny.i18n::usei18n(i18n)
showModal(modalDialog(title = reg_title ,size="s",
shiny::wellPanel(
shiny::actionButton(ns("Finish"), i18n$t("Hello Shiny!" ) )
)
, easyClose = TRUE, footer = NULL ) )
}
M2 <- function(input, output, session ,title,i18n) {
ns <- session$ns
shiny::observeEvent(input$Finish, {
removeModal()
})
}
Did you try the latest dev version? You have to update it through the dev package. I am pretty sure it was fixed there. The problem regarded a missing callback through shiny session.
Your exampe works on my setup.

How to read & display time in Navbar of Shiny R Dashboard

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)

Expand/Collapse shiny box on header click

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
)
}

Shiny module access output outside namespace

I need my Shiny module to hide/show a div outside of the namespace. I tried passing the div id to the module server function and using shinyjs to show/hide it but that is not working. I'm not getting an error, it just doesn't show/hide the div.
I know the Shiny module documentation says modules cannot access outputs outside the namespace. The docs do, though, give a way for the module to access inputs outside the namespace using reactives.
Does anyone know if there is a way for a Shiny module to access an output outside the namespace?
Here is what I'm trying to do:
### ui.R ###
header <- dashboardHeader(
title = a(href = 'http://google.com')
)
dashboardPage(
skin = 'black',
header,
dashboardSidebar(
sidebarMenu( id='tabs',
menuItem('Edit Existing Client', tabName = 'client-info')
)),
dashboardBody(
useShinyjs(),
fluidRow(
tabItems(
tabItem(tabName = "client-info",
div(selectClientModuleUI("clientinfons")),
div(id='editclientinfo', uiOutput('editclientstuff'))
)
)
)
)
)
### server.R ###
shinyServer(function(session,input, output) {
output$editclientstuff <- renderUI({
div(
fluidRow(
column(6,
textInput('editname', "Display name", value ='Testing name')
),
column(6,
numericInput('editastart','Start', value ='3')
)
)
)
})
callModule(selectClientModule, 'clientinfons', 'editclientinfo')
shinyjs::hide(id='editclientstuff')
})
### in global.R ###
selectClientModuleUI <- function(id){
ns <- NS(id)
clientlist = c(0, 1, 2)
names(clientlist) = c('Choose client', 'Fred', 'Kim')
div(
selectInput(ns('selectclient'), 'Select client to edit', choices = clientlist, selected = NULL, multiple = FALSE)
)
}
selectClientModule <- function(input, output, session, divtoshow = ''){
observeEvent(input$selectclient, {
if (!is.null(input$selectclient) && input$selectclient > 0){
print(paste0("showing ", divtoshow))
shinyjs::show(divtoshow)
}
})
}
That is possible by giving the value as a reactive (not as the value of the reactive) to the module. You can change the reactive Value in the module and return the reactive from the Module to the app (note, return the reactive itself, not its value). The following app switches the 'divtoshow' in the main app from inside the module. If nothing is selected, it's hidden, otherwise it's shown (note, I adjusted you code a little so it's working as a stand-alone app):
library(shinydashboard)
library(shinyjs)
# Module
selectClientModuleUI <- function(id){
ns <- NS(id)
clientlist = c(0, 1, 2)
names(clientlist) = c('Choose client', 'Fred', 'Kim')
div(
selectInput(ns('selectclient'), 'Select client to edit', choices = clientlist, selected = NULL, multiple = FALSE)
)
}
selectClientModule <- function(input, output, session, divtoshow){
observeEvent(input$selectclient, {
if (input$selectclient > 0){
print(paste0("showing editclientinfo"))
divtoshow("editclientinfo") # set the div to show to "editclientinfo", this will be visible outside the module
}else{
divtoshow("") # set the div to show to "", if nothing was chosen
}
})
# return the div to show as reactive to the main app
return(divtoshow)
}
# Main App
ui <- shinyUI(
dashboardPage(
skin = 'black',
dashboardHeader(
title = a(href = 'http://google.com')
),
dashboardSidebar(
sidebarMenu( id='tabs',
menuItem('Edit Existing Client', tabName = 'client-info')
)),
dashboardBody(
useShinyjs(),
fluidRow(
tabItems(
tabItem(tabName = "client-info",
div(selectClientModuleUI("clientinfons")),
div(id='editclientinfo', uiOutput('editclientstuff'))
)
)
)
)
))
server <- shinyServer(function(session,input, output) {
output$editclientstuff <- renderUI({
div(
fluidRow(
column(6,
textInput('editname', "Display name", value ='Testing name')
),
column(6,
numericInput('editastart','Start', value ='3')
)
)
)
})
# store the div to show in a reactive
divtoshow <- reactiveVal('')
# divtoshow can be changed in side this module, so it's a return value
divtoshow <- callModule(selectClientModule, 'clientinfons', divtoshow)
# observe the value of divtoshow and toggle the corresponding div
observeEvent(divtoshow(), {
if(divtoshow() == "editclientinfo"){
shinyjs::show("editclientinfo")
}else{
shinyjs::hide("editclientinfo")
}
})
})
shinyApp(ui, server)

Observe datatable pagination event Shiny

I need to change the value of an input every time that the user changes the page of a dataset pagination.
I've tried to use the observeEvent, but it doesn't work.
UI
fluidRow(
column(10,
""
),
column(2,
textInput("inText", "Input text 2", value = "Default text")
),
column(12,
dataTableOutput('table')
)
)
Server
observeEvent(input$table, {
updateTextInput(session, "inText", value = paste("New text",0))
})
Hope you can help me.
Assuming your table id is table as given in your example, you can use:
input$table_state$start / input$table_state$length + 1.
In the following a complete example:
library(DT)
library(shiny)
app <- shinyApp(
ui = fluidPage(
tags$head(
# hides the default search functionality
tags$style(
HTML(".dataTables_filter, .dataTables_info { display: none; }")
)
),
fluidRow(
column(10,
""
),
column(2,
# adding new page filter
uiOutput("pageFilter")
),
column(12,
dataTableOutput('table')
)
)
),
server = function(input, output) {
output$pageFilter <- renderUI({
val <- input$table_state$start / input$table_state$length + 1
numericInput("page", "Page", val, min = 1)
})
output$table <- DT::renderDataTable({
iris
}, options = list(pageLength = 5, stateSave = TRUE))
# using new page filter
observeEvent(input$page, {
dataTableProxy("table") %>% selectPage(input$page)
})
}
)
runApp(app, launch.browser = TRUE)

Resources