圆内点之间的弧
Arc between points in circle
我正在尝试使用 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
似乎是问题的根源。
在@f5r5e5d 指出 plotly 中使用的 Bézier curve
之后,我决定试一试。看起来这也是我的方法。
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
import sys
%matplotlib inline
fig, ax = plt.subplots()
npoints = 5
# 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 Bezier curves
numbers = [i for i in xrange(npoints)]
bezier_path = np.arange(0, 1.01, 0.01)
for a, b in itertools.product(numbers, repeat=2):
if a == b:
continue
x1y1 = x1, y1 = verts[a]
x2y2 = x2, y2 = verts[b]
xbyb = xb, yb = [0, 0]
# Compute and store the Bezier curve points
x = (1 - bezier_path)** 2 * x1 + 2 * (1 - bezier_path) * bezier_path * xb + bezier_path** 2 * x2
y = (1 - bezier_path)** 2 * y1 + 2 * (1 - bezier_path) * bezier_path * yb + bezier_path** 2 * y2
ax.plot(x, y, 'k-')
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
上面的代码描绘了我想要它做什么。稍微修改一下样式,应该就可以了。
由于潜在的问题是“如何在 matplotlib 中绘制和弦图”,我只想让您知道现在有一个 python 库可以做到这一点:mpl-chord-diagram。
你可以做到 pip install mpl-chord-diagram
.
[免责声明]我是当前维护者[/免责声明]
我正在尝试使用 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
似乎是问题的根源。
在@f5r5e5d 指出 plotly 中使用的 Bézier curve
之后,我决定试一试。看起来这也是我的方法。
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
import sys
%matplotlib inline
fig, ax = plt.subplots()
npoints = 5
# 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 Bezier curves
numbers = [i for i in xrange(npoints)]
bezier_path = np.arange(0, 1.01, 0.01)
for a, b in itertools.product(numbers, repeat=2):
if a == b:
continue
x1y1 = x1, y1 = verts[a]
x2y2 = x2, y2 = verts[b]
xbyb = xb, yb = [0, 0]
# Compute and store the Bezier curve points
x = (1 - bezier_path)** 2 * x1 + 2 * (1 - bezier_path) * bezier_path * xb + bezier_path** 2 * x2
y = (1 - bezier_path)** 2 * y1 + 2 * (1 - bezier_path) * bezier_path * yb + bezier_path** 2 * y2
ax.plot(x, y, 'k-')
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
上面的代码描绘了我想要它做什么。稍微修改一下样式,应该就可以了。
由于潜在的问题是“如何在 matplotlib 中绘制和弦图”,我只想让您知道现在有一个 python 库可以做到这一点:mpl-chord-diagram。
你可以做到 pip install mpl-chord-diagram
.
[免责声明]我是当前维护者[/免责声明]