Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/geopandas/contextily
Browse files Browse the repository at this point in the history
  • Loading branch information
darribas committed Feb 3, 2021
2 parents 9a8b652 + 99b2e05 commit 781fd1f
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 96 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM darribas/gds_py:4.1

# Install contextily master
RUN pip install -U git+https://github.com/geopandas/contextily.git@master
RUN pip install -U earthengine-api git+https://github.com/geopandas/contextily.git@master
# Add notebooks
RUN rm -R work/
COPY ./README.md ${HOME}/README.md
Expand Down
2 changes: 1 addition & 1 deletion contextily/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
from .tile import *
from .plotting import add_basemap, add_attribution

__version__ = "1.0.0"
__version__ = "1.0.1"
22 changes: 18 additions & 4 deletions contextily/place.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
import geopy as gp
import numpy as np
import matplotlib.pyplot as plt
from warnings import warn
import warnings

from .tile import howmany, bounds2raster, bounds2img, _sm2ll, _calculate_zoom
from .plotting import INTERPOLATION, ZOOM, add_attribution
from . import providers
from ._providers import TileProvider

# Set user ID for Nominatim
_val = np.random.randint(1000000)
_default_user_agent = f"contextily_user_{_val}"


class Place(object):
"""Geocode a place by name and get its map.
Expand Down Expand Up @@ -45,6 +50,8 @@ class Place(object):
Source url for web tiles, or path to local file. If
local, the file is read with `rasterio` and all
bands are loaded into the basemap.
geocoder : geopy.geocoders
[Optional. Default: geopy.geocoders.Nominatim()] Geocoder method to process `search`
Attributes
----------
Expand All @@ -69,7 +76,14 @@ class Place(object):
"""

def __init__(
self, search, zoom=None, path=None, zoom_adjust=None, source=None, url=None
self,
search,
zoom=None,
path=None,
zoom_adjust=None,
source=None,
url=None,
geocoder=gp.geocoders.Nominatim(user_agent=_default_user_agent),
):
self.path = path
if url is not None and source is None:
Expand All @@ -93,7 +107,7 @@ def __init__(
self.zoom_adjust = zoom_adjust

# Get geocoded values
resp = gp.geocoders.Nominatim().geocode(search)
resp = geocoder.geocode(search)
bbox = np.array([float(ii) for ii in resp.raw["boundingbox"]])

if "display_name" in resp.raw.keys():
Expand Down Expand Up @@ -240,7 +254,7 @@ def plot_map(
ax : instance of matplotlib Axes object or None
The axis on the map is plotted.
"""
warn(
warnings.warn(
(
"The method `plot_map` is deprecated and will be removed from the"
" library in future versions. Please use either `add_basemap` or"
Expand Down
51 changes: 48 additions & 3 deletions contextily/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ def add_basemap(
# Warping
if crs is not None:
image, extent = warp_tiles(image, extent, t_crs=crs, resampling=resampling)
# Check if overlay
if _is_overlay(source) and 'zorder' not in extra_imshow_args:
# If zorder was not set then make it 9 otherwise leave it
extra_imshow_args['zorder'] = 9
# If local source
else:
import rasterio as rio
Expand Down Expand Up @@ -177,18 +181,21 @@ def add_basemap(
}
]
image, img_transform = riomask(raster, window, crop=True)
extent = left, right, bottom, top
else:
# Read full
image = np.array([band for band in raster.read()])
img_transform = raster.transform
bb = raster.bounds
extent = bb.left, bb.right, bb.bottom, bb.top
# Warp
if (crs is not None) and (raster.crs != crs):
image, raster = _warper(
image, bounds, _ = _warper(
image, img_transform, raster.crs, crs, resampling
)
extent = bounds.left, bounds.right, bounds.bottom, bounds.top
image = image.transpose(1, 2, 0)
bb = raster.bounds
extent = bb.left, bb.right, bb.bottom, bb.top

# Plotting
if image.shape[2] == 1:
image = image[:, :, 0]
Expand Down Expand Up @@ -222,6 +229,44 @@ def _reproj_bb(left, right, bottom, top, s_crs, t_crs):
n_l, n_b, n_r, n_t = transform_bounds(s_crs, t_crs, left, bottom, right, top)
return n_l, n_r, n_b, n_t

def _is_overlay(source):
"""
Check if the identified source is an overlay (partially transparent) layer.
Parameters
----------
source : dict
The tile source: web tile provider. Must be preprocessed as
into a dictionary, not just a string.
Returns
-------
bool
Notes
-----
This function is based on a very similar javascript version found in leaflet:
https://github.com/leaflet-extras/leaflet-providers/blob/9eb968f8442ea492626c9c8f0dac8ede484e6905/preview/preview.js#L56-L70
"""
if not isinstance(source, dict):
return False
if source.get('opacity', 1.0) < 1.0:
return True
overlayPatterns = [
'^(OpenWeatherMap|OpenSeaMap)',
'OpenMapSurfer.(Hybrid|AdminBounds|ContourLines|Hillshade|ElementsAtRisk)',
'Stamen.Toner(Hybrid|Lines|Labels)',
'CartoDB.(Positron|DarkMatter|Voyager)OnlyLabels',
'Hydda.RoadsAndLabels',
'^JusticeMap',
'OpenPtMap',
'OpenRailwayMap',
'OpenFireMap',
'SafeCast'
]
import re
return bool(re.match('(' + '|'.join(overlayPatterns) + ')', source.get('name', '')))


def add_attribution(ax, text, font_size=ATTRIBUTION_SIZE, **kwargs):
"""
Expand Down
27 changes: 15 additions & 12 deletions contextily/tile.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def _construct_tile_url(provider, x, y, z):
def _fetch_tile(tile_url, wait, max_retries):
request = _retryer(tile_url, wait, max_retries)
with io.BytesIO(request.content) as image_stream:
image = Image.open(image_stream).convert("RGB")
image = Image.open(image_stream).convert("RGBA")
array = np.asarray(image)
image.close()
return array
Expand Down Expand Up @@ -349,11 +349,11 @@ def warp_tiles(img, extent, t_crs="EPSG:4326", resampling=Resampling.bilinear):
resY = (y[-1] - y[0]) / h
transform = from_origin(x[0] - resX / 2, y[-1] + resY / 2, resX, resY)
# ---
w_img, vrt = _warper(
w_img, bounds, _ = _warper(
img.transpose(2, 0, 1), transform, "EPSG:3857", t_crs, resampling
)
# ---
extent = vrt.bounds.left, vrt.bounds.right, vrt.bounds.bottom, vrt.bounds.top
extent = bounds.left, bounds.right, bounds.bottom, bounds.top
return w_img.transpose(1, 2, 0), extent


Expand Down Expand Up @@ -392,13 +392,13 @@ def warp_img_transform(img, transform, s_crs, t_crs, resampling=Resampling.bilin
Transform of the input image as expressed by `rasterio` and
the `affine` package
"""
w_img, vrt = _warper(img, transform, s_crs, t_crs, resampling)
return w_img, vrt.transform
w_img, _, w_transform = _warper(img, transform, s_crs, t_crs, resampling)
return w_img, w_transform


def _warper(img, transform, s_crs, t_crs, resampling):
"""
Warp an image returning it as a virtual file
Warp an image. Returns the warped image and updated bounds and transform.
"""
b, h, w = img.shape
with MemoryFile() as memfile:
Expand All @@ -411,12 +411,15 @@ def _warper(img, transform, s_crs, t_crs, resampling):
crs=s_crs,
transform=transform,
) as mraster:
for band in range(b):
mraster.write(img[band, :, :], band + 1)
# --- Virtual Warp
vrt = WarpedVRT(mraster, crs=t_crs, resampling=resampling)
img = vrt.read()
return img, vrt
mraster.write(img)

with memfile.open() as mraster:
with WarpedVRT(mraster, crs=t_crs, resampling=resampling) as vrt:
img = vrt.read()
bounds = vrt.bounds
transform = vrt.transform

return img, bounds, transform


def _retryer(tile_url, wait, max_retries):
Expand Down
26 changes: 9 additions & 17 deletions docs/_static/css/custom.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
/* Override some aspects of the pydata-sphinx-theme */

body {
padding-top: 0px;
:root {
--color-active-navigation: 0, 91, 129;
/* Use normal text color (like h3, ..) instead of primary color */
--color-h1: var(--color-text-base);
--color-h2: var(--color-text-base);
}

h1,
h2 {
color: #333;

body {
padding-top: 0px;
}

@media (min-width: 768px) {
Expand All @@ -22,22 +25,11 @@ code {
color: #3b444b;
}

/* Default link color for active + larger font size for sidebar*/
/* Larger font size for sidebar*/
.bd-sidebar .nav > li > a {
font-size: 1em;
}

.bd-sidebar .nav>li>a:hover,
.bd-sidebar .nav > .active:hover > a,
.bd-sidebar .nav > .active > a {
color: #005b81;
}
.toc-entry > .nav-link.active {
color: #005b81;
border-left:2px solid #005b81;
}


/* New element: brand text instead of logo */

/* .navbar-brand-text {
Expand Down
3 changes: 3 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
'css/custom.css',
]

html_sidebars = {
'**': ['docs-sidebar.html'],
}

# ---------------------------------------------------------------------------

Expand Down
120 changes: 109 additions & 11 deletions notebooks/intro_guide.ipynb

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions notebooks/working_with_local_files.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
"source": [
"### Raster from name\n",
"\n",
"The other option `contextily` includes to save rasters is through its Place API, which allows you to query locations through their names (thanks to [`geopy`](https://geopy.readthedocs.io/en/stable/)). For example, we can retrieve a basemap of Sao Paulo:"
"The other option `contextily` includes to save rasters is through its Place API, which allows you to query locations through their names (thanks to [`geopy`](https://geopy.readthedocs.io/en/stable/)). For example, we can retrieve a basemap of Cape Town:"
]
},
{
Expand Down Expand Up @@ -245,8 +245,8 @@
}
],
"source": [
"sao_paulo = ctx.Place(\"Cape Town\", source=ctx.providers.Wikimedia)\n",
"sao_paulo.plot()"
"cape_town = ctx.Place(\"Cape Town\", source=ctx.providers.Wikimedia)\n",
"cape_town.plot()"
]
},
{
Expand All @@ -262,7 +262,7 @@
"metadata": {},
"outputs": [],
"source": [
"sao_paulo = ctx.Place(\"Cape Town\", source=ctx.providers.Wikimedia, path=\"cape_town.tif\")"
"cape_town = ctx.Place(\"Cape Town\", source=ctx.providers.Wikimedia, path=\"cape_town.tif\")"
]
},
{
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

setup(
name="contextily",
version="1.0.0",
version="1.0.1",
description="Context geo-tiles in Python",
long_description=long_description,
long_description_content_type="text/markdown",
Expand All @@ -28,6 +28,7 @@
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython",
"Framework :: Matplotlib",
],
python_requires=">=3.6",
install_requires=install_requires,
Expand Down

0 comments on commit 781fd1f

Please sign in to comment.