The world’s leading publication for data science, AI, and ML professionals.

Visualizing Bus Trajectories in Denver

Using Python and Unfolded to visualize RTD's real-time bus data feeds

Hands-on Tutorials

The Regional Transportation District, more commonly referred to as RTD, is the regional agency operating public transit services in Denver. RTD has an open data platform that publishes:

  • Schedule data, including the full schedule and route configuration
  • Real-time data for RTD bus services, including information about arrival/departure predictions and vehicles locations as GTFS real-time feeds
Final Visualization using Unfolded (Image by Abdullah Kurkcu)
Final Visualization using Unfolded (Image by Abdullah Kurkcu)

We will use the real-time data feed to first store some data and then use freshly released Unfolded studio to visualize bus movements. It is possible to use Uber’s Kepler.gl to achieve the same result.

While looking for examples about how to download GTFS real-time data, I have seen this beautifully crafted article and code showing how to download such geospatial data.

Visualizing Istanbul Bus Traffic With Python and KeplerGL

I followed Ozan Kara‘s approach to download GTFS data for the Denver area and made some modifications to the code, and added some additional post-processing steps to compute bus speeds.

The problem I had faced when I tried to download the data is that there are some idle buses in the GTFS feed, which alters the format of the feed. For example, if a vehicle is idle, then tags such as tripID/stopID do not exist.

Let’s take a look at the regular feed for scheduled vehicles:

If the bus doesn’t have a schedule yet, this is what the JSON looks like:

As you can see, the buses without a schedule do not have stopId, tripId, routeId, and so on. That’s why we have to check if these tags exist before trying to read them. Let’s import the libraries we will need throughout the data download process.

The dummy function below will check for the tags that might exist and pretty much will fill them out with data or NA.

The function below will download the data we need. To be able to download the data from RTD’s GTFS-realtime data feeds, you will need HTTP basic authentication credentials.

Real-Time Data Feeds Documentation

We need to call this function every minute since buses send location updates every minute.

Okay, we now have everything we need. You can run this function as long as you want, but I think an hour-long data will be long enough to build a nice Visualization. I let it run for a day and stored the data. The function below will save busdata as a geoJSON file. It is formatted in a way that Kepler.gl or Unfolded can animate.

Additionally, I created this messy code below if you would like to calculate the speed of buses. I wanted to compute an average bus speed for a given route. That’s why the function will compute the speed between each ping and take the average of all these values for the route.

Do not forget to save this as a new geoJSON file.

Everything we need is ready. You can either go to kepler.gl or unfolded.ai to visualize this geoJSON. I will use Unfolded since I have one of my old friends working for that highly successful company.

Log into studio.unfolded.ai and click on "New Map" at the upper right. That will take you to the screen asking you to upload data.

Just find the geojson file you saved and drop it on this screen. Unfolded will automatically recognize the format and create an animated timeline for you. The only thing we need to change is the color. I want to color these trajectories based on the average bus speed.

Okay, I lied, this is not the only thing I will change. I will increase the trail length too. It looks much cooler with longer trails :) Thanks Unfolded! (Image by Abdullah Kurkcu)
Okay, I lied, this is not the only thing I will change. I will increase the trail length too. It looks much cooler with longer trails 🙂 Thanks Unfolded! (Image by Abdullah Kurkcu)

That’s all! Here is the video of the end product. You might see some flying vehicles. I believe the reason for that is either they turn on/off their trackers or lose connection to the server.


Related Articles