geopandas / contextily

Context geo-tiles in Python
https://contextily.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
493 stars 81 forks source link

`TypeError` raised in `add_basemap()` as shown in Geopandas contextily docs #241

Open mtazzari opened 2 months ago

mtazzari commented 2 months ago

When I tried to reproduce the contextily example

ax = df_wm.plot(figsize=(10, 10), alpha=0.5, edgecolor="k")
cx.add_basemap(ax, zoom=12)

on the GeoPandas website I get the same error that is visible on the docs website (see attached screenshot)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[7], line 2
      1 ax = df_wm.plot(figsize=(10, 10), alpha=0.5, edgecolor="k")
----> 2 cx.add_basemap(ax, zoom=12)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/latest/lib/python3.12/site-packages/contextily/plotting.py:134, in add_basemap(ax, zoom, source, interpolation, attribution, attribution_size, reset_extent, crs, resampling, zoom_adjust, **extra_imshow_args)
    130     left, right, bottom, top = _reproj_bb(
    131         left, right, bottom, top, crs, "epsg:3857"
    132     )
    133 # Download image
--> 134 image, extent = bounds2img(
    135     left, bottom, right, top, zoom=zoom, source=source, ll=False, zoom_adjust=zoom_adjust
    136 )
    137 # Warping
    138 if crs is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/latest/lib/python3.12/site-packages/contextily/tile.py:265, in bounds2img(w, s, e, n, zoom, source, ll, wait, max_retries, n_connections, use_cache, zoom_adjust)
    262 arrays = Parallel(n_jobs=n_connections, prefer=preferred_backend)(
    263     delayed(fetch_tile_fn)(tile_url, wait, max_retries) for tile_url in tile_urls)
    264 # merge downloaded tiles
--> 265 merged, extent = _merge_tiles(tiles, arrays)
    266 # lon/lat extent --> Spheric Mercator
    267 west, south, east, north = extent

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/latest/lib/python3.12/site-packages/contextily/tile.py:670, in _merge_tiles(tiles, arrays)
    668 for ind, arr in zip(indices, arrays):
    669     x, y = ind
--> 670     img[y * h : (y + 1) * h, x * w : (x + 1) * w, :] = arr
    672 bounds = np.array([mt.bounds(t) for t in tiles])
    673 west, south, east, north = (
    674     min(bounds[:, 0]),
    675     min(bounds[:, 1]),
    676     max(bounds[:, 2]),
    677     max(bounds[:, 3]),
    678 )

TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

How can I fix that? Thanks

image

martinfleis commented 2 months ago

Thanks for the report! I will need to investigate what is going on as I am not able to reproduce this locally using the latest environment.

mtazzari commented 2 months ago

Thank you! If it helps: by adding specifically the provider it works:

    # this works
    cx.add_basemap(
        ax, crs="EPSG:32629", source=cx.providers.OpenStreetMap.Mapnik
    )

I am generating different maps with different bounding box of data. It fails in just some of the cases, so the issue might be region-dependent.

mtazzari commented 2 months ago

I'm working in a Python 3.11 environment on Win 10 with these packages:

# Name                    Version                   Build  Channel      
affine                    2.4.0                    pypi_0    pypi       
asttokens                 2.4.1              pyhd8ed1ab_0    conda-forge
attrs                     23.2.0                   pypi_0    pypi       
bzip2                     1.0.8                hcfcfb64_5    conda-forge
ca-certificates           2024.2.2             h56e8100_0    conda-forge
certifi                   2024.2.2                 pypi_0    pypi
charset-normalizer        3.3.2                    pypi_0    pypi
click                     8.1.7                    pypi_0    pypi
click-plugins             1.1.1                    pypi_0    pypi
cligj                     0.7.2                    pypi_0    pypi
colorama                  0.4.6              pyhd8ed1ab_0    conda-forge
comm                      0.2.2              pyhd8ed1ab_0    conda-forge
contextily                1.6.0                    pypi_0    pypi
contourpy                 1.2.1                    pypi_0    pypi
cycler                    0.12.1                   pypi_0    pypi
debugpy                   1.8.1           py311h12c1d0e_0    conda-forge
decorator                 5.1.1              pyhd8ed1ab_0    conda-forge
exceptiongroup            1.2.0              pyhd8ed1ab_2    conda-forge
executing                 2.0.1              pyhd8ed1ab_0    conda-forge
fiona                     1.9.6                    pypi_0    pypi
fonttools                 4.51.0                   pypi_0    pypi
geographiclib             2.0                      pypi_0    pypi
geopandas                 0.14.3                   pypi_0    pypi
geopy                     2.4.1                    pypi_0    pypi
idna                      3.7                      pypi_0    pypi
importlib-metadata        7.1.0              pyha770c72_0    conda-forge
importlib_metadata        7.1.0                hd8ed1ab_0    conda-forge
ipykernel                 6.29.3             pyha63f2e9_0    conda-forge
ipython                   8.22.2             pyh7428d3b_0    conda-forge
jedi                      0.19.1             pyhd8ed1ab_0    conda-forge
joblib                    1.4.0                    pypi_0    pypi
jupyter_client            8.6.1              pyhd8ed1ab_0    conda-forge
jupyter_core              5.7.2           py311h1ea47a8_0    conda-forge
kiwisolver                1.4.5                    pypi_0    pypi
libexpat                  2.6.2                h63175ca_0    conda-forge
libffi                    3.4.2                h8ffe710_5    conda-forge
libsodium                 1.0.18               h8d14728_1    conda-forge
libsqlite                 3.45.3               hcfcfb64_0    conda-forge
libzlib                   1.2.13               hcfcfb64_5    conda-forge
matplotlib                3.8.4                    pypi_0    pypi
matplotlib-inline         0.1.7              pyhd8ed1ab_0    conda-forge
mercantile                1.2.1                    pypi_0    pypi
nest-asyncio              1.6.0              pyhd8ed1ab_0    conda-forge
numpy                     1.26.4                   pypi_0    pypi
openssl                   3.2.1                hcfcfb64_1    conda-forge
packaging                 24.0               pyhd8ed1ab_0    conda-forge
pandas                    2.2.2                    pypi_0    pypi
parso                     0.8.4              pyhd8ed1ab_0    conda-forge
pickleshare               0.7.5                   py_1003    conda-forge
pillow                    10.3.0                   pypi_0    pypi
pip                       24.0               pyhd8ed1ab_0    conda-forge
platformdirs              4.2.0              pyhd8ed1ab_0    conda-forge
prompt-toolkit            3.0.42             pyha770c72_0    conda-forge
psutil                    5.9.8           py311ha68e1ae_0    conda-forge
pure_eval                 0.2.2              pyhd8ed1ab_0    conda-forge
pygments                  2.17.2             pyhd8ed1ab_0    conda-forge
pyparsing                 3.1.2                    pypi_0    pypi
pyproj                    3.6.1                    pypi_0    pypi
python                    3.11.9          h631f459_0_cpython    conda-forge
python-dateutil           2.9.0              pyhd8ed1ab_0    conda-forge
python_abi                3.11                    4_cp311    conda-forge
pytz                      2024.1                   pypi_0    pypi
pywin32                   306             py311h12c1d0e_2    conda-forge
pyyaml                    6.0.1                    pypi_0    pypi
pyzmq                     26.0.2          py311h484c95c_0    conda-forge
rasterio                  1.3.10                   pypi_0    pypi
requests                  2.31.0                   pypi_0    pypi
scikit-learn              1.4.2                    pypi_0    pypi
scipy                     1.13.0                   pypi_0    pypi
setuptools                69.5.1             pyhd8ed1ab_0    conda-forge
shapely                   2.0.4                    pypi_0    pypi
six                       1.16.0             pyh6c4a22f_0    conda-forge
snuggs                    1.4.7                    pypi_0    pypi
stack_data                0.6.2              pyhd8ed1ab_0    conda-forge
threadpoolctl             3.4.0                    pypi_0    pypi
tk                        8.6.13               h5226925_1    conda-forge
tornado                   6.4             py311ha68e1ae_0    conda-forge
traitlets                 5.14.3             pyhd8ed1ab_0    conda-forge
typing_extensions         4.11.0             pyha770c72_0    conda-forge
tzdata                    2024.1                   pypi_0    pypi
ucrt                      10.0.22621.0         h57928b3_0    conda-forge
urllib3                   2.2.1                    pypi_0    pypi
vc                        14.3                hcf57466_18    conda-forge
vc14_runtime              14.38.33130         h82b7239_18    conda-forge
vs2015_runtime            14.38.33130         hcb4865c_18    conda-forge
wcwidth                   0.2.13             pyhd8ed1ab_0    conda-forge
wheel                     0.43.0             pyhd8ed1ab_1    conda-forge
xyzservices               2024.4.0                 pypi_0    pypi
xz                        5.2.6                h8d14728_0    conda-forge
zeromq                    4.3.5                h63175ca_1    conda-forge
zipp                      3.17.0             pyhd8ed1ab_0    conda-forge
mtazzari commented 2 months ago

I've just noticed that the error doesn't show up anymore in the docs but it is still raised locally in my code.

martinfleis commented 2 months ago

I think it is caused by some network error or a server error we do not properly catch. I still wasn't able to reproduce but from the traceback, I suppose we get None instead of an array of values representing tile at some point which shall raise an informative error rather than this one. But in any case, I don't think there's a fix for this as I don't believe it is caused by contextily. The best solution you can hope for is a better error message.

hanksnowdon commented 1 month ago

Wanted to add on here that I am also getting this same error. Happens for some gdfs I am plotting and not for others (seems to be the ones with larger geographic footprints cause the error). Would love any solution, as add_basemap is pretty much unusable for me now!

martinfleis commented 1 month ago

@hanksnowdon Can you share your reproducible example? I still wasn't able to get a reliable example to debug the issue.

hanksnowdon commented 1 month ago

Sure @martinfleis ! Data is downloaded from Chicago Transit Authority website here: https://data.cityofchicago.org/dataset/CTA-L-Rail-Stations-Shapefile/vmyy-m9qj/about_data

import geopandas as gpd 
import contextily as cx
import matplotlib.pyplot as plt 

current_l = gpd.read_file('../CTA_RailStations/CTA_RailStations.shp').to_crs('EPSG:32616')
cx.add_basemap(current_l.plot(), crs = current_l.crs.to_string())

plt.show()

error:


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[171], [line 6](vscode-notebook-cell:?execution_count=171&line=6)
      [3](vscode-notebook-cell:?execution_count=171&line=3) import matplotlib as plt
      [5](vscode-notebook-cell:?execution_count=171&line=5) current_l = gpd.read_file('Data/CTA_RailStations/CTA_RailStations.shp').to_crs('EPSG:32616')
----> [6](vscode-notebook-cell:?execution_count=171&line=6) cx.add_basemap(current_l.plot(), crs = current_l.crs.to_string())
      [8](vscode-notebook-cell:?execution_count=171&line=8) plt.show()

File ~/gis-env/lib/python3.11/site-packages/contextily/plotting.py:134, in add_basemap(ax, zoom, source, interpolation, attribution, attribution_size, reset_extent, crs, resampling, zoom_adjust, **extra_imshow_args)
    [130](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:130)     left, right, bottom, top = _reproj_bb(
    [131](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:131)         left, right, bottom, top, crs, "epsg:3857"
    [132](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:132)     )
    [133](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:133) # Download image
--> [134](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:134) image, extent = bounds2img(
    [135](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:135)     left, bottom, right, top, zoom=zoom, source=source, ll=False, zoom_adjust=zoom_adjust
    [136](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:136) )
    [137](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:137) # Warping
    [138](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/plotting.py:138) if crs is not None:

File ~/gis-env/lib/python3.11/site-packages/contextily/tile.py:265, in bounds2img(w, s, e, n, zoom, source, ll, wait, max_retries, n_connections, use_cache, zoom_adjust)
    [262](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:262) arrays = Parallel(n_jobs=n_connections, prefer=preferred_backend)(
    [263](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:263)     delayed(fetch_tile_fn)(tile_url, wait, max_retries) for tile_url in tile_urls)
    [264](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:264) # merge downloaded tiles
--> [265](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:265) merged, extent = _merge_tiles(tiles, arrays)
    [266](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:266) # lon/lat extent --> Spheric Mercator
    [267](https://file+.vscode-resource.vscode-cdn.netgis-env/lib/python3.11/site-packages/contextily/tile.py:267) west, south, east, north = extent

File ~/gis-env/lib/python3.11/site-packages/contextily/tile.py:670, in _merge_tiles(tiles, arrays)
    [668](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:668) for ind, arr in zip(indices, arrays):
    [669](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:669)     x, y = ind
--> [670](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:670)     img[y * h : (y + 1) * h, x * w : (x + 1) * w, :] = arr
    [672](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:672) bounds = np.array([mt.bounds(t) for t in tiles])
    [673](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:673) west, south, east, north = (
    [674](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:674)     min(bounds[:, 0]),
    [675](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:675)     min(bounds[:, 1]),
    [676](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:676)     max(bounds[:, 2]),
    [677](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:677)     max(bounds[:, 3]),
    [678](https://file+.vscode-resource.vscode-cdn.net/gis-env/lib/python3.11/site-packages/contextily/tile.py:678) )

TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
martinfleis commented 1 month ago

@hanksnowdon that works fine on my side :(

Screenshot 2024-05-22 at 13 20 41

I really don't know how to fix an issue that I can't reproduce. My sense is that it is related to corrupt tile downloads which may be related to the change of the default tiles we did in autumn. Because as reported above, changing the tiles have resolved it for some people. But how to get around this, not sure yet.