I have a shiny app which displayes a leaflet heatmap. I would like to know if is possible to click on a certain point of the map and get the relative row(s) of the dataframe in a data table below.
library(shiny)
library(DT)
library(leaflet)
library(leaflet.extras)
# ui object
ui <- fluidPage(
titlePanel(p("Spatial app", style = "color:#3474A7")),
sidebarLayout(
sidebarPanel(
),
mainPanel(
leafletOutput("map"),
tableOutput("myTable")
)
)
)
# server()
server <- function(input, output, session) {
data <- reactiveValues(clickedMarker=NULL)
output$map<-renderLeaflet({
leaflet(quakes) %>%
addProviderTiles(providers$CartoDB.DarkMatter) %>%
setView( 178, -20, 5 ) %>%
addHeatmap(
lng = ~long, lat = ~lat, intensity = ~mag,
blur = 20, max = 0.05, radius = 15
) %>%
addCircleMarkers(lng = quakes$long, lat = quakes$lat, layerId = quakes$depth,
fillOpacity = 0, weight = 0,
popup = paste("Depth:", quakes$depth, "<br>",
"Stations:", quakes$stations),
labelOptions = labelOptions(noHide = TRUE))
})
# observe the marker click info and print to console when it is changed.
observeEvent(input$map_marker_click,{
print("observed map_marker_click")
data$clickedMarker <- input$map_marker_click
print(data$clickedMarker)
output$myTable <- renderTable({
return(
subset(quakes,depth == data$clickedMarker$depth)
)
})
})
}
# shinyApp()
shinyApp(ui = ui, server = server)
As update to my comment, I think the issue is that when you are trying to subset the dataset at the end, the rows you trying to match with are actually $id and not $depth - I think this is because when you call layerId = quakes$depth it creates an id to match on.
I think this does what you want:
library(shiny)
library(DT)
library(leaflet)
library(leaflet.extras)
# ui object
ui <- fluidPage(
titlePanel(p("Spatial app", style = "color:#3474A7")),
sidebarLayout(
sidebarPanel(
),
mainPanel(
leafletOutput("map"),
tableOutput("myTable")
)
)
)
# server()
server <- function(input, output, session) {
data <- reactiveValues(clickedMarker=NULL)
output$map<-renderLeaflet({
leaflet(quakes) %>%
addProviderTiles(providers$CartoDB.DarkMatter) %>%
setView( 178, -20, 5 ) %>%
addHeatmap(
lng = ~long, lat = ~lat, intensity = ~mag,
blur = 20, max = 0.05, radius = 15
) %>%
addCircleMarkers(lng = quakes$long, lat = quakes$lat, layerId = quakes$depth,
fillOpacity = 0, weight = 0,
popup = paste("Depth:", quakes$depth, "<br>",
"Stations:", quakes$stations),
labelOptions = labelOptions(noHide = TRUE))
})
# observe the marker click info and print to console when it is changed.
observeEvent(input$map_marker_click,{
print("observed map_marker_click")
data$clickedMarker <- input$map_marker_click
print(data$clickedMarker)
output$myTable <- renderTable({
return(
subset(quakes, depth == data$clickedMarker$id)
)
})
})
}
# shinyApp()
shinyApp(ui = ui, server = server)
giving:
If you check the console output you will see the id subsetted (not depth):
[1] "observed map_marker_click"
$id
[1] 46
$.nonce
[1] 0.3895379
$lat
[1] -13.66
$lng
[1] 172.23
Related
I am trying to make a shiny app where I can select a location on the map and display a gauge chart for each corresponding location.
I have been able to make the app reactive but the googlevis gauge display appears on the browser instead of in the app. In the app I get the error $ operator is invalid for atomic vectors. I tried converting the data into a dataframe but I am still getting this error.
the code is as follows
library(shiny)
library(leaflet)
library(shinydashboard)
library(dplyr)
library(googleVis)
#Making the Dataframe
locations<-c("A","B","C")
x<-c(36.05617,36.05626,36.05634)
y<-c(-2.1007,-2.05553,-2.01035)
yield<-c(5.86,3.06,1.07)
df<-data.frame(locations,x,y,yield)
################## Defining UI for application ############################
ui <- shinyUI(dashboardPage(title = "Yield Lookup",
dashboardHeader(title = "Crop Yield (Tonnes per Hectare)",titleWidth = 350),
dashboardSidebar(
sidebarMenu(
menuItem("Map Dashboard", tabName = "datavis", icon = icon("map", verify_fa = FALSE)),
menuItem("Select by Location Name", icon = icon("leaf"),
selectizeInput("locations", "Click on Location", choices = levels(factor(df$locations)))
)
)
),
dashboardBody(
tabItems(
tabItem(tabName = "datavis",
h4("Map and Plot"),
fluidRow(box(width= 8, leafletOutput("map", height = 800)),
box("Gauge for crop yield by area",width = 4, htmlOutput("myplot")))
)
)
)
)
)
################## Defining Server for application ############################
server<- shinyServer(function(input,output, session){
## Sub data
lo<-reactive({
})
locat_data <- reactive({
df[df$locations %in% input$locations,]
})
output[["myplot"]] <- renderGvis({
newdf<-locat_data()%>%select(locations, yield)
newdf<-as.data.frame(newdf)
Gauge <- gvisGauge(as.data.frame(newdf),
options=list(min=0, max=6, greenFrom=4,
greenTo=6, yellowFrom=2, yellowTo=4,
redFrom=0, redTo=2, width=400, height=300))
plot(Gauge)
})
output$map <- renderLeaflet({
leaflet(df) %>%
addTiles() %>%
addCircleMarkers(lng = ~x, lat = ~y, layerId = ~locations, color = "blue", radius = 3) %>%
addCircles(lng = ~x, lat = ~y, weight = 1,
radius = 1, label = ~locations
)
})
observeEvent(input$locations,{
updateSelectInput(session, "locations", "Click on Locations",
choices = levels(factor(df$locations)),
selected = c(input$locations))
})
observeEvent(input$map_marker_click, {
click <- input$map_marker_click
location <- df[which(df$y == click$lat & df$x == click$lng), ]$locations
updateSelectInput(session, "locations", "Click on Location",
choices = levels(factor(df$locations)),
selected = c(input$locations, location))
})
})
shinyApp(ui=ui, server = server)
I am not sure where I am going wrong. Please help.
You were very close.
Just drop the plot() and leave Gauge in the server section. (Alternatively drop the Gauge <- and Gauge on the next line and just leave gvisGauge())
library(shiny)
library(leaflet)
library(shinydashboard)
library(dplyr)
library(googleVis)
#Making the Dataframe
locations<-c("A","B","C")
x<-c(36.05617,36.05626,36.05634)
y<-c(-2.1007,-2.05553,-2.01035)
yield<-c(5.86,3.06,1.07)
df<-data.frame(locations,x,y,yield)
################## Defining UI for application ############################
ui <- shinyUI(dashboardPage(title = "Yield Lookup",
dashboardHeader(title = "Crop Yield (Tonnes per Hectare)",titleWidth = 350),
dashboardSidebar(
sidebarMenu(
menuItem("Map Dashboard", tabName = "datavis", icon = icon("map", verify_fa = FALSE)),
menuItem("Select by Location Name", icon = icon("leaf"),
selectizeInput("locations", "Click on Location", choices = levels(factor(df$locations)))
)
)
),
dashboardBody(
tabItems(
tabItem(tabName = "datavis",
h4("Map and Plot"),
fluidRow(box(width= 8, leafletOutput("map", height = 800)),
box("Gauge for crop yield by area",width = 4, htmlOutput("myplot")))
)
)
)
)
)
################## Defining Server for application ############################
server<- shinyServer(function(input,output, session){
## Sub data
lo<-reactive({
})
locat_data <- reactive({
df[df$locations %in% input$locations,]
})
output[["myplot"]] <- renderGvis({
newdf<-locat_data()%>%select(locations, yield)
newdf<-as.data.frame(newdf)
Gauge <- gvisGauge(as.data.frame(newdf),
options=list(min=0, max=6, greenFrom=4,
greenTo=6, yellowFrom=2, yellowTo=4,
redFrom=0, redTo=2, width=400, height=300))
Gauge
})
output$map <- renderLeaflet({
leaflet(df) %>%
addTiles() %>%
addCircleMarkers(lng = ~x, lat = ~y, layerId = ~locations, color = "blue", radius = 3) %>%
addCircles(lng = ~x, lat = ~y, weight = 1,
radius = 1, label = ~locations
)
})
observeEvent(input$locations,{
updateSelectInput(session, "locations", "Click on Locations",
choices = levels(factor(df$locations)),
selected = c(input$locations))
})
observeEvent(input$map_marker_click, {
click <- input$map_marker_click
location <- df[which(df$y == click$lat & df$x == click$lng), ]$locations
updateSelectInput(session, "locations", "Click on Location",
choices = levels(factor(df$locations)),
selected = c(input$locations, location))
})
})
shinyApp(ui=ui, server = server)
I would like to create a Leaflet Map which renders at a default location, at a zoom level of 4, and then when the user clicks the go button, pans from location to another, both of which have been selected from a dropdown.
I've tried using the following code, the data for which can be found # https://github.com/eoefelein/COVID_Business_Recovery_and_Social_Capital/tree/master/socialCapitalEmployment/data
library(sf)
library(tigris)
library(shiny)
library(shinydashboard)
library(tidyverse)
library(leaflet)
# data loading and processing
USA <- st_read(dsn = 'data/cb_2018_us_county_5m.shp')
counties_sf <- st_as_sf(USA)
counties_reproject_sf <- st_transform(counties_sf, 4326) %>% filter(COUNTYFP < 60010)
emp_rate <- read_csv('data/synthetic_emp_rate_pred.csv')
emp_rate$countyfips <- sprintf("%05d", emp_rate$countyfips)
states_sf_coef <- geo_join(counties_reproject_sf, emp_rate, "GEOID", "countyfips", how='inner')
ui <- fluidPage(
dashboardPage(
dashboardHeader(title="Employee Rate Data"),
dashboardSidebar(
sidebarMenu(
menuItem(
"Maps",
tabName = "maps",
icon=icon("globe")
)
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "maps",
tags$style(type="text/css","#all_airports {height:calc(100vh - 80px) !important;}"),
fluidRow(column(4),
column(8,
selectInput(inputId = "FromCounty",
label="from",
choices=c(unique(emp_rate$countyname)),
selected = 'Travis County, Texas'
),
selectInput(inputId = "ToCounty",
label = "to",
choices=c(unique(emp_rate$countyname))
))),
actionButton("zoomer","go"),
leafletOutput("map")
)
)
)
)
)
server <- function(input, output, session) {
# map
output$map <- renderLeaflet({
mypal <- colorNumeric(palette="viridis", domain=states_sf_coef$rand_pred, na.color="transparent")
# mypalette(c(45,43))
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 38.2393,
lng = -96.3795,
zoom = 4) %>%
addPolygons(
data = states_sf_coef,
fillColor = ~mypal(rand_pred),
# fillColor = ~ mypal(data$value),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3,
popup = paste(
"Region: ",
states_sf_coef$countyname,
"<br>",
"Social Index: ",
states_sf_coef$rand_pred,
"<br>"
)
)
# %>%
# addLayersControl(
# baseGroups = c("Employment Prediction Data (default)", "To-From"),
# options = layersControlOptions(collapsed = FALSE)
# )
})
map_proxy <- leafletProxy("map")
observeEvent(input$zoomer, { # add Smith, county, kansas and default to zoom = 1?
# fromCounty
fromCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$FromCounty)
})
fromData <- fromCountyInput()
fromCoords <- st_coordinates(st_centroid(fromData$geometry))
# toCounty
toCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$ToCounty)
})
toData <- toCountyInput()
toCoords <- st_coordinates(st_centroid(toData$geometry))
map_proxy %>%
flyTo(lng = fromCoords[1], lat = fromCoords[2], zoom = 10)
flyTo(lng = toCoords[1], lat = toCoords[2], zoom = 10)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Right now I'm getting the following error:
Warning: Error in dispatch: argument "map" is missing, with no default. Any guidance would be much appreciated!
I can't access your data to check that this works but I found a solution my (similar) problem by using shinyjs::delay(). This requires that you include the useShinyjs() in the ui as I have done below.
library(sf)
library(tigris)
library(shiny)
library(shinydashboard)
library(tidyverse)
library(leaflet)
library(shinyjs)
# data loading and processing
USA <- st_read(dsn = 'data/cb_2018_us_county_5m.shp')
counties_sf <- st_as_sf(USA)
counties_reproject_sf <- st_transform(counties_sf, 4326) %>% filter(COUNTYFP < 60010)
emp_rate <- read_csv('data/synthetic_emp_rate_pred.csv')
emp_rate$countyfips <- sprintf("%05d", emp_rate$countyfips)
states_sf_coef <- geo_join(counties_reproject_sf, emp_rate, "GEOID", "countyfips", how='inner')
ui <- fluidPage(
dashboardPage(
useShinyjs(),
dashboardHeader(title="Employee Rate Data"),
dashboardSidebar(
sidebarMenu(
menuItem(
"Maps",
tabName = "maps",
icon=icon("globe")
)
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "maps",
tags$style(type="text/css","#all_airports {height:calc(100vh - 80px) !important;}"),
fluidRow(column(4),
column(8,
selectInput(inputId = "FromCounty",
label="from",
choices=c(unique(emp_rate$countyname)),
selected = 'Travis County, Texas'
),
selectInput(inputId = "ToCounty",
label = "to",
choices=c(unique(emp_rate$countyname))
))),
actionButton("zoomer","go"),
leafletOutput("map")
)
)
)
)
)
server <- function(input, output, session) {
# map
output$map <- renderLeaflet({
mypal <- colorNumeric(palette="viridis", domain=states_sf_coef$rand_pred, na.color="transparent")
# mypalette(c(45,43))
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 38.2393,
lng = -96.3795,
zoom = 4) %>%
addPolygons(
data = states_sf_coef,
fillColor = ~mypal(rand_pred),
# fillColor = ~ mypal(data$value),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3,
popup = paste(
"Region: ",
states_sf_coef$countyname,
"<br>",
"Social Index: ",
states_sf_coef$rand_pred,
"<br>"
)
)
# %>%
# addLayersControl(
# baseGroups = c("Employment Prediction Data (default)", "To-From"),
# options = layersControlOptions(collapsed = FALSE)
# )
})
map_proxy <- leafletProxy("map")
observeEvent(input$zoomer, { # add Smith, county, kansas and default to zoom = 1?
# fromCounty
fromCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$FromCounty)
})
fromData <- fromCountyInput()
fromCoords <- st_coordinates(st_centroid(fromData$geometry))
# toCounty
toCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$ToCounty)
})
toData <- toCountyInput()
toCoords <- st_coordinates(st_centroid(toData$geometry))
map_proxy %>%
flyTo(lng = fromCoords[1], lat = fromCoords[2], zoom = 10)
delay(5000, {map_proxy %>% flyTo(lng = toCoords[1], lat = toCoords[2], zoom = 10)})
})
}
# Run the application
shinyApp(ui = ui, server = server)
In continuation to my previous post where this was applied on map, I am trying to filter a table in R Shiny using Dropdown input: How to build dynamic Leaflet Map in RShiny?
Code:
library(shiny)
library(shinydashboard)
library(tidyverse)
library(leaflet)
library(readxl)
library(RCurl)
library(DT)
URL <- "https://www.mohfw.gov.in/pdf/PMJAYPRIVATEHOSPITALSCONSOLIDATED.xlsx"
download.file(URL, destfile = "../../timesnow_PMJAYPRIVATEHOSPITALSCONSOLIDATED.xlsx",method = "curl")
# Data
ind_vaccination_center <- readxl::read_xlsx(path = "../../timesnow_PMJAYPRIVATEHOSPITALSCONSOLIDATED.xlsx",
sheet = 1)
ind_vaccination_leaflet <- ind_vaccination_center %>%
mutate(label_display = paste(
"<h2>", ind_vaccination_center$`Name of the Vaccination Site*`, "</h2>",
"<h4>",ind_vaccination_center$`District*`,",", ind_vaccination_center$`State*`, "</h4>",
"<p>", "Address: ", ind_vaccination_center$Address,",", ind_vaccination_center$`PinCode*`, "</p>",
"<p>", "Mobile: ", ind_vaccination_center$`Mobile Number`, "</p>",
"<p>", "Contact Person: ", ind_vaccination_center$`Contact Person`, "</p>"
)
)
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Covid19 Vaccination Centers in India"),
# Sidebar with a Dropdown
sidebarLayout(
sidebarPanel(
selectInput(inputId = "state_selection",
label = "Select State",
choices = ind_vaccination_center$`State*`),
h3("List of Vaccination Centers is plotted on Map & also listed in searchable table."),
"source of list:",
a("https://www.timesnownews.com/india/article/covid-19-vaccination-in-uttar-pradesh-check-complete-list-of-govt-and-private-hospitals-for-jab/726412"),
br(),
br(),
a("https://www.oneindia.com/india/full-list-of-private-hospitals-where-the-covid-19-vaccine-will-be-administered-3223706.html"),
br(),
br(),
"P.S - There might be more center's added to this list, kindly recheck from other sources as well like:",
br(),
a("https://www.cowin.gov.in/home")
),
# Show Map & table
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Map", leafletOutput("map",height = 800, width = "100%")),
tabPanel("Data Table", tableOutput("mytable"))
)
)
)
)
# Define server logic
server <- function(input, output) {
# solution from: https://stackoverflow.com/questions/66732758/how-to-build-dynamic-leaflet-map-in-rshiny/66733086#66733086
output$map <- renderLeaflet({
req(input$state_selection)
data <- ind_vaccination_leaflet %>%
filter(`State*` == input$state_selection)
# Creating map object & adding layers
leaflet(data) %>%
setView(lat = 26.64510, lng = 80.17012, zoom = 4) %>%
addTiles(group = "OSM") %>%
addProviderTiles(providers$CartoDB.DarkMatter, group = "Dark") %>%
addProviderTiles(providers$CartoDB.Positron, group = "Light") %>%
addProviderTiles("Stamen.Terrain", group = "Terrain") %>%
addProviderTiles("Esri.WorldImagery", group = "WorldImagery") %>%
addLayersControl(baseGroups = c("OSM","WorldImagery","Dark","Light","Terrain")) %>%
addCircleMarkers(
lng = ~`Longitude*`,
lat = ~`Latitude*`,
label = lapply(data$label_display, htmltools::HTML),
color = "midnightblue",
weight = 1,
radius = 8
)%>%
addMiniMap(tiles = providers$OpenStreetMap, width = 120, height=80)
})
output$mytable = DT::renderDataTable({
req(input$state_selection)
data <- ind_vaccination_leaflet %>%
filter(`State*` == input$state_selection)
data
})
}
# Run the application
shinyApp(ui = ui, server = server)
You need to do two changes.
tabPanel("Data Table", dataTableOutput("mytable"))
and
output$mytable = DT::renderDataTable({
req(input$state_selection)
data <- ind_vaccination_leaflet %>%
filter(`State*` == input$state_selection)
datatable(data)
})
I want to display my marker labels based on zoom level.
Based on (https://rstudio.github.io/leaflet/shiny.html) I tried to use "input$MAPID_zoom". In my example, labels stored in location_name should be displayed when zoom level (mapscale) is lower to 6.
What I tried :
library(shiny)
library(leaflet)
# my data
df <- data.frame(
location_name = c('S1', 'S2'),
lng = c(-1.554136, -2.10401),
lat = c(47.218637, 47.218637),
stringsAsFactors = FALSE)
# UI
ui <- shinyUI(fluidPage(
leafletOutput('map')
))
# server
server <- shinyServer(function(input, output, session) {
mapscale <- observe({
input$map_zoom # get zoom level
})
output$map <- renderLeaflet({
leaflet() %>%
addTiles() %>%
addMarkers(data=df, lng = ~lng, lat = ~lat,
label =~if(mapscale<6, location_name))
})
})
shinyApp(ui = ui, server = server)
A few remarks on your code if you like.
If you wrap the zoom in a reactive function, reference it like mapscale(). Use the normal if statement in R and the ~ in front of the variable. Then you should be fine.
Reproducible example:
library(shiny)
library(leaflet)
df <- data.frame(
location_name = c('S1', 'S2'),
lng = c(-1.554136, -2.10401),
lat = c(47.218637, 47.218637),
stringsAsFactors = FALSE
)
ui <- shinyUI(
fluidPage(
leafletOutput(outputId = 'map')
)
)
server <- shinyServer(function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>%
addTiles()
})
observeEvent(
eventExpr = input$map_zoom, {
print(input$map_zoom) # Display zoom level in the console
leafletProxy(
mapId = "map",
session = session
) %>%
clearMarkers() %>%
addMarkers(
data = df,
lng = ~lng,
lat = ~lat,
label = if(input$map_zoom < 6) ~location_name
)
}
)
})
shinyApp(
ui = ui,
server = server
)
I am trying to add two different markers for two different inputs. I got the first one working but not for the second one. Here is my code
ui.R
library(shiny)
library(leaflet)
shinyUI(fluidPage(
# Application title
titlePanel("Aspen GBS Population Structure results on map"),
# Side bar layout
sidebarLayout(
sidebarPanel(
selectInput("structure", label = "Select K for display", choices = c("2", "3", "4", "5", "6"), selected = "2"),
checkboxInput("origin", label = "Flood path")),
mainPanel(
leafletOutput("map")
)
)
)
)
server.R
leafIcons <- icons(
iconUrl = ifelse(data_K2$FP_Icon == "greenleafIcon",
"http://leafletjs.com/docs/images/leaf-green.png",
"http://leafletjs.com/docs/images/leaf-red.png"
),
iconWidth = 38, iconHeight = 95,
iconAnchorX = 22, iconAnchorY = 94,
shadowUrl = "http://leafletjs.com/docs/images/leaf-shadow.png",
shadowWidth = 50, shadowHeight = 64,
shadowAnchorX = 4, shadowAnchorY = 62
)
library(shiny)
shinyServer(function(input, output, session) {
dt <- reactive(
switch(input$structure,
"2" = data_K2$Structure.2,
"3" = data_K2$Structure.3))
output$map <- renderLeaflet(
leaflet(data = data_K2) %>% addTiles() %>% setView(lng = -106.1039361,lat = 50.543981, zoom = 4) %>%
addCircleMarkers(lat = ~Lat, lng = ~Long, popup = ~Location_discription, radius=2, color = ~dt(), fill = TRUE) %>%
addMarkers(lat = ~Lat, lng = ~Long, popup = ~Location_discription, icon = leafIcons)
)
})
I want the addMarkers to get activated when i use the checkboxInput button only. But right now it is selected by default.
I've found the easiest way is to label the markers with groups, then just show/hide them on input. That way you save some computation, and leaflet is designed to do this with leafletProxy (it's well documented on the Rstudio guide). You would need to add an observer as well that would update the map, as in this example,
library(shiny)
library(leaflet)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
checkboxInput("show", "Show/Hide")
),
mainPanel(
leafletOutput("map")
)
)
))
dat <- data.frame(lng = rnorm(3, -106.1039361, 0.5) ,
lat = rnorm(3, 50.543981, 0.5))
server <- shinyServer(function(input, output, session) {
## Your map, give the markers groups
output$map <- renderLeaflet(
leaflet(data = dat) %>%
addTiles() %>% setView(lng = -106.1039361,lat = 50.543981, zoom = 4) %>%
addCircleMarkers(group="circles",
popup = ~paste(lat), radius=2, fill = TRUE) %>%
addMarkers(group="markers")
)
## Observer to update map on input
observeEvent(input$show, {
proxy <- leafletProxy('map')
if (input$show) proxy %>% showGroup('markers')
else proxy %>% hideGroup('markers')
})
})
shinyApp(ui, server)