Расширить 2D-график до 3D - PullRequest
       58

Расширить 2D-график до 3D

0 голосов
/ 01 февраля 2020

Я пытаюсь показать свои 2D-данные в 3D-пространстве.

Вот мой код ниже:

import numpy as np
import matplotlib.pyplot as plt

i = 60
n = 1000
r = 3.8   
eps = 0.7

y = np.ones((n, i))

# random numbers on the first row of array x
np.random.seed(1)
x = np.ones((n+1, i))
x[0, :] = np.random.random(i)


def logistic(r, x):
    return r * x * (1 - x)

present_indi = np.arange(i)        
next_indi = (present_indi + 1) % i
prev_indi = (present_indi - 1) % i  

for n in range(1000):

    y[n, :] = logistic(r, x[n, :])

    x[n+1, :] = (1-eps)*y[n, present_indi] + 0.5*eps*(y[n, prev_indi] + y[n, next_indi])  
#print(x)

# the above logic generates a 2D array 'x'. with i columns and n rows.    


fig, ax = plt.subplots()
for i in range(60):
       for n in range(1000):
           if n>=900:
                ax.plot(i,x[n,i],'*k',ms=0.9)
plt.xlabel('i')
plt.ylabel('x')
plt.title('test')        
plt.show()

Приведенный выше код отлично отображает графики i и x. Я нанес на карту все элементы 1-го столбца X, затем все элементы второго столбца, затем третьего и т. Д. ....., используя вложенное значение для l oop logi c (см. Код)

Теперь мне нужно расширить графическое представление до 3D, т.е. использовать Xaxis = i, Yaxis = n, Zaxis = массив 'x'

Я хочу подготовьте что-то вроде этого: Something like this

Я знаю, что должен использовать mplot3D, но выполнение следующих действий не даст мне никакого результата:

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for i in range(60):
       for n in range(1000):
           if n>=900:
                ax.plot_wireframe(i,n,x[n,i],rstride=1,cstride=1)

1 Ответ

1 голос
/ 01 февраля 2020

Построение 3D-изображений в matplotlib немного сложно. Обычно вы рисуете целые поверхности сразу, а не одну линию за раз. Вы делаете это, передавая три двумерных массива, по одному для каждого измерения положения (x, y, z). Но вы не можете просто пропустить старые 2d-массивы; сами точки должны быть в точном порядке!

Иногда вы можете сделать что-то, что просто работает, но мне проще явно параметризовать графики, используя размеры u и v. Вот что я смог получить здесь:

# Abstract u and v parameters describing surface coordinates
u_plt = np.arange(x.shape[1])
v_plt = np.arange(x.shape[0])

# The outer products here produce 2d arrays. We multiply by
# ones in this case for an identity transformation, but in 
# general, you could use any broadcasted operation on `u`
# and `v`.
x_plt = np.outer(np.ones(np.size(v_plt)), u_plt)
y_plt = np.outer(v_plt, np.ones(np.size(u_plt)))

# In this case, our `x` array gives the `z` values directly.
z_plt = x

fig = plt.figure(figsize=(16, 10))
ax = fig.add_subplot(111, projection='3d')

ax.set_zmargin(1)  # Add a bit more space around the plot.
ax.plot_wireframe(x_plt, y_plt, z_plt,
                  rstride=1, cstride=1,  # "Resolution" of the plot
                  color='blue', linewidth=1.0,
                  alpha=0.7, antialiased=True)

# Tilt the view to match the example.
ax.view_init(elev = 45, azim = -45)

plt.xlabel('i')
plt.ylabel('x')
plt.title('test')
plt.show()

А вот и полученное изображение. Мне пришлось уменьшить n до 80, чтобы сделать это вообще понятным, и я понятия не имею, на что смотрю, поэтому я не уверен, что это правильно. Но я думаю, что это в целом похоже на пример, который вы привели.

wireframe plot

Просто чтобы проиллюстрировать силу этого подхода, вот оболочка наутилуса. Он использует двухэтапную параметризацию, которая может быть сжата, но концептуально более понятна:

n_ticks = 100

# Abstract u and v parameters describing surface coordinates
u_plt = np.arange(n_ticks // 2) * 2
v_plt = np.arange(n_ticks)

# theta is the angle along the leading edge of the shell
# phi is the angle along the spiral of the shell
# r is the distance of the edge from the origin
theta_plt = np.pi * ((u_plt / n_ticks) * 0.99 + 0.005)
phi_plt = np.pi * v_plt / (n_ticks / 5)
r_plt = v_plt / (n_ticks / 5)

# These formulas are based on the formulas for rendering
# a sphere parameterized by theta and phi. The only difference
# is that r is variable here too.
x_plt = r_plt[:, None] * np.cos(phi_plt[:, None]) * np.sin(theta_plt[None, :])
y_plt = r_plt[:, None] * np.sin(phi_plt[:, None]) * np.sin(theta_plt[None, :])
z_plt = r_plt[:, None] * \ 
    (np.ones(np.shape(phi_plt[:, None])) * np.cos(theta_plt[None, :]))

# This varies the color along phi
colors = cm.inferno(1 - (v_plt[:, None] / max(v_plt))) * \
    np.ones(np.shape(u_plt[None, :, None])) 

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d')

ax.set_zmargin(1)
ax.plot_surface(x_plt, y_plt, z_plt,
                rstride=1, cstride=1,
                facecolors=colors, linewidth=1.0,
                alpha=0.3, antialiased=True)
ax.view_init(elev = 45, azim = -45)

plt.show()

plot of a nautilus shell

...