Lab 11: Bus mapping

In this lab, you’ll make an IU bus map that updates in real time.

To start, take a look at the data source you’ll use:
(If the server is down, or the time is late so there are no buses, use this static snapshot from the past.) This data is posted in the recursive format JSON. If you look closely, you can see the latitude and longitude of each bus, its direction, and even how full it is. Refresh the page, and you should see the coordinates change slightly.

A pipeline of steps is required to animate this data: we need to parse it, clean it, project it, transform it, and finally draw it.

Exercise 1 To retrieve data in the recursive format JSON, we provide a small library. Install it as follows:
  • Open DrRacket.

  • In the File menu, choose "Install Package"

  • In the dialog, enter htdp-json

  • Press the button that says "Install" or "Update"

Now put this in your definitions:
(require 2htdp/json)
; read-json/web : String -> JSON
; Retrieves the remote file at the given URL and returns JSON data
; read-json/file : String -> JSON
; Retrieves the local file with the given name and returns JSON data

Exercise 2 Design a function parse that takes one input, ignores it, and returns the current data found at the source above. Because the input is ignored, it can be Anything. The output is a JSON, whose data definition appears below. Use the provided function read-json/web to retrieve real-time (remote) data, or use the provided function read-json/file if you resort to static (local) data.

; A JSON is one of:
; - (make-null)
; - Boolean
; - String
; - Number
; - [ListOf JSON]
; - (make-object [ListOf Member])
; A Member is [List String JSON]
(define-struct null [])
(define-struct object [members])

Try your new function out and examine the result. How does it correspond to what your Web browser shows?

The structures null and object shown above are already defined by the 2htdp/json library, so your code should not duplicate those structure definitions. Also, recall what [List String JSON] means from textbook exercise 239 in lab 8.

Exercise 3 Write the templates for processing a JSON, a [ListOf JSON], and a [ListOf Member].

Exercise 4 Data exchanged in JSON format can contain private information that should be removed as soon as possible. This concern is not serious for a bus map, but let’s practice.

Design a function clean that takes a JSON as input and returns a new JSON like the given one except every JSON that is a String is replaced by "censored". In contrast, a String that is the first of a Member should remain intact.

Exercise 5 Examine the result of combining the functions parse and clean. Note how the result is not just any JSON, but a list of objects. Moreover, each object contains two Members of the form (list "lat" Number) and (list "lon" Number).

Design a function project that takes such a JSON as input and returns a [ListOf Posn]. The x and y coordinates of each output Posn should be the latitude and longitude coordinates of each input object. In other words, they are Earth coordinates.

You’ll probably want to use map. You’ll also probably want to design a helper function that looks up a given String in a given [ListOf Member] and returns the corresponding JSON.

Exercise 6 Design a function transform that takes a Posn in Earth coordinates and returns a Posn in image coordinates suitable for showing Bloomington on your screen.

What image coordinates are suitable depends on how big your map is, so decide on how big your map is, and define constants WIDTH and HEIGHT in pixels, for use in your transform function.

In Earth coordinates, the center of Bloomington is (make-posn 39.162222 -86.529167), so your transform function should probably turn that center into something near (make-posn (/ WIDTH 2) (/ HEIGHT 2)). Also, the farthest the buses move away from that center is about 0.02 degrees, so your transform function should probably turn (make-posn (+ 39.162222 0.02) (+ -86.529167 0.02)) into something near the upper-right corner of the map.

Exercise 7 Combine these new functions, along with the function draw-lop from Assignment 9 Exercise 2, to make an Image showing where the buses are. You’ll probably want to use map.

Exercise 8 Combine these new functions, along with draw-lop, to make a big-bang animation of where the buses are in real time. As usual when using big-bang, the central question is, what is a world?

Watch out! Don’t break the Internet! Because parse retrieves the latest data, it should not run more often than every 3 seconds. So you should only use parse in your on-tick function with the tick duration set to 3 or greater, like this:
(big-bang ... [on-tick ...parse... 5] ...)
In particular, don’t use parse in your to-draw function.

For extra fun, add more information to your map. You can draw each bus differently depending on where it’s headed or how full it is. You can show a street map or a route map in the background. (The data format is documented online. Search for "v2", especially "v2/buses" to start.) You can show a trail of where the bus has been. You can reveal more information by mouse or keyboard interaction.

Exercise 9 Write a function json? that takes Anything as input and returns a Boolean by testing whether the input is a JSON as defined above.