# Finding distance from points to the boundary of the nearest polygon in Python

I asked this question on stackoverflow.com but it seems that doing so here is a better option.

Context: I want to compute the distance from points to the closest boundary of the closest polygon to each point. It has to be the distance to the closest boundary, not the distance to the centroid of the closest polygon.

I have two dataframes. One has points and the other has selected flood zones (polygons). There are thousands of points representing houses or businesses and, potentially, thousands of polygons as well. For each point (home or business location), I need to compute the distance to the nearest boundary across all polygons.

Here is an example:

``````points.head()

Latitude    Longitude   geometry
0   29.873542   -95.300914  POINT (-95.30091 29.87354)
1   29.689952   -95.528468  POINT (-95.52847 29.68995)
2   29.789688   -95.090620  POINT (-95.09062 29.78969)
3   29.559194   -95.145382  POINT (-95.14538 29.55919)
4   29.817562   -95.720350  POINT (-95.72035 29.81756)

geometry    flood2
2   POLYGON ((-96.17839 29.80032, -96.17845 29.80025, -96.17855 29.80013, -96.17870 29.79998, -96.17882 29.79982, -96.17886 29.79977, -96.17908 29.79942, -96.17919 29.79922, -96.17931 29.79906, -96.17944 29.79890, -96.17948 29.79883, -96.17964 29.79866, -96.17969 29.79868, -96.17977 29.79869, -96.17987 29.79878, -96.17994 29.79879, -96.18019 29.79877, -96.18042 29.79870, -96.18063 29.79861, -96.18071 29.79858, -96.18073 29.79858, -96.18075 29.79857, -96.18080 29.79855, -96.18085 29.79856, -96.18085 29.79860, -96.18080 29.79864, -96.18077 29.79867, -96.18075 29.79868, -96.18065 29.79873, -96.18044 29.79883, -96.18031 29.79890, -96.18017 29.79899, -96.18000 29.79913, -96.17977 29.79938, -96.17967 29.79948, -96.17949 29.79973, -96.17918 29.79998, -96.17902 29.80014, -96.17895 29.80023, -96.17891 29.80031, -96.17887 29.80039, -96.17884 29.80045, -96.17839 29.80032))  AV
3   POLYGON ((-96.14694 30.05772, -96.14695 30.05772, -96.14697 30.05770, -96.14702 30.05765, -96.14707 30.05762, -96.14713 30.05756, -96.14720 30.05750, -96.14721 30.05749, -96.14733 30.05739, -96.14756 30.05711, -96.14768 30.05692, -96.14775 30.05667, -96.14784 30.05621, -96.14786 30.05615, -96.14787 30.05599, -96.14769 30.05600, -96.14764 30.05598, -96.14761 30.05596, -96.14758 30.05589, -96.14757 30.05576, -96.14761 30.05559, -96.14763 30.05547, -96.14761 30.05517, -96.14755 30.05503, -96.14740 30.05493, -96.14728 30.05481, -96.14724 30.05468, -96.14711 30.05459, -96.14704 30.05451, -96.14704 30.05435, -96.14703 30.05434, -96.14696 30.05425, -96.14689 30.05416, -96.14676 30.05410, -96.14668 30.05403, -96.14665 30.05400, -96.14642 30.05388, -96.14618 30.05374, -96.14590 30.05360, -96.14574 30.05347, -96.14562 30.05327, -96.14561 30.05323, -96.14563 30.05324, -96.14575 30.05332, -96.14580 30.05338, -96.14582 30.05340, -96.14600 30.05348, -96.14618 30.05351, -96.14632 30.05354, -96.14649 30.05357, -96.14656 30.05359, -96.14668 30.05362, -96.14685 30.05366, -96.14703 30.05368, -96.14726 30.05372, -96.14734 30.05372, -96.14753 30.05378, -96.14761 30.05374, -96.14768 30.05361, -96.14764 30.05345, -96.14750 30.05325, -96.14745 30.05292, -96.14746 30.05281, -96.14744 30.05273, -96.14738 30.05265, -96.14687 30.05239, -96.14678 30.05231, -96.14674 30.05224, -96.14680 30.05220, -96.14697 30.05220, -96.14720 30.05225, -96.14748 30.05240, -96.14761 30.05242, -96.14773 30.05238, -96.14790 30.05223, -96.14796 30.05207, -96.14799 30.05190, -96.14826 30.05164, -96.14840 30.05157, -96.14845 30.05161, -96.14844 30.05170, -96.14828 30.05196, -96.14830 30.05203, -96.14840 30.05216, -96.14839 30.05224, -96.14822 30.05239, -96.14799 30.05267, -96.14795 30.05281, -96.14802 30.05318, -96.14812 30.05330, -96.14822 30.05333, -96.14836 30.05318, -96.14852 30.05307, -96.14865 30.05306, -96.14868 30.05316, -96.14866 30.05328, -96.14854 30.05357, -96.14855 30.05370, -96.14849 30.05382, -96.14832 30.05411, -96.14832 30.05420, -96.14836 30.05434, -96.14845 30.05450, -96.14877 30.05484, -96.14885 30.05498, -96.14885 30.05509, -96.14884 30.05521, -96.14884 30.05546, -96.14882 30.05558, -96.14882 30.05574, -96.14882 30.05577, -96.14880 30.05581, -96.14873 30.05585, -96.14863 30.05588, -96.14863 30.05589, -96.14862 30.05606, -96.14868 30.05615, -96.14877 30.05621, -96.14915 30.05622, -96.14950 30.05613, -96.14967 30.05614, -96.14962 30.05623, -96.14947 30.05641, -96.14936 30.05651, -96.14931 30.05657, -96.14919 30.05666, -96.14912 30.05672, -96.14905 30.05677, -96.14898 30.05683, -96.14895 30.05703, -96.14895 30.05732, -96.14904 30.05737, -96.14912 30.05745, -96.14918 30.05757, -96.14915 30.05762, -96.14905 30.05769, -96.14893 30.05772, -96.14879 30.05776, -96.14862 30.05781, -96.14847 30.05798, -96.14843 30.05811, -96.14843 30.05827, -96.14847 30.05847, -96.14847 30.05858, -96.14866 30.05882, -96.14866 30.05883, -96.14872 30.05890, -96.14874 30.05893, -96.14876 30.05898, -96.14878 30.05902, -96.14879 30.05906, -96.14879 30.05908, -96.14879 30.05913, -96.14879 30.05915, -96.14879 30.05915, -96.14878 30.05916, -96.14877 30.05921, -96.14874 30.05926, -96.14871 30.05929, -96.14871 30.05930, -96.14848 30.05910, -96.14817 30.05882, -96.14711 30.05787, -96.14698 30.05776, -96.14694 30.05772))  AV
5   POLYGON ((-96.09303 29.65069, -96.09323 29.65046, -96.09334 29.65036, -96.09360 29.65013, -96.09420 29.64981, -96.09474 29.64954, -96.09494 29.64951, -96.09509 29.64951, -96.09528 29.64951, -96.09548 29.64945, -96.09580 29.64928, -96.09603 29.64921, -96.09622 29.64903, -96.09642 29.64895, -96.09665 29.64900, -96.09690 29.64905, -96.09732 29.64888, -96.09756 29.64882, -96.09777 29.64881, -96.09795 29.64892, -96.09789 29.64900, -96.09775 29.64901, -96.09749 29.64907, -96.09720 29.64922, -96.09692 29.64936, -96.09656 29.64935, -96.09632 29.64937, -96.09600 29.64959, -96.09565 29.64981, -96.09543 29.64985, -96.09522 29.64999, -96.09503 29.64999, -96.09473 29.65015, -96.09449 29.65029, -96.09428 29.65037, -96.09392 29.65061, -96.09363 29.65075, -96.09343 29.65086, -96.09337 29.65092, -96.09327 29.65113, -96.09303 29.65069))  AV
8   POLYGON ((-96.46769 29.86118, -96.46754 29.86110, -96.46706 29.86111, -96.46687 29.86117, -96.46670 29.86131, -96.46666 29.86140, -96.46663 29.86164, -96.46649 29.86163, -96.46636 29.86158, -96.46603 29.86136, -96.46583 29.86125, -96.46555 29.86116, -96.46546 29.86114, -96.46544 29.86120, -96.46540 29.86123, -96.46530 29.86119, -96.46517 29.86115, -96.46502 29.86109, -96.46497 29.86103, -96.46497 29.86097, -96.46459 29.86073, -96.46414 29.86051, -96.46391 29.86031, -96.46384 29.86022, -96.46376 29.86007, -96.46372 29.85991, -96.46372 29.85978, -96.46373 29.85947, -96.46367 29.85938, -96.46351 29.85921, -96.46333 29.85900, -96.46324 29.85895, -96.46298 29.85886, -96.46280 29.85875, -96.46268 29.85862, -96.46256 29.85838, -96.46249 29.85835, -96.46229 29.85840, -96.46221 29.85837, -96.46205 29.85832, -96.46198 29.85831, -96.46185 29.85833, -96.46171 29.85842, -96.46152 29.85842, -96.46134 29.85832, -96.46116 29.85830, -96.46112 29.85823, -96.46117 29.85815, -96.46119 29.85814, -96.46120 29.85812, -96.46129 29.85805, -96.46141 29.85799, -96.46151 29.85796, -96.46157 29.85794, -96.46163 29.85791, -96.46173 29.85786, -96.46178 29.85780, -96.46178 29.85776, -96.46170 29.85757, -96.46166 29.85750, -96.46144 29.85727, -96.46124 29.85708, -96.46108 29.85694, -96.46090 29.85675, -96.46081 29.85657, -96.46077 29.85640, -96.46075 29.85620, -96.46071 29.85606, -96.46062 29.85592, -96.46043 29.85572, -96.46030 29.85552, -96.46025 29.85547, -96.46016 29.85541, -96.46001 29.85538, -96.45984 29.85541, -96.45943 29.85551, -96.45901 29.85553, -96.45886 29.85556, -96.45848 29.85567, -96.45826 29.85577, -96.45800 29.85589, -96.45784 29.85594, -96.45770 29.85594, -96.45745 29.85588, -96.45732 29.85583, -96.45708 29.85575, -96.45681 29.85574, -96.45655 29.85576, -96.45622 29.85570, -96.45599 29.85572, -96.45586 29.85575, -96.45579 29.85578, -96.45561 29.85592, -96.45551 29.85604, -96.45541 29.85617, -96.45526 29.85639, -96.45513 29.85652, -96.45500 29.85660, -96.45491 29.85664, -96.45481 29.85667, -96.45459 29.85669, -96.45403 29.85667, -96.45384 29.85662, -96.45356 29.85652, -96.45341 29.85654, -96.45332 29.85657, -96.45313 29.85666, -96.45292 29.85671, -96.45287 29.85678, -96.45279 29.85691, -96.45267 29.85698, -96.45249 29.85698, -96.45235 29.85695, -96.45221 29.85687, -96.45208 29.85678, -96.45188 29.85661, -96.45174 29.85654, -96.45159 29.85650, -96.45138 29.85651, -96.45127 29.85657, -96.45115 29.85669, -96.45110 29.85682, -96.45106 29.85697, -96.45096 29.85697, -96.45092 29.85693, -96.45081 29.85676, -96.45071 29.85668, -96.45062 29.85664, -96.45050 29.85661, -96.45027 29.85660, -96.44983 29.85660, -96.44965 29.85657, -96.44947 29.85649, -96.44925 29.85632, -96.44915 29.85629, -96.44900 29.85631, -96.44871 29.85630, -96.44854 29.85636, -96.44851 29.85634, -96.44837 29.85623, -96.44807 29.85607, -96.44786 29.85601, -96.44765 29.85597, -96.44758 29.85594, -96.44734 29.85577, -96.44720 29.85570, -96.44706 29.85565, -96.44669 29.85556, -96.44655 29.85545, -96.44645 29.85525, -96.44636 29.85497, -96.44630 29.85491, -96.44620 29.85488, -96.44599 29.85487, -96.44579 29.85493, -96.44567 29.85493, -96.44551 29.85491, -96.44524 29.85488, -96.44521 29.85499, -96.44517 29.85523, -96.44513 29.85531, -96.44501 29.85547, -96.44481 29.85564, -96.44462 29.85573, -96.44451 29.85576, -96.44436 29.85577, -96.44419 29.85574, -96.44402 29.85568, -96.44395 29.85564, -96.44384 29.85557, -96.44374 29.85554, -96.44368 29.85553, -96.44346 29.85553, -96.44337 29.85548, -96.44334 29.85539, -96.44337 29.85532, -96.44346 29.85516, -96.44347 29.85505, -96.44344 29.85501, -96.44332 29.85485, -96.44331 29.85456, -96.44346 29.85467, -96.44370 29.85484, -96.44370 29.85484, -96.44384 29.85481, -96.44402 29.85477, -96.44414 29.85474, -96.44453 29.85448, -96.44499 29.85388, -96.44499 29.85388, -96.44534 29.85384, -96.44534 29.85384, -96.44590 29.85421, -96.44590 29.85421, -96.44630 29.85482, -96.44638 29.85489, -96.44638 29.85489, -96.44656 29.85504, -96.44656 29.85504, -96.44794 29.85544, -96.44809 29.85557, -96.44837 29.85573, -96.44859 29.85580, -96.44881 29.85584, -96.44906 29.85581, -96.44928 29.85578, -96.44952 29.85584, -96.44967 29.85593, -96.44988 29.85610, -96.45003 29.85615, -96.45041 29.85616, -96.45058 29.85614, -96.45088 29.85608, -96.45103 29.85605, -96.45114 29.85602, -96.45135 29.85597, -96.45155 29.85591, -96.45170 29.85587, -96.45188 29.85582, -96.45207 29.85573, -96.45213 29.85566, -96.45213 29.85566, -96.45221 29.85565, -96.45237 29.85563, -96.45383 29.85560, -96.45386 29.85558, -96.45395 29.85554, -96.45408 29.85529, -96.45414 29.85519, -96.45426 29.85496, -96.45443 29.85478, -96.45455 29.85465, -96.45470 29.85455, -96.45481 29.85448, -96.45490 29.85443, -96.45490 29.85443, -96.45513 29.85438, -96.45525 29.85435, -96.45529 29.85434, -96.45529 29.85434, -96.45635 29.85438, -96.45641 29.85440, -96.45664 29.85448, -96.45779 29.85485, -96.45779 29.85485, -96.45792 29.85483, -96.45795 29.85482, -96.45827 29.85477, -96.45910 29.85463, -96.45923 29.85461, -96.45934 29.85460, -96.45967 29.85456, -96.45977 29.85455, -96.45977 29.85455, -96.45977 29.85455, -96.45998 29.85466, -96.46039 29.85536, -96.46056 29.85566, -96.46086 29.85618, -96.46322 29.85838, -96.46365 29.85877, -96.46365 29.85877, -96.46373 29.85893, -96.46373 29.85893, -96.46373 29.85893, -96.46381 29.85910, -96.46384 29.85923, -96.46402 29.86001, -96.46402 29.86001, -96.46432 29.86040, -96.46456 29.86050, -96.46481 29.86059, -96.46703 29.86057, -96.46719 29.86060, -96.46777 29.86069, -96.46777 29.86069, -96.47021 29.86246, -96.47092 29.86340, -96.47177 29.86428, -96.47177 29.86428, -96.47214 29.86467, -96.47229 29.86495, -96.47233 29.86501, -96.47233 29.86501, -96.47244 29.86537, -96.47231 29.86527, -96.47214 29.86519, -96.47206 29.86517, -96.47180 29.86517, -96.47168 29.86515, -96.47146 29.86515, -96.47141 29.86501, -96.47128 29.86463, -96.47118 29.86446, -96.47104 29.86427, -96.47075 29.86396, -96.47054 29.86379, -96.47034 29.86366, -96.46981 29.86341, -96.46967 29.86333, -96.46961 29.86326, -96.46948 29.86308, -96.46938 29.86302, -96.46917 29.86292, -96.46898 29.86275, -96.46887 29.86255, -96.46886 29.86247, -96.46882 29.86220, -96.46875 29.86211, -96.46863 29.86205, -96.46857 29.86203, -96.46829 29.86196, -96.46813 29.86183, -96.46793 29.86164, -96.46780 29.86155, -96.46778 29.86151, -96.46777 29.86128, -96.46769 29.86118))  AV
10  POLYGON ((-96.42751 29.84184, -96.42716 29.84154, -96.42699 29.84142, -96.42690 29.84139, -96.42665 29.84131, -96.42653 29.84120, -96.42647 29.84106, -96.42642 29.84090, -96.42641 29.84082, -96.42635 29.84055, -96.42627 29.84034, -96.42617 29.84018, -96.42600 29.83999, -96.42582 29.83980, -96.42551 29.83951, -96.42530 29.83929, -96.42505 29.83897, -96.42487 29.83867, -96.42478 29.83842, -96.42473 29.83817, -96.42471 29.83774, -96.42468 29.83762, -96.42462 29.83753, -96.42453 29.83745, -96.42443 29.83738, -96.42431 29.83735, -96.42396 29.83728, -96.42387 29.83724, -96.42374 29.83715, -96.42356 29.83694, -96.42347 29.83679, -96.42342 29.83666, -96.42338 29.83645, -96.42338 29.83625, -96.42343 29.83627, -96.42363 29.83634, -96.42363 29.83634, -96.42378 29.83635, -96.42389 29.83635, -96.42391 29.83635, -96.42399 29.83631, -96.42429 29.83619, -96.42439 29.83615, -96.42449 29.83615, -96.42455 29.83615, -96.42455 29.83615, -96.42462 29.83621, -96.42472 29.83628, -96.42480 29.83653, -96.42486 29.83670, -96.42486 29.83670, -96.42476 29.83771, -96.42480 29.83794, -96.42484 29.83821, -96.42484 29.83821, -96.42504 29.83864, -96.42504 29.83864, -96.42507 29.83870, -96.42507 29.83871, -96.42507 29.83871, -96.42558 29.83927, -96.42607 29.83961, -96.42665 29.84003, -96.42720 29.84028, -96.42798 29.84040, -96.42798 29.84040, -96.42817 29.84043, -96.42865 29.84050, -96.43037 29.84076, -96.43089 29.84084, -96.43125 29.84090, -96.43130 29.84090, -96.43231 29.84090, -96.43305 29.84090, -96.43329 29.84097, -96.43329 29.84097, -96.43336 29.84100, -96.43357 29.84106, -96.43396 29.84133, -96.43415 29.84146, -96.43434 29.84169, -96.43434 29.84169, -96.43436 29.84178, -96.43437 29.84184, -96.43441 29.84203, -96.43437 29.84225, -96.43436 29.84226, -96.43436 29.84227, -96.43436 29.84227, -96.43434 29.84221, -96.43425 29.84202, -96.43415 29.84188, -96.43402 29.84182, -96.43390 29.84179, -96.43376 29.84178, -96.43359 29.84180, -96.43334 29.84187, -96.43320 29.84192, -96.43300 29.84204, -96.43279 29.84218, -96.43266 29.84229, -96.43265 29.84230, -96.43261 29.84233, -96.43246 29.84248, -96.43241 29.84254, -96.43232 29.84266, -96.43223 29.84279, -96.43220 29.84300, -96.43212 29.84307, -96.43184 29.84316, -96.43173 29.84320, -96.43165 29.84324, -96.43146 29.84333, -96.43125 29.84351, -96.43118 29.84351, -96.43112 29.84348, -96.43100 29.84335, -96.43089 29.84323, -96.43067 29.84300, -96.43045 29.84284, -96.43036 29.84279, -96.43020 29.84270, -96.42996 29.84259, -96.42973 29.84250, -96.42936 29.84232, -96.42911 29.84222, -96.42892 29.84217, -96.42891 29.84217, -96.42884 29.84216, -96.42871 29.84214, -96.42839 29.84209, -96.42790 29.84205, -96.42767 29.84195, -96.42751 29.84184))  AV
``````

Now for each point, I need to find the closest boundary and compute the distance to it. The answer suggested in 1 computes the centroid of each polygon and identifies which polygon is the closest. However, 1) it doesn't compute the distance to it and 2) if the closest boundary to a point doesn't change and a boundary that is further away does, the centroid changes as well but the distance that I'm interested in doesn't.

I am aware of NNJoin, a QGIS plugin, that allows to do exactly this. However, I have to do this on a server that does not allow me to install QGIS at all. I have to rely on Python resources such as GeoPandas and Shapely.

• I'd break each polygon into line segments. Get the perpendicular projection from each point to the segment. Determine if the projection is within the segment. Otherwise get the range to the two points that define the segment. Calculate the range. Find the minimum. Maybe simplify with bounding boxes first. Commented Apr 28, 2021 at 17:22
• If you can, use an index structure, e.g. shapely.readthedocs.io/en/latest/… Commented Apr 28, 2021 at 20:10
• What about GDAL? Can that be installed? In the API documentation for Geometry gdal.org/python/index.html there is a function called distance, used like IndividualPointGeometry.Distance(IndividualPolygonGeometry), you could start with a spatial filter selection using expanding buffers of each point until polygon geometries are returned which would be faster than testing each point to every polygon to find the minimum. Commented Apr 29, 2021 at 2:13
• Thanks @MichaelStimson GDAL can be used. I'll check into this. Commented Apr 29, 2021 at 16:30

You can use geopandas sjoin_nearest function and label the optional argument distance_col to a name that suits you.

``````import geopandas as gpd

# set crs, take a metric crs! not WGS84
points = points.set_crs(YOURCRS, allow_override=True)
shape = shape.set_crs(YOURCRS, allow_override=True)

# index the data in order to speed up the spatial join
points.sindex
shape.sindex

# spatial join
gdf_distances = gpd.sjoin_nearest(points,
shape,
how="left",
lsuffix='_left',
rsuffix='_right',
distance_col='distanceToNearestPolygon')
``````

It is likely that there are better ways to do this but the scale of the problem didn't make this (probably inefficient) approach too bad. I ended up doing a double loop over points and polygons. For each point, I computed the distance to all polygons of a different flood zone designation (one at a time). After going over all points and polygons, I computed the minimum distance from a point to any polygon the different flood zone. For the 2.5K point and ~10K polygons, it ended up taking around 12 minutes. There are certainly more efficient ways to do this but for something that only has to be done once, its good enough.