【问题标题】:Arc between points in circle圆中点之间的弧
【发布时间】: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


【解决方案1】:

在@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)

上面的代码描绘了我想要它做什么。对样式进行了一些修改,应该很好。

【讨论】:

    【解决方案2】:

    由于根本问题是“我如何在 matplotlib 中绘制和弦图”,我只想告诉你,现在有一个 python 库可以做到这一点:mpl-chord-diagram

    你可以做pip install mpl-chord-diagram

    [免责声明]我是当前的维护者[/disclaimer]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多