如何平滑类似于 d3 的 curveCardinal 方法实现的闭合线的边缘?

我有几个数据点使用闭合线图连接,我希望线具有平滑的边缘,类似于d3 中curveCardinal方法如何做到这一点。链接在这里

这是我想要做的一个最小的例子:

import numpy as np
from matplotlib import pyplot as plt

x = np.array([0.5, 0.13, 0.4, 0.5, 0.6, 0.7, 0.5])
y = np.array([1.0, 0.7, 0.5, 0.2, 0.4, 0.6, 1.0])

fig, ax = plt.subplots()

ax.plot(x, y)
ax.scatter(x, y)

现在,我想平滑/插入类似于 d3 的 curveCardinal 方法的线。以下是我尝试过的一些方法。

from scipy import interpolate

tck, u = interpolate.splprep([x, y], s=0, per=True)  
xi, yi = interpolate.splev(np.linspace(0, 1, 100), tck)

fig, ax = plt.subplots(1, 1)

ax.plot(xi, yi, '-b')
ax.plot(x, y, 'k')
ax.scatter(x[:2], y[:2], s=200)
ax.scatter(x, y)

上面代码的结果还不错,但我希望当数据点相距很远时曲线会更靠近线(我增加了上面两个此类数据点的大小以突出显示这一点)。本质上,让曲线靠近线。

使用interp1d(和上面的代码有同样的问题):

from scipy.interpolate import interp1d

x = [0.5, 0.13, 0.4, 0.5, 0.6, 0.7, 0.5]
y = [1.0, 0.7, 0.5, 0.2, 0.4, 0.6, 1.0]

orig_len = len(x)
x = x[-3:-1] + x + x[1:3]
y = y[-3:-1] + y + y[1:3]

t = np.arange(len(x))
ti = np.linspace(2, orig_len + 1, 10 * orig_len)

kind='cubic'
xi = interp1d(t, x, kind=kind)(ti)
yi = interp1d(t, y, kind=kind)(ti)

fig, ax = plt.subplots()
ax.plot(xi, yi, 'g')
ax.plot(x, y, 'k')
ax.scatter(x, y)

我还查看了 Chaikins Corner Cutting 算法,但我不喜欢结果。

def chaikins_corner_cutting(coords, refinements=5):
    coords = np.array(coords)

    for _ in range(refinements):
        L = coords.repeat(2, axis=0)
        R = np.empty_like(L)
        R[0] = L[0]
        R[2::2] = L[1:-1:2]
        R[1:-1:2] = L[2::2]
        R[-1] = L[-1]
        coords = L * 0.75 + R * 0.25

    return coords


fig, ax = plt.subplots()

ax.plot(x, y, 'k', linewidth=1)
ax.plot(chaikins_corner_cutting(x, 4), chaikins_corner_cutting(y, 4))

从表面上看,我还查看了 Bezier 曲线、matplotlibs PathPatch 和 Fancy box 实现,但我无法得到任何令人满意的结果。

非常感谢您的建议。

所以,这就是我最终做到的。我决定在每两个现有数据点之间引入新点。下图显示了我如何添加这些新点。红色是我拥有的数据。使用凸包计算数据点的几何中心并从每个点绘制线(用蓝线显示)。将这些线分成两半并连接结果点(绿线)。绿线的中心是添加的新点。

在此处输入图片说明

以下是实现此目的的函数:

def midpoint(p1, p2, sf=1):
    """Calculate the midpoint, with an optional 
    scaling-factor (sf)"""
    xm = ((p1[0]+p2[0])/2) * sf
    ym = ((p1[1]+p2[1])/2) * sf
    return (xm, ym)
def star_curv(old_x, old_y):
    """ Interpolates every point by a star-shaped curve. It does so by adding
    "fake" data points in-between every two data points, and pushes these "fake"
    points towards the center of the graph (roughly 1/4 of the way).
    """

    try:
        points = np.array([old_x, old_y]).reshape(7, 2)
        hull = ConvexHull(points)
        x_mid = np.mean(hull.points[hull.vertices,0])
        y_mid = np.mean(hull.points[hull.vertices,1])
    except:
        x_mid = 0.5
        y_mid = 0.5

    c=1
    x, y = [], []
    for i, j in zip(old_x, old_y):
        x.append(i)
        y.append(j)
        try:
            xm_i, ym_i = midpoint((i, j),
                                  midpoint((i, j), (x_mid, y_mid)))

            xm_j, ym_j = midpoint((old_x[c], old_y[c]),
                                  midpoint((old_x[c], old_y[c]), (x_mid, y_mid)))

            xm, ym = midpoint((xm_i, ym_i), (xm_j, ym_j))
            x.append(xm)
            y.append(ym)
            c += 1
        except IndexError:
            break


    orig_len = len(x)
    x = x[-3:-1] + x + x[1:3]
    y = y[-3:-1] + y + y[1:3]


    t = np.arange(len(x))
    ti = np.linspace(2, orig_len + 1, 10 * orig_len)

    kind='quadratic'
    xi = interp1d(t, x, kind=kind)(ti)
    yi = interp1d(t, y, kind=kind)(ti)

    return xi, yi

这是它的外观:

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from scipy.spatial import ConvexHull

x = [0.5, 0.13, 0.4, 0.5, 0.6, 0.7, 0.5]
y = [1.0, 0.7, 0.5, 0.2, 0.4, 0.6, 1.0]

xi, yi = star_curv(x, y)

fig, ax = plt.subplots()
ax.plot(xi, yi, 'g')

ax.plot(x, y, 'k', alpha=0.5)
ax.scatter(x, y, color='r')

在此处输入图片说明

当数据点更对称时,结果尤其明显,例如以下 x, y 值给出下图中的结果:

x = [0.5, 0.32, 0.34, 0.5, 0.66, 0.65, 0.5]
y = [0.71, 0.6, 0.41, 0.3, 0.41, 0.59, 0.71]

此处介绍的插值与默认的 interp1d 插值之间的比较。

在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

是否可以使用d3并创建类似于vis.js的线/曲线?

来自分类Dev

d3:平滑动画手绘线?

来自分类Dev

在d3中创建新频段时,如何实现平滑过渡?

来自分类Dev

如何实现可变张力功能,D3分层边缘捆绑?

来自分类Dev

如何在D3图形的边缘添加标签

来自分类Dev

如何在D3图形的边缘添加标签

来自分类Dev

如何在d3线中创建折弯

来自分类Dev

d3 线图 - 如何从 Y 轴右侧开始线?

来自分类Dev

如何实现类似于SO的url重写

来自分类Dev

如何实现类似于“truncateat”的东西?

来自分类Dev

如何实现D3甜甜圈图?

来自分类Dev

如何创建类似于ForEach的方法

来自分类Dev

d3:平滑地绘制一条手绘线吗?

来自分类Dev

D3强制布局-如何实现节点的3D外观?

来自分类Dev

如何为模板实现类似于Orientation的属性

来自分类Dev

如何在Rust中实现类似于@override的行为

来自分类Dev

如何在Apache Flink中实现类似于samza的WindowableTask?

来自分类Dev

如何使用AHK实现类似于Visual Studio的链接热键?

来自分类Dev

如何实现类似于Paragon网站的滚动效果

来自分类Dev

如何在bash中实现类似于'apt search'的搜索

来自分类Dev

D3:方向图类似于树的布局,但带有反向链接

来自分类Dev

需要在类似于最近联系人的应用图标上实现 3D 触摸

来自分类Dev

如何制作类似于椭圆的2D数组

来自分类Dev

D3 边缘的条件样式

来自分类Dev

如何在D3中可视化事件时间线?

来自分类Dev

D3分组条形图:如何旋转x轴刻度线的文本?

来自分类Dev

如何始终使用D3 SVG轴渲染末端刻度线

来自分类Dev

D3树图-使用直线而不是对角线时如何过渡链接

来自分类Dev

D3如何从不透明刻度中删除刻度线

Related 相关文章

热门标签

归档