Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ If the user is mixing `cnmaps` with scientific Python or GIS tooling and the res
- Draw multiple records or polygons: `draw_maps`
- Clip `contourf`: `clip_contours_by_map`
- Clip `pcolormesh`: `clip_pcolormesh_by_map`
- Clip `imshow` / hillshade images: `clip_imshow_by_map`
- Clip `quiver`: `clip_quiver_by_map`
- Clip `scatter`: `clip_scatter_by_map`
- Clip contour labels: `clip_clabels_by_map`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ Use after `ax.pcolormesh`.

Use after `ax.quiver`.

### `clip_imshow_by_map(image, map_polygon, ax=None, extent=None, set_extent=False)`

Use after `ax.imshow`, especially for hillshade or RGB image layers created from DEM data.

### `clip_streamplot_by_map(streamplot, map_polygon, ax=None, extent=None, set_extent=False)`

Use after `ax.streamplot`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,39 @@ draw_map(china, ax=ax, color="black", linewidth=1.0)
plt.show()
```

## Clip Hillshade Or Imshow Images

```python
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from matplotlib.colors import LightSource
from cnmaps import clip_imshow_by_map, draw_map, get_adm_maps
from cnmaps.sample import load_dem

lons, lats, dem = load_dem()
hillshade = LightSource(azdeg=315, altdeg=45).shade(
dem,
cmap=plt.cm.Greys,
vert_exag=0.8,
blend_mode="overlay",
)
china = get_adm_maps(country="中国", level="国", record="first", only_polygon=True)

fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection=ccrs.PlateCarree())
image = ax.imshow(
hillshade,
extent=[lons.min(), lons.max(), lats.min(), lats.max()],
origin="lower",
transform=ccrs.PlateCarree(),
)

clip_imshow_by_map(image, china)
draw_map(china, ax=ax, color="black", linewidth=1.0)
ax.set_extent(china.get_extent(), crs=ccrs.PlateCarree())
plt.show()
```

## Clip Streamlines

```python
Expand Down
20 changes: 20 additions & 0 deletions cnmaps/drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,26 @@ def clip_pcolormesh_by_map(mesh, map_polygon: MapPolygon, ax=None, extent=None,
_set_clip_box_if_possible(mesh, ax)


def clip_imshow_by_map(image, map_polygon: MapPolygon, ax=None, extent=None, set_extent=False):
"""
使用边界几何裁剪 `ax.imshow()` 返回的图像对象。

参数:
image: `ax.imshow()` 的返回对象。
map_polygon (MapPolygon): 地图边界对象。
ax (GeoAxes, 可选): 目标坐标轴。
extent (tuple, 可选): 可选裁剪范围。
set_extent (bool, 可选): 是否同步设置坐标轴范围。
"""
ax = _resolve_axes(image, ax=ax)

clip = _make_clip_path(map_polygon, ax=ax, extent=extent)
_set_extent_if_needed(ax, extent=extent, set_extent=set_extent)

image.set_clip_path(clip)
_set_clip_box_if_possible(image, ax)


def clip_quiver_by_map(quiver, map_polygon: MapPolygon, ax=None, extent=None, set_extent=False):
"""
使用边界几何裁剪 `ax.quiver()` 返回的箭矢对象。
Expand Down
Binary file added docs/source/_static/clip-china-hillshade.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions docs/source/content/api-ref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,23 @@ drawing模块主要存放与绘图相关的函数
若为 ``True`` 且同时传入 ``extent``,则自动设置坐标范围。


.. py:function:: clip_imshow_by_map(image, map_polygon, ax=None, extent=None, set_extent=False)
:module: cnmaps.drawing

对 ``imshow`` 图像按地图边界裁剪,常用于山地阴影图(hillshade)或 RGB 栅格底图。

:param image:
``ax.imshow()`` 的返回值。
:param map_polygon:
地图边界对象;支持单个 ``MapPolygon``、列表或 ``GeoDataFrame``。
:param ax:
坐标轴;默认优先使用 ``image.axes``,拿不到时再回退到当前轴。
:param extent:
可选的经纬度范围 ``[left, right, lower, upper]``。
:param bool set_extent:
若为 ``True`` 且同时传入 ``extent``,则自动设置坐标范围。


.. py:function:: clip_streamplot_by_map(streamplot, map_polygon, ax=None, extent=None, set_extent=False)
:module: cnmaps.drawing

Expand Down
37 changes: 37 additions & 0 deletions docs/source/content/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,43 @@ cnmaps可以很方便地对地图进行合并,例如我们可以将北京、

.. image:: ../_static/clip-china-quiver.png

剪切山地阴影图(imshow / hillshade)

.. code:: python

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from matplotlib.colors import LightSource
from cnmaps import get_adm_maps, clip_imshow_by_map, draw_map
from cnmaps.sample import load_dem

lons, lats, dem = load_dem()
hillshade = LightSource(azdeg=315, altdeg=45).shade(
dem,
cmap=plt.cm.Greys,
vert_exag=0.8,
blend_mode='overlay',
)

fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection=ccrs.PlateCarree())
map_polygon = get_adm_maps(country='中国', record='first', only_polygon=True)

image = ax.imshow(
hillshade,
extent=[lons.min(), lons.max(), lats.min(), lats.max()],
origin='lower',
transform=ccrs.PlateCarree(),
)

clip_imshow_by_map(image, map_polygon)
draw_map(map_polygon, color='k', linewidth=1)
ax.set_extent(map_polygon.get_extent())

plt.show()

.. image:: ../_static/clip-china-hillshade.png

剪切流线图(streamplot)

.. code:: python
Expand Down
23 changes: 22 additions & 1 deletion tests/test_docs_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LightSource

from cnmaps import (
clip_clabels_by_map,
clip_contours_by_map,
clip_imshow_by_map,
clip_pcolormesh_by_map,
clip_quiver_by_map,
clip_scatter_by_map,
Expand Down Expand Up @@ -124,7 +126,7 @@ def test_docs_union_example():


def test_docs_clip_examples():
"""覆盖 usage.rst 中 contourf、pcolormesh、quiver、scatter、clabel 裁剪示例。"""
"""覆盖 usage.rst 中 contourf、imshow、pcolormesh、quiver、scatter、clabel 裁剪示例。"""

china = get_adm_maps(country="中国", record="first", only_polygon=True)

Expand All @@ -146,6 +148,25 @@ def test_docs_clip_examples():
draw_map(china, ax=ax, color="k", linewidth=1)
_savefig(fig, "usage", "clip-china-contourf.png")

fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection=ccrs.PlateCarree())
hillshade = LightSource(azdeg=315, altdeg=45).shade(
dem,
cmap=plt.cm.Greys,
vert_exag=0.8,
blend_mode="overlay",
)
image = ax.imshow(
hillshade,
extent=[lons_dem.min(), lons_dem.max(), lats_dem.min(), lats_dem.max()],
origin="lower",
transform=ccrs.PlateCarree(),
)
clip_imshow_by_map(image, china, ax=ax)
draw_map(china, ax=ax, color="k", linewidth=1)
ax.set_extent(china.get_extent())
_savefig(fig, "usage", "clip-china-hillshade.png")

fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection=ccrs.PlateCarree())
mesh = ax.pcolormesh(
Expand Down
38 changes: 38 additions & 0 deletions tests/test_drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from matplotlib.colors import LightSource
from matplotlib.patches import FancyArrowPatch

from cnmaps import (
get_adm_maps,
get_adm_names,
clip_clabels_by_map,
clip_contours_by_map,
clip_imshow_by_map,
clip_streamplot_by_map,
draw_map,
draw_maps,
Expand Down Expand Up @@ -183,6 +185,42 @@ def test_clip_pcolormesh():
plt.close()


def test_clip_imshow():
"""测试剪切 imshow / hillshade 图."""

lons, lats, dem = load_dem()
hillshade = LightSource(azdeg=315, altdeg=45).shade(
dem,
cmap=plt.cm.Greys,
vert_exag=0.8,
blend_mode="overlay",
)

for map_arg in map_args:
name = map_arg["name"]

fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection=ccrs.PlateCarree())
map_polygon = get_adm_maps(**map_arg)

image = ax.imshow(
hillshade,
extent=[lons.min(), lons.max(), lats.min(), lats.max()],
origin="lower",
transform=ccrs.PlateCarree(),
)

clip_imshow_by_map(image, map_polygon)
assert image.get_clip_path() is not None

draw_map(map_polygon, linewidth=1)
ax.set_extent(map_polygon.get_extent(buffer=1))
savefp = os.path.join("./tmp", "test_clip_imshow", f"{name}.png")
os.makedirs(os.path.dirname(savefp), exist_ok=True)
plt.savefig(savefp, bbox_inches="tight")
plt.close()


def test_clip_contour():
"""测试剪切等值线."""

Expand Down
Loading