5
2

例えばこのような形のちょっと変わったハートのつくり方を紹介します!!

王道のハート

ハートの関数はこちらにたくさん紹介されていました。

一番バランスの良いハートは、このような三角関数の組み合わせでつくることができます!

x = 16 * np.sin(t)**3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
コード全体はこちら
# ハートの関数
def heart_shape(num_points):
    t = np.linspace(0, 2 * np.pi, num_points)
    x = 16 * np.sin(t)**3
    y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
    return x, y

# プロットの設定
num_points = 1000
x, y = heart_shape(num_points)

# 描画
fig = make_subplots(rows=1, cols=1)

heart_trace = go.Scatter(
    x=x,
    y=y,
    mode='lines',
    line=dict(color='red'),
    name='Heart Shape'
)

fig.add_trace(heart_trace)

# レイアウト
x_range = [min(x), max(x)]
y_range = [min(y), max(y)]
range_max = max(max(x_range), max(y_range))
range_min = min(min(x_range), min(y_range))
fig.update_layout(
    xaxis=dict(
        scaleanchor="y",
        scaleratio=1,
        showgrid=False,
        zeroline=False,
        range=[range_min, range_max]
    ),
    yaxis=dict(
        showgrid=False,
        zeroline=False,
        range=[range_min, range_max]
    ),
    showlegend=False
)

fig.show()

3Dのきれいなハート

3Dのつるっとしたハートも描くことができます。

コードはこちら
def points(x):
    sl = ()
    for i in range(x.ndim):
        x = (x[sl + np.index_exp[:-1]] + x[sl + np.index_exp[1:]]) / 2.0
        sl += np.index_exp[:]
    return x

# ハートの関数
n = 100
xr = np.linspace(-1.3, 1.3, n)
yr = np.linspace(-1.3, 1.3, n)
zr = np.linspace(-1.3, 1.3, n)
xr, yr, zr = np.meshgrid(xr, yr, zr)
x = points(xr)
y = points(yr)
z = points(zr)
heart = (x**2 + 2.5*y**2 + z**2 - 1)**3 - x**2 * z**3 - (1/9)*y**2 * z**3

# 頂点と面
verts, faces, _, _ = measure.marching_cubes(heart, level=0)

# 3Dメッシュ
x, y, z = verts.T
i, j, k = faces.T
fig = go.Figure(data=[go.Mesh3d(
    x=x, 
    y=y, 
    z=z, 
    i=i, 
    j=j, 
    k=k, 
    color='red', 
    opacity=0.5
)])

# レイアウト
fig.update_layout(
    scene=dict(
        xaxis=dict(showbackground=False),
        yaxis=dict(showbackground=False),
        zaxis=dict(showbackground=False)
    )
)

fig.show()

メッシュなので頂点を多くした方が滑らかです。

ちょっと変わったハート

初めに紹介した2Dのハートのz軸を調整することで面白い形をつくることができます。

動きのあるハート

左右非対称のハートです。

sinカーブを使った滑らかな曲線でz軸の高低差を使ってy軸の正負でサイズが違って見えるように描けます。
ハートの真ん中の部分は実はクルッと回転しています。
無題の動画 (2).gif

コードはこちら
# ハートの関数
def heart_coordinates(num_points):
    t = np.linspace(0, 2 * np.pi, num_points)
    x = 16 * np.sin(t)**3
    y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
    z = -np.sin(t)
    return np.vstack((x, y, z)).T

# 描画の設定
num_points = 1000
pos_3d = heart_coordinates(num_points)
node_trace = go.Scatter3d(
    x=pos_3d[:, 1], 
    y=pos_3d[:, 0],
    z=pos_3d[:, 2],
    mode='markers',
    marker=dict(size=5, color='red')
)

fig = make_subplots(rows=1, cols=1, specs=[[{'type': 'scatter3d'}]])
fig.add_trace(node_trace)

# レイアウト
fig.update_layout(
    title="Heart Shape Graph using Plotly",
    showlegend=False,
    scene=dict(
        xaxis=dict(showbackground=False),
        yaxis=dict(showbackground=False),
        zaxis=dict(showbackground=False),
        camera=dict(
            eye=dict(x=0, y=0, z=2) #アングル調整が大事
        )
    )
)

fig.show()

つながっていないハート

こちらはz軸方向に伸びる紐のような形状です。

無題の動画 (3).gif

コードはこちら
# ハートの関数
def heart_coordinates(num_points):
    t = np.linspace(0, 2 * np.pi, num_points)
    x = 16 * np.sin(t)**3
    y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
    z = t
    return np.vstack((x, y, z)).T

# 描画の設定
num_points = 1000
pos_3d = heart_coordinates(num_points)
node_trace = go.Scatter3d(
    x=pos_3d[:, 1], 
    y=pos_3d[:, 0],
    z=pos_3d[:, 2],
    mode='markers',
    marker=dict(size=3, color='red')
)

fig = make_subplots(rows=1, cols=1, specs=[[{'type': 'scatter3d'}]])
fig.add_trace(node_trace)

# レイアウト
fig.update_layout(
    title="Heart Shape Graph using Plotly",
    showlegend=False,
    scene=dict(
        xaxis=dict(showbackground=False,showaxeslabels=False),
        yaxis=dict(showbackground=False,showaxeslabels=False),
        zaxis=dict(showbackground=False,showaxeslabels=False),
        camera=dict(
            eye=dict(x=-0.01, y=0, z=2.2)
        )
    )
)

fig.show()

これを応用して、z軸が大きくなるにつれてx,y軸も大きくすればこのような図形をつくることができます。

無題の動画 (4).gif

コードはこちら
# ハートの関数
def heart_coordinates(num_points):
    t = np.linspace(0, 10 * np.pi, num_points) #2n*piで何周するかを定義
    z = t
    x = 16 * np.sin(t)**3*z
    y = (13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t))*z
    return np.vstack((x, y, z)).T

# 描画の設定
num_points = 5000
pos_3d = heart_coordinates(num_points)
node_trace = go.Scatter3d(
    x=pos_3d[:, 1], 
    y=pos_3d[:, 0],
    z=pos_3d[:, 2],
    mode='markers',
    marker=dict(size=3, color='red')
)

fig = make_subplots(rows=1, cols=1, specs=[[{'type': 'scatter3d'}]])
fig.add_trace(node_trace)

# レイアウト
fig.update_layout(
    title="Heart Shape Graph using Plotly",
    showlegend=False,
    scene=dict(
        xaxis=dict(showbackground=False,showaxeslabels=False),
        yaxis=dict(showbackground=False,showaxeslabels=False),
        zaxis=dict(showbackground=False,showaxeslabels=False),
        camera=dict(
            eye=dict(x=-0.01, y=0, z=2.2)
        )
    )
)

fig.show()

おまけ

尖ったハート

sin→cosにすると左右対称の中心で尖るハートができます。

無題の動画 (1).gif

コードはこちら
# ハートの関数
def heart_coordinates(num_points):
    t = np.linspace(0, 2 * np.pi, num_points)
    x = 16 * np.sin(t)**3
    y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
    z = np.cos(t)
    return np.vstack((x, y, z)).T

# 描画の設定
num_points = 1000
pos_3d = heart_coordinates(num_points)
node_trace = go.Scatter3d(
    x=pos_3d[:, 1],
    y=pos_3d[:, 0],
    z=pos_3d[:, 2],
    mode='markers',
    marker=dict(size=5, color='red'),
)

fig = make_subplots(rows=1, cols=1, specs=[[{'type': 'scatter3d'}]])
fig.add_trace(node_trace)

# レイアウト
fig.update_layout(
    title="Heart Shape Graph using Plotly",
    showlegend=False,
    scene=dict(
        xaxis=dict(showbackground=False),
        yaxis=dict(showbackground=False),
        zaxis=dict(showbackground=False),
        camera=dict(
            eye=dict(x=0, y=0, z=2)
        )
    )
)

fig.show()
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2