Photo by Terabass from wikimedia

Almost everyone is familiar with the phrase “location, location, location” when evaluating a property. Being mindful of location when purchasing out of home advertising placements is key to running successful outdoor campaigns. Python and the Here.com API can assist in location research when purchasing outdoor media (billboards, bulletins, and digital signage) remotely or when there are many locations to research. The full code an be found on GitHub.

This post outlines a method for querying nearby places corresponding to a set of geographical coordinates associated with out of home media placements. Researching nearby places can enable you to determine whether the location is brand friendly and consistent with your campaign messaging and target audience.

There are 3 files that you’ll need:

  • credentials.yaml
  • boards.csv
  • proximity_ooh.py

credentials.yaml

The file credentials.yaml is where you’ll specify your app id and app credentials to authorize access to the Here.com API.

boards.csv

The file boards.csv should contain data about the outdoor media placements that you’re interested in researching. In the template there are four columns, Media, Location, Latitude, and Longitude. The sample entry is for a placement in Times Square. The data for this row is Billboard, One Times Square, 40.7564, -73.9865. Usually the outdoor media seller will provide you with this information.

proximity_ooh.py

The file proximity_ooh.py is the python script that will query places nearby the coordinates associated with each placement. The script will then create a text file for each placement that lists places at or nearby those geographical coordinates.

First import the following packages:

import herepy
import yaml
import pandas
import re

Next define helper functions. The places_init function will load your API credentials from the yaml file. The at_nearby function will query the Here.com API for places at and places nearby the coordinates associated with a placement. The requests are then stored as dictionaries. The data associated with the keys title, position, distance, and vicinity are then written to a file named after the corresponding row in the Location column in boards.csv. The function at_nearby is written with a functional programming approach. It is later used with the map function in the WriteResults function.

places_init

def places_init(filename):
    '''
    Initialize Here.com Places API with credentials from yaml file
    :param filename:  string for file containing credentials in yaml format
    :return:
    '''

    with open(filename, 'r') as f:
        credentials = yaml.safe_load(f)
        f.close()

    app_id = credentials['app_id']
    app_code = credentials['app_code']

    return(herepy.PlacesApi(app_id, app_code)

at_nearby

def at_nearby(desc, lat, long, fmts='\.|\/'):
    '''
    Write nearby places and places at out of home placements to text files.
    :param desc: name of the column containing placement description in filename
    :param lat: name of the column containing latitude in filename
    :param long: name of the column containing longitude in filename
    :param fmts: regular expression for characters to remove from desc when writing to file
    :return: None
    '''

    desc = re.sub(fmts, '', desc)
    fname = desc + '.txt'
    coordinates = [lat, long]

    at_request = placesApi.places_at(coordinates)
    at_request = at_request.as_dict()
    # at_response = json.dumps(at_request, sort_keys=True, indent=4)

    nearby_request = placesApi.nearby_places(coordinates)
    nearby_request = nearby_request.as_dict()
    # nearby_response = json.dumps(nearby_request, sort_keys=True, indent=4)

    with open(fname, 'w') as f:
        f.write('NEARBY \n\n')
        for entry in nearby_request['results']['items']:
            f.write(str(entry['title'])+'\n')
            f.write(str(entry['position'])+'\n')
            f.write(str(entry['distance'])+'\n')
            f.write(str(entry['vicinity'])+'\n\n')

        f.write('PLACES AT \n\n')
        for entry in at_request['results']['items']:
            f.write(str(entry['title'])+'\n')
            f.write(str(entry['position'])+'\n')
            f.write(str(entry['distance'])+'\n')
            f.write(str(entry['vicinity'])+'\n\n')
        f.close()

WriteResults

The write results function will read the input .csv (in this example boards.csv) and write query results for nearby places’ title, position, distance, and vicinity to text files. There will be one text file for every row (i.e. out of home placement) in the input csv.

def WriteResults(filename, desc, lat, long):
    '''
    Read input csv and call at_nearby function to write results to text files
    One text file for every row (i.e. placement) in the input csv
    :param filename: string of the filename containing out of home placements in .csv format
    :param desc: name of the column containing placement description in filename
    :param lat: name of the column containing latitude in filename
    :param long: name of the column containing longitude in filename
    :return: None
    '''
    activations = pandas.read_csv(filename, skipinitialspace=True)

    activation_description = activations[desc]
    activations_latitude = activations[lat]
    activations_longitude = activations[long]

    list(map(at_nearby, activation_description, activations_latitude, activations_longitude))

Finally, we run the sample example by calling the places_init function and then calling WriteResults.

placesApi = places_init(filename='credentials.yaml')
WriteResults(filename='boards.csv', desc='Location', lat='Latitude', long='Longitude')

Below is a truncated version of our results that will appear in the file One Times Square.txt

NEARBY

Nypd
[40.756376, -73.986431]
6
7th Ave<br/>New York, NY 10036

Iscream by Ice & Vice
[40.75628, -73.98647]
14
Broadway<br/>New York, NY 10036

BMO Bank of Montreal
[40.756274, -73.986393]
17
1485 Broadway<br/>New York, NY 10036

And further along in the file:

PLACES AT

Bubba Gump Shrimp Co
[40.75701, -73.98621]
72
1501 Broadway<br/>New York, NY 10036

Levi’s
[40.7571, -73.9864]
78
1501 Broadway<br/>New York, NY 10036

Tony’s di Napoli
[40.75641, -73.98547]
87
147 W 43rd St<br/>New York, NY 10036

H&M
[40.75603, -73.98573]
77
1472 Broadway<br/>New York, NY 10036

With this output we can get a sense of what other business and points of interest are around our the prospective billboard. This information can aid in determining whether the billboard is a good fit for a campaign and negotiating rates.