The Wolfram Emerging Leaders Program: High School (WELP:HS) is a remote, semester-long program designed for exceptional graduates from the Wolfram High School Summer Research Program to continue to develop their skills. Students work in a small group over the course of a semester to do either a research-based project or a product development–based project under the guidance of expert mentors. Projects are centered around a topic at the intersection of the group’s interests.

Authors:

◼
  • Anoushka Muchhal
  • ◼
  • Claire Bian
  • ◼
  • Gloria Chan
  • The goal of our project was to develop a tool to quantify the walkability of cities, a critical factor in promoting healthier lifestyles and sustainable urban living. We did this by analyzing proximity and accessibility to essential amenities, such as stores and government facilities using OpenStreetMap (OSM) data to create a walkability scale based on spatial relationships and clustering of key nodes in urban areas. By exploring concepts such as reference-point mapping and spatial density analysis, we provide a framework to assess how conducive cities are to walking. This project bridges computational techniques and urban design insights, aiming to contribute to the broader goal of fostering more livable, connected, and eco-friendly communities.

    Introduction

    Walkability is becoming an increasingly important factor for many as they choose where to live, as cities are designed in ways that prioritize cars over pedestrians, making it difficult to navigate them on foot. This lack of walkability not only impacts accessibility but also affects public health, environmental sustainability, and community connections. Walkable cities, on the other hand, encourage healthier lifestyles and create stronger social bonds by improving the perception of social cohesion in a given city. We were inspired by the city-life in our own hometowns and now it affected us, and so, in this project we explore the concept of walkability and its importance in urban living. Using OpenStreetMap (OSM) data and Wolfram technology, we developed a system to evaluate the walkability of cities. By analyzing the proximity of key amenities such as stores and government facilities, our tool assigns a walkability score to different areas. This initiative is part of a broader effort to understand urban infrastructure and advocate for cities that support eco-friendly, healthier, and more cohesive communities.

    Scoring System Methodology

    We decided to create a weighted scoring system so that things like commerce and health services are “worth more” in terms of walkability points than places of entertainment, as those services are more vital in terms of ease of access. The sections we split the scoring guidelines into where shopping, government / health, transportation, food, and entertainment.
    Each section is weighted:
    Shopping: 30%
    Government / Health: 25%
    Transportation: 20%
    Food: 15%
    Entertainment: 10%
    ​
    ​Shopping represents malls, grocery stores, convenience stores, book stores, and in more general terms, places of purchase. Government and Health are facilities that are backed by the government such as hospitals, medical centers, town halls, and banks. Transportation consists of nodes that represent subway/train stations and bus stops. Food encompasses restaurants, bars, cafes, or other places to eat. Finally, Entertainment is split into three categories: leisure, tourism, and more “standard” forms of entertainment — theatres and town centers.
    One thing to note is that our scoring system is built on the nodes listed on OSM. The only data we have is the current user inputted data for the region, which may not account for all the buildings or nodes in a city.

    Finding Nodes

    OSM has many different ways of categorizing ‘nodes’, or places on the map, the ones we will be using the most are the “tags” and the “keys”, we created several functions to return all the nodes that are listed in OSM as that key or tag. This would make it easier for us in the future to weigh/find our score.
    The first thing we did was create a function to retrieve the correct nodes from a given region based on a tag or a key
    Retrieving data from OSM
    In[]:=
    osm=ResourceFunction["OSMImport"][GeoBoundsRegion[{{35.695217,35.708217},{139.756822,139.766822}}]];
    using the select function the findTypes function selects either all the tags or keys of a given type in a region
    In[]:=
    findTypes[region_,type_,kt_]:=Select[region["Nodes"],MemberQ[#Tags,type,2]&]/;kt=="tag"​​findTypes[region_,type_,kt_]:=Select[region["Nodes"],KeyExistsQ[#Tags,type]&]/;kt=="key"
    We then tested these functions on each of the different sectors we wanted to be able to analyze

    Shopping

    Selecting nodes for shopping.
    In[]:=
    findTypes[osm,"shop","key"][[;;3]]
    Out[]=
    670739633PositionGeoPosition[{35.7031,139.764}],Tagsbranch湯島一丁目店,brandFamilyMart,brand:enFamilyMart,brand:jaファミリーマート,brand:wikidataQ1191685,brand:wikipediaen:FamilyMart,nameファミリーマート,name:enFamilyMart,name:jaファミリーマート,name:ja_rmSankusu,shopconvenience,810027463PositionGeoPosition[{35.6958,139.759}],Tagsname明倫館書店,name:enMeirinkan Bookstore,opening_hoursWe,Su off,second_handonly,shopbooks,810027523PositionGeoPosition[{35.6993,139.764}],Tagsbrand丸善,brand:enMARUZEN,brand:ja丸善,brand:wikidataQ1906012,brand:wikipediaja:丸善雄松堂,name丸善,name:enMARUZEN,name:ja丸善,name:ja_rmMaruzen,official_name丸善雄松堂,official_name:enMaruzen Yushodo,official_name:ja丸善雄松堂,payment:cashyes,payment:paypayyes,shopbooks

    Government and Health

    Finding the nodes for government and health facilities.
    In[]:=
    findTypes[osm,"government","key"]
    Out[]=
    1420792405PositionGeoPosition[{35.7004,139.757}],Tagsadmin_level2,buildingpublic,governmentpension_fund,name神田社会保険事務所,name:enKanda Social Insurance Office,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,officegovernment,operator日本年金機構,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html
    In[]:=
    findTypes[osm,"healthcare","key"][[;;2]]
    Out[]=
    1420766935PositionGeoPosition[{35.6984,139.763}],Tagsamenityhospital,healthcarehospital,name佐々木研究所附属杏雲堂病院,name:enKyoundo Hospital,name:esHospital Kyoundo,name:ja佐々木研究所附属杏雲堂病院,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html,wheelchairyes,1420771222PositionGeoPosition[{35.6975,139.766}],Tagsamenityhospital,healthcarehospital,name名倉クリニック,name:enNagura Clinic,name:esClínica Nagura,name:ja名倉クリニック,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html

    Transportation

    Utilizing the “stop_position” tag to find the # of stations and railways
    In[]:=
    findTypes[osm,"stop_position","tag"][[;;2]]
    Out[]=
    264440323PositionGeoPosition[{35.7277,139.745}],Tagsname千石,name:enSengoku,name:ja千石,name:ja_kanaせんごく,name:ja_rmSengoku,name:ruСэнгоку,network都営地下鉄,operator東京都交通局,public_transportstop_position,railwaystop,refI14,subwayyes,wheelchairyes,wikidataQ1039142,wikipediaja:千石駅,264440831PositionGeoPosition[{35.7215,139.752}],Tagsname白山,name:enHakusan,name:ja白山,name:ja_kanaはくさん,name:ja_rmHakusan,name:ruХакусан,network都営地下鉄,operator東京都交通局,public_transportstop_position,railwaystop,refI13,subwayyes,wikidataQ1039879,wikipediaja:白山駅 (東京都)

    Food

    Nodes for food. There isn’t a single specific tag/key inclusive of all the different types of restaurants, so we created list of all the tags that OSM considers to be “restaurants”.
    In[]:=
    resturantTypes={"bar","biergarten","cafe","fast_food","food_court","ice_cream","pub","resturant"};​​(findTypes[osm,#,"tag"]&/@resturantTypes)[[1;;4,1]]
    Out[]=
    PositionGeoPosition[{35.6996,139.767}],Tagsamenitybar,sourceimage;Bing,2007-04,PositionGeoPosition[{35.6962,139.76}],Tagscheck_date2023-02-02,disused:amenitybiergarten,name8taps,PositionGeoPosition[{35.7011,139.76}],Tagsamenitycafe,nameA&A認定ベクターワークスカフェジャパン,name:enA&A Vectorworks Cafe Japan,PositionGeoPosition[{35.6999,139.763}],Tagsamenityfast_food,branchお茶の水駅前店,brandロッテリア,brand:enLotteria,brand:jaロッテリア,brand:wikidataQ249525,brand:wikipediaja:ロッテリア,cuisineburger,nameロッテリア,name:enLotteria,name:jaロッテリア,name:ja_rmRotteria,phone+81 3 5281 8524,takeawayyes,wheelchairlimited

    Entertainment

    Nodes for entertainment.
    In[]:=
    findTypes[osm,"leisure","key"][[;;3]]
    Out[]=
    4970429067PositionGeoPosition[{35.7024,139.766}],Tagsleisureyes,nameビリヤード岡田,5214254966PositionGeoPosition[{35.6953,139.761}],Tagsleisurekaraoke,nameビッグエコー,name:enBig Echo,5253445634PositionGeoPosition[{35.6995,139.763}],Tagsleisurekaraoke,level1;2;3,nameカラオケジョッコ
    Similarly to food, entertainment doesn’t have its own specific tag/key, so we had to list out all the entertainment types manually.
    In[]:=
    entertainmentTypes={"arts_center","brothel","casino","cinema","community_centre","conference_centre","events_venue","exhibition_centre","fountain","gambling","music_venue","nightclub","planetarium","public_bookcase","social_centre","stage","studio","theatre"};​​DeleteCases[(findTypes[osm,#,"tag"]&/@entertainmentTypes),<||>][[1;;3,1]]
    Out[]=
    PositionGeoPosition[{35.7042,139.764}],Tagsamenitycommunity_centre,name湯島児童館,name:enYushima Children's Hall,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html,PositionGeoPosition[{35.7068,139.764}],Tagsamenityfountain,PositionGeoPosition[{35.6964,139.761}],Tagsamenitystudio,check_date2024-02-29,level-1,nameポレット,phone81 335182029
    In[]:=
    findTypes[osm,"tourism","key"][[1]]
    Out[]=
    PositionGeoPosition[{35.7043,139.764}],Tagsaddr:housenumber本郷3-10-15,name日本サッカーミュージアム,name:enJapan Football Museum,opening_hoursMo-Fr 13:00-18:00; Sa-Su 10:00-19:00,source(URL),tourismmuseum,websitehttp://www.jfa.jp/football_museum/,wikidataQ11506477,wikimedia_commonsCategory:Japan Football Museum,wikipediaja:日本サッカーミュージアム

    Creating cells

    In order to process data accurately, we also needed to create a function to take coordinates and divide the area between the coordinates into a grid. This allows us to efficiently separate a large area bounded by two coordinates into smaller chunks. OSM requires data to be exported in chunks of fewer than 50,000 nodes, and this function allows us to create boxes which are likely to allow this export. Users can also change the quantity of areas that each square in the grid covers if the location still exceeds OSM’s export limits. Cells which cover a larger amount of area are more suitable for rural/less densely populated areas.
    The milesquare function takes 2 coordinates and divides the area in between into a grid where any given cell is a square with an area of 1 square mile.
    Accuracy to the second set of coordinates {lat2, lon2} decreases as area covered by an individual cell/square increases to ensure the amount of area covered is accurate (see last GeoBoundsRegion of milesquare function for cell size of 4 square miles).
    Syntax notes: lat1 < lat2, lon1 < lon2. The milesquare function has default cell size of 1 square mile if no argument is given.
    milesquare[{lat1_,lat2_},{lon1_,lon2_},cellsize_:1]:=Module[{divLat,divLon,latVals,lonVals},divLat=RealAbs[(lat1-lat2)/QuantityMagnitude[UnitConvert[GeoDistance[{lat1,lon1},{lat2,lon1}],"Miles"]]];​​(*findwidth*)divLon=RealAbs[(lon1-lon2)/QuantityMagnitude[UnitConvert[GeoDistance[{lat1,lon1},{lat1,lon2}],"Miles"]]];(*findlength*)latVals=Table[lat1+i,{i,0,RealAbs[lat1-lat2],divLat*Sqrt[cellsize]}];​​lonVals=Table[lon1+j,{j,0,RealAbs[lon1-lon2],divLon*Sqrt[cellsize]}];​​​​Table[{{latVals[[x]],latVals[[x+1]]},{lonVals[[y]],lonVals[[y+1]]}},{x,1,Length[latVals]-1},{y,2,Length[lonVals]-1}]]
    In[]:=
    miles4=milesquare[{42.,42.3394},{-71.45,-71.094292},4][[;;3]]
    Out[]=
    {{{{42.,42.029},{-71.4112,-71.3723}},{{42.,42.029},{-71.3723,-71.3335}},{{42.,42.029},{-71.3335,-71.2946}},{{42.,42.029},{-71.2946,-71.2558}},{{42.,42.029},{-71.2558,-71.2169}},{{42.,42.029},{-71.2169,-71.1781}},{{42.,42.029},{-71.1781,-71.1392}},{{42.,42.029},{-71.1392,-71.1004}}},{{{42.029,42.058},{-71.4112,-71.3723}},{{42.029,42.058},{-71.3723,-71.3335}},{{42.029,42.058},{-71.3335,-71.2946}},{{42.029,42.058},{-71.2946,-71.2558}},{{42.029,42.058},{-71.2558,-71.2169}},{{42.029,42.058},{-71.2169,-71.1781}},{{42.029,42.058},{-71.1781,-71.1392}},{{42.029,42.058},{-71.1392,-71.1004}}},{{{42.058,42.0869},{-71.4112,-71.3723}},{{42.058,42.0869},{-71.3723,-71.3335}},{{42.058,42.0869},{-71.3335,-71.2946}},{{42.058,42.0869},{-71.2946,-71.2558}},{{42.058,42.0869},{-71.2558,-71.2169}},{{42.058,42.0869},{-71.2169,-71.1781}},{{42.058,42.0869},{-71.1781,-71.1392}},{{42.058,42.0869},{-71.1392,-71.1004}}}}
    For a cell of 4 square miles, each cell should be a 2x2 square with a diagonal length of 2 Sqrt[2], or approximately 2.828. The work below shows each square fulfills these requirements.
    In[]:=
    2*Sqrt[2]
    Out[]=
    2
    2
    In[]:=
    Quiet[Cases[Flatten[miles4,1],{{xlat1_,xlat2_},{ylon1_,ylon2_}}->GeoDistance[{{xlat1,ylon1},{xlat2,ylon2}}](*finddiagonallength*)]]
    Out[]=
    
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82807
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.82743
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    ,
    2.8268
    mi
    

    Graphing Nodes

    Then we created a function to get the GeoPositions of the nodes we found earlier and we plotted that on a graphic to show the positions of the nodes in the area we were given earlier. This function works by using the shorthand of the Position function to select the specific section of each node which contains the coordinates. Since tags and keys are formatted differently in the data, we overloaded the function to be able to handle both types of input.
    We created a function that would graph all of the nodes in a region, showing the restaurants, shopping centers, government buildings, train/subways, and entertainment centers in different colors.
    We did this using the functions we created earlier to gather the nodes and positions and graphed them using GeoGraphics.
    Combines previously built functions with GeoGraphics display:
    Graphed below are sections of Tokyo and Boston, showing the restaurants in red, the shopping centers in blue, the government buildings in green, the buses/trains in yellow, and the entertainment centers (parks, museums, etc) in purple.

    Finding Walkability

    To find walkability, we first chose a random reference point in the given region. Then, from that reference point, we find the amount of time it takes to walk from the reference point to the nodes. In this example down below, the nodes we chose were nodes of restaurants.
    We first used TravelTime to find the amount of time it takes from the reference point. However, it takes far too long for larger sets of data, which makes it challenging to use.
    As can be seen, GeoDistance uses a fraction of the computational time Travel Time does, and although the timing is less accurate, it is still close enough for the purposes of our project
    Creates a metric for calculating the score based on distances:
    In order to create a metric for judging the walkability of a particular point, we decided on the following scoring system:
    ◼
  • The farther the distance, the lower the score.
  • ◼
  • Anything that is less than 10 minutes away from the reference point gets the highest score of five.
  • ◼
  • Anything that is greater than or equal to a distance of 45 minutes away obtains the score of 0.
  • ◼
  • Any number between 10 and 45 obtains a score in between 0-5 following an inverse square root relationship, the farther the distance, the lower the score.
  • Allocating scores based on the metric:
    Visualization of the equation we used to calculate scores:
    We also needed to know the total miles contained within a given region to factor this into the scoring function.
    Calculates the total miles contained within a region given by latitude and longitude bounding by using UnitConvert along with GeoDistance:
    The final scoring function takes in a set of coordinates which denote the edges of a region in the format {{lat1, lat2}, {lon1, lon2}} where lat1 is less than lat2 and lon1 is less than lon2.
    Using these coordinates it picks a reference point at the center of the region, and then finds every shopping, government, transportation, food, and entertainment node in the full region. Using the GeoDistance between reach node and the reference (center) point, it calculates the estimated time to walk there.
    Each of those times is added to a list for the type it corresponds to (ex, all of the times it takes to get to each shopping node in one list), and then the scores each of those times is determined and added together. Then, the total score for the section is weighted based on it’s importance (ex: shopping is worth 30% of the total score) and all final weighted scores are added together.
    The final score is displayed in terms of points per mile if expanded out from the range given, which is also printed out.
    Calculates the final score of a region based on it’s walkability:
    As you can see here, with a relatively similar amount of square miles, the score is different. The higher the score is per mile, the better the walkability the given region has. The score per mile squared represents the walkability score per mile in that region rather than the overall region itself as this gives a better representation of the walkability score in say a larger region.
    In these two specific examples here, Tokyo has a greater score than downtown Boston, meaning that this portion of Tokyo has better walkability than this portion of Boston.
    score of a small section of Tokyo
    score of a section of downtown Boston

    UI Creation

    To use our scoring system, you enter a range in the form of two (x,y) coordinate pairs which form the top left and bottom right corners of the region you want to score.
    We had hoped to make it more user friendly by creating a map on which you could drag points to select coordinates, but due to the limitations of Dynamic and the already long run time of the program, we simplified the idea.
    This module lets the user input in their own coordinates and calculates the score of the region given. If the input errors out due to either a OSMImport function error such as the region containing too many nodes or being too large, the message “ensure coordinates are valid” is displayed. The function also checks if all the boxes are filled and if the coordinates are being inputted in the correct order, and displayed messages prompting the user to fix any errors.
    To get coordinates to put into the program, go to Open Street Map, and zoom into the area you want to score.

    Expanding the Range

    This function was meant to be able to take in a larger area of coordinates and split them into smaller sections so that we could analyze them using OSMImport, then take the average value of the scores of the smaller sections as the overall score of the area.
    However, we had issues with OSMImport returning value of 0 even when there were nodes in the files of the area, along with the process taking far too long to run.

    Graphing/Visualizing Walkability

    In order to find out the walkability of a given city, we want to find the average walking speed of a person first so we can see if that store lies in the area of 5 minutes, 10 minutes, and 30 minutes range.
    The code below finds out the average walking speed for 5 the minutes, 10 minutes, and 30 minutes range-- meaning how much can you walk in 5 minutes, 10 minutes, and 30 minutes for the average human being.
    We chose the test region Tokyo since it is a densely populated area and is relatively small area too since OSM can’t support a large amount of nodes. We then created a function for ways instead of nodes.
    Next, we find the GeoPosition of all the buildings in a certain area - Tokyo in this example. We will be choosing a random reference node based off a random GeoPosition from the generated list. We will be using the findWays function instead of findNodes since buildings are listed as ways instead of nodes in OSM.
    Now that we’ve found the GeoPositions, we can use them for our walkability code. Let’s first find the number of shops in this region of Tokyo.
    Point of reference (a random building in Tokyo) to use as a reference.
    How far the point of reference is from the shops in Tokyo:
    Then we can find the nodes that are under a five minute walking distance, 10 minute walking distance, and a 30 minute walking distance.
    Now we can illustrate which shops are within a 5 minute distance, 10 minute distance, and 30 minute distance.
    With the reference point in blue, this allows us to see the shops that are less than a five minute walk away in red, less than a ten minute walk away in green, and less than a thirty minute walk away in purple.

    The Next Best Node

    Our next exploration was to try to computationally determine where a new store should be placed in a given area to make the area more walkable. Given a set of stores, where would be the next best place to place a store to make a city more walkable? In order to do this, we first find where is the least dense place and then we can place a node in that low density area.
    Find the density of points in the given sample relative to the shops located in Tokyo.
    Now, we select random points that are less that the median-- these are places with low density.
    These points would be good places to put a new store if your goal was increasing the walkability of the area.
    Graphing them on a graphic for better visualization, the new stores are shown in yellow:

    Conclusion and Future Works

    In this project, we were able to create a tool that can score walkability in a given city. It gives the user a score based on how close the nodes are to a given point. We were also able to make a UI that can give a user the walkability score once prompted with a region. Despite the limitations of OSM, we were able to find our own system of calculating walkability.
    We also recognize that our project can be taken further and there are things that can be improved on. Those things include:
    ◼
  • Working on the next best node function and find a way to exclude patches of water
  • ◼
  • Water is listed under OSM as neither a way or a node, so we can’t use the OSM function in Wolfram to find regions of water
  • ◼
  • Adding onto our walkability function by implementing population density + intersection density as well
  • ◼
  • Finding a way to make the walkability score constant + less “random”
  • Acknowledgements

    We would like to thank Dugan, our mentor, and Rory and Eryn for helping us with our project.

    References

    ◼
  • Environmental Protection Agency. (n.d.). EPA. https://www.epa.gov/smartgrowth/national-walkability-index-user-guide-and-methodology
  • ◼
  • Walk score methodology. Walk Score. (n.d.). https://www.walkscore.com/methodology.shtml
  • ◼
  • Routing OSM Data: How Far Can I Walk in 5 Minutes? - Online Technical Discussion Groups-Wolfram Community. (n.d.). https://community.wolfram.com/groups/-/m/t/942484
  • ◼
  • OSM. OpenStreetMap Wiki. (n.d.). https://wiki.openstreetmap.org/
  • CITE THIS NOTEBOOK

    Scoring walkability of cities around the world using OSM​
    by Wolfram Education Programs​
    Wolfram Community, STAFF PICKS, February 4, 2025
    ​https://community.wolfram.com/groups/-/m/t/3379935