Skip to main content

drogi

What is this thing?

What 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.

All 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.

How is it supposed to work?

Getting the data

Thankfully this part is pretty straightforward. At GeoFabrik GmbH's site 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.

Processing the data

As 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. The WorkRun class is used in the following way:

import drogi
BOUNDS_DICT = {
    "Lublin": (51.1942, 22.4145, 51.3040, 22.6665),
    "lublin_small": (51.2380, 22.5509, 51.2514, 22.5743),
    "new_york": (40.7002, -74.0212, 40.7105, -74.0007),
}
lublin = drogi.WorkRun("Lublin", num_of_trips=0)

What'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:

graph example

Becomes:

graph = {'A': ['B', 'C'],
         'B': ['A', 'C', 'D'],
         'C': ['A', 'B', 'D', 'E'],
         'D': ['B', 'C'],
         'E': ['C']}

Only instead of one-letter strings we're using two-tuples of (latitude, longitude).

Visualizing

To see the graph visualized we draw it on a canvas, represented by an instance of the Canvas class. The following calls:

new_york = drogi.WorkRun("new_york")
my_canvas = drogi.Canvas(new_york.way_map.bounds_to_fetch)
new_york.way_map.render_on_canvas(my_canvas,
                                 color="black",
                                 aa=True,
                                 linewidth=0.7,
                                 alpha=1)
my_canvas.save("new_york.png", dpi=150)

Result in the following image being created:

lublin_small

Walking the graph

Let's conduct a yet another WorkRun, this time with some trips going through the area, and a fresh canvas.

new_run = drogi.WorkRun("lublin_small", num_of_trips=100)
new_canvas = drogi.Canvas(bounds)

To 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 objects.

new_run.way_map.render_on_canvas(new_canvas,
                                 color="black",
                                 aa=True,
                                 linewidth=0.7,
                                 alpha=0.5)
for trip in new_run.list_of_trips:
    trip.path.render_on_canvas(new_canvas,
                               color="red",
                               aa=True,
                               linewidth=1,
                               alpha=0.1)
new_canvas.save("lublin_with_paths.png", dpi=150)

The result will look something like this:

lublin_with_paths

I say "something like this" because origins and destinations of each journey are picked at random, so each run is potentially unique.

Finding obstacles

Now 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. This can be achieved by taking a closer look on the Obstacle class, instances of which are kept in a list inside each Path object. Any area that makes the path deviate from a perfectly straight line is considered an obstacle, like so:

obstacles

Now 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.

BOUNDS_DICT = {"bigger_test": (51.21, 22.50, 51.28, 22.605)}
new_run = drogi.WorkRun("bigger_test", num_of_trips=20000)
my_canvas = drogi.Canvas(new_run.way_map.bounds_to_fetch)
new_run.way_map.render_on_canvas(my_canvas,
                                 color="black",
                                 aa=False,
                                 linewidth=0.1,
                                 alpha=0.2)
for trip in new_run.list_of_trips:
    trip.path.render_on_canvas(my_canvas,
                               color="blue",
                               aa=False,
                               linewidth=0.1,
                               alpha=0.01)
    for obstacle in trip.path.obstacles:
        obstacle.render_on_canvas(my_canvas,
                                  color="red",
                                  alpha=0.005,
                                  linewidth=0,
                                  edgecolor=None)
my_canvas.save("bigger_test.png")                                  

And after 45 minutes on a single core, behold:

bigger_test

With this, we can start to draw some serious conclusions.

Coming up in future versions:

  • Walking between places of interest, instead of random points
  • Layered canvas rendering
  • CLI interface through the argparse module

Metadata

Release files for drogi 0.0.15

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for drogi 0.0.15
File Size Uploaded
drogi-0.0.15.tar.gz 9.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for drogi 0.0.15
File Interpreter ABI Platform
drogi-0.0.15-py3-none-any.whl Python 3 none any Details

Total release size: 27.1 kB

Release files / drogi-0.0.15.tar.gz

Download URL drogi-0.0.15.tar.gz
Size 9.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7131a3c82cc39ccb14173afd74e2719b55a0f14bf27d4a2b2f5f2275eb6539d6
BLAKE2b-256 checksum
How to use checksums
75cd5cdddb899696caaa715e6f3b345734dade42025dd2915338844a1bfe6295
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.11.0 pkginfo/1.4.2 requests/2.19.1 setuptools/40.0.0 requests-toolbelt/0.8.0 tqdm/4.19.5 CPython/3.6.6

Release files / drogi-0.0.15-py3-none-any.whl

Download URL drogi-0.0.15-py3-none-any.whl
Size 17.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
570e7f2ce57329f13e5027f34cc5eb114ad45a6bd39b66f5ec7e1ee6e1a1438a
BLAKE2b-256 checksum
How to use checksums
524cf8e199ddc0bcdf3e1a292bef7b29e0a7ef4eda83d2863424e3e5bcef67ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.11.0 pkginfo/1.4.2 requests/2.19.1 setuptools/40.0.0 requests-toolbelt/0.8.0 tqdm/4.19.5 CPython/3.6.6

Release history Release notifications | RSS feed

This release

0.0.15 This release

2 release files

0.0.14

1 release file

0.0.13

2 release files

0.0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page