绘制曲线以连接Matplotlib中的点

时间:2020-08-24 11:20:41

标签: python matplotlib

所以我试图绘制曲线以连接点,这是我正在使用的代码:-

print(soup.select_one('[data-expected-price]')['data-expected-price'])

代码产生以下输出:- enter image description here

但是我希望曲线看起来像这样: enter image description here

我必须对代码进行哪些更改才能获得所需的结果?

2 个答案:

答案 0 :(得分:16)

这是使用bezier curves的方法。

序列[...., i-indent, i, i + 0.8, ...]将控制点放在每个整数位置i以及前后的一些位置。下图使用indent=0.8; indent=0将创建直线;如果使用indent>1,则曲线将相交更多。其他变化将使曲线或多或少“拐角”。

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
import numpy as np

n_teams = 4
n_weeks = 4
t = np.array([[1, 2, 4, 3],
              [4, 3, 3, 2],
              [3, 4, 1, 4],
              [2, 1, 2, 1]])
fig, ax = plt.subplots(figsize=(10, 4), facecolor='#1b1b1b')
ax.set_facecolor('#1b1b1b')

indent = 0.8
for tj in t:
    ax.scatter(np.arange(len(tj)), tj, marker='o', color='#4F535C', s=100, zorder=3)
    # create bezier curves
    verts = [(i + d, tij) for i, tij in enumerate(tj) for d in (-indent, 0, indent)][1:-1]
    codes = [Path.MOVETO] + [Path.CURVE4] * (len(verts) - 1)
    path = Path(verts, codes)
    patch = patches.PathPatch(path, facecolor='none', lw=2, edgecolor='#4F535C')
    ax.add_patch(patch)
ax.set_xticks([])
ax.set_yticks([])
ax.autoscale() # sets the xlim and ylim for the added patches
plt.show()

resulting plot

彩色版本看起来像:

colors = ['crimson', 'skyblue', 'lime', 'gold']
for tj, color in zip(t, colors):
    ax.scatter(np.arange(len(tj)), tj, marker='o', color=color, s=100, zorder=3)
    verts = [(i + d, tij) for i, tij in enumerate(tj) for d in (-indent, 0, indent)][1:-1]
    codes = [Path.MOVETO] + [Path.CURVE4] * (len(verts) - 1)
    path = Path(verts, codes)
    patch = patches.PathPatch(path, facecolor='none', lw=2, edgecolor=color)
    ax.add_patch(patch)

colored version

以下图表比较了indent的不同值:

comparing indents

答案 1 :(得分:5)

您可以通过自定义FancyArrowPatchconnectionstyle参数来做到这一点。文档对fraction的{​​{1}}和angle的解释不够好,我通过枚举将其绘制出来。

bar

enter image description here

Annotations — Annotating with ArrowConnectionstyle Demo供参考。


回到您的问题。我使用两个import matplotlib.pyplot as plt x1, y1 = 0.3, 0.2 x2, y2 = 0.8, 0.6 fig, axs = plt.subplots(2, 2) axs[0, 0].plot([x1, x2], [y2, y1], ".") axs[0, 0].annotate("", xy=(x1, y2), xycoords='data', xytext=(x2, y1), textcoords='data', arrowprops=dict(arrowstyle="-", color="0.5", connectionstyle="bar,angle=180,fraction=-0.3", ), ) axs[0, 1].plot([x1, x2], [y1, y2], ".") axs[0, 1].annotate("", xy=(x1, y1), xycoords='data', xytext=(x2, y2), textcoords='data', arrowprops=dict(arrowstyle="-", color="0.5", connectionstyle="bar,angle=180,fraction=-0.3", ), ) axs[1, 0].plot([x1, x2], [y2, y1], ".") axs[1, 0].annotate("", xy=(x1, y2), xycoords='data', xytext=(x2, y1), textcoords='data', arrowprops=dict(arrowstyle="-", color="0.5", connectionstyle="bar,angle=90,fraction=-0.3", ), ) axs[1, 1].plot([x1, x2], [y1, y2], ".") axs[1, 1].annotate("", xy=(x1, y1), xycoords='data', xytext=(x2, y2), textcoords='data', arrowprops=dict(arrowstyle="-", color="0.5", connectionstyle="bar,angle=270,fraction=-0.3", ), ) for ax in axs.flat: ax.set(xlim=(0, 1), ylim=(0, 1), aspect=1) fig.tight_layout(pad=0.2) plt.show() 来判断(x1,y1)和(x2,y2)的位置,以检查它们应使用哪个if

connectionstyle

enter image description here


以下是枚举的示例:

import matplotlib.pyplot as plt
import numpy as np

n_teams = 4
n_weeks = 4

fig, ax = plt.subplots(figsize=(6,6))

t = np.array([
    [1, 2, 4, 3],
    [4, 3, 3, 2],
    [3, 4, 1, 4],
    [2, 1, 2, 1]
])

fig.patch.set_facecolor('#1b1b1b')

for nw in range(n_weeks):
    ax.scatter([nw] * n_weeks, t[:, nw], marker='o', color='#4F535C', s=100, zorder=2)
    
ax.axis('off')
    
for team in t:
    x1, x2 = 0, 1
    
    for rank in range(0, len(team) - 1):
        y1 = n_weeks - team[rank] + 1
        y2 = n_weeks - team[rank + 1] + 1

        if (x1 < x2 and y1 > y2):
            ax.annotate("",
                    xy=(x1, y1), xycoords='data',
                    xytext=(x2, y2), textcoords='data',
                    arrowprops=dict(arrowstyle="-", color="0.5",
                                    connectionstyle="bar,angle=180,fraction=-0.2",
                                    ),
                    )

        if (x1 < x2 and y1 < y2):
            ax.annotate("",
                        xy=(x1, y1), xycoords='data',
                        xytext=(x2, y2), textcoords='data',
                        arrowprops=dict(arrowstyle="-", color="0.5",
                                        connectionstyle="bar,angle=270,fraction=-0.4",
                                        ),
                        )

        x1 += 1
        x2 += 1

plt.show()

enter image description here