如何在 matplotlib 中绘制斑马样式轴
How to plot zebra style axis in matplotlib
我想在 zebra style 中绘制轴,类似于:
下面是我的代码:
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import cartopy.crs as ccrs
from cartopy.feature import ShapelyFeature
fig, ax = plt.figure(figsize=(12,9), dpi=150 )
sFilename_shapefile = './some_shape.shp'
pShapeReader = shpreader.Reader(sFilename_shapefile)
pProjection_map = ccrs.PlateCarree()
aShapeFeature = ShapelyFeature(pShapeReader.geometries(),
pProjection_map, facecolor='grey', edgecolor='grey',
linewidth=0.5)
ax.add_feature(aShapeFeature, zorder = 4)
plt.show()
我得到的是这样的:
我有一个适合我的目的的 hacky 解决方案:
示例用法:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
crs = ccrs.PlateCarree()
fig = plt.figure(figsize=(5, 2))
ax = fig.add_subplot(projection=crs)
ax.coastlines()
ax.set_extent((-125, -85, 22, 42))
ax.set_xticks((-120, -110, -100, -90))
ax.set_yticks((25, 30, 35, 40))
add_zebra_frame(ax, crs=crs)
我暂时将框架放在一个函数中。它可能不适用于许多混合 lat/lon 刻度的 polar-type 投影,现在如果你不指定你想要的刻度线,它就不能很好地工作(我仍然不清楚如何Cartopy 选择默认刻度)。
https://gist.github.com/scottstanie/dff0d597e636440fb60b3c5443f70cae
基本上我所做的就是关闭脊柱并在每个 xticks/yticks.
之间绘制一条交替的 black/white 线
import itertools
import matplotlib.patheffects as pe
import numpy as np
def add_zebra_frame(ax, lw=2, crs="pcarree", zorder=None):
ax.spines["geo"].set_visible(False)
left, right, bot, top = ax.get_extent()
# Alternate black and white line segments
bws = itertools.cycle(["k", "white"])
xticks = sorted([left, *ax.get_xticks(), right])
xticks = np.unique(np.array(xticks))
yticks = sorted([bot, *ax.get_yticks(), top])
yticks = np.unique(np.array(yticks))
for ticks, which in zip([xticks, yticks], ["lon", "lat"]):
for idx, (start, end) in enumerate(zip(ticks, ticks[1:])):
bw = next(bws)
if which == "lon":
xs = [[start, end], [start, end]]
ys = [[bot, bot], [top, top]]
else:
xs = [[left, left], [right, right]]
ys = [[start, end], [start, end]]
# For first and lastlines, used the "projecting" effect
capstyle = "butt" if idx not in (0, len(ticks) - 2) else "projecting"
for (xx, yy) in zip(xs, ys):
ax.plot(
xx,
yy,
color=bw,
linewidth=lw,
clip_on=False,
transform=crs,
zorder=zorder,
solid_capstyle=capstyle,
# Add a black border to accentuate white segments
path_effects=[
pe.Stroke(linewidth=lw + 1, foreground="black"),
pe.Normal(),
],
)
我想在 zebra style 中绘制轴,类似于:
下面是我的代码:
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import cartopy.crs as ccrs
from cartopy.feature import ShapelyFeature
fig, ax = plt.figure(figsize=(12,9), dpi=150 )
sFilename_shapefile = './some_shape.shp'
pShapeReader = shpreader.Reader(sFilename_shapefile)
pProjection_map = ccrs.PlateCarree()
aShapeFeature = ShapelyFeature(pShapeReader.geometries(),
pProjection_map, facecolor='grey', edgecolor='grey',
linewidth=0.5)
ax.add_feature(aShapeFeature, zorder = 4)
plt.show()
我得到的是这样的:
我有一个适合我的目的的 hacky 解决方案:
示例用法:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
crs = ccrs.PlateCarree()
fig = plt.figure(figsize=(5, 2))
ax = fig.add_subplot(projection=crs)
ax.coastlines()
ax.set_extent((-125, -85, 22, 42))
ax.set_xticks((-120, -110, -100, -90))
ax.set_yticks((25, 30, 35, 40))
add_zebra_frame(ax, crs=crs)
我暂时将框架放在一个函数中。它可能不适用于许多混合 lat/lon 刻度的 polar-type 投影,现在如果你不指定你想要的刻度线,它就不能很好地工作(我仍然不清楚如何Cartopy 选择默认刻度)。
https://gist.github.com/scottstanie/dff0d597e636440fb60b3c5443f70cae
基本上我所做的就是关闭脊柱并在每个 xticks/yticks.
之间绘制一条交替的 black/white 线import itertools
import matplotlib.patheffects as pe
import numpy as np
def add_zebra_frame(ax, lw=2, crs="pcarree", zorder=None):
ax.spines["geo"].set_visible(False)
left, right, bot, top = ax.get_extent()
# Alternate black and white line segments
bws = itertools.cycle(["k", "white"])
xticks = sorted([left, *ax.get_xticks(), right])
xticks = np.unique(np.array(xticks))
yticks = sorted([bot, *ax.get_yticks(), top])
yticks = np.unique(np.array(yticks))
for ticks, which in zip([xticks, yticks], ["lon", "lat"]):
for idx, (start, end) in enumerate(zip(ticks, ticks[1:])):
bw = next(bws)
if which == "lon":
xs = [[start, end], [start, end]]
ys = [[bot, bot], [top, top]]
else:
xs = [[left, left], [right, right]]
ys = [[start, end], [start, end]]
# For first and lastlines, used the "projecting" effect
capstyle = "butt" if idx not in (0, len(ticks) - 2) else "projecting"
for (xx, yy) in zip(xs, ys):
ax.plot(
xx,
yy,
color=bw,
linewidth=lw,
clip_on=False,
transform=crs,
zorder=zorder,
solid_capstyle=capstyle,
# Add a black border to accentuate white segments
path_effects=[
pe.Stroke(linewidth=lw + 1, foreground="black"),
pe.Normal(),
],
)