Is it safe to go outside?: Coronavirus on-peak/off-peak place indicator

One of the best behavioral strategies for mitigating the risk of coronavirus infection is “social distancing”. On the personal level, this means keeping a distance between yourself and others, ideally by staying at home.

But for most individuals staying at home isn’t possible 24/7, even if you have the luxury of working from home, sometimes you gotta go outside to do stuff. There are times when you must go outside, such as going to the grocery store to buy fresh produce. As individuals make the decision to venture outside to run these errands, they can minimize their risk of exposure (maximize their social distance) by visiting places at “off-peak” hours.

For a while now, Google Maps has been displaying the “popular times” for places like stores, restaurants, etc. And although the data isn’t accessible from the Google Maps API yet, for the time being it can be scraped using the populartimes python library.

So imagine you had a tool where, you could enter the name of a place (“Library in Hoboken, NJ”), and it would tell you whether it’s safe to visit using an algorithm like the following:

  • Take all the popularity values on this day (e.g., “Tuesdays”)
  • Calculate the mean (or median) popularity value
  • Take the current popularity value (the value for the current hour)
  • If the current popularity value is less than the average, then it’s “off-peak” and safe, otherwise it’s “on-peak” and unsafe

Something like the following:

png

Here I’ve drawn bars for the popularity for each hour in the current day. The current hour of the current day is highlighted in red, and a horizontal bar is drawn to indicate the on-peak/off-peak threshold (in this case, based on the mean). When the current hour bar is above the red line, then it’s on-peak and unsafe; when it’s below it’s off-peak and safe.

For full python code implementing this algorithm, see below.

Python code

Imports

import ipywidgets as widgets
import populartimes # https://github.com/m-wrzr/populartimes
import googlemaps
import json
import seaborn as sns
import pandas as pd
import numpy as np
from datetime import datetime
from pytz import timezone

api_key = 'API_KEY_GOES_HERE'

place_widget = widgets.Text(value='Library in Hoboken, NJ')
gmaps = googlemaps.Client(key=api_key)

Functions

# Take place name as text input, return place_id
def place_name_to_id(x):
    result = gmaps.find_place(input = x, 
                          input_type = "textquery",
                          fields = ['place_id'])
    return result['candidates'][0]['place_id']

# Take place_id as input, return current popularity value
# and all popularity values for today, excluding zero values
def get_populartimes(x):    
    daypref = ['Mon','Tues','Wednes','Thurs','Fri','Satur','Sun']
    current_weekday = datetime.today().weekday()
    current_hour = datetime.now(timezone('US/Eastern')).hour
    
    # Fetch data from populartimes
    pdata = populartimes.get_id(api_key, place_name_to_id(x))

    p_today = pdata['populartimes'][weekday_int]['data']
    p_now = ptimes_today['data'][int(current_hour)]
    
    hours = [i for i in range(0, 24)]
    df_pop = pd.DataFrame({'hour': np.array(hours), 'popularity': np.array(p_today)}, 
                           columns=['hour', 'popularity'])
    
    df_pop['now'] = False
    df_pop.loc[int(current_hour), 'now'] = True
    
    return {'pop_data': df_pop, 'current_hour': int(current_hour)}

# Fetch populartimes, then generate a plot
# showing the popularity of current time in relation
# to the mean popularity for this day
def plot_gen():
    p = get_populartimes(place_widget.value)
    
    colors = np.repeat("#34495e", 24)
    colors[p['current_hour']] = '#FF0000'

    plot = sns.barplot( x = 'hour', 
                        y = 'popularity', 
                        palette = list(colors),
                        data = p['pop_data'])

    median_pop = np.median(p['pop_data']['popularity'])
    off_peak = p['pop_data'].loc[p['current_hour'], 'popularity'] < median_pop
    if off_peak: 
        off_peak_label = 'YES'
    else: 
        off_peak_label = 'NO'

    # Plot a line at the mean popularity
    plot.axhline(np.mean(p['pop_data']['popularity']), ls='-', color='#FF0000')
    plot.set_title("Is it safe to go to\n" + place_widget.value + "?\n" + off_peak_label)

Is it safe to go outside?

Here the user would be presented with a text input where they could enter the name of a place. Then they could run this code chunk to generate output like the graph at the bottom.

display(place_widget) # Type place name in input box below
place_name_to_id(place_widget.value)
plot_gen()
Text(value='Library in Hoboken, NJ')

png