I am creating an R Shiny app, where a user can upload their own csv, and the app generates a synthetic dataset. I am trying to add an additional function where the user can select a column they wish to anonymise to make it a shareable file. The rest of the app is currently working, however when I select the column which I want to anonomise, when I press update, the datatable isn't refreshing.
Any help or insight here would be greatly appreciated! I've tried and tried to solve it, but am stuck.
A shortened/reproducible version of the code app is below
`
library(shiny)
library(synthpop)
library(DT)
library(tidyverse)
library(data.table)
library(rsconnect)
library(fontawesome)
library(DT)
library(htmltools)
library(shinythemes)
library(RcppRoll)
library(grid)
library(reactable)
library(shinydashboard)
library(shinydashboardPlus)
library(formattable)
library(dashboardthemes)
library(deidentifyr)
library(anonymizer)
library(digest)
# User interface
ui <- fluidPage(theme = shinytheme("cosmo"),
navbarPage("Synthetic data",
# Upload data tab
tabPanel("Upload data",
sidebarLayout(
sidebarPanel(width = 3,
h4(strong("Upload original data")),
br(),
fileInput(inputId = "datafile", label = "1. Upload a csv file then press 'Update' below.
Note, the larger your dataset, the longer it will take to load", multiple = FALSE, placeholder = "No file selected",
accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")),
actionButton(inputId = "update", label = "Update", icon = icon("fas fa-sync")),
br(),
br(),
h5(strong("2. To view and download the synthesised dataset, click on the 'Synthetic data' tab at the top"))),
mainPanel(dataTableOutput("table"), style = "font-size:80%"))),
# Synthetic data download
tabPanel("Synthetic data",
sidebarLayout(
sidebarPanel(width = 3,
h4(strong("Anonomise data?")),
br(),
uiOutput(outputId = "anon"),
br(),
actionButton(inputId = "update2", label = "Update", icon = icon("fas fa-sync"))),
mainPanel(dataTableOutput("synth"), style = "font-size:75%"))),
))
# Server function
server <- function(input, output, session) {
options(shiny.maxRequestSize=20*1024^2)
contentsrea <- reactive({
inFile <- input$datafile
if(is.null(inFile))
return(NULL)
dataset <- read_csv(inFile$datapath)
})
observeEvent(input$update, {
if(!is.null(input$datafile)){
original <- read_csv(input$datafile$datapath)
my.seed <- 17914709
synResult <- syn(original, seed = my.seed, maxfaclevels = 150)
# Synthetic data
df <- synResult$syn
# Add 'SYNTH' to column headings
colnames(df) <- paste("SYNTH", colnames(df), sep="_")
# Variable dropdown to anonomise data
output$anon <- renderUI({
selectInput(inputId = "anon",
label="1. Select the variable you'd like to anonomise (i.e., athlete name). If not necessary, leave as blank",
choices = c(" ", colnames(df)),
selected = NULL)
})
## Original
output$table <- DT::renderDataTable(original,
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; color: black; font-size:140%',
h3(strong("Original data"))), server = FALSE, rownames=FALSE,
options = list(bFilter=0, iDisplayLength=18,
columnDefs = list(list(className = 'dt-center', targets = '_all')),
dom = 'frtip'))
# Synthetic dataset
output$synth <- DT::renderDataTable(df,
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; color: black; font-size:140%',
h3(strong("Simulated synthetic data"))),
server = FALSE, rownames=FALSE, extensions = c("Buttons"),
options = list(iDisplayLength=18, bFilter=0,
columnDefs = list(list(className = 'dt-center', targets = '_all')),
dom = 'Bfrtip'))
}})
}
# Synthetic dataset with update for anon
observeEvent(input$update2, {
if(!is.null(input$datafile)){
output$synth <- DT::renderDataTable({
# Anonomise
df$ID <- sapply(input$anon, digest, algo = "crc32")
datatable(df,
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; color: black; font-size:140%',
h3(strong("Simulated synthetic data"))),
server = FALSE, rownames=FALSE, extensions = c("Buttons"),
options = list(iDisplayLength=18, bFilter=0,
columnDefs = list(list(className = 'dt-center', targets = '_all')),
dom = 'Bfrtip'))
})
}})
# Run the app ----
shinyApp(ui, server)
`
I have tried removing the update button ans using a reactive table, as well as other anonomise functions. I am completely stuck.
Related
I am new to the world of RShiny and i think reactivity is bit complex to understand. I am trying to make a datatable output based on row and column condition given as per user selectinput dropdown buttons. My DataTable is editable and i want to store the updated table after user edited the cells of the datatable in a new variable but i am stuck.
I tried couple of chunks suggested on stackoverflow but none of them worked for me mostly using proxytable or reactivity. I want to store the datatable after i hit proceed button. Any help would be much appreciated.
Here is my code:
library(shiny)
library(shinyWidgets)
library(shinythemes)
library(DT)
library(data.table)
#ui
shinyApp(
ui = fluidPage(
theme = shinythemes::shinytheme("flatly"),
titlePanel("Trial"),
sidebarLayout(
shiny::sidebarPanel(
#to take multiple user input
shiny::textAreaInput(
"text_input",
label = "Write input"
),
#to slect the columns to be added
shinyWidgets::pickerInput(
inputId = "somevalue",
label = "Columns to add",
choices = colnames(df),
options = list(`actions-box` = TRUE),
multiple = TRUE
),
#action button tot show the table
shinyWidgets::actionBttn(
"show_table",
label = "Show",
size = "sm",
color = "default",
block = TRUE
), width = 2
),
mainPanel(
shiny::tabsetPanel(type = "tabs",
shiny::tabPanel("Table", DT::dataTableOutput("table")),
actionBttn("proceed","proceed")
),width = 10
)
)
),
server = function(input, output,session) {
#to add reactivity to the show button
df_filter <- reactive({
text_input <- trimws(strsplit(input$text_input, ",")[[1]])
df_filter <- df[df$make %chin% text_input, input$somevalue]
})%>% shiny::bindEvent(input$show_table)
#to output hte dt table with the filters
output$table <- DT::renderDT({
DT::datatable(df_filter(),
editable = 'cell',
options = list(scrollX = TRUE , lengthChange = FALSE, autoWidth = TRUE)
# editable = list(target = "row", disable = list(columns = c(2, 4, 5))))
)
})%>% shiny::bindEvent(df_filter())
}
)
I am updating a Shiny app to add two selection radio buttons. I want to use different .Rmd files to create different reports. They will be using different R scripts with different calculations. The tool previously had no selection option and looked like this:
ui.R
ui <- navbarPage(
tags$head(HTML("<script type='text/javascript' src='www/custom_work.js'></script>")),
tabPanel("Main",
includeScript(path = 'www/custom_work.js'),
# https://rstudio.github.io/shinythemes/
sidebarLayout(
sidebarPanel(width=3,
# Input: Select a file ----
fileInput("file1", "Choose Excel file",
multiple = FALSE,
c("application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")),
conditionalPanel(
condition = "output.hot_assay_info",
downloadButton("downloadReport", "Download Report", class ='btn-success')
)
),
mainPanel(
radioButtons(inputId = "type", "Select Type:", choices = c("Up", "Down")),
radioButtons(inputId = "class", "Select Class:", choices = c("Left", "Right")),
tabsetPanel(
tabPanel("A", dataTableOutput("hot_A")),
tabPanel("B", rHandsontableOutput("hot_B", width = "100%", height = 700)),
tabPanel("C", rHandsontableOutput("hot_C", width = "100%", height = 700)),
)
)
)
)
)
server.R
server <- function(input, output, session) {
values <- reactiveValues()
observe({print(input$file1)})
# Observer A Info
observe({
req(input$file1$datapath)
DF <- read_excel(input$file1$datapath, sheet = "A")
values[['A']] <- DF
})
# Observer B Results
observe({
req(input$file1$datapath)
DF <- read_excel(input$file1$datapath, sheet = "B")
values[['B']] <- DF
})
# Observer C Controls
observe({
req(input$file1$datapath)
DF <- read_excel(input$file1$datapath, sheet = "C")
values[['C']] <- DF
})
output$hot_assay_info <- renderDataTable({
req(input$file1$datapath)
DF <- values[["A"]]
})
# Render Screening Table
output$hot_screening <- renderRHandsontable({
req(input$file1$datapath)
DF <- values[["B"]]
})
# Render Normalization Table
output$hot_normalization <- renderRHandsontable({
req(input$file1$datapath)
DF <- values[["C"]]
})
output$downloadReport <- downloadHandler(
filename = function(){
input$filename
},
content = function(filename) {
rmarkdown::render('test.Rmd',
output_file = filename,
params = list(df_values = values))
}
)
}
test.Rmd
---
title: "test"
output:
html_document:
df_print: paged
pdf_document: default
params:
region: ''
df_values: ''
editor_options:
chunk_output_type: console'
---
I added in two radioButtons (in ui) with selection for type and class but I am uncertain how to update the report output based on selections. There will be 4 .Rmd files that are a combination of the two selections:
Up and Left
Up and Right
Down and Left
Down and Right
Thanks for your help!
I was wondering if it is possible to save DT table content together with some additional information which is not part of the data frame/table like app version number, date of execution, sliderInput value etc.
Thank you!
Reprex below:
library(shiny)
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "range", "Set range", 1, 10, 5, 1)
),
mainPanel(
DT::dataTableOutput("table")
)
)
)
server <- function(input, output) {
dfr <- data.frame(var1 <- c(1,2,3),
var2 <- c(11, 22, 33))
output$table <- DT::renderDataTable(
datatable(dfr, extensions = 'Buttons',
class="cell-border stripe",
rownames = FALSE, colnames = c("var1", "var2"),
options = list(dom = "Blfrtip",
buttond = list("copy", list(extend = "collection",
buttons = c("csv", "excel", "pdf"),
text = "Download")), pageLength=10, autoWidth = TRUE,
searchHighlight = TRUE, filter = "top"))
)
}
shinyApp(ui = ui, server = server)
You could save the contents of the data frame and the other information in a list and then save the list.
Or, any R object can have attributes which are completely arbitrary and under your control. You could set attributes of the data frame to record the information you want.
Personally, I'd use the list approach, purely because I don't like attributes.
Here's a suggestion in response to OP's request below.
library(shiny)
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "range", "Set range", 1, 10, 5, 1),
actionButton("saveRds", "Save to Rds"),
actionButton("loadRds", "Load from Rds")
),
mainPanel(
DT::dataTableOutput("table"),
wellPanel(h4("Current data"), verbatimTextOutput("text")),
wellPanel(h4("File data"), verbatimTextOutput("loadedData"))
)
)
)
server <- function(input, output) {
dfr <- data.frame(var1 <- c(1,2,3),
var2 <- c(11, 22, 33))
output$table <- DT::renderDataTable(
datatable(dfr, extensions = 'Buttons',
class="cell-border stripe",
rownames = FALSE, colnames = c("var1", "var2"),
options = list(dom = "Blfrtip",
buttond = list("copy", list(extend = "collection",
buttons = c("csv", "excel", "pdf"),
text = "Download")), pageLength=10, autoWidth = TRUE,
searchHighlight = TRUE, filter = "top"))
)
listInfo <- reactive({
list("data"=dfr, "version"="WebApp Version 1.0", "runDate"=date(), "sliderValue"=input$range)
})
output$text <- renderPrint({
listInfo()
})
observeEvent(input$saveRds, {
saveRDS(listInfo(), "data.Rds")
})
fileData <- reactive({
req(input$loadRds)
readRDS("data.Rds")
})
output$loadedData <- renderPrint({
fileData()
})
}
shinyApp(ui = ui, server = server)
The way you implement "save to file" will depend on the file format: Excel files will clearly have different requirements to PDF files, for example. As a minimum effort demonstation, I've created "Save to Rds" and "Load from RDS" buttons in the sidebar and added a verbatimTextOutput to display the contents of the file when it's loaded. [I'm not sufficiently familiar with DT to know how to add the buttons in the table toolbar.]
OP's effort was pretty close: it's just that writing a list to CSV file takes a little more effort than just calling write.csv...
I have TableTools and ColVis working together, but, as it was explained in another post (R shiny DataTables ColVis behavior), when clicking the Show/hide columns button, the list mixes up with the values in the table underneath, and I cannot make the list disappear.
In that post is mentioned that shiny atm is not compatible with the current data.table version, and I'd like to know if there's any other solution around. Here's my code:
ui.R
library(shiny)
library(shinythemes)
library(ggplot2)
addResourcePath('datatables','\\Users\\Ser\\Downloads\\DataTables-1.10.7\\DataTables-1.10.7\\media')
addResourcePath('tabletools','\\Users\\Ser\\Downloads\\TableTools-2.2.4\\TableTools-2.2.4')
shinyUI(fluidPage(theme = shinytheme("Journal"),
tags$head(
tags$style(HTML("
#import url('//fonts.googleapis.com/css?family=Lobster|Cabin:400,700');
"))
),
headerPanel(
h1("List Manager",
style = "font-family: 'Lobster', cursive;
font-weight: 500; line-height: 1.1;
color: #ad1d28;")),
sidebarLayout(
sidebarPanel(
#File Upload Manager
fileInput('file1', 'Choose file to upload'),
tagList(
singleton(tags$head(tags$script(src='//cdnjs.cloudflare.com/ajax/libs/datatables/1.10.7/js/jquery.dataTables.min.js',type='text/javascript'))),
singleton(tags$head(tags$script(src='//cdnjs.cloudflare.com/ajax/libs/datatables-tabletools/2.1.5/js/TableTools.min.js',type='text/javascript'))),
singleton(tags$head(tags$script(src='//cdnjs.cloudflare.com/ajax/libs/datatables-tabletools/2.1.5/js/ZeroClipboard.min.js',type='text/javascript'))),
singleton(tags$head(tags$link(href='//cdnjs.cloudflare.com/ajax/libs/datatables-tabletools/2.1.5/css/TableTools.min.css',rel='stylesheet',type='text/css'))),
singleton(tags$head(tags$script(src='//cdn.datatables.net/colvis/1.1.0/js/dataTables.colVis.min.js',type='text/javascript'))),
singleton(tags$script(HTML("if (window.innerHeight < 400) alert('Screen too small');")))
)),
mainPanel(
dataTableOutput("mytable"))
)))
server.R
shinyServer(function(input, output) {
output$mytable = renderDataTable({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
read.table(inFile$datapath, header=TRUE, sep='')
}, options = list(
"dom" = 'TC<"clear">lfrtip',
"colVis" = list(
"activate"="click",
"align"="right"),
"oTableTools" = list(
"sSwfPath" = "//cdnjs.cloudflare.com/ajax/libs/datatables-tabletools/2.1.5/swf/copy_csv_xls.swf",
"aButtons" = list(
"copy",
"print",
list("sExtends" = "collection",
"sButtonText" = "Save",
"aButtons" = c("csv","xls")
)
)
)
)
)
})
I also have another question: I'd like to search "<" or ">" values in the searchboxes at the bottom of the table, but I can't make it work. I don't know if I have to add anything to the code so it can be done (such as "regex" or similar).
You may try the DT package instead of hacking the JS libraries by yourself. Here is a minimal example:
library(shiny)
library(DT)
library(shinythemes)
shinyApp(
ui = fluidPage(
theme = shinytheme('journal'),
fluidRow(column(12, DT::dataTableOutput('foo')))
),
server = function(input, output) {
output$foo = DT::renderDataTable(
iris,
filter = 'bottom',
extensions = list(ColVis = list(activate= "click", align = "right")),
options = list(dom = 'C<"clear">lfrtip')
)
}
)
See http://rstudio.github.io/DT/extensions.html for more info on DataTables extensions.
I have been attempting to create a Shiny timeseries plot using NVD3 library. Am relatively new to R, Shiny and NVD3. The problem is that when I run the ShinyApp, no chart renders on the browser. Using chromes developer tools, I can see that the div for myChart is created and populated with data, but not understanding why I cannot see the chart itself.
Would appreciate any and all help on this matter...
My code is like so:
#ui.R
require(rCharts)
shinyUI(pageWithSidebar(
headerPanel("Population Trend By Age Group:"),
sidebarPanel(
selectInput(inputId = "agegrp",
label = "Choose Agegroup",
choices = c("0-4",
"5-9",
"10-14",
"15-19",
"20-24",
"25-29",
"30-34",
"35-39",
"40-44",
"45-49",
"50-54",
"55-59",
"60-64",
"65-69",
"70-74",
"75-79",
"80-84",
"85+"
),
selected = "0-4")
),
mainPanel(
showOutput("myChart", "nvd3")
)
))
server.R:
#server.R
require(rCharts)
data <- read.csv("https://raw.githubusercontent.com/kilimba/data/master/data2.csv")
agegroup_mapping <- read.csv("https://raw.githubusercontent.com/kilimba/data/master/agegroup.csv")
data <- merge(data,agegroup_mapping,by.x="agegrp",by.y="agegroup")
shinyServer(function(input, output) {
output$myChart <- renderChart({
selection <- subset(data,mapping == input$agegrp)
plot <- nPlot(n ~ year,
data = selection,
type = "lineChart",
group = "sex")
# Add axis labels and format the tooltip
plot$yAxis(axisLabel = "Population", width = 62)
plot$xAxis(axisLabel = "Year")
plot$save("ac.html")
return(plot)
})
})
Thanks,
Tumaini
Use renderChart2 instead of renderChart.
rm(list = ls())
library(shiny)
library(rCharts)
data <- read.csv("https://raw.githubusercontent.com/kilimba/data/master/data2.csv")
agegroup_mapping <- read.csv("https://raw.githubusercontent.com/kilimba/data/master/agegroup.csv")
data <- merge(data,agegroup_mapping,by.x="agegrp",by.y="agegroup")
ui =pageWithSidebar(
headerPanel("Population Trend By Age Group:"),
sidebarPanel(
selectInput(inputId = "agegrp",
label = "Choose Agegroup",
choices = c("0-4","5-9","10-14","15-19","20-24","25-29","30-34","35-39",
"40-44","45-49","50-54","55-59","60-64","65-69","70-74","75-79","80-84","85+"),selected = "0-4"),width=2),
mainPanel(
showOutput("myChart", "nvd3")
)
)
server = function(input, output) {
output$myChart <- renderChart2({
#selection <- data[data$mapping == "0-4",]
selection <- data[data$mapping == input$agegrp,]
selection <- subset(data,mapping == input$agegrp)
plot <- nPlot(n ~ year,
data = selection,
type = "lineChart",
group = "sex")
# Add axis labels and format the tooltip
plot$yAxis(axisLabel = "Population", width = 62)
plot$xAxis(axisLabel = "Year")
plot$set(width=1600, height=800)
plot$save("ac.html")
plot
})
}
runApp(list(ui = ui, server = server))