I made a map of every Panda Express location that has Eggplant Tofu

Amit Tallapragada
Analytics Vidhya
Published in
7 min readJan 4, 2021

EDIT: I made an app that live tracks a bunch of different fast foods near you! Check out the map here.

TLDR: I made a map with every Panda Express location in the USA that serves Eggplant Tofu. This post was inspired by Rashiq’s brilliant reverse engineering of the McDonalds API.

If you are vegetarian you already know that Panda Express is a magical place. My go to meal — a Panda Bowl with Eggplant Tofu has been a STAPLE in my diet for the past decade. However, after going to college in Arizona, I learned that not all Pandas are created equally. Some locations DON’T HAVE EGGPLANT TOFU! While this is a much bigger problem, if you’re curious about which locations do serve Eggplant Tofu, then follow along.

Things I learned about the Eggplant Tofu Distribution

  1. Of the 1,984 Pandas Express Locations I scraped, only 157 of them had Eggplant Tofu. Only about 8% of Pandas have Eggplant Tofu 💀
  2. Northern California is a goldmine for this stuff

3. The Midwest is not as hospitable…

4. Except for this lone wolf in Grandview?

5. Hawaii is my safe space.

General Idea For Building this Thing

To create this map I essentially “ordered” food from every single Panda Express in the United States. During the process of ordering food, the Panda Express backend servers return a list of every menu item that the location offers. We can write code that checks if Eggplant Tofu is on that list. However, in order to do this, we are gonna need a list of every Panda Express in the USA.

Step 1: Get a list of a the Panda Express locations in the USA

Note: I’ll be doing all the coding in this tutorial in python

After doing some digging, I found that Panda has an API for this. However, the API returns every single piece of metadata you could want on each of their locations. Because of this, the request takes a long time. I would recommend saving the response from the request to a file so you don’t have to keep making this request. Here is the request you need:

import json
import requests

resp = requests.get(url="https://nomnom-prod-api.pandaexpress.com/restaurants/111469/menu?nomnom=add-restaurant-to-menu")
data = resp.json()
#lets save the data in case we need it again later
with open("pandaLocations.json", "w") as f:
json.dump(data,f)

#the data dictionary contains various keys we don't care about. We just want the key that contains all the restaurant data
restaurants = data['restaurants']

Let’s filter this data

the ‘restaurants’ key contains all the data you could ask for about any Panda Express location. The only things we really need to map whether a location has Eggplant Tofu is the id, latitude, and longitude keys shown below. The ‘id’ parameter is a unique identifier the Panda Express internal API uses to refer to each of its stores. We will use this value to hit another one of their APIs which will give us the menu for a specific store.

restaurants[0].keys()dict_keys(['acceptsordersbeforeopening', 'acceptsordersuntilclosing', 'advanceonly', 'advanceorderdays', 'allowhandoffchoiceatmanualfire', 'attributes', 'availabilitymessage', 'brand', 'calendars', 'candeliver', 'canpickup', 'city', 'contextualpricing', 'country', 'crossstreet', 'customerfacingmessage', 'customfields', 'deliveryarea', 'deliveryfee', 'deliveryfeetiers', 'distance', 'extref', 'hasolopass', 'id', 'isavailable', 'iscurrentlyopen', 'labels', 'latitude', 'longitude', 'maximumpayinstoreorder', 'metadata', 'minimumdeliveryorder', 'minimumpickuporder', 'mobileurl', 'name', 'productrecipientnamelabel', 'requiresphonenumber', 'showcalories', 'slug', 'specialinstructionsmaxlength', 'state', 'storename', 'streetaddress', 'suggestedtippercentage', 'supportedcardtypes', 'supportedcountries', 'supportedtimemodes', 'supportsbaskettransfers', 'supportscoupons', 'supportscurbside', 'supportsdinein', 'supportsdispatch', 'supportsdrivethru', 'supportsfeedback', 'supportsgrouporders', 'supportsguestordering', 'supportsloyalty', 'supportsmanualfire', 'supportsnationalmenu', 'supportsonlineordering', 'supportsproductrecipientnames', 'supportsspecialinstructions', 'supportssplitpayments', 'supportstip', 'telephone', 'url', 'utcoffset', 'zip'])

Now lets loop through the data and filter for the information we need from each restaurant.

eggPlantData = {}
for restaurant in restaurants:
eggPlantData[restaurant['id']] = {"lat":restaurant['latitude'],
"lng":restaurant['longitude'],
"name":restaurant['name'],
"state":restaurant['state']
}

Ok awesome. Now our ‘eggPlantData’ has all the data we need on each restaurant. It is a dictionary where the key is the store ‘id’ and the value is the store’s Geo-coordinates and street address. Let’s take a look at a particular stores entry in ‘eggPlantData’.

eggPlantData[111469]{'lat': 37.331691, 'lng': -121.810975, 'name': 'E Capitol Expwy & Tully', 'state': 'CA'}

We have now built our list of all the Panda Express stores in America. Now let’s figure out how to get each store’s menu items.

Panda Express has another API that will tell us a particular store’s menu items. The only parameter it takes is the store ‘id’ value. Luckily that value is the key in our ‘eggPlantData’ dictionary. Lets take a look at an example request:

store_id = 111469
resp = requests.get(url=f"https://nomnom-prod-api.pandaexpress.com/restaurants/{store_id}/menu?nomnom=add-restaurant-to-menu")
store_data = resp.json()
print(store_data)
{'categories': [{'description': '1 Side & 1 Entree', 'id': 39038, 'images': [{'description': None, 'filename': '72/7288570f72a54140a41afdcfbd0e8980.png?auto=format%2Ccompress&q=60&cs=tinysrgb&w=810&h=540&fit=crop&fm=png32&s=8aff41fd52f99c8e28ffb83d51c3c685', 'groupname': 'mobile-app', 'isdefault': False, 'url': None}, {'description': None, 'filename': '72/7288570f72a54140a41afdcfbd0e8980.png?auto=format%2Ccompress&q=60&cs=tinysrgb&w=810&h=540&fit=crop&fm=png32&s=8aff41fd52f99c8e28ffb83d51c3c685', 'groupname': 'mobile-webapp-menu', 'isdefault': False, 'url': None}, {'description': None, 'filename': '72/7288570f72a54140a41afdcfbd0e8980.png?auto=format%2Ccompress&q=60&cs=tinysrgb&w=810&h=540&fit=crop&fm=png32&s=8aff41fd52f99c8e28ffb83d51c3c685', 'groupname': 'mobile-webapp-customize', 'isdefault': False, 'url': None}, {'description': None, 'filename': '72/7288570f72a54140a41afdcfbd0e8980.png?auto=format%2Ccompress&q=60&cs=tinysrgb&w=716&h=474&fit=crop&fm=png32&s=5c543defe38946e36a8694d0b149fda4', 'groupname': 'desktop-menu', ...}

As you can see we get back a lot of unnecessary data. I had to cut off the majority of the response in order for it to display properly here. The json is tricky to traverse. Essentially, we need to search for a key called “Categories”. This key contains information on the different types of food formats Panda has to offer. These are things like their 2 Entree special, the Panda Bowl, or Individual Entrees & Sides. In our case, we are interested in only Eggplant Tofu. Thus we will be searching the Categories key for an entry called ‘Individual Entrees & Sides’. If we find it we will traverse another nested dictionary within it called ‘Products’. This dictionary will contain all the individual items a particular store carries. Here we can finally search for an entry called “Eggplant Tofu”. Lets see this in action for a single store’s data:

categories = store_data['categories']
individual_dishes = None
for cat in categories:
if cat['description'] == "Individual Entrees & Sides":
individual_dishes = cat['products']
break
for dish in individual_dishes:
if dish['name'] == "Eggplant Tofu":
print("I HAVE EGGPLANT TOFU!!!")
break
I HAVE EGGPLANT TOFU!!!

Perfect. The code snippet above will tell you if a particular store has eggplant tofu. Now let’s run it for every single store in America.

Step 3: Running it for Every Panda Express in America

for store_id, data in eggPlantData.items():
print(store_id)
resp = requests.get(url=f"https://nomnom-prod-api.pandaexpress.com/restaurants/{store_id}/menu?nomnom=add-restaurant-to-menu")
store_data = resp.json()
#get categories
categories = store_data['categories']
individual_dishes = None
eggPlantData[store_id]['has_eggplant'] = False
for cat in categories:
if cat['description'] == "Individual Entrees & Sides":
individual_dishes = cat['products']
break
if individual_dishes == None:
print(f'no individual dishes for: {store_id}')
else:
for dish in individual_dishes:
if dish['name'] == "Eggplant Tofu":
eggPlantData['has_eggplant'] = True
break

with open("eggPlantFinder.json",'w') as f:
json.dump(restaurant,f)

We are looping through our ‘eggPlantData’ dictionary and calling the store API for each store in the dict. We then check if that particular store has Eggplant Tofu or not. We store this in our ‘eggPlantData’ dictionary as another key called “has_eggplant”. This code takes a long time to run so I saved it to a file. I’ll make it available on my Github as well.

We could just stop here. We have a list of every Panda Express along with its coordinates that have Eggplant Tofu. But it wouldn’t be a complete project unless we mapped it…

Step 4: Let’s Map It

import pandas as pd
geoCoordInfo = []
for store, data in eggPlantData.items():
geoCoordInfo.append(data)

df = pd.DataFrame(data=geoCoordInfo)
df.to_csv("panda_eggplant.csv")

I experimented with a bunch of different ways of mapping this project. However, I figured the easiest way to do this was with Google Maps. It’s easily shareable, simple to add markers too, and easy to embed on websites. To do this, let’s first format our data. I might be using the most overkill approach of exporting the ‘eggPlantData’ dictionary to a CSV by using the pandas library.

…Also pandas, panda express?? kinda funny right hahahahaha

Now it’s just a matter of importing our data into Google Maps and selecting a custom logo for locations with/without Eggplant Tofu. I won’t cover this part in detail as Google has a great tutorial on doing this

Step 5: We made it

The Eggplant Tofu Finder

Icons made by Freepik from www.flaticon.com

Here it is. Our glorious map to freedom. I hope you’ve enjoyed this journey as much as I have. Please let me know if you have any questions or comments! Also please consider following me for more pointless content. In the meantime, I’m gonna go eat some Eggplant Tofu…

Eggplant Tofu

Originally published at https://amittallapragada.github.io on January 4, 2021.

--

--

Amit Tallapragada
Analytics Vidhya

I’m a software developer. I am also trying to learn how to blog.