Overtime4728
Overtime4728

Reputation: 144

3D plot of Excel data

I'm trying to recreate this plot using some of my own excel data but I've hit a wall. So far I have:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

df = pd.read_excel(r'/path/to/data.xlsx')

yr = df['Year']
jd = df['Jday']
dc = df['Discharge']

x = np.asarray(yr)
y = np.asarray(jd)
z = np.asarray(dc)

X,Y,Z = np.meshgrid(x,y,z)

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

ax.plot_surface(X,Y,Z, cmap='autumn')

ax.set_xlabel("Year")
ax.set_ylabel("Jday")
ax.set_zlabel("Discharge")


plt.show()

But when I run this I get:

Traceback (most recent call last):
  File "/Users/Desktop/main.py", line 19, in <module>
    ax.plot_surface(X,Y,Z, cmap='autumn')
  File "/Users/venv/lib/python3.10/site-packages/matplotlib/_api/deprecation.py", line 412, in wrapper
    return func(*inner_args, **inner_kwargs)
  File "/Users/venv/lib/python3.10/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 1581, in plot_surface
    raise ValueError("Argument Z must be 2-dimensional.")
ValueError: Argument Z must be 2-dimensional.

Any help would be appreciated.

EDIT:

I changed my code to:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

df = pd.read_excel(r'/path/to/data.xlsx')

yr = df['Year']
jd = df['Jday']
dc = df['Discharge']

X = np.asarray(yr).reshape(-1,2)
Y = np.asarray(jd).reshape(-1,2)
Z = np.asarray(dc).reshape(-1,2)

fig = plt.figure(figsize=(14,8))
ax = plt.axes(projection='3d')

my_cmap = plt.get_cmap('seismic')

surf = ax.plot_surface(X,Y,Z,
                       cmap = my_cmap,
                       edgecolor = 'none')
fig.colorbar(surf, ax=ax,
             shrink = 0.5, aspect = 5)

plt.show()

When I run this it produces the following plot: enter image description here

Which obviously doesn't match the other plot. It seems to be plotting the data from each year in a single line instead of creating filled in polygons which is what I think it's supposed to do. I have a feeling this issue has to do with the .reshape function but I'm not entirely sure.

Upvotes: 1

Views: 1924

Answers (1)

lcdumort
lcdumort

Reputation: 611

Note: original answer completely rewritten!

The problem is, as your data stated, that the Z-argument must be two-dimensional. In your problem, you don't need np.meshgrid at all. This is typically used to make a 'grid' of all possible combinations of X/Y, after which you can use these combinations to calculate your response matrix Z. However, since all your data is read in, it is merely a reshaping of all 1d-arrays to 2d-arrays:

target_shape = (np.sqrt(X.shape[0]),-1)
X = np.reshape(X, target_shape)
Y = np.reshape(Y, target_shape)
Z = np.reshape(Z, target_shape)

Have a look at the documentation of np.reshape for some more information.

Upvotes: 1

Related Questions