在 seaborn 情节上设置剪辑
Setting a clip on a seaborn plot
我在剪辑 seaborn
情节(特别是 kdeplot
)时遇到问题,因为我认为根据 this example in the matplotlib
docs.
会相当简单
例如下面的代码:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
fig = plt.figure()
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
random_points = np.array([p for p in np.random.random(size=(100, 2)) if 0 < p[0] < 1 and 0 < p[1] < 1])
kde = sns.kdeplot(random_points[:,0], random_points[:,1], ax=ax)
xmin, xmax = kde.get_xlim()
ymin, ymax = kde.get_ylim()
patch = mpl.patches.Circle(((xmin + xmax)/2, (ymin + ymax) / 2), radius=0.4)
ax.add_patch(patch)
kde.set_clip_path(patch)
结果如下:
我想裁剪这个结果,这样 KDE 等高线就不会出现在圆圈之外。到目前为止,我还没有找到一种方法...这可能吗?
我想您的示例仅适用于 'imshow'。
要在圆上隐藏等高线,您必须绘制 'inverse' 所需颜色的多边形。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import seaborn as sns
# Color plot except polygon
def mask_outside(poly_verts, facecolor = None, ax = None):
from matplotlib.patches import PathPatch
from matplotlib.path import Path
if ax is None: ax = plt.gca()
if facecolor is None: facecolor = plt.gcf().get_facecolor()
# Construct inverse polygon
xlim, ylim = ax.get_xlim(), ax.get_ylim()
bound_verts = [(xlim[0], ylim[0]), (xlim[0], ylim[1]),
(xlim[1], ylim[1]), (xlim[1], ylim[0]), (xlim[0], ylim[0])]
bound_codes = [Path.MOVETO] + (len(bound_verts) - 1) * [Path.LINETO]
poly_codes = [Path.MOVETO] + (len(poly_verts) - 1) * [Path.LINETO]
# Plot it
path = Path(bound_verts + poly_verts, bound_codes + poly_codes)
ax.add_patch(PathPatch(path, facecolor = facecolor, edgecolor = 'None', zorder = 1e+3))
# Your example
fig = plt.figure()
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
random_points = np.array([p for p in np.random.random(size=(100, 2)) if 0 < p[0] < 1 and 0 < p[1] < 1])
kde = sns.kdeplot(random_points[:,0], random_points[:,1], ax=ax)
xmin, xmax = kde.get_xlim()
ymin, ymax = kde.get_ylim()
patch = mpl.patches.Circle(((xmin + xmax) / 2, (ymin + ymax) / 2), radius=0.4)
mask_outside([tuple(x) for x in patch.get_verts()]) # call before add_patch!
ax.add_patch(patch)
plt.show()
Serenity 的答案适用于简单的形状,但当形状包含超过三个左右的顶点时(我什至难以确定确切的参数),由于未知原因而崩溃。对于足够大的形状,填充会流入边缘应在的位置,as for example here。
然而,它确实让我沿着正确的道路思考。虽然仅仅使用 matplotlib
natives 似乎不可能做到这一点(也许他提供的代码中有错误?),但使用 shapely
库时很容易,它是适用于此类任务。
生成形状
在这种情况下,您将需要 shapely 的 symmetric_difference
method. A symmetric difference 是此剪切操作的集合理论名称。
对于这个例子,我加载了一个曼哈顿形状的多边形作为 shapely.geometry.Polygon
对象。初始化过程我就不在这里隐藏了,简单易行,如你所愿。
我们可以使用 manhattan.envelope
在 manhattan
周围画一个框,然后应用差异。这是以下内容:
unmanhattan = manhattan.envelope.symmetric_difference(manhattan)
这样做让我们:
将其添加到绘图中
好的,但这是一个 shapely
对象而不是 matplotlib
Patch
,我们如何将它添加到图中? descartes
库处理这种转换。
unmanhattan_patch = descartes.PolygonPatch(unmanhattan)
这就是我们所需要的!现在我们做:
unmanhattan_patch = descartes.PolygonPatch(unmanhattan)
ax.add_patch(unmanhattan_patch)
sns.kdeplot(x=points['x_coord'], y=points['y_coord'], ax=ax)
并得到:
再做一些工作将其扩展到视图中的其余多边形(纽约市),我们可以获得以下最终结果:
我在剪辑 seaborn
情节(特别是 kdeplot
)时遇到问题,因为我认为根据 this example in the matplotlib
docs.
例如下面的代码:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
fig = plt.figure()
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
random_points = np.array([p for p in np.random.random(size=(100, 2)) if 0 < p[0] < 1 and 0 < p[1] < 1])
kde = sns.kdeplot(random_points[:,0], random_points[:,1], ax=ax)
xmin, xmax = kde.get_xlim()
ymin, ymax = kde.get_ylim()
patch = mpl.patches.Circle(((xmin + xmax)/2, (ymin + ymax) / 2), radius=0.4)
ax.add_patch(patch)
kde.set_clip_path(patch)
结果如下:
我想裁剪这个结果,这样 KDE 等高线就不会出现在圆圈之外。到目前为止,我还没有找到一种方法...这可能吗?
我想您的示例仅适用于 'imshow'。
要在圆上隐藏等高线,您必须绘制 'inverse' 所需颜色的多边形。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import seaborn as sns
# Color plot except polygon
def mask_outside(poly_verts, facecolor = None, ax = None):
from matplotlib.patches import PathPatch
from matplotlib.path import Path
if ax is None: ax = plt.gca()
if facecolor is None: facecolor = plt.gcf().get_facecolor()
# Construct inverse polygon
xlim, ylim = ax.get_xlim(), ax.get_ylim()
bound_verts = [(xlim[0], ylim[0]), (xlim[0], ylim[1]),
(xlim[1], ylim[1]), (xlim[1], ylim[0]), (xlim[0], ylim[0])]
bound_codes = [Path.MOVETO] + (len(bound_verts) - 1) * [Path.LINETO]
poly_codes = [Path.MOVETO] + (len(poly_verts) - 1) * [Path.LINETO]
# Plot it
path = Path(bound_verts + poly_verts, bound_codes + poly_codes)
ax.add_patch(PathPatch(path, facecolor = facecolor, edgecolor = 'None', zorder = 1e+3))
# Your example
fig = plt.figure()
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
random_points = np.array([p for p in np.random.random(size=(100, 2)) if 0 < p[0] < 1 and 0 < p[1] < 1])
kde = sns.kdeplot(random_points[:,0], random_points[:,1], ax=ax)
xmin, xmax = kde.get_xlim()
ymin, ymax = kde.get_ylim()
patch = mpl.patches.Circle(((xmin + xmax) / 2, (ymin + ymax) / 2), radius=0.4)
mask_outside([tuple(x) for x in patch.get_verts()]) # call before add_patch!
ax.add_patch(patch)
plt.show()
Serenity 的答案适用于简单的形状,但当形状包含超过三个左右的顶点时(我什至难以确定确切的参数),由于未知原因而崩溃。对于足够大的形状,填充会流入边缘应在的位置,as for example here。
然而,它确实让我沿着正确的道路思考。虽然仅仅使用 matplotlib
natives 似乎不可能做到这一点(也许他提供的代码中有错误?),但使用 shapely
库时很容易,它是适用于此类任务。
生成形状
在这种情况下,您将需要 shapely 的 symmetric_difference
method. A symmetric difference 是此剪切操作的集合理论名称。
对于这个例子,我加载了一个曼哈顿形状的多边形作为 shapely.geometry.Polygon
对象。初始化过程我就不在这里隐藏了,简单易行,如你所愿。
我们可以使用 manhattan.envelope
在 manhattan
周围画一个框,然后应用差异。这是以下内容:
unmanhattan = manhattan.envelope.symmetric_difference(manhattan)
这样做让我们:
将其添加到绘图中
好的,但这是一个 shapely
对象而不是 matplotlib
Patch
,我们如何将它添加到图中? descartes
库处理这种转换。
unmanhattan_patch = descartes.PolygonPatch(unmanhattan)
这就是我们所需要的!现在我们做:
unmanhattan_patch = descartes.PolygonPatch(unmanhattan)
ax.add_patch(unmanhattan_patch)
sns.kdeplot(x=points['x_coord'], y=points['y_coord'], ax=ax)
并得到:
再做一些工作将其扩展到视图中的其余多边形(纽约市),我们可以获得以下最终结果: