2016-04-01 7 views
2

Ich zeichne mehrere Zeilen auf dem gleichen Graphen mit Matplotlib in Python mit einer For-Schleife, um jede Zeile der Achse hinzuzufügen.Python for-Schleife zeichnet immer die gleiche Linie wenn 3D (mit Matplotlib)

Wenn in 2D mit jeder Linie über dem anderen geplottet wird, funktioniert das gut.

Beim Plotten in 3D zeigt Python jedes Mal, wenn ich die for-Schleife durchführe, die gleichen graphischen Daten an, auch wenn die Daten signifikant unterschiedlich sind.

Edit: Ich glaube nicht, dass diese Frage ein Duplikat von "How can I tell if NumPy creates a view or a copy?" ist, da es eine bestimmte Instanz von unerwartetem Verhalten hervorhebt.

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() 

Wie Sie sehen können, sollten die Graphen unglaublich anders aussehen;

dies ist ein 2D-Bild des Graphen auf derselben Achse mit einem paar Änderungen an den Code (siehe unten):

Während dies ist die grafische Darstellung des 3D-Plot erzeugt:

.

Das 2D-Diagramm wurde erstellt, indem diese kleinen Änderungen am Code vorgenommen wurden; nichts über der ersten Zeile geändert wurde:

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

Verschieben 'x = np.zeros (Schritte)' im Inneren des ändernden ' für Zeile in init_condition_array 'Schleife behebt das Problem. Es erscheint (irgendwie) 'x' wird innerhalb der' Line3D' Objekte gespeichert, die von 'plt.plot' zurückgegeben werden, aber mutierende' x' beeinflusst die Werte in den anderen 'Line3D's ... – unutbu

+1

Mögliche Duplikate von [Wie kann Ich erkläre, ob NumPy eine Ansicht oder eine Kopie erstellt?] (Http://stackoverflow.com/questions/11524664/how-can-i-tell-if-numpy-creates-a-view-or--copy) –

+0

Danke @unutbu; das ist sortiert - interessant, dass mich die Dokumentation dazu interessieren würde. –

Antwort

1

bewegen x = np.zeros(steps) innerhalb der for row in init_condition_array Schleife Fixes/vermeidet das Problem. x wird in den Line3D Objekten gespeichert, die von plt.plot zurückgegeben werden, und die Änderung x wirkt sich auf die Werte aus, die in den anderen Line3Ds gespeichert sind.

enter image description here


Wenn Sie die source code for Line3D verfolgen durch Sie , dass die Daten, die Sie weitergeben zu plt.plot endet in einem Line3D ‚s _verts3d Attribut finden. Die Daten werden nicht kopiert; Das _verts3d Tuple enthält Referenzen auf die exakt gleichen Arrays.

Und das _verts3d Attribut wird direkt später zugegriffen beim Rendern:

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

Damit die Daten mutiert - auch nach plt.plot Aufruf - mutiert self._verts3d. Dieses einfache Beispiel zeigt das Problem:

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) 

Hier haben wir die ursprünglichen Werte von x haben:

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

Und dies zeigt, dass x mutiert modifiziert 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() 

Diese Überraschung Bei der Erstellung von 2D-Liniendiagrammen tritt keine Fallgrube auf, da dort das Attribut Line2D._xy, das die zum Rendern verwendeten Daten enthält, eine Kopie der Originaldaten speichert.


Dieses Problem im Quellcode fixiert werden könnte, indem in this lineart3d.Line3D.set_3d_properties von

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

zu

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