Seite 1 von 1

mplotlib 3D surface plot erstellen

Verfasst: Mittwoch 25. Februar 2015, 13:29
von thedome
hallo, ich habe erst vor einigen tagen mit python angefangen und sitze seit einiger zeit an einem code, um mehrere datensätze einzulesen und als 3d surface auszugeben. es handelt sich bei den datensätzen um spalten einer tabelle, die in eine liste eingetragen werden. da mehrere dateien eingelesen werden, werden diese listen nochmals in eine liste eingetragen, welche ich anschließend als 3d surface ausgeben möchte. es werden also zwei spalten aus mehreren dateien ausgelesen, welche dann jeweils die x und y koordinaten darstellen. die z koordinate ist dann der dateiname, wobei dieser durch eine aufsteigende zahl ersetzt wird. das problem ist (womöglich), dass die anzahl der werte in den spalten für jede datei unterschiedlich sind. das heißt, dass ich bspw. für "z=1" 20 werte für x und y habe, aber bei "z=2" nur 10 x und y werte.
ich habe zwei fragen:
1. ist es überhaupt möglich, aus solchen daten eine oberfläche zu generieren?
2. ich erhalte für den unten stehenden code folgende fehlermeldung:
File "C:\Python34\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 1620, in plot_surface
avgzsum = sum(p[2] for p in ps2)
TypeError: unsupported operand type(s) for +: 'int' and 'list'

Ich habe mir die axes3d.py angeguckt, aber werde da leider nicht draus schlau.

Code: Alles auswählen

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
from os import path, chdir, listdir
import glob

mypath = path.join('c:','\\','path')
chdir (mypath)
Typ='*.dat'
Dateiinhalt=glob.glob(Typ)

Frliste=[]
Reliste=[]
Run=[]
Runliste=[]

for i in range(len(Dateiinhalt)):

    Mo, Re, Fr = np.loadtxt(Dateiinhalt[i],skiprows=1,unpack=True)
    Frliste.append(list(Fr))
    Reliste.append(list(Re))
    Run=[]
    j=0
    for j in range(len(Fr)):       #dies dient dazu, ein array für die z koordinaten zu erstellen
        Run.append(i+1)
    Runliste.append(list(Run))


fig = plt.figure()
ax = fig.gca(projection='3d')
X = Frliste
Y = Reliste
Z = Runliste
X, Y = np.meshgrid(X, Y)

surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
        linewidth=0, antialiased=False)

ax.set_zlim(0, 40)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

Danke schonmal für jede Hilfe!

Re: mplotlib 3D surface plot erstellen

Verfasst: Mittwoch 25. Februar 2015, 13:44
von MagBen
Probier mal (Zeile 35):

Code: Alles auswählen

Z = np.array(Runliste)
und prüfe nach Zeile 36 ob X.shape, Y.shape und Z.shape übereinstimmen:

Code: Alles auswählen

print( X.shape )
print( Y.shape )
print( Z.shape )

Re: mplotlib 3D surface plot erstellen

Verfasst: Mittwoch 25. Februar 2015, 13:48
von MagBen
thedome hat geschrieben:das problem ist (womöglich), dass die anzahl der werte in den spalten für jede datei unterschiedlich sind.
Genau das ist das Problem. Z muss in jeder Zeile gleichviel Spalten haben.

Füll die fehlenden Spaltenwerte mit np.NaN auf.

Re: mplotlib 3D surface plot erstellen

Verfasst: Mittwoch 25. Februar 2015, 14:16
von thedome
MagBen hat geschrieben:Probier mal (Zeile 35):

Code: Alles auswählen

Z = np.array(Runliste)
und prüfe nach Zeile 36 ob X.shape, Y.shape und Z.shape übereinstimmen:

Code: Alles auswählen

print( X.shape )
print( Y.shape )
print( Z.shape )
vielen Dank MagBen, Z = np.array(Runliste) habe ich schon probiert, da hat sich nichts geändert.
Folgendes kam bei X, Y, Z shape raus:

(1, 36) -> X
(36, 1) -> Y
(36,) ->Z

und wieder die Fehlermeldung:: File "C:\Python34\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 1620, in plot_surface
avgzsum = sum(p[2] for p in ps2)
TypeError: unsupported operand type(s) for +: 'int' and 'list'
MagBen hat geschrieben:
thedome hat geschrieben:das problem ist (womöglich), dass die anzahl der werte in den spalten für jede datei unterschiedlich sind.
Genau das ist das Problem. Z muss in jeder Zeile gleichviel Spalten haben.

Füll die fehlenden Spaltenwerte mit np.NaN auf.
Ich habe in den Zeilen 35 und 36 folgendes ergänzt

Code: Alles auswählen

Z = np.array(Runliste)
np.nan_to_num(Z)
erhalte dann aber folgende Fehlermeldung:
File "C:\Python34\lib\site-packages\numpy\lib\ufunclike.py", line 113, in isposinf
nx.logical_and(nx.isinf(x), ~nx.signbit(x), y)
TypeError: ufunc 'isinf' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
:K

Re: mplotlib 3D surface plot erstellen

Verfasst: Mittwoch 25. Februar 2015, 14:49
von MagBen
thedome hat geschrieben:Folgendes kam bei X, Y, Z shape raus:
(1, 36) -> X
(36, 1) -> Y
(36,) ->Z
Bei allen drei muss das Gleiche rauskommen.

X und Y müssen vor
X, Y = np.meshgrid(X, Y)
1D Arrays bzw. Listen sein, also nicht Listen von Listen, genau das machst Du aber in den Zeilen 22 und 23. Lass das list mal weg;

Code: Alles auswählen

    Frliste.append(Fr)
    Reliste.append(Re)
thedome hat geschrieben:Ich habe in den Zeilen 35 und 36 folgendes ergänzt
Das reicht nicht. Du musst vor Zeile 28 die Liste Run mit NaN auffüllen, sodass die Liste Run immer die selbe Länge hat. NaN kann man in Matplotlib wunderbar nutzen um Lücken in Kurven oder Löcher in Flächen zu definieren. Probier mal diesen Code aus:

Code: Alles auswählen

import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

nx = 100
ny = 30
x = np.linspace(-1,1,nx)
y = np.linspace(-1,1,ny)

x_2d, y_2d = np.meshgrid(x, y)
z_2d = np.cos(np.pi * x_2d) * np.cos(np.pi * y_2d)

print(x_2d.shape) # (30, 100)
print(y_2d.shape) # (30, 100)
print(z_2d.shape) # (30, 100)

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x_2d, y_2d, z_2d, rstride=1, cstride=1, cmap=cm.coolwarm,)

# Jetzt brennen wir ein Loch rein
z_2d[np.sqrt(x_2d**2 + y_2d**2)<.7 ] = np.NaN

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x_2d, y_2d, z_2d, rstride=1, cstride=1, cmap=cm.coolwarm,)

plt.show()