Lab 14: Bus mapping🔗

In this lab, you’ll make an IU bus map that updates in real time. You will use a data source created here at our school by Prof Mehmet Dalkilic and his students in collaboration with IU Campus Bus Service.

Exercise 1. Take a look at two data snapshots using your Web browser:
This data is posted in the recursive format JSON. If you look closely, you can see the longitude and latitude of each bus, its direction, and even its route.

Compare the two snapshots closely. They were taken a few minutes apart. What is one thing that changed? What is one thing that didn’t change?

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

  2. In the File menu, choose “Install Package”

  3. In the dialog, enter htdp-json

  4. Press the button that says “Install” or “Update”

  5. Wait a couple of minutes for the message “post-installing collections”

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
; web-address : String
; The location of the latest bus data
(define web-address "https://www.busgenius.com/api/v1/get_updated_data/10?routes=[195,196,197,198,199,200,201,202,203,206,242]&updateAnnouncements=true")
Hit the “Run” button in DrRacket. Then, in the Interactions Window, enter
(read-json/web web-address)
and examine the result. Does it seem to contain longitudes and latitudes? It should. If not, either download this snapshot from the past into the folder where you are completing this assignment and enter
(read-json/file "buses1.json")
or, without downloading, try
(read-json/web "https://cs.indiana.edu/classes/c211/buses1.json")
and examine the result. Does it seem to contain longitudes and latitudes? It should. If not, get help.

Exercise 3. Examine the result from Exercise 2. How does it correspond to what your Web browser showed in Exercise 1?

As the signatures of read-json/web and read-json/file indicate, this result should be a JSON. Here is the data definition for a JSON:
; A JSON is one of:
; - String
; - Number
; - [ListOf JSON]
; - (make-object [ListOf Member])
(define-struct object [members])
; A Member is (make-member String JSON)
(define-struct member [name value])

The structures object and member shown above are already defined by the 2htdp/json library, so your code should not duplicate those structure definitions.

Exercise 4. In the result from Exercise 2, what parts are JSONs, and what parts are not JSONs?
  1. Give two examples of parts that are JSONs.

  2. Give two examples of parts that are Members rather than JSONs.

  3. Give two examples of parts that are neither JSONs nor Members.

Exercise 5. To make it easier to retrieve JSON data, define a function called parse like this:
; parse : Anything -> JSON
; Ignore the input. Retrieve bus data.
(define (parse whatever)
  (read-json/web web-address))
Try this function out in the Interactions Window. Does it produce a JSON that contains longitudes and latitudes? If not, use the snapshot as described above.

Exercise 6. Design a function draw that takes a [ListOf Posn] representing bus locations and creates an Image showing where the buses are. Use draw-lop and cartesian->screen from Problem set 9: Plotting functions, along with this World centered on campus:
(define iub-view (make-world -86.536 -86.496 39.16 39.19))

Exercise 7. Here is a list of bus locations on campus:
(define sample-bus-posns
   (make-posn -86.5268283 39.1798933)
   (make-posn -86.5220229 39.1631958)
   (make-posn -86.5013583 39.1760933)
   (make-posn -86.52699 39.1802317)
   (make-posn -86.5162083 39.1680917)
   (make-posn -86.5266717 39.1643233)
   (make-posn -86.518595 39.1686967)
   (make-posn -86.5161778 39.1684192)
   (make-posn -86.527125 39.1809483)
   (make-posn -86.5269733 39.1800917)
   (make-posn -86.5169983 39.1839933)
   (make-posn -86.5212888 39.1716147)
   (make-posn -86.5261614 39.1790335)
   (make-posn -86.5236612 39.1763609)
   (make-posn -86.5200923 39.1642786)
   (make-posn -86.5167244 39.1716118)
   (make-posn -86.5270583 39.1805333)))
Use your draw function to draw sample-bus-posns.

Exercise 8. Examine the result of the parse function.
  1. Note how the result is not just any JSON, but an object whose members include a Member whose name is "buses".

  2. Moreover, note how the value of this Member is not just any JSON, but a list of objects.

  3. Finally, note how each object in this list contains two Members of the form (make-member "lng" Number) and (make-member "lat" Number). What other Members are there?

To help retrieve the longitude and latitude, design a function lookup that looks up a given String name in a given [ListOf Member] and returns the corresponding JSON value. If there is no Member whose name is the given String, there should be an error, which you should test using check-error.

Exercise 9. Design a function project that takes such a JSON (i.e., not just any JSON, but one of the form just described) as input and returns a [ListOf Posn]. The Earth coordinates in each input object should become an output Posn: the lng (longitude) coordinate in the input should become the x coordinate in the output, and the lat (latitude) coordinate in the input should become the y coordinate in the output.

Instead of first or rest, use the function lookup from Exercise 8, and the built-in function map.

Exercise 10. Combine the functions parse, draw, and project 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 show a street map or a route map in the background. To start, you can download this map image provided by OpenStreetMap. It shows the same area as circumscribed by iub-view above.

  • You can draw each bus differently depending on its direction (smoothed_heading) or route.

  • You can show a trail of where the bus has been.

  • You can reveal more information by mouse or keyboard interaction.