Created
June 2, 2025 01:56
-
-
Save jGaboardi/a4dbe189b4465327cebdab98b9f3365d to your computer and use it in GitHub Desktop.
bowtie_islands_from_hell
This file contains hidden or 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
| {"metadata":{"kernelspec":{"display_name":"Python 3 (ipykernel)","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.13.3"},"gist_info":{"create_date":"","gist_id":"","gist_url":""}},"nbformat_minor":5,"nbformat":4,"cells":[{"id":"566b7674-dacd-48ad-ae13-d388428a6f16","cell_type":"markdown","source":"# Bowtie + geometry order matters?\n\n* in `nodes.get_components()`","metadata":{}},{"id":"6d9229c4-10ee-4e59-b914-15ef2be6b4fd","cell_type":"code","source":"%load_ext watermark\n%watermark","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:11.422000Z","iopub.execute_input":"2025-06-02T01:55:11.422272Z","iopub.status.idle":"2025-06-02T01:55:11.446426Z","shell.execute_reply.started":"2025-06-02T01:55:11.422244Z","shell.execute_reply":"2025-06-02T01:55:11.446122Z"},"trusted":true},"outputs":[{"name":"stdout","output_type":"stream","text":"Last updated: 2025-06-01T21:55:11.436719-04:00\n\nPython implementation: CPython\nPython version : 3.13.3\nIPython version : 9.2.0\n\nCompiler : Clang 18.1.8 \nOS : Darwin\nRelease : 24.5.0\nMachine : arm64\nProcessor : arm\nCPU cores : 8\nArchitecture: 64bit\n\n"}],"execution_count":1},{"id":"c14a7ae4-01bf-4099-9728-51d3dd06d952","cell_type":"code","source":"import geopandas\nimport networkx\nimport numpy\nimport osmnx\nimport pandas\nimport shapely\n\nfrom shapely import Point, LineString\n\nimport neatnet","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:11.447016Z","iopub.execute_input":"2025-06-02T01:55:11.447160Z","iopub.status.idle":"2025-06-02T01:55:13.071317Z","shell.execute_reply.started":"2025-06-02T01:55:11.447142Z","shell.execute_reply":"2025-06-02T01:55:13.071074Z"},"trusted":true},"outputs":[],"execution_count":2},{"id":"71fc4a6a-2e49-4a2f-86ea-f1eb3df6e8c7","cell_type":"code","source":"%watermark -w\n%watermark -iv","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.071691Z","iopub.execute_input":"2025-06-02T01:55:13.071859Z","iopub.status.idle":"2025-06-02T01:55:13.075574Z","shell.execute_reply.started":"2025-06-02T01:55:13.071850Z","shell.execute_reply":"2025-06-02T01:55:13.075388Z"},"trusted":true},"outputs":[{"name":"stdout","output_type":"stream","text":"Watermark: 2.5.0\n\npandas : 2.2.3\nshapely : 2.1.1\nneatnet : 0.1.2.dev11+g84a1dca\nnetworkx : 3.4.2\ngeopandas: 1.0.1\nnumpy : 2.2.6\nosmnx : 2.0.3\n\n"}],"execution_count":3},{"id":"95a6bdd2-83cc-4a68-80c4-d4496cb2e89c","cell_type":"markdown","source":"-----------------------------------------------------\n\n## Synthetic\n\n### Mimic empirical features","metadata":{}},{"id":"2847b2de-6500-40aa-a8df-70342684efab","cell_type":"code","source":"# left edge loop points\np01, p02, p03 = Point(1, 1), Point(1, 3), Point(2, 2)\n\n# right edge loop points\np04, p05, p06 = Point(7, 1), Point(7, 3), Point(6, 2)\n\n# two middle edges points\np07, p08, p09, p10 = Point(3, 3), Point(5, 3), Point(5, 1), Point(3, 1)\n\n# left and right loops\nloop1, loop2 = LineString((p03, p01, p02, p03)), LineString((p06, p04, p05, p06))\n\n# lower & upper middle edges\nmid1 = LineString((p03, p07, p08, p06))\nmid2 = LineString((p06, p09, p10, p03))","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.075905Z","iopub.execute_input":"2025-06-02T01:55:13.076008Z","iopub.status.idle":"2025-06-02T01:55:13.078243Z","shell.execute_reply.started":"2025-06-02T01:55:13.076000Z","shell.execute_reply":"2025-06-02T01:55:13.078055Z"},"trusted":true},"outputs":[],"execution_count":4},{"id":"06007f90-3489-4624-81e5-23b01f768c72","cell_type":"markdown","source":"### Cases\n#### (1) loop, loop, edge, edge\n\ncorrect result from `nodes.get_components()` - seemingly by accident?","metadata":{}},{"id":"6444cf5d-8a94-47bc-aee5-c8b43d1e929c","cell_type":"code","source":"case_loop_loop_edge_edge = geopandas.GeoDataFrame(geometry=[loop1, loop2, mid1, mid2])\ncase_loop_loop_edge_edge.plot(cmap=\"Paired\", lw=5)\ncase_loop_loop_edge_edge","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.078461Z","iopub.execute_input":"2025-06-02T01:55:13.078527Z","iopub.status.idle":"2025-06-02T01:55:13.174552Z","shell.execute_reply.started":"2025-06-02T01:55:13.078520Z","shell.execute_reply":"2025-06-02T01:55:13.174324Z"},"trusted":true},"outputs":[{"execution_count":5,"output_type":"execute_result","data":{"text/plain":" geometry\n0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n1 LINESTRING (6 2, 7 1, 7 3, 6 2)\n2 LINESTRING (2 2, 3 3, 5 3, 6 2)\n3 LINESTRING (6 2, 5 1, 3 1, 2 2)","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>LINESTRING (2 2, 1 1, 1 3, 2 2)</td>\n </tr>\n <tr>\n <th>1</th>\n <td>LINESTRING (6 2, 7 1, 7 3, 6 2)</td>\n </tr>\n <tr>\n <th>2</th>\n <td>LINESTRING (2 2, 3 3, 5 3, 6 2)</td>\n </tr>\n <tr>\n <th>3</th>\n <td>LINESTRING (6 2, 5 1, 3 1, 2 2)</td>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 640x480 with 1 Axes>","image/png":"iVBORw0KGgoAAAANSUhEUgAAAiMAAADRCAYAAAAe77KKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAIKBJREFUeJzt3X9QVPe9//HXwsKiCGuw8uuyKEajBqKxkpuQ+COWVi8mXJ04afudtqFJ65QGTRrGmVxyZ247kzTYadpRay9WrzXx60TT70UN1t+9Eay5aMVo4/UH0W8YIQgxatxFQhZhz/2D7OrK7nLOcvZ8zo/XY+b8sWfPYd9sU/fp+bHaJEmSQERERCRInOgBiIiIyNoYI0RERCQUY4SIiIiEYowQERGRUIwRIiIiEooxQkREREIxRoiIiEgoxggREREJZRc9gBw+nw+XL19GSkoKbDab6HGIiIhIBkmS0NXVhezsbMTFhT/+YYgYuXz5Mlwul+gxiIiIKAptbW3IyckJ+7whYiQlJQXAwC+TmpoqeBoiIiKSw+PxwOVyBT7HwzFEjPhPzaSmpjJGiIiIDGaoSywUXcBaU1ODadOmBaKgqKgIe/fujbhPQ0MDZs6ciaSkJEyYMAHr1q1T8pJEhiRJEhcuMVuIzEbRkZGcnBysXLkSEydOBAC89dZbWLRoEU6ePIn8/PxB27e0tGDhwoVYunQptmzZgvfffx/PP/88xo4diyVLlqjzG0Sp5Vo3zl25iZ5b/UhNsmPGPzjxtWSH0JnI+Lpv9KDt7BV0f94Dn48fGqQ+e2I8RmeMguv+DNgT40WPQwYmSRKk8+fh+/DvwJdfwpaZibivz4Rt7FjNZ7FJw8zstLQ0/PrXv8aPfvSjQc+9/PLLqKurw7lz5wLrysvL8fe//x2NjY2yX8Pj8cDpdMLtdqtymubja9041vp50DobgIfH3YO8tORh/3yyphuf3sTFpk8gMUJIA47kREx5NBeJSQmiRyEDknw++BrqIV28GPyEw4H4RYthczpVeR25n99Rf89If38/tm3bhu7ubhQVFYXcprGxEfPnzw9at2DBAjQ1NeHWrVthf7bX64XH4wla1HT2065B6yQAxy59jpbr3aq+FlkDQ4S05u3uxfn/bkXvl+H/LCUKJWyIAIDXC9/5c4PXx5jiGDl9+jRGjRoFh8OB8vJy7NixA/fff3/IbTs7O5GRkRG0LiMjA319fbh69WrY16iurobT6Qwsat7W29vvQ5e3L+RzDBKKBkOERGGQkFIRQ8S/zWefaTjRAMUxMnnyZJw6dQpHjx7FT3/6U5SVleHs2bNht7/7Clr/WaFIV9ZWVVXB7XYHlra2NqVjhjXUWSkGCSnBECHRGCQkl5wQAQD0+7QZ6A6Kb+1NTEwMXMBaWFiI48ePY/Xq1fjDH/4waNvMzEx0dnYGrbty5QrsdjvGjBkT9jUcDgccDnEXk/qDBACvIaGwGCKkF/4g4TUkFI7sEBFk2N8zIkkSvF5vyOeKioqwa9euoHUHDhxAYWEhEhL0/X8YBglFIjdE4u1xA1dHEw2T1C9FvEOLQULh6D1EAIUx8sorr6CkpAQulwtdXV3Ytm0b6uvrsW/fPgADp1fa29uxefNmAAN3zqxduxaVlZVYunQpGhsbsXHjRmzdulX93yQGGCQUitwQSc+7B7n5Gfz3lEgVfb39aG68hC88of/yBzBIaDAjhAig8JqRTz/9FD/4wQ8wefJkFBcX49ixY9i3bx++9a1vAQA6OjrQ2toa2D4vLw979uxBfX09HnzwQbz66qtYs2aN8O8YUYLXkNCdGCIkij0xHpOLxmFkauRT2LyGhPyMEiKACt8zogU1v2fE29eP7ac7FO/H7yEhhgjpgZwjJAC/h8TqhhUi6RmwL1qkyhwx/54Rq+EREmtjiJBe8AgJDcVIR0T8GCN3GOrjg0FiTQwR0hsGCYUjO0R09ucUY+QOyYnxeCAr8mkgBom1MERIrxgkdDfZIZKQgLjHZmkzlEyMkbsUZKYySAgAQ4T0j0FCfkpCJL6kBLa7vh1dNMZICAwSYoiQUTBISHmIZGozmAKMkTAYJNbFECGjYZBYlxlCBGCMRMQgsR6GCBkVg8R6zBIiAGNkSAwS62CIkNExSKzDTCECMEZkYZCYH0OEzIJBYn5mCxGAMSIbg8S8GCJkNgwS8zJjiACMEUUYJObDECGzYpCYj1lDBGCMKMYgMQ+GCJkdg8Q8zBwiAGMkKgwS42OIkFUwSIzP7CECMEaixiAxLoYIWQ2DxLisECIAY2RYGCTGwxAhq2KQGI9VQgRgjAwbg8Q4GCJkdQwS47BSiACMEVUwSPSPIUI0gEGif1YLEYAxohoGiX4xRIiCMUj0y4ohAjBGVMUg0R+GCFFoDBL9sWqIAIwR1TFI9IMhQhQZg0Q/rBwiAGMkJhgk4jFEiORhkIhn9RABGCMxwyARhyFCpAyDRByGyADGSAwxSLTHECGKDoNEewyR2xgjMcYg0Q5DhGh4GCTaYYgEY4xogEESewwRInUwSGKPITIYY0QjDJLYYYgQqYtBEjsMkdAYIxpikKiPIUIUGwwS9TFEwlMUI9XV1XjooYeQkpKC9PR0LF68GM3NzRH3qa+vh81mG7ScP39+WIMbFYNEPQwRothikKiHIRKZohhpaGhARUUFjh49ioMHD6Kvrw/z589Hd/fQH5rNzc3o6OgILJMmTYp6aKNjkAwfQ4RIGwyS4WOIDM2uZON9+/YFPd60aRPS09Nx4sQJzJkzJ+K+6enpGD16tOIBzaogcyBGTnd4wm7jDxIAyEtL1mIsQ2CIEGnLHyTNjZfwhccbdjt/kEx5NBeJSQkaTqhfDBF5hnXNiNvtBgCkpaUNue2MGTOQlZWF4uJiHDp0KOK2Xq8XHo8naDEjHiFRjiFCJAaPkCjHEJEv6hiRJAmVlZWYNWsWCgoKwm6XlZWF9evXo7a2Ftu3b8fkyZNRXFyMw4cPh92nuroaTqczsLhcrmjH1D0GiXwMESKxGCTyMUSUsUmSFPlP9jAqKiqwe/duHDlyBDk5OYr2LS0thc1mQ11dXcjnvV4vvN7bhwI9Hg9cLhfcbjdSUyN/cA/F29eP7ac7Qj43KjEepflZw/r50fqfTk/EUzYAYAPw8Lh7LHnKhiFCpB99vf1DnrIBAEdyoiVP2RghRKTr19Ff+5+hn0zPgH3RIlVex+PxwOl0Dvn5HdWRkeXLl6Ourg6HDh1SHCIA8Mgjj+DChQthn3c4HEhNTQ1azI5HSMJjiBDpC4+QhGeEENEjRTEiSRKWLVuG7du347333kNeXl5UL3ry5ElkZYk5AqFnDJLBGCJE+sQgGYwhEj1Fd9NUVFTg7bffxrvvvouUlBR0dnYCAJxOJ0aMGAEAqKqqQnt7OzZv3gwAWLVqFcaPH4/8/Hz09vZiy5YtqK2tRW1trcq/ijnwLpvbGCJE+sa7bG5jiAyPoiMjNTU1cLvdePzxx5GVlRVY3nnnncA2HR0daG1tDTzu7e3FihUrMG3aNMyePRtHjhzB7t278dRTT6n3W5gMj5AwRIiMgkdIGCJqiPoCVi3JvQBGDr1ewBqKVS9qZYgQGY9VL2o1aoiY4gJW0oYVj5AwRIiMyYpHSIwaInrEGNE5KwUJQ4TI2KwUJAwRdTFGDMAKQcIQITIHKwQJQ0R9jBGDMHOQMESIzMXMQcIQiQ3GiIGYMUgYIkTmZMYgYYjEDmPEYMwUJAwRInMzU5AwRGKLMWJAZggShgiRNZghSBgisccYMSgjBwlDhMhajBwkDBFtMEYMzIhBwhAhsiYjBglDRDuMEYMzUpAwRIiszUhBwhDRFmPEBIwQJAwRIgKMESQMEe0xRkxCz0HCECGiO+k5SBgiYjBGTESPQcIQIaJQ9BgkDBFxGCMmo6cgYYgQUSR6ChKGiFiMERPSQ5AwRIhIDj0ECUNEPMaISYkMEoYIESkhMkgYIvrAGDExEUHCECGiaIgIEoaIfjBGTE7LIGGIENFwaBkkDBF9YYxYgBZBwhAhIjVoESQMEf1hjFhELIOEIUJEaoplkDBE9IkxYiGxCBKGCBHFQiyChCGiX4wRi1EzSBgiRBRLagYJQ0TfGCMWpEaQMESISAtqBAlDRP8YIxY1nCBhiBCRloYTJAwRY2CMWFg0QcIQISIRogkShohx2EUPQGIVZA7EyOkOT9ht/EHS+3kPus5fZYgQkRD+IGluvIQvPN6w2w0EySVMkj5BwscMESNQdGSkuroaDz30EFJSUpCeno7Fixejubl5yP0aGhowc+ZMJCUlYcKECVi3bl3UA5P65BwhGdHTB/fZzxgiRCSU/CMkt3DBk4JbcYnhN2KI6IaiGGloaEBFRQWOHj2KgwcPoq+vD/Pnz0d3d/i7LlpaWrBw4ULMnj0bJ0+exCuvvIIXXngBtbW1wx6e1BMpSEb29CHrWg+GyguGCBFpQXaQ2EfiQtoDoYOEIaIrik7T7Nu3L+jxpk2bkJ6ejhMnTmDOnDkh91m3bh1yc3OxatUqAMDUqVPR1NSEN954A0uWLIluaoqJcKdsRnj7gkLki5YGAMDIvLmBdQwRItJSqFM2kq8fXafewsiJ/wR7ajYAoDc+CT32kUjo7b29M0NEd4Z1Aavb7QYApKWlhd2msbER8+fPD1q3YMECNDU14dYt9f8paBqeUEdIrjkduDEqAcBAiLiP/Q7uY78LRAlDhIhEuPMIieTrx42ja9Dd/Gdce+/f0Oe5DJvkQ96Ns0jtvXF7J4aILkUdI5IkobKyErNmzUJBQUHY7To7O5GRkRG0LiMjA319fbh69WrIfbxeLzweT9BC2inITMXXku84rGmz4arTgasdR+A+9jtA8gGSD+5jv0NCdxNDhIiEsSfG476Hc3DzxO/x5aW/AgB8Pddx7b1/Q2b7YTi9nwdtHzdnLkNEh6KOkWXLluHDDz/E1q1bh9z27g8qSZJCrverrq6G0+kMLC6XK9oxKQqX3T24/kVv0Lr4s/+F3oZVAyHiJ/nQumslPnl/l7YDEhF9RfL148P/+FfcvFgftN7Xcx1njm3EzS+CY8R3/DikCNc5khhRxcjy5ctRV1eHQ4cOIScnJ+K2mZmZ6OzsDFp35coV2O12jBkzJuQ+VVVVcLvdgaWtrS2aMSkKl909+GvLNdx500z8mb/AsffXsN0ZIn6SDydrqtB2pE67IYmIMBAiH/z7v6D9v/8c8nlvbzeOnfx/wUHicaP/z39mkOiMohiRJAnLli3D9u3b8d577yEvL2/IfYqKinDw4MGgdQcOHEBhYSESEhJC7uNwOJCamhq0UOyFChEAiOv6LHSI+DFIiEhjQ4WIX19/L27d6gleySDRHUUxUlFRgS1btuDtt99GSkoKOjs70dnZiZ6e2/9DV1VV4Zlnngk8Li8vx6VLl1BZWYlz587hj3/8IzZu3IgVK1ao91vQsIULEQC49cj/Qe+sH0b+AQwSItKI3BCJj0/AP05/Cvc4swc/ySDRFUUxUlNTA7fbjccffxxZWVmB5Z133gls09HRgdbW1sDjvLw87NmzB/X19XjwwQfx6quvYs2aNbytV0cihYjfraLvIXXBTyL/IAYJEcWY7BBxjMQ/zn42dIj4MUh0Q9H3jPgvPI3kzTffHLRu7ty5+OCDD5S8FGlETogAwH1jR+Hrz7yIC84knP/T6vAbfhUkAOCa9c8qTkpEVic7RJJGouhf/gP35E5F/57dwLVr4Tf+Kkjin3wStuRklScmufgP5VmYohD5BydsNhvuW1yOKd9+MfIOPEJCRCpTGiJp982ALSkJ8QufAMLcLBHAIyTCMUYsKpoQCaxjkBCRhqIJET8GiTEwRixoOCESeI5BQkQaGE6I+DFI9I8xYjFqhEhgGwYJEcWQGiHixyDRN8aIhagZIoFtGSREFANqhogfg0S/GCMWEYsQCezDICEiFcUiRPwYJPrEGLGAWIZIYF8GCRGpIJYh4scg0R/GiMlpESKBn8EgIaJh0CJE/Bgk+sIYMTEtQyTwsxgkRBQFLUPEj0GiH4wRkxIRIoGfySAhIgVEhIgfg0QfGCMmJDJEAj+bQUJEMogMET8GiXiMEZPRQ4gEXoNBQkQR6CFE/BgkYjFGTERPIRJ4LQYJEYWgpxDxY5CIwxgxCT2GSOA1GSREdAc9hogfg0QMxogJ6DlEAq/NICEi6DtE/Bgk2mOMGJwRQiQwA4OEyNKMECJ+DBJtMUYMzEghEpiFQUJkSUYKET8GiXYYIwZlxBDxY5AQWYsRQ8SPQaINxogBGTlE/BgkRNZg5BDxY5DEHmPEYMwQIn4MEiJzM0OI+DFIYosxYiBmChE/BgmROZkpRPwYJLHDGDEIM4aIH4OEyFzMGCJ+DJLYYIwYgJlDxI9BQmQOZg4RPwaJ+hgjOmeFEPFjkBAZmxVCxI9Boi7GiI5ZKUT8GCRExmSlEPFjkKiHMaJTVgwRPwYJkbFYMUT8GCTqYIzokJVDxI9BQmQMVg4RPwbJ8CmOkcOHD6O0tBTZ2dmw2WzYuXNnxO3r6+ths9kGLefPn492ZlNjiNzGICHSN4bIbQyS4VEcI93d3Zg+fTrWrl2raL/m5mZ0dHQElkmTJil9adNjiAzGICHSJ4bIYAyS6NmV7lBSUoKSkhLFL5Seno7Ro0cr3s8qGCLh3be4HABw/k+rw2/0VZAAgGvWP2sxFpFlMUTC8wdJ/57dwLVr4Tf8Kkjin3wStuRk7QbUKc2uGZkxYwaysrJQXFyMQ4cORdzW6/XC4/EELWbGEBkaj5AQ6QNDZGg8QqJczGMkKysL69evR21tLbZv347JkyejuLgYhw8fDrtPdXU1nE5nYHG5XLEeUxiGiHwMEiKxGCLyMUiUsUmSNMTHYISdbTbs2LEDixcvVrRfaWkpbDYb6upCf2B4vV54vd7AY4/HA5fLBbfbjdTU1GjHHfjZff3Yfroj5HOjEuNRmp81rJ+vBEMkOh/tXBf5lA0A2OIw46fVPGVDpBKGSHSkL78c+pQNAKQ6NT1lI12/jv7a/wz9ZHoG7IsWqfI6Ho8HTqdzyM9vIbf2PvLII7hw4ULY5x0OB1JTU4MWs2GIRI9HSIi0xRCJHo+QyCMkRk6ePImsLO2OQOgNQ2T4GCRE2mCIDB+DZGiK76a5efMmLl68GHjc0tKCU6dOIS0tDbm5uaiqqkJ7ezs2b94MAFi1ahXGjx+P/Px89Pb2YsuWLaitrUVtba16v4WBMETUw7tsiGKLIaIe3mUTmeIYaWpqwrx58wKPKysrAQBlZWV488030dHRgdbW1sDzvb29WLFiBdrb2zFixAjk5+dj9+7dWLhwoQrjGwtDRH0MEqLYYIioj0ES3rAuYNWK3Atg5BB1AStDJLZ4USuRehgisaWHi1p5AasFMURij9eQEKmDIRJ7vIZkMMZIjDFEtMMgIRoehoh2GCTBGCMxxBDRHoOEKDoMEe0xSG5jjMQIQ0QcBgmRMgwRcRgkAxgjMcAQEY9BQiQPQ0Q8BgljRHUMEf1gkBBFxhDRD6sHCWNERQwR/WGQEIXGENEfKwcJY0QlDBH9YpAQBWOI6JdVg4QxogKGiP4xSIgGMET0z4pBwhgZJoaIcTBIyOoYIsZhtSBhjAwDQ8R4GCRkVQwR47FSkDBGosQQMS4GCVkNQ8S4rBIkjJEoMESMj0FCVsEQMT4rBAljRCGGiHkwSMjsGCLmYfYgYYwowBAxHwYJmRVDxHzMHCSMEZkYIubFICGzYYiYl1mDhDEiA0PE/BgkZBYMEfMzY5AwRobAELEOBgkZHUPEOswWJIyRCBgi1sMgIaNiiFiPmYKEMRIGQ8S6GCRkNAwR6zJLkDBGQmCIEIOEjIIhQmYIEsbIXRgi5McgIb1jiJCf4iD54gttBpOJMXKHnls+hggFYZCQXjFE6G5KgsT33n9pM5RMjJE79EsSQ4QGYZCQ3jBEKBzZQeL1ajOQTIwRBRgi1sUgIb1giNBQZAeJjjBGZGKIEIOERGOIkFxGCxLFMXL48GGUlpYiOzsbNpsNO3fuHHKfhoYGzJw5E0lJSZgwYQLWrVsXzazCMETIj0FCojBESCkjBYld6Q7d3d2YPn06nn32WSxZsmTI7VtaWrBw4UIsXboUW7Zswfvvv4/nn38eY8eOlbW/aAwRutt9i8sBAOf/tDr8Rl8FySd/rYMtjgcgafi8nutwt5yJuA1DhO7mD5L+PbuBa9dEjxOW4hgpKSlBSUmJ7O3XrVuH3NxcrFq1CgAwdepUNDU14Y033tB9jDBEKBy5QfLZ6fc1moisjiFC4RghSGL+V7bGxkbMnz8/aN2CBQvQ1NSEW7duxfrlo8YQoaHIOmVDpAGGCA1F76dsYh4jnZ2dyMjICFqXkZGBvr4+XL16NeQ+Xq8XHo8naNESQ4TkYpCQaAwRkkt2kAj46NPkZPbdH+qSJIVc71ddXQ2n0xlYXC6XarMkxschyR7+12aIkFIMEhKFIUJKyQkS2z1pGk40IOYxkpmZic7OzqB1V65cgd1ux5gwb0ZVVRXcbndgaWtrU20em82GvLTkkM8xRChaDBLSGkOEohUxSGw2xE2cqPlMii9gVaqoqAi7du0KWnfgwAEUFhYiISEh5D4OhwMOhyNmM03LTsUtnw8fX+uGTwLscTZMz3Zi0teSGSIUtfsWlyNp9Fj8z/9dib6em6LHIRNLyZmIrz//KzjH3y96FDIoW1IS4p94Er6jjZA++mhg5YgRiHv4EdiysrSfR/KfM5Hp5s2buHjxIgBgxowZ+O1vf4t58+YhLS0Nubm5qKqqQnt7OzZv3gxg4NbegoIC/OQnP8HSpUvR2NiI8vJybN26VfbdNB6PB06nE263G6mpqQp/xfC8ff3o7Zcwwh4HezxvvyR1+Pp60fXJ/0ffl/r6h6jIHJLuScfI9Bz+xYlUI335JdDTAzidqn8VgdzPb8VHRpqamjBv3rzA48rKSgBAWVkZ3nzzTXR0dKC1tTXwfF5eHvbs2YOXXnoJv//975GdnY01a9bo4rZehz0ejpgfGyKribMnwjl+qugxiIhksSUlAUlJYmdQemREhFgdGSEiIqLYidmRERH8vaT1Lb5EREQUPf/n9lDHPQwRI11dXQCg6i2+REREpI2uri44nc6wzxviNI3P58Ply5eRkpKi6kVbHo8HLpcLbW1tPP0jA98v+fheycf3Sj6+V/LxvZIvlu+VJEno6upCdnY24iJcHGuIIyNxcXHIycmJ2c9PTU3lf6wK8P2Sj++VfHyv5ON7JR/fK/li9V5FOiLix/tZiYiISCjGCBEREQll6RhxOBz4+c9/HtNvezUTvl/y8b2Sj++VfHyv5ON7JZ8e3itDXMBKRERE5mXpIyNEREQkHmOEiIiIhGKMEBERkVCMESIiIhLKsjFy+PBhlJaWIjs7GzabDTt37hQ9ki5VV1fjoYceQkpKCtLT07F48WI0NzeLHkuXampqMG3atMAXBxUVFWHv3r2ixzKE6upq2Gw2/OxnPxM9ii794he/gM1mC1oyMzNFj6Vb7e3t+P73v48xY8Zg5MiRePDBB3HixAnRY+nO+PHjB/13ZbPZUFFRofkslo2R7u5uTJ8+HWvXrhU9iq41NDSgoqICR48excGDB9HX14f58+eju7tb9Gi6k5OTg5UrV6KpqQlNTU34xje+gUWLFuHMmTOiR9O148ePY/369Zg2bZroUXQtPz8fHR0dgeX06dOiR9Klzz//HI899hgSEhKwd+9enD17Fr/5zW8wevRo0aPpzvHjx4P+mzp48CAA4Omnn9Z8FkN8HXwslJSUoKSkRPQYurdv376gx5s2bUJ6ejpOnDiBOXPmCJpKn0pLS4Me//KXv0RNTQ2OHj2K/Px8QVPp282bN/G9730PGzZswGuvvSZ6HF2z2+08GiLDr371K7hcLmzatCmwbvz48eIG0rGxY8cGPV65ciXuvfdezJ07V/NZLHtkhKLjdrsBAGlpaYIn0bf+/n5s27YN3d3dKCoqEj2OblVUVOCJJ57AN7/5TdGj6N6FCxeQnZ2NvLw8fPe738XHH38seiRdqqurQ2FhIZ5++mmkp6djxowZ2LBhg+ixdK+3txdbtmzBc889p+o/SCsXY4RkkyQJlZWVmDVrFgoKCkSPo0unT5/GqFGj4HA4UF5ejh07duD+++8XPZYubdu2DR988AGqq6tFj6J7Dz/8MDZv3oz9+/djw4YN6OzsxKOPPopr166JHk13Pv74Y9TU1GDSpEnYv38/ysvL8cILL2Dz5s2iR9O1nTt34saNG/jhD38o5PUte5qGlFu2bBk+/PBDHDlyRPQoujV58mScOnUKN27cQG1tLcrKytDQ0MAguUtbWxtefPFFHDhwAElJSaLH0b07Tyk/8MADKCoqwr333ou33noLlZWVAifTH5/Ph8LCQrz++usAgBkzZuDMmTOoqanBM888I3g6/dq4cSNKSkqQnZ0t5PV5ZIRkWb58Oerq6nDo0CHk5OSIHke3EhMTMXHiRBQWFqK6uhrTp0/H6tWrRY+lOydOnMCVK1cwc+ZM2O122O12NDQ0YM2aNbDb7ejv7xc9oq4lJyfjgQcewIULF0SPojtZWVmD4n/q1KlobW0VNJH+Xbp0CX/5y1/w4x//WNgMPDJCEUmShOXLl2PHjh2or69HXl6e6JEMRZIkeL1e0WPoTnFx8aC7QZ599llMmTIFL7/8MuLj4wVNZgxerxfnzp3D7NmzRY+iO4899tigrx/46KOPMG7cOEET6Z//xoQnnnhC2AyWjZGbN2/i4sWLgcctLS04deoU0tLSkJubK3AyfamoqMDbb7+Nd999FykpKejs7AQAOJ1OjBgxQvB0+vLKK6+gpKQELpcLXV1d2LZtG+rr6wfdkURASkrKoOuOkpOTMWbMGF6PFMKKFStQWlqK3NxcXLlyBa+99ho8Hg/KyspEj6Y7L730Eh599FG8/vrr+Pa3v42//e1vWL9+PdavXy96NF3y+XzYtGkTysrKYLcLTALJog4dOiQBGLSUlZWJHk1XQr1HAKRNmzaJHk13nnvuOWncuHFSYmKiNHbsWKm4uFg6cOCA6LEMY+7cudKLL74oegxd+s53viNlZWVJCQkJUnZ2tvTUU09JZ86cET2Wbu3atUsqKCiQHA6HNGXKFGn9+vWiR9Kt/fv3SwCk5uZmoXPYJEmSxGQQERERES9gJSIiIsEYI0RERCQUY4SIiIiEYowQERGRUIwRIiIiEooxQkREREIxRoiIiEgoxggREREJxRghIiIioRgjREREJBRjhIiIiIRijBAREZFQ/wvS4awKCqrRmQAAAABJRU5ErkJggg=="},"metadata":{}}],"execution_count":5},{"id":"01593e9e-dbc1-43f9-92c6-e6516f9dac52","cell_type":"markdown","source":"#### (2) loop, edge, edge, loop\n\nincorrect result from `nodes.get_components()`","metadata":{}},{"id":"ed70ab37-ac04-470e-ad3b-334bcab17374","cell_type":"code","source":"case_loop_edge_edge_loop = geopandas.GeoDataFrame(geometry=[loop1, mid1, mid2, loop2])\ncase_loop_edge_edge_loop.plot(cmap=\"Paired\", lw=5)\ncase_loop_edge_edge_loop","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.176003Z","iopub.execute_input":"2025-06-02T01:55:13.176093Z","iopub.status.idle":"2025-06-02T01:55:13.211320Z","shell.execute_reply.started":"2025-06-02T01:55:13.176084Z","shell.execute_reply":"2025-06-02T01:55:13.211081Z"},"trusted":true},"outputs":[{"execution_count":6,"output_type":"execute_result","data":{"text/plain":" geometry\n0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n1 LINESTRING (2 2, 3 3, 5 3, 6 2)\n2 LINESTRING (6 2, 5 1, 3 1, 2 2)\n3 LINESTRING (6 2, 7 1, 7 3, 6 2)","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>LINESTRING (2 2, 1 1, 1 3, 2 2)</td>\n </tr>\n <tr>\n <th>1</th>\n <td>LINESTRING (2 2, 3 3, 5 3, 6 2)</td>\n </tr>\n <tr>\n <th>2</th>\n <td>LINESTRING (6 2, 5 1, 3 1, 2 2)</td>\n </tr>\n <tr>\n <th>3</th>\n <td>LINESTRING (6 2, 7 1, 7 3, 6 2)</td>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 640x480 with 1 Axes>","image/png":"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"},"metadata":{}}],"execution_count":6},{"id":"98c5ff05-3676-48af-b680-e94bc5b85ac9","cell_type":"markdown","source":"--------------------\n## Break down `remove_interstitial_nodes()` & `get_components()`","metadata":{}},{"id":"be1e4f93-84dd-42d5-8ee1-454449516ac4","cell_type":"code","source":"# case (1)\n#synthetic_edges = case_loop_loop_edge_edge.copy()\n\n# case (2)\nsynthetic_edges = case_loop_edge_edge_loop.copy()\n\nsynthetic_edges.plot(cmap=\"Paired\", lw=5)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.211661Z","iopub.execute_input":"2025-06-02T01:55:13.211732Z","iopub.status.idle":"2025-06-02T01:55:13.245711Z","shell.execute_reply.started":"2025-06-02T01:55:13.211724Z","shell.execute_reply":"2025-06-02T01:55:13.245467Z"},"trusted":true},"outputs":[{"execution_count":7,"output_type":"execute_result","data":{"text/plain":"<Axes: >"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 640x480 with 1 Axes>","image/png":"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"},"metadata":{}}],"execution_count":7},{"id":"ee548873-71fe-482f-b5de-527a4244a5ac","cell_type":"markdown","source":"### Internal processing prior to `get_components()` [call](https://github.com/uscuni/neatnet/blob/84a1dcac84b50d88be1eed294d3e00546a6c5f73/neatnet/nodes.py#L385)\n\n* [here](https://github.com/uscuni/neatnet/blob/84a1dcac84b50d88be1eed294d3e00546a6c5f73/neatnet/nodes.py#L383)","metadata":{}},{"id":"241349c8-c053-4ded-acd6-e3a2c98bfddf","cell_type":"code","source":"synthetic_edges = synthetic_edges.explode(ignore_index=True)\nsynthetic_edges","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.246040Z","iopub.execute_input":"2025-06-02T01:55:13.246111Z","iopub.status.idle":"2025-06-02T01:55:13.250441Z","shell.execute_reply.started":"2025-06-02T01:55:13.246103Z","shell.execute_reply":"2025-06-02T01:55:13.250221Z"},"trusted":true},"outputs":[{"execution_count":8,"output_type":"execute_result","data":{"text/plain":" geometry\n0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n1 LINESTRING (2 2, 3 3, 5 3, 6 2)\n2 LINESTRING (6 2, 5 1, 3 1, 2 2)\n3 LINESTRING (6 2, 7 1, 7 3, 6 2)","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>LINESTRING (2 2, 1 1, 1 3, 2 2)</td>\n </tr>\n <tr>\n <th>1</th>\n <td>LINESTRING (2 2, 3 3, 5 3, 6 2)</td>\n </tr>\n <tr>\n <th>2</th>\n <td>LINESTRING (6 2, 5 1, 3 1, 2 2)</td>\n </tr>\n <tr>\n <th>3</th>\n <td>LINESTRING (6 2, 7 1, 7 3, 6 2)</td>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":8},{"id":"97fa95b3-e1c4-4ad0-a603-cba37ed554d9","cell_type":"code","source":"synthetic_edges_get_components_input = synthetic_edges.geometry\nsynthetic_edges_get_components_input","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.250778Z","iopub.execute_input":"2025-06-02T01:55:13.250874Z","iopub.status.idle":"2025-06-02T01:55:13.253341Z","shell.execute_reply.started":"2025-06-02T01:55:13.250865Z","shell.execute_reply":"2025-06-02T01:55:13.253110Z"},"trusted":true},"outputs":[{"execution_count":9,"output_type":"execute_result","data":{"text/plain":"0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n1 LINESTRING (2 2, 3 3, 5 3, 6 2)\n2 LINESTRING (6 2, 5 1, 3 1, 2 2)\n3 LINESTRING (6 2, 7 1, 7 3, 6 2)\nName: geometry, dtype: geometry"},"metadata":{}}],"execution_count":9},{"id":"55948839-7483-4996-b531-1dead6d24fcd","cell_type":"markdown","source":"### Inside `get_components()`\n\n* [here](https://github.com/uscuni/neatnet/blob/84a1dcac84b50d88be1eed294d3e00546a6c5f73/neatnet/nodes.py#L134-L192)","metadata":{}},{"id":"33158bd8-e81b-4fd0-92d6-b9eade196449","cell_type":"code","source":"# convert edges geoseries to numpy array\nedgelines = numpy.array(synthetic_edges_get_components_input)\nedgelines","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.253701Z","iopub.execute_input":"2025-06-02T01:55:13.253820Z","iopub.status.idle":"2025-06-02T01:55:13.255880Z","shell.execute_reply.started":"2025-06-02T01:55:13.253813Z","shell.execute_reply":"2025-06-02T01:55:13.255697Z"},"trusted":true},"outputs":[{"execution_count":10,"output_type":"execute_result","data":{"text/plain":"array([<LINESTRING (2 2, 1 1, 1 3, 2 2)>,\n <LINESTRING (2 2, 3 3, 5 3, 6 2)>,\n <LINESTRING (6 2, 5 1, 3 1, 2 2)>,\n <LINESTRING (6 2, 7 1, 7 3, 6 2)>], dtype=object)"},"metadata":{}}],"execution_count":10},{"id":"bd9ec238-5f15-4cdc-9e41-c05aa5bb7fa9","cell_type":"code","source":"# fetch edge starting points\nstart_points = shapely.get_point(edgelines, 0)\nstart_points","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.256181Z","iopub.execute_input":"2025-06-02T01:55:13.256342Z","iopub.status.idle":"2025-06-02T01:55:13.258203Z","shell.execute_reply.started":"2025-06-02T01:55:13.256334Z","shell.execute_reply":"2025-06-02T01:55:13.258019Z"},"trusted":true},"outputs":[{"execution_count":11,"output_type":"execute_result","data":{"text/plain":"array([<POINT (2 2)>, <POINT (2 2)>, <POINT (6 2)>, <POINT (6 2)>],\n dtype=object)"},"metadata":{}}],"execution_count":11},{"id":"a3efe6bb-5e8a-42ff-b7ab-de91f8b5bcdf","cell_type":"code","source":"# fetch edge ending points\nend_points = shapely.get_point(edgelines, -1)\nend_points","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.258486Z","iopub.execute_input":"2025-06-02T01:55:13.258568Z","iopub.status.idle":"2025-06-02T01:55:13.260437Z","shell.execute_reply.started":"2025-06-02T01:55:13.258561Z","shell.execute_reply":"2025-06-02T01:55:13.260264Z"},"trusted":true},"outputs":[{"execution_count":12,"output_type":"execute_result","data":{"text/plain":"array([<POINT (2 2)>, <POINT (6 2)>, <POINT (2 2)>, <POINT (6 2)>],\n dtype=object)"},"metadata":{}}],"execution_count":12},{"id":"2c61de34-536e-478e-8feb-125e7ab5a185","cell_type":"code","source":"# 1. combine start and end point into 1 array\n# 2. retain only unique\npoints = shapely.points(\n numpy.unique(\n shapely.get_coordinates(numpy.concatenate([start_points, end_points])), axis=0\n )\n)\npoints","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.260737Z","iopub.execute_input":"2025-06-02T01:55:13.260796Z","iopub.status.idle":"2025-06-02T01:55:13.262844Z","shell.execute_reply.started":"2025-06-02T01:55:13.260790Z","shell.execute_reply":"2025-06-02T01:55:13.262668Z"},"trusted":true},"outputs":[{"execution_count":13,"output_type":"execute_result","data":{"text/plain":"array([<POINT (2 2)>, <POINT (6 2)>], dtype=object)"},"metadata":{}}],"execution_count":13},{"id":"71de7b3f-c100-4d1b-bf06-848b594db508","cell_type":"code","source":"# query topological bounds of edgeline geometries\n# -- ** loops have no topological bounds and are ommited from query **\ninp, res = shapely.STRtree(shapely.boundary(edgelines)).query(\n points, predicate=\"intersects\"\n)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.263103Z","iopub.execute_input":"2025-06-02T01:55:13.263166Z","iopub.status.idle":"2025-06-02T01:55:13.264746Z","shell.execute_reply.started":"2025-06-02T01:55:13.263158Z","shell.execute_reply":"2025-06-02T01:55:13.264552Z"},"trusted":true},"outputs":[],"execution_count":14},{"id":"82f3c94b-f34b-4f6e-b8e6-2ccf3958f3fd","cell_type":"code","source":"# input indices\ninp","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.265042Z","iopub.execute_input":"2025-06-02T01:55:13.265097Z","iopub.status.idle":"2025-06-02T01:55:13.266911Z","shell.execute_reply.started":"2025-06-02T01:55:13.265091Z","shell.execute_reply":"2025-06-02T01:55:13.266742Z"},"trusted":true},"outputs":[{"execution_count":15,"output_type":"execute_result","data":{"text/plain":"array([0, 0, 1, 1])"},"metadata":{}}],"execution_count":15},{"id":"1b339508-78ff-415d-b259-2ca35721c679","cell_type":"code","source":"# result indices\nres","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.267198Z","iopub.execute_input":"2025-06-02T01:55:13.267252Z","iopub.status.idle":"2025-06-02T01:55:13.268971Z","shell.execute_reply.started":"2025-06-02T01:55:13.267246Z","shell.execute_reply":"2025-06-02T01:55:13.268797Z"},"trusted":true},"outputs":[{"execution_count":16,"output_type":"execute_result","data":{"text/plain":"array([1, 2, 1, 2])"},"metadata":{}}],"execution_count":16},{"id":"ac43edcc-92e5-4c9e-a6b0-5681c1100514","cell_type":"code","source":"# fetch unique input indices & counts\nunique, counts = numpy.unique(inp, return_counts=True)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.269184Z","iopub.execute_input":"2025-06-02T01:55:13.269243Z","iopub.status.idle":"2025-06-02T01:55:13.270697Z","shell.execute_reply.started":"2025-06-02T01:55:13.269236Z","shell.execute_reply":"2025-06-02T01:55:13.270531Z"},"trusted":true},"outputs":[],"execution_count":17},{"id":"015e7f26-1f2d-4507-bfad-e8905349cee9","cell_type":"code","source":"# unique input indices (point)\nunique","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.271081Z","iopub.execute_input":"2025-06-02T01:55:13.271289Z","iopub.status.idle":"2025-06-02T01:55:13.273099Z","shell.execute_reply.started":"2025-06-02T01:55:13.271280Z","shell.execute_reply":"2025-06-02T01:55:13.272933Z"},"trusted":true},"outputs":[{"execution_count":18,"output_type":"execute_result","data":{"text/plain":"array([0, 1])"},"metadata":{}}],"execution_count":18},{"id":"92926267-60f3-4ea6-ac58-06035d09c3dd","cell_type":"code","source":"# unique input count (point)\ncounts","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.273385Z","iopub.execute_input":"2025-06-02T01:55:13.273558Z","iopub.status.idle":"2025-06-02T01:55:13.275234Z","shell.execute_reply.started":"2025-06-02T01:55:13.273550Z","shell.execute_reply":"2025-06-02T01:55:13.275059Z"},"trusted":true},"outputs":[{"execution_count":19,"output_type":"execute_result","data":{"text/plain":"array([2, 2])"},"metadata":{}}],"execution_count":19},{"id":"fff9c233-1f75-481a-9cdd-afb80491a9e3","cell_type":"code","source":"# create a mask to determine points intersecting 2 geometries\nmask = numpy.isin(inp, unique[counts == 2])\nmask","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.275423Z","iopub.execute_input":"2025-06-02T01:55:13.275481Z","iopub.status.idle":"2025-06-02T01:55:13.277500Z","shell.execute_reply.started":"2025-06-02T01:55:13.275474Z","shell.execute_reply":"2025-06-02T01:55:13.277288Z"},"trusted":true},"outputs":[{"execution_count":20,"output_type":"execute_result","data":{"text/plain":"array([ True, True, True, True])"},"metadata":{}}],"execution_count":20},{"id":"554c141f-5c93-4805-b27f-2dff2bd34a3c","cell_type":"code","source":"# determine input to merge\nmerge_inp = inp[mask]\nmerge_inp","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.280458Z","iopub.execute_input":"2025-06-02T01:55:13.280655Z","iopub.status.idle":"2025-06-02T01:55:13.283175Z","shell.execute_reply.started":"2025-06-02T01:55:13.280626Z","shell.execute_reply":"2025-06-02T01:55:13.282966Z"},"trusted":true},"outputs":[{"execution_count":21,"output_type":"execute_result","data":{"text/plain":"array([0, 0, 1, 1])"},"metadata":{}}],"execution_count":21},{"id":"b7931ab7-7db3-40b9-ae19-8899dd0dbd6a","cell_type":"code","source":"# determine result to merge\nmerge_res = res[mask]\nmerge_res","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.283419Z","iopub.execute_input":"2025-06-02T01:55:13.283482Z","iopub.status.idle":"2025-06-02T01:55:13.285423Z","shell.execute_reply.started":"2025-06-02T01:55:13.283475Z","shell.execute_reply":"2025-06-02T01:55:13.285216Z"},"trusted":true},"outputs":[{"execution_count":22,"output_type":"execute_result","data":{"text/plain":"array([1, 2, 1, 2])"},"metadata":{}}],"execution_count":22},{"id":"412c4c01-cbe9-454d-a101-c20a698951ad","cell_type":"code","source":"# isolate edgeline index of loops\nclosed = numpy.arange(len(edgelines))[shapely.is_closed(edgelines)]\nclosed","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.285675Z","iopub.execute_input":"2025-06-02T01:55:13.285736Z","iopub.status.idle":"2025-06-02T01:55:13.287880Z","shell.execute_reply.started":"2025-06-02T01:55:13.285730Z","shell.execute_reply":"2025-06-02T01:55:13.287690Z"},"trusted":true},"outputs":[{"execution_count":23,"output_type":"execute_result","data":{"text/plain":"array([0, 3])"},"metadata":{}}],"execution_count":23},{"id":"d1588b9f-e115-4ce5-ade7-42c83ecc6057","cell_type":"code","source":"# mask to to consider for merging\n# - edges to not consider\n# - points to not consider\nmask = numpy.isin(merge_res, closed) | numpy.isin(merge_inp, closed)\nmask","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.288312Z","iopub.execute_input":"2025-06-02T01:55:13.288409Z","iopub.status.idle":"2025-06-02T01:55:13.290573Z","shell.execute_reply.started":"2025-06-02T01:55:13.288369Z","shell.execute_reply":"2025-06-02T01:55:13.290392Z"},"trusted":true},"outputs":[{"execution_count":24,"output_type":"execute_result","data":{"text/plain":"array([ True, True, False, False])"},"metadata":{}}],"execution_count":24},{"id":"4594b8a8-c088-4645-8abd-cbc4f0435a09","cell_type":"code","source":"# inverse of point mask\nmerge_inp = merge_inp[~mask]\nmerge_inp","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.290891Z","iopub.execute_input":"2025-06-02T01:55:13.290950Z","iopub.status.idle":"2025-06-02T01:55:13.292940Z","shell.execute_reply.started":"2025-06-02T01:55:13.290943Z","shell.execute_reply":"2025-06-02T01:55:13.292749Z"},"trusted":true},"outputs":[{"execution_count":25,"output_type":"execute_result","data":{"text/plain":"array([1, 1])"},"metadata":{}}],"execution_count":25},{"id":"abad3d32-fbb2-47ea-8416-fef37e433326","cell_type":"code","source":"# inverse of edge mask\nmerge_res = merge_res[~mask]\nmerge_res","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.293230Z","iopub.execute_input":"2025-06-02T01:55:13.293315Z","iopub.status.idle":"2025-06-02T01:55:13.295203Z","shell.execute_reply.started":"2025-06-02T01:55:13.293307Z","shell.execute_reply":"2025-06-02T01:55:13.295012Z"},"trusted":true},"outputs":[{"execution_count":26,"output_type":"execute_result","data":{"text/plain":"array([1, 2])"},"metadata":{}}],"execution_count":26},{"id":"29257f2e-5999-4218-a429-203e5694c27c","cell_type":"code","source":"#g = networkx.Graph(list(zip((merge_inp * -1) - 1, merge_res, strict=True)))\n#g","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.295508Z","iopub.execute_input":"2025-06-02T01:55:13.295572Z","iopub.status.idle":"2025-06-02T01:55:13.296849Z","shell.execute_reply.started":"2025-06-02T01:55:13.295566Z","shell.execute_reply":"2025-06-02T01:55:13.296675Z"},"trusted":true},"outputs":[],"execution_count":27},{"id":"b8b00225-5f5e-494c-8c55-cb9c43a33746","cell_type":"code","source":"nodes_component_list = list(zip((merge_inp * -1) - 1, merge_res, strict=True))\nnodes_component_list","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.297066Z","iopub.execute_input":"2025-06-02T01:55:13.297121Z","iopub.status.idle":"2025-06-02T01:55:13.299028Z","shell.execute_reply.started":"2025-06-02T01:55:13.297115Z","shell.execute_reply":"2025-06-02T01:55:13.298861Z"},"trusted":true},"outputs":[{"execution_count":28,"output_type":"execute_result","data":{"text/plain":"[(np.int64(-2), np.int64(1)), (np.int64(-2), np.int64(2))]"},"metadata":{}}],"execution_count":28},{"id":"96dacc3f-2793-404f-b9e2-46a8702195a9","cell_type":"code","source":"g = networkx.Graph(nodes_component_list)\ng","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.299337Z","iopub.execute_input":"2025-06-02T01:55:13.299396Z","iopub.status.idle":"2025-06-02T01:55:13.302045Z","shell.execute_reply.started":"2025-06-02T01:55:13.299389Z","shell.execute_reply":"2025-06-02T01:55:13.301803Z"},"trusted":true},"outputs":[{"execution_count":29,"output_type":"execute_result","data":{"text/plain":"<networkx.classes.graph.Graph at 0x162d5a3c0>"},"metadata":{}}],"execution_count":29},{"id":"79bc3c25-5cbe-4780-bf81-28dc591d2aa1","cell_type":"code","source":"components = {\n i: {v for v in k if v > -1} for i, k in enumerate(networkx.connected_components(g))\n}\ncomponents","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.302335Z","iopub.execute_input":"2025-06-02T01:55:13.302428Z","iopub.status.idle":"2025-06-02T01:55:13.304949Z","shell.execute_reply.started":"2025-06-02T01:55:13.302420Z","shell.execute_reply":"2025-06-02T01:55:13.304753Z"},"trusted":true},"outputs":[{"execution_count":30,"output_type":"execute_result","data":{"text/plain":"{0: {np.int64(1), np.int64(2)}}"},"metadata":{}}],"execution_count":30},{"id":"17d6a824-cb58-4b0e-a2f4-36c9259b368d","cell_type":"code","source":"component_labels = {value: key for key in components for value in components[key]}\ncomponent_labels","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.305292Z","iopub.execute_input":"2025-06-02T01:55:13.305375Z","iopub.status.idle":"2025-06-02T01:55:13.307265Z","shell.execute_reply.started":"2025-06-02T01:55:13.305367Z","shell.execute_reply":"2025-06-02T01:55:13.307044Z"},"trusted":true},"outputs":[{"execution_count":31,"output_type":"execute_result","data":{"text/plain":"{np.int64(1): 0, np.int64(2): 0}"},"metadata":{}}],"execution_count":31},{"id":"99d34ae9-c2fc-44e8-bf59-0e46f9b321dd","cell_type":"code","source":"labels = pandas.Series(component_labels, index=range(len(edgelines)))\nlabels","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.307569Z","iopub.execute_input":"2025-06-02T01:55:13.307632Z","iopub.status.idle":"2025-06-02T01:55:13.310833Z","shell.execute_reply.started":"2025-06-02T01:55:13.307625Z","shell.execute_reply":"2025-06-02T01:55:13.310632Z"},"trusted":true},"outputs":[{"execution_count":32,"output_type":"execute_result","data":{"text/plain":"0 NaN\n1 0.0\n2 0.0\n3 NaN\ndtype: float64"},"metadata":{}}],"execution_count":32},{"id":"96d4258c-31bf-4a79-9016-21c3d23e7c7b","cell_type":"code","source":"max_label = len(edgelines) - 1 if pandas.isna(labels.max()) else int(labels.max())\nmax_label","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.311075Z","iopub.execute_input":"2025-06-02T01:55:13.311138Z","iopub.status.idle":"2025-06-02T01:55:13.313207Z","shell.execute_reply.started":"2025-06-02T01:55:13.311131Z","shell.execute_reply":"2025-06-02T01:55:13.313018Z"},"trusted":true},"outputs":[{"execution_count":33,"output_type":"execute_result","data":{"text/plain":"0"},"metadata":{}}],"execution_count":33},{"id":"baaf08db-83b6-4d20-ae64-78c0c7154eb9","cell_type":"code","source":"filling = pandas.Series(range(max_label + 1, max_label + len(edgelines) + 1))\nfilling","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.313406Z","iopub.execute_input":"2025-06-02T01:55:13.313466Z","iopub.status.idle":"2025-06-02T01:55:13.315840Z","shell.execute_reply.started":"2025-06-02T01:55:13.313459Z","shell.execute_reply":"2025-06-02T01:55:13.315461Z"},"trusted":true},"outputs":[{"execution_count":34,"output_type":"execute_result","data":{"text/plain":"0 1\n1 2\n2 3\n3 4\ndtype: int64"},"metadata":{}}],"execution_count":34},{"id":"8fd37a1f-132c-4eb8-8453-35faa8492aa1","cell_type":"code","source":"labels = labels.fillna(filling)\nlabels","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.316195Z","iopub.execute_input":"2025-06-02T01:55:13.316269Z","iopub.status.idle":"2025-06-02T01:55:13.318697Z","shell.execute_reply.started":"2025-06-02T01:55:13.316262Z","shell.execute_reply":"2025-06-02T01:55:13.318491Z"},"trusted":true},"outputs":[{"execution_count":35,"output_type":"execute_result","data":{"text/plain":"0 1.0\n1 0.0\n2 0.0\n3 4.0\ndtype: float64"},"metadata":{}}],"execution_count":35},{"id":"7222c8ea-1050-4239-aabc-6adf5f26b2ba","cell_type":"code","source":"labels = labels.values\nlabels","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.319024Z","iopub.execute_input":"2025-06-02T01:55:13.319130Z","iopub.status.idle":"2025-06-02T01:55:13.321207Z","shell.execute_reply.started":"2025-06-02T01:55:13.319123Z","shell.execute_reply":"2025-06-02T01:55:13.320939Z"},"trusted":true},"outputs":[{"execution_count":36,"output_type":"execute_result","data":{"text/plain":"array([1., 0., 0., 4.])"},"metadata":{}}],"execution_count":36},{"id":"a94d8ecb-ef54-4e9e-b83a-2572b1b2006c","cell_type":"markdown","source":"### Following `get_components()`\n\n* [here](https://github.com/uscuni/neatnet/blob/84a1dcac84b50d88be1eed294d3e00546a6c5f73/neatnet/nodes.py#L387-L404)","metadata":{}},{"id":"5b1c603e-5bfe-43c1-a326-e5d8406824dd","cell_type":"code","source":"data = synthetic_edges.drop(labels=synthetic_edges.geometry.name, axis=1)\ndata","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.321521Z","iopub.execute_input":"2025-06-02T01:55:13.321583Z","iopub.status.idle":"2025-06-02T01:55:13.324573Z","shell.execute_reply.started":"2025-06-02T01:55:13.321577Z","shell.execute_reply":"2025-06-02T01:55:13.324377Z"},"trusted":true},"outputs":[{"execution_count":37,"output_type":"execute_result","data":{"text/plain":"Empty DataFrame\nColumns: []\nIndex: [0, 1, 2, 3]","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 </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n </tr>\n <tr>\n <th>1</th>\n </tr>\n <tr>\n <th>2</th>\n </tr>\n <tr>\n <th>3</th>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":37},{"id":"af278fd3-42b5-4352-9232-dda7fd08ac32","cell_type":"code","source":"aggfunc = \"first\"\nkwargs = {}\n\naggregated_data = data.groupby(by=labels).agg(aggfunc, **kwargs)\naggregated_data","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.324925Z","iopub.execute_input":"2025-06-02T01:55:13.325047Z","iopub.status.idle":"2025-06-02T01:55:13.328142Z","shell.execute_reply.started":"2025-06-02T01:55:13.325041Z","shell.execute_reply":"2025-06-02T01:55:13.327919Z"},"trusted":true},"outputs":[{"execution_count":38,"output_type":"execute_result","data":{"text/plain":"Empty DataFrame\nColumns: []\nIndex: [0.0, 1.0, 4.0]","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 </tr>\n </thead>\n <tbody>\n <tr>\n <th>0.0</th>\n </tr>\n <tr>\n <th>1.0</th>\n </tr>\n <tr>\n <th>4.0</th>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":38},{"id":"ee115588-1157-46c1-8a37-e3558c883753","cell_type":"code","source":"aggregated_data.columns = aggregated_data.columns.to_flat_index()\naggregated_data","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.328481Z","iopub.execute_input":"2025-06-02T01:55:13.328604Z","iopub.status.idle":"2025-06-02T01:55:13.330912Z","shell.execute_reply.started":"2025-06-02T01:55:13.328595Z","shell.execute_reply":"2025-06-02T01:55:13.330730Z"},"trusted":true},"outputs":[{"execution_count":39,"output_type":"execute_result","data":{"text/plain":"Empty DataFrame\nColumns: []\nIndex: [0.0, 1.0, 4.0]","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 </tr>\n </thead>\n <tbody>\n <tr>\n <th>0.0</th>\n </tr>\n <tr>\n <th>1.0</th>\n </tr>\n <tr>\n <th>4.0</th>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":39},{"id":"a74b7c78-f818-4af7-94e1-d520901e5659","cell_type":"markdown","source":"### Merges our 2 lines onto 1 loop due to labeling from `get_components()`\n\n#### internal merging func\n\n* [here](https://github.com/uscuni/neatnet/blob/84a1dcac84b50d88be1eed294d3e00546a6c5f73/neatnet/nodes.py#L373-L375)","metadata":{}},{"id":"128bb2f0-8727-42a2-bc90-cc5e0a14ce8a","cell_type":"code","source":"def merge_geometries(block):\n \"\"\"Helper in processing the spatial component.\"\"\"\n return shapely.line_merge(shapely.GeometryCollection(block.values))","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.331239Z","iopub.execute_input":"2025-06-02T01:55:13.331339Z","iopub.status.idle":"2025-06-02T01:55:13.332767Z","shell.execute_reply.started":"2025-06-02T01:55:13.331333Z","shell.execute_reply":"2025-06-02T01:55:13.332585Z"},"trusted":true},"outputs":[],"execution_count":40},{"id":"edb7a590-9cc8-4b9c-a0b8-2a92e13451d2","cell_type":"markdown","source":"### Case 2 gets merged back into loop\n\n* \"loop, edge, edge, loop\"\n* due to the two middle connecting edged being labels as 1 component","metadata":{}},{"id":"f00bb454-a7ce-4d38-b9ae-cd6edf54154c","cell_type":"code","source":"g = (\n synthetic_edges\n .groupby(group_keys=False, by=labels)\n [synthetic_edges.geometry.name]\n .agg(merge_geometries)\n)\naggregated_geometry = geopandas.GeoDataFrame(\n g, geometry=synthetic_edges.geometry.name, crs=synthetic_edges.crs\n)\naggregated_geometry.plot(cmap=\"Paired\", lw=5)\naggregated_geometry","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.333108Z","iopub.execute_input":"2025-06-02T01:55:13.333208Z","iopub.status.idle":"2025-06-02T01:55:13.371078Z","shell.execute_reply.started":"2025-06-02T01:55:13.333201Z","shell.execute_reply":"2025-06-02T01:55:13.370828Z"},"trusted":true},"outputs":[{"execution_count":41,"output_type":"execute_result","data":{"text/plain":" geometry\n0.0 LINESTRING (2 2, 3 3, 5 3, 6 2, 5 1, 3 1, 2 2)\n1.0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n4.0 LINESTRING (6 2, 7 1, 7 3, 6 2)","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0.0</th>\n <td>LINESTRING (2 2, 3 3, 5 3, 6 2, 5 1, 3 1, 2 2)</td>\n </tr>\n <tr>\n <th>1.0</th>\n <td>LINESTRING (2 2, 1 1, 1 3, 2 2)</td>\n </tr>\n <tr>\n <th>4.0</th>\n <td>LINESTRING (6 2, 7 1, 7 3, 6 2)</td>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 640x480 with 1 Axes>","image/png":"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"},"metadata":{}}],"execution_count":41},{"id":"55e5ab89-acb6-4c99-bf94-29d05f78c932","cell_type":"code","source":"aggregated = aggregated_geometry.join(aggregated_data)\naggregated","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.371395Z","iopub.execute_input":"2025-06-02T01:55:13.371470Z","iopub.status.idle":"2025-06-02T01:55:13.375891Z","shell.execute_reply.started":"2025-06-02T01:55:13.371458Z","shell.execute_reply":"2025-06-02T01:55:13.375657Z"},"trusted":true},"outputs":[{"execution_count":42,"output_type":"execute_result","data":{"text/plain":" geometry\n0.0 LINESTRING (2 2, 3 3, 5 3, 6 2, 5 1, 3 1, 2 2)\n1.0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n4.0 LINESTRING (6 2, 7 1, 7 3, 6 2)","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0.0</th>\n <td>LINESTRING (2 2, 3 3, 5 3, 6 2, 5 1, 3 1, 2 2)</td>\n </tr>\n <tr>\n <th>1.0</th>\n <td>LINESTRING (2 2, 1 1, 1 3, 2 2)</td>\n </tr>\n <tr>\n <th>4.0</th>\n <td>LINESTRING (6 2, 7 1, 7 3, 6 2)</td>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":42},{"id":"94f907e1-ef4c-4fe2-83dd-5e620f88b44f","cell_type":"code","source":"# Derive nodes\nnodes = neatnet.nodes._nodes_from_edges(aggregated.geometry)\nnodes","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.376249Z","iopub.execute_input":"2025-06-02T01:55:13.376348Z","iopub.status.idle":"2025-06-02T01:55:13.378613Z","shell.execute_reply.started":"2025-06-02T01:55:13.376339Z","shell.execute_reply":"2025-06-02T01:55:13.378425Z"},"trusted":true},"outputs":[{"execution_count":43,"output_type":"execute_result","data":{"text/plain":"array([<POINT (2 2)>, <POINT (6 2)>], dtype=object)"},"metadata":{}}],"execution_count":43},{"id":"e36178a1-ca0a-4a11-9780-13b67bf5561a","cell_type":"code","source":"# Bifurcate edges into loops and non-loops\nloops, not_loops = neatnet.nodes._loops_and_non_loops(aggregated)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.378954Z","iopub.execute_input":"2025-06-02T01:55:13.379052Z","iopub.status.idle":"2025-06-02T01:55:13.380981Z","shell.execute_reply.started":"2025-06-02T01:55:13.379045Z","shell.execute_reply":"2025-06-02T01:55:13.380778Z"},"trusted":true},"outputs":[],"execution_count":44},{"id":"da32bb9b-1a3f-4826-8813-36469d72c6dc","cell_type":"code","source":"loops","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.381214Z","iopub.execute_input":"2025-06-02T01:55:13.381274Z","iopub.status.idle":"2025-06-02T01:55:13.384037Z","shell.execute_reply.started":"2025-06-02T01:55:13.381267Z","shell.execute_reply":"2025-06-02T01:55:13.383844Z"},"trusted":true},"outputs":[{"execution_count":45,"output_type":"execute_result","data":{"text/plain":" geometry\n0.0 LINESTRING (2 2, 3 3, 5 3, 6 2, 5 1, 3 1, 2 2)\n1.0 LINESTRING (2 2, 1 1, 1 3, 2 2)\n4.0 LINESTRING (6 2, 7 1, 7 3, 6 2)","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0.0</th>\n <td>LINESTRING (2 2, 3 3, 5 3, 6 2, 5 1, 3 1, 2 2)</td>\n </tr>\n <tr>\n <th>1.0</th>\n <td>LINESTRING (2 2, 1 1, 1 3, 2 2)</td>\n </tr>\n <tr>\n <th>4.0</th>\n <td>LINESTRING (6 2, 7 1, 7 3, 6 2)</td>\n </tr>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":45},{"id":"8aeda79f-1a94-4482-9225-f4f530a7c95d","cell_type":"code","source":"not_loops","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.384272Z","iopub.execute_input":"2025-06-02T01:55:13.384336Z","iopub.status.idle":"2025-06-02T01:55:13.386668Z","shell.execute_reply.started":"2025-06-02T01:55:13.384329Z","shell.execute_reply":"2025-06-02T01:55:13.386469Z"},"trusted":true},"outputs":[{"execution_count":46,"output_type":"execute_result","data":{"text/plain":"Empty GeoDataFrame\nColumns: [geometry]\nIndex: []","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>geometry</th>\n </tr>\n </thead>\n <tbody>\n </tbody>\n</table>\n</div>"},"metadata":{}}],"execution_count":46},{"id":"1063607b-d1e7-4a5d-a5d5-206f3e00a0bf","cell_type":"markdown","source":"### Replicate error due to:\n\n1. Erronoeus merge of 2 edges in 1 loop\n2. Then target loops only intersecting other loops","metadata":{}},{"id":"28c98926-750e-4f25-a58a-ed2fd87f65a9","cell_type":"code","source":"# Ensure:\n# - all loops have exactly 1 endpoint; and\n# - that endpoint shares a node with an intersecting line\nfixed_loops = []\nfixed_index = []\nnode_ix, loop_ix = loops.sindex.query(nodes, predicate=\"intersects\")\nfor ix in numpy.unique(loop_ix):\n loop_geom = loops.geometry.iloc[ix]\n target_nodes = nodes[node_ix[loop_ix == ix]]\n if len(target_nodes) == 2:\n new_sequence = neatnet.nodes._rotate_loop_coords(loop_geom, not_loops)\n fixed_loops.append(shapely.LineString(new_sequence))\n fixed_index.append(ix)\n\naggregated.loc[loops.index[fixed_index], aggregated.geometry.name] = fixed_loops\naggregated.reset_index(drop=True)\naggregated.plot(cmap=\"Paired\", lw=5)\naggregated","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.386916Z","iopub.execute_input":"2025-06-02T01:55:13.387035Z","iopub.status.idle":"2025-06-02T01:55:13.533641Z","shell.execute_reply.started":"2025-06-02T01:55:13.387028Z","shell.execute_reply":"2025-06-02T01:55:13.533227Z"},"trusted":true},"outputs":[{"traceback":["\u001b[31m---------------------------------------------------------------------------\u001b[39m","\u001b[31mValueError\u001b[39m Traceback (most recent call last)","\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[47]\u001b[39m\u001b[32m, line 11\u001b[39m\n\u001b[32m 9\u001b[39m target_nodes = nodes[node_ix[loop_ix == ix]]\n\u001b[32m 10\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(target_nodes) == \u001b[32m2\u001b[39m:\n\u001b[32m---> \u001b[39m\u001b[32m11\u001b[39m new_sequence = \u001b[43mneatnet\u001b[49m\u001b[43m.\u001b[49m\u001b[43mnodes\u001b[49m\u001b[43m.\u001b[49m\u001b[43m_rotate_loop_coords\u001b[49m\u001b[43m(\u001b[49m\u001b[43mloop_geom\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnot_loops\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 12\u001b[39m fixed_loops.append(shapely.LineString(new_sequence))\n\u001b[32m 13\u001b[39m fixed_index.append(ix)\n","\u001b[36mFile \u001b[39m\u001b[32m~/github_repos/uscuni/neatnet/neatnet/nodes.py:449\u001b[39m, in \u001b[36m_rotate_loop_coords\u001b[39m\u001b[34m(loop_geom, not_loops)\u001b[39m\n\u001b[32m 446\u001b[39m mode = mode.iloc[[\u001b[32m0\u001b[39m]]\n\u001b[32m 448\u001b[39m new_start = mode.get_coordinates().values\n\u001b[32m--> \u001b[39m\u001b[32m449\u001b[39m _coords_match = (\u001b[43mloop_coords\u001b[49m\u001b[43m \u001b[49m\u001b[43m==\u001b[49m\u001b[43m \u001b[49m\u001b[43mnew_start\u001b[49m).all(axis=\u001b[32m1\u001b[39m)\n\u001b[32m 450\u001b[39m new_start_idx = np.where(_coords_match)[\u001b[32m0\u001b[39m].squeeze()\n\u001b[32m 452\u001b[39m rolled_coords = np.roll(loop_coords[:-\u001b[32m1\u001b[39m], -new_start_idx, axis=\u001b[32m0\u001b[39m)\n","\u001b[31mValueError\u001b[39m: operands could not be broadcast together with shapes (7,2) (0,2) "],"ename":"ValueError","evalue":"operands could not be broadcast together with shapes (7,2) (0,2) ","output_type":"error"}],"execution_count":47},{"id":"d3672638-8274-4b38-b0ed-9fe4948151d9","cell_type":"markdown","source":"## Compare the 2 cases\n\n### loop_loop_edge_edge\n\n* correctly does not much indexing","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:48:37.507728Z","iopub.status.idle":"2025-06-02T01:48:37.507821Z","shell.execute_reply.started":"2025-06-02T01:48:37.507767Z","shell.execute_reply":"2025-06-02T01:48:37.507772Z"}}},{"id":"f0847780-7f8e-425f-a3ff-fece5ee12f1f","cell_type":"code","source":"neatnet.nodes.get_components(\n case_loop_loop_edge_edge.explode().geometry\n)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:21.147450Z","iopub.execute_input":"2025-06-02T01:55:21.148110Z","iopub.status.idle":"2025-06-02T01:55:21.160165Z","shell.execute_reply.started":"2025-06-02T01:55:21.148076Z","shell.execute_reply":"2025-06-02T01:55:21.159674Z"},"trusted":true},"outputs":[{"execution_count":48,"output_type":"execute_result","data":{"text/plain":"array([4., 5., 6., 7.])"},"metadata":{}}],"execution_count":48},{"id":"6364eb32-acc9-4c9f-960d-814199c57477","cell_type":"markdown","source":"# return incorrect indexing","metadata":{}},{"id":"5ae63bef-ef84-4e78-bfa7-fc4dceb25c80","cell_type":"code","source":"neatnet.nodes.get_components(\n case_loop_edge_edge_loop.explode().geometry\n)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:22.363917Z","iopub.execute_input":"2025-06-02T01:55:22.364624Z","iopub.status.idle":"2025-06-02T01:55:22.376283Z","shell.execute_reply.started":"2025-06-02T01:55:22.364571Z","shell.execute_reply":"2025-06-02T01:55:22.375537Z"},"trusted":true},"outputs":[{"execution_count":49,"output_type":"execute_result","data":{"text/plain":"array([1., 0., 0., 4.])"},"metadata":{}}],"execution_count":49},{"id":"d242cf57-0a45-475a-86de-cd1f05fc1e2c","cell_type":"code","source":"#def verbose_get_components(input_edgelines):\n# \n# # convert edges geoseries to numpy array\n# edgelines = numpy.array(input_edgelines)\n# print(f\"edgelines\\n{edgelines}\\n\\n-------\\n\")\n# \n# # fetch edge starting points\n# start_points = shapely.get_point(edgelines, 0)\n# print(f\"start_points\\n{start_points}\\n\\n-------\\n\")\n#\n# # fetch edge ending points\n# end_points = shapely.get_point(edgelines, -1)\n# print(f\"end_points\\n{end_points}\\n\\n-------\\n\")\n#\n# # 1. combine start and end point into 1 array\n# # 2. retain only unique\n# points = shapely.points(\n# numpy.unique(\n# shapely.get_coordinates(numpy.concatenate([start_points, end_points])), axis=0\n# )\n# )\n# print(f\"points\\n{points}\\n\\n-------\\n\")\n#\n# # query topological bounds of edgeline geometries\n# # -- ** loops have no topological bounds and are ommited from query **\n# inp, res = shapely.STRtree(shapely.boundary(edgelines)).query(\n# points, predicate=\"intersects\"\n# )\n# print(f\"inp\\n{inp}\\n\\n-------\\n\")\n# print(f\"res\\n{res}\\n\\n-------\\n\")\n#\n# # fetch unique input indices & counts\n# unique, counts = numpy.unique(inp, return_counts=True)\n#\n# print(f\"unique\\n{unique}\\n\\n-------\\n\")\n# print(f\"counts\\n{counts}\\n\\n-------\\n\")\n#\n# # create a mask to determine points intersecting 2 geometries\n# mask = numpy.isin(inp, unique[counts == 2])\n# print(f\"mask\\n{mask}\\n\\n-------\\n\")\n#\n# # determine input to merge\n# merge_inp = inp[mask]\n# print(f\"merge_inp\\n{merge_inp}\\n\\n-------\\n\")\n#\n# # determine result to merge\n# merge_res = res[mask]\n# print(f\"merge_res\\n{merge_res}\\n\\n-------\\n\")\n#\n# # isolate edgeline index of loops\n# closed = numpy.arange(len(edgelines))[shapely.is_closed(edgelines)]\n# print(f\"closed\\n{closed}\\n\\n-------\\n\")\n#\n# # redefine mask to to consider for merging\n# # - edges to not consider\n# # - points to not consider\n# mask = numpy.isin(merge_res, closed) | numpy.isin(merge_inp, closed)\n# print(f\"mask\\n{mask}\\n\\n-------\\n\")","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.534586Z","iopub.status.idle":"2025-06-02T01:55:13.534663Z","shell.execute_reply.started":"2025-06-02T01:55:13.534621Z","shell.execute_reply":"2025-06-02T01:55:13.534625Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"abf14c52-ad1c-49be-88b9-3ab9a5e18796","cell_type":"code","source":"#verbose_get_components(\n# case_loop_loop_edge_edge.explode(ignore_index=True).geometry\n#)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.535106Z","iopub.status.idle":"2025-06-02T01:55:13.535203Z","shell.execute_reply.started":"2025-06-02T01:55:13.535144Z","shell.execute_reply":"2025-06-02T01:55:13.535148Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"68503268-cdb7-46fd-af75-026f559bb791","cell_type":"code","source":"#verbose_get_components(\n# case_loop_edge_edge_loop.explode(ignore_index=True).geometry\n#)","metadata":{"execution":{"iopub.status.busy":"2025-06-02T01:55:13.535608Z","iopub.status.idle":"2025-06-02T01:55:13.535777Z","shell.execute_reply.started":"2025-06-02T01:55:13.535722Z","shell.execute_reply":"2025-06-02T01:55:13.535726Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"d2bafbfb-faa8-4e5c-a1d2-1eeb39860178","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment