marceloprates / prettymaps

A small set of Python functions to draw pretty maps from OpenStreetMap data. Based on osmnx, matplotlib and shapely libraries.
GNU Affero General Public License v3.0
11.04k stars 516 forks source link

Not able to get the Seine in Paris (just a piece of it) #46

Open phpdistiller opened 2 years ago

phpdistiller commented 2 years ago

Hi,

I have 'water': {'tags': {'natural': ['water', 'bay']}}, and 'water': {'fc': '#A1CAE2', 'ec': '#6da8c2', 'lw': 0.5, 'zorder': 2},. I get this : seine

And, as you can see, I big part of the Seine is missing. What did I miss ?

G21-Goose commented 2 years ago

Hi, I've tried to replicate your issue but I don't get any missing parts in the Seine. image

This is the code I used to make it:

from prettymaps import *
from matplotlib import pyplot as plt

# Setup figure
figsize=(10,10)
fig, ax = plt.subplots(figsize = figsize, constrained_layout = True)

# Plot
layers = plot(
    (48.8534, 2.3397), radius = 7000,
    ax = ax,
    layers = {
        'perimeter': {'circle': False},
        'water': {
            'tags':{
                'natural': ['water', 'bay']
            },
        },
    },
    drawing_kwargs = {
        'background': {'fc': '#FFFFFF', 'ec': '#FFFFFF', 'zorder': -1},
        'perimeter': {'fill': False, 'lw': 0, 'zorder': 0},
        'water': {'fc': '#A1CAE2', 'ec': '#6da8c2', 'lw': 0.5, 'zorder': 2},
    },
    osm_credit = {'x': .02, 'y': .00, 'color': '#2F3737'}
)

# Set bounds
xmin, ymin, xmax, ymax = layers['perimeter'].bounds
dx, dy = xmax-xmin, ymax-ymin
ax.set_xlim(xmin-.06*dx, xmax+.06*dx)
ax.set_ylim(ymin-.06*dy, ymax+.02*dy)

plt.savefig('./prints/seine.png')
plt.savefig('./prints/seine.svg')
phpdistiller commented 2 years ago

I used this code :

fig, ax = plt.subplots(figsize = (10,10), constrained_layout = True)

plot(
    'Paris, France',

    ax = ax,

    layers = {
        'perimeter': {},
        'water': {'tags': {'natural': ['water', 'bay']}},
    },
    drawing_kwargs = {
        'perimeter': {'fill': False, 'ec': '#2F3737', 'lw': 0.1, 'zorder': 0},
        'water': {'fc': '#A1CAE2', 'ec': '#6da8c2', 'lw': 0.5, 'zorder': 2},
    }
)

ax.autoscale()

plt.savefig('paris.png')
plt.savefig('paris.svg')

I have tried different things but without success so far. The left part is missing.

G21-Goose commented 2 years ago

Ah ok, I get the same issue as you now. Seems like a work around is to use coordinates, but the your perimeter won't be around Paris, just a constant radius.

Looking through get_geometries() in fetch.py it looks as if this might be to do with how the intersections are done with the perimeter.

I tried changing the line:

geometries = geometries.intersection(perimeter)

to

geometries = perimeter.intersection(unary_union(geometries.geometry))

and I seem to be able to get the rest of the Seine (below where I'm also showing the perimeter). image

I think this change results in only getting one piece of geometry, which will probably effect the multi-colour buildings, but interestingly, a lot of the error messages (like the ones in #36 ) seem to disappear?!

G21-Goose commented 2 years ago

Actually, looks like it can be replaced with:

geometries = geometries.intersection(perimeter).buffer(0)

which still creates warnings (but the warning seems to be related to GeoSeries)

or it can be a list which creates no warnings because it doesn't use GeoSeries

geometries = [geo.intersection(perimeter).buffer(0) for geo in geometries.geometry]

Both these ways seem to still preserve having multiple polygons (which would be needed for the buildings) instead of just making them one polygon.