Created
June 24, 2021 23:35
-
-
Save knu2xs/030838310ad5c448401b3d906defaeeb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pathlib import Path\n", | |
"\n", | |
"from arcgis.features import GeoAccessor\n", | |
"import arcpy\n", | |
"import numpy as np\n", | |
"import pandas as pd" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"mxd_pth = Path('.').absolute()\n", | |
"\n", | |
"gdb = mxd_pth/'Tutorial'/'Paris.gdb'\n", | |
"assert gdb.exists()\n", | |
"\n", | |
"origin_pth = gdb/'Analysis'/'Stores'\n", | |
"dest_pth = gdb/'Analysis'/'Warehouses'\n", | |
"network_pth = gdb/'Transportation'/'ParisMultimodal_ND'\n", | |
"\n", | |
"for pth in [origin_pth, dest_pth, network_pth]:\n", | |
" assert arcpy.Exists(pth)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>ID</th>\n", | |
" <th>NOM</th>\n", | |
" <th>SHAPE</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>000001</td>\n", | |
" <td>LES BOUTIQUES DU PALAIS DES CONGRES</td>\n", | |
" <td>{\"x\": 596182.601794213, \"y\": 2431199.582779128...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>000002</td>\n", | |
" <td>AU PRINTEMPS HAUSSMANN</td>\n", | |
" <td>{\"x\": 599368.5253811851, \"y\": 2430651.20669861...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>000003</td>\n", | |
" <td>GALERIES LAFAYETTE HAUSSMANN</td>\n", | |
" <td>{\"x\": 599664.9621174559, \"y\": 2430660.46239462...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>000004</td>\n", | |
" <td>ARCADES DU LIDO</td>\n", | |
" <td>{\"x\": 597639.9985315725, \"y\": 2430364.54277835...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>000005</td>\n", | |
" <td>GALERIE DU CLARIDGE</td>\n", | |
" <td>{\"x\": 597690.3071396202, \"y\": 2430329.63948231...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>5</th>\n", | |
" <td>000006</td>\n", | |
" <td>ELYSEE 26</td>\n", | |
" <td>{\"x\": 597954.9855398685, \"y\": 2430202.24669820...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>6</th>\n", | |
" <td>000007</td>\n", | |
" <td>GALERIE DES TROIS QUARTIERS</td>\n", | |
" <td>{\"x\": 599208.536133036, \"y\": 2430133.602874133...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>7</th>\n", | |
" <td>000008</td>\n", | |
" <td>GALERIE SAINT DIDIER</td>\n", | |
" <td>{\"x\": 596126.9558421671, \"y\": 2429772.06405779...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>8</th>\n", | |
" <td>000009</td>\n", | |
" <td>ESPACE EXPANSION FORUM DES HALLES</td>\n", | |
" <td>{\"x\": 600844.0707265586, \"y\": 2429275.27685733...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>9</th>\n", | |
" <td>000010</td>\n", | |
" <td>GALERIE CARROUSEL DU LOUVRE</td>\n", | |
" <td>{\"x\": 599789.3456055745, \"y\": 2429231.37388129...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>10</th>\n", | |
" <td>000011</td>\n", | |
" <td>SAMARITAINE</td>\n", | |
" <td>{\"x\": 600402.9038781449, \"y\": 2429019.58455309...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>11</th>\n", | |
" <td>000012</td>\n", | |
" <td>BAZAR DE L'HOTEL-DE-VILLE</td>\n", | |
" <td>{\"x\": 601258.298182942, \"y\": 2428816.153656907...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>12</th>\n", | |
" <td>000013</td>\n", | |
" <td>GALERIE COMMERCIALE PASSY PLAZA</td>\n", | |
" <td>{\"x\": 595804.7212178633, \"y\": 2428771.56663286...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>13</th>\n", | |
" <td>000014</td>\n", | |
" <td>LE MARCHE SAINT GERMAIN</td>\n", | |
" <td>{\"x\": 599799.4023095816, \"y\": 2428193.35480832...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>14</th>\n", | |
" <td>000015</td>\n", | |
" <td>LE BON MARCHE</td>\n", | |
" <td>{\"x\": 599070.2113969028, \"y\": 2428076.60804022...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>15</th>\n", | |
" <td>000016</td>\n", | |
" <td>PRINTEMPS NATION</td>\n", | |
" <td>{\"x\": 604702.910026148, \"y\": 2427772.155959934...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>16</th>\n", | |
" <td>000017</td>\n", | |
" <td>S.C.I. BEAUGRENELLE</td>\n", | |
" <td>{\"x\": 596031.6214420721, \"y\": 2427823.00626398...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>17</th>\n", | |
" <td>000018</td>\n", | |
" <td>MAINE-MONTPARNASSE</td>\n", | |
" <td>{\"x\": 598974.0665008128, \"y\": 2427236.25501543...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>18</th>\n", | |
" <td>000019</td>\n", | |
" <td>GAITE</td>\n", | |
" <td>{\"x\": 599123.6964369565, \"y\": 2426514.43015076...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>19</th>\n", | |
" <td>000020</td>\n", | |
" <td>ITALIE 2</td>\n", | |
" <td>{\"x\": 601459.7025991306, \"y\": 2425637.53528594...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>20</th>\n", | |
" <td>000021</td>\n", | |
" <td>CENTRE COMMERCIAL MASSENA 13</td>\n", | |
" <td>{\"x\": 602230.1008078456, \"y\": 2424710.39286908...</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" ID NOM \\\n", | |
"0 000001 LES BOUTIQUES DU PALAIS DES CONGRES \n", | |
"1 000002 AU PRINTEMPS HAUSSMANN \n", | |
"2 000003 GALERIES LAFAYETTE HAUSSMANN \n", | |
"3 000004 ARCADES DU LIDO \n", | |
"4 000005 GALERIE DU CLARIDGE \n", | |
"5 000006 ELYSEE 26 \n", | |
"6 000007 GALERIE DES TROIS QUARTIERS \n", | |
"7 000008 GALERIE SAINT DIDIER \n", | |
"8 000009 ESPACE EXPANSION FORUM DES HALLES \n", | |
"9 000010 GALERIE CARROUSEL DU LOUVRE \n", | |
"10 000011 SAMARITAINE \n", | |
"11 000012 BAZAR DE L'HOTEL-DE-VILLE \n", | |
"12 000013 GALERIE COMMERCIALE PASSY PLAZA \n", | |
"13 000014 LE MARCHE SAINT GERMAIN \n", | |
"14 000015 LE BON MARCHE \n", | |
"15 000016 PRINTEMPS NATION \n", | |
"16 000017 S.C.I. BEAUGRENELLE \n", | |
"17 000018 MAINE-MONTPARNASSE \n", | |
"18 000019 GAITE \n", | |
"19 000020 ITALIE 2 \n", | |
"20 000021 CENTRE COMMERCIAL MASSENA 13 \n", | |
"\n", | |
" SHAPE \n", | |
"0 {\"x\": 596182.601794213, \"y\": 2431199.582779128... \n", | |
"1 {\"x\": 599368.5253811851, \"y\": 2430651.20669861... \n", | |
"2 {\"x\": 599664.9621174559, \"y\": 2430660.46239462... \n", | |
"3 {\"x\": 597639.9985315725, \"y\": 2430364.54277835... \n", | |
"4 {\"x\": 597690.3071396202, \"y\": 2430329.63948231... \n", | |
"5 {\"x\": 597954.9855398685, \"y\": 2430202.24669820... \n", | |
"6 {\"x\": 599208.536133036, \"y\": 2430133.602874133... \n", | |
"7 {\"x\": 596126.9558421671, \"y\": 2429772.06405779... \n", | |
"8 {\"x\": 600844.0707265586, \"y\": 2429275.27685733... \n", | |
"9 {\"x\": 599789.3456055745, \"y\": 2429231.37388129... \n", | |
"10 {\"x\": 600402.9038781449, \"y\": 2429019.58455309... \n", | |
"11 {\"x\": 601258.298182942, \"y\": 2428816.153656907... \n", | |
"12 {\"x\": 595804.7212178633, \"y\": 2428771.56663286... \n", | |
"13 {\"x\": 599799.4023095816, \"y\": 2428193.35480832... \n", | |
"14 {\"x\": 599070.2113969028, \"y\": 2428076.60804022... \n", | |
"15 {\"x\": 604702.910026148, \"y\": 2427772.155959934... \n", | |
"16 {\"x\": 596031.6214420721, \"y\": 2427823.00626398... \n", | |
"17 {\"x\": 598974.0665008128, \"y\": 2427236.25501543... \n", | |
"18 {\"x\": 599123.6964369565, \"y\": 2426514.43015076... \n", | |
"19 {\"x\": 601459.7025991306, \"y\": 2425637.53528594... \n", | |
"20 {\"x\": 602230.1008078456, \"y\": 2424710.39286908... " | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"origin_df = GeoAccessor.from_featureclass(origin_pth)\n", | |
"origin_df['ID'] = origin_df.OBJECTID.astype(str).str.zfill(6)\n", | |
"origin_df.drop(columns='OBJECTID', inplace=True)\n", | |
"origin_df = origin_df[['ID', 'NOM', 'SHAPE']]\n", | |
"\n", | |
"origin_df" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>ID</th>\n", | |
" <th>Name</th>\n", | |
" <th>SHAPE</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>000001</td>\n", | |
" <td>Warehouse #1</td>\n", | |
" <td>{\"x\": 600178.6250939369, \"y\": 2432824.00006064...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>000002</td>\n", | |
" <td>Warehouse #2</td>\n", | |
" <td>{\"x\": 604289.7500897646, \"y\": 2431475.74993138...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>000003</td>\n", | |
" <td>Warehouse #3</td>\n", | |
" <td>{\"x\": 604616.0000740662, \"y\": 2428176.99999231...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>000004</td>\n", | |
" <td>Warehouse #4</td>\n", | |
" <td>{\"x\": 600452.1250141934, \"y\": 2424742.75000511...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>000005</td>\n", | |
" <td>Warehouse #5</td>\n", | |
" <td>{\"x\": 596102.8749461398, \"y\": 2427193.99992739...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>5</th>\n", | |
" <td>000006</td>\n", | |
" <td>Warehouse #6</td>\n", | |
" <td>{\"x\": 595105.8750092089, \"y\": 2431015.74993095...</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" ID Name SHAPE\n", | |
"0 000001 Warehouse #1 {\"x\": 600178.6250939369, \"y\": 2432824.00006064...\n", | |
"1 000002 Warehouse #2 {\"x\": 604289.7500897646, \"y\": 2431475.74993138...\n", | |
"2 000003 Warehouse #3 {\"x\": 604616.0000740662, \"y\": 2428176.99999231...\n", | |
"3 000004 Warehouse #4 {\"x\": 600452.1250141934, \"y\": 2424742.75000511...\n", | |
"4 000005 Warehouse #5 {\"x\": 596102.8749461398, \"y\": 2427193.99992739...\n", | |
"5 000006 Warehouse #6 {\"x\": 595105.8750092089, \"y\": 2431015.74993095..." | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"dest_df = GeoAccessor.from_featureclass(dest_pth)\n", | |
"\n", | |
"dest_df['ID'] = dest_df.OBJECTID.astype(str).str.zfill(6)\n", | |
"dest_df.drop(columns='OBJECTID', inplace=True)\n", | |
"\n", | |
"dest_df" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Wall time: 2.5 s\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>destination_id</th>\n", | |
" <th>destination_rank</th>\n", | |
" <th>origin_id</th>\n", | |
" <th>proximity_distance</th>\n", | |
" <th>proximity_drive_time</th>\n", | |
" <th>origin_NOM</th>\n", | |
" <th>destination_Name</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>000006</td>\n", | |
" <td>1</td>\n", | |
" <td>000001</td>\n", | |
" <td>0.859860</td>\n", | |
" <td>4.151506</td>\n", | |
" <td>LES BOUTIQUES DU PALAIS DES CONGRES</td>\n", | |
" <td>Warehouse #6</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>000001</td>\n", | |
" <td>2</td>\n", | |
" <td>000001</td>\n", | |
" <td>2.950608</td>\n", | |
" <td>14.245770</td>\n", | |
" <td>LES BOUTIQUES DU PALAIS DES CONGRES</td>\n", | |
" <td>Warehouse #1</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>000005</td>\n", | |
" <td>3</td>\n", | |
" <td>000001</td>\n", | |
" <td>3.136645</td>\n", | |
" <td>15.143359</td>\n", | |
" <td>LES BOUTIQUES DU PALAIS DES CONGRES</td>\n", | |
" <td>Warehouse #5</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>000001</td>\n", | |
" <td>1</td>\n", | |
" <td>000002</td>\n", | |
" <td>1.708167</td>\n", | |
" <td>8.247251</td>\n", | |
" <td>AU PRINTEMPS HAUSSMANN</td>\n", | |
" <td>Warehouse #1</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>000006</td>\n", | |
" <td>2</td>\n", | |
" <td>000002</td>\n", | |
" <td>3.049405</td>\n", | |
" <td>14.722712</td>\n", | |
" <td>AU PRINTEMPS HAUSSMANN</td>\n", | |
" <td>Warehouse #6</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>...</th>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>58</th>\n", | |
" <td>000003</td>\n", | |
" <td>2</td>\n", | |
" <td>000020</td>\n", | |
" <td>3.315711</td>\n", | |
" <td>16.008703</td>\n", | |
" <td>ITALIE 2</td>\n", | |
" <td>Warehouse #3</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>59</th>\n", | |
" <td>000005</td>\n", | |
" <td>3</td>\n", | |
" <td>000020</td>\n", | |
" <td>3.808590</td>\n", | |
" <td>18.387483</td>\n", | |
" <td>ITALIE 2</td>\n", | |
" <td>Warehouse #5</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>60</th>\n", | |
" <td>000004</td>\n", | |
" <td>1</td>\n", | |
" <td>000021</td>\n", | |
" <td>1.292817</td>\n", | |
" <td>6.241873</td>\n", | |
" <td>CENTRE COMMERCIAL MASSENA 13</td>\n", | |
" <td>Warehouse #4</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>61</th>\n", | |
" <td>000003</td>\n", | |
" <td>2</td>\n", | |
" <td>000021</td>\n", | |
" <td>3.482784</td>\n", | |
" <td>16.815357</td>\n", | |
" <td>CENTRE COMMERCIAL MASSENA 13</td>\n", | |
" <td>Warehouse #3</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>62</th>\n", | |
" <td>000005</td>\n", | |
" <td>3</td>\n", | |
" <td>000021</td>\n", | |
" <td>4.395511</td>\n", | |
" <td>21.220847</td>\n", | |
" <td>CENTRE COMMERCIAL MASSENA 13</td>\n", | |
" <td>Warehouse #5</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"<p>63 rows × 7 columns</p>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" destination_id destination_rank origin_id proximity_distance \\\n", | |
"0 000006 1 000001 0.859860 \n", | |
"1 000001 2 000001 2.950608 \n", | |
"2 000005 3 000001 3.136645 \n", | |
"3 000001 1 000002 1.708167 \n", | |
"4 000006 2 000002 3.049405 \n", | |
".. ... ... ... ... \n", | |
"58 000003 2 000020 3.315711 \n", | |
"59 000005 3 000020 3.808590 \n", | |
"60 000004 1 000021 1.292817 \n", | |
"61 000003 2 000021 3.482784 \n", | |
"62 000005 3 000021 4.395511 \n", | |
"\n", | |
" proximity_drive_time origin_NOM destination_Name \n", | |
"0 4.151506 LES BOUTIQUES DU PALAIS DES CONGRES Warehouse #6 \n", | |
"1 14.245770 LES BOUTIQUES DU PALAIS DES CONGRES Warehouse #1 \n", | |
"2 15.143359 LES BOUTIQUES DU PALAIS DES CONGRES Warehouse #5 \n", | |
"3 8.247251 AU PRINTEMPS HAUSSMANN Warehouse #1 \n", | |
"4 14.722712 AU PRINTEMPS HAUSSMANN Warehouse #6 \n", | |
".. ... ... ... \n", | |
"58 16.008703 ITALIE 2 Warehouse #3 \n", | |
"59 18.387483 ITALIE 2 Warehouse #5 \n", | |
"60 6.241873 CENTRE COMMERCIAL MASSENA 13 Warehouse #4 \n", | |
"61 16.815357 CENTRE COMMERCIAL MASSENA 13 Warehouse #3 \n", | |
"62 21.220847 CENTRE COMMERCIAL MASSENA 13 Warehouse #5 \n", | |
"\n", | |
"[63 rows x 7 columns]" | |
] | |
}, | |
"execution_count": 5, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"%%time\n", | |
"\n", | |
"from collections import Iterable\n", | |
"\n", | |
"# mocked parameters\n", | |
"origin_id_col = 'ID'\n", | |
"origin_keep_cols = ['NOM']\n", | |
"\n", | |
"dest_id_col = 'ID'\n", | |
"dest_keep_cols = ['Name']\n", | |
"\n", | |
"\n", | |
"def add_od_df_to_solve(solve_df: pd.DataFrame, solve_join_column: str, od_df: pd.DataFrame, id_col:str='ID', \n", | |
" keep_cols: Iterable = None, keep_col_prefix:str=None, keep_col_suffix:str=None):\n", | |
"\n", | |
" # add a sequential index to the origin or destination dataframe for joining later\n", | |
" od_df['route_id'] = np.arange(len(od_df.index)) + 1\n", | |
" \n", | |
" # organize od dataframe based on keep columns\n", | |
" if len(keep_cols):\n", | |
" drop_cols = [c for c in od_df.columns if c != id_col and c not in keep_cols]\n", | |
" else:\n", | |
" drop_cols = [id_col]\n", | |
"\n", | |
" keep_df = od_df.set_index('route_id', drop=True).drop(columns=drop_cols, errors='ignore')\n", | |
" if keep_col_prefix is not None:\n", | |
" keep_df.columns = [f'{keep_col_prefix}_{c}' if c != id_col else id_col for c in keep_df.columns]\n", | |
" if keep_col_suffix is not None:\n", | |
" keep_df.columns = [f'{c}_{keep_col_suffix}' if c != id_col else id_col for c in keep_df.columns]\n", | |
" \n", | |
" # join dataframe to solve solution\n", | |
" solve_df = solve_df.join(keep_df, on=solve_join_column)\n", | |
" \n", | |
" # populate the solve_df with the UIDs\n", | |
" solve_df[solve_join_column] = solve_df[id_col]\n", | |
" \n", | |
" # drop the id column\n", | |
" solve_df.drop(columns=id_col, inplace=True)\n", | |
" \n", | |
" return solve_df\n", | |
"\n", | |
"\n", | |
"# create origin-destination solver\n", | |
"od = arcpy.nax.OriginDestinationCostMatrix(str(network_pth))\n", | |
"\n", | |
"# get the travel mode dict\n", | |
"travel_modes = arcpy.nax.GetTravelModes(str(network_pth))\n", | |
"\n", | |
"# populate properties for solver\n", | |
"od.travelMode = travel_modes['Driving Time']\n", | |
"od.timeUnits = arcpy.nax.TimeUnits.Minutes\n", | |
"od.distanceUnits = arcpy.nax.DistanceUnits.Miles\n", | |
"od.defaultDestinationCount = 3\n", | |
"od.lineShapeType = arcpy.nax.LineShapeType.StraightLine\n", | |
"\n", | |
"# populate the origins and destinations using cursors\n", | |
"with od.insertCursor(arcpy.nax.OriginDestinationCostMatrixInputDataType.Origins, field_names=['Name', 'SHAPE@JSON']) as origin_cur:\n", | |
" for _, row in origin_df.iterrows():\n", | |
" origin_cur.insertRow([row[origin_id_col], row[origin_df.spatial.name].JSON])\n", | |
" \n", | |
"with od.insertCursor(arcpy.nax.OriginDestinationCostMatrixInputDataType.Destinations, field_names=['Name', 'SHAPE@JSON']) as dest_cur:\n", | |
" for _, row in dest_df.iterrows():\n", | |
" dest_cur.insertRow([row[dest_id_col], row[dest_df.spatial.name].JSON])\n", | |
"\n", | |
"# execute the solve\n", | |
"res = od.solve()\n", | |
"\n", | |
"# if it worked\n", | |
"if res.solveSucceeded:\n", | |
"\n", | |
" # get the solved dataframe\n", | |
" solve_df = res\\\n", | |
" .toArrowTable(arcpy.nax.OriginDestinationCostMatrixOutputDataType.Lines, [\"DestinationOID\", \"DestinationRank\", \"OriginOID\", \"Total_Distance\", \"Total_Time\"])\\\n", | |
" .to_pandas()\n", | |
" \n", | |
" solve_df = add_od_df_to_solve(solve_df, 'OriginOID', origin_df, origin_id_col, origin_keep_cols, 'origin')\n", | |
" solve_df = add_od_df_to_solve(solve_df, 'DestinationOID', dest_df, dest_id_col, dest_keep_cols, 'destination')\n", | |
" \n", | |
" solve_df = solve_df.rename(columns={\n", | |
" 'OriginOID': 'origin_id',\n", | |
" 'DestinationOID': 'destination_id',\n", | |
" 'DestinationRank': 'destination_rank', \n", | |
" 'Total_Distance': 'proximity_distance', \n", | |
" 'Total_Time': 'proximity_drive_time'\n", | |
" })\n", | |
" \n", | |
"else:\n", | |
" raise RuntimeError(res.solverMessages(arcpy.nax.MessageSeverity.All))\n", | |
"\n", | |
"solve_df" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.7.10" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment