如何使用pandas与matplotlib创建3D图表

3

我在使用pandas转换数据以便在matplot lib中呈现三维数据时遇到了一些困难。我通常拥有的数据是数字列(通常是时间和某个值)。因此,让我们创建一些测试数据来说明。

import pandas as pd

pattern = ("....1...."
           "....1...."
           "..11111.."
           ".1133311."
           "111393111"
           ".1133311."
           "..11111.."
           "....1...."
           "....1....")

# create the data and coords
Zdata = list(map(lambda d:0 if d == '.' else int(d), pattern))
Zinverse = list(map(lambda d:1 if d == '.' else -int(d), pattern))
Xdata = [x for y in range(1,10) for x in range(1,10)]
Ydata = [y for y in range(1,10) for x in range(1,10)]
# pivot the data into columns
data = [d for d in zip(Xdata,Ydata,Zdata,Zinverse)]

# create the data frame 
df = pd.DataFrame(data, columns=['X','Y','Z',"Zi"], index=zip(Xdata,Ydata))
df.head(5)

enter image description here

编辑:这段数据是演示数据,通常来自需要更多清理和转换才能绘图的数据库查询。在这种情况下,数据已对齐,除了有一个我们不需要的列(Zi)之外,没有问题。

因此,pattern 中的数字被转换为 df 的 Z 列中的高度数据('Zi' 是反向图像),并且使用该数据帧,我努力想出了这个旋转方法,它由 3 个单独的操作组成。我想知道是否可以更好地实现。

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

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

Xs = df.pivot(index='X', columns='Y', values='X').values
Ys = df.pivot(index='X', columns='Y', values='Y').values
Zs = df.pivot(index='X', columns='Y', values='Z').values

ax.plot_surface(Xs,Ys,Zs, cmap=cm.RdYlGn)

plt.show()

enter image description here

虽然我已经有一些东西在运作,但我感觉肯定有比我现在做的更好的方法。在一个大数据集上,我想做三个透视表可能是绘制图表的一种昂贵方式。是否有更有效的方法来转换这些数据呢?

1个回答

1

我猜你可以通过不使用pandas(只使用numpy数组)并使用numpy提供的一些方便函数(如linespacemeshgrid)来避免在数据准备过程中执行一些步骤。

我重写了你的代码,尝试保持相同的逻辑和相同的变量名称:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

pattern = ("....1...."
           "....1...."
           "..11111.."
           ".1133311."
           "111393111"
           ".1133311."
           "..11111.."
           "....1...."
           "....1....")


# Extract the value according to your logic
Zdata = list(map(lambda d:0 if d == '.' else int(d), pattern))

# Assuming the pattern is always a square
size = int(len(Zdata) ** 0.5)

# Create a mesh grid for plotting the surface
Xdata = np.linspace(1, size, size)
Ydata = np.linspace(1, size, size)
Xs, Ys = np.meshgrid(Xdata, Ydata)

# Convert the Zdata to a numpy array with the appropriate shape
Zs = np.array(Zdata).reshape((size, size))

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

# Plot the surface
ax.plot_surface(Xs, Ys, Zs, cmap=cm.RdYlGn)
plt.show()

谢谢@mgc,我希望使用pandas,因为它能够在绘图之前执行许多其他清理和转换数据的功能。真实数据将是数百万行的多维数据列。因此,根据我的理解,在pandas dataframe中进行groupby或resample数据操作更容易,但我还不太熟悉pandas,无法确定最有效的绘图方式。 - Peter Moore
抱歉,发帖后我确实有印象是修改了你的最小示例的设置,而不是真正回答它。 - mgc
尽管如此,我很感激@mgc所做的努力。我故意避免使用meshgrid和linspace来创建示例,因为这些是难以理解的函数,并选择了不需要查找的标准Python方法。使用太多难以理解的方法会让读者感到困惑,即使他们可能有一个很好的答案。 - Peter Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接