【发布时间】:2017-02-10 15:16:48
【问题描述】:
我正在尝试使用 Matplotlib 绘制和弦图。我知道已经存在的库,比如 Plotly 给了我这个功能,但我真的很想在 matplotlib 中做。
到目前为止,我的代码如下所示:
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig, ax = plt.subplots()
ax.axhline(0, color='black', linestyle='--')
ax.axvline(0, color='black', linestyle='--')
npoints = 3
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the arcs
numbers = [i for i in xrange(npoints)]
for i, j in itertools.product(numbers, repeat=2):
if i == j:
continue
x1y1 = x1, y1 = verts[i]
x2y2 = x2, y2 = verts[j]
# Calculate the centre of the Arc
mxmy = mx, my = [(x1 + x2) / 2, (y1 + y2) / 2]
r = np.sqrt((x1 - mx)**2 + (y1 - my)**2)
xy = [mx - r, my - r]
width = 2 * r
height = 2 * r
start_angle = np.arctan2(y1 - my, x1 - mx) * 180 / np.pi
end_angle = np.arctan2(y2 - my, x2 - mx) * 180 / np.pi
arc = patches.Arc(mxmy, width, height, start_angle, end_angle)
ax.add_patch(arc)
# Plot the points
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.annotate("1", (x[0], y[0]), xytext=(x[0] + .5, y[0] + .5))
ax.annotate("2", (x[1], y[1]), xytext=(x[1] - 1, y[1] + .5))
ax.annotate("3", (x[2], y[2]), xytext=(x[2] - 1, y[2] - 1))
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
我期待更像下面的东西(图片来自Plotly)
编辑 1
我想在以下点之间画弧:
- 1 和 2
- 1 和 3
- 2 和 3
理想情况下,这些弧线应该在内侧。
编辑 2
经过进一步调查,我认为end_angle 似乎是问题的根源。
【问题讨论】:
-
你的意思是
plotly而不是pyplot,因为pyplot是matplotlib -
我猜你的主要问题是弧中心的计算。中心不能只是两点坐标的平均值......
-
阅读参考文献:
...we draw a cubic Bézier curve ...更多的数学运算可以防止曲线在具有高多重性的点处相交,这使得在视觉上追踪它们变得困难。也许操纵 Arc w, h 参数可以产生类似的效果 -
这不是一个可运行的示例——
length没有定义,您在需要numpoints的地方使用硬编码的 20。修复这些问题并使用npoints=3,这将让您在更改代码时看到代码实际在做什么。 -
你有一个数学问题,而不是一个编码问题。就我个人而言,我会使用纸和铅笔(字面意思是绘制几何图形)来查看我的想法。
标签: python matplotlib geometry plotly