I am using shinyTree to render a data table. The following is the dataset with codes used so far:
library(shiny)
library(shinyTree)
newdat <- structure(list(RESPID = c("41000123", "41004132", "41006132",
"41007121", "41007123"), PDT_A = c(125, 66, 45, 28,
0), PDT_B = c(10, 0, 0, 0, 0), PDT_C = c(0, 0, 0, 0, 0), PDT_D = c(450,
105, 75, 192, 0), PDT_TOTAL = c(585, 171, 120, 220, 0)), .Names = c("RESPID",
"PDT_A", "PDT_B", "PDT_C", "PDT_D", "PDT_TOTAL"), row.names = c("6",
"40", "56", "59", "61"), class = "data.frame")
server <- shinyServer(function(input, output, session) {
newdata <- reactive({newdat})
output$tree <- renderTree({
sss=list('TOTAL_VALUE'= list('TOTAL_VALUE_OF_MERCHANDISE' = structure(list('PDT_TOTAL'='1001'), stopened=FALSE),
'PDT_CAT' = structure(list('PDT_TOTAL'='1002','PDT_A'='152','PDT_B'='153','PDT_C'='154','PDT_D'='155'), stopened=FALSE)
))
attr(sss[[1]],"stopened")=FALSE
sss
})
catdat <- reactive({
tree <- input$tree
unlist(get_selected(tree))
})
coldat <- reactive({
newdata()[,catdat()]
})
output$datatab <- renderDataTable({
coldat()
})
})
ui <- shinyUI(
pageWithSidebar(
headerPanel("TEST"),
sidebarPanel(
shinyTree("tree", checkbox = TRUE)
),
mainPanel(
dataTableOutput("datatab")
)
))
shinyApp(ui,server)
The tree gets generated. I have following trouble in rendering the columns through data table output:
The first branch of the tree, refers to only one column: which is not rendering in shiny. I am getting an error message undefined columns selected.
The second branch of the tree supposed to render all five columns of the table. However it renders only any four of the columns.
If i select root of the second branch, i am getting the same undefined columns selected. When I uncheck one of the branch the table with 4 columns gets rendered.
How do i render all the columns?
Is there a way where I can remove the check boxes at the branch root / nodes level?
Ad 1. You get this error because if you select the first branch of the tree, then catdat() returns a vector with "PDT_TOTAL" and "TOTAL_VALUE_OF_MERCHANDISE" and there is no such variable as "TOTAL_VALUE_OF_MERCHANDISE" in your dataset.
Ad 2. If you select all five options then catdat() returns additionally "PDT_CAT" and you have the same problem as above - there is no such variable in your dataset. (Same above - if you select all options, so "PDT_TOTAL", it returns additionally "TOTAL_VALUE_OF_MERCHANDISE")
To render all columns you could do following:
First, select dynamically variables from your dataset and then remove duplicates as catdat() returns twice "TOTAL_VALUE" when the very first option TOTAL_VALUE is selected.
There is also another issue: newdata()[,vars] returns a vector if there is only one variable selected and renderDataTable won't print anything as it works only with dataframes. To address this issue you can remove , to ensure that the subsetting returns always a dataframe - newdata()[vars]
coldat <- reactive({
vars <- catdat()
vars <- vars[!(vars %in% c("TOTAL_VALUE", "TOTAL_VALUE_OF_MERCHANDISE", "PDT_CAT"))]
vars <- unique(vars)
print(vars)
# newdata()[,vars] # If you select only one variable then this reactive returns an object of class numeric and not a data.frame
newdata()[vars] # remove "," and it will always return a data frame
})
Full example:
library(shiny)
library(shinyTree)
newdat <- structure(list(RESPID = c("41000123", "41004132", "41006132",
"41007121", "41007123"), PDT_A = c(125, 66, 45, 28,
0), PDT_B = c(10, 0, 0, 0, 0), PDT_C = c(0, 0, 0, 0, 0), PDT_D = c(450,
105, 75, 192, 0), PDT_TOTAL = c(585, 171, 120, 220, 0)), .Names = c("RESPID",
"PDT_A", "PDT_B", "PDT_C", "PDT_D", "PDT_TOTAL"), row.names = c("6",
"40", "56", "59", "61"), class = "data.frame")
server <- shinyServer(function(input, output, session) {
newdata <- reactive({newdat})
output$tree <- renderTree({
sss=list('TOTAL_VALUE'= list('TOTAL_VALUE_OF_MERCHANDISE' = structure(list('PDT_TOTAL'='1001'), stopened=FALSE),
'PDT_CAT' = structure(list('PDT_TOTAL'='1002','PDT_A'='152','PDT_B'='153','PDT_C'='154','PDT_D'='155'), stopened=FALSE)
))
attr(sss[[1]],"stopened")=FALSE
sss
})
catdat <- reactive({
tree <- input$tree
unlist(get_selected(tree))
})
coldat <- reactive({
vars <- catdat()
vars <- vars[!(vars %in% c("TOTAL_VALUE", "TOTAL_VALUE_OF_MERCHANDISE", "PDT_CAT"))]
vars <- unique(vars)
print(vars)
# newdata()[,vars] # If you select only one variable then this reactive returns an object of class numeric and not a data.frame
newdata()[vars] # remove "," and it will always return a data frame
})
output$datatab <- renderDataTable({
coldat()
})
})
ui <- shinyUI(
pageWithSidebar(
headerPanel("TEST"),
sidebarPanel(
shinyTree("tree", checkbox = TRUE)
),
mainPanel(
dataTableOutput("datatab")
)
))
shinyApp(ui,server)
Related
The code below reads a CSV file and displays the Datatable in the Main panel. The field in 'Column to search' is automatically detected. I've created a field named 'Replace' and a field called 'by' that can be used to replace certain values in a column's cell.
I want to highlight that cell in any colour, preferably orange, wherever the values are replaced.
Could someone please explain how I can do this in R shiny?
CSV
ID Type Category values
21 A1 B1 030,066,008,030,066,008
22 C1 D1 020,030,075,080,095,100
23 E1 F1 030,085,095,060,201,030
Expected Output:
If I change 030 to 100 in the columns 'values,' I want that cell (in column Values and Row 2) to be coloured.
code
library(shiny)
library(DT)
library(stringr)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
selectInput("col", "Column to search:", NULL),
textInput("old", "Replace:"),
textInput("new", "By:"),
actionButton("replace", "Replace!"),
),
mainPanel(
DTOutput("table1")
)
)
)
server <- function(input, output, session) {
my_data <- reactiveVal(NULL)
observeEvent(input$file1, {
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
# validate(need(ext == "csv", "Please upload a csv file"))
my_data(read.csv2(file$datapath, header = input$header))
updateSelectInput(session, "col", choices = names(my_data()))
})
observeEvent(input$replace, {
req(input$col)
dat <- req(my_data())
traf <- if (is.numeric(dat[[input$col]])) as.numeric else identity
my_data(dat %>%
mutate(!!rlang::sym(input$col) :=
stringr::str_replace_all(!!rlang::sym(input$col),
input$old,
input$new) %>%
traf()))
})
output$table1 <- renderDT(
req(my_data())
)
}
shinyApp(ui, server)
I thought of a possible workaround that consists in using DT::formatStyle() to color each modified cell. One drawback of using this approach is that the csv imported will have twice as many columns (because i will need them to tell formatStyle() in which cells it has to add colors). However, the additional cols can be hidden so they don't appear displayed, but they will be present in the object passed to datatable. The additional columns are required if the cells need to stay colored after each edit, if that's not the case, then one extra column will suffice. Notice that the good news is that only R code is used here.
The first step will be to create the additional columns, so after the .csv file is read into reactive my_data():
#create (n = number of columns) reactive values.
nms <- vector('list', ncol(my_data())) %>% set_names(names(my_data()))
ccol <<- exec("reactiveValues", !!!nms)
#pre-allocate all the columns that we're going to use.
my_data(map_dfc(names(ccol), ~transmute(my_data(), 'orange_{.x}' := 0)) %>% {bind_cols(my_data(), .)})
Now, each time a column is modified somewhere, the corresponding orange_colname will contain a boolean indicated if a modification took place.
ccol[[input$col]] <- str_detect(dat[[input$col]], input$old)
my_data(my_data() %>%
mutate('orange_{input$col}' := ccol[[input$col]]))
finally, we render the table using datatable()'s option argument to hide the extra cols, and then use a for loop to add the colors in each column. I need to use a loop here because the app can import any table really as long it is a data frame.
Dtable <-
datatable(my_data(),
options = list(columnDefs = list(list(visible = FALSE, targets = (ncol(my_data())):((ncol(my_data()) / 2) + 1) ))))
walk(names(ccol), ~ { Dtable <<- Dtable %>% formatStyle(..1, str_glue("orange_{.x}"),
backgroundColor = styleEqual(c(1), c("orange"))) })
Dtable
App:
library(shiny)
library(DT)
library(stringr)
library(tidyverse)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
selectInput("col", "Column to search:", NULL),
textInput("old", "Replace:"),
textInput("new", "By:"),
actionButton("replace", "Replace!"),
),
mainPanel(
DTOutput("table1")
)
)
)
server <- function(input, output, session) {
my_data <- reactiveVal(NULL)
last_coloured <- reactiveVal(NULL)
observeEvent(input$file1, {
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
# validate(need(ext == "csv", "Please upload a csv file"))
my_data(read_csv(file$datapath))
updateSelectInput(session, "col", choices = names(my_data()))
#create (n = number of columns) reactive values.
nms <- vector('list', ncol(my_data())) %>% set_names(names(my_data()))
ccol <<- exec("reactiveValues", !!!nms)
#pre-allocate all the columns that we're going to use.
my_data(map_dfc(names(ccol), ~transmute(my_data(), 'orange_{.x}' := 0)) %>% {bind_cols(my_data(), .)})
})
observeEvent(input$replace, {
req(input$col)
dat <- req(my_data())
traf <- if (is.numeric(dat[[input$col]])) as.numeric else identity
my_data(dat %>%
mutate(!!rlang::sym(input$col) :=
stringr::str_replace_all(
!!rlang::sym(input$col),
input$old,
input$new
) %>%
traf()))
# also i would like to know which rows are modified
ccol[[input$col]] <- str_detect(dat[[input$col]], input$old)
my_data(my_data() %>%
mutate('orange_{input$col}' := ccol[[input$col]]))
})
output$table1 <- renderDT({
req(my_data())
Dtable <-
datatable(my_data(),
options = list(columnDefs = list(list(visible = FALSE, targets = (ncol(my_data())):((ncol(my_data()) / 2) + 1) ))))
walk(names(ccol), ~ { Dtable <<- Dtable %>% formatStyle(..1, str_glue("orange_{.x}"),
backgroundColor = styleEqual(c(1), c("orange"))) })
Dtable
})
}
shinyApp(ui, server)
I used the parameter selection from renderDT(). After changing my_data(), you can compare which positions were changed in relation with dat (where you stored the unchanged data.frame) and then pass them as coordinates to the selection parameter
server <- function(input, output, session) {
my_data <- reactiveVal(NULL)
positions <- reactiveVal(NULL) ## here we'll save positions of changed cells
observeEvent(input$file1, {
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
# validate(need(ext == "csv", "Please upload a csv file"))
my_data(read.csv2(file$datapath, sep = ",", header = input$header))
updateSelectInput(session, "col", choices = names(my_data()))
})
observeEvent(input$replace, {
req(input$col, my_data())
dat<- my_data()
traf <- if (is.numeric(dat[[input$col]])) as.numeric else identity
my_data(dat %>%
mutate(!!rlang::sym(input$col) :=
stringr::str_replace_all(!!rlang::sym(input$col),
input$old,
input$new) %>%
traf()))
positions(which(dat != my_data(), arr.ind = T)) # this is where new
# values positions are stored
})
output$table1 <- renderDT({
req(my_data())
}, selection=list(mode="single",##### this argument let you select a cell
target="cell",
selected = positions()))
}
If you set input$old to "030", all cells will be selected, since "030" is present in all 3 cells. But if you do it with "066", you'll see only the first cell of "values" will be highlighted
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 want to download the output of this App which I made but there is an error and when I open the downloaded data it is empty.I make a data set by output$other_val_show and I want to download it. Any advice?
The following code in for the UI section.
library(shiny)
library(quantreg)
library(quantregGrowth)
library(plotly)
library(rsconnect)
library(ggplot2)
library(lattice)
ui = tagList(
tags$head(tags$style(HTML("body{ background: aliceblue; }"))),
navbarPage(title="",
tabPanel("Data Import",
sidebarLayout(sidebarPanel( fileInput("file","Upload your CSV",multiple = FALSE),
tags$hr(),
h5(helpText("Select the read.table parameters below")),
checkboxInput(inputId = 'header', label = 'Header', value = FALSE),
checkboxInput(inputId = "stringAsFactors", "StringAsFactors", FALSE),
radioButtons (inputId = 'sep', label = 'Separator',
choices = c(Comma=',',Semicolon=';',Tab='\t', Space=''), selected = ',')
),
mainPanel(uiOutput("tb1"))
)),
tabPanel("Interval",
sidebarLayout(sidebarPanel(
uiOutput("model_select"),
uiOutput("var1_select"),
uiOutput("rest_var_select"),
#uiOutput("testText1"), br(),
#textInput("Smooting Parameter min value", "Smooting Parameter max value", value = "")
sliderInput("range", "Smooth Parameter range:",min = 0, max = 1000, value = c(0,100)),
downloadButton('downloadData', 'Download')
),
mainPanel(helpText("Selected variables and Fitted values"),
verbatimTextOutput("other_val_show")))),
tabPanel("Model Summary", verbatimTextOutput("summary")),
tabPanel("Scatterplot", plotOutput("scatterplot"))#, # Plot
#tabPanel("Distribution", # Plots of distributions
#fluidRow(
#column(6, plotOutput("distribution1")),
#column(6, plotOutput("distribution2")))
#)
,inverse = TRUE,position="static-top",theme ="bootstrap.css"))
The following code in for the Server section. (I want to download the output which is "gr" and I want to download it by downloadHandler function.
server<-function(input,output) {
data <- reactive({
lower <- input$range[1]
upper <- input$range[2]
file1 <- input$file
if(is.null(file1)){return()}
read.table(file=file1$datapath, sep=input$sep, header = input$header, stringsAsFactors = input$stringAsFactors)
})
output$table <- renderTable({
if(is.null(data())){return ()}
data()
})
output$tb1 <- renderUI({
tableOutput("table")
})
#output$model_select<-renderUI({
#selectInput("modelselect","Select Algo",choices = c("Reference Interval"="Model"))
#})
output$var1_select<-renderUI({
selectInput("ind_var_select","Select Independent Variable", choices =as.list(names(data())),multiple = FALSE)
})
output$rest_var_select<-renderUI({
checkboxGroupInput("other_var_select","Select Dependent Variable",choices =as.list(names(data()))) #Select other Var
})
output$other_val_show<-renderPrint({
input$other_var_select
input$ind_var_select
f<-data()
lower <- input$range[1]
upper <- input$range[2]
library(caret)
library(quantregGrowth)
dep_vars <- paste0(input$ind_var_select, collapse = "+")
after_tilde <- paste0("ps(", dep_vars, ", lambda = seq(",lower,",",upper,",l=100))")
dyn_string <- paste0(input$other_var_select, " ~ ", after_tilde)
Model<-quantregGrowth::gcrq(as.formula(dyn_string),tau=c(0.025,0.975), data=f)
temp <- data.frame(Model$fitted)
gr <- cbind(f, temp)
print(gr)
})
output$downloadData <- downloadHandler(
write.csv(gr, file, row.names = FALSE)
)
}
shinyApp(ui=ui,server=server)
It's hard to fully answer this without a minimal reproducibile example, but here's what I would try:
Create gr outside of renderPrint
Use gr() in downloadHandler
Rewrite downloadHandler to include content and filename arguments
Here's a minimal example with the same logic as your app, i.e. create a reactive dataframe which is both printed (renderPrint) and downloadable (downloadHandler).
library(shiny)
ui <- navbarPage(title = "Example",
tabPanel("First",
selectInput("fruit", "Fruit", c("apple", "orange", "pear")),
h4("Output from renderPrint:"),
textOutput("other_val_show"),
h4("Download Button: "),
downloadButton("downloadData")))
server <- function(input, output) {
gr <- reactive({
data.frame(fruit = input$fruit)
})
output$other_val_show <- renderPrint({
print(gr())
})
output$downloadData <- downloadHandler(
filename = "example.csv",
content = function(file) {
write.csv(gr(), file)
})
}
shinyApp(ui, server)
You define gr inside the scope of that renderPrint function so it isn't available to downloadHandler. You should define gr as a reactive value somewhere outside that function. That way, when you assign it in the renderPrint function, it will be accessible to the entire scope of your program.
In the future, it would be helpful to provide the text of any error messages you get - they are often quite helpful to solving problems.
I have seen that this problem has happened to other people, but their solutions have not worked for me. I have my app.R file and a .RData file with the required inputs in the same ECWA_Strategic_Planning_Tool directory. When I run:
library(rsconnect)
rsconnect::deployApp('C:/Users/mikialynn/Documents/Duke/Spring2017/MP/GISTool/Final/ECWA_Strategic_Planning_Tool')
I get the following error on the web page that opens up:
ERROR: An error has occurred. Check your logs or contact the app author for clarification.
However, I cannot find anything wrong. I install all of my packages, I use relative pathways etc. I am pasting all of the code from my app below. If anyone can spot what I'm doing wrong, I would greatly appreciate it!
library(shiny)
library(leaflet)
library(sp)
library(rgdal)
library(rstudioapi) # For working directory
library(raster)
library(RColorBrewer)
library(rgeos) #Maybe use gSimplify to simplify polygon
library(DT) #To make interactive DataTable
library(plotly) #For pie chart
library(ggplot2) # for layout
# Set Working Directory
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
# Load R Workspace
load('Shiny.Strategies.RData')
# UI variables
neigh.names <- levels(merge.proj$View)
neigh.default <- c("Urban7")
dt.names <- c('PARCEL_ID', 'PIN', 'OWNER_NAME', 'SITE_ADDRE', 'OWNER_ADDR',
'SUM_ACRE', 'LANDUSE_DE', 'LAND_VALUE', 'TOTAL_VALU', 'SALE_PRICE',
'Pluvial_WtScore', 'Rest_WtScore', 'GI_WtScore', 'SC_WtScore',
'UNCWI_WtScore', 'Total_Score', 'View')
dt.default <- c('PARCEL_ID', 'Pluvial_WtScore', 'Rest_WtScore',
'GI_WtScore', 'SC_WtScore', 'UNCWI_WtScore', 'Total_Score', 'View')
# Build UI
ui <- fluidPage(
titlePanel("ECWA Strategic Planning Tool"),
HTML('<br>'),
column(2,
HTML("<strong>Instructions:</strong><br/><br/>"),
HTML("<p>1) Select weights for parameters and click 'Run' to
initiate tool.<br/><br/>
2) Use rightside panel to adjust Table and Map Settings.<br/>
<br/>
3) Use search/sort functions of Table to identify parcels.
Select row to display Total Score Chart.<br/><br/>
4) Input View and Parcel ID from Table to Map settings to
identify parcel in Map.<br/><br/>
5) When satisfied with weights, click 'Export Shapefile' to
save shapefile of all parcels.<p/><br/>"),
HTML("<strong>Calculate Parcel Scores: </strong><br/>"),
helpText('The sum of the weights must equal to 1.'),
sliderInput(inputId = "weightPluvial", label = "Weight for Pluvial
Flooding",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightRest", label = "Weight for
Restoration",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightGI", label = "Weight for Green
Infrastructure",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightSC", label = "Weight for City
Stormwater Controls",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightUNCWI", label = "Weight for UNCWI",
value = 0.20, min = 0, max = 1),
actionButton("run", "Run"),
actionButton("export", "Export Shapefile")),
column(8,
HTML("<h3><strong>Table Summary</strong></h3>"),
HTML("<br>"),
dataTableOutput("table")),
column(2,
HTML("<p><br><br></p>"),
HTML("<h4>Table Settings:</h4>"),
checkboxGroupInput(inputId = 'show_vars', label = 'Select column(s)
to display in Table:', choices = dt.names, selected = dt.default),
HTML("<strong>Total Score Chart:</strong>"),
helpText("Please select Table row to display pie chart."),
plotlyOutput("pie")
),
fluidRow(
column(8, offset = 2,
HTML("<br>"),
HTML("<h3><strong>Map Display</strong></h3>"),
leafletOutput("map", height = 800),
HTML("<br><br>")),
column(2,
HTML("<p><br><br><br></p>"),
HTML("<h4>Map Settings:</h4>"),
checkboxGroupInput(inputId = 'show_neigh', label = 'Select
View(s) to display in Map:', choices = neigh.names,
selected = neigh.default),
HTML("<br>"),
sliderInput("range", "Select score range to display in Map:", min
= 0.0, max= 10.0, value = as.numeric(c("0.0", "10.0")), step = 0.1),
HTML("<br>"),
HTML("<strong>Parcel Zoom:</strong>"),
helpText("The View and Score Range must contain the parcel of
interest to execute zoom."),
numericInput('parcel','Enter Parcel ID',0)
)
))
# SERVER
server <- function(input, output) {
defaultData <-
eventReactive(input$run, {
# Multiply by Weights
merge.proj#data$Pluvial_WtScore <-
round(merge.proj#data$Pluvial_Score*input$weightPluvial, digits = 1)
merge.proj#data$Rest_WtScore <-
round(merge.proj#data$Rest_Score*input$weightRest, digits = 1)
merge.proj#data$GI_WtScore <-
round(merge.proj#data$GI_Score*input$weightGI, digits = 1)
merge.proj#data$SC_WtScore <-
round(merge.proj#data$SC_Score*input$weightSC, digits = 1)
merge.proj#data$UNCWI_WtScore <-
round(merge.proj#data$UNCWI_Score*input$weightUNCWI, digits = 1)
# Find Total Score
merge.proj#data$Total_Score <- merge.proj#data$Pluvial_WtScore +
merge.proj#data$Rest_WtScore + merge.proj#data$GI_WtScore +
merge.proj#data$SC_WtScore + merge.proj#data$UNCWI_WtScore
return(merge.proj)
})
# Subset by neighborhood
neighData <- reactive ({
merge.proj <- defaultData()
merge.proj[merge.proj$View%in%input$show_neigh,]
})
# Plot with leaflet
# Palette for map
colorpal <- reactive({
merge.proj <- neighData()
colorNumeric(palette = "YlOrRd",
domain = merge.proj$Total_Score)
})
# Pop Up Option for map
# popup <- paste0("<strong>Parcel ID: </strong>",
# merge.proj#data$PARCEL_ID,
# "<br><strong>Total Score: </strong>",
# merge.proj#data$Total_Score)
# Label Option for map
labels <- reactive({
merge.proj <- neighData()
sprintf("<strong>Parcel ID: </strong>%s<br/><strong>Total Score:
</strong>%g",
merge.proj$PARCEL_ID,
merge.proj$Total_Score) %>% lapply(htmltools::HTML)
})
# Render Default Map
output$map <- renderLeaflet ({
merge.proj <- neighData()
pal <- colorpal()
lab <- labels()
leaflet() %>%
#addProviderTiles(provider='Esri.WorldImagery') %>%
# setView(zoom =) %>%
addTiles() %>%
addPolygons(
#data = merge.proj[input$show_neigh,, drop = FALSE],
data=merge.proj,
fillColor = ~pal(Total_Score),
weight = 1,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 3,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
# popup= popup) %>%
label = lab,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(position = "bottomleft",pal = pal, opacity = 0.7, values =
merge.proj$Total_Score, title = "<strong>Total Score</strong>")
})
# Build Data Table
output$table <- renderDataTable({
merge.proj <- defaultData()
table.dat <- merge.proj[, c('PARCEL_ID', 'PIN', 'OWNER_NAME',
'SITE_ADDRE', 'OWNER_ADDR', 'SUM_ACRE', 'LANDUSE_DE', 'LAND_VALUE',
'TOTAL_VALU', 'SALE_PRICE', 'Pluvial_WtScore', 'Rest_WtScore', 'GI_WtScore',
'SC_WtScore', 'UNCWI_WtScore', 'Total_Score', 'View')]
datatable(data = table.dat#data[, input$show_vars, drop = FALSE],
options = list(lengthMenu = c(5, 10, 20, 30), pageLength = 20), rownames =
FALSE)
})
# Plot-ly
output$pie <- renderPlotly({
merge.proj <- defaultData()
names <- c('Pluvial', 'Rest', 'GI', 'SC', 'UNCWI')
colors <- c('rgb(128,133,133)', 'rgb(211,94,96)', 'rgb(144,103,167)',
'rgb(114,147,203)', 'rgb(171,104,87)')
selectedrowindex <-
input$table_rows_selected[length(input$table_rows_selected)]
selectedrowindex <- as.numeric(selectedrowindex)
df <- data.frame(merge.proj[selectedrowindex, c('Pluvial_WtScore',
'Rest_WtScore', 'GI_WtScore', 'SC_WtScore', 'UNCWI_WtScore')])
vector <- unname(unlist(df[1,]))
if (!is.null(input$table_rows_selected)) {
par(mar = c(4, 4, 1, .1))
plot_ly(labels = names, values = vector, type = 'pie',
textposition = 'inside',
textinfo = 'label+percent',
insidetextfont = list(color = '#FFFFFF'),
hoverinfo = 'text',
text = ~paste('Score:', vector),
marker = list(colors = colors,
line = list(color = '#FFFFFF', width = 1)),
#The 'pull' attribute can also be used to create space between the sectors
showlegend = FALSE) %>%
layout(#title = '% Total Score',
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
}
else {return(NULL)}
})
# Update map to parcel score slider
# Subset data
filteredData <- reactive({
merge.proj <- neighData()
merge.proj[merge.proj#data$Total_Score >= input$range[1] &
merge.proj#data$Total_Score <= input$range[2],]
})
# New Palette
colorpal2 <- reactive({
merge.proj <- filteredData()
colorNumeric(palette = "YlOrRd",
domain = merge.proj$Total_Score)
})
# Pop Up Option
# popup <- paste0("<strong>Parcel ID: </strong>",
# merge.proj#data$PARCEL_ID,
# "<br><strong>Total Score: </strong>",
# merge.proj#data$Total_Score)
# Label Option
labels2 <- reactive({
merge.proj <- filteredData()
sprintf("<strong>Parcel ID: </strong>%s<br/><strong>Total Score:
</strong>%g",
merge.proj$PARCEL_ID,
merge.proj$Total_Score) %>% lapply(htmltools::HTML)
})
#Leaflet Proxy
observe({
merge.proj <- filteredData()
pal2 <- colorpal2()
lab2 <- labels2()
leaf <- leafletProxy("map", data = filteredData()) %>%
clearShapes() %>%
addPolygons(
fillColor = ~pal2(Total_Score),
weight = 1,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 3,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
# popup= popup) %>%
label = lab2,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto"))
if(input$parcel>0){
sub.dat <- merge.proj[merge.proj$PARCEL_ID==input$parcel,]
zx <- mean(extent(sub.dat)[1:2])
zy <- mean(extent(sub.dat)[3:4])
leaf <- leaf %>%
setView(lng=zx,lat=zy,zoom=16)
}
leaf
})
#Update Legend
observe({
proxy <- leafletProxy("map", data = filteredData())
pal2 <- colorpal2()
proxy %>% clearControls()
proxy %>% addLegend(position = "bottomleft",pal = pal2, opacity = 0.7,
values = ~Total_Score, title = "<strong>Total Score</strong>")
})
# Export new shapefile
#make so that user can choose name and allow overwrite
observeEvent(input$export, {
merge.proj <- defaultData()
writeOGR(merge.proj, dsn = "Data", layer = "Strategies_Output", driver =
"ESRI Shapefile")
})
}
shinyApp(ui = ui, server = server)
Issue resolved! My initial suspicion was correct; it had to do with the .rdata file. It also relates to shinyapp.io's servers which run on a Linux based server. From my reading, Linux only handles lowercase file paths and extensions. The reason why it worked for the .csv file is because it's pretty common to have the file extension saved in all lowercase. This was not the case for the .RData file. Using the RStudio IDE and the physical "Save Workspace" button, the default file extension is .RData (case sensitive). I couldn't rename the file extension (for some reason, I'm not the most tech-savvy person). Similar to the load() function, there's the save() function. Previously, I used the save() file as follows (note the capitalized .RData at the end):
save(df_training_separated_with_models, file = "sample_data_with_models.RData")
However, using the same function in all lowercase fixes the issue:
save(df_training_separated_with_models, file = "sample_data_with_models.rdata")
Hope this helps any other poor soul with the same issue that is scouring the internet and other forums.
Cheers!
When I run my Shiny app, the headers of my data tables get shifted to the left. See below.Say this table is on Tab A.
The headers get aligned correctly when I click on a different tab (Tab B),then click on Tab A again. See below for the corrected headers.
Any idea what's causing it? Below is a simplified version of my code. Thanks in advance!
ui.R
library("shinythemes")
fluidPage(title = "Segmentation App", theme = shinytheme("spacelab"),
navbarPage("Segmentation", id = "allResults",
tabPanel(value='result_scorecard', title='ScoreCard',
sidebarLayout(
sidebarPanel(
h4("Select a cluster solution to profile"),
width = 3
),
mainPanel(
verticalLayout(
helpText(strong('Summary of Cluster Solutions')),
column(DT::dataTableOutput('out_best'), width = 12),
helpText(strong('ScoreCard Table')),
column(DT::dataTableOutput('out_scorecard'), width = 12)
)
)
)
),
tabPanel(value='profile', title='Profile',
verticalLayout(
column(DT::dataTableOutput('prop_by_cluster_ind'), width=10)
)
)
)
)
server.R
function(input, output, session) {
best_sols <- reactive({
A <- c(100, 101, 201)
B <- c(100, 101, 201)
C <- c(100, 101, 201)
temp <- as.matrix(cbind(A, B, C))
colnames(temp) <- c("A", "B", "C")
rownames(temp) <- c("k=1","k=2","k=3")
return(temp)
})
score_seg <- reactive({
A <- c("solution=1","solution=2","solution=3","solution=4","solution=5")
B <- c(100, 101, 201, 333, 444)
C <- c(100, 101, 201, 333, 444)
temp <- data.frame(A, B, C)
colnames(temp) <- c("A", "B", "score_seg")
return(temp)
})
profile_result_ind <- reactive({
A1 <- c("var1","var2","var3","var4","var5")
A2 <- c("var1","var2","var3","var4","var5")
B <- c(100, 101, 201, 333, 444)
C <- c(100, 101, 201, 333, 444)
temp <- data.frame(A1, A2, B, C)
colnames(temp) <- c("","","1","2")
return(temp)
})
# Table 1
output$out_best <- DT::renderDataTable({
DT::datatable(best_sols(), caption = "", rownames = TRUE, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(width = '100px', targets = 1)), paging = FALSE, searching = FALSE), selection='none') %>% formatRound(1:5, 3)
#}
})
# Table 2
output$out_scorecard <- DT::renderDataTable({
DT::datatable(score_seg(), caption = "", rownames = F, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(width = '200px', targets = 1)), paging = FALSE, searching = FALSE), selection='single') %>% formatRound(1:5, 3)
})
# Table 3
output$prop_by_cluster_ind <- DT::renderDataTable({
DT::datatable(profile_result_ind(), class= 'compact stripe', caption = '', rownames = F, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(width = '300px', targets = 1), list(className = 'dt-left', targets="_all")), paging = FALSE, searching = FALSE)) %>% formatStyle(as.character(seq(1:2)))
})
}
I figured it out.
The headers will be aligned correctly if we change the autoWidth option to FALSE.
I had a table with long rownames such as you and had a similar problem with offset column names, but setting autoWidth=FALSE did not solve the problem. I discovered that it was being caused by scrollX=TRUE. I changed ScrollX=FALSE and wrapped the datatable in a div with overflow-x=TRUE to regain the scroll feature:
div(style="overflow-x:auto",renderDataTable({tableName},options=list(scrollX=FALSE))