3D Scatterplot eines 2D-Arrays

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
phtagen
User
Beiträge: 5
Registriert: Mittwoch 27. Februar 2019, 11:02

Hallo liebes Forum,

ich bin noch recht jungfräulich in Python unterwegs. Ich hab bereits im Internet recherchiert in der Annahme mein Problem wäre ein Standardfall in Python, aber irgendwie hab ich mich da geirrt oder bin zu blöd richtig zu suchen.

Folgende Situation: Ich habe eine 2D-Intensitätsverteilung als Messwertmatrix. Man kann sich das wie ein Graustufenbild vorstellen. Ich möchte jetzt allerdings keine Darstellung als Bild, sondern die gemessenen Intensitätswerte als 3D-Scatterplot. D. h. in der MxN-Matrix habe möchte die M-Dimension auf der X-Achse, die N-Dimension auf der Y-Achse und die Intensitätsverteilung als Z-Wert punktweise dargestellt haben (siehe hierzu auch angehängte Grafiken).

Da die Originalmessdaten als Bild vorliegen, habe ich das in ImageJ schon so dargestellt bekommen (siehe intensity_distro für die Originaldaten und wunsch_darstellung für das was ich letztlich erreichen möchte).

Da ich allerdings einfach etwas Freiheit haben möchte, was die Verteilung der Daten auf den Achsen angeht, möchte ich das Ganze in Python umsetzen. Und hier scheitere ich momentan. Ich habe mit plot_surface zumindest schon so was ähnliches hinbekommen (siehe surface_plot_python), allerdings möchte ich hier keine Oberfläche sehen, sondern nur die Datenpunkte selbst.

Hat da jemand eine Idee?

Anhänglich ist noch ein Code-Schnippsel, sowie drei Bilder von dem was ich haben möchte und dem was ich bis jetzt habe. Nebenfrage: Gibt es eine Möglichkeit auf das Meshgrid zu verzichten, sodass ich direkt auf der X-/Y-Achse die Werte aus demX/Y-Array angezeigt bekomme (die Werte entsprechen jeweils einer Länge)? Und wie bekomme ich das Grid aus?

Merci

Phtagen

Code: Alles auswählen

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from skimage import io
data = np.genfromtxt('/path_to_my_data/corr.txt', delimiter = ' ')

X = data[0, 1:]
Y = data[1:, 0]
Z = data[1:, 1:]
nx = data[0,1:].size
ny = data[1:,0].size
npx = np.linspace(0,1,nx)
npy= np.linspace(0,1,ny)
xv, yv = np.meshgrid(npx, npy)

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

ax.plot_surface(xv, yv, Z)

ax.set_xlabel('$t_{low}$')
ax.set_ylabel('$t_{hi}$')
ax.set_zlabel('$p_{ges}$')

plt.show()
Bild
Bild
Bild
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
phtagen
User
Beiträge: 5
Registriert: Mittwoch 27. Februar 2019, 11:02

Hallo Thomas,

vielen Dank für deine Antwort. Leider hilft die mir so nicht weiter. Ich habe natürlich bereits Google bemüht und zig ähnliche Seiten mit ähnlichen Beispielen gefunden. Das Problem hierbei ist, dass das Datenarray, welches dort in dem Beispiel geplottet wird, eindimensional ist, denn bei zs handelt es sich um einen Spaltenvektor mit 100 Einträgen.

Ich möchte aber eine Matrix auf diese Weise plotten mit MxN Einträgen.

Ich sehe auch gerade, dass meine Bilder nicht angezeigt werden. Wie kann ich meinen Beitrag editieren um direkt die links anzugeben (ich finde dazu tatsächlich keine Option neben meinem Beitrag?!?)?

Grüße
Pht...
ArtooDetoo
User
Beiträge: 60
Registriert: Dienstag 4. Dezember 2018, 16:57

Ich schätze das Stichwort, das du suchst, ist Surface Plot.

edit: Vielleicht doch nicht, es werden ja keine einzelnen Punkte geplottet. Für den von Thomas vorgeschlagenen Scatterplot müsstest du deine Matrix dann in ein eindimensionales Array umwandeln. Dann würde das funktionieren.
phtagen
User
Beiträge: 5
Registriert: Mittwoch 27. Februar 2019, 11:02

Hallo ArtooDetoo,

danke für die Antwort. Das mit dem Surface Plot hatte ich auch schon. Aber wie du richtig festgestellt hast, werden da nicht einzelne Punkte geplottet. Bei mir sieht das Ganze im Moment aus wie ein 3D-Bar-Chart.

Gibt es denn irgendwelche Optionen für den Surface Plot, sodass dieser nur als Punktwolke dargestellt wird?

NB: Ich weiß immer noch nicht, wie ich meinen ersten Beitrag editieren kann. Muss das von nem Admin freigeschaltet werden? Egal, hier nochmal die Links zu meinen Bildern, in der Hoffnung, dass die jetzt abrufbar sind.

https://www.bilder-upload.eu/bild-3a078 ... 2.jpg.html
https://www.bilder-upload.eu/bild-1e339 ... 9.jpg.html
https://www.bilder-upload.eu/bild-a7226 ... .jpeg.html
__deets__
User
Beiträge: 14533
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man kann hier Beitraege nur fuer einen gewissen Zeitraum bearbeiten. Danach sind sie gesperrt zur Bearbeitung, damit nicht nachtraeglich Leute Aussagen veraendern oder wie auch so manche Spezis alles loeschen wenn ihr Problem geloest ist - auf das kein anderer was davon hat.

Und hier ist nix dabei? https://matplotlib.org/gallery.html#mplot3d
phtagen
User
Beiträge: 5
Registriert: Mittwoch 27. Februar 2019, 11:02

Moin __deets__,

ok gut zu wissen.
damit nicht nachtraeglich Leute Aussagen veraendern oder wie auch so manche Spezis alles loeschen wenn ihr Problem geloest ist
- solche Leute soll es wohl geben...

Auf der von Dir verlinkten Seite war ich auch schon, leider ohne fündig zu werden. Ich hätte ehrlich gesagt nicht gedacht, dass das so ein übler Spezialfall ist, den ich hier haben möchte. Zumal ImageJ genau diese Ansicht von Haus aus mitbringt.

Mhmm, die einzige Idee die ich jetzt noch hätte, wäre über alle Spalten oder Zeilen zu loopen und dann halt jede Spalte/Zeile als Scatter in die Grafik zu hauen.

Aber das kann es doch echt nicht sein, oder?!?

Grüße
__deets__
User
Beiträge: 14533
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also ich verstehe nicht, was zB an https://matplotlib.org/examples/mplot3d ... _demo.html jetzt nicht im Grunde dein gewuenschter Plot ist. Was ist daran falsch? Wenn du die Farbe vom Wert abhaengig machst, bekommst du doch pro Datenpunkt einen Punkt im Plot? Oder verstehe ich nicht, was du willst?
phtagen
User
Beiträge: 5
Registriert: Mittwoch 27. Februar 2019, 11:02

Das ist das Beispiel was Thomas mir auch schon vorgeschlagen hatte. Die Argumente die du dem scatter(..) übergibst, müssen alle die gleiche Größe haben. D. h. also, dass das Z-Array nur 1D sein kann. Ich habe ein 2D-Array für Z, d. h. prinzipiell ist hier schon der surface oder contour-plot richtig. Aber die Art der Darstellung passt nicht, ich möchte halt die Daten als Punktwolke dargestellt haben und nicht als Fläche.

Ich habe jetzt mal folgendes gemacht: In einem Loop mache ich aus jeder Zeile meines 2D-Arrays je einen Zeilenvektor und plotte diesen dann mit scatter() in meine Grafik.

Hätte aber nicht gedacht, dass man das so anstellen muss...

Code: Alles auswählen

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

data = np.genfromtxt('/path_to_my_data/corr.txt', delimiter = ' ')

X = data[0, 1:]
Y = data[1:, 0]
Z = data[1:, 1:]
nx = data[0,1:].size

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

for i in range(nx):
    ax.scatter(X[:], Y[i], Z[:,i], c='gray', marker='.')

ax.set_xlabel('$t_{low}$')
ax.set_ylabel('$t_{hi}$')
ax.set_zlabel('$p_{ges}$')
ax.grid('off')

plt.show()
Das Ergebnis sieht dann so aus und kommt dem langsam nahe was ich haben möchte:

https://www.bilder-upload.eu/bild-c8edd ... .jpeg.html

Wenn da aber jemand noch einen besseren Vorschlag hat, dann bitte her damit!

Viele Grüße

Pht...
Antworten