Skip to content
Switch branches/tags
Go to file
add floor data and adjusted bar plot
7 contributors

Users who have contributed to this file

@knissk @chenc29 @erickj4 @zhaox9 @paranr @mayerm2 @demasm
## Data Incite RPI Study Safe App using UI Template
# Uses Shinydashboard as a framework
# UI Template Created by Arielle Cerini, Brian Hotopp, Haoyu He, and James Young
# Edited by Kara Kniss
# Version: 15 Mar 2021
options(dplyr.summarise.inform = FALSE)
options(tidyverse.quiet = TRUE)
#document for reading in the relevant libraries, data, and cleaning
# source('read_wapData_vol.R') # Use for production deployment
source('read_wapData.R') # Use for dev
# Data for Roma's additions
buildinghoursAccessInfo <- read_csv("buildinghoursAccessInfo.csv")
# Suppress those dplyr warnings
survey_url <- tags$a("survey", href = "", style = 'color: #990000; background-color: #FAFAFA')
usability_study_url <- tags$a("usability study", href = "", style = 'color: #990000; background-color: #FAFAFA')
ui <- dashboardPage(skin = "black", title = "RPI StudySafe",
dashboardHeader(title = tags$div(
class = "title-text",
tags$style(".logo {max-width: 80%;}"),
tags$div(id = "logo_block", tags$img(class="logo", src="Rensselaer.png", id="Rensselear Polytechnic Institute Logo") )),
titleWidth = "340px"
width = 320,
sidebarMenu(id = "tabs", collapsed = TRUE,
menuItem("Find a Place to Study", tabName = "week_activity"),
menuItem("About", tabName = "about"),
box(width= 12, collapsible = TRUE, title = tags$div(HTML("<span style = 'color: #54585a '>Feedback Forms</span>")),
style = 'color: #54585a;', solidHeader=TRUE,
tagList("Have any comments? Please follow the link to",
"this", survey_url, "and let us know if you have any",
" issues, questions, or suggestions regarding",
" the StudySafe app."),
tags$br(), tags$br(),
tagList("Help us make the app better! Take a few",
"minutes to participate in our ",usability_study_url, ".")
style = "background-color: #f7f7f7; height: 100%; min-height: 100vh;",
tabItem(tabName = "about",
HTML("<h1 style = 'text-align: left'>About <span style = 'color:#54585a'>RPI</span> <b><span style = 'color: #990000;'>StudySafe</span></b></h1>
<div style='margin-left: 5%'>
<p>RPI StudySafe is an app that reveals the anonymous usage of Wi-Fi access points and aggregations of wireless users on
the campus network at <a href = ''; style = 'color: #990000; background-color: #f7f7f7'>Rensselaer Polytechnic Institute</a>,
Troy, New York. Analysis and visualizations are by students and staff of
<a href = ''; style = 'color: #990000; background-color: #f7f7f7'>The Rensselaer Institute for Data Exploration and Applications (IDEA)</a>.
This is an app associated with the COVID-19 contact tracing and campus network mapping projects.</p>
<p>RPI StudySafe is designed to present WAP data to on-campus users so they can make informed decisions on where to go for extended periods of time on campus.
The data can be interacted with in several ways, including selecting certain dates, times, locations, as well as through interactive geographical maps.
Geographic location and density of each WAP are combined by building, and the data is updated every two hours.</p>
<h4 style = 'text-align: left'>Find a Place to Study </h4>
<div style='margin-left: 1%'>
<p>The \"Find a Place to Study\" tab includes two visualizations: </p>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<li> A map of the RPI campus.</li>
<li> A barplot of WiFi access throughout the day.</li>
</ol> </span>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<p><h3 style = 'text-align: left'>How to Customize the Visualizations</h3></p>
Users can customize both visualizations in the \"Find a Place to Study\" pop-up menu with the following:</span>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<li>Building: To change the building, select the dropdown menu under <b> Choose a Building</b>.</li>
<li>Activity: If you would like to list the building options in the dropdown menu by activity rather than type, turn on the <b>List by Activity</b> button.</li>
<li>Day: To select a day within the past seven days, click on the tab of the day you would like to view.</li>
<li>Time: You will see that the current time is automatically the default time and is highlighted in pink on the barplot. To view a different time, simply click on any other bar, and the visualizations will automatically update.</li>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<p><h3 style = 'text-align: left'>Detailed Map Description</h3></p></span>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<li>The map displays a pin for each building on campus. </li>
<li>The color of the pin represents the individual building's percentage capacity at the time selected. The legend in the top left corner specifies the meaning of each color. </li>
<li>The user may click on any pin on the campus map to view more detailed information for that building with the barplot in the pop-up menu on the right. The selected building pin will be green once selected.</li>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<p><h3 style = 'text-align: left'>Detailed Barplot Description</h3></p></span>
<span style = 'padding-bottom: 6.9px; font-size: 1.2em;line-height: 1.6em;font-weight: 400;color: #6e6e6e;'>
<li>The barplot displays the WiFi access in terms of percentage of capacity for every hour throughout the day. </li>
<li>The current time is highlighted in pink, and the user may view any other time by simply clicking on a different bar.</li>
<li>Above the barplot, a short message will summarize the current situation of the building:
<li>If the building is less than 25% capacity, the message will read \"usually not busy\".</li>
<li>If the building is between 25% to 50% capacity, the message will read \"usually not too busy\".</li>
<li>If the building is between 50% to 75% capacity, the message will read \"usually a bit busy\".</li>
<li>If the building is above 75% capacity, the message will read \"usually as busy as it can get\".</li>
<li>The user may also move the \"Find a Place to Study\" pop-up menu around by dragging it to the desired position.</li>
<h4 style = 'text-align: left'>DISCLAIMERS</h4>
<div style='margin-left: 1%'>
<p>Some of the information displayed is approximated and/or may not be 100% accurate as it is an approximation of imperfect data.
Improvements to this application will continue to be made. </p>
HTML("<footer text-align: center; '>
<h1 style = 'color:#990000; font-size: 1.5em;'>
<a href=''; style = 'color: #990000; background-color: #f7f7f7;'>About IDEA</a>
<a href=''; style = 'color: #990000; background-color: #f7f7f7;'>Privacy Policy</a>
<a href=''; style = 'color: #990000; background-color: #f7f7f7;'>GitHub</a>
# Find a place to study
tabItem(tabName = "week_activity",
fluidRow(column(h4(textOutput('MT_title_summary'), style = 'color: #d6001c'),width =12)),
tags$style(type="text/css", '#campusMap {height: 65vh; margin: auto;}'),
tags$style(type='text/css', "#click_on_map {text-align:center; font-size: 25px;}"),
tags$style(type="text/css", '#barPanel {width: 60vw; margin: auto;}'),
# shinyjs::hidden(
tags$div(id = "barPanel",
fluidRow(column(width = 6, h2("Find a Place to Study")),
column(width = 6, div(style = "display:inline-block; float:right", actionButton(inputId = "submit_find", label = "Close Panel")))),
fluidRow(column(width = 6, pickerInput(inputId = 'user_selected_building', label = tags$div(HTML("<b><span style = 'color: #54585a'>Choose a Building</span></b>")),
options = list(`live-search` = TRUE),
choices = byCat_single)),
column(width = 6, pickerInput(inputId = "user_selected_day", label = tags$div(HTML("<b><span style = 'color: #54585a'>Choose a Day</span></b>")),
choices = weekdays(Sys.Date()+0:6)))),
prettySwitch(inputId = 'byActivity', inline = TRUE,
label= tags$div(HTML("<b><span style = 'color: #54585a'>List by Activity</span></b>")),
value = FALSE, status = "default", fill = TRUE, bigger = TRUE),
uiOutput("busy_info", align = "center"),
uiOutput("BuildingInfo", align = "center"),
plotOutput("hourly_crowd", click = "pick_time", height="20vh"),
h1("StudySafe uses near-real-time, anonymous WiFi data from the last 3 weeks")),
$(document).ready(function() {
$(\'head\').append(\'<link rel="stylesheet" href="" type="text/css" />\');
$(\'head\').append(\'<link rel="stylesheet" href="brand_style.css" type="text/css" />\');
$("header").find("nav").append(\'<p style="font-size: 200%; text-align: center;">RPI<b><span style = "color: #990000;"><span style="padding-left:2px; padding-right: 2px;">StudySafe</span></span></b></p>\');
// $(".sidebar-toggle").insertAfter(".tab-content");
# Define server logic required
server <- function(input, output, session) {
#Activity Tagging Switch
observeEvent(input$byActivity, {
if (input$byActivity == FALSE) {
updatePickerInput(session, inputId = "user_selected_building", choices = byCat_single, selected = input$user_selected_building)
} else {
updatePickerInput(session, inputId = "user_selected_building", choices = byAct_single, selected = input$user_selected_building)
application_state <- reactiveValues()
# set the initial application state
application_state$day <- weekdays(Sys.Date())[1]
application_state$time <- as.integer(format(Sys.time(), "%H"))
application_state$building <- "Amos Eaton"
output$click_on_map <- renderText({paste("Click on any marker on the map for more information!")})
# if the user selected day changes, update the application state
observeEvent(input$user_selected_day, {
application_state$day <- input$user_selected_day
# if the user selected time changes, update the application state
observeEvent(input$pick_time, {
# shiny returns the time in input$pick time since it's what we used as the axis
application_state$time <- floor(as.numeric(input$pick_time$x) - as.numeric(input$pick_time$domain$left))
# if the user selected building changes, update the application state
observeEvent(input$user_selected_building, {
application_state$building <- input$user_selected_building
# if the user clicks a building on the map, update the picker
# updatePickerInput updates input$user_selected building which triggers the above observer and updates the application state
observeEvent(input$campusMap_marker_click, {
# get the buliding clicked from the lat and long of the marker
clicked_lat = input$campusMap_marker_click$lat
clicked_lng = input$campusMap_marker_click$lng
data <- user_predictions %>% filter(weekday == application_state$day & lng == clicked_lng & lat == clicked_lat)
building <- (data$Building)[1]
updatePickerInput(session, inputId="user_selected_building", selected=building)
leafletProxy("campusMap") %>% clearGroup(group="selected") %>% addAwesomeMarkers(icon= icon, lat=clicked_lat, lng=clicked_lng, group="selected")
shinyjs::showElement(id= "barPanel")
# if user close the bar plot panel
observeEvent(input$submit_find, {
shinyjs::hideElement(id= "barPanel")
# main leaflet map
output$campusMap <- renderLeaflet({
data <- user_predictions %>% filter(weekday == application_state$day)
point <- data %>% filter(Building == application_state$building) %>% select(lat,lng) %>% unique()
map_info <- get_map_info(data, application_state$time, hits_per_wap_semester_by_building_max)
leaf_map <- get_map(map_info, point$lat, point$lng)
leaf_map %>% addAwesomeMarkers(icon= icon, lat=point$lat, lng=point$lng, group="selected")
# "google-maps" style plot
output$hourly_crowd <- renderPlot({
# get data to feed into make_plot
data <- user_predictions_fl %>% filter(weekday == application_state$day & Building == application_state$building)
# browser()
make_plot(data, application_state$time, application_state$building, hits_per_wap_semester_by_building_max)
}, bg="transparent")
# print information on how busy the building is
output$busy_info <- renderUI({
data <- user_predictions %>% filter(weekday == application_state$day & Hour == application_state$time & Building == application_state$building)
text <- busy_text(data, application_state$building, hits_per_wap_semester_by_building_max)
time_ampm <-[application_state$time+1,2]
p("At", time_ampm, " ", application_state$building,"is", text)
output$BuildingInfo <- renderUI({
if(application_state$building %in% buildinghoursAccessInfo$Building ){
#paste("You have selected" , building_select)
{stringr::str_c(application_state$building, "hours: ",buildinghoursAccessInfo[buildinghoursAccessInfo$Building == application_state$building, ]$TimeZone,
', Access:',
buildinghoursAccessInfo[buildinghoursAccessInfo$Building == application_state$building, ]$Mode, sep = " ")}
paste("Building hours and access information for", application_state$building, "are not available at this time")
#paste("You have selected" , building_select)
# print title block
output$MT_title_summary <- renderText({
time_ampm <-[application_state$time+1,2]
stringr::str_c("RPI on ", application_state$day,' at ', time_ampm)
# Content of modal dialog
query_modal <- modalDialog(
title = tags$div(HTML("<h2><span style = 'color: #54585a; text-transform: capitalize;'>Welcome to RPI</span><b><span style = 'color: #990000; text-transform: capitalize;' > StudySafe</span></b></h2>")),
tags$div(HTML("<span style = 'font-weight: 400;color: #6e6e6e;'>
<p><b>WARNING:</b> The StudySafe application represents experimental, student-created work. Reasonable
effort has been made to provide a safe, informative, enjoyable user experience, but
some StudySafe application features may not comply with Web Content Accessibility Guidelines (WCAG).
<i>Use at your own risk.</i></p>
</span> ")),
easyClose = F,
footer = tagList(
actionButton("run", "Continue to StudySafe", style = ' color: white; background-color:#990000')
# Creates modal dialog
# Removes modal
observeEvent(input$run, {
# Run the application
shinyApp(ui = ui, server = server)