如何在没有数学的情况下获得matplotlib中重叠补丁的轮廓

时间:2016-01-10 04:28:28

标签: python matplotlib

http://matplotlib.org/examples/pylab_examples/ellipse_rotated.html

我想在这些补丁的重叠区域(准多边形)的轮廓上添加线条,如上例所示。 如何在不解决方程的情况下实现这一目标?

2 个答案:

答案 0 :(得分:2)

您可能会发现Coloring Intersection of Circles/Patches in Matplotlib有用。

它使用Shapely库创建所需的几何体,然后将其呈现为使用matplotlib显示。

要在Shapely中获得有角度的椭圆,您可以创建一个缓冲点(圆圈),然后缩放并旋转它。

修改:我无法安装Shapely(Anaconda 3.4 64bit + Windows 10 + Shapely == GRRRR),所以这是未经测试的:

import numpy as np
import shapely.geometry as sg
import shapely.affinity as sa
import descartes
import matplotlib.pyplot as plt
from functools import reduce

def shapely_ellipse(center, major_axis, minor_axis, rotation=0.):
    el = sg.Point(0., 0.).buffer(1.)               # a unit circle
    el = sa.scale(el, major_axis/2, minor_axis/2)  # make it elliptic
    el = sa.rotate(el, rotation)
    el = sa.translate(el, *center)
    return el

def intersect(a, b):
    return a.intersection(b)

def main():
    # make ellipses
    delta = 45.  # degrees
    angles = np.arange(0., 360. + delta, delta)
    ells = [shapely_ellipse((1,1), 4, 2, a) for a in angles]

    # find intersection
    center = reduce(intersect, ells)

    # convert to matplotlib patches
    center = descartes.PolygonPatch(center, ec='k', alpha=0.5)

    # plot it
    # ax = plt.subplot(111, aspect='equal')
    ax = plt.gca()
    for e in ells:
        e = descartes.PolygonPatch(e)
        e.set_alpha(0.1)
        ax.add_artist(e)

    ax.add_patch(center)
    ax.set_xlim(-2, 4)
    ax.set_ylim(-1, 3)
    ax.set_aspect('equal')
    plt.show()

if __name__ == "__main__":
    main()

enter image description here

答案 1 :(得分:1)

仅使用matplotlib(及其依赖项,NumPy),

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as patches

fig = plt.figure()
ax = plt.subplot(111, aspect='equal')

num_ellipses = 4
angles = np.linspace(0, 180, num_ellipses, endpoint=False)
ellipses = [patches.Ellipse((1, 1), 4, 2, a) for a in angles]

# The transform used for rendering the Ellipse as points depends on the
# axes.  So you must add the Ellipses to an axes to fix its transform before
# calling any method that returns coordinates.
for e in ellipses:
    e.set_alpha(0.1)
    ax.add_artist(e)

# get the points on the ellipses in axes coordinates
axes_points = [e.get_verts() for e in ellipses]

# find which points are inside ALL the paths
all_axes_points = np.row_stack(axes_points)

# create the boolean mask using the points and paths in axes coordinates
in_all_ellipses = np.all(
    [e.get_path().contains_points(all_axes_points, e.get_transform(), radius=0.0) 
     for e in ellipses], axis=0)

# find the points in data coordinates
transdata = ax.transData.inverted()
data_points = [transdata.transform(points) for points in axes_points]
all_data_points = np.row_stack(data_points)
intersection = all_data_points[in_all_ellipses]

# Finding the convex hull of `intersection` would be more robust, but adds another dependency
# import scipy.spatial as spatial
# import matplotlib.collections as mcoll
# hull = spatial.ConvexHull(intersection)
# # Draw a black outline around the intersection
# lc = mcoll.LineCollection(intersection[hull.simplices], 
#                           colors='black', linewidth=2, zorder=5)
# ax.add_collection(lc)

# Instead, we can find the convex hull in this special case by ordering the points 
# according to its angle away from (1,1) 
idx = np.argsort(np.arctan2(intersection[:,1]-1, intersection[:,0]-1))
# use np.r_[idx, idx[0]] to append the first point to the end, thus connecting
# the outline
intersection = intersection[np.r_[idx, idx[0]]]

plt.plot(intersection[:, 0], intersection[:, 1], 'k', lw=2, zorder=5)

# Draw an outline around each ellipse just for fun.
for points in data_points:
    plt.plot(points[:, 0], points[:, 1])

plt.xlim(-2, 4)
plt.ylim(-1, 3)

plt.show()

enter image description here

上面的主要思想是使用path.contains_points方法来测试a 点在路径内。每个椭圆都有一个路径,每个椭圆都是 大致由点组成。如果我们收集所有这些点并测试它们 每个路径都有path.contains_points,然后是包含的点 所有路径都在交叉路口。

请注意,如果放大整个区域的角落,您会看到一个 缺少一点交集。这归因于e.get_verts() 缺乏足够高的分辨率。我们可以通过使用NumPy来计算 椭圆上的点,但这可能违反了精神 "没有求解方程式"需求。

您可能想知道matplotlib 如何在高处绘制椭圆 分辨率但却无法访问高分辨率点本身。 "魔术"是在draw方法中完成的,它使用了一些复杂的方法 用弧度逼近椭圆部分的算法。不幸的是,代码 这样做只会渲染弧线,它不会让你访问弧线或弧线中的点(如 我可以看到。)