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:
Authors:
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
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
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.
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
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
Shopping
Selecting nodes for shopping.
In[]:=
findTypes[osm,"shop","key"][[;;3]]
Out[]=
670739633PositionGeoPosition[{35.7031,139.764}],Tagsbranch湯島一丁目店,brandFamilyMart,brand:enFamilyMart,brand:jaファミリーマート,brand:wikidataQ1191685,brand:wikipediaen:FamilyMart,nameファミリーマート,name:enFamilyMart,name:jaファミリーマート,name:ja_rmSankusu,shopconvenience,810027463PositionGeoPosition[{35.6958,139.759}],Tagsname明倫館書店,name:enMeirinkan Bookstore,opening_hoursWe,Su off,second_handonly,shopbooks,810027523PositionGeoPosition[{35.6993,139.764}],Tagsbrand丸善,brand:enMARUZEN,brand:ja丸善,brand:wikidataQ1906012,brand:wikipediaja:丸善雄松堂,name丸善,name:enMARUZEN,name:ja丸善,name:ja_rmMaruzen,official_name丸善雄松堂,official_name:enMaruzen Yushodo,official_name:ja丸善雄松堂,payment:cashyes,payment:paypayyes,shopbooks
Government and Health
Government and Health
Finding the nodes for government and health facilities.
In[]:=
findTypes[osm,"government","key"]
Out[]=
1420792405PositionGeoPosition[{35.7004,139.757}],Tagsadmin_level2,buildingpublic,governmentpension_fund,name神田社会保険事務所,name:enKanda Social Insurance Office,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,officegovernment,operator日本年金機構,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html
In[]:=
findTypes[osm,"healthcare","key"][[;;2]]
Out[]=
1420766935PositionGeoPosition[{35.6984,139.763}],Tagsamenityhospital,healthcarehospital,name佐々木研究所附属杏雲堂病院,name:enKyoundo Hospital,name:esHospital Kyoundo,name:ja佐々木研究所附属杏雲堂病院,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html,wheelchairyes,1420771222PositionGeoPosition[{35.6975,139.766}],Tagsamenityhospital,healthcarehospital,name名倉クリニック,name:enNagura Clinic,name:esClínica Nagura,name:ja名倉クリニック,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html
Transportation
Transportation
Utilizing the “stop_position” tag to find the # of stations and railways
In[]:=
findTypes[osm,"stop_position","tag"][[;;2]]
Out[]=
264440323PositionGeoPosition[{35.7277,139.745}],Tagsname千石,name:enSengoku,name:ja千石,name:ja_kanaせんごく,name:ja_rmSengoku,name:ruСэнгоку,network都営地下鉄,operator東京都交通局,public_transportstop_position,railwaystop,refI14,subwayyes,wheelchairyes,wikidataQ1039142,wikipediaja:千石駅,264440831PositionGeoPosition[{35.7215,139.752}],Tagsname白山,name:enHakusan,name:ja白山,name:ja_kanaはくさん,name:ja_rmHakusan,name:ruХакусан,network都営地下鉄,operator東京都交通局,public_transportstop_position,railwaystop,refI13,subwayyes,wikidataQ1039879,wikipediaja:白山駅 (東京都)
Food
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[]=
PositionGeoPosition[{35.6996,139.767}],Tagsamenitybar,sourceimage;Bing,2007-04,PositionGeoPosition[{35.6962,139.76}],Tagscheck_date2023-02-02,disused:amenitybiergarten,name8taps,PositionGeoPosition[{35.7011,139.76}],Tagsamenitycafe,nameA&A認定ベクターワークスカフェジャパン,name:enA&A Vectorworks Cafe Japan,PositionGeoPosition[{35.6999,139.763}],Tagsamenityfast_food,branchお茶の水駅前店,brandロッテリア,brand:enLotteria,brand:jaロッテリア,brand:wikidataQ249525,brand:wikipediaja:ロッテリア,cuisineburger,nameロッテリア,name:enLotteria,name:jaロッテリア,name:ja_rmRotteria,phone+81 3 5281 8524,takeawayyes,wheelchairlimited
Entertainment
Entertainment
Nodes for entertainment.
In[]:=
findTypes[osm,"leisure","key"][[;;3]]
Out[]=
4970429067PositionGeoPosition[{35.7024,139.766}],Tagsleisureyes,nameビリヤード岡田,5214254966PositionGeoPosition[{35.6953,139.761}],Tagsleisurekaraoke,nameビッグエコー,name:enBig Echo,5253445634PositionGeoPosition[{35.6995,139.763}],Tagsleisurekaraoke,level1;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[]=
PositionGeoPosition[{35.7042,139.764}],Tagsamenitycommunity_centre,name湯島児童館,name:enYushima Children's Hall,noteNational-Land Numerical Information (Public Facility) 2006, MLIT Japan,note:ja国土数値情報(公共施設データ)平成19年 国土交通省,sourceKSJ2,source_refhttp://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-P02-v2_0.html,PositionGeoPosition[{35.7068,139.764}],Tagsamenityfountain,PositionGeoPosition[{35.6964,139.761}],Tagsamenitystudio,check_date2024-02-29,level-1,nameポレット,phone81 335182029
In[]:=
findTypes[osm,"tourism","key"][[1]]
Out[]=
PositionGeoPosition[{35.7043,139.764}],Tagsaddr:housenumber本郷3-10-15,name日本サッカーミュージアム,name:enJapan Football Museum,opening_hoursMo-Fr 13:00-18:00; Sa-Su 10:00-19:00,source(URL),tourismmuseum,websitehttp://www.jfa.jp/football_museum/,wikidataQ11506477,wikimedia_commonsCategory:Japan Football Museum,wikipediaja:日本サッカーミュージアム
Creating cells
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.
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[]=
,,,,,,,,,,,,,,,,,,,,,,,
Graphing Nodes
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.
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
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.
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.
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
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.
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
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
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.
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
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
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:
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
Acknowledgements
We would like to thank Dugan, our mentor, and Rory and Eryn for helping us with our project.
References
References
◼
Environmental Protection Agency. (n.d.). EPA. https://www.epa.gov/smartgrowth/national-walkability-index-user-guide-and-methodology
◼
◼
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
◼
CITE THIS NOTEBOOK
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
by Wolfram Education Programs
Wolfram Community, STAFF PICKS, February 4, 2025
https://community.wolfram.com/groups/-/m/t/3379935