I'm trying to find a code that can quantify the proximity of countries in Europe, taking into account shared borders and I am completely stumped.

So ideally, countries that share a border have a high number and then countries where you have to pass through several borders have a significantly lower score.

Is there also a code which could tell me how many borders one would have to cross to get from country A to country B?

Any help would be greatly appreciated!

  • 1
    $\begingroup$ By "borders", do you mean geographical borders? $\endgroup$ – J. M.'s torpor Mar 12 '18 at 16:06
  • $\begingroup$ Yes, the shared geographical borders. $\endgroup$ – user09320290 Mar 12 '18 at 16:08


Inspired by J.M.'s comment I will give a more compact and more functional solution here:

euCountries = CountryData["Europe"];

edges = Inner[
    Function[ {c, listbc}, Sort @ UndirectedEdge[ c, # ]& /@ listbc ],
    Map[ CountryData[ #, "BorderingCountries" ]&, euCountries ],

g = Graph[ euCountries, edges, VertexLabels -> "Name", ImageSize -> Large ];

Original Solution

A quick an dirty go at this is maybe to build a graph for say Europe with an edge connecting two countries meaning that they are neighbors.

countriesInEurope = CountryData[ "Europe" ];

We then find the neighbors for each country and store them together with the country itself in a list of strings:

listNeighbors = (({#}~Join~CountryData[#, "BorderingCountries"]) & /@ 
countriesInEurope) /. e_Entity :> CountryData[e, "Name"];

We now construct the edges for the graph with taking care of duplicates, so that two countries will only be connected by a single undirected edge:

countryEdges[ list_ ] := With[
     country = First @ list,
     neighbors = Rest @ list
   } ,
   If[ neighbors === {}, Return[Nothing] ];
   Map[ country \[UndirectedEdge] # &, neighbors ]

edges = Map[ countryEdges, listNeighbors ] // RightComposition[
   ReplaceAll[ UndirectedEdge[ a_, b_] :> UndirectedEdge @@ Sort@{a, b}],


Now we can have our graph:

g = Graph[ Flatten @ listNeighbors, edges, VertexLabels -> "Name" , ImageSize -> Large]

enter image description here

Working With the Graph

We see that there are two countries in between Germany and Croatia:

FindShortestPath[ g, "Germany", "Croatia"]

{"Germany", "Austria", "Hungary", "Croatia"}

We can also have a CountryDistance that would give the number of borders to cross:

countryDistance[a_ , b_ ] := FindShortestPath[ g, a, b] // Length // # - 1 &

countryDistance[ "Germany", "Morocco" ]


So with a bit of work more can be done in this line...

  • 1
    $\begingroup$ Here's a compact version: euCountries = CanonicalName[CountryData["Europe"]]; edges = Union[Flatten[Table[Sort[UndirectedEdge[bord, #]], {bord, CanonicalName[CountryData[#, "BorderingCountries"]]}] & /@ euCountries]]; g = Graph[euCountries, edges, ImageSize -> Large, VertexLabels -> "Name"] $\endgroup$ – J. M.'s torpor Mar 13 '18 at 4:58
  • $\begingroup$ @J.M. Interestingly, one may drop CanonicalName completely in your version as VertexLabels -> "Name" takes care of it. $\endgroup$ – gwr Mar 13 '18 at 11:07
  • 1
    $\begingroup$ I know, I just preferred storing strings instead of Entity[] objects in the vertices. $\endgroup$ – J. M.'s torpor Mar 13 '18 at 12:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.