{ "info": { "author": "Maciej Kluczy\u0144ski", "author_email": "maciej.lukasz.kluczynski@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# drogi\n\n## What is this thing?\n\nWhat I'm aiming to accomplish here is building a tool for analyzing city maps in terms of walkability, driveability, bikeability and so on. Its intended ultimate purpose is generating large amounts of data, as well as creating a simple way to visualize infrastructure trouble spots in a given area.\n\nAll in the spirit of new urbanism, urban renaissance, sustainability and reducing car dependency, concepts about which you can read in other places on the web, should you feel so inclined.\n\n## How is it supposed to work?\n\n#### Getting the data\n\nThankfully this part is pretty straightforward. At [GeoFabrik GmbH's site](https://download.geofabrik.de/) we can get OpenStreetMap .osm data as convenient extracts. But for the purposes of this readme we won't, at least not yet. Instead I manually grabbed an extract of my neighbourhood, it's smaller and in a sense means I get more intimate domain knowledge of what I'm looking at.\n\n#### Processing the data\n\nAs I mentioned I intend to use this thing to generate data. For that reason I have decided to design it around a concept of a **WorkRun** which will consist of fetching the data, piece by piece, gluing it together to make a city-sized graph and walking it repeatedly. The patterns that emerge from all the walked paths can then be used to infer deductions.\nThe WorkRun class is used in the following way:\n```python\nimport drogi\nBOUNDS_DICT = {\n \"Lublin\": (51.1942, 22.4145, 51.3040, 22.6665),\n \"lublin_small\": (51.2380, 22.5509, 51.2514, 22.5743),\n \"new_york\": (40.7002, -74.0212, 40.7105, -74.0007),\n}\nlublin = drogi.WorkRun(\"Lublin\", num_of_trips=0)\n```\nWhat's happening inside is the walkable ways from the .osm map get converted into `shapely.LineString` objects and then a graph, represented as a dictionary, is built from those. The representation is pretty standard for Python, the following graph:\n\n![graph example](img/graph.png)\n\nBecomes:\n```python\ngraph = {'A': ['B', 'C'],\n 'B': ['A', 'C', 'D'],\n 'C': ['A', 'B', 'D', 'E'],\n 'D': ['B', 'C'],\n 'E': ['C']}\n```\nOnly instead of one-letter strings we're using two-tuples of `(latitude, longitude)`.\n\n#### Visualizing\n\nTo see the graph visualized we draw it on a canvas, represented by an instance of the `Canvas` class. The following calls:\n```python\nnew_york = drogi.WorkRun(\"new_york\")\nmy_canvas = drogi.Canvas(new_york.way_map.bounds_to_fetch)\nnew_york.way_map.render_on_canvas(my_canvas,\n color=\"black\",\n aa=True,\n linewidth=0.7,\n alpha=1)\nmy_canvas.save(\"new_york.png\", dpi=150)\n```\nResult in the following image being created:\n\n![lublin_small](img/new_york.png)\n\n#### Walking the graph\n\nLet's conduct a yet another WorkRun, this time with some trips going through the area, and a fresh canvas.\n\n```python\nnew_run = drogi.WorkRun(\"lublin_small\", num_of_trips=100)\nnew_canvas = drogi.Canvas(bounds)\n```\nTo get some sense of which walkways are more popular than the others we can draw them semi-opaque on top of one another. We'll also tweak the lines so they appear a bit lighter. You can customize it a fair bit as `render_on_canvas` functions use matplotlib's [Line2D](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html) objects.\n```python\nnew_run.way_map.render_on_canvas(new_canvas,\n color=\"black\",\n aa=True,\n linewidth=0.7,\n alpha=0.5)\nfor trip in new_run.list_of_trips:\n trip.path.render_on_canvas(new_canvas,\n color=\"red\",\n aa=True,\n linewidth=1,\n alpha=0.1)\nnew_canvas.save(\"lublin_with_paths.png\", dpi=150)\n```\nThe result will look something like this:\n\n![lublin_with_paths](img/lublin_with_paths.png)\n\nI say \"something like this\" because origins and destinations of each journey are picked at random, so each run is potentially unique.\n\n#### Finding obstacles\n\nNow let's say we'd want to know the areas which are the biggest offenders in terms of decreasing walkability of the neighbourhood. Such an area could be a river, an unpassable highway or a large factory.\nThis can be achieved by taking a closer look on the `Obstacle` class, instances of which are kept in a list inside each `Path` object.\nAny area that makes the path deviate from a perfectly straight line is considered an obstacle, like so:\n\n![obstacles](img/obstacles.png)\n\nNow suppose we shaded these areas for a large number of paths. What we'd get is a map showing the unwalkable bits of the city. Let's try it.\n\n```python\n\nBOUNDS_DICT = {\"bigger_test\": (51.21, 22.50, 51.28, 22.605)}\nnew_run = drogi.WorkRun(\"bigger_test\", num_of_trips=20000)\nmy_canvas = drogi.Canvas(new_run.way_map.bounds_to_fetch)\nnew_run.way_map.render_on_canvas(my_canvas,\n color=\"black\",\n aa=False,\n linewidth=0.1,\n alpha=0.2)\nfor trip in new_run.list_of_trips:\n trip.path.render_on_canvas(my_canvas,\n color=\"blue\",\n aa=False,\n linewidth=0.1,\n alpha=0.01)\n for obstacle in trip.path.obstacles:\n obstacle.render_on_canvas(my_canvas,\n color=\"red\",\n alpha=0.005,\n linewidth=0,\n edgecolor=None)\nmy_canvas.save(\"bigger_test.png\") \n```\nAnd after 45 minutes on a single core, behold:\n\n![bigger_test](img/20k_test2018-09-08_17:40:16.724652.png)\n\nWith this, we can start to draw some serious conclusions.\n\n#### Coming up in future versions:\n* Walking between places of interest, instead of random points\n* Layered canvas rendering\n* CLI interface through the argparse module\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mklucz/drogi", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "drogi", "package_url": "https://pypi.org/project/drogi/", "platform": "", "project_url": "https://pypi.org/project/drogi/", "project_urls": { "Homepage": "https://github.com/mklucz/drogi" }, "release_url": "https://pypi.org/project/drogi/0.0.15/", "requires_dist": null, "requires_python": "", "summary": "Tool for analysing urban moveability.", "version": "0.0.15" }, "last_serial": 4341389, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "7642258f075a593bf8bf09b669c0c012", "sha256": "4283dacf9087cc60a19a6effddb1e78608ff4a33301e9fc4cbaf0c16cf7aa413" }, "downloads": -1, "filename": "drogi-0.0.1.tar.gz", "has_sig": false, "md5_digest": "7642258f075a593bf8bf09b669c0c012", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2339, "upload_time": "2018-05-30T22:03:21", "url": "https://files.pythonhosted.org/packages/2e/57/2f98c1dd2ad9a2ca4a7c68ae02bfe26e27d8806d0f25a9074b03250d4874/drogi-0.0.1.tar.gz" } ], "0.0.13": [ { "comment_text": "", "digests": { "md5": "2820b799444393a7fc4d124effc6d2a6", "sha256": "8a86f9393cf2f36ff288f31f815ab36a61d7a65d1580240b9590fab414282a5a" }, "downloads": -1, "filename": "drogi-0.0.13-py3-none-any.whl", "has_sig": false, "md5_digest": "2820b799444393a7fc4d124effc6d2a6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14282, "upload_time": "2018-10-01T04:15:56", "url": "https://files.pythonhosted.org/packages/eb/6c/cccfa1f68a506e8550f3a506d26c467e5dcc30d07de7637831fefdd26c37/drogi-0.0.13-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9d4bf3f9459a4a4c564ac59adc0ea882", "sha256": "2c8daba5a6a111235716b15217eb696cda1291c37894aa77d973410e2d382b08" }, "downloads": -1, "filename": "drogi-0.0.13.tar.gz", "has_sig": false, "md5_digest": "9d4bf3f9459a4a4c564ac59adc0ea882", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6294, "upload_time": "2018-06-16T19:19:52", "url": "https://files.pythonhosted.org/packages/99/87/b1864427f81b1c111838bbf9127095836399aaf85bcbfd9cc4ea3e4a9205/drogi-0.0.13.tar.gz" } ], "0.0.14": [ { "comment_text": "", "digests": { "md5": "53b410bd3f39bdcd696e9b5c908272b8", "sha256": "4681cb6cbacbd5b91458bc3bbf997335d5c7783baae6cba6846722f85b20c8c7" }, "downloads": -1, "filename": "drogi-0.0.14-py3-none-any.whl", "has_sig": false, "md5_digest": "53b410bd3f39bdcd696e9b5c908272b8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17760, "upload_time": "2018-10-01T04:15:57", "url": "https://files.pythonhosted.org/packages/ac/2c/9d0e736093a0d49411924ebab26c35f8bca26e24613ec6ad1397b38d3475/drogi-0.0.14-py3-none-any.whl" } ], "0.0.15": [ { "comment_text": "", "digests": { "md5": "8f9d1042d52e2d8638b12e4efb245a42", "sha256": "570e7f2ce57329f13e5027f34cc5eb114ad45a6bd39b66f5ec7e1ee6e1a1438a" }, "downloads": -1, "filename": "drogi-0.0.15-py3-none-any.whl", "has_sig": false, "md5_digest": "8f9d1042d52e2d8638b12e4efb245a42", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17780, "upload_time": "2018-10-04T18:41:05", "url": "https://files.pythonhosted.org/packages/52/4c/f8e199ddc0bcdf3e1a292bef7b29e0a7ef4eda83d2863424e3e5bcef67ad/drogi-0.0.15-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6d6cd16a669b39b009219580174cafba", "sha256": "7131a3c82cc39ccb14173afd74e2719b55a0f14bf27d4a2b2f5f2275eb6539d6" }, "downloads": -1, "filename": "drogi-0.0.15.tar.gz", "has_sig": false, "md5_digest": "6d6cd16a669b39b009219580174cafba", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9328, "upload_time": "2018-10-04T18:42:12", "url": "https://files.pythonhosted.org/packages/75/cd/5cdddb899696caaa715e6f3b345734dade42025dd2915338844a1bfe6295/drogi-0.0.15.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8f9d1042d52e2d8638b12e4efb245a42", "sha256": "570e7f2ce57329f13e5027f34cc5eb114ad45a6bd39b66f5ec7e1ee6e1a1438a" }, "downloads": -1, "filename": "drogi-0.0.15-py3-none-any.whl", "has_sig": false, "md5_digest": "8f9d1042d52e2d8638b12e4efb245a42", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17780, "upload_time": "2018-10-04T18:41:05", "url": "https://files.pythonhosted.org/packages/52/4c/f8e199ddc0bcdf3e1a292bef7b29e0a7ef4eda83d2863424e3e5bcef67ad/drogi-0.0.15-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6d6cd16a669b39b009219580174cafba", "sha256": "7131a3c82cc39ccb14173afd74e2719b55a0f14bf27d4a2b2f5f2275eb6539d6" }, "downloads": -1, "filename": "drogi-0.0.15.tar.gz", "has_sig": false, "md5_digest": "6d6cd16a669b39b009219580174cafba", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9328, "upload_time": "2018-10-04T18:42:12", "url": "https://files.pythonhosted.org/packages/75/cd/5cdddb899696caaa715e6f3b345734dade42025dd2915338844a1bfe6295/drogi-0.0.15.tar.gz" } ] }