rene
rene

Reputation: 99

How to plot a surface plot from pandas columns

I am trying to make an evaluation of my area measurement. However, I can't get it to make an area from the points (Position_x, Position_y, Position_z) from a CSV file.

I always get the error: ValueError: Argument Z must be 2-dimensional. and don't know how to fix it.

Can someone please help me with this. I have given an example below.

CSV FILE

Position Y,Position X,Mediane
1.5,0.5,-69.00
1.5,1.0,-67.00
1.5,1.5,-68.00
1.5,2.0,-67.00
1.5,2.5,-63.00
1.5,3.0,-55.50
1.5,3.5,-59.00
1.5,4.0,-62.00
1.5,4.5,-65.00
1.5,5.0,-68.00
1.5,5.5,-65.00
1.5,6.0,-69.00
2,0.5,-72.00
2,1.0,-74.00
2,1.5,-67.00
2,2.0,-71.00
2,2.5,-66.00

Python Code:

import numpy as np
import matplotlib.pyplot as plt 
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
import pandas as pd
from sys import exit

df = pd.read_csv(r"C:\Users\ramsa\OneDrive\Desktop\Messungen\Auswertungen\Test_Auswertung.csv")
def update_lines(num, data, line):
    line.set_data(data[0:2, :num])    
    line.set_3d_properties(data[2, :num])    
    return line

fig = plt.figure(figsize = (12,10))
ax = plt.axes(projection='3d')

x = df['Position X']
y = df['Position Y']

X, Y = np.meshgrid(x, y)
Z = df['Mediane']

surf = ax.plot_surface(X, Y, Z, cmap = plt.cm.cividis)

ax.set_xlabel('x', labelpad=20)
ax.set_ylabel('y', labelpad=20)
ax.set_zlabel('z', labelpad=20)

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

plt.show()

Upvotes: 2

Views: 298

Answers (2)

rene
rene

Reputation: 99

The solution is.

import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# CSV-Datei einlesen
data = pd.read_csv(r"C:\Users\ramsa\OneDrive\Desktop\Messungen\Auswertungen\Test_Auswertung.csv")

# Daten extrahieren
position_y = data['Position Y']
position_x = data['Position X']
mediane = data['Mediane']

# Z-Werte sortieren
sorted_indices = mediane.argsort()
position_y = position_y[sorted_indices]
position_x = position_x[sorted_indices]
mediane = mediane[sorted_indices]

# 3D-Plot erstellen
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(position_x, position_y, mediane, cmap='viridis')

# Achsenbeschriftung
ax.set_xlabel('Position X')
ax.set_ylabel('Position Y')
ax.set_zlabel('Mediane')

# Plot anzeigen
plt.show()

Upvotes: 1

HackXIt
HackXIt

Reputation: 542

The error message you're receiving is due to the fact that ax.plot_surface requires a 2D array for Z, while you're providing a 1D array.

The np.meshgrid function generates a two-dimensional grid from the x and y vectors, so we need to make sure our Z also corresponds to the shape of this grid.

However, the data from the CSV file does not form a regular grid which is necessary for plot_surface function to work. You can use the scipy.interpolate.griddata function to interpolate the irregularly spaced data to a regular grid.

Here is how you could do it:

import numpy as np
import matplotlib.pyplot as plt 
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
import pandas as pd
from sys import exit
from scipy.interpolate import griddata

df = pd.read_csv(r"C:\Users\ramsa\OneDrive\Desktop\Messungen\Auswertungen\Test_Auswertung.csv")

fig = plt.figure(figsize = (12,10))
ax = plt.axes(projection='3d')

# Construct the grid.
x = df['Position X']
y = df['Position Y']
z = df['Mediane']

# Interpolate Z values on 2D grid (Creating a 2D representation of Z values)
xi = np.linspace(x.min(), x.max(), len(x.unique()))
yi = np.linspace(y.min(), y.max(), len(y.unique()))
xi, yi = np.meshgrid(xi, yi)
zi = griddata((x, y), z, (xi, yi), method='cubic')

# Draw the surface plot
surf = ax.plot_surface(xi, yi, zi, cmap = plt.cm.cividis)

ax.set_xlabel('x', labelpad=20)
ax.set_ylabel('y', labelpad=20)
ax.set_zlabel('z', labelpad=20)

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

plt.show()

In this code, the griddata function is used to create a 2D representation of Z values, which fits the 2D grid we created with np.meshgrid.

Note that method='cubic' is used to interpolate the values. This method is good for smooth data, but it could lead to artifacts for non-smooth data or data with large gradients. In such cases, you might want to try method='linear' or method='nearest' instead.

Upvotes: 2

Related Questions