`Hello everyone,
My Rshiny app allows users to input data and show it interactively in the map and table. However, I want to allow user to upload his own coordinates file. then bind the other informations interactively. Simply put: User upload coordinates => see them on the map => click on given point on the map => coordinates will be added to the XY values(in the form) => user inputs other information => update the coordinates file he uploaded and see changes interactively to keep track of the remaining coordinates to complete. For this, I created a logical column called : Collected(0,1) to keep track of collected data.
Here is my Code. Thank your for your help.
C'A `
# Load the required package
library(shiny)
library(leaflet)
library(readxl)
## Generate coordinates files
data.frame( Date=as.Date(NA),
X=runif(n=100, min = 65, max=72),
Y=runif(n=100, min = 40, max=47),
Elevation= runif(n=100, min = 50, max=250),
Grid=NA,
Group=NA,
Line=NA,
Station=NA,
Activity=NA,
Comments=NA,
Collected=NA)|>
write.xlsx("Coordinates_files.xlsx")
# Create a data frame to store the collected data
collected_data <- data.frame(Date = as.Date(character()),
X = numeric(),
Y = numeric(),
Elevation = numeric(),
Grid = character(),
Group = numeric(),
Line = numeric(),
Station = numeric(),
Activity = character(),
Comments = character(),
collected=logical())
# Define UI
ui <- fluidPage(
titlePanel("Field Data Collection"),
sidebarLayout(
sidebarPanel(
fileInput(inputId = "coords_file", label = "Upload coordinate data set"),
dateInput(inputId = "date", label = "Date", value = Sys.Date()),
numericInput(inputId = "x", label = "X", value = 0),
numericInput(inputId = "y", label = "Y", value = 0),
numericInput(inputId = "elevation", label = "Elevation", value = 0),
textInput(inputId = "grid", label = "Grid Name", value = ""),
numericInput(inputId = "group", label = "Group Number", value = 0),
numericInput(inputId = "line", label = "Line Number", value = 0),
numericInput(inputId = "station", label = "Station Number", value = 0),
selectInput(inputId = "activity", label = "Activity Type",
choices = c("Walking", "Sampling", "Surveying")),
textInput(inputId = "comments", label = "Comments", value = ""),
actionButton(inputId = "submit", label = icon("check-circle", "Submit"))
),
mainPanel(
tabsetPanel(
tabPanel("Data Table", tableOutput(outputId = "data")),
tabPanel("Map", leafletOutput(outputId = "map"))
)
)
)
)
# Define server
# Define server
server <- function(input, output, session) {
# Define a reactive value to store the collected data
collected_data <- reactiveValues(df = data.frame(Date = as.Date(character()),
X = numeric(),
Y = numeric(),
Elevation = numeric(),
Grid = character(),
Group = numeric(),
Line = numeric(),
Station = numeric(),
Activity = character(),
Comments = character(),
Collected = logical()),
file_path = "")
# Function to update the map with new coordinates
update_map <- function(df) {
leaflet() %>%
addTiles() %>%
addMarkers(data = df, ~X, ~Y,
popup = ~paste("Station: ", Station, "<br>",
"Collected: ", ifelse(Collected, "Yes", "No")))
}
# Function to read in uploaded file
read_data <- reactive({
req(input$coords_file)
data <- read_excel(input$coords_file$datapath)
data
})
# Add an upload button for the user to import a file
observeEvent(input$coords_file, {
collected_data$df <- read_data()
update_map(collected_data$df)
collected_data$file_path <- input$coords_file$datapath
})
# Function to add a new row of data to the collected_data data frame
add_row <- function() {
new_row <- reactive({
data.frame(Date = as.Date(input$date),
X = input$x,
Y = input$y,
Elevation = input$elevation,
Grid = input$grid,
Group = input$group,
Line = input$line,
Station = input$station,
Activity = input$activity,
Comments = input$comments,
Collected = FALSE,
stringsAsFactors = FALSE)
})
collected_data$df <- rbind(collected_data$df, new_row())
updateActionButton(session, "submit", label = tags$i(class = "fa fa-check"))
}
# Create a reactive expression to store the mapped data for the day
mapped_data <- reactive({
if (!is.null(input$date)) {
subset(collected_data$df, Date == as.Date(input$date))
} else {
collected_data$df <- NA
}
})
# Update the map with the mapped data for the day
output$map <- renderLeaflet({
update_map(mapped_data())
})
# Show the collected data in the table
output$data <- renderTable({
collected_data$df
})
# Add new row to the collected_data data frame when the user clicks "Submit"
observeEvent(input$submit, {
add_row()
})
# Save the collected data to a CSV file when the app is closed
session$onSessionEnded(function() {
write.csv(collected_data$df, file = collected_data$file_path,
row.names = FALSE)
})
# Update data and map when user clicks on marker
observe({
req(collected_data$df)
if (input$map_marker_click$id != "NULL") {
clicked_id <- as.numeric(input$map_marker_click$id)
if (!is.na(clicked_id)) {
collected_data$df[clicked_id, "Collected"] <- TRUE
update_map(mapped_data())
}
}
})
}
shinyApp(ui, server)