Lab 5: Maps & More Maps

In this lab, you’ll be using everything you’ve learned about tables (and some of what you’re learning about lists) to create a data visualization tool. Specifically, you’ll use a dataset of active Providence business licenses published by the Rhode Island government to mark locations on a map.

A key goal of this lab is to give you practice breaking large problems into separate tasks, each of which gets handled with its own collection of functions, expressions, and operators. As you work on the problems, practice writing out the lists of tasks and using those to guide your work.

Part 1: Making a Simple Map

Question 1.1: Loading the data

Before you start working with the data, take a look at the Providence Business License dataset. The first sheet (inside the file) is the original dataset, and the second sheet is a pruned version with only the columns you’ll need for this lab. Load the pruned sheet into Pyret by pasting the following code into the definitions window:

include image
include shared-gdrive("cs111-2019.arr", "1JXQztpDCkTv2WRnQCjO7RGUgFv3pfgsB")
include gdrive-sheets
import data-source as ds
include shared-gdrive("stencil.arr", "1W61RYJDms4y-1tP_oQ9igydaYr-nmHCr")
include image-structs
import lists as L

##############
# SETUP CODE #
##############

ssid = "18eKc_o-eZ8TWno6ePYkcMGKhx-Y2Fe8LEERqV5gClaU"
data-sheet = load-spreadsheet(ssid)
pvd-businesses = 
  load-table: license-id, name, extended-hours, hotel, parking, 
    restaurant, food-and-liquor, food-dispenser, lat, long
    source: data-sheet.sheet-by-name("Licenses_Pruned", true)
    sanitize license-id using ds.string-sanitizer
    sanitize name using ds.string-sanitizer
    sanitize extended-hours using ds.bool-sanitizer
    sanitize hotel using ds.bool-sanitizer
    sanitize parking using ds.bool-sanitizer
    sanitize restaurant using ds.bool-sanitizer
    sanitize food-and-liquor using ds.bool-sanitizer
    sanitize food-dispenser using ds.bool-sanitizer
    sanitize lat using ds.num-sanitizer
    sanitize long using ds.num-sanitizer
  end

Question 1.2: Generate a Map

We have provided you with a function table-to-map(t :: Table) -> Image that takes in a table with columns named "x", "y", and "color". Treat table-to-map like a built-in function; you can call it just like you called filter-by or any other built-in function in previous labs. Each row of the table represents a business at location (x,y) on the map. table-to-map takes a map of Providence and places a dot of the specified color at location (x,y) on the map. Its final output should look something like this:

To use table-to-map, you will need to convert the longitude and latitude values in the table to x- and y-coordinate values. Only locations that fit within the bounds of the Providence map can be included. We’ve defined the following values for you in the stencil.arr file that the setup code includes:

LAT-MIN - the minimum latitude that fits the map
LAT-MAX - the maximum latitude that fits the map

LON-MIN - the minimum longitude that fits the map
LON-MAX - the maximum longitude that fits the map

HEIGHT - the height of the map
WIDTH - the width of the map

Try typing LAT-MIN or any of these values in the interactions window, you should see they are predefined values that you can use in your functions.

Use these to write functions that scale latitudes to y values and longitudes to x values relative to the map dimensions. Use these functions to add columns named x and y to the pvd-businesses table with these scaled values. Also, add a column labeled color; for now, set each row’s color to “black.” This extended table can now be used as an input to table-to-map.

To check whether your function is correct, compare your map to the one above. They should have dots in the same places.


CHECKPOINT: Call over a TA once you reach this point.


Part 2: Analyzing the Data

Now that you have a map of good ol’ Providence (albeit not a very pretty one), we need to put it to good use. Your cowboy friend Billy the Teen (of the infamous mill case) has taken you up on your invitation to visit and has just arrived in Providence. He wants to know what he should do while he’s here!

Question 2.1: Generate a tourist map

Write a function generate-tourist-map(needs-hotel :: Boolean, has-stable :: Boolean, stays-up-late :: Boolean, eats-out :: Boolean, businesses :: Table) -> Image that takes in a series of Booleans and the original pvd-businesses table and returns a map marked with the places that Billy the Teen might want to visit.

If a place has more than one relevant characteristic, it should be colored according to the characteristic that’s most important to Billy. Starting with the most important characteristic, Billy cares first about hotels, then eating out, then places that have parking, and lastly, places that stay open late.

Think about how you can use booleans to compute the desired color for each row

NOTE: Look at the list of predefined colors in the Pyret Documentation to see what options you have.


CHECKPOINT: Call over a TA once you reach this point.


Part 3: Doughnuts!

It turns out that your friend Billy is a big advocate for local businesses and wants to try out all the local doughnut shops in Providence.

How do we distinguish local shops from those in national chains? One way is to find all the doughnut shops and see which ones have names that appear many times in the data—local shops will have fewer entries in the list. A frequency-bar chart would show us this answer visually, but what if we had to compute this information from a list of names of doughnut shops, rather than read it off of a frequency-bar-chart?

Question 3.1

Here’s a collection of operations on tables and lists (assuming we imported lists as L). Write a function using operations from the following collection that produces a list of names of local doughnut shops. We’ll consider a doughnut shop to be local if it has no more than 2 locations in the providence-business table.

Write a function to determine whether a row describes a doughnut shop, and then filter the providence-business table to contain only the doughnut shops. Look for the doughnut shop (hint hint) that isn’t local (you can do this by eye), and remove it from the table using your list functions.

Something to keep in mind: There are two spellings for the tasty round dessert of interest: donut and doughnut. Be aware of this when you are looking for businesses.

Remember to write out your list of tasks first and use that to guide your work.

Question 3.2

Given the list of names of local doughnut shops, generate a map that highlights all doughnut shops, marking local stores with a red dot and non-local stores with a black dot.


CHECKPOINT: Call over a TA once you reach this point.


Part 4: A Different Kind of Map

Unsatisfied with how few local doughnut shops there are in Providence, Billy the Teen decides to open his own (Billy Boy’s Old Mill Doughnut)! After conducting a survey of existing options, he’s created a list of the most popular doughnut options.

Question 4.1

Write a function create-donuts(donut-colors :: List<String>) -> List<Image> that takes in a list of strings representing valid colors and produces a list of doughnuts. Each doughnut should look like the following image:

However, each doughnut should have a color that corresponds to its location in the list. Each doughnut should also have a randomly generated size, such that its radius is between 15-35 units.

HINT: Take a look at the List operations from part 3.1.

Question 4.2

Billy the Teen has discovered that the ideal doughnut size has a radius within 20-30. He wants to discard all of the doughnut images that are outside of that range and make display signs out of the rest.

Write a function generate-donut-signs(donut-images :: List<Image>) -> List<Image> that takes in the output list from create-donut. This function should remove all of the doughnuts that lie outside of the size range and put the remaining doughnuts on rectangular backgrounds. This is what an output list item should look like:


CHECKPOINT: Call over a TA once you reach this point.


Success!

Billy invited you to enjoy a full day of doughnuts, on the house! Business at Old Mill Doughnuts is booming, but you’ve already gotten a call about a new case that desperately needs your attention.