2016-04-01 1 views
2

Je trace plusieurs lignes sur le même graphe en utilisant matplotlib en Python en utilisant une boucle for pour ajouter chaque ligne à l'axe.Python for-loop trace toujours la même ligne en 3D (en utilisant matplotlib)

Lorsque tracé en 2D avec chaque ligne au-dessus de l'autre cela fonctionne bien. Cependant, lors d'un traçage en 3D, python affiche les mêmes données graphiques chaque fois que je parcours la boucle for, même si les données sont significativement différentes. Edit: Je ne crois pas que cette question est un doublon de "How can I tell if NumPy creates a view or a copy?" car elle met en évidence une instance particulière de comportement inattendu.

import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import axes3d 

###### Unimportant maths not relevant to the question ###### 

def rossler(x_n, y_n, z_n, h, a, b, c): 
    #defining the rossler function 
    x_n1=x_n+h*(-y_n-z_n) 
    y_n1=y_n+h*(x_n+a*y_n) 
    z_n1=z_n+h*(b+z_n*(x_n-c)) 
    return x_n1,y_n1,z_n1 

#defining a, b, and c 
a = 1.0/5.0 
b = 1.0/5.0 
c = 5 

#defining time limits and steps 
t_0 = 0 
t_f = 50*np.pi 
h = 0.01 
steps = int((t_f-t_0)/h) 

#create plotting values 
t = np.linspace(t_0,t_f,steps) 
x = np.zeros(steps) 
y = np.zeros(steps) 
z = np.zeros(steps) 

##### Relevant to the question again ##### 

init_condition_array = [[0,0,0],[0.1,0,0],[0.2,0,0],[0.3,0,0]] 
color_array = ["red","orange","green","blue"] 
color_counter = 0 
zs_array = [0, 0.1, 0.2, 0.3] 

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

for row in init_condition_array: 
    x[0] = row[0] 
    y[0] = row[1] 
    z[0] = row[2] 

    for i in range(x.size-1): 
     #re-evaluate the values of the x-arrays depending on the initial conditions 
     [x[i+1],y[i+1],z[i+1]]=rossler(x[i],y[i],z[i],t[i+1]-t[i],a,b,c) 

    plt.plot(t,x,zs=zs_array[color_counter],zdir="z",color=color_array[color_counter]) 
    color_counter += 1 

ax.set_xlabel('t') 
ax.set_ylabel('x(t)') 
plt.show() 

Comme vous pouvez le voir, les graphiques devraient être incroyablement différents;

ceci est une image 2D des graphiques sur le même axe avec quelques modifications au code (ci-dessous):

Bien que ce soit le graphe produit par le tracé 3D:

.

Le tracé 2D a été créé en faisant ces petites modifications au code; rien au-dessus de la première ligne a été modifiée:

init_condition_array = [[0,0,0],[0.1,0,0],[0.2,0,0],[0.3,0,0]] 
color_array = ["red","orange","green","blue"] 
color_counter = 0 

fig = plt.figure() 
ax = fig.add_subplot(111) 

for row in init_condition_array: 
    x[0] = row[0] 
    y[0] = row[1] 
    z[0] = row[2] 

    for i in range(x.size-1): 
     #re-evaluate the values of the x-arrays depending on the initial conditions 
     [x[i+1],y[i+1],z[i+1]]=rossler(x[i],y[i],z[i],t[i+1]-t[i],a,b,c) 

    plt.plot(t,x,color=color_array[color_counter],lw=1) 
    color_counter += 1 

ax.set_xlabel('t') 
ax.set_ylabel('x(t)') 
plt.show() 
+3

Déplacement 'x = np.zeros (étapes)' 'l'intérieur du pour row dans la boucle init_condition_array' corrige/évite le problème. Il semble (en quelque sorte) 'x' est stocké dans les objets' Line3D' retournés par 'plt.plot', mais la mutation 'x' affecte les valeurs stockées dans l'autre' Line3D's ... – unutbu

+1

Possible dupliquer de [Comment peut Je dis si NumPy crée une vue ou une copie?] (Http://stackoverflow.com/questions/11524664/how-can-i-tell-if-numpy-creates-a-view-or-a-copy) –

+0

Merci @unutbu; ça c'est réglé - intéressant ça, ça m'intéresserait de voir la documentation sur celle-là. –

Répondre

1

Déplacement x = np.zeros(steps) à l'intérieur des corrections de boucle for row in init_condition_array/évite le problème. x est stocké à l'intérieur des Line3D objets retournés par plt.plot, et la mutation affecte les valeurs stockées dans l'autre Line3Ds.

enter image description here


Si vous trace à travers le source code for Line3D, vous trouverez que les données que vous transmettez à plt.plot se termine dans un attribut _verts3d de » Line3D . Les données ne sont pas copiées. le tuple _verts3d contient des références aux mêmes matrices exactes .

Et ce _verts3d attribut est directement accessible plus tard lors du rendu:

def draw(self, renderer): 
    xs3d, ys3d, zs3d = self._verts3d 

Ainsi les données muter - même après avoir appelé plt.plot - mute self._verts3d. Cet exemple simple illustre le problème:

import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import axes3d 

fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 
t = np.linspace(0, 1, 5) 
x = np.sin(t) 
line, = plt.plot(t, x, 0) 

Ici, nous avons les valeurs d'origine de x:

print(line._verts3d[1]) 
# [ 0.   0.24740396 0.47942554 0.68163876 0.84147098] 

Et cela montre que muter x modifie line._verts3d:

x[:] = 1 
print(line._verts3d[1]) 
# [ 1. 1. 1. 1. 1.] 

# The result is a straight line, not a sine wave. 
plt.show() 

Ce surprenant g ne se produit pas lors de la création de tracés linéaires 2D car l'attribut Line2D._xy qui contient les données utilisées pour le rendu stocke une copie des données d'origine.


Ce problème pourrait être résolu dans le code source en changeant this line dans art3d.Line3D.set_3d_properties de

self._verts3d = art3d.juggle_axes(xs, ys, zs, zdir) 

à

import copy 
self._verts3d = copy.deepcopy(art3d.juggle_axes(xs, ys, zs, zdir))